1//===-- HashedNameToDIE.h ---------------------------------------*- C++ -*-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#ifndef SymbolFileDWARF_HashedNameToDIE_h_
11#define SymbolFileDWARF_HashedNameToDIE_h_
12
13#include <vector>
14
15#include "DWARFDefines.h"
16#include "DWARFFormValue.h"
17
18#include "lldb/lldb-defines.h"
19#include "lldb/Core/dwarf.h"
20#include "lldb/Core/RegularExpression.h"
21#include "lldb/Core/MappedHash.h"
22
23
24class SymbolFileDWARF;
25class DWARFCompileUnit;
26class DWARFDebugInfoEntry;
27
28struct DWARFMappedHash
29{
30    struct DIEInfo
31    {
32        dw_offset_t offset;  // The DIE offset
33        dw_tag_t tag;
34        uint32_t type_flags; // Any flags for this DIEInfo
35        uint32_t qualified_name_hash; // A 32 bit hash of the fully qualified name
36
37        DIEInfo () :
38            offset (DW_INVALID_OFFSET),
39            tag (0),
40            type_flags (0),
41            qualified_name_hash (0)
42        {
43        }
44
45        DIEInfo (dw_offset_t o, dw_tag_t t, uint32_t f, uint32_t h) :
46            offset(o),
47            tag (t),
48            type_flags (f),
49            qualified_name_hash (h)
50        {
51        }
52
53        void
54        Clear()
55        {
56            offset = DW_INVALID_OFFSET;
57            tag = 0;
58            type_flags = 0;
59            qualified_name_hash = 0;
60        }
61    };
62
63    typedef std::vector<DIEInfo> DIEInfoArray;
64    typedef std::vector<uint32_t> DIEArray;
65
66    static void
67    ExtractDIEArray (const DIEInfoArray &die_info_array,
68                     DIEArray &die_offsets)
69    {
70        const size_t count = die_info_array.size();
71        for (size_t i=0; i<count; ++i)
72        {
73            die_offsets.push_back (die_info_array[i].offset);
74        }
75    }
76
77    static void
78    ExtractDIEArray (const DIEInfoArray &die_info_array,
79                     const dw_tag_t tag,
80                     DIEArray &die_offsets)
81    {
82        if (tag == 0)
83        {
84            ExtractDIEArray (die_info_array, die_offsets);
85        }
86        else
87        {
88            const size_t count = die_info_array.size();
89            for (size_t i=0; i<count; ++i)
90            {
91                const dw_tag_t die_tag = die_info_array[i].tag;
92                bool tag_matches = die_tag == 0 || tag == die_tag;
93                if (!tag_matches)
94                {
95                    if (die_tag == DW_TAG_class_type || die_tag == DW_TAG_structure_type)
96                        tag_matches = tag == DW_TAG_structure_type || tag == DW_TAG_class_type;
97                }
98                if (tag_matches)
99                    die_offsets.push_back (die_info_array[i].offset);
100            }
101        }
102    }
103
104    static void
105    ExtractDIEArray (const DIEInfoArray &die_info_array,
106                     const dw_tag_t tag,
107                     const uint32_t qualified_name_hash,
108                     DIEArray &die_offsets)
109    {
110        if (tag == 0)
111        {
112            ExtractDIEArray (die_info_array, die_offsets);
113        }
114        else
115        {
116            const size_t count = die_info_array.size();
117            for (size_t i=0; i<count; ++i)
118            {
119                if (qualified_name_hash != die_info_array[i].qualified_name_hash)
120                    continue;
121                const dw_tag_t die_tag = die_info_array[i].tag;
122                bool tag_matches = die_tag == 0 || tag == die_tag;
123                if (!tag_matches)
124                {
125                    if (die_tag == DW_TAG_class_type || die_tag == DW_TAG_structure_type)
126                        tag_matches = tag == DW_TAG_structure_type || tag == DW_TAG_class_type;
127                }
128                if (tag_matches)
129                    die_offsets.push_back (die_info_array[i].offset);
130            }
131        }
132    }
133
134    enum AtomType
135    {
136        eAtomTypeNULL       = 0u,
137        eAtomTypeDIEOffset  = 1u,   // DIE offset, check form for encoding
138        eAtomTypeCUOffset   = 2u,   // DIE offset of the compiler unit header that contains the item in question
139        eAtomTypeTag        = 3u,   // DW_TAG_xxx value, should be encoded as DW_FORM_data1 (if no tags exceed 255) or DW_FORM_data2
140        eAtomTypeNameFlags  = 4u,   // Flags from enum NameFlags
141        eAtomTypeTypeFlags  = 5u,   // Flags from enum TypeFlags,
142        eAtomTypeQualNameHash = 6u  // A 32 bit hash of the full qualified name (since all hash entries are basename only)
143                                    // For example a type like "std::vector<int>::iterator" would have a name of "iterator"
144                                    // and a 32 bit hash for "std::vector<int>::iterator" to allow us to not have to pull
145                                    // in debug info for a type when we know the fully qualified name.
146    };
147
148    // Bit definitions for the eAtomTypeTypeFlags flags
149    enum TypeFlags
150    {
151        // Always set for C++, only set for ObjC if this is the
152        // @implementation for class
153        eTypeFlagClassIsImplementation  = ( 1u << 1 )
154    };
155
156
157    static void
158    ExtractClassOrStructDIEArray (const DIEInfoArray &die_info_array,
159                                  bool return_implementation_only_if_available,
160                                  DIEArray &die_offsets)
161    {
162        const size_t count = die_info_array.size();
163        for (size_t i=0; i<count; ++i)
164        {
165            const dw_tag_t die_tag = die_info_array[i].tag;
166            if (die_tag == 0 || die_tag == DW_TAG_class_type || die_tag == DW_TAG_structure_type)
167            {
168                if (die_info_array[i].type_flags & eTypeFlagClassIsImplementation)
169                {
170                    if (return_implementation_only_if_available)
171                    {
172                        // We found the one true definiton for this class, so
173                        // only return that
174                        die_offsets.clear();
175                        die_offsets.push_back (die_info_array[i].offset);
176                        return;
177                    }
178                    else
179                    {
180                        // Put the one true definition as the first entry so it
181                        // matches first
182                        die_offsets.insert (die_offsets.begin(), die_info_array[i].offset);
183                    }
184                }
185                else
186                {
187                    die_offsets.push_back (die_info_array[i].offset);
188                }
189            }
190        }
191    }
192
193    static void
194    ExtractTypesFromDIEArray (const DIEInfoArray &die_info_array,
195                              uint32_t type_flag_mask,
196                              uint32_t type_flag_value,
197                              DIEArray &die_offsets)
198    {
199        const size_t count = die_info_array.size();
200        for (size_t i=0; i<count; ++i)
201        {
202            if ((die_info_array[i].type_flags & type_flag_mask) == type_flag_value)
203                die_offsets.push_back (die_info_array[i].offset);
204        }
205    }
206
207    struct Atom
208    {
209        uint16_t type;
210        dw_form_t form;
211
212        Atom (uint16_t t = eAtomTypeNULL, dw_form_t f = 0) :
213            type (t),
214            form (f)
215        {
216        }
217    };
218
219    typedef std::vector<Atom> AtomArray;
220
221    static uint32_t
222    GetTypeFlags (SymbolFileDWARF *dwarf2Data,
223                  const DWARFCompileUnit* cu,
224                  const DWARFDebugInfoEntry* die);
225
226
227    static const char *
228    GetAtomTypeName (uint16_t atom)
229    {
230        switch (atom)
231        {
232            case eAtomTypeNULL:         return "NULL";
233            case eAtomTypeDIEOffset:    return "die-offset";
234            case eAtomTypeCUOffset:     return "cu-offset";
235            case eAtomTypeTag:          return "die-tag";
236            case eAtomTypeNameFlags:    return "name-flags";
237            case eAtomTypeTypeFlags:    return "type-flags";
238            case eAtomTypeQualNameHash: return "qualified-name-hash";
239        }
240        return "<invalid>";
241    }
242    struct Prologue
243    {
244        // DIE offset base so die offsets in hash_data can be CU relative
245        dw_offset_t die_base_offset;
246        AtomArray atoms;
247        uint32_t atom_mask;
248        size_t min_hash_data_byte_size;
249        bool hash_data_has_fixed_byte_size;
250
251        Prologue (dw_offset_t _die_base_offset = 0) :
252            die_base_offset (_die_base_offset),
253            atoms(),
254            atom_mask (0),
255            min_hash_data_byte_size(0),
256            hash_data_has_fixed_byte_size(true)
257        {
258            // Define an array of DIE offsets by first defining an array,
259            // and then define the atom type for the array, in this case
260            // we have an array of DIE offsets
261            AppendAtom (eAtomTypeDIEOffset, DW_FORM_data4);
262        }
263
264        virtual ~Prologue()
265        {
266        }
267
268        void
269        ClearAtoms ()
270        {
271            hash_data_has_fixed_byte_size = true;
272            min_hash_data_byte_size = 0;
273            atom_mask = 0;
274            atoms.clear();
275        }
276
277        bool
278        ContainsAtom (AtomType atom_type) const
279        {
280            return (atom_mask & (1u << atom_type)) != 0;
281        }
282
283        virtual void
284        Clear ()
285        {
286            die_base_offset = 0;
287            ClearAtoms ();
288        }
289
290        void
291        AppendAtom (AtomType type, dw_form_t form)
292        {
293            atoms.push_back (Atom(type, form));
294            atom_mask |= 1u << type;
295            switch (form)
296            {
297                case DW_FORM_indirect:
298                case DW_FORM_exprloc:
299                case DW_FORM_flag_present:
300                case DW_FORM_ref_sig8:
301                    assert (!"Unhandled atom form");
302                    break;
303
304                case DW_FORM_string:
305                case DW_FORM_block:
306                case DW_FORM_block1:
307                case DW_FORM_sdata:
308                case DW_FORM_udata:
309                case DW_FORM_ref_udata:
310                    hash_data_has_fixed_byte_size = false;
311                    // Fall through to the cases below...
312                case DW_FORM_flag:
313                case DW_FORM_data1:
314                case DW_FORM_ref1:
315                case DW_FORM_sec_offset:
316                    min_hash_data_byte_size += 1;
317                    break;
318
319                case DW_FORM_block2:
320                    hash_data_has_fixed_byte_size = false;
321                    // Fall through to the cases below...
322                case DW_FORM_data2:
323                case DW_FORM_ref2:
324                    min_hash_data_byte_size += 2;
325                    break;
326
327                case DW_FORM_block4:
328                    hash_data_has_fixed_byte_size = false;
329                    // Fall through to the cases below...
330                case DW_FORM_data4:
331                case DW_FORM_ref4:
332                case DW_FORM_addr:
333                case DW_FORM_ref_addr:
334                case DW_FORM_strp:
335                    min_hash_data_byte_size += 4;
336                    break;
337
338                case DW_FORM_data8:
339                case DW_FORM_ref8:
340                    min_hash_data_byte_size += 8;
341                    break;
342
343            }
344        }
345
346//        void
347//        Dump (std::ostream* ostrm_ptr);
348
349        lldb::offset_t
350        Read (const lldb_private::DataExtractor &data,
351              lldb::offset_t offset)
352        {
353            ClearAtoms ();
354
355            die_base_offset = data.GetU32 (&offset);
356
357            const uint32_t atom_count = data.GetU32 (&offset);
358            if (atom_count == 0x00060003u)
359            {
360                // Old format, deal with contents of old pre-release format
361                while (data.GetU32(&offset))
362                    /* do nothing */;
363
364                // Hardcode to the only known value for now.
365                AppendAtom (eAtomTypeDIEOffset, DW_FORM_data4);
366            }
367            else
368            {
369                for (uint32_t i=0; i<atom_count; ++i)
370                {
371                    AtomType type = (AtomType)data.GetU16 (&offset);
372                    dw_form_t form = (dw_form_t)data.GetU16 (&offset);
373                    AppendAtom (type, form);
374                }
375            }
376            return offset;
377        }
378
379//        virtual void
380//        Write (BinaryStreamBuf &s);
381
382        size_t
383        GetByteSize () const
384        {
385            // Add an extra count to the atoms size for the zero termination Atom that gets
386            // written to disk
387            return sizeof(die_base_offset) + sizeof(uint32_t) + atoms.size() * sizeof(Atom);
388        }
389
390        size_t
391        GetMinumumHashDataByteSize () const
392        {
393            return min_hash_data_byte_size;
394        }
395
396        bool
397        HashDataHasFixedByteSize() const
398        {
399            return hash_data_has_fixed_byte_size;
400        }
401    };
402
403    struct Header : public MappedHash::Header<Prologue>
404    {
405        Header (dw_offset_t _die_base_offset = 0)
406        {
407        }
408
409        virtual
410        ~Header()
411        {
412        }
413
414        virtual size_t
415        GetByteSize (const HeaderData &header_data)
416        {
417            return header_data.GetByteSize();
418        }
419
420        //        virtual void
421        //        Dump (std::ostream* ostrm_ptr);
422        //
423        virtual lldb::offset_t
424        Read (lldb_private::DataExtractor &data, lldb::offset_t offset)
425        {
426            offset = MappedHash::Header<Prologue>::Read (data, offset);
427            if (offset != UINT32_MAX)
428            {
429                offset = header_data.Read (data, offset);
430            }
431            return offset;
432        }
433
434        bool
435        Read (const lldb_private::DWARFDataExtractor &data,
436              lldb::offset_t *offset_ptr,
437              DIEInfo &hash_data) const
438        {
439            const size_t num_atoms = header_data.atoms.size();
440            if (num_atoms == 0)
441                return false;
442
443            for (size_t i=0; i<num_atoms; ++i)
444            {
445                DWARFFormValue form_value (header_data.atoms[i].form);
446
447                if (!form_value.ExtractValue(data, offset_ptr, NULL))
448                    return false;
449
450                switch (header_data.atoms[i].type)
451                {
452                    case eAtomTypeDIEOffset:    // DIE offset, check form for encoding
453                        hash_data.offset = (dw_offset_t)form_value.Reference (header_data.die_base_offset);
454                        break;
455
456                    case eAtomTypeTag:          // DW_TAG value for the DIE
457                        hash_data.tag = (dw_tag_t)form_value.Unsigned ();
458
459                    case eAtomTypeTypeFlags:    // Flags from enum TypeFlags
460                        hash_data.type_flags = (uint32_t)form_value.Unsigned ();
461                        break;
462
463                    case eAtomTypeQualNameHash:    // Flags from enum TypeFlags
464                        hash_data.qualified_name_hash = form_value.Unsigned ();
465                        break;
466
467                    default:
468                        // We can always skip atomes we don't know about
469                        break;
470                }
471            }
472            return true;
473        }
474
475        void
476        Dump (lldb_private::Stream& strm, const DIEInfo &hash_data) const
477        {
478            const size_t num_atoms = header_data.atoms.size();
479            for (size_t i=0; i<num_atoms; ++i)
480            {
481                if (i > 0)
482                    strm.PutCString (", ");
483
484                DWARFFormValue form_value (header_data.atoms[i].form);
485                switch (header_data.atoms[i].type)
486                {
487                    case eAtomTypeDIEOffset:    // DIE offset, check form for encoding
488                        strm.Printf ("{0x%8.8x}", hash_data.offset);
489                        break;
490
491                    case eAtomTypeTag:          // DW_TAG value for the DIE
492                        {
493                            const char *tag_cstr = lldb_private::DW_TAG_value_to_name (hash_data.tag);
494                            if (tag_cstr)
495                                strm.PutCString (tag_cstr);
496                            else
497                                strm.Printf ("DW_TAG_(0x%4.4x)", hash_data.tag);
498                        }
499                        break;
500
501                    case eAtomTypeTypeFlags:    // Flags from enum TypeFlags
502                        strm.Printf ("0x%2.2x", hash_data.type_flags);
503                        if (hash_data.type_flags)
504                        {
505                            strm.PutCString (" (");
506                            if (hash_data.type_flags & eTypeFlagClassIsImplementation)
507                                strm.PutCString (" implementation");
508                            strm.PutCString (" )");
509                        }
510                        break;
511
512                    case eAtomTypeQualNameHash:    // Flags from enum TypeFlags
513                        strm.Printf ("0x%8.8x", hash_data.qualified_name_hash);
514                        break;
515
516                    default:
517                        strm.Printf ("AtomType(0x%x)", header_data.atoms[i].type);
518                        break;
519                }
520            }
521        }
522    };
523
524//    class ExportTable
525//    {
526//    public:
527//        ExportTable ();
528//
529//        void
530//        AppendNames (DWARFDebugPubnamesSet &pubnames_set,
531//                     StringTable &string_table);
532//
533//        void
534//        AppendNamesEntry (SymbolFileDWARF *dwarf2Data,
535//                          const DWARFCompileUnit* cu,
536//                          const DWARFDebugInfoEntry* die,
537//                          StringTable &string_table);
538//
539//        void
540//        AppendTypesEntry (DWARFData *dwarf2Data,
541//                          const DWARFCompileUnit* cu,
542//                          const DWARFDebugInfoEntry* die,
543//                          StringTable &string_table);
544//
545//        size_t
546//        Save (BinaryStreamBuf &names_data, const StringTable &string_table);
547//
548//        void
549//        AppendName (const char *name,
550//                    uint32_t die_offset,
551//                    StringTable &string_table,
552//                    dw_offset_t name_debug_str_offset = DW_INVALID_OFFSET); // If "name" has already been looked up, then it can be supplied
553//        void
554//        AppendType (const char *name,
555//                    uint32_t die_offset,
556//                    StringTable &string_table);
557//
558//
559//    protected:
560//        struct Entry
561//        {
562//            uint32_t hash;
563//            uint32_t str_offset;
564//            uint32_t die_offset;
565//        };
566//
567//        // Map uniqued .debug_str offset to the corresponding DIE offsets
568//        typedef std::map<uint32_t, DIEInfoArray> NameInfo;
569//        // Map a name hash to one or more name infos
570//        typedef std::map<uint32_t, NameInfo> BucketEntry;
571//
572//        static uint32_t
573//        GetByteSize (const NameInfo &name_info);
574//
575//        typedef std::vector<BucketEntry> BucketEntryColl;
576//        typedef std::vector<Entry> EntryColl;
577//        EntryColl m_entries;
578//
579//    };
580
581
582    // A class for reading and using a saved hash table from a block of data
583    // in memory
584    class MemoryTable : public MappedHash::MemoryTable<uint32_t, DWARFMappedHash::Header, DIEInfoArray>
585    {
586    public:
587
588        MemoryTable (lldb_private::DWARFDataExtractor &table_data,
589                     const lldb_private::DWARFDataExtractor &string_table,
590                     const char *name) :
591            MappedHash::MemoryTable<uint32_t, Header, DIEInfoArray> (table_data),
592            m_data (table_data),
593            m_string_table (string_table),
594            m_name (name)
595        {
596        }
597
598        virtual
599        ~MemoryTable ()
600        {
601        }
602
603        virtual const char *
604        GetStringForKeyType (KeyType key) const
605        {
606            // The key in the DWARF table is the .debug_str offset for the string
607            return m_string_table.PeekCStr (key);
608        }
609
610        virtual bool
611        ReadHashData (uint32_t hash_data_offset,
612                      HashData &hash_data) const
613        {
614            lldb::offset_t offset = hash_data_offset;
615            offset += 4; // Skip string table offset that contains offset of hash name in .debug_str
616            const uint32_t count = m_data.GetU32 (&offset);
617            if (count > 0)
618            {
619                hash_data.resize(count);
620                for (uint32_t i=0; i<count; ++i)
621                {
622                    if (!m_header.Read(m_data, &offset, hash_data[i]))
623                        return false;
624                }
625            }
626            else
627                hash_data.clear();
628            return true;
629        }
630
631        virtual Result
632        GetHashDataForName (const char *name,
633                            lldb::offset_t* hash_data_offset_ptr,
634                            Pair &pair) const
635        {
636            pair.key = m_data.GetU32 (hash_data_offset_ptr);
637            pair.value.clear();
638
639            // If the key is zero, this terminates our chain of HashData objects
640            // for this hash value.
641            if (pair.key == 0)
642                return eResultEndOfHashData;
643
644            // There definitely should be a string for this string offset, if
645            // there isn't, there is something wrong, return and error
646            const char *strp_cstr = m_string_table.PeekCStr (pair.key);
647            if (strp_cstr == NULL)
648            {
649                *hash_data_offset_ptr = UINT32_MAX;
650                return eResultError;
651            }
652
653            const uint32_t count = m_data.GetU32 (hash_data_offset_ptr);
654            const size_t min_total_hash_data_size = count * m_header.header_data.GetMinumumHashDataByteSize();
655            if (count > 0 && m_data.ValidOffsetForDataOfSize (*hash_data_offset_ptr, min_total_hash_data_size))
656            {
657                // We have at least one HashData entry, and we have enough
658                // data to parse at leats "count" HashData enties.
659
660                // First make sure the entire C string matches...
661                const bool match = strcmp (name, strp_cstr) == 0;
662
663                if (!match && m_header.header_data.HashDataHasFixedByteSize())
664                {
665                    // If the string doesn't match and we have fixed size data,
666                    // we can just add the total byte size of all HashData objects
667                    // to the hash data offset and be done...
668                    *hash_data_offset_ptr += min_total_hash_data_size;
669                }
670                else
671                {
672                    // If the string does match, or we don't have fixed size data
673                    // then we need to read the hash data as a stream. If the
674                    // string matches we also append all HashData objects to the
675                    // value array.
676                    for (uint32_t i=0; i<count; ++i)
677                    {
678                        DIEInfo die_info;
679                        if (m_header.Read(m_data, hash_data_offset_ptr, die_info))
680                        {
681                            // Only happend the HashData if the string matched...
682                            if (match)
683                                pair.value.push_back (die_info);
684                        }
685                        else
686                        {
687                            // Something went wrong while reading the data
688                            *hash_data_offset_ptr = UINT32_MAX;
689                            return eResultError;
690                        }
691                    }
692                }
693                // Return the correct response depending on if the string matched
694                // or not...
695                if (match)
696                    return eResultKeyMatch;     // The key (cstring) matches and we have lookup results!
697                else
698                    return eResultKeyMismatch;  // The key doesn't match, this function will get called
699                                                // again for the next key/value or the key terminator
700                                                // which in our case is a zero .debug_str offset.
701            }
702            else
703            {
704                *hash_data_offset_ptr = UINT32_MAX;
705                return eResultError;
706            }
707        }
708
709        virtual Result
710        AppendHashDataForRegularExpression (const lldb_private::RegularExpression& regex,
711                                            lldb::offset_t* hash_data_offset_ptr,
712                                            Pair &pair) const
713        {
714            pair.key = m_data.GetU32 (hash_data_offset_ptr);
715            // If the key is zero, this terminates our chain of HashData objects
716            // for this hash value.
717            if (pair.key == 0)
718                return eResultEndOfHashData;
719
720            // There definitely should be a string for this string offset, if
721            // there isn't, there is something wrong, return and error
722            const char *strp_cstr = m_string_table.PeekCStr (pair.key);
723            if (strp_cstr == NULL)
724                return eResultError;
725
726            const uint32_t count = m_data.GetU32 (hash_data_offset_ptr);
727            const size_t min_total_hash_data_size = count * m_header.header_data.GetMinumumHashDataByteSize();
728            if (count > 0 && m_data.ValidOffsetForDataOfSize (*hash_data_offset_ptr, min_total_hash_data_size))
729            {
730                const bool match = regex.Execute(strp_cstr);
731
732                if (!match && m_header.header_data.HashDataHasFixedByteSize())
733                {
734                    // If the regex doesn't match and we have fixed size data,
735                    // we can just add the total byte size of all HashData objects
736                    // to the hash data offset and be done...
737                    *hash_data_offset_ptr += min_total_hash_data_size;
738                }
739                else
740                {
741                    // If the string does match, or we don't have fixed size data
742                    // then we need to read the hash data as a stream. If the
743                    // string matches we also append all HashData objects to the
744                    // value array.
745                    for (uint32_t i=0; i<count; ++i)
746                    {
747                        DIEInfo die_info;
748                        if (m_header.Read(m_data, hash_data_offset_ptr, die_info))
749                        {
750                            // Only happend the HashData if the string matched...
751                            if (match)
752                                pair.value.push_back (die_info);
753                        }
754                        else
755                        {
756                            // Something went wrong while reading the data
757                            *hash_data_offset_ptr = UINT32_MAX;
758                            return eResultError;
759                        }
760                    }
761                }
762                // Return the correct response depending on if the string matched
763                // or not...
764                if (match)
765                    return eResultKeyMatch;     // The key (cstring) matches and we have lookup results!
766                else
767                    return eResultKeyMismatch;  // The key doesn't match, this function will get called
768                                                // again for the next key/value or the key terminator
769                                                // which in our case is a zero .debug_str offset.
770            }
771            else
772            {
773                *hash_data_offset_ptr = UINT32_MAX;
774                return eResultError;
775            }
776        }
777
778        size_t
779        AppendAllDIEsThatMatchingRegex (const lldb_private::RegularExpression& regex,
780                                        DIEInfoArray &die_info_array) const
781        {
782            const uint32_t hash_count = m_header.hashes_count;
783            Pair pair;
784            for (uint32_t offset_idx=0; offset_idx<hash_count; ++offset_idx)
785            {
786                lldb::offset_t hash_data_offset = GetHashDataOffset (offset_idx);
787                while (hash_data_offset != UINT32_MAX)
788                {
789                    const lldb::offset_t prev_hash_data_offset = hash_data_offset;
790                    Result hash_result = AppendHashDataForRegularExpression (regex, &hash_data_offset, pair);
791                    if (prev_hash_data_offset == hash_data_offset)
792                        break;
793
794                    // Check the result of getting our hash data
795                    switch (hash_result)
796                    {
797                        case eResultKeyMatch:
798                        case eResultKeyMismatch:
799                            // Whether we matches or not, it doesn't matter, we
800                            // keep looking.
801                            break;
802
803                        case eResultEndOfHashData:
804                        case eResultError:
805                            hash_data_offset = UINT32_MAX;
806                            break;
807                    }
808                }
809            }
810            die_info_array.swap (pair.value);
811            return die_info_array.size();
812        }
813
814        size_t
815        AppendAllDIEsInRange (const uint32_t die_offset_start,
816                              const uint32_t die_offset_end,
817                              DIEInfoArray &die_info_array) const
818        {
819            const uint32_t hash_count = m_header.hashes_count;
820            for (uint32_t offset_idx=0; offset_idx<hash_count; ++offset_idx)
821            {
822                bool done = false;
823                lldb::offset_t hash_data_offset = GetHashDataOffset (offset_idx);
824                while (!done && hash_data_offset != UINT32_MAX)
825                {
826                    KeyType key = m_data.GetU32 (&hash_data_offset);
827                    // If the key is zero, this terminates our chain of HashData objects
828                    // for this hash value.
829                    if (key == 0)
830                        break;
831
832                    const uint32_t count = m_data.GetU32 (&hash_data_offset);
833                    for (uint32_t i=0; i<count; ++i)
834                    {
835                        DIEInfo die_info;
836                        if (m_header.Read(m_data, &hash_data_offset, die_info))
837                        {
838                            if (die_info.offset == 0)
839                                done = true;
840                            if (die_offset_start <= die_info.offset && die_info.offset < die_offset_end)
841                                die_info_array.push_back(die_info);
842                        }
843                    }
844                }
845            }
846            return die_info_array.size();
847        }
848
849        size_t
850        FindByName (const char *name, DIEArray &die_offsets)
851        {
852            DIEInfoArray die_info_array;
853            if (FindByName(name, die_info_array))
854                DWARFMappedHash::ExtractDIEArray (die_info_array, die_offsets);
855            return die_info_array.size();
856        }
857
858        size_t
859        FindByNameAndTag (const char *name,
860                          const dw_tag_t tag,
861                          DIEArray &die_offsets)
862        {
863            DIEInfoArray die_info_array;
864            if (FindByName(name, die_info_array))
865                DWARFMappedHash::ExtractDIEArray (die_info_array, tag, die_offsets);
866            return die_info_array.size();
867        }
868
869        size_t
870        FindByNameAndTagAndQualifiedNameHash (const char *name,
871                                              const dw_tag_t tag,
872                                              const uint32_t qualified_name_hash,
873                                              DIEArray &die_offsets)
874        {
875            DIEInfoArray die_info_array;
876            if (FindByName(name, die_info_array))
877                DWARFMappedHash::ExtractDIEArray (die_info_array, tag, qualified_name_hash, die_offsets);
878            return die_info_array.size();
879        }
880
881        size_t
882        FindCompleteObjCClassByName (const char *name, DIEArray &die_offsets, bool must_be_implementation)
883        {
884            DIEInfoArray die_info_array;
885            if (FindByName(name, die_info_array))
886            {
887                if (must_be_implementation && GetHeader().header_data.ContainsAtom (eAtomTypeTypeFlags))
888                {
889                    // If we have two atoms, then we have the DIE offset and
890                    // the type flags so we can find the objective C class
891                    // efficiently.
892                    DWARFMappedHash::ExtractTypesFromDIEArray (die_info_array,
893                                                               UINT32_MAX,
894                                                               eTypeFlagClassIsImplementation,
895                                                               die_offsets);
896                }
897                else
898                {
899                    // We don't only want the one true definition, so try and see
900                    // what we can find, and only return class or struct DIEs.
901                    // If we do have the full implementation, then return it alone,
902                    // else return all possible matches.
903                    const bool return_implementation_only_if_available = true;
904                    DWARFMappedHash::ExtractClassOrStructDIEArray (die_info_array,
905                                                                   return_implementation_only_if_available,
906                                                                   die_offsets);
907                }
908            }
909            return die_offsets.size();
910        }
911
912        size_t
913        FindByName (const char *name, DIEInfoArray &die_info_array)
914        {
915            Pair kv_pair;
916            size_t old_size = die_info_array.size();
917            if (Find (name, kv_pair))
918            {
919                die_info_array.swap(kv_pair.value);
920                return die_info_array.size() - old_size;
921            }
922            return 0;
923        }
924
925    protected:
926        const lldb_private::DWARFDataExtractor &m_data;
927        const lldb_private::DWARFDataExtractor &m_string_table;
928        std::string m_name;
929    };
930};
931
932
933#endif  // SymbolFileDWARF_HashedNameToDIE_h_
934