1 //===-- DWARFUnit.cpp -------------------------------------------*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
11 #include "lldb/Core/Module.h"
12 #include "lldb/Host/StringConvert.h"
13 #include "lldb/Symbol/ObjectFile.h"
14 #include "lldb/Utility/LLDBAssert.h"
15 #include "lldb/Utility/StreamString.h"
16 #include "lldb/Utility/Timer.h"
17 #include "llvm/Object/Error.h"
19 #include "DWARFCompileUnit.h"
20 #include "DWARFDebugAranges.h"
21 #include "DWARFDebugInfo.h"
22 #include "DWARFTypeUnit.h"
23 #include "LogChannelDWARF.h"
24 #include "SymbolFileDWARFDwo.h"
27 using namespace lldb_private;
32 DWARFUnit::DWARFUnit(SymbolFileDWARF &dwarf, lldb::user_id_t uid,
33 const DWARFUnitHeader &header,
34 const DWARFAbbreviationDeclarationSet &abbrevs,
35 DIERef::Section section)
36 : UserID(uid), m_dwarf(dwarf), m_header(header), m_abbrevs(&abbrevs),
37 m_cancel_scopes(false), m_section(section) {}
39 DWARFUnit::~DWARFUnit() = default;
41 // Parses first DIE of a compile unit.
42 void DWARFUnit::ExtractUnitDIEIfNeeded() {
44 llvm::sys::ScopedReader lock(m_first_die_mutex);
46 return; // Already parsed
48 llvm::sys::ScopedWriter lock(m_first_die_mutex);
50 return; // Already parsed
52 static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
53 Timer scoped_timer(func_cat, "%8.8x: DWARFUnit::ExtractUnitDIEIfNeeded()",
56 // Set the offset to that of the first DIE and calculate the start of the
57 // next compilation unit header.
58 lldb::offset_t offset = GetFirstDIEOffset();
60 // We are in our compile unit, parse starting at the offset we were told to
62 const DWARFDataExtractor &data = GetData();
63 if (offset < GetNextUnitOffset() &&
64 m_first_die.Extract(data, this, &offset)) {
65 AddUnitDIE(m_first_die);
70 // Parses a compile unit and indexes its DIEs if it hasn't already been done.
71 // It will leave this compile unit extracted forever.
72 void DWARFUnit::ExtractDIEsIfNeeded() {
73 m_cancel_scopes = true;
76 llvm::sys::ScopedReader lock(m_die_array_mutex);
77 if (!m_die_array.empty())
78 return; // Already parsed
80 llvm::sys::ScopedWriter lock(m_die_array_mutex);
81 if (!m_die_array.empty())
82 return; // Already parsed
84 ExtractDIEsRWLocked();
87 // Parses a compile unit and indexes its DIEs if it hasn't already been done.
88 // It will clear this compile unit after returned instance gets out of scope,
89 // no other ScopedExtractDIEs instance is running for this compile unit
90 // and no ExtractDIEsIfNeeded() has been executed during this ScopedExtractDIEs
92 DWARFUnit::ScopedExtractDIEs DWARFUnit::ExtractDIEsScoped() {
93 ScopedExtractDIEs scoped(*this);
96 llvm::sys::ScopedReader lock(m_die_array_mutex);
97 if (!m_die_array.empty())
98 return scoped; // Already parsed
100 llvm::sys::ScopedWriter lock(m_die_array_mutex);
101 if (!m_die_array.empty())
102 return scoped; // Already parsed
104 // Otherwise m_die_array would be already populated.
105 lldbassert(!m_cancel_scopes);
107 ExtractDIEsRWLocked();
108 scoped.m_clear_dies = true;
112 DWARFUnit::ScopedExtractDIEs::ScopedExtractDIEs(DWARFUnit &cu) : m_cu(&cu) {
113 m_cu->m_die_array_scoped_mutex.lock_shared();
116 DWARFUnit::ScopedExtractDIEs::~ScopedExtractDIEs() {
119 m_cu->m_die_array_scoped_mutex.unlock_shared();
120 if (!m_clear_dies || m_cu->m_cancel_scopes)
122 // Be sure no other ScopedExtractDIEs is running anymore.
123 llvm::sys::ScopedWriter lock_scoped(m_cu->m_die_array_scoped_mutex);
124 llvm::sys::ScopedWriter lock(m_cu->m_die_array_mutex);
125 if (m_cu->m_cancel_scopes)
127 m_cu->ClearDIEsRWLocked();
130 DWARFUnit::ScopedExtractDIEs::ScopedExtractDIEs(ScopedExtractDIEs &&rhs)
131 : m_cu(rhs.m_cu), m_clear_dies(rhs.m_clear_dies) {
135 DWARFUnit::ScopedExtractDIEs &DWARFUnit::ScopedExtractDIEs::operator=(
136 DWARFUnit::ScopedExtractDIEs &&rhs) {
139 m_clear_dies = rhs.m_clear_dies;
143 // Parses a compile unit and indexes its DIEs, m_die_array_mutex must be
144 // held R/W and m_die_array must be empty.
145 void DWARFUnit::ExtractDIEsRWLocked() {
146 llvm::sys::ScopedWriter first_die_lock(m_first_die_mutex);
148 static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
149 Timer scoped_timer(func_cat, "%8.8x: DWARFUnit::ExtractDIEsIfNeeded()",
152 // Set the offset to that of the first DIE and calculate the start of the
153 // next compilation unit header.
154 lldb::offset_t offset = GetFirstDIEOffset();
155 lldb::offset_t next_cu_offset = GetNextUnitOffset();
157 DWARFDebugInfoEntry die;
160 // We are in our compile unit, parse starting at the offset we were told to
162 const DWARFDataExtractor &data = GetData();
163 std::vector<uint32_t> die_index_stack;
164 die_index_stack.reserve(32);
165 die_index_stack.push_back(0);
166 bool prev_die_had_children = false;
167 while (offset < next_cu_offset && die.Extract(data, this, &offset)) {
168 const bool null_die = die.IsNULL();
170 assert(m_die_array.empty() && "Compile unit DIE already added");
172 // The average bytes per DIE entry has been seen to be around 14-20 so
173 // lets pre-reserve half of that since we are now stripping the NULL
176 // Only reserve the memory if we are adding children of the main
177 // compile unit DIE. The compile unit DIE is always the first entry, so
178 // if our size is 1, then we are adding the first compile unit child
179 // DIE and should reserve the memory.
180 m_die_array.reserve(GetDebugInfoSize() / 24);
181 m_die_array.push_back(die);
184 AddUnitDIE(m_die_array.front());
186 // With -fsplit-dwarf-inlining, clang will emit non-empty skeleton compile
187 // units. We are not able to access these DIE *and* the dwo file
188 // simultaneously. We also don't need to do that as the dwo file will
189 // contain a superset of information. So, we don't even attempt to parse
190 // any remaining DIEs.
191 if (m_dwo_symbol_file) {
192 m_die_array.front().SetHasChildren(false);
198 if (prev_die_had_children) {
199 // This will only happen if a DIE says is has children but all it
200 // contains is a NULL tag. Since we are removing the NULL DIEs from
201 // the list (saves up to 25% in C++ code), we need a way to let the
202 // DIE know that it actually doesn't have children.
203 if (!m_die_array.empty())
204 m_die_array.back().SetHasChildren(false);
207 die.SetParentIndex(m_die_array.size() - die_index_stack[depth - 1]);
209 if (die_index_stack.back())
210 m_die_array[die_index_stack.back()].SetSiblingIndex(
211 m_die_array.size() - die_index_stack.back());
213 // Only push the DIE if it isn't a NULL DIE
214 m_die_array.push_back(die);
220 if (!die_index_stack.empty())
221 die_index_stack.pop_back();
225 prev_die_had_children = false;
227 die_index_stack.back() = m_die_array.size() - 1;
229 const bool die_has_children = die.HasChildren();
230 if (die_has_children) {
231 die_index_stack.push_back(0);
234 prev_die_had_children = die_has_children;
238 break; // We are done with this compile unit!
241 if (!m_die_array.empty()) {
243 // Only needed for the assertion.
244 m_first_die.SetHasChildren(m_die_array.front().HasChildren());
245 lldbassert(m_first_die == m_die_array.front());
247 m_first_die = m_die_array.front();
250 m_die_array.shrink_to_fit();
252 if (m_dwo_symbol_file) {
253 DWARFUnit *dwo_cu = m_dwo_symbol_file->GetCompileUnit();
254 dwo_cu->ExtractDIEsIfNeeded();
258 // This is used when a split dwarf is enabled.
259 // A skeleton compilation unit may contain the DW_AT_str_offsets_base attribute
260 // that points to the first string offset of the CU contribution to the
261 // .debug_str_offsets. At the same time, the corresponding split debug unit also
262 // may use DW_FORM_strx* forms pointing to its own .debug_str_offsets.dwo and
263 // for that case, we should find the offset (skip the section header).
264 static void SetDwoStrOffsetsBase(DWARFUnit *dwo_cu) {
265 lldb::offset_t baseOffset = 0;
267 const DWARFDataExtractor &strOffsets =
268 dwo_cu->GetSymbolFileDWARF().GetDWARFContext().getOrLoadStrOffsetsData();
269 uint64_t length = strOffsets.GetU32(&baseOffset);
270 if (length == 0xffffffff)
271 length = strOffsets.GetU64(&baseOffset);
274 if (strOffsets.GetU16(&baseOffset) < 5)
280 dwo_cu->SetStrOffsetsBase(baseOffset);
283 // m_die_array_mutex must be already held as read/write.
284 void DWARFUnit::AddUnitDIE(const DWARFDebugInfoEntry &cu_die) {
285 llvm::Optional<uint64_t> addr_base, gnu_addr_base, ranges_base,
288 DWARFAttributes attributes;
289 size_t num_attributes = cu_die.GetAttributes(this, attributes);
290 for (size_t i = 0; i < num_attributes; ++i) {
291 dw_attr_t attr = attributes.AttributeAtIndex(i);
292 DWARFFormValue form_value;
293 if (!attributes.ExtractFormValueAtIndex(i, form_value))
296 case DW_AT_addr_base:
297 addr_base = form_value.Unsigned();
298 SetAddrBase(*addr_base);
300 case DW_AT_rnglists_base:
301 ranges_base = form_value.Unsigned();
302 SetRangesBase(*ranges_base);
304 case DW_AT_str_offsets_base:
305 SetStrOffsetsBase(form_value.Unsigned());
308 SetBaseAddress(form_value.Address());
311 // If the value was already set by DW_AT_low_pc, don't update it.
312 if (m_base_addr == LLDB_INVALID_ADDRESS)
313 SetBaseAddress(form_value.Address());
315 case DW_AT_stmt_list:
316 m_line_table_offset = form_value.Unsigned();
318 case DW_AT_GNU_addr_base:
319 gnu_addr_base = form_value.Unsigned();
321 case DW_AT_GNU_ranges_base:
322 gnu_ranges_base = form_value.Unsigned();
327 std::unique_ptr<SymbolFileDWARFDwo> dwo_symbol_file =
328 m_dwarf.GetDwoSymbolFileForCompileUnit(*this, cu_die);
329 if (!dwo_symbol_file)
332 DWARFUnit *dwo_cu = dwo_symbol_file->GetCompileUnit();
334 return; // Can't fetch the compile unit from the dwo file.
336 DWARFBaseDIE dwo_cu_die = dwo_cu->GetUnitDIEOnly();
337 if (!dwo_cu_die.IsValid())
338 return; // Can't fetch the compile unit DIE from the dwo file.
340 uint64_t main_dwo_id =
341 cu_die.GetAttributeValueAsUnsigned(this, DW_AT_GNU_dwo_id, 0);
342 uint64_t sub_dwo_id =
343 dwo_cu_die.GetAttributeValueAsUnsigned(DW_AT_GNU_dwo_id, 0);
344 if (main_dwo_id != sub_dwo_id)
345 return; // The 2 dwo ID isn't match. Don't use the dwo file as it belongs to
346 // a differectn compilation.
348 m_dwo_symbol_file = std::move(dwo_symbol_file);
350 // Here for DWO CU we want to use the address base set in the skeleton unit
351 // (DW_AT_addr_base) if it is available and use the DW_AT_GNU_addr_base
352 // otherwise. We do that because pre-DWARF v5 could use the DW_AT_GNU_*
353 // attributes which were applicable to the DWO units. The corresponding
354 // DW_AT_* attributes standardized in DWARF v5 are also applicable to the main
357 dwo_cu->SetAddrBase(*addr_base);
358 else if (gnu_addr_base)
359 dwo_cu->SetAddrBase(*gnu_addr_base);
362 dwo_cu->SetRangesBase(*ranges_base);
363 else if (gnu_ranges_base)
364 dwo_cu->SetRangesBase(*gnu_ranges_base);
366 for (size_t i = 0; i < m_dwo_symbol_file->DebugInfo()->GetNumUnits(); ++i) {
367 DWARFUnit *unit = m_dwo_symbol_file->DebugInfo()->GetUnitAtIndex(i);
368 SetDwoStrOffsetsBase(unit);
372 DWARFDIE DWARFUnit::LookupAddress(const dw_addr_t address) {
374 const DWARFDebugAranges &func_aranges = GetFunctionAranges();
376 // Re-check the aranges auto pointer contents in case it was created above
377 if (!func_aranges.IsEmpty())
378 return GetDIE(func_aranges.FindAddress(address));
383 size_t DWARFUnit::AppendDIEsWithTag(const dw_tag_t tag,
384 std::vector<DWARFDIE> &dies,
385 uint32_t depth) const {
386 size_t old_size = dies.size();
388 llvm::sys::ScopedReader lock(m_die_array_mutex);
389 DWARFDebugInfoEntry::const_iterator pos;
390 DWARFDebugInfoEntry::const_iterator end = m_die_array.end();
391 for (pos = m_die_array.begin(); pos != end; ++pos) {
392 if (pos->Tag() == tag)
393 dies.emplace_back(this, &(*pos));
397 // Return the number of DIEs added to the collection
398 return dies.size() - old_size;
401 size_t DWARFUnit::GetDebugInfoSize() const {
402 return GetLengthByteSize() + GetLength() - GetHeaderByteSize();
405 const DWARFAbbreviationDeclarationSet *DWARFUnit::GetAbbreviations() const {
409 dw_offset_t DWARFUnit::GetAbbrevOffset() const {
410 return m_abbrevs ? m_abbrevs->GetOffset() : DW_INVALID_OFFSET;
413 dw_offset_t DWARFUnit::GetLineTableOffset() {
414 ExtractUnitDIEIfNeeded();
415 return m_line_table_offset;
418 void DWARFUnit::SetAddrBase(dw_addr_t addr_base) { m_addr_base = addr_base; }
420 void DWARFUnit::SetRangesBase(dw_addr_t ranges_base) {
421 m_ranges_base = ranges_base;
424 void DWARFUnit::SetStrOffsetsBase(dw_offset_t str_offsets_base) {
425 m_str_offsets_base = str_offsets_base;
428 // It may be called only with m_die_array_mutex held R/W.
429 void DWARFUnit::ClearDIEsRWLocked() {
431 m_die_array.shrink_to_fit();
433 if (m_dwo_symbol_file)
434 m_dwo_symbol_file->GetCompileUnit()->ClearDIEsRWLocked();
437 lldb::ByteOrder DWARFUnit::GetByteOrder() const {
438 return m_dwarf.GetObjectFile()->GetByteOrder();
441 TypeSystem *DWARFUnit::GetTypeSystem() {
442 return m_dwarf.GetTypeSystemForLanguage(GetLanguageType());
445 void DWARFUnit::SetBaseAddress(dw_addr_t base_addr) { m_base_addr = base_addr; }
447 // Compare function DWARFDebugAranges::Range structures
448 static bool CompareDIEOffset(const DWARFDebugInfoEntry &die,
449 const dw_offset_t die_offset) {
450 return die.GetOffset() < die_offset;
455 // Get the DIE (Debug Information Entry) with the specified offset by first
456 // checking if the DIE is contained within this compile unit and grabbing the
457 // DIE from this compile unit. Otherwise we grab the DIE from the DWARF file.
459 DWARFUnit::GetDIE(dw_offset_t die_offset) {
460 if (die_offset != DW_INVALID_OFFSET) {
461 if (GetDwoSymbolFile())
462 return GetDwoSymbolFile()->GetCompileUnit()->GetDIE(die_offset);
464 if (ContainsDIEOffset(die_offset)) {
465 ExtractDIEsIfNeeded();
466 DWARFDebugInfoEntry::const_iterator end = m_die_array.cend();
467 DWARFDebugInfoEntry::const_iterator pos =
468 lower_bound(m_die_array.cbegin(), end, die_offset, CompareDIEOffset);
470 if (die_offset == (*pos).GetOffset())
471 return DWARFDIE(this, &(*pos));
474 GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError(
475 "GetDIE for DIE 0x%" PRIx32 " is outside of its CU 0x%" PRIx32,
476 die_offset, GetOffset());
478 return DWARFDIE(); // Not found
481 DWARFUnit &DWARFUnit::GetNonSkeletonUnit() {
482 if (SymbolFileDWARFDwo *dwo = GetDwoSymbolFile())
483 return *dwo->GetCompileUnit();
487 uint8_t DWARFUnit::GetAddressByteSize(const DWARFUnit *cu) {
489 return cu->GetAddressByteSize();
490 return DWARFUnit::GetDefaultAddressSize();
493 uint8_t DWARFUnit::GetDefaultAddressSize() { return 4; }
495 void *DWARFUnit::GetUserData() const { return m_user_data; }
497 void DWARFUnit::SetUserData(void *d) {
499 if (m_dwo_symbol_file)
500 m_dwo_symbol_file->GetCompileUnit()->SetUserData(d);
503 bool DWARFUnit::Supports_DW_AT_APPLE_objc_complete_type() {
504 return GetProducer() != eProducerLLVMGCC;
507 bool DWARFUnit::DW_AT_decl_file_attributes_are_invalid() {
508 // llvm-gcc makes completely invalid decl file attributes and won't ever be
509 // fixed, so we need to know to ignore these.
510 return GetProducer() == eProducerLLVMGCC;
513 bool DWARFUnit::Supports_unnamed_objc_bitfields() {
514 if (GetProducer() == eProducerClang) {
515 const uint32_t major_version = GetProducerVersionMajor();
516 return major_version > 425 ||
517 (major_version == 425 && GetProducerVersionUpdate() >= 13);
519 return true; // Assume all other compilers didn't have incorrect ObjC bitfield
523 void DWARFUnit::ParseProducerInfo() {
524 m_producer_version_major = UINT32_MAX;
525 m_producer_version_minor = UINT32_MAX;
526 m_producer_version_update = UINT32_MAX;
528 const DWARFDebugInfoEntry *die = GetUnitDIEPtrOnly();
531 const char *producer_cstr =
532 die->GetAttributeValueAsString(this, DW_AT_producer, nullptr);
534 RegularExpression llvm_gcc_regex(
535 llvm::StringRef("^4\\.[012]\\.[01] \\(Based on Apple "
536 "Inc\\. build [0-9]+\\) \\(LLVM build "
538 if (llvm_gcc_regex.Execute(llvm::StringRef(producer_cstr))) {
539 m_producer = eProducerLLVMGCC;
540 } else if (strstr(producer_cstr, "clang")) {
541 static RegularExpression g_clang_version_regex(
542 llvm::StringRef("clang-([0-9]+)\\.([0-9]+)\\.([0-9]+)"));
543 RegularExpression::Match regex_match(3);
544 if (g_clang_version_regex.Execute(llvm::StringRef(producer_cstr),
547 if (regex_match.GetMatchAtIndex(producer_cstr, 1, str))
548 m_producer_version_major =
549 StringConvert::ToUInt32(str.c_str(), UINT32_MAX, 10);
550 if (regex_match.GetMatchAtIndex(producer_cstr, 2, str))
551 m_producer_version_minor =
552 StringConvert::ToUInt32(str.c_str(), UINT32_MAX, 10);
553 if (regex_match.GetMatchAtIndex(producer_cstr, 3, str))
554 m_producer_version_update =
555 StringConvert::ToUInt32(str.c_str(), UINT32_MAX, 10);
557 m_producer = eProducerClang;
558 } else if (strstr(producer_cstr, "GNU"))
559 m_producer = eProducerGCC;
562 if (m_producer == eProducerInvalid)
563 m_producer = eProcucerOther;
566 DWARFProducer DWARFUnit::GetProducer() {
567 if (m_producer == eProducerInvalid)
572 uint32_t DWARFUnit::GetProducerVersionMajor() {
573 if (m_producer_version_major == 0)
575 return m_producer_version_major;
578 uint32_t DWARFUnit::GetProducerVersionMinor() {
579 if (m_producer_version_minor == 0)
581 return m_producer_version_minor;
584 uint32_t DWARFUnit::GetProducerVersionUpdate() {
585 if (m_producer_version_update == 0)
587 return m_producer_version_update;
589 LanguageType DWARFUnit::LanguageTypeFromDWARF(uint64_t val) {
590 // Note: user languages between lo_user and hi_user must be handled
593 case DW_LANG_Mips_Assembler:
594 return eLanguageTypeMipsAssembler;
595 case DW_LANG_GOOGLE_RenderScript:
596 return eLanguageTypeExtRenderScript;
598 return static_cast<LanguageType>(val);
602 LanguageType DWARFUnit::GetLanguageType() {
603 if (m_language_type != eLanguageTypeUnknown)
604 return m_language_type;
606 const DWARFDebugInfoEntry *die = GetUnitDIEPtrOnly();
608 m_language_type = LanguageTypeFromDWARF(
609 die->GetAttributeValueAsUnsigned(this, DW_AT_language, 0));
610 return m_language_type;
613 bool DWARFUnit::GetIsOptimized() {
614 if (m_is_optimized == eLazyBoolCalculate) {
615 const DWARFDebugInfoEntry *die = GetUnitDIEPtrOnly();
617 m_is_optimized = eLazyBoolNo;
618 if (die->GetAttributeValueAsUnsigned(this, DW_AT_APPLE_optimized, 0) ==
620 m_is_optimized = eLazyBoolYes;
624 return m_is_optimized == eLazyBoolYes;
627 FileSpec::Style DWARFUnit::GetPathStyle() {
629 ComputeCompDirAndGuessPathStyle();
630 return m_comp_dir->GetPathStyle();
633 const FileSpec &DWARFUnit::GetCompilationDirectory() {
635 ComputeCompDirAndGuessPathStyle();
639 const FileSpec &DWARFUnit::GetAbsolutePath() {
641 ComputeAbsolutePath();
645 FileSpec DWARFUnit::GetFile(size_t file_idx) {
646 return m_dwarf.GetFile(*this, file_idx);
649 // DWARF2/3 suggests the form hostname:pathname for compilation directory.
650 // Remove the host part if present.
651 static llvm::StringRef
652 removeHostnameFromPathname(llvm::StringRef path_from_dwarf) {
653 llvm::StringRef host, path;
654 std::tie(host, path) = path_from_dwarf.split(':');
656 if (host.contains('/'))
657 return path_from_dwarf;
659 // check whether we have a windows path, and so the first character is a
660 // drive-letter not a hostname.
661 if (host.size() == 1 && llvm::isAlpha(host[0]) && path.startswith("\\"))
662 return path_from_dwarf;
667 static FileSpec resolveCompDir(const FileSpec &path) {
668 bool is_symlink = SymbolFileDWARF::GetSymlinkPaths().FindFileIndex(
669 0, path, /*full*/ true) != UINT32_MAX;
674 namespace fs = llvm::sys::fs;
675 if (fs::get_file_type(path.GetPath(), false) != fs::file_type::symlink_file)
678 FileSpec resolved_symlink;
679 const auto error = FileSystem::Instance().Readlink(path, resolved_symlink);
681 return resolved_symlink;
686 void DWARFUnit::ComputeCompDirAndGuessPathStyle() {
687 m_comp_dir = FileSpec();
688 const DWARFDebugInfoEntry *die = GetUnitDIEPtrOnly();
692 llvm::StringRef comp_dir = removeHostnameFromPathname(
693 die->GetAttributeValueAsString(this, DW_AT_comp_dir, nullptr));
694 if (!comp_dir.empty()) {
695 FileSpec::Style comp_dir_style =
696 FileSpec::GuessPathStyle(comp_dir).getValueOr(FileSpec::Style::native);
697 m_comp_dir = resolveCompDir(FileSpec(comp_dir, comp_dir_style));
699 // Try to detect the style based on the DW_AT_name attribute, but just store
700 // the detected style in the m_comp_dir field.
702 die->GetAttributeValueAsString(this, DW_AT_name, nullptr);
703 m_comp_dir = FileSpec(
704 "", FileSpec::GuessPathStyle(name).getValueOr(FileSpec::Style::native));
708 void DWARFUnit::ComputeAbsolutePath() {
709 m_file_spec = FileSpec();
710 const DWARFDebugInfoEntry *die = GetUnitDIEPtrOnly();
715 FileSpec(die->GetAttributeValueAsString(this, DW_AT_name, nullptr),
718 if (m_file_spec->IsRelative())
719 m_file_spec->MakeAbsolute(GetCompilationDirectory());
722 SymbolFileDWARFDwo *DWARFUnit::GetDwoSymbolFile() const {
723 return m_dwo_symbol_file.get();
726 const DWARFDebugAranges &DWARFUnit::GetFunctionAranges() {
727 if (m_func_aranges_up == nullptr) {
728 m_func_aranges_up.reset(new DWARFDebugAranges());
729 const DWARFDebugInfoEntry *die = DIEPtr();
731 die->BuildFunctionAddressRangeTable(this, m_func_aranges_up.get());
733 if (m_dwo_symbol_file) {
734 DWARFUnit *dwo_cu = m_dwo_symbol_file->GetCompileUnit();
735 const DWARFDebugInfoEntry *dwo_die = dwo_cu->DIEPtr();
737 dwo_die->BuildFunctionAddressRangeTable(dwo_cu,
738 m_func_aranges_up.get());
741 const bool minimize = false;
742 m_func_aranges_up->Sort(minimize);
744 return *m_func_aranges_up;
747 llvm::Expected<DWARFUnitHeader>
748 DWARFUnitHeader::extract(const DWARFDataExtractor &data, DIERef::Section section,
749 lldb::offset_t *offset_ptr) {
750 DWARFUnitHeader header;
751 header.m_offset = *offset_ptr;
752 header.m_length = data.GetDWARFInitialLength(offset_ptr);
753 header.m_version = data.GetU16(offset_ptr);
754 if (header.m_version == 5) {
755 header.m_unit_type = data.GetU8(offset_ptr);
756 header.m_addr_size = data.GetU8(offset_ptr);
757 header.m_abbr_offset = data.GetDWARFOffset(offset_ptr);
758 if (header.m_unit_type == llvm::dwarf::DW_UT_skeleton)
759 header.m_dwo_id = data.GetU64(offset_ptr);
761 header.m_abbr_offset = data.GetDWARFOffset(offset_ptr);
762 header.m_addr_size = data.GetU8(offset_ptr);
764 section == DIERef::Section::DebugTypes ? DW_UT_type : DW_UT_compile;
767 if (header.IsTypeUnit()) {
768 header.m_type_hash = data.GetU64(offset_ptr);
769 header.m_type_offset = data.GetDWARFOffset(offset_ptr);
772 bool length_OK = data.ValidOffset(header.GetNextUnitOffset() - 1);
773 bool version_OK = SymbolFileDWARF::SupportedVersion(header.m_version);
774 bool addr_size_OK = (header.m_addr_size == 4) || (header.m_addr_size == 8);
775 bool type_offset_OK =
776 !header.IsTypeUnit() || (header.m_type_offset <= header.GetLength());
779 return llvm::make_error<llvm::object::GenericBinaryError>(
780 "Invalid unit length");
782 return llvm::make_error<llvm::object::GenericBinaryError>(
783 "Unsupported unit version");
785 return llvm::make_error<llvm::object::GenericBinaryError>(
786 "Invalid unit address size");
788 return llvm::make_error<llvm::object::GenericBinaryError>(
789 "Type offset out of range");
794 llvm::Expected<DWARFUnitSP>
795 DWARFUnit::extract(SymbolFileDWARF &dwarf, user_id_t uid,
796 const DWARFDataExtractor &debug_info,
797 DIERef::Section section, lldb::offset_t *offset_ptr) {
798 assert(debug_info.ValidOffset(*offset_ptr));
800 auto expected_header =
801 DWARFUnitHeader::extract(debug_info, section, offset_ptr);
802 if (!expected_header)
803 return expected_header.takeError();
805 const DWARFDebugAbbrev *abbr = dwarf.DebugAbbrev();
807 return llvm::make_error<llvm::object::GenericBinaryError>(
808 "No debug_abbrev data");
810 bool abbr_offset_OK =
811 dwarf.GetDWARFContext().getOrLoadAbbrevData().ValidOffset(
812 expected_header->GetAbbrOffset());
814 return llvm::make_error<llvm::object::GenericBinaryError>(
815 "Abbreviation offset for unit is not valid");
817 const DWARFAbbreviationDeclarationSet *abbrevs =
818 abbr->GetAbbreviationDeclarationSet(expected_header->GetAbbrOffset());
820 return llvm::make_error<llvm::object::GenericBinaryError>(
821 "No abbrev exists at the specified offset.");
823 if (expected_header->IsTypeUnit())
825 new DWARFTypeUnit(dwarf, uid, *expected_header, *abbrevs, section));
827 new DWARFCompileUnit(dwarf, uid, *expected_header, *abbrevs, section));
830 const lldb_private::DWARFDataExtractor &DWARFUnit::GetData() const {
831 return m_section == DIERef::Section::DebugTypes
832 ? m_dwarf.GetDWARFContext().getOrLoadDebugTypesData()
833 : m_dwarf.GetDWARFContext().getOrLoadDebugInfoData();
836 uint32_t DWARFUnit::GetHeaderByteSize() const {
837 switch (m_header.GetUnitType()) {
838 case llvm::dwarf::DW_UT_compile:
839 case llvm::dwarf::DW_UT_partial:
840 return GetVersion() < 5 ? 11 : 12;
841 case llvm::dwarf::DW_UT_skeleton:
842 case llvm::dwarf::DW_UT_split_compile:
844 case llvm::dwarf::DW_UT_type:
845 case llvm::dwarf::DW_UT_split_type:
846 return GetVersion() < 5 ? 23 : 24;
848 llvm_unreachable("invalid UnitType.");
851 llvm::Expected<DWARFRangeList>
852 DWARFUnit::FindRnglistFromOffset(dw_offset_t offset) const {
853 const DWARFDebugRangesBase *debug_ranges;
854 llvm::StringRef section;
855 if (GetVersion() <= 4) {
856 debug_ranges = m_dwarf.GetDebugRanges();
857 section = "debug_ranges";
859 debug_ranges = m_dwarf.GetDebugRngLists();
860 section = "debug_rnglists";
863 return llvm::make_error<llvm::object::GenericBinaryError>("No " + section +
866 DWARFRangeList ranges;
867 debug_ranges->FindRanges(this, offset, ranges);
871 llvm::Expected<DWARFRangeList>
872 DWARFUnit::FindRnglistFromIndex(uint32_t index) const {
873 const DWARFDebugRangesBase *debug_rnglists = m_dwarf.GetDebugRngLists();
875 return llvm::make_error<llvm::object::GenericBinaryError>(
876 "No debug_rnglists section");
877 return FindRnglistFromOffset(debug_rnglists->GetOffset(index));