[Lldb-commits] [lldb] Add `target modules dump separate-debug-info` (PR #66035)
Tom Yang via lldb-commits
lldb-commits at lists.llvm.org
Mon Sep 11 17:31:17 PDT 2023
https://github.com/zhyty updated https://github.com/llvm/llvm-project/pull/66035:
>From 0f4cf3648bd1a8d6e9114965e6eb6cdbc7ed01dd Mon Sep 17 00:00:00 2001
From: Tom Yang <toyang at fb.com>
Date: Mon, 11 Sep 2023 17:17:13 -0700
Subject: [PATCH] Add `target modules dump separate-debug-info`
Summary:
Add a new command
```
target modules dump separate-debug-info [<file1> ...]
```
or
```
image dump separate-debug-info [<file1> ...]
```
(since `image` is an alias for `target modules`).
This lists the separate debug info files and their current status (loaded or not loaded) for the specified modules. This diff implements this command for mach-O files with OSO and ELF files with dwo.
Example dwo:
```
(lldb) image dump separate-debug-info
[
{
"separate-debug-info-files": [
{
"comp_dir": ".",
"dwo_id": 7516252579671439727,
"dwo_name": "a-main.dwo",
"loaded": true,
"resolved_dwo_path": "/home/toyang/workspace/dwo-scratch/a-main.dwo"
},
{
"comp_dir": ".",
"dwo_id": 13601198072221073203,
"dwo_name": "a-foo.dwo",
"loaded": true,
"resolved_dwo_path": "/home/toyang/workspace/dwo-scratch/a-foo.dwo"
}
],
"symfile": "/home/toyang/workspace/dwo-scratch/a.out"
}
]
```
Example dwo with missing dwo:
```
warning: (x86_64) /home/toyang/workspace/dwp/a.out unable to locate separate debug file (dwo, dwp). Debugging will be degraded. (troubleshoot with https://fburl.com/missing_dwo)
Current executable set to '/home/toyang/workspace/dwp/a.out' (x86_64).
(lldb) image dump separate-debug-info
[
{
"separate-debug-info-files": [
{
"comp_dir": "/home/toyang/workspace/dwp",
"dwo_id": 11115620165179865774,
"dwo_name": "a-main.dwo",
"loaded": false
},
{
"comp_dir": "/home/toyang/workspace/dwp",
"dwo_id": 13601198072221073203,
"dwo_name": "a-foo.dwo",
"loaded": false
}
],
"symfile": "/home/toyang/workspace/dwp/a.out"
}
]
```
Example output with dwp:
```
(lldb) image dump separate-debug-info
[
{
"separate-debug-info-files": [
{
"comp_dir": "/home/toyang/workspace/dwp",
"dwo_id": 11115620165179865774,
"dwo_name": "a-main.dwo",
"loaded": true,
"resolved_dwo_path": "/home/toyang/workspace/dwp/a.out.dwp"
},
{
"comp_dir": "/home/toyang/workspace/dwp",
"dwo_id": 13601198072221073203,
"dwo_name": "a-foo.dwo",
"loaded": true,
"resolved_dwo_path": "/home/toyang/workspace/dwp/a.out.dwp"
}
],
"symfile": "/home/toyang/workspace/dwp/a.out"
}
]
```
Example oso on my Mac (after manipulating the mod times with `touch`):
```
[
{
"separate-debug-info-files": [
{
"error": "debug map object file \"/Users/toyang/workspace/scratch/main.o\" changed (actual: 0x64e64868, debug map: 0x64e4fb23) since this executable was linked, debug info will not be loaded",
"loaded": false,
"oso_mod_time": 1692728099,
"oso_path": "/Users/toyang/workspace/scratch/main.o",
"so_file": "/Users/toyang/workspace/scratch/main.cpp"
},
{
"error": "debug map object file \"/Users/toyang/workspace/scratch/foo.o\" changed (actual: 0x64e64868, debug map: 0x64e4fb23) since this executable was linked, debug info will not be loaded",
"loaded": false,
"oso_mod_time": 1692728099,
"oso_path": "/Users/toyang/workspace/scratch/foo.o",
"so_file": "/Users/toyang/workspace/scratch/foo.cpp"
}
],
"symfile": "/Users/toyang/workspace/scratch/a-oso.out"
}
]
```
Test Plan:
Tested on Mac OS and Linux.
```
lldb-dotest -p TestDumpDwo
lldb-dotest -p TestDumpOso
```
Reviewers:
Subscribers:
Tasks:
Tags:
---
lldb/include/lldb/Symbol/SymbolFile.h | 11 ++
lldb/source/Commands/CommandObjectTarget.cpp | 146 ++++++++++++++++--
.../SymbolFile/DWARF/SymbolFileDWARF.cpp | 58 +++++++
.../SymbolFile/DWARF/SymbolFileDWARF.h | 5 +
.../DWARF/SymbolFileDWARFDebugMap.cpp | 33 +++-
.../DWARF/SymbolFileDWARFDebugMap.h | 5 +
lldb/source/Symbol/SymbolFile.cpp | 14 ++
.../dump-separate-debug-info/dwo/Makefile | 4 +
.../dwo/TestDumpDwo.py | 68 ++++++++
.../dump-separate-debug-info/dwo/foo.cpp | 3 +
.../target/dump-separate-debug-info/dwo/foo.h | 6 +
.../dump-separate-debug-info/dwo/main.cpp | 3 +
.../dump-separate-debug-info/oso/Makefile | 3 +
.../oso/TestDumpOso.py | 68 ++++++++
.../dump-separate-debug-info/oso/foo.cpp | 3 +
.../target/dump-separate-debug-info/oso/foo.h | 6 +
.../dump-separate-debug-info/oso/main.cpp | 3 +
17 files changed, 421 insertions(+), 18 deletions(-)
create mode 100644 lldb/test/API/commands/target/dump-separate-debug-info/dwo/Makefile
create mode 100644 lldb/test/API/commands/target/dump-separate-debug-info/dwo/TestDumpDwo.py
create mode 100644 lldb/test/API/commands/target/dump-separate-debug-info/dwo/foo.cpp
create mode 100644 lldb/test/API/commands/target/dump-separate-debug-info/dwo/foo.h
create mode 100644 lldb/test/API/commands/target/dump-separate-debug-info/dwo/main.cpp
create mode 100644 lldb/test/API/commands/target/dump-separate-debug-info/oso/Makefile
create mode 100644 lldb/test/API/commands/target/dump-separate-debug-info/oso/TestDumpOso.py
create mode 100644 lldb/test/API/commands/target/dump-separate-debug-info/oso/foo.cpp
create mode 100644 lldb/test/API/commands/target/dump-separate-debug-info/oso/foo.h
create mode 100644 lldb/test/API/commands/target/dump-separate-debug-info/oso/main.cpp
diff --git a/lldb/include/lldb/Symbol/SymbolFile.h b/lldb/include/lldb/Symbol/SymbolFile.h
index 8de752816cf94ee..347bfc445caa8b5 100644
--- a/lldb/include/lldb/Symbol/SymbolFile.h
+++ b/lldb/include/lldb/Symbol/SymbolFile.h
@@ -22,6 +22,7 @@
#include "lldb/Symbol/TypeList.h"
#include "lldb/Symbol/TypeSystem.h"
#include "lldb/Target/Statistics.h"
+#include "lldb/Utility/StructuredData.h"
#include "lldb/Utility/XcodeSDK.h"
#include "lldb/lldb-private.h"
#include "llvm/ADT/DenseSet.h"
@@ -377,6 +378,10 @@ class SymbolFile : public PluginInterface {
virtual void Dump(Stream &s) = 0;
+ /// Return true if separate debug info files are supported and this function
+ /// succeeded, false otherwise.
+ bool DumpSeparateDebugInfoFiles(StructuredData::Dictionary &d);
+
/// Metrics gathering functions
/// Return the size in bytes of all debug information in the symbol file.
@@ -459,6 +464,12 @@ class SymbolFile : public PluginInterface {
virtual void GetCompileOptions(
std::unordered_map<lldb::CompUnitSP, lldb_private::Args> &args) {}
+ /// Return true if separate debug info files are supported and this function
+ /// succeeded, false otherwise.
+ virtual bool GetSeparateDebugInfoFiles(StructuredData::Array &array) {
+ return false;
+ };
+
private:
SymbolFile(const SymbolFile &) = delete;
const SymbolFile &operator=(const SymbolFile &) = delete;
diff --git a/lldb/source/Commands/CommandObjectTarget.cpp b/lldb/source/Commands/CommandObjectTarget.cpp
index 33330ef0926d61f..276d85977c4ef34 100644
--- a/lldb/source/Commands/CommandObjectTarget.cpp
+++ b/lldb/source/Commands/CommandObjectTarget.cpp
@@ -52,6 +52,7 @@
#include "lldb/Utility/FileSpec.h"
#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/State.h"
+#include "lldb/Utility/StructuredData.h"
#include "lldb/Utility/Timer.h"
#include "lldb/lldb-enumerations.h"
#include "lldb/lldb-private-enumerations.h"
@@ -1462,6 +1463,21 @@ static bool DumpModuleSymbolFile(Stream &strm, Module *module) {
return false;
}
+static bool DumpModuleSeparateDebugInfoFiles(
+ StructuredData::Array &separate_debug_info_files, Module *module) {
+ if (module) {
+ if (SymbolFile *symbol_file = module->GetSymbolFile(true)) {
+ StructuredData::Dictionary d;
+ if (symbol_file->DumpSeparateDebugInfoFiles(d)) {
+ separate_debug_info_files.AddItem(
+ std::make_shared<StructuredData::Dictionary>(std::move(d)));
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
static void DumpAddress(ExecutionContextScope *exe_scope,
const Address &so_addr, bool verbose, bool all_ranges,
Stream &strm) {
@@ -2005,9 +2021,10 @@ class CommandObjectTargetModulesDumpSymtab
result.GetOutputStream().EOL();
result.GetOutputStream().EOL();
}
- if (INTERRUPT_REQUESTED(GetDebugger(),
+ if (INTERRUPT_REQUESTED(GetDebugger(),
"Interrupted in dump all symtabs with {0} "
- "of {1} dumped.", num_dumped, num_modules))
+ "of {1} dumped.",
+ num_dumped, num_modules))
break;
num_dumped++;
@@ -2035,9 +2052,10 @@ class CommandObjectTargetModulesDumpSymtab
result.GetOutputStream().EOL();
result.GetOutputStream().EOL();
}
- if (INTERRUPT_REQUESTED(GetDebugger(),
- "Interrupted in dump symtab list with {0} of {1} dumped.",
- num_dumped, num_matches))
+ if (INTERRUPT_REQUESTED(
+ GetDebugger(),
+ "Interrupted in dump symtab list with {0} of {1} dumped.",
+ num_dumped, num_matches))
break;
num_dumped++;
@@ -2099,9 +2117,10 @@ class CommandObjectTargetModulesDumpSections
result.GetOutputStream().Format("Dumping sections for {0} modules.\n",
num_modules);
for (size_t image_idx = 0; image_idx < num_modules; ++image_idx) {
- if (INTERRUPT_REQUESTED(GetDebugger(),
- "Interrupted in dump all sections with {0} of {1} dumped",
- image_idx, num_modules))
+ if (INTERRUPT_REQUESTED(
+ GetDebugger(),
+ "Interrupted in dump all sections with {0} of {1} dumped",
+ image_idx, num_modules))
break;
num_dumped++;
@@ -2120,9 +2139,10 @@ class CommandObjectTargetModulesDumpSections
FindModulesByName(target, arg_cstr, module_list, true);
if (num_matches > 0) {
for (size_t i = 0; i < num_matches; ++i) {
- if (INTERRUPT_REQUESTED(GetDebugger(),
- "Interrupted in dump section list with {0} of {1} dumped.",
- i, num_matches))
+ if (INTERRUPT_REQUESTED(
+ GetDebugger(),
+ "Interrupted in dump section list with {0} of {1} dumped.",
+ i, num_matches))
break;
Module *module = module_list.GetModulePointerAtIndex(i);
@@ -2265,9 +2285,10 @@ class CommandObjectTargetModulesDumpClangAST
}
for (size_t i = 0; i < num_matches; ++i) {
- if (INTERRUPT_REQUESTED(GetDebugger(),
- "Interrupted in dump clang ast list with {0} of {1} dumped.",
- i, num_matches))
+ if (INTERRUPT_REQUESTED(
+ GetDebugger(),
+ "Interrupted in dump clang ast list with {0} of {1} dumped.", i,
+ num_matches))
break;
Module *m = module_list.GetModulePointerAtIndex(i);
@@ -2406,10 +2427,10 @@ class CommandObjectTargetModulesDumpLineTable
if (num_modules > 0) {
uint32_t num_dumped = 0;
for (ModuleSP module_sp : target_modules.ModulesNoLocking()) {
- if (INTERRUPT_REQUESTED(GetDebugger(),
+ if (INTERRUPT_REQUESTED(GetDebugger(),
"Interrupted in dump all line tables with "
- "{0} of {1} dumped", num_dumped,
- num_modules))
+ "{0} of {1} dumped",
+ num_dumped, num_modules))
break;
if (DumpCompileUnitLineTable(
@@ -2462,6 +2483,93 @@ class CommandObjectTargetModulesDumpLineTable
CommandOptions m_options;
};
+#pragma mark CommandObjectTargetModulesDumpSeparateDebugInfoFiles
+
+// Image debug dwo dumping command
+
+class CommandObjectTargetModulesDumpSeparateDebugInfoFiles
+ : public CommandObjectTargetModulesModuleAutoComplete {
+public:
+ CommandObjectTargetModulesDumpSeparateDebugInfoFiles(
+ CommandInterpreter &interpreter)
+ : CommandObjectTargetModulesModuleAutoComplete(
+ interpreter, "target modules dump separate-debug-info",
+ "Dump the separate debug info symbol files for one or more target "
+ "modules.",
+ //"target modules dump separate-debug-info [<file1> ...]")
+ nullptr, eCommandRequiresTarget) {}
+
+ ~CommandObjectTargetModulesDumpSeparateDebugInfoFiles() override = default;
+
+protected:
+ bool DoExecute(Args &command, CommandReturnObject &result) override {
+ Target &target = GetSelectedTarget();
+ uint32_t num_dumped = 0;
+
+ uint32_t addr_byte_size = target.GetArchitecture().GetAddressByteSize();
+ result.GetOutputStream().SetAddressByteSize(addr_byte_size);
+ result.GetErrorStream().SetAddressByteSize(addr_byte_size);
+
+ StructuredData::Array separate_debug_info_files;
+ if (command.GetArgumentCount() == 0) {
+ // Dump all sections for all modules images
+ const ModuleList &target_modules = target.GetImages();
+ std::lock_guard<std::recursive_mutex> guard(target_modules.GetMutex());
+ const size_t num_modules = target_modules.GetSize();
+ if (num_modules == 0) {
+ result.AppendError("the target has no associated executable images");
+ return false;
+ }
+ for (ModuleSP module_sp : target_modules.ModulesNoLocking()) {
+ if (INTERRUPT_REQUESTED(
+ GetDebugger(),
+ "Interrupted in dumping all "
+ "separate debug info with {0} of {1} modules dumped",
+ num_dumped, num_modules))
+ break;
+
+ if (DumpModuleSeparateDebugInfoFiles(separate_debug_info_files,
+ module_sp.get()))
+ num_dumped++;
+ }
+ } else {
+ // Dump specified images (by basename or fullpath)
+ const char *arg_cstr;
+ for (int arg_idx = 0;
+ (arg_cstr = command.GetArgumentAtIndex(arg_idx)) != nullptr;
+ ++arg_idx) {
+ ModuleList module_list;
+ const size_t num_matches =
+ FindModulesByName(&target, arg_cstr, module_list, true);
+ if (num_matches > 0) {
+ for (size_t i = 0; i < num_matches; ++i) {
+ if (INTERRUPT_REQUESTED(GetDebugger(),
+ "Interrupted dumping {0} "
+ "of {1} requested modules",
+ i, num_matches))
+ break;
+ Module *module = module_list.GetModulePointerAtIndex(i);
+ if (DumpModuleSeparateDebugInfoFiles(separate_debug_info_files,
+ module))
+ num_dumped++;
+ }
+ } else
+ result.AppendWarningWithFormat(
+ "Unable to find an image that matches '%s'.\n", arg_cstr);
+ }
+ }
+
+ if (num_dumped > 0) {
+ separate_debug_info_files.Dump(result.GetOutputStream(),
+ /* pretty_print */ true);
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ } else {
+ result.AppendError("no matching executable images found");
+ }
+ return result.Succeeded();
+ }
+};
+
#pragma mark CommandObjectTargetModulesDump
// Dump multi-word command for target modules
@@ -2499,6 +2607,10 @@ class CommandObjectTargetModulesDump : public CommandObjectMultiword {
"pcm-info",
CommandObjectSP(
new CommandObjectTargetModulesDumpClangPCMInfo(interpreter)));
+ LoadSubCommand("separate-debug-info",
+ CommandObjectSP(
+ new CommandObjectTargetModulesDumpSeparateDebugInfoFiles(
+ interpreter)));
}
~CommandObjectTargetModulesDump() override = default;
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
index 04c729e333a9854..695f6b43f9e4331 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -10,6 +10,7 @@
#include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h"
#include "llvm/Support/Casting.h"
+#include "llvm/Support/Format.h"
#include "llvm/Support/Threading.h"
#include "lldb/Core/Module.h"
@@ -24,6 +25,7 @@
#include "lldb/Utility/RegularExpression.h"
#include "lldb/Utility/Scalar.h"
#include "lldb/Utility/StreamString.h"
+#include "lldb/Utility/StructuredData.h"
#include "lldb/Utility/Timer.h"
#include "Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h"
@@ -4214,6 +4216,62 @@ void SymbolFileDWARF::DumpClangAST(Stream &s) {
clang->Dump(s.AsRawOstream());
}
+bool SymbolFileDWARF::GetSeparateDebugInfoFiles(StructuredData::Array &array) {
+ DWARFDebugInfo &info = DebugInfo();
+ const size_t num_cus = info.GetNumUnits();
+ for (size_t cu_idx = 0; cu_idx < num_cus; cu_idx++) {
+ DWARFUnit *unit = info.GetUnitAtIndex(cu_idx);
+ DWARFCompileUnit *dwarf_cu = llvm::dyn_cast<DWARFCompileUnit>(unit);
+ if (dwarf_cu == nullptr) {
+ continue;
+ }
+
+ // Check if this is a DWO unit by checking if it has a DWO ID.
+ // NOTE: it seems that `DWARFUnit::IsDWOUnit` is always false?
+ if (!dwarf_cu->GetDWOId().has_value())
+ continue;
+
+ StructuredData::DictionarySP dwo_data =
+ std::make_shared<StructuredData::Dictionary>();
+ const uint64_t dwo_id = dwarf_cu->GetDWOId().value();
+ dwo_data->AddIntegerItem("dwo_id", dwo_id);
+
+ if (const DWARFBaseDIE die = dwarf_cu->GetUnitDIEOnly()) {
+ const char *dwo_name = GetDWOName(*dwarf_cu, *die.GetDIE());
+ if (dwo_name) {
+ dwo_data->AddStringItem("dwo_name", dwo_name);
+ } else {
+ dwo_data->AddStringItem("error", "missing dwo name");
+ }
+
+ const char *comp_dir = die.GetDIE()->GetAttributeValueAsString(
+ dwarf_cu, DW_AT_comp_dir, nullptr);
+ if (comp_dir) {
+ dwo_data->AddStringItem("comp_dir", comp_dir);
+ }
+ } else {
+ dwo_data->AddStringItem(
+ "error",
+ llvm::formatv("unable to get unit DIE for DWARFUnit at {0:x}",
+ dwarf_cu->GetOffset())
+ .str());
+ }
+
+ // If we have a DWO symbol file, that means we were able to successfully
+ // load it.
+ SymbolFile *dwo_symfile = dwarf_cu->GetDwoSymbolFile();
+ if (dwo_symfile) {
+ dwo_data->AddStringItem(
+ "resolved_dwo_path",
+ dwo_symfile->GetObjectFile()->GetFileSpec().GetPath());
+ }
+ dwo_data->AddBooleanItem("loaded", dwo_symfile != nullptr);
+ array.AddItem(dwo_data);
+ }
+
+ return true;
+}
+
SymbolFileDWARFDebugMap *SymbolFileDWARF::GetDebugMapSymfile() {
if (m_debug_map_symfile == nullptr) {
lldb::ModuleSP module_sp(m_debug_map_module_wp.lock());
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
index 191a5abcf265abd..79bcdbbba5d5963 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
@@ -30,6 +30,7 @@
#include "lldb/Utility/ConstString.h"
#include "lldb/Utility/Flags.h"
#include "lldb/Utility/RangeMap.h"
+#include "lldb/Utility/StructuredData.h"
#include "lldb/lldb-private.h"
#include "DWARFContext.h"
@@ -282,6 +283,10 @@ class SymbolFileDWARF : public lldb_private::SymbolFileCommon {
void DumpClangAST(lldb_private::Stream &s) override;
+ /// Retrieve the external dwo files.
+ bool GetSeparateDebugInfoFiles(
+ lldb_private::StructuredData::Array &array) override;
+
lldb_private::DWARFContext &GetDWARFContext() { return m_context; }
const std::shared_ptr<SymbolFileDWARFDwo> &GetDwpSymbolFile();
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
index eadedd32e1a4aaf..dd9add83f0d4267 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
@@ -18,8 +18,9 @@
#include "lldb/Host/FileSystem.h"
#include "lldb/Utility/RangeMap.h"
#include "lldb/Utility/RegularExpression.h"
-#include "lldb/Utility/Timer.h"
#include "lldb/Utility/StreamString.h"
+#include "lldb/Utility/StructuredData.h"
+#include "lldb/Utility/Timer.h"
//#define DEBUG_OSO_DMAP // DO NOT CHECKIN WITH THIS NOT COMMENTED OUT
@@ -1271,6 +1272,36 @@ void SymbolFileDWARFDebugMap::DumpClangAST(Stream &s) {
});
}
+bool SymbolFileDWARFDebugMap::GetSeparateDebugInfoFiles(
+ lldb_private::StructuredData::Array &array) {
+ const uint32_t cu_count = GetNumCompileUnits();
+ for (uint32_t cu_idx = 0; cu_idx < cu_count; ++cu_idx) {
+ const auto &info = m_compile_unit_infos[cu_idx];
+ StructuredData::DictionarySP oso_data =
+ std::make_shared<StructuredData::Dictionary>();
+ oso_data->AddStringItem("so_file", info.so_file.GetPath());
+ oso_data->AddStringItem("oso_path", info.oso_path);
+ oso_data->AddIntegerItem("oso_mod_time",
+ (uint32_t)llvm::sys::toTimeT(info.oso_mod_time));
+
+ bool loaded_successfully = false;
+ if (GetModuleByOSOIndex(cu_idx)) {
+ // If we have a valid pointer to the module, we successfully
+ // loaded the oso if there are no load errors.
+ if (!info.oso_load_error.Fail()) {
+ loaded_successfully = true;
+ }
+ }
+ if (!loaded_successfully) {
+ oso_data->AddStringItem("error", info.oso_load_error.AsCString());
+ }
+ oso_data->AddBooleanItem("loaded", loaded_successfully);
+ array.AddItem(oso_data);
+ }
+
+ return true;
+}
+
lldb::CompUnitSP
SymbolFileDWARFDebugMap::GetCompileUnit(SymbolFileDWARF *oso_dwarf, DWARFCompileUnit &dwarf_cu) {
if (oso_dwarf) {
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
index 881fd4c45ff05a0..b486e82eab73d20 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
@@ -19,6 +19,7 @@
#include <vector>
#include "UniqueDWARFASTType.h"
+#include "lldb/Utility/StructuredData.h"
class SymbolFileDWARF;
class DWARFCompileUnit;
@@ -148,6 +149,10 @@ class SymbolFileDWARFDebugMap : public lldb_private::SymbolFileCommon {
void DumpClangAST(lldb_private::Stream &s) override;
+ /// Get the external oso files.
+ bool GetSeparateDebugInfoFiles(
+ lldb_private::StructuredData::Array &array) override;
+
// PluginInterface protocol
llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
diff --git a/lldb/source/Symbol/SymbolFile.cpp b/lldb/source/Symbol/SymbolFile.cpp
index b271efd07bfe36f..ad02a8b2c861907 100644
--- a/lldb/source/Symbol/SymbolFile.cpp
+++ b/lldb/source/Symbol/SymbolFile.cpp
@@ -18,6 +18,7 @@
#include "lldb/Symbol/VariableList.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/StreamString.h"
+#include "lldb/Utility/StructuredData.h"
#include "lldb/lldb-private.h"
#include <future>
@@ -162,6 +163,19 @@ void SymbolFile::AssertModuleLock() {
SymbolFile::RegisterInfoResolver::~RegisterInfoResolver() = default;
+bool SymbolFile::DumpSeparateDebugInfoFiles(StructuredData::Dictionary &d) {
+ StructuredData::Array array;
+ if (!GetSeparateDebugInfoFiles(array)) {
+ return false;
+ }
+
+ d.AddStringItem("symfile", GetMainObjectFile()->GetFileSpec().GetPath());
+ d.AddItem("separate-debug-info-files",
+ std::make_shared<StructuredData::Array>(std::move(array)));
+
+ return true;
+}
+
Symtab *SymbolFileCommon::GetSymtab() {
std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
// Fetch the symtab from the main object file.
diff --git a/lldb/test/API/commands/target/dump-separate-debug-info/dwo/Makefile b/lldb/test/API/commands/target/dump-separate-debug-info/dwo/Makefile
new file mode 100644
index 000000000000000..3b6d788b2b0130a
--- /dev/null
+++ b/lldb/test/API/commands/target/dump-separate-debug-info/dwo/Makefile
@@ -0,0 +1,4 @@
+CXX_SOURCES := main.cpp foo.cpp
+CFLAGS_EXTRAS := -gsplit-dwarf
+
+include Makefile.rules
diff --git a/lldb/test/API/commands/target/dump-separate-debug-info/dwo/TestDumpDwo.py b/lldb/test/API/commands/target/dump-separate-debug-info/dwo/TestDumpDwo.py
new file mode 100644
index 000000000000000..b74f371e3862d37
--- /dev/null
+++ b/lldb/test/API/commands/target/dump-separate-debug-info/dwo/TestDumpDwo.py
@@ -0,0 +1,68 @@
+"""
+Test 'target modules dump separate-debug-info' for dwo files.
+"""
+
+import os
+import json
+
+from lldbsuite.test import lldbtest, lldbutil
+from lldbsuite.test.decorators import *
+
+
+class TestDumpDWO(lldbtest.TestBase):
+ NO_DEBUG_INFO_TESTCASE = True
+
+ def get_dwos_from_command_output(self):
+ """Returns a dictionary of `symfile` -> {`dwo_name` -> dwo_info object}."""
+ result = {}
+ output = json.loads(self.res.GetOutput())
+ for symfile_entry in output:
+ dwo_dict = {}
+ for dwo_entry in symfile_entry["separate-debug-info-files"]:
+ dwo_dict[dwo_entry["dwo_name"]] = dwo_entry
+ result[symfile_entry["symfile"]] = dwo_dict
+ return result
+
+ @skipIfRemote
+ @skipIfDarwin
+ def test_shows_dwo_loaded(self):
+ self.build()
+ exe = self.getBuildArtifact("a.out")
+ main_dwo = self.getBuildArtifact("main.dwo")
+ foo_dwo = self.getBuildArtifact("foo.dwo")
+
+ # Make sure dwo files exist
+ self.assertTrue(os.path.exists(main_dwo), f'Make sure "{main_dwo}" file exists')
+ self.assertTrue(os.path.exists(foo_dwo), f'Make sure "{foo_dwo}" file exists')
+
+ target = self.dbg.CreateTarget(exe)
+ self.assertTrue(target, lldbtest.VALID_TARGET)
+
+ self.runCmd("target modules dump separate-debug-info")
+
+ # Check the output
+ output = self.get_dwos_from_command_output()
+ self.assertTrue(output[exe]["main.dwo"]["loaded"])
+ self.assertTrue(output[exe]["foo.dwo"]["loaded"])
+
+ @skipIfRemote
+ @skipIfDarwin
+ def test_shows_dwo_not_loaded(self):
+ self.build()
+ exe = self.getBuildArtifact("a.out")
+ main_dwo = self.getBuildArtifact("main.dwo")
+ foo_dwo = self.getBuildArtifact("foo.dwo")
+
+ # REMOVE the dwo files
+ os.unlink(main_dwo)
+ os.unlink(foo_dwo)
+
+ target = self.dbg.CreateTarget(exe)
+ self.assertTrue(target, lldbtest.VALID_TARGET)
+
+ self.runCmd("target modules dump separate-debug-info")
+
+ # Check the output
+ output = self.get_dwos_from_command_output()
+ self.assertFalse(output[exe]["main.dwo"]["loaded"])
+ self.assertFalse(output[exe]["foo.dwo"]["loaded"])
diff --git a/lldb/test/API/commands/target/dump-separate-debug-info/dwo/foo.cpp b/lldb/test/API/commands/target/dump-separate-debug-info/dwo/foo.cpp
new file mode 100644
index 000000000000000..28e2b6e768df4e7
--- /dev/null
+++ b/lldb/test/API/commands/target/dump-separate-debug-info/dwo/foo.cpp
@@ -0,0 +1,3 @@
+#include "foo.h"
+
+int foo() { return 1; }
diff --git a/lldb/test/API/commands/target/dump-separate-debug-info/dwo/foo.h b/lldb/test/API/commands/target/dump-separate-debug-info/dwo/foo.h
new file mode 100644
index 000000000000000..4ec598ad513eb91
--- /dev/null
+++ b/lldb/test/API/commands/target/dump-separate-debug-info/dwo/foo.h
@@ -0,0 +1,6 @@
+#ifndef FOO_H
+#define FOO_H
+
+int foo();
+
+#endif
diff --git a/lldb/test/API/commands/target/dump-separate-debug-info/dwo/main.cpp b/lldb/test/API/commands/target/dump-separate-debug-info/dwo/main.cpp
new file mode 100644
index 000000000000000..8087e682432798b
--- /dev/null
+++ b/lldb/test/API/commands/target/dump-separate-debug-info/dwo/main.cpp
@@ -0,0 +1,3 @@
+#include "foo.h"
+
+int main() { return foo(); }
diff --git a/lldb/test/API/commands/target/dump-separate-debug-info/oso/Makefile b/lldb/test/API/commands/target/dump-separate-debug-info/oso/Makefile
new file mode 100644
index 000000000000000..7df22699c57d573
--- /dev/null
+++ b/lldb/test/API/commands/target/dump-separate-debug-info/oso/Makefile
@@ -0,0 +1,3 @@
+CXX_SOURCES := main.cpp foo.cpp
+
+include Makefile.rules
diff --git a/lldb/test/API/commands/target/dump-separate-debug-info/oso/TestDumpOso.py b/lldb/test/API/commands/target/dump-separate-debug-info/oso/TestDumpOso.py
new file mode 100644
index 000000000000000..9021f597bdf806b
--- /dev/null
+++ b/lldb/test/API/commands/target/dump-separate-debug-info/oso/TestDumpOso.py
@@ -0,0 +1,68 @@
+"""
+Test 'target modules dump separate-debug-info' for oso files.
+"""
+
+import os
+import json
+
+from lldbsuite.test import lldbtest, lldbutil
+from lldbsuite.test.decorators import *
+
+
+class TestDumpOso(lldbtest.TestBase):
+ NO_DEBUG_INFO_TESTCASE = True
+
+ def get_osos_from_command_output(self):
+ """Returns a dictionary of `symfile` -> {`OSO_PATH` -> oso_info object}."""
+ result = {}
+ output = json.loads(self.res.GetOutput())
+ for symfile_entry in output:
+ oso_dict = {}
+ for oso_entry in symfile_entry["separate-debug-info-files"]:
+ oso_dict[oso_entry["oso_path"]] = oso_entry
+ result[symfile_entry["symfile"]] = oso_dict
+ return result
+
+ @skipIfRemote
+ @skipUnlessDarwin
+ def test_shows_oso_loaded(self):
+ self.build(debug_info="dwarf")
+ exe = self.getBuildArtifact("a.out")
+ main_o = self.getBuildArtifact("main.o")
+ foo_o = self.getBuildArtifact("foo.o")
+
+ # Make sure o files exist
+ self.assertTrue(os.path.exists(main_o), f'Make sure "{main_o}" file exists')
+ self.assertTrue(os.path.exists(foo_o), f'Make sure "{foo_o}" file exists')
+
+ target = self.dbg.CreateTarget(exe)
+ self.assertTrue(target, lldbtest.VALID_TARGET)
+
+ self.runCmd("target modules dump separate-debug-info")
+
+ # Check the output
+ osos = self.get_osos_from_command_output()
+ self.assertTrue(osos[exe][main_o]["loaded"])
+ self.assertTrue(osos[exe][foo_o]["loaded"])
+
+ @skipIfRemote
+ @skipUnlessDarwin
+ def test_shows_oso_not_loaded(self):
+ self.build(debug_info="dwarf")
+ exe = self.getBuildArtifact("a.out")
+ main_o = self.getBuildArtifact("main.o")
+ foo_o = self.getBuildArtifact("foo.o")
+
+ # REMOVE the o files
+ os.unlink(main_o)
+ os.unlink(foo_o)
+
+ target = self.dbg.CreateTarget(exe)
+ self.assertTrue(target, lldbtest.VALID_TARGET)
+
+ self.runCmd("target modules dump separate-debug-info")
+
+ # Check the output
+ osos = self.get_osos_from_command_output()
+ self.assertFalse(osos[exe][main_o]["loaded"])
+ self.assertFalse(osos[exe][foo_o]["loaded"])
diff --git a/lldb/test/API/commands/target/dump-separate-debug-info/oso/foo.cpp b/lldb/test/API/commands/target/dump-separate-debug-info/oso/foo.cpp
new file mode 100644
index 000000000000000..28e2b6e768df4e7
--- /dev/null
+++ b/lldb/test/API/commands/target/dump-separate-debug-info/oso/foo.cpp
@@ -0,0 +1,3 @@
+#include "foo.h"
+
+int foo() { return 1; }
diff --git a/lldb/test/API/commands/target/dump-separate-debug-info/oso/foo.h b/lldb/test/API/commands/target/dump-separate-debug-info/oso/foo.h
new file mode 100644
index 000000000000000..4ec598ad513eb91
--- /dev/null
+++ b/lldb/test/API/commands/target/dump-separate-debug-info/oso/foo.h
@@ -0,0 +1,6 @@
+#ifndef FOO_H
+#define FOO_H
+
+int foo();
+
+#endif
diff --git a/lldb/test/API/commands/target/dump-separate-debug-info/oso/main.cpp b/lldb/test/API/commands/target/dump-separate-debug-info/oso/main.cpp
new file mode 100644
index 000000000000000..8087e682432798b
--- /dev/null
+++ b/lldb/test/API/commands/target/dump-separate-debug-info/oso/main.cpp
@@ -0,0 +1,3 @@
+#include "foo.h"
+
+int main() { return foo(); }
More information about the lldb-commits
mailing list