xref: /openbsd-src/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.cpp (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1dda28197Spatrick //===-- HashedNameToDIE.cpp -----------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick 
9061da546Spatrick #include "HashedNameToDIE.h"
10061da546Spatrick #include "llvm/ADT/StringRef.h"
11061da546Spatrick 
12*f6aab3d8Srobert using namespace lldb_private::dwarf;
13*f6aab3d8Srobert 
ExtractDIEArray(const DIEInfoArray & die_info_array,llvm::function_ref<bool (DIERef ref)> callback)14dda28197Spatrick bool DWARFMappedHash::ExtractDIEArray(
15dda28197Spatrick     const DIEInfoArray &die_info_array,
16dda28197Spatrick     llvm::function_ref<bool(DIERef ref)> callback) {
17061da546Spatrick   const size_t count = die_info_array.size();
18061da546Spatrick   for (size_t i = 0; i < count; ++i)
19dda28197Spatrick     if (!callback(DIERef(die_info_array[i])))
20dda28197Spatrick       return false;
21dda28197Spatrick   return true;
22061da546Spatrick }
23061da546Spatrick 
ExtractDIEArray(const DIEInfoArray & die_info_array,const dw_tag_t tag,llvm::function_ref<bool (DIERef ref)> callback)24dda28197Spatrick void DWARFMappedHash::ExtractDIEArray(
25dda28197Spatrick     const DIEInfoArray &die_info_array, const dw_tag_t tag,
26dda28197Spatrick     llvm::function_ref<bool(DIERef ref)> callback) {
27061da546Spatrick   if (tag == 0) {
28dda28197Spatrick     ExtractDIEArray(die_info_array, callback);
29dda28197Spatrick     return;
30dda28197Spatrick   }
31dda28197Spatrick 
32061da546Spatrick   const size_t count = die_info_array.size();
33061da546Spatrick   for (size_t i = 0; i < count; ++i) {
34061da546Spatrick     const dw_tag_t die_tag = die_info_array[i].tag;
35061da546Spatrick     bool tag_matches = die_tag == 0 || tag == die_tag;
36061da546Spatrick     if (!tag_matches) {
37061da546Spatrick       if (die_tag == DW_TAG_class_type || die_tag == DW_TAG_structure_type)
38dda28197Spatrick         tag_matches = tag == DW_TAG_structure_type || tag == DW_TAG_class_type;
39061da546Spatrick     }
40dda28197Spatrick     if (tag_matches) {
41dda28197Spatrick       if (!callback(DIERef(die_info_array[i])))
42dda28197Spatrick         return;
43061da546Spatrick     }
44061da546Spatrick   }
45061da546Spatrick }
46061da546Spatrick 
ExtractDIEArray(const DIEInfoArray & die_info_array,const dw_tag_t tag,const uint32_t qualified_name_hash,llvm::function_ref<bool (DIERef ref)> callback)47dda28197Spatrick void DWARFMappedHash::ExtractDIEArray(
48dda28197Spatrick     const DIEInfoArray &die_info_array, const dw_tag_t tag,
49061da546Spatrick     const uint32_t qualified_name_hash,
50dda28197Spatrick     llvm::function_ref<bool(DIERef ref)> callback) {
51061da546Spatrick   if (tag == 0) {
52dda28197Spatrick     ExtractDIEArray(die_info_array, callback);
53dda28197Spatrick     return;
54dda28197Spatrick   }
55dda28197Spatrick 
56061da546Spatrick   const size_t count = die_info_array.size();
57061da546Spatrick   for (size_t i = 0; i < count; ++i) {
58061da546Spatrick     if (qualified_name_hash != die_info_array[i].qualified_name_hash)
59061da546Spatrick       continue;
60061da546Spatrick     const dw_tag_t die_tag = die_info_array[i].tag;
61061da546Spatrick     bool tag_matches = die_tag == 0 || tag == die_tag;
62061da546Spatrick     if (!tag_matches) {
63061da546Spatrick       if (die_tag == DW_TAG_class_type || die_tag == DW_TAG_structure_type)
64dda28197Spatrick         tag_matches = tag == DW_TAG_structure_type || tag == DW_TAG_class_type;
65061da546Spatrick     }
66dda28197Spatrick     if (tag_matches) {
67dda28197Spatrick       if (!callback(DIERef(die_info_array[i])))
68dda28197Spatrick         return;
69061da546Spatrick     }
70061da546Spatrick   }
71061da546Spatrick }
72061da546Spatrick 
ExtractClassOrStructDIEArray(const DIEInfoArray & die_info_array,bool return_implementation_only_if_available,llvm::function_ref<bool (DIERef ref)> callback)73061da546Spatrick void DWARFMappedHash::ExtractClassOrStructDIEArray(
74061da546Spatrick     const DIEInfoArray &die_info_array,
75dda28197Spatrick     bool return_implementation_only_if_available,
76dda28197Spatrick     llvm::function_ref<bool(DIERef ref)> callback) {
77061da546Spatrick   const size_t count = die_info_array.size();
78061da546Spatrick   for (size_t i = 0; i < count; ++i) {
79061da546Spatrick     const dw_tag_t die_tag = die_info_array[i].tag;
80dda28197Spatrick     if (!(die_tag == 0 || die_tag == DW_TAG_class_type ||
81dda28197Spatrick           die_tag == DW_TAG_structure_type))
82dda28197Spatrick       continue;
83dda28197Spatrick     bool is_implementation =
84dda28197Spatrick         (die_info_array[i].type_flags & eTypeFlagClassIsImplementation) != 0;
85dda28197Spatrick     if (is_implementation != return_implementation_only_if_available)
86dda28197Spatrick       continue;
87061da546Spatrick     if (return_implementation_only_if_available) {
88061da546Spatrick       // We found the one true definition for this class, so only return
89061da546Spatrick       // that
90dda28197Spatrick       callback(DIERef(die_info_array[i]));
91061da546Spatrick       return;
92061da546Spatrick     }
93dda28197Spatrick     if (!callback(DIERef(die_info_array[i])))
94dda28197Spatrick       return;
95061da546Spatrick   }
96061da546Spatrick }
97061da546Spatrick 
ExtractTypesFromDIEArray(const DIEInfoArray & die_info_array,uint32_t type_flag_mask,uint32_t type_flag_value,llvm::function_ref<bool (DIERef ref)> callback)98061da546Spatrick void DWARFMappedHash::ExtractTypesFromDIEArray(
99061da546Spatrick     const DIEInfoArray &die_info_array, uint32_t type_flag_mask,
100dda28197Spatrick     uint32_t type_flag_value, llvm::function_ref<bool(DIERef ref)> callback) {
101061da546Spatrick   const size_t count = die_info_array.size();
102061da546Spatrick   for (size_t i = 0; i < count; ++i) {
103dda28197Spatrick     if ((die_info_array[i].type_flags & type_flag_mask) == type_flag_value) {
104dda28197Spatrick       if (!callback(DIERef(die_info_array[i])))
105dda28197Spatrick         return;
106dda28197Spatrick     }
107061da546Spatrick   }
108061da546Spatrick }
109061da546Spatrick 
GetAtomTypeName(uint16_t atom)110061da546Spatrick const char *DWARFMappedHash::GetAtomTypeName(uint16_t atom) {
111061da546Spatrick   switch (atom) {
112061da546Spatrick   case eAtomTypeNULL:
113061da546Spatrick     return "NULL";
114061da546Spatrick   case eAtomTypeDIEOffset:
115061da546Spatrick     return "die-offset";
116061da546Spatrick   case eAtomTypeCUOffset:
117061da546Spatrick     return "cu-offset";
118061da546Spatrick   case eAtomTypeTag:
119061da546Spatrick     return "die-tag";
120061da546Spatrick   case eAtomTypeNameFlags:
121061da546Spatrick     return "name-flags";
122061da546Spatrick   case eAtomTypeTypeFlags:
123061da546Spatrick     return "type-flags";
124061da546Spatrick   case eAtomTypeQualNameHash:
125061da546Spatrick     return "qualified-name-hash";
126061da546Spatrick   }
127061da546Spatrick   return "<invalid>";
128061da546Spatrick }
129061da546Spatrick 
DIEInfo(dw_offset_t o,dw_tag_t t,uint32_t f,uint32_t h)130061da546Spatrick DWARFMappedHash::DIEInfo::DIEInfo(dw_offset_t o, dw_tag_t t, uint32_t f,
131061da546Spatrick                                   uint32_t h)
132061da546Spatrick     : die_offset(o), tag(t), type_flags(f), qualified_name_hash(h) {}
133061da546Spatrick 
Prologue(dw_offset_t _die_base_offset)134061da546Spatrick DWARFMappedHash::Prologue::Prologue(dw_offset_t _die_base_offset)
135be691f3bSpatrick     : die_base_offset(_die_base_offset), atoms() {
136061da546Spatrick   // Define an array of DIE offsets by first defining an array, and then define
137061da546Spatrick   // the atom type for the array, in this case we have an array of DIE offsets.
138061da546Spatrick   AppendAtom(eAtomTypeDIEOffset, DW_FORM_data4);
139061da546Spatrick }
140061da546Spatrick 
ClearAtoms()141061da546Spatrick void DWARFMappedHash::Prologue::ClearAtoms() {
142061da546Spatrick   hash_data_has_fixed_byte_size = true;
143061da546Spatrick   min_hash_data_byte_size = 0;
144061da546Spatrick   atom_mask = 0;
145061da546Spatrick   atoms.clear();
146061da546Spatrick }
147061da546Spatrick 
ContainsAtom(AtomType atom_type) const148061da546Spatrick bool DWARFMappedHash::Prologue::ContainsAtom(AtomType atom_type) const {
149061da546Spatrick   return (atom_mask & (1u << atom_type)) != 0;
150061da546Spatrick }
151061da546Spatrick 
Clear()152061da546Spatrick void DWARFMappedHash::Prologue::Clear() {
153061da546Spatrick   die_base_offset = 0;
154061da546Spatrick   ClearAtoms();
155061da546Spatrick }
156061da546Spatrick 
AppendAtom(AtomType type,dw_form_t form)157061da546Spatrick void DWARFMappedHash::Prologue::AppendAtom(AtomType type, dw_form_t form) {
158061da546Spatrick   atoms.push_back({type, form});
159061da546Spatrick   atom_mask |= 1u << type;
160061da546Spatrick   switch (form) {
161061da546Spatrick   case DW_FORM_indirect:
162061da546Spatrick   case DW_FORM_exprloc:
163061da546Spatrick   case DW_FORM_flag_present:
164061da546Spatrick   case DW_FORM_ref_sig8:
165061da546Spatrick     llvm_unreachable("Unhandled atom form");
166061da546Spatrick 
167061da546Spatrick   case DW_FORM_addrx:
168061da546Spatrick   case DW_FORM_string:
169061da546Spatrick   case DW_FORM_block:
170061da546Spatrick   case DW_FORM_block1:
171061da546Spatrick   case DW_FORM_sdata:
172061da546Spatrick   case DW_FORM_udata:
173061da546Spatrick   case DW_FORM_ref_udata:
174061da546Spatrick   case DW_FORM_GNU_addr_index:
175061da546Spatrick   case DW_FORM_GNU_str_index:
176061da546Spatrick     hash_data_has_fixed_byte_size = false;
177*f6aab3d8Srobert     [[fallthrough]];
178061da546Spatrick   case DW_FORM_flag:
179061da546Spatrick   case DW_FORM_data1:
180061da546Spatrick   case DW_FORM_ref1:
181061da546Spatrick   case DW_FORM_sec_offset:
182061da546Spatrick     min_hash_data_byte_size += 1;
183061da546Spatrick     break;
184061da546Spatrick 
185061da546Spatrick   case DW_FORM_block2:
186061da546Spatrick     hash_data_has_fixed_byte_size = false;
187*f6aab3d8Srobert     [[fallthrough]];
188061da546Spatrick   case DW_FORM_data2:
189061da546Spatrick   case DW_FORM_ref2:
190061da546Spatrick     min_hash_data_byte_size += 2;
191061da546Spatrick     break;
192061da546Spatrick 
193061da546Spatrick   case DW_FORM_block4:
194061da546Spatrick     hash_data_has_fixed_byte_size = false;
195*f6aab3d8Srobert     [[fallthrough]];
196061da546Spatrick   case DW_FORM_data4:
197061da546Spatrick   case DW_FORM_ref4:
198061da546Spatrick   case DW_FORM_addr:
199061da546Spatrick   case DW_FORM_ref_addr:
200061da546Spatrick   case DW_FORM_strp:
201061da546Spatrick     min_hash_data_byte_size += 4;
202061da546Spatrick     break;
203061da546Spatrick 
204061da546Spatrick   case DW_FORM_data8:
205061da546Spatrick   case DW_FORM_ref8:
206061da546Spatrick     min_hash_data_byte_size += 8;
207061da546Spatrick     break;
208061da546Spatrick   }
209061da546Spatrick }
210061da546Spatrick 
211061da546Spatrick lldb::offset_t
Read(const lldb_private::DataExtractor & data,lldb::offset_t offset)212061da546Spatrick DWARFMappedHash::Prologue::Read(const lldb_private::DataExtractor &data,
213061da546Spatrick                                 lldb::offset_t offset) {
214061da546Spatrick   ClearAtoms();
215061da546Spatrick 
216061da546Spatrick   die_base_offset = data.GetU32(&offset);
217061da546Spatrick 
218061da546Spatrick   const uint32_t atom_count = data.GetU32(&offset);
219061da546Spatrick   if (atom_count == 0x00060003u) {
220061da546Spatrick     // Old format, deal with contents of old pre-release format.
221061da546Spatrick     while (data.GetU32(&offset)) {
222061da546Spatrick       /* do nothing */;
223061da546Spatrick     }
224061da546Spatrick 
225061da546Spatrick     // Hardcode to the only known value for now.
226061da546Spatrick     AppendAtom(eAtomTypeDIEOffset, DW_FORM_data4);
227061da546Spatrick   } else {
228061da546Spatrick     for (uint32_t i = 0; i < atom_count; ++i) {
229061da546Spatrick       AtomType type = (AtomType)data.GetU16(&offset);
230061da546Spatrick       dw_form_t form = (dw_form_t)data.GetU16(&offset);
231061da546Spatrick       AppendAtom(type, form);
232061da546Spatrick     }
233061da546Spatrick   }
234061da546Spatrick   return offset;
235061da546Spatrick }
236061da546Spatrick 
GetByteSize() const237061da546Spatrick size_t DWARFMappedHash::Prologue::GetByteSize() const {
238061da546Spatrick   // Add an extra count to the atoms size for the zero termination Atom that
239061da546Spatrick   // gets written to disk.
240061da546Spatrick   return sizeof(die_base_offset) + sizeof(uint32_t) +
241061da546Spatrick          atoms.size() * sizeof(Atom);
242061da546Spatrick }
243061da546Spatrick 
GetMinimumHashDataByteSize() const244061da546Spatrick size_t DWARFMappedHash::Prologue::GetMinimumHashDataByteSize() const {
245061da546Spatrick   return min_hash_data_byte_size;
246061da546Spatrick }
247061da546Spatrick 
HashDataHasFixedByteSize() const248061da546Spatrick bool DWARFMappedHash::Prologue::HashDataHasFixedByteSize() const {
249061da546Spatrick   return hash_data_has_fixed_byte_size;
250061da546Spatrick }
251061da546Spatrick 
GetByteSize(const HeaderData & header_data)252061da546Spatrick size_t DWARFMappedHash::Header::GetByteSize(const HeaderData &header_data) {
253061da546Spatrick   return header_data.GetByteSize();
254061da546Spatrick }
255061da546Spatrick 
Read(lldb_private::DataExtractor & data,lldb::offset_t offset)256061da546Spatrick lldb::offset_t DWARFMappedHash::Header::Read(lldb_private::DataExtractor &data,
257061da546Spatrick                                              lldb::offset_t offset) {
258061da546Spatrick   offset = MappedHash::Header<Prologue>::Read(data, offset);
259061da546Spatrick   if (offset != UINT32_MAX) {
260061da546Spatrick     offset = header_data.Read(data, offset);
261061da546Spatrick   }
262061da546Spatrick   return offset;
263061da546Spatrick }
264061da546Spatrick 
Read(const lldb_private::DWARFDataExtractor & data,lldb::offset_t * offset_ptr,DIEInfo & hash_data) const265061da546Spatrick bool DWARFMappedHash::Header::Read(const lldb_private::DWARFDataExtractor &data,
266061da546Spatrick                                    lldb::offset_t *offset_ptr,
267061da546Spatrick                                    DIEInfo &hash_data) const {
268061da546Spatrick   const size_t num_atoms = header_data.atoms.size();
269061da546Spatrick   if (num_atoms == 0)
270061da546Spatrick     return false;
271061da546Spatrick 
272061da546Spatrick   for (size_t i = 0; i < num_atoms; ++i) {
273061da546Spatrick     DWARFFormValue form_value(nullptr, header_data.atoms[i].form);
274061da546Spatrick 
275061da546Spatrick     if (!form_value.ExtractValue(data, offset_ptr))
276061da546Spatrick       return false;
277061da546Spatrick 
278061da546Spatrick     switch (header_data.atoms[i].type) {
279061da546Spatrick     case eAtomTypeDIEOffset: // DIE offset, check form for encoding
280061da546Spatrick       hash_data.die_offset =
281061da546Spatrick           DWARFFormValue::IsDataForm(form_value.Form())
282061da546Spatrick               ? form_value.Unsigned()
283061da546Spatrick               : form_value.Reference(header_data.die_base_offset);
284061da546Spatrick       break;
285061da546Spatrick 
286061da546Spatrick     case eAtomTypeTag: // DW_TAG value for the DIE
287061da546Spatrick       hash_data.tag = (dw_tag_t)form_value.Unsigned();
288061da546Spatrick       break;
289061da546Spatrick 
290061da546Spatrick     case eAtomTypeTypeFlags: // Flags from enum TypeFlags
291061da546Spatrick       hash_data.type_flags = (uint32_t)form_value.Unsigned();
292061da546Spatrick       break;
293061da546Spatrick 
294061da546Spatrick     case eAtomTypeQualNameHash: // Flags from enum TypeFlags
295061da546Spatrick       hash_data.qualified_name_hash = form_value.Unsigned();
296061da546Spatrick       break;
297061da546Spatrick 
298061da546Spatrick     default:
299061da546Spatrick       // We can always skip atoms we don't know about.
300061da546Spatrick       break;
301061da546Spatrick     }
302061da546Spatrick   }
303061da546Spatrick   return hash_data.die_offset != DW_INVALID_OFFSET;
304061da546Spatrick }
305061da546Spatrick 
MemoryTable(lldb_private::DWARFDataExtractor & table_data,const lldb_private::DWARFDataExtractor & string_table,const char * name)306061da546Spatrick DWARFMappedHash::MemoryTable::MemoryTable(
307061da546Spatrick     lldb_private::DWARFDataExtractor &table_data,
308061da546Spatrick     const lldb_private::DWARFDataExtractor &string_table, const char *name)
309061da546Spatrick     : MappedHash::MemoryTable<uint32_t, Header, DIEInfoArray>(table_data),
310061da546Spatrick       m_data(table_data), m_string_table(string_table), m_name(name) {}
311061da546Spatrick 
312061da546Spatrick const char *
GetStringForKeyType(KeyType key) const313061da546Spatrick DWARFMappedHash::MemoryTable::GetStringForKeyType(KeyType key) const {
314061da546Spatrick   // The key in the DWARF table is the .debug_str offset for the string
315061da546Spatrick   return m_string_table.PeekCStr(key);
316061da546Spatrick }
317061da546Spatrick 
ReadHashData(uint32_t hash_data_offset,HashData & hash_data) const318061da546Spatrick bool DWARFMappedHash::MemoryTable::ReadHashData(uint32_t hash_data_offset,
319061da546Spatrick                                                 HashData &hash_data) const {
320061da546Spatrick   lldb::offset_t offset = hash_data_offset;
321061da546Spatrick   // Skip string table offset that contains offset of hash name in .debug_str.
322061da546Spatrick   offset += 4;
323061da546Spatrick   const uint32_t count = m_data.GetU32(&offset);
324061da546Spatrick   if (count > 0) {
325061da546Spatrick     hash_data.resize(count);
326061da546Spatrick     for (uint32_t i = 0; i < count; ++i) {
327061da546Spatrick       if (!m_header.Read(m_data, &offset, hash_data[i]))
328061da546Spatrick         return false;
329061da546Spatrick     }
330061da546Spatrick   } else
331061da546Spatrick     hash_data.clear();
332061da546Spatrick   return true;
333061da546Spatrick }
334061da546Spatrick 
335061da546Spatrick DWARFMappedHash::MemoryTable::Result
GetHashDataForName(llvm::StringRef name,lldb::offset_t * hash_data_offset_ptr,Pair & pair) const336061da546Spatrick DWARFMappedHash::MemoryTable::GetHashDataForName(
337061da546Spatrick     llvm::StringRef name, lldb::offset_t *hash_data_offset_ptr,
338061da546Spatrick     Pair &pair) const {
339061da546Spatrick   pair.key = m_data.GetU32(hash_data_offset_ptr);
340061da546Spatrick   pair.value.clear();
341061da546Spatrick 
342061da546Spatrick   // If the key is zero, this terminates our chain of HashData objects for this
343061da546Spatrick   // hash value.
344061da546Spatrick   if (pair.key == 0)
345061da546Spatrick     return eResultEndOfHashData;
346061da546Spatrick 
347061da546Spatrick   // There definitely should be a string for this string offset, if there
348061da546Spatrick   // isn't, there is something wrong, return and error.
349061da546Spatrick   const char *strp_cstr = m_string_table.PeekCStr(pair.key);
350061da546Spatrick   if (strp_cstr == nullptr) {
351061da546Spatrick     *hash_data_offset_ptr = UINT32_MAX;
352061da546Spatrick     return eResultError;
353061da546Spatrick   }
354061da546Spatrick 
355061da546Spatrick   const uint32_t count = m_data.GetU32(hash_data_offset_ptr);
356061da546Spatrick   const size_t min_total_hash_data_size =
357061da546Spatrick       count * m_header.header_data.GetMinimumHashDataByteSize();
358061da546Spatrick   if (count > 0 && m_data.ValidOffsetForDataOfSize(*hash_data_offset_ptr,
359061da546Spatrick                                                    min_total_hash_data_size)) {
360061da546Spatrick     // We have at least one HashData entry, and we have enough data to parse at
361061da546Spatrick     // least "count" HashData entries.
362061da546Spatrick 
363061da546Spatrick     // First make sure the entire C string matches...
364061da546Spatrick     const bool match = name == strp_cstr;
365061da546Spatrick 
366061da546Spatrick     if (!match && m_header.header_data.HashDataHasFixedByteSize()) {
367061da546Spatrick       // If the string doesn't match and we have fixed size data, we can just
368061da546Spatrick       // add the total byte size of all HashData objects to the hash data
369061da546Spatrick       // offset and be done...
370061da546Spatrick       *hash_data_offset_ptr += min_total_hash_data_size;
371061da546Spatrick     } else {
372061da546Spatrick       // If the string does match, or we don't have fixed size data then we
373061da546Spatrick       // need to read the hash data as a stream. If the string matches we also
374061da546Spatrick       // append all HashData objects to the value array.
375061da546Spatrick       for (uint32_t i = 0; i < count; ++i) {
376061da546Spatrick         DIEInfo die_info;
377061da546Spatrick         if (m_header.Read(m_data, hash_data_offset_ptr, die_info)) {
378061da546Spatrick           // Only happened if the HashData of the string matched...
379061da546Spatrick           if (match)
380061da546Spatrick             pair.value.push_back(die_info);
381061da546Spatrick         } else {
382061da546Spatrick           // Something went wrong while reading the data.
383061da546Spatrick           *hash_data_offset_ptr = UINT32_MAX;
384061da546Spatrick           return eResultError;
385061da546Spatrick         }
386061da546Spatrick       }
387061da546Spatrick     }
388061da546Spatrick     // Return the correct response depending on if the string matched or not...
389061da546Spatrick     if (match) {
390061da546Spatrick       // The key (cstring) matches and we have lookup results!
391061da546Spatrick       return eResultKeyMatch;
392061da546Spatrick     } else {
393061da546Spatrick       // The key doesn't match, this function will get called again for the
394061da546Spatrick       // next key/value or the key terminator which in our case is a zero
395061da546Spatrick       // .debug_str offset.
396061da546Spatrick       return eResultKeyMismatch;
397061da546Spatrick     }
398061da546Spatrick   } else {
399061da546Spatrick     *hash_data_offset_ptr = UINT32_MAX;
400061da546Spatrick     return eResultError;
401061da546Spatrick   }
402061da546Spatrick }
403061da546Spatrick 
404061da546Spatrick DWARFMappedHash::MemoryTable::Result
AppendHashDataForRegularExpression(const lldb_private::RegularExpression & regex,lldb::offset_t * hash_data_offset_ptr,Pair & pair) const405061da546Spatrick DWARFMappedHash::MemoryTable::AppendHashDataForRegularExpression(
406061da546Spatrick     const lldb_private::RegularExpression &regex,
407061da546Spatrick     lldb::offset_t *hash_data_offset_ptr, Pair &pair) const {
408061da546Spatrick   pair.key = m_data.GetU32(hash_data_offset_ptr);
409061da546Spatrick   // If the key is zero, this terminates our chain of HashData objects for this
410061da546Spatrick   // hash value.
411061da546Spatrick   if (pair.key == 0)
412061da546Spatrick     return eResultEndOfHashData;
413061da546Spatrick 
414061da546Spatrick   // There definitely should be a string for this string offset, if there
415061da546Spatrick   // isn't, there is something wrong, return and error.
416061da546Spatrick   const char *strp_cstr = m_string_table.PeekCStr(pair.key);
417061da546Spatrick   if (strp_cstr == nullptr)
418061da546Spatrick     return eResultError;
419061da546Spatrick 
420061da546Spatrick   const uint32_t count = m_data.GetU32(hash_data_offset_ptr);
421061da546Spatrick   const size_t min_total_hash_data_size =
422061da546Spatrick       count * m_header.header_data.GetMinimumHashDataByteSize();
423061da546Spatrick   if (count > 0 && m_data.ValidOffsetForDataOfSize(*hash_data_offset_ptr,
424061da546Spatrick                                                    min_total_hash_data_size)) {
425061da546Spatrick     const bool match = regex.Execute(llvm::StringRef(strp_cstr));
426061da546Spatrick 
427061da546Spatrick     if (!match && m_header.header_data.HashDataHasFixedByteSize()) {
428061da546Spatrick       // If the regex doesn't match and we have fixed size data, we can just
429061da546Spatrick       // add the total byte size of all HashData objects to the hash data
430061da546Spatrick       // offset and be done...
431061da546Spatrick       *hash_data_offset_ptr += min_total_hash_data_size;
432061da546Spatrick     } else {
433061da546Spatrick       // If the string does match, or we don't have fixed size data then we
434061da546Spatrick       // need to read the hash data as a stream. If the string matches we also
435061da546Spatrick       // append all HashData objects to the value array.
436061da546Spatrick       for (uint32_t i = 0; i < count; ++i) {
437061da546Spatrick         DIEInfo die_info;
438061da546Spatrick         if (m_header.Read(m_data, hash_data_offset_ptr, die_info)) {
439061da546Spatrick           // Only happened if the HashData of the string matched...
440061da546Spatrick           if (match)
441061da546Spatrick             pair.value.push_back(die_info);
442061da546Spatrick         } else {
443061da546Spatrick           // Something went wrong while reading the data
444061da546Spatrick           *hash_data_offset_ptr = UINT32_MAX;
445061da546Spatrick           return eResultError;
446061da546Spatrick         }
447061da546Spatrick       }
448061da546Spatrick     }
449061da546Spatrick     // Return the correct response depending on if the string matched or not...
450061da546Spatrick     if (match) {
451061da546Spatrick       // The key (cstring) matches and we have lookup results!
452061da546Spatrick       return eResultKeyMatch;
453061da546Spatrick     } else {
454061da546Spatrick       // The key doesn't match, this function will get called again for the
455061da546Spatrick       // next key/value or the key terminator which in our case is a zero
456061da546Spatrick       // .debug_str offset.
457061da546Spatrick       return eResultKeyMismatch;
458061da546Spatrick     }
459061da546Spatrick   } else {
460061da546Spatrick     *hash_data_offset_ptr = UINT32_MAX;
461061da546Spatrick     return eResultError;
462061da546Spatrick   }
463061da546Spatrick }
464061da546Spatrick 
AppendAllDIEsThatMatchingRegex(const lldb_private::RegularExpression & regex,DIEInfoArray & die_info_array) const465dda28197Spatrick void DWARFMappedHash::MemoryTable::AppendAllDIEsThatMatchingRegex(
466061da546Spatrick     const lldb_private::RegularExpression &regex,
467061da546Spatrick     DIEInfoArray &die_info_array) const {
468061da546Spatrick   const uint32_t hash_count = m_header.hashes_count;
469061da546Spatrick   Pair pair;
470061da546Spatrick   for (uint32_t offset_idx = 0; offset_idx < hash_count; ++offset_idx) {
471061da546Spatrick     lldb::offset_t hash_data_offset = GetHashDataOffset(offset_idx);
472061da546Spatrick     while (hash_data_offset != UINT32_MAX) {
473061da546Spatrick       const lldb::offset_t prev_hash_data_offset = hash_data_offset;
474061da546Spatrick       Result hash_result =
475061da546Spatrick           AppendHashDataForRegularExpression(regex, &hash_data_offset, pair);
476061da546Spatrick       if (prev_hash_data_offset == hash_data_offset)
477061da546Spatrick         break;
478061da546Spatrick 
479061da546Spatrick       // Check the result of getting our hash data.
480061da546Spatrick       switch (hash_result) {
481061da546Spatrick       case eResultKeyMatch:
482061da546Spatrick       case eResultKeyMismatch:
483061da546Spatrick         // Whether we matches or not, it doesn't matter, we keep looking.
484061da546Spatrick         break;
485061da546Spatrick 
486061da546Spatrick       case eResultEndOfHashData:
487061da546Spatrick       case eResultError:
488061da546Spatrick         hash_data_offset = UINT32_MAX;
489061da546Spatrick         break;
490061da546Spatrick       }
491061da546Spatrick     }
492061da546Spatrick   }
493061da546Spatrick   die_info_array.swap(pair.value);
494061da546Spatrick }
495061da546Spatrick 
AppendAllDIEsInRange(const uint32_t die_offset_start,const uint32_t die_offset_end,DIEInfoArray & die_info_array) const496dda28197Spatrick void DWARFMappedHash::MemoryTable::AppendAllDIEsInRange(
497061da546Spatrick     const uint32_t die_offset_start, const uint32_t die_offset_end,
498061da546Spatrick     DIEInfoArray &die_info_array) const {
499061da546Spatrick   const uint32_t hash_count = m_header.hashes_count;
500061da546Spatrick   for (uint32_t offset_idx = 0; offset_idx < hash_count; ++offset_idx) {
501061da546Spatrick     bool done = false;
502061da546Spatrick     lldb::offset_t hash_data_offset = GetHashDataOffset(offset_idx);
503061da546Spatrick     while (!done && hash_data_offset != UINT32_MAX) {
504061da546Spatrick       KeyType key = m_data.GetU32(&hash_data_offset);
505061da546Spatrick       // If the key is zero, this terminates our chain of HashData objects for
506061da546Spatrick       // this hash value.
507061da546Spatrick       if (key == 0)
508061da546Spatrick         break;
509061da546Spatrick 
510061da546Spatrick       const uint32_t count = m_data.GetU32(&hash_data_offset);
511061da546Spatrick       for (uint32_t i = 0; i < count; ++i) {
512061da546Spatrick         DIEInfo die_info;
513061da546Spatrick         if (m_header.Read(m_data, &hash_data_offset, die_info)) {
514061da546Spatrick           if (die_info.die_offset == 0)
515061da546Spatrick             done = true;
516061da546Spatrick           if (die_offset_start <= die_info.die_offset &&
517061da546Spatrick               die_info.die_offset < die_offset_end)
518061da546Spatrick             die_info_array.push_back(die_info);
519061da546Spatrick         }
520061da546Spatrick       }
521061da546Spatrick     }
522061da546Spatrick   }
523061da546Spatrick }
524061da546Spatrick 
FindByName(llvm::StringRef name,llvm::function_ref<bool (DIERef ref)> callback)525dda28197Spatrick bool DWARFMappedHash::MemoryTable::FindByName(
526dda28197Spatrick     llvm::StringRef name, llvm::function_ref<bool(DIERef ref)> callback) {
527061da546Spatrick   if (name.empty())
528dda28197Spatrick     return true;
529061da546Spatrick 
530061da546Spatrick   DIEInfoArray die_info_array;
531dda28197Spatrick   FindByName(name, die_info_array);
532dda28197Spatrick   return DWARFMappedHash::ExtractDIEArray(die_info_array, callback);
533061da546Spatrick }
534061da546Spatrick 
FindByNameAndTag(llvm::StringRef name,const dw_tag_t tag,llvm::function_ref<bool (DIERef ref)> callback)535dda28197Spatrick void DWARFMappedHash::MemoryTable::FindByNameAndTag(
536061da546Spatrick     llvm::StringRef name, const dw_tag_t tag,
537dda28197Spatrick     llvm::function_ref<bool(DIERef ref)> callback) {
538061da546Spatrick   DIEInfoArray die_info_array;
539dda28197Spatrick   FindByName(name, die_info_array);
540dda28197Spatrick   DWARFMappedHash::ExtractDIEArray(die_info_array, tag, callback);
541061da546Spatrick }
542061da546Spatrick 
FindByNameAndTagAndQualifiedNameHash(llvm::StringRef name,const dw_tag_t tag,const uint32_t qualified_name_hash,llvm::function_ref<bool (DIERef ref)> callback)543dda28197Spatrick void DWARFMappedHash::MemoryTable::FindByNameAndTagAndQualifiedNameHash(
544dda28197Spatrick     llvm::StringRef name, const dw_tag_t tag,
545dda28197Spatrick     const uint32_t qualified_name_hash,
546dda28197Spatrick     llvm::function_ref<bool(DIERef ref)> callback) {
547061da546Spatrick   DIEInfoArray die_info_array;
548dda28197Spatrick   FindByName(name, die_info_array);
549dda28197Spatrick   DWARFMappedHash::ExtractDIEArray(die_info_array, tag, qualified_name_hash,
550dda28197Spatrick                                    callback);
551dda28197Spatrick }
552dda28197Spatrick 
FindCompleteObjCClassByName(llvm::StringRef name,llvm::function_ref<bool (DIERef ref)> callback,bool must_be_implementation)553dda28197Spatrick void DWARFMappedHash::MemoryTable::FindCompleteObjCClassByName(
554dda28197Spatrick     llvm::StringRef name, llvm::function_ref<bool(DIERef ref)> callback,
555dda28197Spatrick     bool must_be_implementation) {
556dda28197Spatrick   DIEInfoArray die_info_array;
557dda28197Spatrick   FindByName(name, die_info_array);
558061da546Spatrick   if (must_be_implementation &&
559061da546Spatrick       GetHeader().header_data.ContainsAtom(eAtomTypeTypeFlags)) {
560061da546Spatrick     // If we have two atoms, then we have the DIE offset and the type flags
561061da546Spatrick     // so we can find the objective C class efficiently.
562dda28197Spatrick     DWARFMappedHash::ExtractTypesFromDIEArray(
563dda28197Spatrick         die_info_array, UINT32_MAX, eTypeFlagClassIsImplementation, callback);
564dda28197Spatrick     return;
565dda28197Spatrick   }
566061da546Spatrick   // We don't only want the one true definition, so try and see what we can
567061da546Spatrick   // find, and only return class or struct DIEs. If we do have the full
568061da546Spatrick   // implementation, then return it alone, else return all possible
569061da546Spatrick   // matches.
570dda28197Spatrick   bool found_implementation = false;
571061da546Spatrick   DWARFMappedHash::ExtractClassOrStructDIEArray(
572dda28197Spatrick       die_info_array, true /*return_implementation_only_if_available*/,
573dda28197Spatrick       [&](DIERef ref) {
574dda28197Spatrick         found_implementation = true;
575dda28197Spatrick         // Here the return value does not matter as we are called at most once.
576dda28197Spatrick         return callback(ref);
577dda28197Spatrick       });
578dda28197Spatrick   if (found_implementation)
579dda28197Spatrick     return;
580dda28197Spatrick   DWARFMappedHash::ExtractClassOrStructDIEArray(
581dda28197Spatrick       die_info_array, false /*return_implementation_only_if_available*/,
582dda28197Spatrick       callback);
583061da546Spatrick }
584061da546Spatrick 
FindByName(llvm::StringRef name,DIEInfoArray & die_info_array)585dda28197Spatrick void DWARFMappedHash::MemoryTable::FindByName(llvm::StringRef name,
586061da546Spatrick                                               DIEInfoArray &die_info_array) {
587061da546Spatrick   if (name.empty())
588dda28197Spatrick     return;
589061da546Spatrick 
590061da546Spatrick   Pair kv_pair;
591dda28197Spatrick   if (Find(name, kv_pair))
592061da546Spatrick     die_info_array.swap(kv_pair.value);
593061da546Spatrick }
594