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 ®ex,
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 ®ex,
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