180814287SRaphael Isemann //===-- HashedNameToDIE.cpp -----------------------------------------------===//
2715cbe89STamas Berghammer //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6715cbe89STamas Berghammer //
7715cbe89STamas Berghammer //===----------------------------------------------------------------------===//
8715cbe89STamas Berghammer 
9715cbe89STamas Berghammer #include "HashedNameToDIE.h"
1095eae423SZachary Turner #include "llvm/ADT/StringRef.h"
11715cbe89STamas Berghammer 
12*ae869d44SShafik Yaghmour using namespace lldb_private::dwarf;
13*ae869d44SShafik Yaghmour 
ExtractDIEArray(const DIEInfoArray & die_info_array,llvm::function_ref<bool (DIERef ref)> callback)145e04b5f2SJan Kratochvil bool DWARFMappedHash::ExtractDIEArray(
155e04b5f2SJan Kratochvil     const DIEInfoArray &die_info_array,
165e04b5f2SJan Kratochvil     llvm::function_ref<bool(DIERef ref)> callback) {
17715cbe89STamas Berghammer   const size_t count = die_info_array.size();
18715cbe89STamas Berghammer   for (size_t i = 0; i < count; ++i)
195e04b5f2SJan Kratochvil     if (!callback(DIERef(die_info_array[i])))
205e04b5f2SJan Kratochvil       return false;
215e04b5f2SJan Kratochvil   return true;
22715cbe89STamas Berghammer }
23715cbe89STamas Berghammer 
ExtractDIEArray(const DIEInfoArray & die_info_array,const dw_tag_t tag,llvm::function_ref<bool (DIERef ref)> callback)245e04b5f2SJan Kratochvil void DWARFMappedHash::ExtractDIEArray(
255e04b5f2SJan Kratochvil     const DIEInfoArray &die_info_array, const dw_tag_t tag,
265e04b5f2SJan Kratochvil     llvm::function_ref<bool(DIERef ref)> callback) {
27b9c1b51eSKate Stone   if (tag == 0) {
285e04b5f2SJan Kratochvil     ExtractDIEArray(die_info_array, callback);
2980237523SJan Kratochvil     return;
3080237523SJan Kratochvil   }
3180237523SJan Kratochvil 
32715cbe89STamas Berghammer   const size_t count = die_info_array.size();
33b9c1b51eSKate Stone   for (size_t i = 0; i < count; ++i) {
34715cbe89STamas Berghammer     const dw_tag_t die_tag = die_info_array[i].tag;
35715cbe89STamas Berghammer     bool tag_matches = die_tag == 0 || tag == die_tag;
36b9c1b51eSKate Stone     if (!tag_matches) {
37715cbe89STamas Berghammer       if (die_tag == DW_TAG_class_type || die_tag == DW_TAG_structure_type)
3880237523SJan Kratochvil         tag_matches = tag == DW_TAG_structure_type || tag == DW_TAG_class_type;
39715cbe89STamas Berghammer     }
405e04b5f2SJan Kratochvil     if (tag_matches) {
415e04b5f2SJan Kratochvil       if (!callback(DIERef(die_info_array[i])))
425e04b5f2SJan Kratochvil         return;
435e04b5f2SJan Kratochvil     }
44715cbe89STamas Berghammer   }
45715cbe89STamas Berghammer }
46715cbe89STamas Berghammer 
ExtractDIEArray(const DIEInfoArray & die_info_array,const dw_tag_t tag,const uint32_t qualified_name_hash,llvm::function_ref<bool (DIERef ref)> callback)475e04b5f2SJan Kratochvil void DWARFMappedHash::ExtractDIEArray(
485e04b5f2SJan Kratochvil     const DIEInfoArray &die_info_array, const dw_tag_t tag,
49715cbe89STamas Berghammer     const uint32_t qualified_name_hash,
505e04b5f2SJan Kratochvil     llvm::function_ref<bool(DIERef ref)> callback) {
51b9c1b51eSKate Stone   if (tag == 0) {
525e04b5f2SJan Kratochvil     ExtractDIEArray(die_info_array, callback);
5380237523SJan Kratochvil     return;
5480237523SJan Kratochvil   }
5580237523SJan Kratochvil 
56715cbe89STamas Berghammer   const size_t count = die_info_array.size();
57b9c1b51eSKate Stone   for (size_t i = 0; i < count; ++i) {
58715cbe89STamas Berghammer     if (qualified_name_hash != die_info_array[i].qualified_name_hash)
59715cbe89STamas Berghammer       continue;
60715cbe89STamas Berghammer     const dw_tag_t die_tag = die_info_array[i].tag;
61715cbe89STamas Berghammer     bool tag_matches = die_tag == 0 || tag == die_tag;
62b9c1b51eSKate Stone     if (!tag_matches) {
63715cbe89STamas Berghammer       if (die_tag == DW_TAG_class_type || die_tag == DW_TAG_structure_type)
6480237523SJan Kratochvil         tag_matches = tag == DW_TAG_structure_type || tag == DW_TAG_class_type;
65715cbe89STamas Berghammer     }
665e04b5f2SJan Kratochvil     if (tag_matches) {
675e04b5f2SJan Kratochvil       if (!callback(DIERef(die_info_array[i])))
685e04b5f2SJan Kratochvil         return;
695e04b5f2SJan Kratochvil     }
70715cbe89STamas Berghammer   }
71715cbe89STamas Berghammer }
72715cbe89STamas Berghammer 
ExtractClassOrStructDIEArray(const DIEInfoArray & die_info_array,bool return_implementation_only_if_available,llvm::function_ref<bool (DIERef ref)> callback)73b9c1b51eSKate Stone void DWARFMappedHash::ExtractClassOrStructDIEArray(
74b9c1b51eSKate Stone     const DIEInfoArray &die_info_array,
755e04b5f2SJan Kratochvil     bool return_implementation_only_if_available,
765e04b5f2SJan Kratochvil     llvm::function_ref<bool(DIERef ref)> callback) {
77715cbe89STamas Berghammer   const size_t count = die_info_array.size();
78b9c1b51eSKate Stone   for (size_t i = 0; i < count; ++i) {
79715cbe89STamas Berghammer     const dw_tag_t die_tag = die_info_array[i].tag;
808fbac4e1SJan Kratochvil     if (!(die_tag == 0 || die_tag == DW_TAG_class_type ||
818fbac4e1SJan Kratochvil           die_tag == DW_TAG_structure_type))
8280237523SJan Kratochvil       continue;
835e04b5f2SJan Kratochvil     bool is_implementation =
845e04b5f2SJan Kratochvil         (die_info_array[i].type_flags & eTypeFlagClassIsImplementation) != 0;
855e04b5f2SJan Kratochvil     if (is_implementation != return_implementation_only_if_available)
865e04b5f2SJan Kratochvil       continue;
87b9c1b51eSKate Stone     if (return_implementation_only_if_available) {
8805097246SAdrian Prantl       // We found the one true definition for this class, so only return
8905097246SAdrian Prantl       // that
905e04b5f2SJan Kratochvil       callback(DIERef(die_info_array[i]));
91715cbe89STamas Berghammer       return;
92715cbe89STamas Berghammer     }
935e04b5f2SJan Kratochvil     if (!callback(DIERef(die_info_array[i])))
945e04b5f2SJan Kratochvil       return;
95715cbe89STamas Berghammer   }
96715cbe89STamas Berghammer }
97715cbe89STamas Berghammer 
ExtractTypesFromDIEArray(const DIEInfoArray & die_info_array,uint32_t type_flag_mask,uint32_t type_flag_value,llvm::function_ref<bool (DIERef ref)> callback)98b9c1b51eSKate Stone void DWARFMappedHash::ExtractTypesFromDIEArray(
99b9c1b51eSKate Stone     const DIEInfoArray &die_info_array, uint32_t type_flag_mask,
1005e04b5f2SJan Kratochvil     uint32_t type_flag_value, llvm::function_ref<bool(DIERef ref)> callback) {
101715cbe89STamas Berghammer   const size_t count = die_info_array.size();
102b9c1b51eSKate Stone   for (size_t i = 0; i < count; ++i) {
1035e04b5f2SJan Kratochvil     if ((die_info_array[i].type_flags & type_flag_mask) == type_flag_value) {
1045e04b5f2SJan Kratochvil       if (!callback(DIERef(die_info_array[i])))
1055e04b5f2SJan Kratochvil         return;
1065e04b5f2SJan Kratochvil     }
107715cbe89STamas Berghammer   }
108715cbe89STamas Berghammer }
109715cbe89STamas Berghammer 
GetAtomTypeName(uint16_t atom)110b9c1b51eSKate Stone const char *DWARFMappedHash::GetAtomTypeName(uint16_t atom) {
111b9c1b51eSKate Stone   switch (atom) {
112b9c1b51eSKate Stone   case eAtomTypeNULL:
113b9c1b51eSKate Stone     return "NULL";
114b9c1b51eSKate Stone   case eAtomTypeDIEOffset:
115b9c1b51eSKate Stone     return "die-offset";
116b9c1b51eSKate Stone   case eAtomTypeCUOffset:
117b9c1b51eSKate Stone     return "cu-offset";
118b9c1b51eSKate Stone   case eAtomTypeTag:
119b9c1b51eSKate Stone     return "die-tag";
120b9c1b51eSKate Stone   case eAtomTypeNameFlags:
121b9c1b51eSKate Stone     return "name-flags";
122b9c1b51eSKate Stone   case eAtomTypeTypeFlags:
123b9c1b51eSKate Stone     return "type-flags";
124b9c1b51eSKate Stone   case eAtomTypeQualNameHash:
125b9c1b51eSKate Stone     return "qualified-name-hash";
126715cbe89STamas Berghammer   }
127715cbe89STamas Berghammer   return "<invalid>";
128715cbe89STamas Berghammer }
129715cbe89STamas Berghammer 
DIEInfo(dw_offset_t o,dw_tag_t t,uint32_t f,uint32_t h)13067b45aceSPavel Labath DWARFMappedHash::DIEInfo::DIEInfo(dw_offset_t o, dw_tag_t t, uint32_t f,
13167b45aceSPavel Labath                                   uint32_t h)
13267b45aceSPavel Labath     : die_offset(o), tag(t), type_flags(f), qualified_name_hash(h) {}
133715cbe89STamas Berghammer 
Prologue(dw_offset_t _die_base_offset)134b9c1b51eSKate Stone DWARFMappedHash::Prologue::Prologue(dw_offset_t _die_base_offset)
1359494c510SJonas Devlieghere     : die_base_offset(_die_base_offset), atoms() {
13605097246SAdrian Prantl   // Define an array of DIE offsets by first defining an array, and then define
1370a8a225fSJonas Devlieghere   // the atom type for the array, in this case we have an array of DIE offsets.
138715cbe89STamas Berghammer   AppendAtom(eAtomTypeDIEOffset, DW_FORM_data4);
139715cbe89STamas Berghammer }
140715cbe89STamas Berghammer 
ClearAtoms()141b9c1b51eSKate Stone void DWARFMappedHash::Prologue::ClearAtoms() {
142715cbe89STamas Berghammer   hash_data_has_fixed_byte_size = true;
143715cbe89STamas Berghammer   min_hash_data_byte_size = 0;
144715cbe89STamas Berghammer   atom_mask = 0;
145715cbe89STamas Berghammer   atoms.clear();
146715cbe89STamas Berghammer }
147715cbe89STamas Berghammer 
ContainsAtom(AtomType atom_type) const148b9c1b51eSKate Stone bool DWARFMappedHash::Prologue::ContainsAtom(AtomType atom_type) const {
149715cbe89STamas Berghammer   return (atom_mask & (1u << atom_type)) != 0;
150715cbe89STamas Berghammer }
151715cbe89STamas Berghammer 
Clear()152b9c1b51eSKate Stone void DWARFMappedHash::Prologue::Clear() {
153715cbe89STamas Berghammer   die_base_offset = 0;
154715cbe89STamas Berghammer   ClearAtoms();
155715cbe89STamas Berghammer }
156715cbe89STamas Berghammer 
AppendAtom(AtomType type,dw_form_t form)157b9c1b51eSKate Stone void DWARFMappedHash::Prologue::AppendAtom(AtomType type, dw_form_t form) {
158715cbe89STamas Berghammer   atoms.push_back({type, form});
159715cbe89STamas Berghammer   atom_mask |= 1u << type;
160b9c1b51eSKate Stone   switch (form) {
161715cbe89STamas Berghammer   case DW_FORM_indirect:
162715cbe89STamas Berghammer   case DW_FORM_exprloc:
163715cbe89STamas Berghammer   case DW_FORM_flag_present:
164715cbe89STamas Berghammer   case DW_FORM_ref_sig8:
165a322f36cSDavid Blaikie     llvm_unreachable("Unhandled atom form");
166715cbe89STamas Berghammer 
167d0156256SAli Tamur   case DW_FORM_addrx:
168715cbe89STamas Berghammer   case DW_FORM_string:
169715cbe89STamas Berghammer   case DW_FORM_block:
170715cbe89STamas Berghammer   case DW_FORM_block1:
171715cbe89STamas Berghammer   case DW_FORM_sdata:
172715cbe89STamas Berghammer   case DW_FORM_udata:
173715cbe89STamas Berghammer   case DW_FORM_ref_udata:
174715cbe89STamas Berghammer   case DW_FORM_GNU_addr_index:
175715cbe89STamas Berghammer   case DW_FORM_GNU_str_index:
176715cbe89STamas Berghammer     hash_data_has_fixed_byte_size = false;
17762e0681aSJason Molenda     LLVM_FALLTHROUGH;
178715cbe89STamas Berghammer   case DW_FORM_flag:
179715cbe89STamas Berghammer   case DW_FORM_data1:
180715cbe89STamas Berghammer   case DW_FORM_ref1:
181715cbe89STamas Berghammer   case DW_FORM_sec_offset:
182715cbe89STamas Berghammer     min_hash_data_byte_size += 1;
183715cbe89STamas Berghammer     break;
184715cbe89STamas Berghammer 
185715cbe89STamas Berghammer   case DW_FORM_block2:
186715cbe89STamas Berghammer     hash_data_has_fixed_byte_size = false;
18762e0681aSJason Molenda     LLVM_FALLTHROUGH;
188715cbe89STamas Berghammer   case DW_FORM_data2:
189715cbe89STamas Berghammer   case DW_FORM_ref2:
190715cbe89STamas Berghammer     min_hash_data_byte_size += 2;
191715cbe89STamas Berghammer     break;
192715cbe89STamas Berghammer 
193715cbe89STamas Berghammer   case DW_FORM_block4:
194715cbe89STamas Berghammer     hash_data_has_fixed_byte_size = false;
19562e0681aSJason Molenda     LLVM_FALLTHROUGH;
196715cbe89STamas Berghammer   case DW_FORM_data4:
197715cbe89STamas Berghammer   case DW_FORM_ref4:
198715cbe89STamas Berghammer   case DW_FORM_addr:
199715cbe89STamas Berghammer   case DW_FORM_ref_addr:
200715cbe89STamas Berghammer   case DW_FORM_strp:
201715cbe89STamas Berghammer     min_hash_data_byte_size += 4;
202715cbe89STamas Berghammer     break;
203715cbe89STamas Berghammer 
204715cbe89STamas Berghammer   case DW_FORM_data8:
205715cbe89STamas Berghammer   case DW_FORM_ref8:
206715cbe89STamas Berghammer     min_hash_data_byte_size += 8;
207715cbe89STamas Berghammer     break;
208715cbe89STamas Berghammer   }
209715cbe89STamas Berghammer }
210715cbe89STamas Berghammer 
211715cbe89STamas Berghammer lldb::offset_t
Read(const lldb_private::DataExtractor & data,lldb::offset_t offset)212715cbe89STamas Berghammer DWARFMappedHash::Prologue::Read(const lldb_private::DataExtractor &data,
213b9c1b51eSKate Stone                                 lldb::offset_t offset) {
214715cbe89STamas Berghammer   ClearAtoms();
215715cbe89STamas Berghammer 
216715cbe89STamas Berghammer   die_base_offset = data.GetU32(&offset);
217715cbe89STamas Berghammer 
218715cbe89STamas Berghammer   const uint32_t atom_count = data.GetU32(&offset);
219b9c1b51eSKate Stone   if (atom_count == 0x00060003u) {
2200a8a225fSJonas Devlieghere     // Old format, deal with contents of old pre-release format.
2210a8a225fSJonas Devlieghere     while (data.GetU32(&offset)) {
222715cbe89STamas Berghammer       /* do nothing */;
2230a8a225fSJonas Devlieghere     }
224715cbe89STamas Berghammer 
225715cbe89STamas Berghammer     // Hardcode to the only known value for now.
226715cbe89STamas Berghammer     AppendAtom(eAtomTypeDIEOffset, DW_FORM_data4);
227b9c1b51eSKate Stone   } else {
228b9c1b51eSKate Stone     for (uint32_t i = 0; i < atom_count; ++i) {
229715cbe89STamas Berghammer       AtomType type = (AtomType)data.GetU16(&offset);
230715cbe89STamas Berghammer       dw_form_t form = (dw_form_t)data.GetU16(&offset);
231715cbe89STamas Berghammer       AppendAtom(type, form);
232715cbe89STamas Berghammer     }
233715cbe89STamas Berghammer   }
234715cbe89STamas Berghammer   return offset;
235715cbe89STamas Berghammer }
236715cbe89STamas Berghammer 
GetByteSize() const237b9c1b51eSKate Stone size_t DWARFMappedHash::Prologue::GetByteSize() const {
238b9c1b51eSKate Stone   // Add an extra count to the atoms size for the zero termination Atom that
2390a8a225fSJonas Devlieghere   // gets written to disk.
240b9c1b51eSKate Stone   return sizeof(die_base_offset) + sizeof(uint32_t) +
241b9c1b51eSKate Stone          atoms.size() * sizeof(Atom);
242715cbe89STamas Berghammer }
243715cbe89STamas Berghammer 
GetMinimumHashDataByteSize() const244b9c1b51eSKate Stone size_t DWARFMappedHash::Prologue::GetMinimumHashDataByteSize() const {
245715cbe89STamas Berghammer   return min_hash_data_byte_size;
246715cbe89STamas Berghammer }
247715cbe89STamas Berghammer 
HashDataHasFixedByteSize() const248b9c1b51eSKate Stone bool DWARFMappedHash::Prologue::HashDataHasFixedByteSize() const {
249715cbe89STamas Berghammer   return hash_data_has_fixed_byte_size;
250715cbe89STamas Berghammer }
251715cbe89STamas Berghammer 
GetByteSize(const HeaderData & header_data)252b9c1b51eSKate Stone size_t DWARFMappedHash::Header::GetByteSize(const HeaderData &header_data) {
253715cbe89STamas Berghammer   return header_data.GetByteSize();
254715cbe89STamas Berghammer }
255715cbe89STamas Berghammer 
Read(lldb_private::DataExtractor & data,lldb::offset_t offset)256b9c1b51eSKate Stone lldb::offset_t DWARFMappedHash::Header::Read(lldb_private::DataExtractor &data,
257b9c1b51eSKate Stone                                              lldb::offset_t offset) {
258715cbe89STamas Berghammer   offset = MappedHash::Header<Prologue>::Read(data, offset);
259b9c1b51eSKate Stone   if (offset != UINT32_MAX) {
260715cbe89STamas Berghammer     offset = header_data.Read(data, offset);
261715cbe89STamas Berghammer   }
262715cbe89STamas Berghammer   return offset;
263715cbe89STamas Berghammer }
264715cbe89STamas Berghammer 
Read(const lldb_private::DWARFDataExtractor & data,lldb::offset_t * offset_ptr,DIEInfo & hash_data) const265b9c1b51eSKate Stone bool DWARFMappedHash::Header::Read(const lldb_private::DWARFDataExtractor &data,
266715cbe89STamas Berghammer                                    lldb::offset_t *offset_ptr,
267b9c1b51eSKate Stone                                    DIEInfo &hash_data) const {
268715cbe89STamas Berghammer   const size_t num_atoms = header_data.atoms.size();
269715cbe89STamas Berghammer   if (num_atoms == 0)
270715cbe89STamas Berghammer     return false;
271715cbe89STamas Berghammer 
272b9c1b51eSKate Stone   for (size_t i = 0; i < num_atoms; ++i) {
273248a1305SKonrad Kleine     DWARFFormValue form_value(nullptr, header_data.atoms[i].form);
274715cbe89STamas Berghammer 
275715cbe89STamas Berghammer     if (!form_value.ExtractValue(data, offset_ptr))
276715cbe89STamas Berghammer       return false;
277715cbe89STamas Berghammer 
278b9c1b51eSKate Stone     switch (header_data.atoms[i].type) {
279715cbe89STamas Berghammer     case eAtomTypeDIEOffset: // DIE offset, check form for encoding
28067b45aceSPavel Labath       hash_data.die_offset =
2813eba3f1aSPavel Labath           DWARFFormValue::IsDataForm(form_value.Form())
2823eba3f1aSPavel Labath               ? form_value.Unsigned()
2833eba3f1aSPavel Labath               : form_value.Reference(header_data.die_base_offset);
284715cbe89STamas Berghammer       break;
285715cbe89STamas Berghammer 
286715cbe89STamas Berghammer     case eAtomTypeTag: // DW_TAG value for the DIE
287715cbe89STamas Berghammer       hash_data.tag = (dw_tag_t)form_value.Unsigned();
288cec91ef9SGreg Clayton       break;
289715cbe89STamas Berghammer 
290715cbe89STamas Berghammer     case eAtomTypeTypeFlags: // Flags from enum TypeFlags
291715cbe89STamas Berghammer       hash_data.type_flags = (uint32_t)form_value.Unsigned();
292715cbe89STamas Berghammer       break;
293715cbe89STamas Berghammer 
294715cbe89STamas Berghammer     case eAtomTypeQualNameHash: // Flags from enum TypeFlags
295715cbe89STamas Berghammer       hash_data.qualified_name_hash = form_value.Unsigned();
296715cbe89STamas Berghammer       break;
297715cbe89STamas Berghammer 
298715cbe89STamas Berghammer     default:
2990a8a225fSJonas Devlieghere       // We can always skip atoms we don't know about.
300715cbe89STamas Berghammer       break;
301715cbe89STamas Berghammer     }
302715cbe89STamas Berghammer   }
30367b45aceSPavel Labath   return hash_data.die_offset != DW_INVALID_OFFSET;
304715cbe89STamas Berghammer }
305715cbe89STamas Berghammer 
MemoryTable(lldb_private::DWARFDataExtractor & table_data,const lldb_private::DWARFDataExtractor & string_table,const char * name)306b9c1b51eSKate Stone DWARFMappedHash::MemoryTable::MemoryTable(
307b9c1b51eSKate Stone     lldb_private::DWARFDataExtractor &table_data,
308b9c1b51eSKate Stone     const lldb_private::DWARFDataExtractor &string_table, const char *name)
309b9c1b51eSKate Stone     : MappedHash::MemoryTable<uint32_t, Header, DIEInfoArray>(table_data),
310b9c1b51eSKate Stone       m_data(table_data), m_string_table(string_table), m_name(name) {}
311715cbe89STamas Berghammer 
312715cbe89STamas Berghammer const char *
GetStringForKeyType(KeyType key) const313b9c1b51eSKate Stone DWARFMappedHash::MemoryTable::GetStringForKeyType(KeyType key) const {
314715cbe89STamas Berghammer   // The key in the DWARF table is the .debug_str offset for the string
315715cbe89STamas Berghammer   return m_string_table.PeekCStr(key);
316715cbe89STamas Berghammer }
317715cbe89STamas Berghammer 
ReadHashData(uint32_t hash_data_offset,HashData & hash_data) const318b9c1b51eSKate Stone bool DWARFMappedHash::MemoryTable::ReadHashData(uint32_t hash_data_offset,
319b9c1b51eSKate Stone                                                 HashData &hash_data) const {
320715cbe89STamas Berghammer   lldb::offset_t offset = hash_data_offset;
3210a8a225fSJonas Devlieghere   // Skip string table offset that contains offset of hash name in .debug_str.
3220a8a225fSJonas Devlieghere   offset += 4;
323715cbe89STamas Berghammer   const uint32_t count = m_data.GetU32(&offset);
324b9c1b51eSKate Stone   if (count > 0) {
325715cbe89STamas Berghammer     hash_data.resize(count);
326b9c1b51eSKate Stone     for (uint32_t i = 0; i < count; ++i) {
327715cbe89STamas Berghammer       if (!m_header.Read(m_data, &offset, hash_data[i]))
328715cbe89STamas Berghammer         return false;
329715cbe89STamas Berghammer     }
330b9c1b51eSKate Stone   } else
331715cbe89STamas Berghammer     hash_data.clear();
332715cbe89STamas Berghammer   return true;
333715cbe89STamas Berghammer }
334715cbe89STamas Berghammer 
335715cbe89STamas Berghammer DWARFMappedHash::MemoryTable::Result
GetHashDataForName(llvm::StringRef name,lldb::offset_t * hash_data_offset_ptr,Pair & pair) const336b9c1b51eSKate Stone DWARFMappedHash::MemoryTable::GetHashDataForName(
337b39fca95SPavel Labath     llvm::StringRef name, lldb::offset_t *hash_data_offset_ptr,
338b39fca95SPavel Labath     Pair &pair) const {
339715cbe89STamas Berghammer   pair.key = m_data.GetU32(hash_data_offset_ptr);
340715cbe89STamas Berghammer   pair.value.clear();
341715cbe89STamas Berghammer 
34205097246SAdrian Prantl   // If the key is zero, this terminates our chain of HashData objects for this
34305097246SAdrian Prantl   // hash value.
344715cbe89STamas Berghammer   if (pair.key == 0)
345715cbe89STamas Berghammer     return eResultEndOfHashData;
346715cbe89STamas Berghammer 
34705097246SAdrian Prantl   // There definitely should be a string for this string offset, if there
3480a8a225fSJonas Devlieghere   // isn't, there is something wrong, return and error.
349715cbe89STamas Berghammer   const char *strp_cstr = m_string_table.PeekCStr(pair.key);
350248a1305SKonrad Kleine   if (strp_cstr == nullptr) {
351715cbe89STamas Berghammer     *hash_data_offset_ptr = UINT32_MAX;
352715cbe89STamas Berghammer     return eResultError;
353715cbe89STamas Berghammer   }
354715cbe89STamas Berghammer 
355715cbe89STamas Berghammer   const uint32_t count = m_data.GetU32(hash_data_offset_ptr);
356b9c1b51eSKate Stone   const size_t min_total_hash_data_size =
357b9c1b51eSKate Stone       count * m_header.header_data.GetMinimumHashDataByteSize();
3580a8a225fSJonas Devlieghere   if (count > 0 && m_data.ValidOffsetForDataOfSize(*hash_data_offset_ptr,
359b9c1b51eSKate Stone                                                    min_total_hash_data_size)) {
36005097246SAdrian Prantl     // We have at least one HashData entry, and we have enough data to parse at
36105097246SAdrian Prantl     // least "count" HashData entries.
362715cbe89STamas Berghammer 
363715cbe89STamas Berghammer     // First make sure the entire C string matches...
364b39fca95SPavel Labath     const bool match = name == strp_cstr;
365715cbe89STamas Berghammer 
366b9c1b51eSKate Stone     if (!match && m_header.header_data.HashDataHasFixedByteSize()) {
36705097246SAdrian Prantl       // If the string doesn't match and we have fixed size data, we can just
36805097246SAdrian Prantl       // add the total byte size of all HashData objects to the hash data
36905097246SAdrian Prantl       // offset and be done...
370715cbe89STamas Berghammer       *hash_data_offset_ptr += min_total_hash_data_size;
371b9c1b51eSKate Stone     } else {
37205097246SAdrian Prantl       // If the string does match, or we don't have fixed size data then we
37305097246SAdrian Prantl       // need to read the hash data as a stream. If the string matches we also
37405097246SAdrian Prantl       // append all HashData objects to the value array.
375b9c1b51eSKate Stone       for (uint32_t i = 0; i < count; ++i) {
376715cbe89STamas Berghammer         DIEInfo die_info;
377b9c1b51eSKate Stone         if (m_header.Read(m_data, hash_data_offset_ptr, die_info)) {
378715cbe89STamas Berghammer           // Only happened if the HashData of the string matched...
379715cbe89STamas Berghammer           if (match)
380715cbe89STamas Berghammer             pair.value.push_back(die_info);
381b9c1b51eSKate Stone         } else {
3820a8a225fSJonas Devlieghere           // Something went wrong while reading the data.
383715cbe89STamas Berghammer           *hash_data_offset_ptr = UINT32_MAX;
384715cbe89STamas Berghammer           return eResultError;
385715cbe89STamas Berghammer         }
386715cbe89STamas Berghammer       }
387715cbe89STamas Berghammer     }
38805097246SAdrian Prantl     // Return the correct response depending on if the string matched or not...
3890a8a225fSJonas Devlieghere     if (match) {
3900a8a225fSJonas Devlieghere       // The key (cstring) matches and we have lookup results!
3910a8a225fSJonas Devlieghere       return eResultKeyMatch;
3920a8a225fSJonas Devlieghere     } else {
3930a8a225fSJonas Devlieghere       // The key doesn't match, this function will get called again for the
3940a8a225fSJonas Devlieghere       // next key/value or the key terminator which in our case is a zero
3950a8a225fSJonas Devlieghere       // .debug_str offset.
3960a8a225fSJonas Devlieghere       return eResultKeyMismatch;
3970a8a225fSJonas Devlieghere     }
398b9c1b51eSKate Stone   } else {
399715cbe89STamas Berghammer     *hash_data_offset_ptr = UINT32_MAX;
400715cbe89STamas Berghammer     return eResultError;
401715cbe89STamas Berghammer   }
402715cbe89STamas Berghammer }
403715cbe89STamas Berghammer 
404715cbe89STamas Berghammer DWARFMappedHash::MemoryTable::Result
AppendHashDataForRegularExpression(const lldb_private::RegularExpression & regex,lldb::offset_t * hash_data_offset_ptr,Pair & pair) const405715cbe89STamas Berghammer DWARFMappedHash::MemoryTable::AppendHashDataForRegularExpression(
406715cbe89STamas Berghammer     const lldb_private::RegularExpression &regex,
407b9c1b51eSKate Stone     lldb::offset_t *hash_data_offset_ptr, Pair &pair) const {
408715cbe89STamas Berghammer   pair.key = m_data.GetU32(hash_data_offset_ptr);
40905097246SAdrian Prantl   // If the key is zero, this terminates our chain of HashData objects for this
41005097246SAdrian Prantl   // hash value.
411715cbe89STamas Berghammer   if (pair.key == 0)
412715cbe89STamas Berghammer     return eResultEndOfHashData;
413715cbe89STamas Berghammer 
41405097246SAdrian Prantl   // There definitely should be a string for this string offset, if there
4150a8a225fSJonas Devlieghere   // isn't, there is something wrong, return and error.
416715cbe89STamas Berghammer   const char *strp_cstr = m_string_table.PeekCStr(pair.key);
417248a1305SKonrad Kleine   if (strp_cstr == nullptr)
418715cbe89STamas Berghammer     return eResultError;
419715cbe89STamas Berghammer 
420715cbe89STamas Berghammer   const uint32_t count = m_data.GetU32(hash_data_offset_ptr);
421b9c1b51eSKate Stone   const size_t min_total_hash_data_size =
422b9c1b51eSKate Stone       count * m_header.header_data.GetMinimumHashDataByteSize();
4230a8a225fSJonas Devlieghere   if (count > 0 && m_data.ValidOffsetForDataOfSize(*hash_data_offset_ptr,
424b9c1b51eSKate Stone                                                    min_total_hash_data_size)) {
42595eae423SZachary Turner     const bool match = regex.Execute(llvm::StringRef(strp_cstr));
426715cbe89STamas Berghammer 
427b9c1b51eSKate Stone     if (!match && m_header.header_data.HashDataHasFixedByteSize()) {
42805097246SAdrian Prantl       // If the regex doesn't match and we have fixed size data, we can just
42905097246SAdrian Prantl       // add the total byte size of all HashData objects to the hash data
43005097246SAdrian Prantl       // offset and be done...
431715cbe89STamas Berghammer       *hash_data_offset_ptr += min_total_hash_data_size;
432b9c1b51eSKate Stone     } else {
43305097246SAdrian Prantl       // If the string does match, or we don't have fixed size data then we
43405097246SAdrian Prantl       // need to read the hash data as a stream. If the string matches we also
43505097246SAdrian Prantl       // append all HashData objects to the value array.
436b9c1b51eSKate Stone       for (uint32_t i = 0; i < count; ++i) {
437715cbe89STamas Berghammer         DIEInfo die_info;
438b9c1b51eSKate Stone         if (m_header.Read(m_data, hash_data_offset_ptr, die_info)) {
439715cbe89STamas Berghammer           // Only happened if the HashData of the string matched...
440715cbe89STamas Berghammer           if (match)
441715cbe89STamas Berghammer             pair.value.push_back(die_info);
442b9c1b51eSKate Stone         } else {
443715cbe89STamas Berghammer           // Something went wrong while reading the data
444715cbe89STamas Berghammer           *hash_data_offset_ptr = UINT32_MAX;
445715cbe89STamas Berghammer           return eResultError;
446715cbe89STamas Berghammer         }
447715cbe89STamas Berghammer       }
448715cbe89STamas Berghammer     }
44905097246SAdrian Prantl     // Return the correct response depending on if the string matched or not...
4500a8a225fSJonas Devlieghere     if (match) {
4510a8a225fSJonas Devlieghere       // The key (cstring) matches and we have lookup results!
4520a8a225fSJonas Devlieghere       return eResultKeyMatch;
4530a8a225fSJonas Devlieghere     } else {
4540a8a225fSJonas Devlieghere       // The key doesn't match, this function will get called again for the
4550a8a225fSJonas Devlieghere       // next key/value or the key terminator which in our case is a zero
4560a8a225fSJonas Devlieghere       // .debug_str offset.
4570a8a225fSJonas Devlieghere       return eResultKeyMismatch;
4580a8a225fSJonas Devlieghere     }
459b9c1b51eSKate Stone   } else {
460715cbe89STamas Berghammer     *hash_data_offset_ptr = UINT32_MAX;
461715cbe89STamas Berghammer     return eResultError;
462715cbe89STamas Berghammer   }
463715cbe89STamas Berghammer }
464715cbe89STamas Berghammer 
AppendAllDIEsThatMatchingRegex(const lldb_private::RegularExpression & regex,DIEInfoArray & die_info_array) const4655e04b5f2SJan Kratochvil void DWARFMappedHash::MemoryTable::AppendAllDIEsThatMatchingRegex(
466715cbe89STamas Berghammer     const lldb_private::RegularExpression &regex,
467b9c1b51eSKate Stone     DIEInfoArray &die_info_array) const {
468715cbe89STamas Berghammer   const uint32_t hash_count = m_header.hashes_count;
469715cbe89STamas Berghammer   Pair pair;
470b9c1b51eSKate Stone   for (uint32_t offset_idx = 0; offset_idx < hash_count; ++offset_idx) {
471715cbe89STamas Berghammer     lldb::offset_t hash_data_offset = GetHashDataOffset(offset_idx);
472b9c1b51eSKate Stone     while (hash_data_offset != UINT32_MAX) {
473715cbe89STamas Berghammer       const lldb::offset_t prev_hash_data_offset = hash_data_offset;
474b9c1b51eSKate Stone       Result hash_result =
475b9c1b51eSKate Stone           AppendHashDataForRegularExpression(regex, &hash_data_offset, pair);
476715cbe89STamas Berghammer       if (prev_hash_data_offset == hash_data_offset)
477715cbe89STamas Berghammer         break;
478715cbe89STamas Berghammer 
4790a8a225fSJonas Devlieghere       // Check the result of getting our hash data.
480b9c1b51eSKate Stone       switch (hash_result) {
481715cbe89STamas Berghammer       case eResultKeyMatch:
482715cbe89STamas Berghammer       case eResultKeyMismatch:
48305097246SAdrian Prantl         // Whether we matches or not, it doesn't matter, we keep looking.
484715cbe89STamas Berghammer         break;
485715cbe89STamas Berghammer 
486715cbe89STamas Berghammer       case eResultEndOfHashData:
487715cbe89STamas Berghammer       case eResultError:
488715cbe89STamas Berghammer         hash_data_offset = UINT32_MAX;
489715cbe89STamas Berghammer         break;
490715cbe89STamas Berghammer       }
491715cbe89STamas Berghammer     }
492715cbe89STamas Berghammer   }
493715cbe89STamas Berghammer   die_info_array.swap(pair.value);
494715cbe89STamas Berghammer }
495715cbe89STamas Berghammer 
AppendAllDIEsInRange(const uint32_t die_offset_start,const uint32_t die_offset_end,DIEInfoArray & die_info_array) const4965e04b5f2SJan Kratochvil void DWARFMappedHash::MemoryTable::AppendAllDIEsInRange(
497b9c1b51eSKate Stone     const uint32_t die_offset_start, const uint32_t die_offset_end,
498b9c1b51eSKate Stone     DIEInfoArray &die_info_array) const {
499715cbe89STamas Berghammer   const uint32_t hash_count = m_header.hashes_count;
500b9c1b51eSKate Stone   for (uint32_t offset_idx = 0; offset_idx < hash_count; ++offset_idx) {
501715cbe89STamas Berghammer     bool done = false;
502715cbe89STamas Berghammer     lldb::offset_t hash_data_offset = GetHashDataOffset(offset_idx);
503b9c1b51eSKate Stone     while (!done && hash_data_offset != UINT32_MAX) {
504715cbe89STamas Berghammer       KeyType key = m_data.GetU32(&hash_data_offset);
50505097246SAdrian Prantl       // If the key is zero, this terminates our chain of HashData objects for
50605097246SAdrian Prantl       // this hash value.
507715cbe89STamas Berghammer       if (key == 0)
508715cbe89STamas Berghammer         break;
509715cbe89STamas Berghammer 
510715cbe89STamas Berghammer       const uint32_t count = m_data.GetU32(&hash_data_offset);
511b9c1b51eSKate Stone       for (uint32_t i = 0; i < count; ++i) {
512715cbe89STamas Berghammer         DIEInfo die_info;
513b9c1b51eSKate Stone         if (m_header.Read(m_data, &hash_data_offset, die_info)) {
51467b45aceSPavel Labath           if (die_info.die_offset == 0)
515715cbe89STamas Berghammer             done = true;
51667b45aceSPavel Labath           if (die_offset_start <= die_info.die_offset &&
51767b45aceSPavel Labath               die_info.die_offset < die_offset_end)
518715cbe89STamas Berghammer             die_info_array.push_back(die_info);
519715cbe89STamas Berghammer         }
520715cbe89STamas Berghammer       }
521715cbe89STamas Berghammer     }
522715cbe89STamas Berghammer   }
523715cbe89STamas Berghammer }
524715cbe89STamas Berghammer 
FindByName(llvm::StringRef name,llvm::function_ref<bool (DIERef ref)> callback)5255e04b5f2SJan Kratochvil bool DWARFMappedHash::MemoryTable::FindByName(
5265e04b5f2SJan Kratochvil     llvm::StringRef name, llvm::function_ref<bool(DIERef ref)> callback) {
527b39fca95SPavel Labath   if (name.empty())
5285e04b5f2SJan Kratochvil     return true;
5299b0cfe25SSean Callanan 
530715cbe89STamas Berghammer   DIEInfoArray die_info_array;
5315e04b5f2SJan Kratochvil   FindByName(name, die_info_array);
5325e04b5f2SJan Kratochvil   return DWARFMappedHash::ExtractDIEArray(die_info_array, callback);
533715cbe89STamas Berghammer }
534715cbe89STamas Berghammer 
FindByNameAndTag(llvm::StringRef name,const dw_tag_t tag,llvm::function_ref<bool (DIERef ref)> callback)5355e04b5f2SJan Kratochvil void DWARFMappedHash::MemoryTable::FindByNameAndTag(
536bd47c470SJan Kratochvil     llvm::StringRef name, const dw_tag_t tag,
5375e04b5f2SJan Kratochvil     llvm::function_ref<bool(DIERef ref)> callback) {
538715cbe89STamas Berghammer   DIEInfoArray die_info_array;
5395e04b5f2SJan Kratochvil   FindByName(name, die_info_array);
5405e04b5f2SJan Kratochvil   DWARFMappedHash::ExtractDIEArray(die_info_array, tag, callback);
541bd47c470SJan Kratochvil }
542bd47c470SJan Kratochvil 
FindByNameAndTagAndQualifiedNameHash(llvm::StringRef name,const dw_tag_t tag,const uint32_t qualified_name_hash,llvm::function_ref<bool (DIERef ref)> callback)5435e04b5f2SJan Kratochvil void DWARFMappedHash::MemoryTable::FindByNameAndTagAndQualifiedNameHash(
5445e04b5f2SJan Kratochvil     llvm::StringRef name, const dw_tag_t tag,
5455e04b5f2SJan Kratochvil     const uint32_t qualified_name_hash,
5465e04b5f2SJan Kratochvil     llvm::function_ref<bool(DIERef ref)> callback) {
547bd47c470SJan Kratochvil   DIEInfoArray die_info_array;
5485e04b5f2SJan Kratochvil   FindByName(name, die_info_array);
5495e04b5f2SJan Kratochvil   DWARFMappedHash::ExtractDIEArray(die_info_array, tag, qualified_name_hash,
5505e04b5f2SJan Kratochvil                                    callback);
5515e04b5f2SJan Kratochvil }
5525e04b5f2SJan Kratochvil 
FindCompleteObjCClassByName(llvm::StringRef name,llvm::function_ref<bool (DIERef ref)> callback,bool must_be_implementation)5535e04b5f2SJan Kratochvil void DWARFMappedHash::MemoryTable::FindCompleteObjCClassByName(
5545e04b5f2SJan Kratochvil     llvm::StringRef name, llvm::function_ref<bool(DIERef ref)> callback,
5555e04b5f2SJan Kratochvil     bool must_be_implementation) {
5565e04b5f2SJan Kratochvil   DIEInfoArray die_info_array;
5575e04b5f2SJan Kratochvil   FindByName(name, die_info_array);
558b9c1b51eSKate Stone   if (must_be_implementation &&
559b9c1b51eSKate Stone       GetHeader().header_data.ContainsAtom(eAtomTypeTypeFlags)) {
56005097246SAdrian Prantl     // If we have two atoms, then we have the DIE offset and the type flags
56105097246SAdrian Prantl     // so we can find the objective C class efficiently.
5625e04b5f2SJan Kratochvil     DWARFMappedHash::ExtractTypesFromDIEArray(
5635e04b5f2SJan Kratochvil         die_info_array, UINT32_MAX, eTypeFlagClassIsImplementation, callback);
5645e04b5f2SJan Kratochvil     return;
56580237523SJan Kratochvil   }
56605097246SAdrian Prantl   // We don't only want the one true definition, so try and see what we can
56705097246SAdrian Prantl   // find, and only return class or struct DIEs. If we do have the full
56805097246SAdrian Prantl   // implementation, then return it alone, else return all possible
56905097246SAdrian Prantl   // matches.
5705e04b5f2SJan Kratochvil   bool found_implementation = false;
571b9c1b51eSKate Stone   DWARFMappedHash::ExtractClassOrStructDIEArray(
5725e04b5f2SJan Kratochvil       die_info_array, true /*return_implementation_only_if_available*/,
5735e04b5f2SJan Kratochvil       [&](DIERef ref) {
5745e04b5f2SJan Kratochvil         found_implementation = true;
5755e04b5f2SJan Kratochvil         // Here the return value does not matter as we are called at most once.
5765e04b5f2SJan Kratochvil         return callback(ref);
5775e04b5f2SJan Kratochvil       });
5785e04b5f2SJan Kratochvil   if (found_implementation)
5795e04b5f2SJan Kratochvil     return;
5805e04b5f2SJan Kratochvil   DWARFMappedHash::ExtractClassOrStructDIEArray(
5815e04b5f2SJan Kratochvil       die_info_array, false /*return_implementation_only_if_available*/,
5825e04b5f2SJan Kratochvil       callback);
583715cbe89STamas Berghammer }
584715cbe89STamas Berghammer 
FindByName(llvm::StringRef name,DIEInfoArray & die_info_array)5855e04b5f2SJan Kratochvil void DWARFMappedHash::MemoryTable::FindByName(llvm::StringRef name,
586b9c1b51eSKate Stone                                               DIEInfoArray &die_info_array) {
587b39fca95SPavel Labath   if (name.empty())
5885e04b5f2SJan Kratochvil     return;
5899b0cfe25SSean Callanan 
590715cbe89STamas Berghammer   Pair kv_pair;
5915e04b5f2SJan Kratochvil   if (Find(name, kv_pair))
592715cbe89STamas Berghammer     die_info_array.swap(kv_pair.value);
593715cbe89STamas Berghammer }
594