[llvm] [llvm-dwp] Add a new flag `--exec-dwo-path-remapping-file=<filename>`. (PR #157587)
Michael Park via llvm-commits
llvm-commits at lists.llvm.org
Wed Sep 10 00:17:31 PDT 2025
https://github.com/mpark updated https://github.com/llvm/llvm-project/pull/157587
>From da34ce416f28089ca9d10fbbf31875b1beb54e71 Mon Sep 17 00:00:00 2001
From: Michael Park <mcypark at gmail.com>
Date: Mon, 8 Sep 2025 18:01:52 -0700
Subject: [PATCH] [llvm-dwp] Add a new flag
`--exec-dwo-path-remapping-file=<filename>` that allows remapping the dwo
paths embedded in executables and libraries.
---
.../X86/dwos_list_from_exec_remap.test | 129 ++++++++++++++++++
llvm/tools/llvm-dwp/Opts.td | 2 +
llvm/tools/llvm-dwp/llvm-dwp.cpp | 47 ++++++-
3 files changed, 176 insertions(+), 2 deletions(-)
create mode 100644 llvm/test/tools/llvm-dwp/X86/dwos_list_from_exec_remap.test
diff --git a/llvm/test/tools/llvm-dwp/X86/dwos_list_from_exec_remap.test b/llvm/test/tools/llvm-dwp/X86/dwos_list_from_exec_remap.test
new file mode 100644
index 0000000000000..437d635b54e31
--- /dev/null
+++ b/llvm/test/tools/llvm-dwp/X86/dwos_list_from_exec_remap.test
@@ -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
+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"
diff --git a/llvm/tools/llvm-dwp/Opts.td b/llvm/tools/llvm-dwp/Opts.td
index 46593bc40ebae..ecc1c25814c50 100644
--- a/llvm/tools/llvm-dwp/Opts.td
+++ b/llvm/tools/llvm-dwp/Opts.td
@@ -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.">;
diff --git a/llvm/tools/llvm-dwp/llvm-dwp.cpp b/llvm/tools/llvm-dwp/llvm-dwp.cpp
index 61ba82d0634ac..c5761017aa27d 100644
--- a/llvm/tools/llvm-dwp/llvm-dwp.cpp
+++ b/llvm/tools/llvm-dwp/llvm-dwp.cpp
@@ -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"
@@ -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();
@@ -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));
}
}
@@ -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;
@@ -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(),
More information about the llvm-commits
mailing list