1 //===-- HashedNameToDIE.cpp -------------------------------------*- 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 #include "HashedNameToDIE.h"
11 
12 void
13 DWARFMappedHash::ExtractDIEArray (const DIEInfoArray &die_info_array, DIEArray &die_offsets)
14 {
15     const size_t count = die_info_array.size();
16     for (size_t i=0; i<count; ++i)
17         die_offsets.emplace_back(die_info_array[i].cu_offset, die_info_array[i].offset);
18 }
19 
20 void
21 DWARFMappedHash::ExtractDIEArray (const DIEInfoArray &die_info_array,
22                                   const dw_tag_t tag,
23                                   DIEArray &die_offsets)
24 {
25     if (tag == 0)
26     {
27         ExtractDIEArray (die_info_array, die_offsets);
28     }
29     else
30     {
31         const size_t count = die_info_array.size();
32         for (size_t i=0; i<count; ++i)
33         {
34             const dw_tag_t die_tag = die_info_array[i].tag;
35             bool tag_matches = die_tag == 0 || tag == die_tag;
36             if (!tag_matches)
37             {
38                 if (die_tag == DW_TAG_class_type || die_tag == DW_TAG_structure_type)
39                     tag_matches = tag == DW_TAG_structure_type || tag == DW_TAG_class_type;
40             }
41             if (tag_matches)
42                 die_offsets.emplace_back(die_info_array[i].cu_offset, die_info_array[i].offset);
43         }
44     }
45 }
46 
47 void
48 DWARFMappedHash::ExtractDIEArray (const DIEInfoArray &die_info_array,
49                                   const dw_tag_t tag,
50                                   const uint32_t qualified_name_hash,
51                                   DIEArray &die_offsets)
52 {
53     if (tag == 0)
54     {
55         ExtractDIEArray (die_info_array, die_offsets);
56     }
57     else
58     {
59         const size_t count = die_info_array.size();
60         for (size_t i=0; i<count; ++i)
61         {
62             if (qualified_name_hash != die_info_array[i].qualified_name_hash)
63                 continue;
64             const dw_tag_t die_tag = die_info_array[i].tag;
65             bool tag_matches = die_tag == 0 || tag == die_tag;
66             if (!tag_matches)
67             {
68                 if (die_tag == DW_TAG_class_type || die_tag == DW_TAG_structure_type)
69                     tag_matches = tag == DW_TAG_structure_type || tag == DW_TAG_class_type;
70             }
71             if (tag_matches)
72                 die_offsets.emplace_back(die_info_array[i].cu_offset, die_info_array[i].offset);
73         }
74     }
75 }
76 
77 void
78 DWARFMappedHash::ExtractClassOrStructDIEArray (const DIEInfoArray &die_info_array,
79                                                bool return_implementation_only_if_available,
80                                                DIEArray &die_offsets)
81 {
82     const size_t count = die_info_array.size();
83     for (size_t i=0; i<count; ++i)
84     {
85         const dw_tag_t die_tag = die_info_array[i].tag;
86         if (die_tag == 0 || die_tag == DW_TAG_class_type || die_tag == DW_TAG_structure_type)
87         {
88             if (die_info_array[i].type_flags & eTypeFlagClassIsImplementation)
89             {
90                 if (return_implementation_only_if_available)
91                 {
92                     // We found the one true definition for this class, so
93                     // only return that
94                     die_offsets.clear();
95                     die_offsets.emplace_back(die_info_array[i].cu_offset, die_info_array[i].offset);
96                     return;
97                 }
98                 else
99                 {
100                     // Put the one true definition as the first entry so it
101                     // matches first
102                     die_offsets.emplace(die_offsets.begin(), die_info_array[i].cu_offset, die_info_array[i].offset);
103                 }
104             }
105             else
106             {
107                 die_offsets.emplace_back(die_info_array[i].cu_offset, die_info_array[i].offset);
108             }
109         }
110     }
111 }
112 
113 void
114 DWARFMappedHash::ExtractTypesFromDIEArray (const DIEInfoArray &die_info_array,
115                                            uint32_t type_flag_mask,
116                                            uint32_t type_flag_value,
117                                            DIEArray &die_offsets)
118 {
119     const size_t count = die_info_array.size();
120     for (size_t i=0; i<count; ++i)
121     {
122         if ((die_info_array[i].type_flags & type_flag_mask) == type_flag_value)
123             die_offsets.emplace_back(die_info_array[i].cu_offset, die_info_array[i].offset);
124     }
125 }
126 
127 const char *
128 DWARFMappedHash::GetAtomTypeName (uint16_t atom)
129 {
130     switch (atom)
131     {
132         case eAtomTypeNULL:         return "NULL";
133         case eAtomTypeDIEOffset:    return "die-offset";
134         case eAtomTypeCUOffset:     return "cu-offset";
135         case eAtomTypeTag:          return "die-tag";
136         case eAtomTypeNameFlags:    return "name-flags";
137         case eAtomTypeTypeFlags:    return "type-flags";
138         case eAtomTypeQualNameHash: return "qualified-name-hash";
139     }
140     return "<invalid>";
141 }
142 
143 DWARFMappedHash::DIEInfo::DIEInfo () :
144     cu_offset (DW_INVALID_OFFSET),
145     offset (DW_INVALID_OFFSET),
146     tag (0),
147     type_flags (0),
148     qualified_name_hash (0)
149 {
150 }
151 
152 DWARFMappedHash::DIEInfo::DIEInfo (dw_offset_t c,
153                                    dw_offset_t o,
154                                    dw_tag_t t,
155                                    uint32_t f,
156                                    uint32_t h) :
157     cu_offset (c),
158     offset (o),
159     tag (t),
160     type_flags (f),
161     qualified_name_hash (h)
162 {
163 }
164 
165 DWARFMappedHash::Prologue::Prologue (dw_offset_t _die_base_offset) :
166     die_base_offset (_die_base_offset),
167     atoms(),
168     atom_mask (0),
169     min_hash_data_byte_size(0),
170     hash_data_has_fixed_byte_size(true)
171 {
172     // Define an array of DIE offsets by first defining an array,
173     // and then define the atom type for the array, in this case
174     // we have an array of DIE offsets
175     AppendAtom (eAtomTypeDIEOffset, DW_FORM_data4);
176 }
177 
178 void
179 DWARFMappedHash::Prologue::ClearAtoms ()
180 {
181     hash_data_has_fixed_byte_size = true;
182     min_hash_data_byte_size = 0;
183     atom_mask = 0;
184     atoms.clear();
185 }
186 
187 bool
188 DWARFMappedHash::Prologue::ContainsAtom (AtomType atom_type) const
189 {
190     return (atom_mask & (1u << atom_type)) != 0;
191 }
192 
193 void
194 DWARFMappedHash::Prologue::Clear ()
195 {
196     die_base_offset = 0;
197     ClearAtoms ();
198 }
199 
200 void
201 DWARFMappedHash::Prologue::AppendAtom (AtomType type, dw_form_t form)
202 {
203     atoms.push_back ({type, form});
204     atom_mask |= 1u << type;
205     switch (form)
206     {
207         case DW_FORM_indirect:
208         case DW_FORM_exprloc:
209         case DW_FORM_flag_present:
210         case DW_FORM_ref_sig8:
211             assert (!"Unhandled atom form");
212             break;
213 
214         case DW_FORM_string:
215         case DW_FORM_block:
216         case DW_FORM_block1:
217         case DW_FORM_sdata:
218         case DW_FORM_udata:
219         case DW_FORM_ref_udata:
220         case DW_FORM_GNU_addr_index:
221         case DW_FORM_GNU_str_index:
222             hash_data_has_fixed_byte_size = false;
223             LLVM_FALLTHROUGH;
224         case DW_FORM_flag:
225         case DW_FORM_data1:
226         case DW_FORM_ref1:
227         case DW_FORM_sec_offset:
228             min_hash_data_byte_size += 1;
229             break;
230 
231         case DW_FORM_block2:
232             hash_data_has_fixed_byte_size = false;
233             LLVM_FALLTHROUGH;
234         case DW_FORM_data2:
235         case DW_FORM_ref2:
236             min_hash_data_byte_size += 2;
237             break;
238 
239         case DW_FORM_block4:
240             hash_data_has_fixed_byte_size = false;
241             LLVM_FALLTHROUGH;
242         case DW_FORM_data4:
243         case DW_FORM_ref4:
244         case DW_FORM_addr:
245         case DW_FORM_ref_addr:
246         case DW_FORM_strp:
247             min_hash_data_byte_size += 4;
248             break;
249 
250         case DW_FORM_data8:
251         case DW_FORM_ref8:
252             min_hash_data_byte_size += 8;
253             break;
254 
255     }
256 }
257 
258 lldb::offset_t
259 DWARFMappedHash::Prologue::Read (const lldb_private::DataExtractor &data,
260       lldb::offset_t offset)
261 {
262     ClearAtoms ();
263 
264     die_base_offset = data.GetU32 (&offset);
265 
266     const uint32_t atom_count = data.GetU32 (&offset);
267     if (atom_count == 0x00060003u)
268     {
269         // Old format, deal with contents of old pre-release format
270         while (data.GetU32(&offset))
271             /* do nothing */;
272 
273         // Hardcode to the only known value for now.
274         AppendAtom (eAtomTypeDIEOffset, DW_FORM_data4);
275     }
276     else
277     {
278         for (uint32_t i=0; i<atom_count; ++i)
279         {
280             AtomType type = (AtomType)data.GetU16 (&offset);
281             dw_form_t form = (dw_form_t)data.GetU16 (&offset);
282             AppendAtom (type, form);
283         }
284     }
285     return offset;
286 }
287 
288 size_t
289 DWARFMappedHash::Prologue::GetByteSize () const
290 {
291     // Add an extra count to the atoms size for the zero termination Atom that gets
292     // written to disk
293     return sizeof(die_base_offset) + sizeof(uint32_t) + atoms.size() * sizeof(Atom);
294 }
295 
296 size_t
297 DWARFMappedHash::Prologue::GetMinimumHashDataByteSize () const
298 {
299     return min_hash_data_byte_size;
300 }
301 
302 bool
303 DWARFMappedHash::Prologue::HashDataHasFixedByteSize() const
304 {
305     return hash_data_has_fixed_byte_size;
306 }
307 
308 size_t
309 DWARFMappedHash::Header::GetByteSize (const HeaderData &header_data)
310 {
311     return header_data.GetByteSize();
312 }
313 
314 lldb::offset_t
315 DWARFMappedHash::Header::Read (lldb_private::DataExtractor &data, lldb::offset_t offset)
316 {
317     offset = MappedHash::Header<Prologue>::Read (data, offset);
318     if (offset != UINT32_MAX)
319     {
320         offset = header_data.Read (data, offset);
321     }
322     return offset;
323 }
324 
325 bool
326 DWARFMappedHash::Header::Read (const lldb_private::DWARFDataExtractor &data,
327                                lldb::offset_t *offset_ptr,
328                                DIEInfo &hash_data) const
329 {
330     const size_t num_atoms = header_data.atoms.size();
331     if (num_atoms == 0)
332         return false;
333 
334     for (size_t i=0; i<num_atoms; ++i)
335     {
336         DWARFFormValue form_value (NULL, header_data.atoms[i].form);
337 
338         if (!form_value.ExtractValue(data, offset_ptr))
339             return false;
340 
341         switch (header_data.atoms[i].type)
342         {
343             case eAtomTypeDIEOffset:    // DIE offset, check form for encoding
344                 hash_data.offset = (dw_offset_t)form_value.Reference (header_data.die_base_offset);
345                 break;
346 
347             case eAtomTypeTag:          // DW_TAG value for the DIE
348                 hash_data.tag = (dw_tag_t)form_value.Unsigned ();
349                 break;
350 
351             case eAtomTypeTypeFlags:    // Flags from enum TypeFlags
352                 hash_data.type_flags = (uint32_t)form_value.Unsigned ();
353                 break;
354 
355             case eAtomTypeQualNameHash:    // Flags from enum TypeFlags
356                 hash_data.qualified_name_hash = form_value.Unsigned ();
357                 break;
358 
359             default:
360                 // We can always skip atoms we don't know about
361                 break;
362         }
363     }
364     return true;
365 }
366 
367 void
368 DWARFMappedHash::Header::Dump (lldb_private::Stream& strm, const DIEInfo &hash_data) const
369 {
370     const size_t num_atoms = header_data.atoms.size();
371     for (size_t i=0; i<num_atoms; ++i)
372     {
373         if (i > 0)
374             strm.PutCString (", ");
375 
376         DWARFFormValue form_value (NULL, header_data.atoms[i].form);
377         switch (header_data.atoms[i].type)
378         {
379             case eAtomTypeDIEOffset:    // DIE offset, check form for encoding
380                 strm.Printf ("{0x%8.8x}", hash_data.offset);
381                 break;
382 
383             case eAtomTypeTag:          // DW_TAG value for the DIE
384                 {
385                     const char *tag_cstr = lldb_private::DW_TAG_value_to_name (hash_data.tag);
386                     if (tag_cstr)
387                         strm.PutCString (tag_cstr);
388                     else
389                         strm.Printf ("DW_TAG_(0x%4.4x)", hash_data.tag);
390                 }
391                 break;
392 
393             case eAtomTypeTypeFlags:    // Flags from enum TypeFlags
394                 strm.Printf ("0x%2.2x", hash_data.type_flags);
395                 if (hash_data.type_flags)
396                 {
397                     strm.PutCString (" (");
398                     if (hash_data.type_flags & eTypeFlagClassIsImplementation)
399                         strm.PutCString (" implementation");
400                     strm.PutCString (" )");
401                 }
402                 break;
403 
404             case eAtomTypeQualNameHash:    // Flags from enum TypeFlags
405                 strm.Printf ("0x%8.8x", hash_data.qualified_name_hash);
406                 break;
407 
408             default:
409                 strm.Printf ("AtomType(0x%x)", header_data.atoms[i].type);
410                 break;
411         }
412     }
413 }
414 
415 DWARFMappedHash::MemoryTable::MemoryTable (lldb_private::DWARFDataExtractor &table_data,
416                                            const lldb_private::DWARFDataExtractor &string_table,
417                                            const char *name) :
418     MappedHash::MemoryTable<uint32_t, Header, DIEInfoArray> (table_data),
419     m_data (table_data),
420     m_string_table (string_table),
421     m_name (name)
422 {
423 }
424 
425 const char *
426 DWARFMappedHash::MemoryTable::GetStringForKeyType (KeyType key) const
427 {
428     // The key in the DWARF table is the .debug_str offset for the string
429     return m_string_table.PeekCStr (key);
430 }
431 
432 bool
433 DWARFMappedHash::MemoryTable::ReadHashData (uint32_t hash_data_offset, HashData &hash_data) const
434 {
435     lldb::offset_t offset = hash_data_offset;
436     offset += 4; // Skip string table offset that contains offset of hash name in .debug_str
437     const uint32_t count = m_data.GetU32 (&offset);
438     if (count > 0)
439     {
440         hash_data.resize(count);
441         for (uint32_t i=0; i<count; ++i)
442         {
443             if (!m_header.Read(m_data, &offset, hash_data[i]))
444                 return false;
445         }
446     }
447     else
448         hash_data.clear();
449     return true;
450 }
451 
452 DWARFMappedHash::MemoryTable::Result
453 DWARFMappedHash::MemoryTable::GetHashDataForName (const char *name,
454                                                   lldb::offset_t* hash_data_offset_ptr,
455                                                   Pair &pair) const
456 {
457     pair.key = m_data.GetU32 (hash_data_offset_ptr);
458     pair.value.clear();
459 
460     // If the key is zero, this terminates our chain of HashData objects
461     // for this hash value.
462     if (pair.key == 0)
463         return eResultEndOfHashData;
464 
465     // There definitely should be a string for this string offset, if
466     // there isn't, there is something wrong, return and error
467     const char *strp_cstr = m_string_table.PeekCStr (pair.key);
468     if (strp_cstr == NULL)
469     {
470         *hash_data_offset_ptr = UINT32_MAX;
471         return eResultError;
472     }
473 
474     const uint32_t count = m_data.GetU32 (hash_data_offset_ptr);
475     const size_t min_total_hash_data_size = count * m_header.header_data.GetMinimumHashDataByteSize();
476     if (count > 0 && m_data.ValidOffsetForDataOfSize (*hash_data_offset_ptr, min_total_hash_data_size))
477     {
478         // We have at least one HashData entry, and we have enough
479         // data to parse at least "count" HashData entries.
480 
481         // First make sure the entire C string matches...
482         const bool match = strcmp (name, strp_cstr) == 0;
483 
484         if (!match && m_header.header_data.HashDataHasFixedByteSize())
485         {
486             // If the string doesn't match and we have fixed size data,
487             // we can just add the total byte size of all HashData objects
488             // to the hash data offset and be done...
489             *hash_data_offset_ptr += min_total_hash_data_size;
490         }
491         else
492         {
493             // If the string does match, or we don't have fixed size data
494             // then we need to read the hash data as a stream. If the
495             // string matches we also append all HashData objects to the
496             // value array.
497             for (uint32_t i=0; i<count; ++i)
498             {
499                 DIEInfo die_info;
500                 if (m_header.Read(m_data, hash_data_offset_ptr, die_info))
501                 {
502                     // Only happened if the HashData of the string matched...
503                     if (match)
504                         pair.value.push_back (die_info);
505                 }
506                 else
507                 {
508                     // Something went wrong while reading the data
509                     *hash_data_offset_ptr = UINT32_MAX;
510                     return eResultError;
511                 }
512             }
513         }
514         // Return the correct response depending on if the string matched
515         // or not...
516         if (match)
517             return eResultKeyMatch;     // The key (cstring) matches and we have lookup results!
518         else
519             return eResultKeyMismatch;  // The key doesn't match, this function will get called
520                                         // again for the next key/value or the key terminator
521                                         // which in our case is a zero .debug_str offset.
522     }
523     else
524     {
525         *hash_data_offset_ptr = UINT32_MAX;
526         return eResultError;
527     }
528 }
529 
530 DWARFMappedHash::MemoryTable::Result
531 DWARFMappedHash::MemoryTable::AppendHashDataForRegularExpression (
532         const lldb_private::RegularExpression& regex,
533         lldb::offset_t* hash_data_offset_ptr,
534         Pair &pair) const
535 {
536     pair.key = m_data.GetU32 (hash_data_offset_ptr);
537     // If the key is zero, this terminates our chain of HashData objects
538     // for this hash value.
539     if (pair.key == 0)
540         return eResultEndOfHashData;
541 
542     // There definitely should be a string for this string offset, if
543     // there isn't, there is something wrong, return and error
544     const char *strp_cstr = m_string_table.PeekCStr (pair.key);
545     if (strp_cstr == NULL)
546         return eResultError;
547 
548     const uint32_t count = m_data.GetU32 (hash_data_offset_ptr);
549     const size_t min_total_hash_data_size = count * m_header.header_data.GetMinimumHashDataByteSize();
550     if (count > 0 && m_data.ValidOffsetForDataOfSize (*hash_data_offset_ptr, min_total_hash_data_size))
551     {
552         const bool match = regex.Execute(strp_cstr);
553 
554         if (!match && m_header.header_data.HashDataHasFixedByteSize())
555         {
556             // If the regex doesn't match and we have fixed size data,
557             // we can just add the total byte size of all HashData objects
558             // to the hash data offset and be done...
559             *hash_data_offset_ptr += min_total_hash_data_size;
560         }
561         else
562         {
563             // If the string does match, or we don't have fixed size data
564             // then we need to read the hash data as a stream. If the
565             // string matches we also append all HashData objects to the
566             // value array.
567             for (uint32_t i=0; i<count; ++i)
568             {
569                 DIEInfo die_info;
570                 if (m_header.Read(m_data, hash_data_offset_ptr, die_info))
571                 {
572                     // Only happened if the HashData of the string matched...
573                     if (match)
574                         pair.value.push_back (die_info);
575                 }
576                 else
577                 {
578                     // Something went wrong while reading the data
579                     *hash_data_offset_ptr = UINT32_MAX;
580                     return eResultError;
581                 }
582             }
583         }
584         // Return the correct response depending on if the string matched
585         // or not...
586         if (match)
587             return eResultKeyMatch;     // The key (cstring) matches and we have lookup results!
588         else
589             return eResultKeyMismatch;  // The key doesn't match, this function will get called
590                                         // again for the next key/value or the key terminator
591                                         // which in our case is a zero .debug_str offset.
592     }
593     else
594     {
595         *hash_data_offset_ptr = UINT32_MAX;
596         return eResultError;
597     }
598 }
599 
600 size_t
601 DWARFMappedHash::MemoryTable::AppendAllDIEsThatMatchingRegex (
602         const lldb_private::RegularExpression& regex,
603         DIEInfoArray &die_info_array) const
604 {
605     const uint32_t hash_count = m_header.hashes_count;
606     Pair pair;
607     for (uint32_t offset_idx=0; offset_idx<hash_count; ++offset_idx)
608     {
609         lldb::offset_t hash_data_offset = GetHashDataOffset (offset_idx);
610         while (hash_data_offset != UINT32_MAX)
611         {
612             const lldb::offset_t prev_hash_data_offset = hash_data_offset;
613             Result hash_result = AppendHashDataForRegularExpression (regex, &hash_data_offset, pair);
614             if (prev_hash_data_offset == hash_data_offset)
615                 break;
616 
617             // Check the result of getting our hash data
618             switch (hash_result)
619             {
620                 case eResultKeyMatch:
621                 case eResultKeyMismatch:
622                     // Whether we matches or not, it doesn't matter, we
623                     // keep looking.
624                     break;
625 
626                 case eResultEndOfHashData:
627                 case eResultError:
628                     hash_data_offset = UINT32_MAX;
629                     break;
630             }
631         }
632     }
633     die_info_array.swap (pair.value);
634     return die_info_array.size();
635 }
636 
637 size_t
638 DWARFMappedHash::MemoryTable::AppendAllDIEsInRange (const uint32_t die_offset_start,
639                                                     const uint32_t die_offset_end,
640                                                     DIEInfoArray &die_info_array) const
641 {
642     const uint32_t hash_count = m_header.hashes_count;
643     for (uint32_t offset_idx=0; offset_idx<hash_count; ++offset_idx)
644     {
645         bool done = false;
646         lldb::offset_t hash_data_offset = GetHashDataOffset (offset_idx);
647         while (!done && hash_data_offset != UINT32_MAX)
648         {
649             KeyType key = m_data.GetU32 (&hash_data_offset);
650             // If the key is zero, this terminates our chain of HashData objects
651             // for this hash value.
652             if (key == 0)
653                 break;
654 
655             const uint32_t count = m_data.GetU32 (&hash_data_offset);
656             for (uint32_t i=0; i<count; ++i)
657             {
658                 DIEInfo die_info;
659                 if (m_header.Read(m_data, &hash_data_offset, die_info))
660                 {
661                     if (die_info.offset == 0)
662                         done = true;
663                     if (die_offset_start <= die_info.offset && die_info.offset < die_offset_end)
664                         die_info_array.push_back(die_info);
665                 }
666             }
667         }
668     }
669     return die_info_array.size();
670 }
671 
672 size_t
673 DWARFMappedHash::MemoryTable::FindByName (const char *name, DIEArray &die_offsets)
674 {
675     if (!name || !name[0])
676         return 0;
677 
678     DIEInfoArray die_info_array;
679     if (FindByName(name, die_info_array))
680         DWARFMappedHash::ExtractDIEArray (die_info_array, die_offsets);
681     return die_info_array.size();
682 }
683 
684 size_t
685 DWARFMappedHash::MemoryTable::FindByNameAndTag (const char *name,
686                                                 const dw_tag_t tag,
687                                                 DIEArray &die_offsets)
688 {
689     DIEInfoArray die_info_array;
690     if (FindByName(name, die_info_array))
691         DWARFMappedHash::ExtractDIEArray (die_info_array, tag, die_offsets);
692     return die_info_array.size();
693 }
694 
695 size_t
696 DWARFMappedHash::MemoryTable::FindByNameAndTagAndQualifiedNameHash (const char *name,
697                                                                     const dw_tag_t tag,
698                                                                     const uint32_t qualified_name_hash,
699                                                                     DIEArray &die_offsets)
700 {
701     DIEInfoArray die_info_array;
702     if (FindByName(name, die_info_array))
703         DWARFMappedHash::ExtractDIEArray (die_info_array, tag, qualified_name_hash, die_offsets);
704     return die_info_array.size();
705 }
706 
707 size_t
708 DWARFMappedHash::MemoryTable::FindCompleteObjCClassByName (const char *name,
709                                                            DIEArray &die_offsets,
710                                                            bool must_be_implementation)
711 {
712     DIEInfoArray die_info_array;
713     if (FindByName(name, die_info_array))
714     {
715         if (must_be_implementation && GetHeader().header_data.ContainsAtom (eAtomTypeTypeFlags))
716         {
717             // If we have two atoms, then we have the DIE offset and
718             // the type flags so we can find the objective C class
719             // efficiently.
720             DWARFMappedHash::ExtractTypesFromDIEArray (die_info_array,
721                                                        UINT32_MAX,
722                                                        eTypeFlagClassIsImplementation,
723                                                        die_offsets);
724         }
725         else
726         {
727             // We don't only want the one true definition, so try and see
728             // what we can find, and only return class or struct DIEs.
729             // If we do have the full implementation, then return it alone,
730             // else return all possible matches.
731             const bool return_implementation_only_if_available = true;
732             DWARFMappedHash::ExtractClassOrStructDIEArray (die_info_array,
733                                                            return_implementation_only_if_available,
734                                                            die_offsets);
735         }
736     }
737     return die_offsets.size();
738 }
739 
740 size_t
741 DWARFMappedHash::MemoryTable::FindByName (const char *name, DIEInfoArray &die_info_array)
742 {
743     if (!name || !name[0])
744         return 0;
745 
746     Pair kv_pair;
747     size_t old_size = die_info_array.size();
748     if (Find (name, kv_pair))
749     {
750         die_info_array.swap(kv_pair.value);
751         return die_info_array.size() - old_size;
752     }
753     return 0;
754 }
755