1 //===-- HashedNameToDIE.cpp -----------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "HashedNameToDIE.h"
10 #include "llvm/ADT/StringRef.h"
11 
12 using namespace lldb_private::dwarf;
13 
ExtractDIEArray(const DIEInfoArray & die_info_array,llvm::function_ref<bool (DIERef ref)> callback)14 bool DWARFMappedHash::ExtractDIEArray(
15     const DIEInfoArray &die_info_array,
16     llvm::function_ref<bool(DIERef ref)> callback) {
17   const size_t count = die_info_array.size();
18   for (size_t i = 0; i < count; ++i)
19     if (!callback(DIERef(die_info_array[i])))
20       return false;
21   return true;
22 }
23 
ExtractDIEArray(const DIEInfoArray & die_info_array,const dw_tag_t tag,llvm::function_ref<bool (DIERef ref)> callback)24 void DWARFMappedHash::ExtractDIEArray(
25     const DIEInfoArray &die_info_array, const dw_tag_t tag,
26     llvm::function_ref<bool(DIERef ref)> callback) {
27   if (tag == 0) {
28     ExtractDIEArray(die_info_array, callback);
29     return;
30   }
31 
32   const size_t count = die_info_array.size();
33   for (size_t i = 0; i < count; ++i) {
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       if (die_tag == DW_TAG_class_type || die_tag == DW_TAG_structure_type)
38         tag_matches = tag == DW_TAG_structure_type || tag == DW_TAG_class_type;
39     }
40     if (tag_matches) {
41       if (!callback(DIERef(die_info_array[i])))
42         return;
43     }
44   }
45 }
46 
ExtractDIEArray(const DIEInfoArray & die_info_array,const dw_tag_t tag,const uint32_t qualified_name_hash,llvm::function_ref<bool (DIERef ref)> callback)47 void DWARFMappedHash::ExtractDIEArray(
48     const DIEInfoArray &die_info_array, const dw_tag_t tag,
49     const uint32_t qualified_name_hash,
50     llvm::function_ref<bool(DIERef ref)> callback) {
51   if (tag == 0) {
52     ExtractDIEArray(die_info_array, callback);
53     return;
54   }
55 
56   const size_t count = die_info_array.size();
57   for (size_t i = 0; i < count; ++i) {
58     if (qualified_name_hash != die_info_array[i].qualified_name_hash)
59       continue;
60     const dw_tag_t die_tag = die_info_array[i].tag;
61     bool tag_matches = die_tag == 0 || tag == die_tag;
62     if (!tag_matches) {
63       if (die_tag == DW_TAG_class_type || die_tag == DW_TAG_structure_type)
64         tag_matches = tag == DW_TAG_structure_type || tag == DW_TAG_class_type;
65     }
66     if (tag_matches) {
67       if (!callback(DIERef(die_info_array[i])))
68         return;
69     }
70   }
71 }
72 
ExtractClassOrStructDIEArray(const DIEInfoArray & die_info_array,bool return_implementation_only_if_available,llvm::function_ref<bool (DIERef ref)> callback)73 void DWARFMappedHash::ExtractClassOrStructDIEArray(
74     const DIEInfoArray &die_info_array,
75     bool return_implementation_only_if_available,
76     llvm::function_ref<bool(DIERef ref)> callback) {
77   const size_t count = die_info_array.size();
78   for (size_t i = 0; i < count; ++i) {
79     const dw_tag_t die_tag = die_info_array[i].tag;
80     if (!(die_tag == 0 || die_tag == DW_TAG_class_type ||
81           die_tag == DW_TAG_structure_type))
82       continue;
83     bool is_implementation =
84         (die_info_array[i].type_flags & eTypeFlagClassIsImplementation) != 0;
85     if (is_implementation != return_implementation_only_if_available)
86       continue;
87     if (return_implementation_only_if_available) {
88       // We found the one true definition for this class, so only return
89       // that
90       callback(DIERef(die_info_array[i]));
91       return;
92     }
93     if (!callback(DIERef(die_info_array[i])))
94       return;
95   }
96 }
97 
ExtractTypesFromDIEArray(const DIEInfoArray & die_info_array,uint32_t type_flag_mask,uint32_t type_flag_value,llvm::function_ref<bool (DIERef ref)> callback)98 void DWARFMappedHash::ExtractTypesFromDIEArray(
99     const DIEInfoArray &die_info_array, uint32_t type_flag_mask,
100     uint32_t type_flag_value, llvm::function_ref<bool(DIERef ref)> callback) {
101   const size_t count = die_info_array.size();
102   for (size_t i = 0; i < count; ++i) {
103     if ((die_info_array[i].type_flags & type_flag_mask) == type_flag_value) {
104       if (!callback(DIERef(die_info_array[i])))
105         return;
106     }
107   }
108 }
109 
GetAtomTypeName(uint16_t atom)110 const char *DWARFMappedHash::GetAtomTypeName(uint16_t atom) {
111   switch (atom) {
112   case eAtomTypeNULL:
113     return "NULL";
114   case eAtomTypeDIEOffset:
115     return "die-offset";
116   case eAtomTypeCUOffset:
117     return "cu-offset";
118   case eAtomTypeTag:
119     return "die-tag";
120   case eAtomTypeNameFlags:
121     return "name-flags";
122   case eAtomTypeTypeFlags:
123     return "type-flags";
124   case eAtomTypeQualNameHash:
125     return "qualified-name-hash";
126   }
127   return "<invalid>";
128 }
129 
DIEInfo(dw_offset_t o,dw_tag_t t,uint32_t f,uint32_t h)130 DWARFMappedHash::DIEInfo::DIEInfo(dw_offset_t o, dw_tag_t t, uint32_t f,
131                                   uint32_t h)
132     : die_offset(o), tag(t), type_flags(f), qualified_name_hash(h) {}
133 
Prologue(dw_offset_t _die_base_offset)134 DWARFMappedHash::Prologue::Prologue(dw_offset_t _die_base_offset)
135     : die_base_offset(_die_base_offset), atoms() {
136   // Define an array of DIE offsets by first defining an array, and then define
137   // the atom type for the array, in this case we have an array of DIE offsets.
138   AppendAtom(eAtomTypeDIEOffset, DW_FORM_data4);
139 }
140 
ClearAtoms()141 void DWARFMappedHash::Prologue::ClearAtoms() {
142   hash_data_has_fixed_byte_size = true;
143   min_hash_data_byte_size = 0;
144   atom_mask = 0;
145   atoms.clear();
146 }
147 
ContainsAtom(AtomType atom_type) const148 bool DWARFMappedHash::Prologue::ContainsAtom(AtomType atom_type) const {
149   return (atom_mask & (1u << atom_type)) != 0;
150 }
151 
Clear()152 void DWARFMappedHash::Prologue::Clear() {
153   die_base_offset = 0;
154   ClearAtoms();
155 }
156 
AppendAtom(AtomType type,dw_form_t form)157 void DWARFMappedHash::Prologue::AppendAtom(AtomType type, dw_form_t form) {
158   atoms.push_back({type, form});
159   atom_mask |= 1u << type;
160   switch (form) {
161   case DW_FORM_indirect:
162   case DW_FORM_exprloc:
163   case DW_FORM_flag_present:
164   case DW_FORM_ref_sig8:
165     llvm_unreachable("Unhandled atom form");
166 
167   case DW_FORM_addrx:
168   case DW_FORM_string:
169   case DW_FORM_block:
170   case DW_FORM_block1:
171   case DW_FORM_sdata:
172   case DW_FORM_udata:
173   case DW_FORM_ref_udata:
174   case DW_FORM_GNU_addr_index:
175   case DW_FORM_GNU_str_index:
176     hash_data_has_fixed_byte_size = false;
177     [[fallthrough]];
178   case DW_FORM_flag:
179   case DW_FORM_data1:
180   case DW_FORM_ref1:
181   case DW_FORM_sec_offset:
182     min_hash_data_byte_size += 1;
183     break;
184 
185   case DW_FORM_block2:
186     hash_data_has_fixed_byte_size = false;
187     [[fallthrough]];
188   case DW_FORM_data2:
189   case DW_FORM_ref2:
190     min_hash_data_byte_size += 2;
191     break;
192 
193   case DW_FORM_block4:
194     hash_data_has_fixed_byte_size = false;
195     [[fallthrough]];
196   case DW_FORM_data4:
197   case DW_FORM_ref4:
198   case DW_FORM_addr:
199   case DW_FORM_ref_addr:
200   case DW_FORM_strp:
201     min_hash_data_byte_size += 4;
202     break;
203 
204   case DW_FORM_data8:
205   case DW_FORM_ref8:
206     min_hash_data_byte_size += 8;
207     break;
208   }
209 }
210 
211 lldb::offset_t
Read(const lldb_private::DataExtractor & data,lldb::offset_t offset)212 DWARFMappedHash::Prologue::Read(const lldb_private::DataExtractor &data,
213                                 lldb::offset_t offset) {
214   ClearAtoms();
215 
216   die_base_offset = data.GetU32(&offset);
217 
218   const uint32_t atom_count = data.GetU32(&offset);
219   if (atom_count == 0x00060003u) {
220     // Old format, deal with contents of old pre-release format.
221     while (data.GetU32(&offset)) {
222       /* do nothing */;
223     }
224 
225     // Hardcode to the only known value for now.
226     AppendAtom(eAtomTypeDIEOffset, DW_FORM_data4);
227   } else {
228     for (uint32_t i = 0; i < atom_count; ++i) {
229       AtomType type = (AtomType)data.GetU16(&offset);
230       dw_form_t form = (dw_form_t)data.GetU16(&offset);
231       AppendAtom(type, form);
232     }
233   }
234   return offset;
235 }
236 
GetByteSize() const237 size_t DWARFMappedHash::Prologue::GetByteSize() const {
238   // Add an extra count to the atoms size for the zero termination Atom that
239   // gets written to disk.
240   return sizeof(die_base_offset) + sizeof(uint32_t) +
241          atoms.size() * sizeof(Atom);
242 }
243 
GetMinimumHashDataByteSize() const244 size_t DWARFMappedHash::Prologue::GetMinimumHashDataByteSize() const {
245   return min_hash_data_byte_size;
246 }
247 
HashDataHasFixedByteSize() const248 bool DWARFMappedHash::Prologue::HashDataHasFixedByteSize() const {
249   return hash_data_has_fixed_byte_size;
250 }
251 
GetByteSize(const HeaderData & header_data)252 size_t DWARFMappedHash::Header::GetByteSize(const HeaderData &header_data) {
253   return header_data.GetByteSize();
254 }
255 
Read(lldb_private::DataExtractor & data,lldb::offset_t offset)256 lldb::offset_t DWARFMappedHash::Header::Read(lldb_private::DataExtractor &data,
257                                              lldb::offset_t offset) {
258   offset = MappedHash::Header<Prologue>::Read(data, offset);
259   if (offset != UINT32_MAX) {
260     offset = header_data.Read(data, offset);
261   }
262   return offset;
263 }
264 
Read(const lldb_private::DWARFDataExtractor & data,lldb::offset_t * offset_ptr,DIEInfo & hash_data) const265 bool DWARFMappedHash::Header::Read(const lldb_private::DWARFDataExtractor &data,
266                                    lldb::offset_t *offset_ptr,
267                                    DIEInfo &hash_data) const {
268   const size_t num_atoms = header_data.atoms.size();
269   if (num_atoms == 0)
270     return false;
271 
272   for (size_t i = 0; i < num_atoms; ++i) {
273     DWARFFormValue form_value(nullptr, header_data.atoms[i].form);
274 
275     if (!form_value.ExtractValue(data, offset_ptr))
276       return false;
277 
278     switch (header_data.atoms[i].type) {
279     case eAtomTypeDIEOffset: // DIE offset, check form for encoding
280       hash_data.die_offset =
281           DWARFFormValue::IsDataForm(form_value.Form())
282               ? form_value.Unsigned()
283               : form_value.Reference(header_data.die_base_offset);
284       break;
285 
286     case eAtomTypeTag: // DW_TAG value for the DIE
287       hash_data.tag = (dw_tag_t)form_value.Unsigned();
288       break;
289 
290     case eAtomTypeTypeFlags: // Flags from enum TypeFlags
291       hash_data.type_flags = (uint32_t)form_value.Unsigned();
292       break;
293 
294     case eAtomTypeQualNameHash: // Flags from enum TypeFlags
295       hash_data.qualified_name_hash = form_value.Unsigned();
296       break;
297 
298     default:
299       // We can always skip atoms we don't know about.
300       break;
301     }
302   }
303   return hash_data.die_offset != DW_INVALID_OFFSET;
304 }
305 
MemoryTable(lldb_private::DWARFDataExtractor & table_data,const lldb_private::DWARFDataExtractor & string_table,const char * name)306 DWARFMappedHash::MemoryTable::MemoryTable(
307     lldb_private::DWARFDataExtractor &table_data,
308     const lldb_private::DWARFDataExtractor &string_table, const char *name)
309     : MappedHash::MemoryTable<uint32_t, Header, DIEInfoArray>(table_data),
310       m_data(table_data), m_string_table(string_table), m_name(name) {}
311 
312 const char *
GetStringForKeyType(KeyType key) const313 DWARFMappedHash::MemoryTable::GetStringForKeyType(KeyType key) const {
314   // The key in the DWARF table is the .debug_str offset for the string
315   return m_string_table.PeekCStr(key);
316 }
317 
ReadHashData(uint32_t hash_data_offset,HashData & hash_data) const318 bool DWARFMappedHash::MemoryTable::ReadHashData(uint32_t hash_data_offset,
319                                                 HashData &hash_data) const {
320   lldb::offset_t offset = hash_data_offset;
321   // Skip string table offset that contains offset of hash name in .debug_str.
322   offset += 4;
323   const uint32_t count = m_data.GetU32(&offset);
324   if (count > 0) {
325     hash_data.resize(count);
326     for (uint32_t i = 0; i < count; ++i) {
327       if (!m_header.Read(m_data, &offset, hash_data[i]))
328         return false;
329     }
330   } else
331     hash_data.clear();
332   return true;
333 }
334 
335 DWARFMappedHash::MemoryTable::Result
GetHashDataForName(llvm::StringRef name,lldb::offset_t * hash_data_offset_ptr,Pair & pair) const336 DWARFMappedHash::MemoryTable::GetHashDataForName(
337     llvm::StringRef name, lldb::offset_t *hash_data_offset_ptr,
338     Pair &pair) const {
339   pair.key = m_data.GetU32(hash_data_offset_ptr);
340   pair.value.clear();
341 
342   // If the key is zero, this terminates our chain of HashData objects for this
343   // hash value.
344   if (pair.key == 0)
345     return eResultEndOfHashData;
346 
347   // There definitely should be a string for this string offset, if there
348   // isn't, there is something wrong, return and error.
349   const char *strp_cstr = m_string_table.PeekCStr(pair.key);
350   if (strp_cstr == nullptr) {
351     *hash_data_offset_ptr = UINT32_MAX;
352     return eResultError;
353   }
354 
355   const uint32_t count = m_data.GetU32(hash_data_offset_ptr);
356   const size_t min_total_hash_data_size =
357       count * m_header.header_data.GetMinimumHashDataByteSize();
358   if (count > 0 && m_data.ValidOffsetForDataOfSize(*hash_data_offset_ptr,
359                                                    min_total_hash_data_size)) {
360     // We have at least one HashData entry, and we have enough data to parse at
361     // least "count" HashData entries.
362 
363     // First make sure the entire C string matches...
364     const bool match = name == strp_cstr;
365 
366     if (!match && m_header.header_data.HashDataHasFixedByteSize()) {
367       // If the string doesn't match and we have fixed size data, we can just
368       // add the total byte size of all HashData objects to the hash data
369       // offset and be done...
370       *hash_data_offset_ptr += min_total_hash_data_size;
371     } else {
372       // If the string does match, or we don't have fixed size data then we
373       // need to read the hash data as a stream. If the string matches we also
374       // append all HashData objects to the value array.
375       for (uint32_t i = 0; i < count; ++i) {
376         DIEInfo die_info;
377         if (m_header.Read(m_data, hash_data_offset_ptr, die_info)) {
378           // Only happened if the HashData of the string matched...
379           if (match)
380             pair.value.push_back(die_info);
381         } else {
382           // Something went wrong while reading the data.
383           *hash_data_offset_ptr = UINT32_MAX;
384           return eResultError;
385         }
386       }
387     }
388     // Return the correct response depending on if the string matched or not...
389     if (match) {
390       // The key (cstring) matches and we have lookup results!
391       return eResultKeyMatch;
392     } else {
393       // The key doesn't match, this function will get called again for the
394       // next key/value or the key terminator which in our case is a zero
395       // .debug_str offset.
396       return eResultKeyMismatch;
397     }
398   } else {
399     *hash_data_offset_ptr = UINT32_MAX;
400     return eResultError;
401   }
402 }
403 
404 DWARFMappedHash::MemoryTable::Result
AppendHashDataForRegularExpression(const lldb_private::RegularExpression & regex,lldb::offset_t * hash_data_offset_ptr,Pair & pair) const405 DWARFMappedHash::MemoryTable::AppendHashDataForRegularExpression(
406     const lldb_private::RegularExpression &regex,
407     lldb::offset_t *hash_data_offset_ptr, Pair &pair) const {
408   pair.key = m_data.GetU32(hash_data_offset_ptr);
409   // If the key is zero, this terminates our chain of HashData objects for this
410   // hash value.
411   if (pair.key == 0)
412     return eResultEndOfHashData;
413 
414   // There definitely should be a string for this string offset, if there
415   // isn't, there is something wrong, return and error.
416   const char *strp_cstr = m_string_table.PeekCStr(pair.key);
417   if (strp_cstr == nullptr)
418     return eResultError;
419 
420   const uint32_t count = m_data.GetU32(hash_data_offset_ptr);
421   const size_t min_total_hash_data_size =
422       count * m_header.header_data.GetMinimumHashDataByteSize();
423   if (count > 0 && m_data.ValidOffsetForDataOfSize(*hash_data_offset_ptr,
424                                                    min_total_hash_data_size)) {
425     const bool match = regex.Execute(llvm::StringRef(strp_cstr));
426 
427     if (!match && m_header.header_data.HashDataHasFixedByteSize()) {
428       // If the regex doesn't match and we have fixed size data, we can just
429       // add the total byte size of all HashData objects to the hash data
430       // offset and be done...
431       *hash_data_offset_ptr += min_total_hash_data_size;
432     } else {
433       // If the string does match, or we don't have fixed size data then we
434       // need to read the hash data as a stream. If the string matches we also
435       // append all HashData objects to the value array.
436       for (uint32_t i = 0; i < count; ++i) {
437         DIEInfo die_info;
438         if (m_header.Read(m_data, hash_data_offset_ptr, die_info)) {
439           // Only happened if the HashData of the string matched...
440           if (match)
441             pair.value.push_back(die_info);
442         } else {
443           // Something went wrong while reading the data
444           *hash_data_offset_ptr = UINT32_MAX;
445           return eResultError;
446         }
447       }
448     }
449     // Return the correct response depending on if the string matched or not...
450     if (match) {
451       // The key (cstring) matches and we have lookup results!
452       return eResultKeyMatch;
453     } else {
454       // The key doesn't match, this function will get called again for the
455       // next key/value or the key terminator which in our case is a zero
456       // .debug_str offset.
457       return eResultKeyMismatch;
458     }
459   } else {
460     *hash_data_offset_ptr = UINT32_MAX;
461     return eResultError;
462   }
463 }
464 
AppendAllDIEsThatMatchingRegex(const lldb_private::RegularExpression & regex,DIEInfoArray & die_info_array) const465 void DWARFMappedHash::MemoryTable::AppendAllDIEsThatMatchingRegex(
466     const lldb_private::RegularExpression &regex,
467     DIEInfoArray &die_info_array) const {
468   const uint32_t hash_count = m_header.hashes_count;
469   Pair pair;
470   for (uint32_t offset_idx = 0; offset_idx < hash_count; ++offset_idx) {
471     lldb::offset_t hash_data_offset = GetHashDataOffset(offset_idx);
472     while (hash_data_offset != UINT32_MAX) {
473       const lldb::offset_t prev_hash_data_offset = hash_data_offset;
474       Result hash_result =
475           AppendHashDataForRegularExpression(regex, &hash_data_offset, pair);
476       if (prev_hash_data_offset == hash_data_offset)
477         break;
478 
479       // Check the result of getting our hash data.
480       switch (hash_result) {
481       case eResultKeyMatch:
482       case eResultKeyMismatch:
483         // Whether we matches or not, it doesn't matter, we keep looking.
484         break;
485 
486       case eResultEndOfHashData:
487       case eResultError:
488         hash_data_offset = UINT32_MAX;
489         break;
490       }
491     }
492   }
493   die_info_array.swap(pair.value);
494 }
495 
AppendAllDIEsInRange(const uint32_t die_offset_start,const uint32_t die_offset_end,DIEInfoArray & die_info_array) const496 void DWARFMappedHash::MemoryTable::AppendAllDIEsInRange(
497     const uint32_t die_offset_start, const uint32_t die_offset_end,
498     DIEInfoArray &die_info_array) const {
499   const uint32_t hash_count = m_header.hashes_count;
500   for (uint32_t offset_idx = 0; offset_idx < hash_count; ++offset_idx) {
501     bool done = false;
502     lldb::offset_t hash_data_offset = GetHashDataOffset(offset_idx);
503     while (!done && hash_data_offset != UINT32_MAX) {
504       KeyType key = m_data.GetU32(&hash_data_offset);
505       // If the key is zero, this terminates our chain of HashData objects for
506       // this hash value.
507       if (key == 0)
508         break;
509 
510       const uint32_t count = m_data.GetU32(&hash_data_offset);
511       for (uint32_t i = 0; i < count; ++i) {
512         DIEInfo die_info;
513         if (m_header.Read(m_data, &hash_data_offset, die_info)) {
514           if (die_info.die_offset == 0)
515             done = true;
516           if (die_offset_start <= die_info.die_offset &&
517               die_info.die_offset < die_offset_end)
518             die_info_array.push_back(die_info);
519         }
520       }
521     }
522   }
523 }
524 
FindByName(llvm::StringRef name,llvm::function_ref<bool (DIERef ref)> callback)525 bool DWARFMappedHash::MemoryTable::FindByName(
526     llvm::StringRef name, llvm::function_ref<bool(DIERef ref)> callback) {
527   if (name.empty())
528     return true;
529 
530   DIEInfoArray die_info_array;
531   FindByName(name, die_info_array);
532   return DWARFMappedHash::ExtractDIEArray(die_info_array, callback);
533 }
534 
FindByNameAndTag(llvm::StringRef name,const dw_tag_t tag,llvm::function_ref<bool (DIERef ref)> callback)535 void DWARFMappedHash::MemoryTable::FindByNameAndTag(
536     llvm::StringRef name, const dw_tag_t tag,
537     llvm::function_ref<bool(DIERef ref)> callback) {
538   DIEInfoArray die_info_array;
539   FindByName(name, die_info_array);
540   DWARFMappedHash::ExtractDIEArray(die_info_array, tag, callback);
541 }
542 
FindByNameAndTagAndQualifiedNameHash(llvm::StringRef name,const dw_tag_t tag,const uint32_t qualified_name_hash,llvm::function_ref<bool (DIERef ref)> callback)543 void DWARFMappedHash::MemoryTable::FindByNameAndTagAndQualifiedNameHash(
544     llvm::StringRef name, const dw_tag_t tag,
545     const uint32_t qualified_name_hash,
546     llvm::function_ref<bool(DIERef ref)> callback) {
547   DIEInfoArray die_info_array;
548   FindByName(name, die_info_array);
549   DWARFMappedHash::ExtractDIEArray(die_info_array, tag, qualified_name_hash,
550                                    callback);
551 }
552 
FindCompleteObjCClassByName(llvm::StringRef name,llvm::function_ref<bool (DIERef ref)> callback,bool must_be_implementation)553 void DWARFMappedHash::MemoryTable::FindCompleteObjCClassByName(
554     llvm::StringRef name, llvm::function_ref<bool(DIERef ref)> callback,
555     bool must_be_implementation) {
556   DIEInfoArray die_info_array;
557   FindByName(name, die_info_array);
558   if (must_be_implementation &&
559       GetHeader().header_data.ContainsAtom(eAtomTypeTypeFlags)) {
560     // If we have two atoms, then we have the DIE offset and the type flags
561     // so we can find the objective C class efficiently.
562     DWARFMappedHash::ExtractTypesFromDIEArray(
563         die_info_array, UINT32_MAX, eTypeFlagClassIsImplementation, callback);
564     return;
565   }
566   // We don't only want the one true definition, so try and see what we can
567   // find, and only return class or struct DIEs. If we do have the full
568   // implementation, then return it alone, else return all possible
569   // matches.
570   bool found_implementation = false;
571   DWARFMappedHash::ExtractClassOrStructDIEArray(
572       die_info_array, true /*return_implementation_only_if_available*/,
573       [&](DIERef ref) {
574         found_implementation = true;
575         // Here the return value does not matter as we are called at most once.
576         return callback(ref);
577       });
578   if (found_implementation)
579     return;
580   DWARFMappedHash::ExtractClassOrStructDIEArray(
581       die_info_array, false /*return_implementation_only_if_available*/,
582       callback);
583 }
584 
FindByName(llvm::StringRef name,DIEInfoArray & die_info_array)585 void DWARFMappedHash::MemoryTable::FindByName(llvm::StringRef name,
586                                               DIEInfoArray &die_info_array) {
587   if (name.empty())
588     return;
589 
590   Pair kv_pair;
591   if (Find(name, kv_pair))
592     die_info_array.swap(kv_pair.value);
593 }
594