[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