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