Skip to content
Closed
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
129 changes: 129 additions & 0 deletions llvm/test/tools/llvm-dwp/X86/dwos_list_from_exec_remap.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
// Test remapping old DWO paths in the executables and libraries to new paths.

RUN: rm -rf %t
RUN: mkdir %t
RUN: cd %t

RUN: cp %p/../Inputs/dwos_list_from_exec/main main
RUN: cp %p/../Inputs/dwos_list_from_exec/libd.so libd.so

// Test remapping full DWO paths (<DW_AT_comp_dir>/<DW_AT_dwo_name>) to absolute paths
RUN: touch remapping_path_to_absolute.txt
RUN: echo "./a.dwo %p/../Inputs/dwos_list_from_exec/a.dwo" >> remapping_path_to_absolute.txt
RUN: echo "./b.dwo %p/../Inputs/dwos_list_from_exec/b.dwo" >> remapping_path_to_absolute.txt
RUN: echo "./d.dwo %p/../Inputs/dwos_list_from_exec/d.dwo" >> remapping_path_to_absolute.txt
RUN: llvm-dwp %p/../Inputs/dwos_list_from_exec/c.dwo %p/../Inputs/dwos_list_from_exec/e.dwo \
RUN: -e main -e libd.so --exec-dwo-path-remapping-file=remapping_path_to_absolute.txt -o - | llvm-dwarfdump -v - | FileCheck %s

// Test remapping full DWO paths (<DW_AT_comp_dir>/<DW_AT_dwo_name>) to relative paths
RUN: mkdir foo && cp %p/../Inputs/dwos_list_from_exec/a.dwo foo/a.dwo
RUN: mkdir bar && cp %p/../Inputs/dwos_list_from_exec/b.dwo bar/b.dwo
RUN: mkdir qux && cp %p/../Inputs/dwos_list_from_exec/d.dwo qux/d.dwo
RUN: touch remapping_path_to_relative.txt
RUN: echo "./a.dwo foo/a.dwo" >> remapping_path_to_relative.txt
RUN: echo "./b.dwo bar/b.dwo" >> remapping_path_to_relative.txt
RUN: echo "./d.dwo qux/d.dwo" >> remapping_path_to_relative.txt
RUN: llvm-dwp %p/../Inputs/dwos_list_from_exec/c.dwo %p/../Inputs/dwos_list_from_exec/e.dwo \
RUN: -e main -e libd.so --exec-dwo-path-remapping-file=remapping_path_to_relative.txt -o - | llvm-dwarfdump -v - | FileCheck %s

// Test remapping DWO name (<DW_AT_dwo_name>) to relative paths
RUN: touch remapping_name_to_relative.txt
RUN: echo "a.dwo foo/a.dwo" >> remapping_name_to_relative.txt
RUN: echo "b.dwo bar/b.dwo" >> remapping_name_to_relative.txt
RUN: echo "d.dwo qux/d.dwo" >> remapping_name_to_relative.txt
RUN: llvm-dwp %p/../Inputs/dwos_list_from_exec/c.dwo %p/../Inputs/dwos_list_from_exec/e.dwo \
RUN: -e main -e libd.so --exec-dwo-path-remapping-file=remapping_name_to_relative.txt -o - | llvm-dwarfdump -v - | FileCheck %s

// Test remapping with multiple files
RUN: touch remapping_main.txt
RUN: echo "./a.dwo %p/../Inputs/dwos_list_from_exec/a.dwo" >> remapping_main.txt
RUN: echo "./b.dwo %p/../Inputs/dwos_list_from_exec/b.dwo" >> remapping_main.txt
RUN: echo "./d.dwo %p/../Inputs/dwos_list_from_exec/d.dwo" > remapping_libd.txt
RUN: llvm-dwp %p/../Inputs/dwos_list_from_exec/c.dwo %p/../Inputs/dwos_list_from_exec/e.dwo \
RUN: -e main -e libd.so \
RUN: --exec-dwo-path-remapping-file=remapping_main.txt \
RUN: --exec-dwo-path-remapping-file=remapping_libd.txt \
RUN: -o - | llvm-dwarfdump -v - | FileCheck %s

Build commands for the test binaries:

