diff --git a/lldb/bindings/interface/SBModuleSpecListExtensions.i b/lldb/bindings/interface/SBModuleSpecListExtensions.i index ab51dc4498ad8..7d23f5bc940fc 100644 --- a/lldb/bindings/interface/SBModuleSpecListExtensions.i +++ b/lldb/bindings/interface/SBModuleSpecListExtensions.i @@ -10,7 +10,10 @@ STRING_EXTENSION_OUTSIDE(SBModuleSpecList) def __iter__(self): '''Iterate over all ModuleSpecs in a lldb.SBModuleSpecList object.''' return lldb_iter(self, 'GetSize', 'GetSpecAtIndex') + + def __getitem__(self, index): + '''Get an lldb.SBModuleSpec at a given index, an invalid SBModuleSpec will be returned if the index is invalid.''' + return self.GetSpecAtIndex(index) %} #endif } - diff --git a/lldb/include/lldb/API/SBModule.h b/lldb/include/lldb/API/SBModule.h index 4009ca1461e51..2917c5cb5564d 100644 --- a/lldb/include/lldb/API/SBModule.h +++ b/lldb/include/lldb/API/SBModule.h @@ -287,6 +287,14 @@ class LLDB_API SBModule { /// A const reference to the file specification object. lldb::SBFileSpec GetSymbolFileSpec() const; + /// Get a list of filespecs associated with all the separate symbol files + /// associated with this module. + /// + /// \return + /// A list of filespecs associated with all the separate symbol files + /// associated with this module. + lldb::SBModuleSpecList GetSeparateDebugInfoFiles(); + lldb::SBAddress GetObjectFileHeaderAddress() const; lldb::SBAddress GetObjectFileEntryPointAddress() const; diff --git a/lldb/include/lldb/API/SBModuleSpec.h b/lldb/include/lldb/API/SBModuleSpec.h index 8d1ecfe6e6f8b..0d2987668e406 100644 --- a/lldb/include/lldb/API/SBModuleSpec.h +++ b/lldb/include/lldb/API/SBModuleSpec.h @@ -125,6 +125,9 @@ class SBModuleSpecList { bool GetDescription(lldb::SBStream &description); private: + friend class SBModule; + + SBModuleSpecList(lldb_private::ModuleSpecList &&module_spec_list); std::unique_ptr m_opaque_up; }; diff --git a/lldb/include/lldb/Core/Module.h b/lldb/include/lldb/Core/Module.h index 8513e147ee523..72a4e1808732e 100644 --- a/lldb/include/lldb/Core/Module.h +++ b/lldb/include/lldb/Core/Module.h @@ -483,6 +483,8 @@ class Module : public std::enable_shared_from_this, const FileSpec &GetSymbolFileFileSpec() const { return m_symfile_spec; } + ModuleSpecList GetSeparateDebugInfoFiles(); + void PreloadSymbols(); void SetSymbolFileFileSpec(const FileSpec &file); diff --git a/lldb/include/lldb/Symbol/SymbolFile.h b/lldb/include/lldb/Symbol/SymbolFile.h index bbc615d9fdc38..28b5fea0d6796 100644 --- a/lldb/include/lldb/Symbol/SymbolFile.h +++ b/lldb/include/lldb/Symbol/SymbolFile.h @@ -496,6 +496,18 @@ class SymbolFile : public PluginInterface { /// symbol file doesn't support DWO files, both counts will be 0. virtual std::pair GetDwoFileCounts() { return {0, 0}; } + /// Return a map of separate debug info files that are loaded. + /// + /// Unlike GetSeparateDebugInfo(), this function will only return the list of + /// files, if there are errors they are simply ignored. This function will + /// always return a valid list, even if it is empty. + /// + /// \return + /// A unique list of all the filespecs, or an empty list. + virtual lldb_private::ModuleSpecList GetSeparateDebugInfoFiles() { + return {}; + } + virtual lldb::TypeSP MakeType(lldb::user_id_t uid, ConstString name, std::optional byte_size, SymbolContextScope *context, diff --git a/lldb/include/lldb/Symbol/SymbolFileOnDemand.h b/lldb/include/lldb/Symbol/SymbolFileOnDemand.h index 6e3c2477d1769..fbb942df726d0 100644 --- a/lldb/include/lldb/Symbol/SymbolFileOnDemand.h +++ b/lldb/include/lldb/Symbol/SymbolFileOnDemand.h @@ -229,6 +229,10 @@ class SymbolFileOnDemand : public lldb_private::SymbolFile { load_all_debug_info); } + lldb_private::ModuleSpecList GetSeparateDebugInfoFiles() override { + return m_sym_file_impl->GetSeparateDebugInfoFiles(); + } + lldb::TypeSP MakeType(lldb::user_id_t uid, ConstString name, std::optional byte_size, SymbolContextScope *context, diff --git a/lldb/source/API/SBModule.cpp b/lldb/source/API/SBModule.cpp index 5a57f45f0d475..e2db8b46ea274 100644 --- a/lldb/source/API/SBModule.cpp +++ b/lldb/source/API/SBModule.cpp @@ -633,6 +633,14 @@ lldb::SBFileSpec SBModule::GetSymbolFileSpec() const { return sb_file_spec; } +lldb::SBModuleSpecList SBModule::GetSeparateDebugInfoFiles() { + ModuleSP module_sp(GetSP()); + if (module_sp) + return lldb::SBModuleSpecList(module_sp->GetSeparateDebugInfoFiles()); + + return lldb::SBModuleSpecList(); +} + lldb::SBAddress SBModule::GetObjectFileHeaderAddress() const { LLDB_INSTRUMENT_VA(this); diff --git a/lldb/source/API/SBModuleSpec.cpp b/lldb/source/API/SBModuleSpec.cpp index fbbcfeac20178..938397cc5c60f 100644 --- a/lldb/source/API/SBModuleSpec.cpp +++ b/lldb/source/API/SBModuleSpec.cpp @@ -183,6 +183,11 @@ SBModuleSpecList::SBModuleSpecList(const SBModuleSpecList &rhs) LLDB_INSTRUMENT_VA(this, rhs); } +SBModuleSpecList::SBModuleSpecList(lldb_private::ModuleSpecList &&module_spec) + : m_opaque_up(new ModuleSpecList(std::move(module_spec))) { + LLDB_INSTRUMENT_VA(this); +} + SBModuleSpecList &SBModuleSpecList::operator=(const SBModuleSpecList &rhs) { LLDB_INSTRUMENT_VA(this, rhs); diff --git a/lldb/source/Core/Module.cpp b/lldb/source/Core/Module.cpp index f27a95de484df..cb95f95857a03 100644 --- a/lldb/source/Core/Module.cpp +++ b/lldb/source/Core/Module.cpp @@ -1647,3 +1647,11 @@ DataFileCache *Module::GetIndexCache() { .GetPath()); return g_data_file_cache; } + +lldb_private::ModuleSpecList Module::GetSeparateDebugInfoFiles() { + SymbolFile *symfile = GetSymbolFile(false); + if (!symfile) + return {}; + + return symfile->GetSeparateDebugInfoFiles(); +} diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index b15e0c15fedb8..53460d260f68f 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -4215,6 +4215,30 @@ void SymbolFileDWARF::DumpClangAST(Stream &s, llvm::StringRef filter) { clang->Dump(s.AsRawOstream(), filter); } +lldb_private::ModuleSpecList SymbolFileDWARF::GetSeparateDebugInfoFiles() { + DWARFDebugInfo &info = DebugInfo(); + const size_t num_cus = info.GetNumUnits(); + lldb_private::ModuleSpecList spec_list; + for (uint32_t cu_idx = 0; cu_idx < num_cus; ++cu_idx) { + DWARFUnit *unit = info.GetUnitAtIndex(cu_idx); + DWARFCompileUnit *dwarf_cu = llvm::dyn_cast(unit); + if (dwarf_cu == nullptr) + continue; + + if (!dwarf_cu->GetDWOId().has_value()) + continue; + + SymbolFile *dwo_symfile = dwarf_cu->GetDwoSymbolFile(); + if (!dwo_symfile) + continue; + + lldb_private::FileSpec symfile_spec = + dwo_symfile->GetObjectFile()->GetFileSpec(); + spec_list.Append(symfile_spec); + } + return spec_list; +} + bool SymbolFileDWARF::GetSeparateDebugInfo(StructuredData::Dictionary &d, bool errors_only, bool load_all_debug_info) { diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h index d7db8a3c0869f..14566de99a7de 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -279,6 +279,8 @@ class SymbolFileDWARF : public SymbolFileCommon { void DumpClangAST(Stream &s, llvm::StringRef filter) override; + lldb_private::ModuleSpecList GetSeparateDebugInfoFiles() override; + /// List separate dwo files. bool GetSeparateDebugInfo(StructuredData::Dictionary &d, bool errors_only, bool load_all_debug_info = false) override; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp index 9d7452a1988fa..0cd1c4e6607ef 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp @@ -1277,6 +1277,20 @@ void SymbolFileDWARFDebugMap::DumpClangAST(Stream &s, llvm::StringRef filter) { }); } +lldb_private::ModuleSpecList +SymbolFileDWARFDebugMap::GetSeparateDebugInfoFiles() { + const uint32_t cu_count = GetNumCompileUnits(); + lldb_private::ModuleSpecList spec_list; + for (uint32_t cu_idx = 0; cu_idx < cu_count; ++cu_idx) { + const auto &info = m_compile_unit_infos[cu_idx]; + if (info.so_file.GetPath().empty()) + continue; + + spec_list.Append(lldb_private::FileSpec(info.oso_path)); + } + return spec_list; +} + bool SymbolFileDWARFDebugMap::GetSeparateDebugInfo( lldb_private::StructuredData::Dictionary &d, bool errors_only, bool load_all_debug_info) { diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h index e1f1df23951c6..b51dfdd24646f 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h @@ -131,6 +131,8 @@ class SymbolFileDWARFDebugMap : public SymbolFileCommon { void DumpClangAST(Stream &s, llvm::StringRef filter) override; + lldb_private::ModuleSpecList GetSeparateDebugInfoFiles() override; + /// List separate oso files. bool GetSeparateDebugInfo(StructuredData::Dictionary &d, bool errors_only, bool load_all_debug_info = false) override; diff --git a/lldb/test/API/python_api/sbmodule/SeperateDebugInfo/Makefile b/lldb/test/API/python_api/sbmodule/SeperateDebugInfo/Makefile new file mode 100644 index 0000000000000..99998b20bcb05 --- /dev/null +++ b/lldb/test/API/python_api/sbmodule/SeperateDebugInfo/Makefile @@ -0,0 +1,3 @@ +CXX_SOURCES := main.cpp + +include Makefile.rules diff --git a/lldb/test/API/python_api/sbmodule/SeperateDebugInfo/TestSBModuleSeparateDebugInfo.py b/lldb/test/API/python_api/sbmodule/SeperateDebugInfo/TestSBModuleSeparateDebugInfo.py new file mode 100644 index 0000000000000..b36bfd009bc2e --- /dev/null +++ b/lldb/test/API/python_api/sbmodule/SeperateDebugInfo/TestSBModuleSeparateDebugInfo.py @@ -0,0 +1,44 @@ +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +import os, signal, subprocess + +from lldbsuite.test import lldbutil + + +class SBModuleSeparateDebugInfoCase(TestBase): + def setUp(self): + TestBase.setUp(self) + self.background_pid = None + + def tearDown(self): + TestBase.tearDown(self) + if self.background_pid: + os.kill(self.background_pid, signal.SIGKILL) + + @skipIf(debug_info=no_match("dwo")) + def test_get_separate_debug_info_files_dwo(self): + """Test the SBModule::GetSeparateDebugInfoFiles""" + self.build() + exe = self.getBuildArtifact("a.out") + target = self.dbg.CreateTarget(exe) + + # Target should have a DWO + main_module = target.GetModuleAtIndex(0) + file_specs = main_module.GetSeparateDebugInfoFiles() + self.assertEqual(len(file_specs), 1) + self.assertTrue(file_specs[0].GetFileSpec().GetFilename().endswith(".dwo")) + + @skipUnlessDarwin + @skipIf(debug_info=no_match("dwarf")) + def test_get_separate_debug_info_files_darwin_dwarf(self): + """Test the SBModule::GetSeparateDebugInfoFiles""" + self.build() + exe = self.getBuildArtifact("a.out") + target = self.dbg.CreateTarget(exe) + + # Target should have a DWO + main_module = target.GetModuleAtIndex(0) + file_specs = main_module.GetSeparateDebugInfoFiles() + self.assertEqual(len(file_specs), 1) + self.assertTrue(file_specs[0].GetFileSpec().GetFilename().endswith(".o")) diff --git a/lldb/test/API/python_api/sbmodule/SeperateDebugInfo/main.cpp b/lldb/test/API/python_api/sbmodule/SeperateDebugInfo/main.cpp new file mode 100644 index 0000000000000..f54a8087e1dc4 --- /dev/null +++ b/lldb/test/API/python_api/sbmodule/SeperateDebugInfo/main.cpp @@ -0,0 +1,5 @@ +int main() { + int x = 40; + x += 2; // break here + return x; +}