diff options
Diffstat (limited to 'lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp')
| -rw-r--r-- | lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp | 487 |
1 files changed, 307 insertions, 180 deletions
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index c982d59c2830..d45a8b56efe4 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -94,6 +94,8 @@ using namespace lldb; using namespace lldb_private; +char SymbolFileDWARF::ID; + // static inline bool // child_requires_parent_class_union_or_struct_to_be_completed (dw_tag_t tag) //{ @@ -179,36 +181,46 @@ ParseLLVMLineTable(lldb_private::DWARFContext &context, return *line_table; } -static FileSpecList ParseSupportFilesFromPrologue( - const lldb::ModuleSP &module, - const llvm::DWARFDebugLine::Prologue &prologue, FileSpec::Style style, - llvm::StringRef compile_dir = {}, FileSpec first_file = {}) { +static llvm::Optional<std::string> +GetFileByIndex(const llvm::DWARFDebugLine::Prologue &prologue, size_t idx, + llvm::StringRef compile_dir, FileSpec::Style style) { + // Try to get an absolute path first. + std::string abs_path; + auto absolute = llvm::DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath; + if (prologue.getFileNameByIndex(idx, compile_dir, absolute, abs_path, style)) + return std::move(abs_path); + + // Otherwise ask for a relative path. + std::string rel_path; + auto relative = llvm::DILineInfoSpecifier::FileLineInfoKind::Default; + if (!prologue.getFileNameByIndex(idx, compile_dir, relative, rel_path, style)) + return {}; + return std::move(rel_path); +} + +static FileSpecList +ParseSupportFilesFromPrologue(const lldb::ModuleSP &module, + const llvm::DWARFDebugLine::Prologue &prologue, + FileSpec::Style style, + llvm::StringRef compile_dir = {}) { FileSpecList support_files; - support_files.Append(first_file); + size_t first_file = 0; + if (prologue.getVersion() <= 4) { + // File index 0 is not valid before DWARF v5. Add a dummy entry to ensure + // support file list indices match those we get from the debug info and line + // tables. + support_files.Append(FileSpec()); + first_file = 1; + } const size_t number_of_files = prologue.FileNames.size(); - for (size_t idx = 1; idx <= number_of_files; ++idx) { - std::string original_file; - if (!prologue.getFileNameByIndex( - idx, compile_dir, - llvm::DILineInfoSpecifier::FileLineInfoKind::Default, original_file, - style)) { - // Always add an entry so the indexes remain correct. - support_files.EmplaceBack(); - continue; - } - + for (size_t idx = first_file; idx <= number_of_files; ++idx) { std::string remapped_file; - if (!prologue.getFileNameByIndex( - idx, compile_dir, - llvm::DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, - remapped_file, style)) { - // Always add an entry so the indexes remain correct. - support_files.EmplaceBack(original_file, style); - continue; - } + if (auto file_path = GetFileByIndex(prologue, idx, compile_dir, style)) + if (!module->RemapSourceFile(llvm::StringRef(*file_path), remapped_file)) + remapped_file = std::move(*file_path); - module->RemapSourceFile(llvm::StringRef(original_file), remapped_file); + // Unconditionally add an entry, so the indices match up. support_files.EmplaceBack(remapped_file, style); } @@ -585,22 +597,6 @@ void SymbolFileDWARF::LoadSectionData(lldb::SectionType sect_type, m_objfile_sp->ReadSectionData(section_sp.get(), data); } -const DWARFDataExtractor &SymbolFileDWARF::DebugLocData() { - const DWARFDataExtractor &debugLocData = get_debug_loc_data(); - if (debugLocData.GetByteSize() > 0) - return debugLocData; - return get_debug_loclists_data(); -} - -const DWARFDataExtractor &SymbolFileDWARF::get_debug_loc_data() { - return GetCachedSectionData(eSectionTypeDWARFDebugLoc, m_data_debug_loc); -} - -const DWARFDataExtractor &SymbolFileDWARF::get_debug_loclists_data() { - return GetCachedSectionData(eSectionTypeDWARFDebugLocLists, - m_data_debug_loclists); -} - DWARFDebugAbbrev *SymbolFileDWARF::DebugAbbrev() { if (m_abbr) return m_abbr.get(); @@ -672,21 +668,6 @@ DWARFDebugRanges *SymbolFileDWARF::GetDebugRanges() { return m_ranges.get(); } -DWARFDebugRngLists *SymbolFileDWARF::GetDebugRngLists() { - if (!m_rnglists) { - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, "%s this = %p", LLVM_PRETTY_FUNCTION, - static_cast<void *>(this)); - - if (m_context.getOrLoadRngListsData().GetByteSize() > 0) - m_rnglists.reset(new DWARFDebugRngLists()); - - if (m_rnglists) - m_rnglists->Extract(m_context); - } - return m_rnglists.get(); -} - lldb::CompUnitSP SymbolFileDWARF::ParseCompileUnit(DWARFCompileUnit &dwarf_cu) { CompUnitSP cu_sp; CompileUnit *comp_unit = (CompileUnit *)dwarf_cu.GetUserData(); @@ -703,7 +684,8 @@ lldb::CompUnitSP SymbolFileDWARF::ParseCompileUnit(DWARFCompileUnit &dwarf_cu) { } else { ModuleSP module_sp(m_objfile_sp->GetModule()); if (module_sp) { - const DWARFDIE cu_die = dwarf_cu.DIE(); + const DWARFBaseDIE cu_die = + dwarf_cu.GetNonSkeletonUnit().GetUnitDIEOnly(); if (cu_die) { FileSpec cu_file_spec(cu_die.GetName(), dwarf_cu.GetPathStyle()); if (cu_file_spec) { @@ -721,7 +703,7 @@ lldb::CompUnitSP SymbolFileDWARF::ParseCompileUnit(DWARFCompileUnit &dwarf_cu) { LanguageType cu_language = DWARFUnit::LanguageTypeFromDWARF( cu_die.GetAttributeValueAsUnsigned(DW_AT_language, 0)); - bool is_optimized = dwarf_cu.GetIsOptimized(); + bool is_optimized = dwarf_cu.GetNonSkeletonUnit().GetIsOptimized(); BuildCuTranslationTable(); cu_sp = std::make_shared<CompileUnit>( module_sp, &dwarf_cu, cu_file_spec, @@ -828,15 +810,20 @@ lldb::LanguageType SymbolFileDWARF::ParseLanguage(CompileUnit &comp_unit) { } size_t SymbolFileDWARF::ParseFunctions(CompileUnit &comp_unit) { + static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); + Timer scoped_timer(func_cat, "SymbolFileDWARF::ParseFunctions"); std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); DWARFUnit *dwarf_cu = GetDWARFCompileUnit(&comp_unit); if (!dwarf_cu) return 0; size_t functions_added = 0; - std::vector<DWARFDIE> function_dies; - dwarf_cu->AppendDIEsWithTag(DW_TAG_subprogram, function_dies); - for (const DWARFDIE &die : function_dies) { + dwarf_cu = &dwarf_cu->GetNonSkeletonUnit(); + for (DWARFDebugInfoEntry &entry : dwarf_cu->dies()) { + if (entry.Tag() != DW_TAG_subprogram) + continue; + + DWARFDIE die(dwarf_cu, &entry); if (comp_unit.FindFunctionByUID(die.GetID())) continue; if (ParseFunction(comp_unit, die)) @@ -846,16 +833,32 @@ size_t SymbolFileDWARF::ParseFunctions(CompileUnit &comp_unit) { return functions_added; } -void SymbolFileDWARF::ForEachExternalModule( - CompileUnit &comp_unit, llvm::function_ref<void(ModuleSP)> f) { - UpdateExternalModuleListIfNeeded(); +bool SymbolFileDWARF::ForEachExternalModule( + CompileUnit &comp_unit, + llvm::DenseSet<lldb_private::SymbolFile *> &visited_symbol_files, + llvm::function_ref<bool(Module &)> lambda) { + // Only visit each symbol file once. + if (!visited_symbol_files.insert(this).second) + return false; + UpdateExternalModuleListIfNeeded(); for (auto &p : m_external_type_modules) { ModuleSP module = p.second; - f(module); - for (std::size_t i = 0; i < module->GetNumCompileUnits(); ++i) - module->GetCompileUnitAtIndex(i)->ForEachExternalModule(f); + if (!module) + continue; + + // Invoke the action and potentially early-exit. + if (lambda(*module)) + return true; + + for (std::size_t i = 0; i < module->GetNumCompileUnits(); ++i) { + auto cu = module->GetCompileUnitAtIndex(i); + bool early_exit = cu->ForEachExternalModule(visited_symbol_files, lambda); + if (early_exit) + return true; + } } + return false; } bool SymbolFileDWARF::ParseSupportFiles(CompileUnit &comp_unit, @@ -961,7 +964,7 @@ bool SymbolFileDWARF::ParseImportedModules( DW_AT_LLVM_include_path, nullptr)) module.search_path = ConstString(include_path); if (const char *sysroot = module_die.GetAttributeValueAsString( - DW_AT_LLVM_isysroot, nullptr)) + DW_AT_LLVM_sysroot, nullptr)) module.sysroot = ConstString(sysroot); imported_modules.push_back(module); } @@ -1023,7 +1026,7 @@ bool SymbolFileDWARF::ParseLineTable(CompileUnit &comp_unit) { comp_unit.SetSupportFiles(ParseSupportFilesFromPrologue( comp_unit.GetModule(), line_table->Prologue, dwarf_cu->GetPathStyle(), - dwarf_cu->GetCompilationDirectory().GetCString(), FileSpec(comp_unit))); + dwarf_cu->GetCompilationDirectory().GetCString())); return true; } @@ -1507,7 +1510,7 @@ bool SymbolFileDWARF::GetFunction(const DWARFDIE &die, SymbolContext &sc) { return false; } -lldb::ModuleSP SymbolFileDWARF::GetDWOModule(ConstString name) { +lldb::ModuleSP SymbolFileDWARF::GetExternalModule(ConstString name) { UpdateExternalModuleListIfNeeded(); const auto &pos = m_external_type_modules.find(name); if (pos != m_external_type_modules.end()) @@ -1532,12 +1535,48 @@ SymbolFileDWARF::GetDIE(const DIERef &die_ref) { return DWARFDIE(); } +/// Return the DW_AT_(GNU_)dwo_name. +static const char *GetDWOName(DWARFCompileUnit &dwarf_cu, + const DWARFDebugInfoEntry &cu_die) { + const char *dwo_name = + cu_die.GetAttributeValueAsString(&dwarf_cu, DW_AT_GNU_dwo_name, nullptr); + if (!dwo_name) + dwo_name = + cu_die.GetAttributeValueAsString(&dwarf_cu, DW_AT_dwo_name, nullptr); + return dwo_name; +} + +/// Return the DW_AT_(GNU_)dwo_id. +/// FIXME: Technically 0 is a valid hash. +static uint64_t GetDWOId(DWARFCompileUnit &dwarf_cu, + const DWARFDebugInfoEntry &cu_die) { + uint64_t dwo_id = + cu_die.GetAttributeValueAsUnsigned(&dwarf_cu, DW_AT_GNU_dwo_id, 0); + if (!dwo_id) + dwo_id = cu_die.GetAttributeValueAsUnsigned(&dwarf_cu, DW_AT_dwo_id, 0); + return dwo_id; +} + +llvm::Optional<uint64_t> SymbolFileDWARF::GetDWOId() { + if (GetNumCompileUnits() == 1) { + if (auto comp_unit = GetCompileUnitAtIndex(0)) + if (DWARFCompileUnit *cu = llvm::dyn_cast_or_null<DWARFCompileUnit>( + GetDWARFCompileUnit(comp_unit.get()))) + if (DWARFDebugInfoEntry *cu_die = cu->DIE().GetDIE()) + if (uint64_t dwo_id = ::GetDWOId(*cu, *cu_die)) + return dwo_id; + } + return {}; +} + std::unique_ptr<SymbolFileDWARFDwo> SymbolFileDWARF::GetDwoSymbolFileForCompileUnit( DWARFUnit &unit, const DWARFDebugInfoEntry &cu_die) { - // If we are using a dSYM file, we never want the standard DWO files since - // the -gmodules support uses the same DWO machanism to specify full debug - // info files for modules. + // If this is a Darwin-style debug map (non-.dSYM) symbol file, + // never attempt to load ELF-style DWO files since the -gmodules + // support uses the same DWO machanism to specify full debug info + // files for modules. This is handled in + // UpdateExternalModuleListIfNeeded(). if (GetDebugMapSymfile()) return nullptr; @@ -1546,15 +1585,13 @@ SymbolFileDWARF::GetDwoSymbolFileForCompileUnit( if (!dwarf_cu) return nullptr; - const char *dwo_name = - cu_die.GetAttributeValueAsString(dwarf_cu, DW_AT_GNU_dwo_name, nullptr); + const char *dwo_name = GetDWOName(*dwarf_cu, cu_die); if (!dwo_name) return nullptr; SymbolFileDWARFDwp *dwp_symfile = GetDwpSymbolFile(); if (dwp_symfile) { - uint64_t dwo_id = - cu_die.GetAttributeValueAsUnsigned(dwarf_cu, DW_AT_GNU_dwo_id, 0); + uint64_t dwo_id = ::GetDWOId(*dwarf_cu, cu_die); std::unique_ptr<SymbolFileDWARFDwo> dwo_symfile = dwp_symfile->GetSymbolFileForDwoId(*dwarf_cu, dwo_id); if (dwo_symfile) @@ -1594,76 +1631,101 @@ void SymbolFileDWARF::UpdateExternalModuleListIfNeeded() { if (m_fetched_external_modules) return; m_fetched_external_modules = true; - DWARFDebugInfo *debug_info = DebugInfo(); + // Follow DWO skeleton unit breadcrumbs. const uint32_t num_compile_units = GetNumCompileUnits(); for (uint32_t cu_idx = 0; cu_idx < num_compile_units; ++cu_idx) { - DWARFUnit *dwarf_cu = debug_info->GetUnitAtIndex(cu_idx); + auto *dwarf_cu = + llvm::dyn_cast<DWARFCompileUnit>(debug_info->GetUnitAtIndex(cu_idx)); + if (!dwarf_cu) + continue; const DWARFBaseDIE die = dwarf_cu->GetUnitDIEOnly(); - if (die && !die.HasChildren()) { - const char *name = die.GetAttributeValueAsString(DW_AT_name, nullptr); + if (!die || die.HasChildren() || !die.GetDIE()) + continue; - if (name) { - ConstString const_name(name); - if (m_external_type_modules.find(const_name) == - m_external_type_modules.end()) { - ModuleSP module_sp; - const char *dwo_path = - die.GetAttributeValueAsString(DW_AT_GNU_dwo_name, nullptr); - if (dwo_path) { - ModuleSpec dwo_module_spec; - dwo_module_spec.GetFileSpec().SetFile(dwo_path, - FileSpec::Style::native); - if (dwo_module_spec.GetFileSpec().IsRelative()) { - const char *comp_dir = - die.GetAttributeValueAsString(DW_AT_comp_dir, nullptr); - if (comp_dir) { - dwo_module_spec.GetFileSpec().SetFile(comp_dir, - FileSpec::Style::native); - FileSystem::Instance().Resolve(dwo_module_spec.GetFileSpec()); - dwo_module_spec.GetFileSpec().AppendPathComponent(dwo_path); - } - } - dwo_module_spec.GetArchitecture() = - m_objfile_sp->GetModule()->GetArchitecture(); + const char *name = die.GetAttributeValueAsString(DW_AT_name, nullptr); + if (!name) + continue; - // When LLDB loads "external" modules it looks at the presence of - // DW_AT_GNU_dwo_name. However, when the already created module - // (corresponding to .dwo itself) is being processed, it will see - // the presence of DW_AT_GNU_dwo_name (which contains the name of - // dwo file) and will try to call ModuleList::GetSharedModule - // again. In some cases (i.e. for empty files) Clang 4.0 generates - // a *.dwo file which has DW_AT_GNU_dwo_name, but no - // DW_AT_comp_dir. In this case the method - // ModuleList::GetSharedModule will fail and the warning will be - // printed. However, as one can notice in this case we don't - // actually need to try to load the already loaded module - // (corresponding to .dwo) so we simply skip it. - if (m_objfile_sp->GetFileSpec().GetFileNameExtension() == ".dwo" && - llvm::StringRef(m_objfile_sp->GetFileSpec().GetPath()) - .endswith(dwo_module_spec.GetFileSpec().GetPath())) { - continue; - } + ConstString const_name(name); + ModuleSP &module_sp = m_external_type_modules[const_name]; + if (module_sp) + continue; - Status error = ModuleList::GetSharedModule( - dwo_module_spec, module_sp, nullptr, nullptr, nullptr); - if (!module_sp) { - GetObjectFile()->GetModule()->ReportWarning( - "0x%8.8x: unable to locate module needed for external types: " - "%s\nerror: %s\nDebugging will be degraded due to missing " - "types. Rebuilding your project will regenerate the needed " - "module files.", - die.GetOffset(), - dwo_module_spec.GetFileSpec().GetPath().c_str(), - error.AsCString("unknown error")); - } - } - m_external_type_modules[const_name] = module_sp; - } + const char *dwo_path = GetDWOName(*dwarf_cu, *die.GetDIE()); + if (!dwo_path) + continue; + + ModuleSpec dwo_module_spec; + dwo_module_spec.GetFileSpec().SetFile(dwo_path, FileSpec::Style::native); + if (dwo_module_spec.GetFileSpec().IsRelative()) { + const char *comp_dir = + die.GetAttributeValueAsString(DW_AT_comp_dir, nullptr); + if (comp_dir) { + dwo_module_spec.GetFileSpec().SetFile(comp_dir, + FileSpec::Style::native); + FileSystem::Instance().Resolve(dwo_module_spec.GetFileSpec()); + dwo_module_spec.GetFileSpec().AppendPathComponent(dwo_path); } } + dwo_module_spec.GetArchitecture() = + m_objfile_sp->GetModule()->GetArchitecture(); + + // When LLDB loads "external" modules it looks at the presence of + // DW_AT_dwo_name. However, when the already created module + // (corresponding to .dwo itself) is being processed, it will see + // the presence of DW_AT_dwo_name (which contains the name of dwo + // file) and will try to call ModuleList::GetSharedModule + // again. In some cases (i.e., for empty files) Clang 4.0 + // generates a *.dwo file which has DW_AT_dwo_name, but no + // DW_AT_comp_dir. In this case the method + // ModuleList::GetSharedModule will fail and the warning will be + // printed. However, as one can notice in this case we don't + // actually need to try to load the already loaded module + // (corresponding to .dwo) so we simply skip it. + if (m_objfile_sp->GetFileSpec().GetFileNameExtension() == ".dwo" && + llvm::StringRef(m_objfile_sp->GetFileSpec().GetPath()) + .endswith(dwo_module_spec.GetFileSpec().GetPath())) { + continue; + } + + Status error = ModuleList::GetSharedModule(dwo_module_spec, module_sp, + nullptr, nullptr, nullptr); + if (!module_sp) { + GetObjectFile()->GetModule()->ReportWarning( + "0x%8.8x: unable to locate module needed for external types: " + "%s\nerror: %s\nDebugging will be degraded due to missing " + "types. Rebuilding the project will regenerate the needed " + "module files.", + die.GetOffset(), dwo_module_spec.GetFileSpec().GetPath().c_str(), + error.AsCString("unknown error")); + continue; + } + + // Verify the DWO hash. + // FIXME: Technically "0" is a valid hash. + uint64_t dwo_id = ::GetDWOId(*dwarf_cu, *die.GetDIE()); + if (!dwo_id) + continue; + + auto *dwo_symfile = + llvm::dyn_cast_or_null<SymbolFileDWARF>(module_sp->GetSymbolFile()); + if (!dwo_symfile) + continue; + llvm::Optional<uint64_t> dwo_dwo_id = dwo_symfile->GetDWOId(); + if (!dwo_dwo_id) + continue; + + if (dwo_id != dwo_dwo_id) { + GetObjectFile()->GetModule()->ReportWarning( + "0x%8.8x: Module %s is out-of-date (hash mismatch). Type information " + "from this module may be incomplete or inconsistent with the rest of " + "the program. Rebuilding the project will regenerate the needed " + "module files.", + die.GetOffset(), dwo_module_spec.GetFileSpec().GetPath().c_str()); + } } } @@ -1867,9 +1929,8 @@ uint32_t SymbolFileDWARF::ResolveSymbolContext(const FileSpec &file_spec, if (!dc_cu) continue; - const bool full_match = (bool)file_spec.GetDirectory(); bool file_spec_matches_cu_file_spec = - FileSpec::Equal(file_spec, *dc_cu, full_match); + FileSpec::Match(file_spec, dc_cu->GetPrimaryFile()); if (check_inlines || file_spec_matches_cu_file_spec) { SymbolContext sc(m_objfile_sp->GetModule()); sc.comp_unit = dc_cu; @@ -2208,9 +2269,12 @@ bool SymbolFileDWARF::ResolveFunction(const DWARFDIE &orig_die, addr = sc.function->GetAddressRange().GetBaseAddress(); } - if (addr.IsValid()) { - sc_list.Append(sc); - return true; + + if (auto section_sp = addr.GetSection()) { + if (section_sp->GetPermissions() & ePermissionsExecutable) { + sc_list.Append(sc); + return true; + } } } @@ -2364,12 +2428,10 @@ void SymbolFileDWARF::FindTypes( llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files, TypeMap &types) { std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); - // Make sure we haven't already searched this SymbolFile before... - if (searched_symbol_files.count(this)) + // Make sure we haven't already searched this SymbolFile before. + if (!searched_symbol_files.insert(this).second) return; - searched_symbol_files.insert(this); - DWARFDebugInfo *info = DebugInfo(); if (!info) return; @@ -2451,8 +2513,13 @@ void SymbolFileDWARF::FindTypes( } } -void SymbolFileDWARF::FindTypes(llvm::ArrayRef<CompilerContext> pattern, - LanguageSet languages, TypeMap &types) { +void SymbolFileDWARF::FindTypes( + llvm::ArrayRef<CompilerContext> pattern, LanguageSet languages, + llvm::DenseSet<SymbolFile *> &searched_symbol_files, TypeMap &types) { + // Make sure we haven't already searched this SymbolFile before. + if (!searched_symbol_files.insert(this).second) + return; + std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); if (pattern.empty()) return; @@ -2482,11 +2549,22 @@ void SymbolFileDWARF::FindTypes(llvm::ArrayRef<CompilerContext> pattern, if (!contextMatches(die_context, pattern)) continue; - if (Type *matching_type = ResolveType(die, true, true)) + if (Type *matching_type = ResolveType(die, true, true)) { // We found a type pointer, now find the shared pointer form our type // list. types.InsertUnique(matching_type->shared_from_this()); + } } + + // Next search through the reachable Clang modules. This only applies for + // DWARF objects compiled with -gmodules that haven't been processed by + // dsymutil. + UpdateExternalModuleListIfNeeded(); + + for (const auto &pair : m_external_type_modules) + if (ModuleSP external_module_sp = pair.second) + external_module_sp->FindTypes(pattern, languages, searched_symbol_files, + types); } CompilerDeclContext @@ -3268,15 +3346,17 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc, module, DataExtractor(data, block_offset, block_length), die.GetCU()); } else { - DataExtractor data = DebugLocData(); - const dw_offset_t offset = form_value.Unsigned(); + DataExtractor data = die.GetCU()->GetLocationData(); + dw_offset_t offset = form_value.Unsigned(); + if (form_value.Form() == DW_FORM_loclistx) + offset = die.GetCU()->GetLoclistOffset(offset).getValueOr(-1); if (data.ValidOffset(offset)) { data = DataExtractor(data, offset, data.GetByteSize() - offset); location = DWARFExpression(module, data, die.GetCU()); assert(func_low_pc != LLDB_INVALID_ADDRESS); - location.SetLocationListSlide( - func_low_pc - - attributes.CompileUnitAtIndex(i)->GetBaseAddress()); + location.SetLocationListAddresses( + attributes.CompileUnitAtIndex(i)->GetBaseAddress(), + func_low_pc); } } } break; @@ -3685,8 +3765,8 @@ CollectCallSiteParameters(ModuleSP module, DWARFDIE call_site_die) { if (child.Tag() != DW_TAG_call_site_parameter) continue; - llvm::Optional<DWARFExpression> LocationInCallee = {}; - llvm::Optional<DWARFExpression> LocationInCaller = {}; + llvm::Optional<DWARFExpression> LocationInCallee; + llvm::Optional<DWARFExpression> LocationInCaller; DWARFAttributes attributes; const size_t num_attributes = child.GetAttributes(attributes); @@ -3725,7 +3805,7 @@ CollectCallSiteParameters(ModuleSP module, DWARFDIE call_site_die) { } /// Collect call graph edges present in a function DIE. -static std::vector<lldb_private::CallEdge> +static std::vector<std::unique_ptr<lldb_private::CallEdge>> CollectCallEdges(ModuleSP module, DWARFDIE function_die) { // Check if the function has a supported call site-related attribute. // TODO: In the future it may be worthwhile to support call_all_source_calls. @@ -3743,32 +3823,87 @@ CollectCallEdges(ModuleSP module, DWARFDIE function_die) { // to be DWARF5-compliant. This may need to be done lazily to be performant. // For now, assume that all entries are nested directly under the subprogram // (this is the kind of DWARF LLVM produces) and parse them eagerly. - std::vector<CallEdge> call_edges; + std::vector<std::unique_ptr<CallEdge>> call_edges; for (DWARFDIE child = function_die.GetFirstChild(); child.IsValid(); child = child.GetSibling()) { if (child.Tag() != DW_TAG_call_site) continue; - // Extract DW_AT_call_origin (the call target's DIE). - DWARFDIE call_origin = child.GetReferencedDIE(DW_AT_call_origin); - if (!call_origin.IsValid()) { - LLDB_LOG(log, "CollectCallEdges: Invalid call origin in {0}", - function_die.GetPubname()); + llvm::Optional<DWARFDIE> call_origin; + llvm::Optional<DWARFExpression> call_target; + addr_t return_pc = LLDB_INVALID_ADDRESS; + + DWARFAttributes attributes; + const size_t num_attributes = child.GetAttributes(attributes); + for (size_t i = 0; i < num_attributes; ++i) { + DWARFFormValue form_value; + if (!attributes.ExtractFormValueAtIndex(i, form_value)) { + LLDB_LOG(log, "CollectCallEdges: Could not extract TAG_call_site form"); + break; + } + + dw_attr_t attr = attributes.AttributeAtIndex(i); + + // Extract DW_AT_call_origin (the call target's DIE). + if (attr == DW_AT_call_origin) { + call_origin = form_value.Reference(); + if (!call_origin->IsValid()) { + LLDB_LOG(log, "CollectCallEdges: Invalid call origin in {0}", + function_die.GetPubname()); + break; + } + } + + // Extract DW_AT_call_return_pc (the PC the call returns to) if it's + // available. It should only ever be unavailable for tail call edges, in + // which case use LLDB_INVALID_ADDRESS. + if (attr == DW_AT_call_return_pc) + return_pc = form_value.Address(); + + // Extract DW_AT_call_target (the location of the address of the indirect + // call). + if (attr == DW_AT_call_target) { + if (!DWARFFormValue::IsBlockForm(form_value.Form())) { + LLDB_LOG(log, + "CollectCallEdges: AT_call_target does not have block form"); + break; + } + + auto data = child.GetData(); + uint32_t block_offset = form_value.BlockData() - data.GetDataStart(); + uint32_t block_length = form_value.Unsigned(); + call_target = DWARFExpression( + module, DataExtractor(data, block_offset, block_length), + child.GetCU()); + } + } + if (!call_origin && !call_target) { + LLDB_LOG(log, "CollectCallEdges: call site without any call target"); continue; } - // Extract DW_AT_call_return_pc (the PC the call returns to) if it's - // available. It should only ever be unavailable for tail call edges, in - // which case use LLDB_INVALID_ADDRESS. - addr_t return_pc = child.GetAttributeValueAsAddress(DW_AT_call_return_pc, - LLDB_INVALID_ADDRESS); - // Extract call site parameters. CallSiteParameterArray parameters = CollectCallSiteParameters(module, child); - LLDB_LOG(log, "CollectCallEdges: Found call origin: {0} (retn-PC: {1:x})", - call_origin.GetPubname(), return_pc); + std::unique_ptr<CallEdge> edge; + if (call_origin) { + LLDB_LOG(log, "CollectCallEdges: Found call origin: {0} (retn-PC: {1:x})", + call_origin->GetPubname(), return_pc); + edge = std::make_unique<DirectCallEdge>(call_origin->GetMangledName(), + return_pc, std::move(parameters)); + } else { + if (log) { + StreamString call_target_desc; + call_target->GetDescription(&call_target_desc, eDescriptionLevelBrief, + LLDB_INVALID_ADDRESS, nullptr); + LLDB_LOG(log, "CollectCallEdges: Found indirect call target: {0}", + call_target_desc.GetString()); + } + edge = std::make_unique<IndirectCallEdge>(*call_target, return_pc, + std::move(parameters)); + } + if (log && parameters.size()) { for (const CallSiteParameter ¶m : parameters) { StreamString callee_loc_desc, caller_loc_desc; @@ -3783,13 +3918,12 @@ CollectCallEdges(ModuleSP module, DWARFDIE function_die) { } } - call_edges.emplace_back(call_origin.GetMangledName(), return_pc, - std::move(parameters)); + call_edges.push_back(std::move(edge)); } return call_edges; } -std::vector<lldb_private::CallEdge> +std::vector<std::unique_ptr<lldb_private::CallEdge>> SymbolFileDWARF::ParseCallEdgesInFunction(UserID func_id) { DWARFDIE func_die = GetDIE(func_id.GetID()); if (func_die.IsValid()) @@ -3829,13 +3963,6 @@ SymbolFileDWARFDebugMap *SymbolFileDWARF::GetDebugMapSymfile() { return m_debug_map_symfile; } -DWARFExpression::LocationListFormat -SymbolFileDWARF::GetLocationListFormat() const { - if (m_data_debug_loclists.m_data.GetByteSize() > 0) - return DWARFExpression::LocLists; - return DWARFExpression::RegularLocationList; -} - SymbolFileDWARFDwp *SymbolFileDWARF::GetDwpSymbolFile() { llvm::call_once(m_dwp_symfile_once_flag, [this]() { ModuleSpec module_spec; |
