Skip to content

[lldb] Add more ways to find the .dwp file. #81067

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Feb 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions lldb/include/lldb/Utility/FileSpecList.h
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,10 @@ class FileSpecList {
const_iterator begin() const { return m_files.begin(); }
const_iterator end() const { return m_files.end(); }

llvm::iterator_range<const_iterator> files() const {
return llvm::make_range(begin(), end());
}

protected:
collection m_files; ///< A collection of FileSpec objects.
};
Expand Down
1 change: 1 addition & 0 deletions lldb/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ static constexpr Log::Category g_categories[] = {
{{"map"},
{"log insertions of object files into DWARF debug maps"},
DWARFLog::DebugMap},
{{"split"}, {"log split DWARF related activities"}, DWARFLog::SplitDwarf},
};

static Log::Channel g_channel(g_categories, DWARFLog::DebugInfo);
Expand Down
1 change: 1 addition & 0 deletions lldb/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ enum class DWARFLog : Log::MaskType {
DebugMap = Log::ChannelFlag<2>,
Lookups = Log::ChannelFlag<3>,
TypeCompletion = Log::ChannelFlag<4>,
SplitDwarf = Log::ChannelFlag<5>,
LLVM_MARK_AS_BITMASK_ENUM(TypeCompletion)
};
LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
Expand Down
68 changes: 51 additions & 17 deletions lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4349,26 +4349,60 @@ SymbolFileDWARFDebugMap *SymbolFileDWARF::GetDebugMapSymfile() {

const std::shared_ptr<SymbolFileDWARFDwo> &SymbolFileDWARF::GetDwpSymbolFile() {
llvm::call_once(m_dwp_symfile_once_flag, [this]() {
// Create a list of files to try and append .dwp to.
FileSpecList symfiles;
// Append the module's object file path.
const FileSpec module_fspec = m_objfile_sp->GetModule()->GetFileSpec();
symfiles.Append(module_fspec);
// Append the object file for this SymbolFile only if it is different from
// the module's file path. Our main module could be "a.out", our symbol file
// could be "a.debug" and our ".dwp" file might be "a.debug.dwp" instead of
// "a.out.dwp".
const FileSpec symfile_fspec(m_objfile_sp->GetFileSpec());
if (symfile_fspec != module_fspec) {
symfiles.Append(symfile_fspec);
} else {
// If we don't have a separate debug info file, then try stripping the
// extension. The main module could be "a.debug" and the .dwp file could
// be "a.dwp" instead of "a.debug.dwp".
ConstString filename_no_ext =
module_fspec.GetFileNameStrippingExtension();
if (filename_no_ext != module_fspec.GetFilename()) {
FileSpec module_spec_no_ext(module_fspec);
module_spec_no_ext.SetFilename(filename_no_ext);
symfiles.Append(module_spec_no_ext);
}
}
Log *log = GetLog(DWARFLog::SplitDwarf);
FileSpecList search_paths = Target::GetDefaultDebugFileSearchPaths();
ModuleSpec module_spec;
module_spec.GetFileSpec() = m_objfile_sp->GetFileSpec();
module_spec.GetSymbolFileSpec() =
FileSpec(m_objfile_sp->GetModule()->GetFileSpec().GetPath() + ".dwp");

module_spec.GetUUID() = m_objfile_sp->GetUUID();
FileSpecList search_paths = Target::GetDefaultDebugFileSearchPaths();
FileSpec dwp_filespec =
PluginManager::LocateExecutableSymbolFile(module_spec, search_paths);
if (FileSystem::Instance().Exists(dwp_filespec)) {
DataBufferSP dwp_file_data_sp;
lldb::offset_t dwp_file_data_offset = 0;
ObjectFileSP dwp_obj_file = ObjectFile::FindPlugin(
GetObjectFile()->GetModule(), &dwp_filespec, 0,
FileSystem::Instance().GetByteSize(dwp_filespec), dwp_file_data_sp,
dwp_file_data_offset);
if (!dwp_obj_file)
return;
m_dwp_symfile = std::make_shared<SymbolFileDWARFDwo>(
*this, dwp_obj_file, DIERef::k_file_index_mask);
for (const auto &symfile : symfiles.files()) {
module_spec.GetSymbolFileSpec() =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding a logging for each probing entries.

One thing I noticed that Microsoft debugger (like windbg) does well is they provide an option to show debug artifacts probing paths for both local and symbol servers. This provides an important self servicing capability for end users - even they do not know the debug info file locating algorithms, they can use the probing paths to figure out and rename to match the expected probing.

FileSpec(symfile.GetPath() + ".dwp", symfile.GetPathStyle());
LLDB_LOG(log, "Searching for DWP using: \"{0}\"",
module_spec.GetSymbolFileSpec());
FileSpec dwp_filespec =
PluginManager::LocateExecutableSymbolFile(module_spec, search_paths);
if (FileSystem::Instance().Exists(dwp_filespec)) {
LLDB_LOG(log, "Found DWP file: \"{0}\"", dwp_filespec);
DataBufferSP dwp_file_data_sp;
lldb::offset_t dwp_file_data_offset = 0;
ObjectFileSP dwp_obj_file = ObjectFile::FindPlugin(
GetObjectFile()->GetModule(), &dwp_filespec, 0,
FileSystem::Instance().GetByteSize(dwp_filespec), dwp_file_data_sp,
dwp_file_data_offset);
if (dwp_obj_file) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar, adding a logging saying - found a matching dwp file and use it.

m_dwp_symfile = std::make_shared<SymbolFileDWARFDwo>(
*this, dwp_obj_file, DIERef::k_file_index_mask);
break;
}
}
}
if (!m_dwp_symfile) {
LLDB_LOG(log, "Unable to locate for DWP file for: \"{0}\"",
m_objfile_sp->GetModule()->GetFileSpec());
}
});
return m_dwp_symfile;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
// REQUIRES: lld

// Now test with DWARF5
// RUN: %clang -target x86_64-pc-linux -gsplit-dwarf -gdwarf-5 -c %s -o %t.dwarf5.o
// RUN: ld.lld %t.dwarf5.o -o %t.dwarf5
// RUN: llvm-dwp %t.dwarf5.dwo -o %t.dwarf5.dwp
// RUN: rm %t.dwarf5.dwo
// RUN: llvm-objcopy --only-keep-debug %t.dwarf5 %t.dwarf5.debug
// RUN: llvm-objcopy --strip-all --add-gnu-debuglink=%t.dwarf5.debug %t.dwarf5
// RUN: %lldb %t.dwarf5 -o "target variable a" -b | FileCheck %s
// RUN: %lldb \
// RUN: -O "log enable dwarf split" \
// RUN: -o "target variable a" \
// RUN: -b %t.dwarf5 | FileCheck %s

// Run one time with the index cache enabled to populate the index cache. When
// we populate the index cache we have to parse all of the DWARF debug info
Expand Down Expand Up @@ -34,14 +38,42 @@
// RUN: -o "statistics dump" \
// RUN: %t.dwarf5 -b | FileCheck %s -check-prefix=CACHED

// Make sure that if we load the "%t.dwarf5.debug" file, that we can find and
// load the .dwo file from the .dwp when it is "%t.dwarf5.dwp"
// RUN: %lldb %t.dwarf5.debug -o "b main" -b | FileCheck %s -check-prefix=DEBUG

// Make sure that if we load the "%t.dwarf5" file, that we can find and
// load the .dwo file from the .dwp when it is "%t.dwarf5.debug.dwp"
// RUN: mv %t.dwarf5.dwp %t.dwarf5.debug.dwp
// RUN: %lldb %t.dwarf5 -o "b main" -b | FileCheck %s -check-prefix=DEBUG

// Make sure that if we load the "%t.dwarf5.debug" file, that we can find and
// load the .dwo file from the .dwp when it is "%t.dwarf5.debug.dwp"
// RUN: %lldb %t.dwarf5.debug -o "b main" -b | FileCheck %s -check-prefix=DEBUG

// Make sure that if we remove the .dwp file we see an appropriate error.
// RUN: rm %t.dwarf5.debug.dwp
// RUN: %lldb \
// RUN: -O "log enable dwarf split" \
// RUN: -o "b main" \
// RUN: -b %t.dwarf5 2>&1 | FileCheck %s -check-prefix=NODWP

// RUN: %lldb \
// RUN: -O "log enable dwarf split" \
// RUN: -o "b main" \
// RUN: -b %t.dwarf5.debug 2>&1 | FileCheck %s -check-prefix=NODWP

// Now test with DWARF4
// RUN: %clang -target x86_64-pc-linux -gsplit-dwarf -gdwarf-4 -c %s -o %t.dwarf4.o
// RUN: ld.lld %t.dwarf4.o -o %t.dwarf4
// RUN: llvm-dwp %t.dwarf4.dwo -o %t.dwarf4.dwp
// RUN: rm %t.dwarf4.dwo
// RUN: llvm-objcopy --only-keep-debug %t.dwarf4 %t.dwarf4.debug
// RUN: llvm-objcopy --strip-all --add-gnu-debuglink=%t.dwarf4.debug %t.dwarf4
// RUN: %lldb %t.dwarf4 -o "target variable a" -b | FileCheck %s
// RUN: %lldb \
// RUN: -O "log enable dwarf split" \
// RUN: -o "target variable a" \
// RUN: -b %t.dwarf4 | FileCheck %s

// Run one time with the index cache enabled to populate the index cache. When
// we populate the index cache we have to parse all of the DWARF debug info
Expand Down Expand Up @@ -69,6 +101,46 @@
// RUN: -o "statistics dump" \
// RUN: %t.dwarf4 -b | FileCheck %s -check-prefix=CACHED

// Make sure that if we load the "%t.dwarf4.debug" file, that we can find and
// load the .dwo file from the .dwp when it is "%t.dwarf4.dwp"
// RUN: %lldb %t.dwarf4.debug -o "b main" -b | FileCheck %s -check-prefix=DEBUG

// Make sure that if we load the "%t.dwarf4" file, that we can find and
// load the .dwo file from the .dwp when it is "%t.dwarf4.debug.dwp"
// RUN: mv %t.dwarf4.dwp %t.dwarf4.debug.dwp
// RUN: %lldb %t.dwarf4 -o "b main" -b | FileCheck %s -check-prefix=DEBUG

// Make sure that if we load the "%t.dwarf4.debug" file, that we can find and
// load the .dwo file from the .dwp when it is "%t.dwarf4.debug.dwp"
// RUN: %lldb %t.dwarf4.debug -o "b main" -b | FileCheck %s -check-prefix=DEBUG

// Make sure that if we remove the .dwp file we see an appropriate error.
// RUN: rm %t.dwarf4.debug.dwp
// RUN: %lldb \
// RUN: -O "log enable dwarf split" \
// RUN: -o "b main" \
// RUN: -b %t.dwarf4 2>&1 | FileCheck %s -check-prefix=NODWP

// RUN: %lldb \
// RUN: -O "log enable dwarf split" \
// RUN: -o "b main" \
// RUN: -b %t.dwarf4.debug 2>&1 | FileCheck %s -check-prefix=NODWP

// Test if we have a GNU build ID in our main executable and in our debug file,
// and we have a .dwp file that doesn't, that we can still load our .dwp file.
// RUN: %clang -target x86_64-pc-linux -gsplit-dwarf -gdwarf-5 -c %s -o %t.o
// RUN: ld.lld %t.o --build-id=md5 -o %t
// RUN: llvm-dwp %t.dwo -o %t.dwp
// RUN: rm %t.dwo
// RUN: llvm-objcopy --only-keep-debug %t %t.debug
// RUN: llvm-objcopy --strip-all --add-gnu-debuglink=%t.debug %t
// RUN: %lldb \
// RUN: -O "log enable dwarf split" \
// RUN: -o "target variable a" \
// RUN: -b %t | FileCheck %s

// CHECK: Searching for DWP using:
// CHECK: Found DWP file:
// CHECK: (A) a = (x = 47)

// CACHE: script lldb.target.modules[0].FindTypes('::A').GetTypeAtIndex(0)
Expand All @@ -83,6 +155,16 @@
// CACHED-NEXT: }
// CACHED: "totalDebugInfoIndexLoadedFromCache": 1

// Make sure debug information was loaded by verifying that the
// DEBUG: Breakpoint 1: where = dwp-separate-debug-file.cpp.tmp.dwarf{{[45]}}{{(\.debug)?}}`main + {{[0-9]+}} at dwp-separate-debug-file.cpp:{{[0-9]+}}:{{[0-9]+}}, address = {{0x[0-9a-fA-F]+}}

// Make sure if we load the stripped binary or the debug info file with no .dwp
// nor any .dwo files that we are not able to fine the .dwp or .dwo files.
// NODWP: Searching for DWP using:
// NODWP: Searching for DWP using:
// NODWP: Unable to locate for DWP file for:
// NODWP: unable to locate separate debug file (dwo, dwp). Debugging will be degraded.

struct A {
int x = 47;
};
Expand Down