clang++ -Xclang -fdebug-compilation-dir -Xclang "./" -g -O0 -gsplit-dwarf a.cpp b.cpp -o main
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you specify dwarf version explicitly, in case default changes in the future.
Kind of surprised it defaults to 4. I thought 5 was the default now.

Copy link
Member Author

@mpark mpark Sep 10, 2025

Choose a reason for hiding this comment

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

I'm basically willing to do whatever here, but I'm not sure just adding -gdwarf-5 here makes sense. This test is largely copied from the existing dwos_list_from_exec_simple.test, which has these binaries checked into the repo under Inputs/dwos_list_from_exec. The binaries were definitely built to DWARF-4 spec. I could specify -gdwarf-5 in both and update the checked in binaries or, alternatively I could specify -gdwarf-4 in these tests to pin the version. Do you have a preferred approach?

Copy link
Contributor

Choose a reason for hiding this comment

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

Oh I missed this operates on binary level. I thought we converted all tests to be text version. Never mind.

clang++ -g -O0 -gsplit-dwarf -c c.cpp -o c.o
clang++ -Xclang -fdebug-compilation-dir -Xclang "./" -g -O0 -gsplit-dwarf -fPIC -shared d.cpp -o libd.so
clang++ -g -O0 -gsplit-dwarf -c e.cpp -o e.o

sources:
a.cpp:
void a() {}

b.cpp:
void b() {}
int main() {
return 0;
}

c.cpp:
void c() {}

d.cpp:
void d() {}

e.cpp:
void e() {}

CHECK-LABEL: .debug_abbrev.dwo contents:

CHECK-LABEL: Abbrev table for offset:
CHECK: DW_TAG_compile_unit
CHECK: DW_TAG_subprogram

CHECK-LABEL: Abbrev table for offset:
CHECK: DW_TAG_compile_unit
CHECK: DW_TAG_subprogram

CHECK-LABEL: Abbrev table for offset:
CHECK: DW_TAG_compile_unit
CHECK: DW_TAG_subprogram

CHECK-LABEL: Abbrev table for offset:
CHECK: DW_TAG_compile_unit
CHECK: DW_TAG_subprogram

CHECK-LABEL: Abbrev table for offset:
CHECK: DW_TAG_compile_unit
CHECK: DW_TAG_subprogram

CHECK: .debug_info.dwo contents:
CHECK: [[AOFF:0x[0-9a-f]*]]:

CHECK-LABEL: Compile Unit: length = {{.*}}, version = 0x0004
CHECK: DW_TAG_compile_unit
CHECK: DW_AT_name {{.*}} "c.cpp"
CHECK: DW_TAG_subprogram
CHECK: DW_AT_name {{.*}} "c"

CHECK-LABEL: Compile Unit: length = {{.*}}, version = 0x0004
CHECK: DW_TAG_compile_unit
CHECK: DW_AT_name {{.*}} "e.cpp"
CHECK: DW_TAG_subprogram
CHECK: DW_AT_name {{.*}} "e"

CHECK-LABEL: Compile Unit: length = {{.*}}, version = 0x0004
CHECK: DW_TAG_compile_unit
CHECK: DW_AT_name {{.*}} "a.cpp"
CHECK: DW_TAG_subprogram
CHECK: DW_AT_name {{.*}} "a"

CHECK-LABEL: Compile Unit: length = {{.*}}, version = 0x0004
CHECK: DW_TAG_compile_unit
CHECK: DW_AT_name {{.*}} "b.cpp"
CHECK: DW_TAG_subprogram
CHECK: DW_AT_name {{.*}} "b"
CHECK: DW_TAG_subprogram
CHECK: DW_AT_name {{.*}} "main"

CHECK-LABEL: Compile Unit: length = {{.*}}, version = 0x0004
CHECK: DW_TAG_compile_unit
CHECK: DW_AT_name {{.*}} "d.cpp"
CHECK: DW_TAG_subprogram
CHECK: DW_AT_name {{.*}} "d"
2 changes: 2 additions & 0 deletions llvm/tools/llvm-dwp/Opts.td
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,5 @@ def continueOnCuIndexOverflow_EQ : Joined<["-", "--"], "continue-on-cu-index-ove
"\t\ttruncated but valid DWP file, discarding any DWO files that would not fit within \n"
"\t\tthe 32 bit/4GB limits of the format.">,
Values<"continue,soft-stop">;
def execDwoPathRemappingFile : Joined<["--"], "exec-dwo-path-remapping-file=">, MetaVarName<"<filename>">,
HelpText<"Use the old and new paths described in <filename> to map old dwo paths in executables/libraries to the new paths.">;
47 changes: 45 additions & 2 deletions llvm/tools/llvm-dwp/llvm-dwp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
// package files).
//
//===----------------------------------------------------------------------===//
#include "llvm/ADT/StringMap.h"
#include "llvm/DWP/DWP.h"
#include "llvm/DWP/DWPError.h"
#include "llvm/DWP/DWPStringPool.h"
Expand Down Expand Up @@ -75,7 +76,8 @@ static std::string OutputFilename;
static std::string ContinueOption;

