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             // Fall through to the cases below...
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             // Fall through to the cases below...
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             // Fall through to the cases below...
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 
350             case eAtomTypeTypeFlags:    // Flags from enum TypeFlags
351                 hash_data.type_flags = (uint32_t)form_value.Unsigned ();
352                 break;
353 
354             case eAtomTypeQualNameHash:    // Flags from enum TypeFlags
355                 hash_data.qualified_name_hash = form_value.Unsigned ();
356                 break;
357 
358             default:
359                 // We can always skip atoms we don't know about
360                 break;
361         }
362     }
363     return true;
364 }
365 
366 void
367 DWARFMappedHash::Header::Dump (lldb_private::Stream& strm, const DIEInfo &hash_data) const
368 {
369     const size_t num_atoms = header_data.atoms.size();
370     for (size_t i=0; i<num_atoms; ++i)
371     {
372         if (i > 0)
373             strm.PutCString (", ");
374 
375         DWARFFormValue form_value (NULL, header_data.atoms[i].form);
376         switch (header_data.atoms[i].type)
377         {
378             case eAtomTypeDIEOffset:    // DIE offset, check form for encoding
379                 strm.Printf ("{0x%8.8x}", hash_data.offset);
380                 break;
381 
382             case eAtomTypeTag:          // DW_TAG value for the DIE
383                 {
384                     const char *tag_cstr = lldb_private::DW_TAG_value_to_name (hash_data.tag);
385                     if (tag_cstr)
386                         strm.PutCString (tag_cstr);
387                     else
388                         strm.Printf ("DW_TAG_(0x%4.4x)", hash_data.tag);
389                 }
390                 break;
391 
392             case eAtomTypeTypeFlags:    // Flags from enum TypeFlags
393                 strm.Printf ("0x%2.2x", hash_data.type_flags);
394                 if (hash_data.type_flags)
395                 {
396                     strm.PutCString (" (");
397                     if (hash_data.type_flags & eTypeFlagClassIsImplementation)
398                         strm.PutCString (" implementation");
399                     strm.PutCString (" )");
400                 }
401                 break;
402 
403             case eAtomTypeQualNameHash:    // Flags from enum TypeFlags
404                 strm.Printf ("0x%8.8x", hash_data.qualified_name_hash);
405                 break;
406 
407             default:
408                 strm.Printf ("AtomType(0x%x)", header_data.atoms[i].type);
409                 break;
410         }
411     }
412 }
413 
414 DWARFMappedHash::MemoryTable::MemoryTable (lldb_private::DWARFDataExtractor &table_data,
415                                            const lldb_private::DWARFDataExtractor &string_table,
416                                            const char *name) :
417     MappedHash::MemoryTable<uint32_t, Header, DIEInfoArray> (table_data),
418     m_data (table_data),
419     m_string_table (string_table),
420     m_name (name)
421 {
422 }
423 
424 const char *
425 DWARFMappedHash::MemoryTable::GetStringForKeyType (KeyType key) const
426 {
427     // The key in the DWARF table is the .debug_str offset for the string
428     return m_string_table.PeekCStr (key);
429 }
430 
431 bool
432 DWARFMappedHash::MemoryTable::ReadHashData (uint32_t hash_data_offset, HashData &hash_data) const
433 {
434     lldb::offset_t offset = hash_data_offset;
435     offset += 4; // Skip string table offset that contains offset of hash name in .debug_str
436     const uint32_t count = m_data.GetU32 (&offset);
437     if (count > 0)
438     {
439         hash_data.resize(count);
440         for (uint32_t i=0; i<count; ++i)
441         {
442             if (!m_header.Read(m_data, &offset, hash_data[i]))
443                 return false;
444         }
445     }
446     else
447         hash_data.clear();
448     return true;
449 }
450 
451 DWARFMappedHash::MemoryTable::Result
452 DWARFMappedHash::MemoryTable::GetHashDataForName (const char *name,
453                                                   lldb::offset_t* hash_data_offset_ptr,
454                                                   Pair &pair) const
455 {
456     pair.key = m_data.GetU32 (hash_data_offset_ptr);
457     pair.value.clear();
458 
459     // If the key is zero, this terminates our chain of HashData objects
460     // for this hash value.
461     if (pair.key == 0)
462         return eResultEndOfHashData;
463 
464     // There definitely should be a string for this string offset, if
465     // there isn't, there is something wrong, return and error
466     const char *strp_cstr = m_string_table.PeekCStr (pair.key);
467     if (strp_cstr == NULL)
468     {
469         *hash_data_offset_ptr = UINT32_MAX;
470         return eResultError;
471     }
472 
473     const uint32_t count = m_data.GetU32 (hash_data_offset_ptr);
474     const size_t min_total_hash_data_size = count * m_header.header_data.GetMinimumHashDataByteSize();
475     if (count > 0 && m_data.ValidOffsetForDataOfSize (*hash_data_offset_ptr, min_total_hash_data_size))
476     {
477         // We have at least one HashData entry, and we have enough
478         // data to parse at least "count" HashData entries.
479 
480         // First make sure the entire C string matches...
481         const bool match = strcmp (name, strp_cstr) == 0;
482 
483         if (!match && m_header.header_data.HashDataHasFixedByteSize())
484         {
485             // If the string doesn't match and we have fixed size data,
486             // we can just add the total byte size of all HashData objects
487             // to the hash data offset and be done...
488             *hash_data_offset_ptr += min_total_hash_data_size;
489         }
490         else
491         {
492             // If the string does match, or we don't have fixed size data
493             // then we need to read the hash data as a stream. If the
494             // string matches we also append all HashData objects to the
495             // value array.
496             for (uint32_t i=0; i<count; ++i)
497             {
498                 DIEInfo die_info;
499                 if (m_header.Read(m_data, hash_data_offset_ptr, die_info))
500                 {
501                     // Only happened if the HashData of the string matched...
502                     if (match)
503                         pair.value.push_back (die_info);
504                 }
505                 else
506                 {
507                     // Something went wrong while reading the data
508                     *hash_data_offset_ptr = UINT32_MAX;
509                     return eResultError;
510                 }
511             }
512         }
513         // Return the correct response depending on if the string matched
514         // or not...
515         if (match)
516             return eResultKeyMatch;     // The key (cstring) matches and we have lookup results!
517         else
518             return eResultKeyMismatch;  // The key doesn't match, this function will get called
519                                         // again for the next key/value or the key terminator
520                                         // which in our case is a zero .debug_str offset.
521     }
522     else
523     {
524         *hash_data_offset_ptr = UINT32_MAX;
525         return eResultError;
526     }
527 }
528 
529 DWARFMappedHash::MemoryTable::Result
530 DWARFMappedHash::MemoryTable::AppendHashDataForRegularExpression (
531         const lldb_private::RegularExpression& regex,
532         lldb::offset_t* hash_data_offset_ptr,
533         Pair &pair) const
534 {
535     pair.key = m_data.GetU32 (hash_data_offset_ptr);
536     // If the key is zero, this terminates our chain of HashData objects
537     // for this hash value.
538     if (pair.key == 0)
539         return eResultEndOfHashData;
540 
541     // There definitely should be a string for this string offset, if
542     // there isn't, there is something wrong, return and error
543     const char *strp_cstr = m_string_table.PeekCStr (pair.key);
544     if (strp_cstr == NULL)
545         return eResultError;
546 
547     const uint32_t count = m_data.GetU32 (hash_data_offset_ptr);
548     const size_t min_total_hash_data_size = count * m_header.header_data.GetMinimumHashDataByteSize();
549     if (count > 0 && m_data.ValidOffsetForDataOfSize (*hash_data_offset_ptr, min_total_hash_data_size))
550     {
551         const bool match = regex.Execute(strp_cstr);
552 
553         if (!match && m_header.header_data.HashDataHasFixedByteSize())
554         {
555             // If the regex doesn't match and we have fixed size data,
556             // we can just add the total byte size of all HashData objects
557             // to the hash data offset and be done...
558             *hash_data_offset_ptr += min_total_hash_data_size;
559         }
560         else
561         {
562             // If the string does match, or we don't have fixed size data
563             // then we need to read the hash data as a stream. If the
564             // string matches we also append all HashData objects to the
565             // value array.
566             for (uint32_t i=0; i<count; ++i)
567             {
568                 DIEInfo die_info;
569                 if (m_header.Read(m_data, hash_data_offset_ptr, die_info))
570                 {
571                     // Only happened if the HashData of the string matched...
572                     if (match)
573                         pair.value.push_back (die_info);
574                 }
575                 else
576                 {
577                     // Something went wrong while reading the data
578                     *hash_data_offset_ptr = UINT32_MAX;
579                     return eResultError;
580                 }
581             }
582         }
583         // Return the correct response depending on if the string matched
584         // or not...
585         if (match)
586             return eResultKeyMatch;     // The key (cstring) matches and we have lookup results!
587         else
588             return eResultKeyMismatch;  // The key doesn't match, this function will get called
589                                         // again for the next key/value or the key terminator
590                                         // which in our case is a zero .debug_str offset.
591     }
592     else
593     {
594         *hash_data_offset_ptr = UINT32_MAX;
595         return eResultError;
596     }
597 }
598 
599 size_t
600 DWARFMappedHash::MemoryTable::AppendAllDIEsThatMatchingRegex (
601         const lldb_private::RegularExpression& regex,
602         DIEInfoArray &die_info_array) const
603 {
604     const uint32_t hash_count = m_header.hashes_count;
605     Pair pair;
606     for (uint32_t offset_idx=0; offset_idx<hash_count; ++offset_idx)
607     {
608         lldb::offset_t hash_data_offset = GetHashDataOffset (offset_idx);
609         while (hash_data_offset != UINT32_MAX)
610         {
611             const lldb::offset_t prev_hash_data_offset = hash_data_offset;
612             Result hash_result = AppendHashDataForRegularExpression (regex, &hash_data_offset, pair);
613             if (prev_hash_data_offset == hash_data_offset)
614                 break;
615 
616             // Check the result of getting our hash data
617             switch (hash_result)
618             {
619                 case eResultKeyMatch:
620                 case eResultKeyMismatch:
621                     // Whether we matches or not, it doesn't matter, we
622                     // keep looking.
623                     break;
624 
625                 case eResultEndOfHashData:
626                 case eResultError:
627                     hash_data_offset = UINT32_MAX;
628                     break;
629             }
630         }
631     }
632     die_info_array.swap (pair.value);
633     return die_info_array.size();
634 }
635 
636 size_t
637 DWARFMappedHash::MemoryTable::AppendAllDIEsInRange (const uint32_t die_offset_start,
638                                                     const uint32_t die_offset_end,
639                                                     DIEInfoArray &die_info_array) const
640 {
641     const uint32_t hash_count = m_header.hashes_count;
642     for (uint32_t offset_idx=0; offset_idx<hash_count; ++offset_idx)
643     {
644         bool done = false;
645         lldb::offset_t hash_data_offset = GetHashDataOffset (offset_idx);
646         while (!done && hash_data_offset != UINT32_MAX)
647         {
648             KeyType key = m_data.GetU32 (&hash_data_offset);
649             // If the key is zero, this terminates our chain of HashData objects
650             // for this hash value.
651             if (key == 0)
652                 break;
653 
654             const uint32_t count = m_data.GetU32 (&hash_data_offset);
655             for (uint32_t i=0; i<count; ++i)
656             {
657                 DIEInfo die_info;
658                 if (m_header.Read(m_data, &hash_data_offset, die_info))
659                 {
660                     if (die_info.offset == 0)
661                         done = true;
662                     if (die_offset_start <= die_info.offset && die_info.offset < die_offset_end)
663                         die_info_array.push_back(die_info);
664                 }
665             }
666         }
667     }
668     return die_info_array.size();
669 }
670 
671 size_t
672 DWARFMappedHash::MemoryTable::FindByName (const char *name, DIEArray &die_offsets)
673 {
674     DIEInfoArray die_info_array;
675     if (FindByName(name, die_info_array))
676         DWARFMappedHash::ExtractDIEArray (die_info_array, die_offsets);
677     return die_info_array.size();
678 }
679 
680 size_t
681 DWARFMappedHash::MemoryTable::FindByNameAndTag (const char *name,
682                                                 const dw_tag_t tag,
683                                                 DIEArray &die_offsets)
684 {
685     DIEInfoArray die_info_array;
686     if (FindByName(name, die_info_array))
687         DWARFMappedHash::ExtractDIEArray (die_info_array, tag, die_offsets);
688     return die_info_array.size();
689 }
690 
691 size_t
692 DWARFMappedHash::MemoryTable::FindByNameAndTagAndQualifiedNameHash (const char *name,
693                                                                     const dw_tag_t tag,
694                                                                     const uint32_t qualified_name_hash,
695                                                                     DIEArray &die_offsets)
696 {
697     DIEInfoArray die_info_array;
698     if (FindByName(name, die_info_array))
699         DWARFMappedHash::ExtractDIEArray (die_info_array, tag, qualified_name_hash, die_offsets);
700     return die_info_array.size();
701 }
702 
703 size_t
704 DWARFMappedHash::MemoryTable::FindCompleteObjCClassByName (const char *name,
705                                                            DIEArray &die_offsets,
706                                                            bool must_be_implementation)
707 {
708     DIEInfoArray die_info_array;
709     if (FindByName(name, die_info_array))
710     {
711         if (must_be_implementation && GetHeader().header_data.ContainsAtom (eAtomTypeTypeFlags))
712         {
713             // If we have two atoms, then we have the DIE offset and
714             // the type flags so we can find the objective C class
715             // efficiently.
716             DWARFMappedHash::ExtractTypesFromDIEArray (die_info_array,
717                                                        UINT32_MAX,
718                                                        eTypeFlagClassIsImplementation,
719                                                        die_offsets);
720         }
721         else
722         {
723             // We don't only want the one true definition, so try and see
724             // what we can find, and only return class or struct DIEs.
725             // If we do have the full implementation, then return it alone,
726             // else return all possible matches.
727             const bool return_implementation_only_if_available = true;
728             DWARFMappedHash::ExtractClassOrStructDIEArray (die_info_array,
729                                                            return_implementation_only_if_available,
730                                                            die_offsets);
731         }
732     }
733     return die_offsets.size();
734 }
735 
736 size_t
737 DWARFMappedHash::MemoryTable::FindByName (const char *name, DIEInfoArray &die_info_array)
738 {
739     Pair kv_pair;
740     size_t old_size = die_info_array.size();
741     if (Find (name, kv_pair))
742     {
743         die_info_array.swap(kv_pair.value);
744         return die_info_array.size() - old_size;
745     }
746     return 0;
747 }
748