HashedNameToDIE.h revision 732579b63a2624512812c8e33cc110a1437e49b6
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::DataExtractor &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::DataExtractor &table_data,
589                     const lldb_private::DataExtractor &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 Result
611        GetHashDataForName (const char *name,
612                            lldb::offset_t* hash_data_offset_ptr,
613                            Pair &pair) const
614        {
615            pair.key = m_data.GetU32 (hash_data_offset_ptr);
616            pair.value.clear();
617
618            // If the key is zero, this terminates our chain of HashData objects
619            // for this hash value.
620            if (pair.key == 0)
621                return eResultEndOfHashData;
622
623            // There definitely should be a string for this string offset, if
624            // there isn't, there is something wrong, return and error
625            const char *strp_cstr = m_string_table.PeekCStr (pair.key);
626            if (strp_cstr == NULL)
627            {
628                *hash_data_offset_ptr = UINT32_MAX;
629                return eResultError;
630            }
631
632            const uint32_t count = m_data.GetU32 (hash_data_offset_ptr);
633            const size_t min_total_hash_data_size = count * m_header.header_data.GetMinumumHashDataByteSize();
634            if (count > 0 && m_data.ValidOffsetForDataOfSize (*hash_data_offset_ptr, min_total_hash_data_size))
635            {
636                // We have at least one HashData entry, and we have enough
637                // data to parse at leats "count" HashData enties.
638
639                // First make sure the entire C string matches...
640                const bool match = strcmp (name, strp_cstr) == 0;
641
642                if (!match && m_header.header_data.HashDataHasFixedByteSize())
643                {
644                    // If the string doesn't match and we have fixed size data,
645                    // we can just add the total byte size of all HashData objects
646                    // to the hash data offset and be done...
647                    *hash_data_offset_ptr += min_total_hash_data_size;
648                }
649                else
650                {
651                    // If the string does match, or we don't have fixed size data
652                    // then we need to read the hash data as a stream. If the
653                    // string matches we also append all HashData objects to the
654                    // value array.
655                    for (uint32_t i=0; i<count; ++i)
656                    {
657                        DIEInfo die_info;
658                        if (m_header.Read(m_data, hash_data_offset_ptr, die_info))
659                        {
660                            // Only happend the HashData if the string matched...
661                            if (match)
662                                pair.value.push_back (die_info);
663                        }
664                        else
665                        {
666                            // Something went wrong while reading the data
667                            *hash_data_offset_ptr = UINT32_MAX;
668                            return eResultError;
669                        }
670                    }
671                }
672                // Return the correct response depending on if the string matched
673                // or not...
674                if (match)
675                    return eResultKeyMatch;     // The key (cstring) matches and we have lookup results!
676                else
677                    return eResultKeyMismatch;  // The key doesn't match, this function will get called
678                                                // again for the next key/value or the key terminator
679                                                // which in our case is a zero .debug_str offset.
680            }
681            else
682            {
683                *hash_data_offset_ptr = UINT32_MAX;
684                return eResultError;
685            }
686        }
687
688        virtual Result
689        AppendHashDataForRegularExpression (const lldb_private::RegularExpression& regex,
690                                            lldb::offset_t* hash_data_offset_ptr,
691                                            Pair &pair) const
692        {
693            pair.key = m_data.GetU32 (hash_data_offset_ptr);
694            // If the key is zero, this terminates our chain of HashData objects
695            // for this hash value.
696            if (pair.key == 0)
697                return eResultEndOfHashData;
698
699            // There definitely should be a string for this string offset, if
700            // there isn't, there is something wrong, return and error
701            const char *strp_cstr = m_string_table.PeekCStr (pair.key);
702            if (strp_cstr == NULL)
703                return eResultError;
704
705            const uint32_t count = m_data.GetU32 (hash_data_offset_ptr);
706            const size_t min_total_hash_data_size = count * m_header.header_data.GetMinumumHashDataByteSize();
707            if (count > 0 && m_data.ValidOffsetForDataOfSize (*hash_data_offset_ptr, min_total_hash_data_size))
708            {
709                const bool match = regex.Execute(strp_cstr);
710
711                if (!match && m_header.header_data.HashDataHasFixedByteSize())
712                {
713                    // If the regex doesn't match and we have fixed size data,
714                    // we can just add the total byte size of all HashData objects
715                    // to the hash data offset and be done...
716                    *hash_data_offset_ptr += min_total_hash_data_size;
717                }
718                else
719                {
720                    // If the string does match, or we don't have fixed size data
721                    // then we need to read the hash data as a stream. If the
722                    // string matches we also append all HashData objects to the
723                    // value array.
724                    for (uint32_t i=0; i<count; ++i)
725                    {
726                        DIEInfo die_info;
727                        if (m_header.Read(m_data, hash_data_offset_ptr, die_info))
728                        {
729                            // Only happend the HashData if the string matched...
730                            if (match)
731                                pair.value.push_back (die_info);
732                        }
733                        else
734                        {
735                            // Something went wrong while reading the data
736                            *hash_data_offset_ptr = UINT32_MAX;
737                            return eResultError;
738                        }
739                    }
740                }
741                // Return the correct response depending on if the string matched
742                // or not...
743                if (match)
744                    return eResultKeyMatch;     // The key (cstring) matches and we have lookup results!
745                else
746                    return eResultKeyMismatch;  // The key doesn't match, this function will get called
747                                                // again for the next key/value or the key terminator
748                                                // which in our case is a zero .debug_str offset.
749            }
750            else
751            {
752                *hash_data_offset_ptr = UINT32_MAX;
753                return eResultError;
754            }
755        }
756
757        size_t
758        AppendAllDIEsThatMatchingRegex (const lldb_private::RegularExpression& regex,
759                                        DIEInfoArray &die_info_array) const
760        {
761            const uint32_t hash_count = m_header.hashes_count;
762            Pair pair;
763            for (uint32_t offset_idx=0; offset_idx<hash_count; ++offset_idx)
764            {
765                lldb::offset_t hash_data_offset = GetHashDataOffset (offset_idx);
766                while (hash_data_offset != UINT32_MAX)
767                {
768                    const lldb::offset_t prev_hash_data_offset = hash_data_offset;
769                    Result hash_result = AppendHashDataForRegularExpression (regex, &hash_data_offset, pair);
770                    if (prev_hash_data_offset == hash_data_offset)
771                        break;
772
773                    // Check the result of getting our hash data
774                    switch (hash_result)
775                    {
776                        case eResultKeyMatch:
777                        case eResultKeyMismatch:
778                            // Whether we matches or not, it doesn't matter, we
779                            // keep looking.
780                            break;
781
782                        case eResultEndOfHashData:
783                        case eResultError:
784                            hash_data_offset = UINT32_MAX;
785                            break;
786                    }
787                }
788            }
789            die_info_array.swap (pair.value);
790            return die_info_array.size();
791        }
792
793        size_t
794        AppendAllDIEsInRange (const uint32_t die_offset_start,
795                              const uint32_t die_offset_end,
796                              DIEInfoArray &die_info_array) const
797        {
798            const uint32_t hash_count = m_header.hashes_count;
799            for (uint32_t offset_idx=0; offset_idx<hash_count; ++offset_idx)
800            {
801                bool done = false;
802                lldb::offset_t hash_data_offset = GetHashDataOffset (offset_idx);
803                while (!done && hash_data_offset != UINT32_MAX)
804                {
805                    KeyType key = m_data.GetU32 (&hash_data_offset);
806                    // If the key is zero, this terminates our chain of HashData objects
807                    // for this hash value.
808                    if (key == 0)
809                        break;
810
811                    const uint32_t count = m_data.GetU32 (&hash_data_offset);
812                    for (uint32_t i=0; i<count; ++i)
813                    {
814                        DIEInfo die_info;
815                        if (m_header.Read(m_data, &hash_data_offset, die_info))
816                        {
817                            if (die_info.offset == 0)
818                                done = true;
819                            if (die_offset_start <= die_info.offset && die_info.offset < die_offset_end)
820                                die_info_array.push_back(die_info);
821                        }
822                    }
823                }
824            }
825            return die_info_array.size();
826        }
827
828        size_t
829        FindByName (const char *name, DIEArray &die_offsets)
830        {
831            DIEInfoArray die_info_array;
832            if (FindByName(name, die_info_array))
833                DWARFMappedHash::ExtractDIEArray (die_info_array, die_offsets);
834            return die_info_array.size();
835        }
836
837        size_t
838        FindByNameAndTag (const char *name,
839                          const dw_tag_t tag,
840                          DIEArray &die_offsets)
841        {
842            DIEInfoArray die_info_array;
843            if (FindByName(name, die_info_array))
844                DWARFMappedHash::ExtractDIEArray (die_info_array, tag, die_offsets);
845            return die_info_array.size();
846        }
847
848        size_t
849        FindByNameAndTagAndQualifiedNameHash (const char *name,
850                                              const dw_tag_t tag,
851                                              const uint32_t qualified_name_hash,
852                                              DIEArray &die_offsets)
853        {
854            DIEInfoArray die_info_array;
855            if (FindByName(name, die_info_array))
856                DWARFMappedHash::ExtractDIEArray (die_info_array, tag, qualified_name_hash, die_offsets);
857            return die_info_array.size();
858        }
859
860        size_t
861        FindCompleteObjCClassByName (const char *name, DIEArray &die_offsets, bool must_be_implementation)
862        {
863            DIEInfoArray die_info_array;
864            if (FindByName(name, die_info_array))
865            {
866                if (must_be_implementation && GetHeader().header_data.ContainsAtom (eAtomTypeTypeFlags))
867                {
868                    // If we have two atoms, then we have the DIE offset and
869                    // the type flags so we can find the objective C class
870                    // efficiently.
871                    DWARFMappedHash::ExtractTypesFromDIEArray (die_info_array,
872                                                               UINT32_MAX,
873                                                               eTypeFlagClassIsImplementation,
874                                                               die_offsets);
875                }
876                else
877                {
878                    // We don't only want the one true definition, so try and see
879                    // what we can find, and only return class or struct DIEs.
880                    // If we do have the full implementation, then return it alone,
881                    // else return all possible matches.
882                    const bool return_implementation_only_if_available = true;
883                    DWARFMappedHash::ExtractClassOrStructDIEArray (die_info_array,
884                                                                   return_implementation_only_if_available,
885                                                                   die_offsets);
886                }
887            }
888            return die_offsets.size();
889        }
890
891        size_t
892        FindByName (const char *name, DIEInfoArray &die_info_array)
893        {
894            Pair kv_pair;
895            size_t old_size = die_info_array.size();
896            if (Find (name, kv_pair))
897            {
898                die_info_array.swap(kv_pair.value);
899                return die_info_array.size() - old_size;
900            }
901            return 0;
902        }
903
904    protected:
905        const lldb_private::DataExtractor &m_data;
906        const lldb_private::DataExtractor &m_string_table;
907        std::string m_name;
908    };
909};
910
911
912#endif  // SymbolFileDWARF_HashedNameToDIE_h_
913