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