1 //===-- HashedNameToDIE.cpp -------------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "HashedNameToDIE.h"
11 #include "llvm/ADT/StringRef.h"
13 void DWARFMappedHash::ExtractDIEArray(const DIEInfoArray &die_info_array,
14 DIEArray &die_offsets) {
15 const size_t count = die_info_array.size();
16 for (size_t i = 0; i < count; ++i)
17 die_offsets.emplace_back(die_info_array[i].cu_offset,
18 die_info_array[i].offset);
21 void DWARFMappedHash::ExtractDIEArray(const DIEInfoArray &die_info_array,
23 DIEArray &die_offsets) {
25 ExtractDIEArray(die_info_array, die_offsets);
27 const size_t count = die_info_array.size();
28 for (size_t i = 0; i < count; ++i) {
29 const dw_tag_t die_tag = die_info_array[i].tag;
30 bool tag_matches = die_tag == 0 || tag == die_tag;
32 if (die_tag == DW_TAG_class_type || die_tag == DW_TAG_structure_type)
34 tag == DW_TAG_structure_type || tag == DW_TAG_class_type;
37 die_offsets.emplace_back(die_info_array[i].cu_offset,
38 die_info_array[i].offset);
43 void DWARFMappedHash::ExtractDIEArray(const DIEInfoArray &die_info_array,
45 const uint32_t qualified_name_hash,
46 DIEArray &die_offsets) {
48 ExtractDIEArray(die_info_array, die_offsets);
50 const size_t count = die_info_array.size();
51 for (size_t i = 0; i < count; ++i) {
52 if (qualified_name_hash != die_info_array[i].qualified_name_hash)
54 const dw_tag_t die_tag = die_info_array[i].tag;
55 bool tag_matches = die_tag == 0 || tag == die_tag;
57 if (die_tag == DW_TAG_class_type || die_tag == DW_TAG_structure_type)
59 tag == DW_TAG_structure_type || tag == DW_TAG_class_type;
62 die_offsets.emplace_back(die_info_array[i].cu_offset,
63 die_info_array[i].offset);
68 void DWARFMappedHash::ExtractClassOrStructDIEArray(
69 const DIEInfoArray &die_info_array,
70 bool return_implementation_only_if_available, DIEArray &die_offsets) {
71 const size_t count = die_info_array.size();
72 for (size_t i = 0; i < count; ++i) {
73 const dw_tag_t die_tag = die_info_array[i].tag;
74 if (die_tag == 0 || die_tag == DW_TAG_class_type ||
75 die_tag == DW_TAG_structure_type) {
76 if (die_info_array[i].type_flags & eTypeFlagClassIsImplementation) {
77 if (return_implementation_only_if_available) {
78 // We found the one true definition for this class, so only return
81 die_offsets.emplace_back(die_info_array[i].cu_offset,
82 die_info_array[i].offset);
85 // Put the one true definition as the first entry so it matches first
86 die_offsets.emplace(die_offsets.begin(), die_info_array[i].cu_offset,
87 die_info_array[i].offset);
90 die_offsets.emplace_back(die_info_array[i].cu_offset,
91 die_info_array[i].offset);
97 void DWARFMappedHash::ExtractTypesFromDIEArray(
98 const DIEInfoArray &die_info_array, uint32_t type_flag_mask,
99 uint32_t type_flag_value, DIEArray &die_offsets) {
100 const size_t count = die_info_array.size();
101 for (size_t i = 0; i < count; ++i) {
102 if ((die_info_array[i].type_flags & type_flag_mask) == type_flag_value)
103 die_offsets.emplace_back(die_info_array[i].cu_offset,
104 die_info_array[i].offset);
108 const char *DWARFMappedHash::GetAtomTypeName(uint16_t atom) {
112 case eAtomTypeDIEOffset:
114 case eAtomTypeCUOffset:
118 case eAtomTypeNameFlags:
120 case eAtomTypeTypeFlags:
122 case eAtomTypeQualNameHash:
123 return "qualified-name-hash";
128 DWARFMappedHash::DIEInfo::DIEInfo()
129 : cu_offset(DW_INVALID_OFFSET), offset(DW_INVALID_OFFSET), tag(0),
130 type_flags(0), qualified_name_hash(0) {}
132 DWARFMappedHash::DIEInfo::DIEInfo(dw_offset_t c, dw_offset_t o, dw_tag_t t,
133 uint32_t f, uint32_t h)
134 : cu_offset(c), offset(o), tag(t), type_flags(f), qualified_name_hash(h) {}
136 DWARFMappedHash::Prologue::Prologue(dw_offset_t _die_base_offset)
137 : die_base_offset(_die_base_offset), atoms(), atom_mask(0),
138 min_hash_data_byte_size(0), hash_data_has_fixed_byte_size(true) {
139 // Define an array of DIE offsets by first defining an array, and then define
140 // the atom type for the array, in this case we have an array of DIE offsets
141 AppendAtom(eAtomTypeDIEOffset, DW_FORM_data4);
144 void DWARFMappedHash::Prologue::ClearAtoms() {
145 hash_data_has_fixed_byte_size = true;
146 min_hash_data_byte_size = 0;
151 bool DWARFMappedHash::Prologue::ContainsAtom(AtomType atom_type) const {
152 return (atom_mask & (1u << atom_type)) != 0;
155 void DWARFMappedHash::Prologue::Clear() {
160 void DWARFMappedHash::Prologue::AppendAtom(AtomType type, dw_form_t form) {
161 atoms.push_back({type, form});
162 atom_mask |= 1u << type;
164 case DW_FORM_indirect:
165 case DW_FORM_exprloc:
166 case DW_FORM_flag_present:
167 case DW_FORM_ref_sig8:
168 llvm_unreachable("Unhandled atom form");
175 case DW_FORM_ref_udata:
176 case DW_FORM_GNU_addr_index:
177 case DW_FORM_GNU_str_index:
178 hash_data_has_fixed_byte_size = false;
183 case DW_FORM_sec_offset:
184 min_hash_data_byte_size += 1;
188 hash_data_has_fixed_byte_size = false;
192 min_hash_data_byte_size += 2;
196 hash_data_has_fixed_byte_size = false;
201 case DW_FORM_ref_addr:
203 min_hash_data_byte_size += 4;
208 min_hash_data_byte_size += 8;
214 DWARFMappedHash::Prologue::Read(const lldb_private::DataExtractor &data,
215 lldb::offset_t offset) {
218 die_base_offset = data.GetU32(&offset);
220 const uint32_t atom_count = data.GetU32(&offset);
221 if (atom_count == 0x00060003u) {
222 // Old format, deal with contents of old pre-release format
223 while (data.GetU32(&offset))
226 // Hardcode to the only known value for now.
227 AppendAtom(eAtomTypeDIEOffset, DW_FORM_data4);
229 for (uint32_t i = 0; i < atom_count; ++i) {
230 AtomType type = (AtomType)data.GetU16(&offset);
231 dw_form_t form = (dw_form_t)data.GetU16(&offset);
232 AppendAtom(type, form);
238 size_t DWARFMappedHash::Prologue::GetByteSize() const {
239 // Add an extra count to the atoms size for the zero termination Atom that
240 // gets written to disk
241 return sizeof(die_base_offset) + sizeof(uint32_t) +
242 atoms.size() * sizeof(Atom);
245 size_t DWARFMappedHash::Prologue::GetMinimumHashDataByteSize() const {
246 return min_hash_data_byte_size;
249 bool DWARFMappedHash::Prologue::HashDataHasFixedByteSize() const {
250 return hash_data_has_fixed_byte_size;
253 size_t DWARFMappedHash::Header::GetByteSize(const HeaderData &header_data) {
254 return header_data.GetByteSize();
257 lldb::offset_t DWARFMappedHash::Header::Read(lldb_private::DataExtractor &data,
258 lldb::offset_t offset) {
259 offset = MappedHash::Header<Prologue>::Read(data, offset);
260 if (offset != UINT32_MAX) {
261 offset = header_data.Read(data, offset);
266 bool DWARFMappedHash::Header::Read(const lldb_private::DWARFDataExtractor &data,
267 lldb::offset_t *offset_ptr,
268 DIEInfo &hash_data) const {
269 const size_t num_atoms = header_data.atoms.size();
273 for (size_t i = 0; i < num_atoms; ++i) {
274 DWARFFormValue form_value(NULL, header_data.atoms[i].form);
276 if (!form_value.ExtractValue(data, offset_ptr))
279 switch (header_data.atoms[i].type) {
280 case eAtomTypeDIEOffset: // DIE offset, check form for encoding
282 DWARFFormValue::IsDataForm(form_value.Form())
283 ? form_value.Unsigned()
284 : form_value.Reference(header_data.die_base_offset);
287 case eAtomTypeTag: // DW_TAG value for the DIE
288 hash_data.tag = (dw_tag_t)form_value.Unsigned();
291 case eAtomTypeTypeFlags: // Flags from enum TypeFlags
292 hash_data.type_flags = (uint32_t)form_value.Unsigned();
295 case eAtomTypeQualNameHash: // Flags from enum TypeFlags
296 hash_data.qualified_name_hash = form_value.Unsigned();
300 // We can always skip atoms we don't know about
307 void DWARFMappedHash::Header::Dump(lldb_private::Stream &strm,
308 const DIEInfo &hash_data) const {
309 const size_t num_atoms = header_data.atoms.size();
310 for (size_t i = 0; i < num_atoms; ++i) {
312 strm.PutCString(", ");
314 DWARFFormValue form_value(NULL, header_data.atoms[i].form);
315 switch (header_data.atoms[i].type) {
316 case eAtomTypeDIEOffset: // DIE offset, check form for encoding
317 strm.Printf("{0x%8.8x}", hash_data.offset);
320 case eAtomTypeTag: // DW_TAG value for the DIE
322 const char *tag_cstr = lldb_private::DW_TAG_value_to_name(hash_data.tag);
324 strm.PutCString(tag_cstr);
326 strm.Printf("DW_TAG_(0x%4.4x)", hash_data.tag);
329 case eAtomTypeTypeFlags: // Flags from enum TypeFlags
330 strm.Printf("0x%2.2x", hash_data.type_flags);
331 if (hash_data.type_flags) {
332 strm.PutCString(" (");
333 if (hash_data.type_flags & eTypeFlagClassIsImplementation)
334 strm.PutCString(" implementation");
335 strm.PutCString(" )");
339 case eAtomTypeQualNameHash: // Flags from enum TypeFlags
340 strm.Printf("0x%8.8x", hash_data.qualified_name_hash);
344 strm.Printf("AtomType(0x%x)", header_data.atoms[i].type);
350 DWARFMappedHash::MemoryTable::MemoryTable(
351 lldb_private::DWARFDataExtractor &table_data,
352 const lldb_private::DWARFDataExtractor &string_table, const char *name)
353 : MappedHash::MemoryTable<uint32_t, Header, DIEInfoArray>(table_data),
354 m_data(table_data), m_string_table(string_table), m_name(name) {}
357 DWARFMappedHash::MemoryTable::GetStringForKeyType(KeyType key) const {
358 // The key in the DWARF table is the .debug_str offset for the string
359 return m_string_table.PeekCStr(key);
362 bool DWARFMappedHash::MemoryTable::ReadHashData(uint32_t hash_data_offset,
363 HashData &hash_data) const {
364 lldb::offset_t offset = hash_data_offset;
365 offset += 4; // Skip string table offset that contains offset of hash name in
367 const uint32_t count = m_data.GetU32(&offset);
369 hash_data.resize(count);
370 for (uint32_t i = 0; i < count; ++i) {
371 if (!m_header.Read(m_data, &offset, hash_data[i]))
379 DWARFMappedHash::MemoryTable::Result
380 DWARFMappedHash::MemoryTable::GetHashDataForName(
381 llvm::StringRef name, lldb::offset_t *hash_data_offset_ptr,
383 pair.key = m_data.GetU32(hash_data_offset_ptr);
386 // If the key is zero, this terminates our chain of HashData objects for this
389 return eResultEndOfHashData;
391 // There definitely should be a string for this string offset, if there
392 // isn't, there is something wrong, return and error
393 const char *strp_cstr = m_string_table.PeekCStr(pair.key);
394 if (strp_cstr == NULL) {
395 *hash_data_offset_ptr = UINT32_MAX;
399 const uint32_t count = m_data.GetU32(hash_data_offset_ptr);
400 const size_t min_total_hash_data_size =
401 count * m_header.header_data.GetMinimumHashDataByteSize();
403 m_data.ValidOffsetForDataOfSize(*hash_data_offset_ptr,
404 min_total_hash_data_size)) {
405 // We have at least one HashData entry, and we have enough data to parse at
406 // least "count" HashData entries.
408 // First make sure the entire C string matches...
409 const bool match = name == strp_cstr;
411 if (!match && m_header.header_data.HashDataHasFixedByteSize()) {
412 // If the string doesn't match and we have fixed size data, we can just
413 // add the total byte size of all HashData objects to the hash data
414 // offset and be done...
415 *hash_data_offset_ptr += min_total_hash_data_size;
417 // If the string does match, or we don't have fixed size data then we
418 // need to read the hash data as a stream. If the string matches we also
419 // append all HashData objects to the value array.
420 for (uint32_t i = 0; i < count; ++i) {
422 if (m_header.Read(m_data, hash_data_offset_ptr, die_info)) {
423 // Only happened if the HashData of the string matched...
425 pair.value.push_back(die_info);
427 // Something went wrong while reading the data
428 *hash_data_offset_ptr = UINT32_MAX;
433 // Return the correct response depending on if the string matched or not...
435 return eResultKeyMatch; // The key (cstring) matches and we have lookup
438 return eResultKeyMismatch; // The key doesn't match, this function will
440 // again for the next key/value or the key terminator which in our case is
441 // a zero .debug_str offset.
443 *hash_data_offset_ptr = UINT32_MAX;
448 DWARFMappedHash::MemoryTable::Result
449 DWARFMappedHash::MemoryTable::AppendHashDataForRegularExpression(
450 const lldb_private::RegularExpression ®ex,
451 lldb::offset_t *hash_data_offset_ptr, Pair &pair) const {
452 pair.key = m_data.GetU32(hash_data_offset_ptr);
453 // If the key is zero, this terminates our chain of HashData objects for this
456 return eResultEndOfHashData;
458 // There definitely should be a string for this string offset, if there
459 // isn't, there is something wrong, return and error
460 const char *strp_cstr = m_string_table.PeekCStr(pair.key);
461 if (strp_cstr == NULL)
464 const uint32_t count = m_data.GetU32(hash_data_offset_ptr);
465 const size_t min_total_hash_data_size =
466 count * m_header.header_data.GetMinimumHashDataByteSize();
468 m_data.ValidOffsetForDataOfSize(*hash_data_offset_ptr,
469 min_total_hash_data_size)) {
470 const bool match = regex.Execute(llvm::StringRef(strp_cstr));
472 if (!match && m_header.header_data.HashDataHasFixedByteSize()) {
473 // If the regex doesn't match and we have fixed size data, we can just
474 // add the total byte size of all HashData objects to the hash data
475 // offset and be done...
476 *hash_data_offset_ptr += min_total_hash_data_size;
478 // If the string does match, or we don't have fixed size data then we
479 // need to read the hash data as a stream. If the string matches we also
480 // append all HashData objects to the value array.
481 for (uint32_t i = 0; i < count; ++i) {
483 if (m_header.Read(m_data, hash_data_offset_ptr, die_info)) {
484 // Only happened if the HashData of the string matched...
486 pair.value.push_back(die_info);
488 // Something went wrong while reading the data
489 *hash_data_offset_ptr = UINT32_MAX;
494 // Return the correct response depending on if the string matched or not...
496 return eResultKeyMatch; // The key (cstring) matches and we have lookup
499 return eResultKeyMismatch; // The key doesn't match, this function will
501 // again for the next key/value or the key terminator which in our case is
502 // a zero .debug_str offset.
504 *hash_data_offset_ptr = UINT32_MAX;
509 size_t DWARFMappedHash::MemoryTable::AppendAllDIEsThatMatchingRegex(
510 const lldb_private::RegularExpression ®ex,
511 DIEInfoArray &die_info_array) const {
512 const uint32_t hash_count = m_header.hashes_count;
514 for (uint32_t offset_idx = 0; offset_idx < hash_count; ++offset_idx) {
515 lldb::offset_t hash_data_offset = GetHashDataOffset(offset_idx);
516 while (hash_data_offset != UINT32_MAX) {
517 const lldb::offset_t prev_hash_data_offset = hash_data_offset;
519 AppendHashDataForRegularExpression(regex, &hash_data_offset, pair);
520 if (prev_hash_data_offset == hash_data_offset)
523 // Check the result of getting our hash data
524 switch (hash_result) {
525 case eResultKeyMatch:
526 case eResultKeyMismatch:
527 // Whether we matches or not, it doesn't matter, we keep looking.
530 case eResultEndOfHashData:
532 hash_data_offset = UINT32_MAX;
537 die_info_array.swap(pair.value);
538 return die_info_array.size();
541 size_t DWARFMappedHash::MemoryTable::AppendAllDIEsInRange(
542 const uint32_t die_offset_start, const uint32_t die_offset_end,
543 DIEInfoArray &die_info_array) const {
544 const uint32_t hash_count = m_header.hashes_count;
545 for (uint32_t offset_idx = 0; offset_idx < hash_count; ++offset_idx) {
547 lldb::offset_t hash_data_offset = GetHashDataOffset(offset_idx);
548 while (!done && hash_data_offset != UINT32_MAX) {
549 KeyType key = m_data.GetU32(&hash_data_offset);
550 // If the key is zero, this terminates our chain of HashData objects for
555 const uint32_t count = m_data.GetU32(&hash_data_offset);
556 for (uint32_t i = 0; i < count; ++i) {
558 if (m_header.Read(m_data, &hash_data_offset, die_info)) {
559 if (die_info.offset == 0)
561 if (die_offset_start <= die_info.offset &&
562 die_info.offset < die_offset_end)
563 die_info_array.push_back(die_info);
568 return die_info_array.size();
571 size_t DWARFMappedHash::MemoryTable::FindByName(llvm::StringRef name,
572 DIEArray &die_offsets) {
576 DIEInfoArray die_info_array;
577 if (FindByName(name, die_info_array))
578 DWARFMappedHash::ExtractDIEArray(die_info_array, die_offsets);
579 return die_info_array.size();
582 size_t DWARFMappedHash::MemoryTable::FindByNameAndTag(llvm::StringRef name,
584 DIEArray &die_offsets) {
585 DIEInfoArray die_info_array;
586 if (FindByName(name, die_info_array))
587 DWARFMappedHash::ExtractDIEArray(die_info_array, tag, die_offsets);
588 return die_info_array.size();
591 size_t DWARFMappedHash::MemoryTable::FindByNameAndTagAndQualifiedNameHash(
592 llvm::StringRef name, const dw_tag_t tag,
593 const uint32_t qualified_name_hash, DIEArray &die_offsets) {
594 DIEInfoArray die_info_array;
595 if (FindByName(name, die_info_array))
596 DWARFMappedHash::ExtractDIEArray(die_info_array, tag, qualified_name_hash,
598 return die_info_array.size();
601 size_t DWARFMappedHash::MemoryTable::FindCompleteObjCClassByName(
602 llvm::StringRef name, DIEArray &die_offsets, bool must_be_implementation) {
603 DIEInfoArray die_info_array;
604 if (FindByName(name, die_info_array)) {
605 if (must_be_implementation &&
606 GetHeader().header_data.ContainsAtom(eAtomTypeTypeFlags)) {
607 // If we have two atoms, then we have the DIE offset and the type flags
608 // so we can find the objective C class efficiently.
609 DWARFMappedHash::ExtractTypesFromDIEArray(die_info_array, UINT32_MAX,
610 eTypeFlagClassIsImplementation,
613 // We don't only want the one true definition, so try and see what we can
614 // find, and only return class or struct DIEs. If we do have the full
615 // implementation, then return it alone, else return all possible
617 const bool return_implementation_only_if_available = true;
618 DWARFMappedHash::ExtractClassOrStructDIEArray(
619 die_info_array, return_implementation_only_if_available, die_offsets);
622 return die_offsets.size();
625 size_t DWARFMappedHash::MemoryTable::FindByName(llvm::StringRef name,
626 DIEInfoArray &die_info_array) {
631 size_t old_size = die_info_array.size();
632 if (Find(name, kv_pair)) {
633 die_info_array.swap(kv_pair.value);
634 return die_info_array.size() - old_size;