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 
24 class SymbolFileDWARF;
25 class DWARFCompileUnit;
26 class DWARFDebugInfoEntry;
27 
28 struct 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 
DIEInfoDWARFMappedHash::DIEInfo37         DIEInfo () :
38             offset (DW_INVALID_OFFSET),
39             tag (0),
40             type_flags (0),
41             qualified_name_hash (0)
42         {
43         }
44 
DIEInfoDWARFMappedHash::DIEInfo45         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
ClearDWARFMappedHash::DIEInfo54         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
ExtractDIEArrayDWARFMappedHash67     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
ExtractDIEArrayDWARFMappedHash78     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
ExtractDIEArrayDWARFMappedHash105     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
ExtractClassOrStructDIEArrayDWARFMappedHash158     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
ExtractTypesFromDIEArrayDWARFMappedHash194     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) :
typeDWARFMappedHash::Atom213             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 *
GetAtomTypeNameDWARFMappedHash228     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) :
die_base_offsetDWARFMappedHash::Prologue252             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 
~PrologueDWARFMappedHash::Prologue264         virtual ~Prologue()
265         {
266         }
267 
268         void
ClearAtomsDWARFMappedHash::Prologue269         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
ContainsAtomDWARFMappedHash::Prologue278         ContainsAtom (AtomType atom_type) const
279         {
280             return (atom_mask & (1u << atom_type)) != 0;
281         }
282 
283         virtual void
ClearDWARFMappedHash::Prologue284         Clear ()
285         {
286             die_base_offset = 0;
287             ClearAtoms ();
288         }
289 
290         void
AppendAtomDWARFMappedHash::Prologue291         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
ReadDWARFMappedHash::Prologue350         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
GetByteSizeDWARFMappedHash::Prologue383         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
GetMinumumHashDataByteSizeDWARFMappedHash::Prologue391         GetMinumumHashDataByteSize () const
392         {
393             return min_hash_data_byte_size;
394         }
395 
396         bool
HashDataHasFixedByteSizeDWARFMappedHash::Prologue397         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
~HeaderDWARFMappedHash::Header410         ~Header()
411         {
412         }
413 
414         virtual size_t
GetByteSizeDWARFMappedHash::Header415         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
ReadDWARFMappedHash::Header424         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
ReadDWARFMappedHash::Header435         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
DumpDWARFMappedHash::Header476         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 
MemoryTableDWARFMappedHash588         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
~MemoryTableDWARFMappedHash599         ~MemoryTable ()
600         {
601         }
602 
603         virtual const char *
GetStringForKeyTypeDWARFMappedHash604         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
ReadHashDataDWARFMappedHash611         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
GetHashDataForNameDWARFMappedHash632         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
AppendHashDataForRegularExpressionDWARFMappedHash710         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
AppendAllDIEsThatMatchingRegexDWARFMappedHash779         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
AppendAllDIEsInRangeDWARFMappedHash815         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
FindByNameDWARFMappedHash850         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
FindByNameAndTagDWARFMappedHash859         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
FindByNameAndTagAndQualifiedNameHashDWARFMappedHash870         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
FindCompleteObjCClassByNameDWARFMappedHash882         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
FindByNameDWARFMappedHash913         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::DataExtractor &m_data;
927         const lldb_private::DataExtractor &m_string_table;
928         std::string m_name;
929     };
930 };
931 
932 
933 #endif  // SymbolFileDWARF_HashedNameToDIE_h_
934