static Expected<SmallVector<std::string, 16>>
getDWOFilenames(StringRef ExecFilename) {
getDWOFilenames(StringRef ExecFilename,
const StringMap<StringRef> &DWOPathMap) {
auto ErrOrObj = object::ObjectFile::createObjectFile(ExecFilename);
if (!ErrOrObj)
return ErrOrObj.takeError();
Expand All @@ -95,11 +97,17 @@ getDWOFilenames(StringRef ExecFilename) {
if (!DWOCompDir.empty()) {
SmallString<16> DWOPath(DWOName);
sys::fs::make_absolute(DWOCompDir, DWOPath);
if (auto I = DWOPathMap.find(DWOPath); I != DWOPathMap.end())
DWOPath = I->getValue();
if (auto I = DWOPathMap.find(DWOName); I != DWOPathMap.end())
DWOName = I->getValue();
if (!sys::fs::exists(DWOPath) && sys::fs::exists(DWOName))
DWOPaths.push_back(std::move(DWOName));
else
DWOPaths.emplace_back(DWOPath.data(), DWOPath.size());
} else {
if (auto I = DWOPathMap.find(DWOName); I != DWOPathMap.end())
DWOName = I->getValue();
DWOPaths.push_back(std::move(DWOName));
}
}
Expand All @@ -120,6 +128,33 @@ static Expected<Triple> readTargetTriple(StringRef FileName) {
return ErrOrObj->getBinary()->makeTriple();
}

static Error addPathsToRemapFromFile(StringMap<StringRef> &DWOPathMap,
BumpPtrAllocator &Alloc,
StringRef Filename) {
StringSaver Saver(Alloc);
SmallVector<StringRef, 16> Lines;
auto BufOrErr = MemoryBuffer::getFile(Filename);
if (!BufOrErr)
return createFileError(Filename, BufOrErr.getError());

BufOrErr.get()->getBuffer().split(Lines, '\n');
for (size_t LineNo = 0, NumLines = Lines.size(); LineNo < NumLines;
++LineNo) {
StringRef TrimmedLine = Lines[LineNo].split('#').first.trim();
if (TrimmedLine.empty())
continue;

std::pair<StringRef, StringRef> Pair = Saver.save(TrimmedLine).split(' ');
StringRef NewName = Pair.second.trim();
if (NewName.empty())
return createStringError(errc::invalid_argument,
"%s:%zu: missing new DWO path",
Filename.str().c_str(), LineNo + 1);
DWOPathMap.insert({Pair.first, NewName});
}
return Error::success();
}

int llvm_dwp_main(int argc, char **argv, const llvm::ToolContext &) {
DwpOptTable Tbl;
llvm::BumpPtrAllocator A;
Expand Down Expand Up @@ -173,8 +208,16 @@ int llvm_dwp_main(int argc, char **argv, const llvm::ToolContext &) {
llvm::InitializeAllTargets();
llvm::InitializeAllAsmPrinters();

llvm::StringMap<StringRef> DWOPathMap;
for (auto *Arg : Args.filtered(OPT_execDwoPathRemappingFile)) {
if (Error E = addPathsToRemapFromFile(DWOPathMap, A, Arg->getValue())) {
logAllUnhandledErrors(std::move(E), WithColor::error());
return 1;
}
}

for (const auto &ExecFilename : ExecFilenames) {
auto DWOs = getDWOFilenames(ExecFilename);
auto DWOs = getDWOFilenames(ExecFilename, DWOPathMap);
if (!DWOs) {
logAllUnhandledErrors(
handleErrors(DWOs.takeError(),
Expand Down