Index: include/llvm/MC/MCContext.h =================================================================== --- include/llvm/MC/MCContext.h +++ include/llvm/MC/MCContext.h @@ -137,6 +137,9 @@ /// The compilation directory to use for DW_AT_comp_dir. SmallString<128> CompilationDir; + /// Prefix replacement map for source file information. + std::map DebugPrefixMap; + /// The main file name if passed in explicitly. std::string MainFileName; @@ -490,6 +493,14 @@ /// Set the compilation directory for DW_AT_comp_dir void setCompilationDir(StringRef S) { CompilationDir = S.str(); } + /// Get the debug prefix map. + const std::map &getDebugPrefixMap() const { + return DebugPrefixMap; + } + + /// Add an entry to the debug prefix map. + void addDebugPrefixMapEntry(const std::string &From, const std::string &To); + /// Get the main file name for use in error messages and debug /// info. This can be set to ensure we've got the correct file name /// after preprocessing or for -save-temps. Index: lib/MC/MCContext.cpp =================================================================== --- lib/MC/MCContext.cpp +++ lib/MC/MCContext.cpp @@ -535,6 +535,10 @@ return *new (MCSubtargetAllocator.Allocate()) MCSubtargetInfo(STI); } +void MCContext::addDebugPrefixMapEntry(const std::string &From, const std::string &To) { + DebugPrefixMap.insert(std::make_pair(From, To)); +} + //===----------------------------------------------------------------------===// // Dwarf Management //===----------------------------------------------------------------------===// Index: lib/MC/MCDwarf.cpp =================================================================== --- lib/MC/MCDwarf.cpp +++ lib/MC/MCDwarf.cpp @@ -307,6 +307,13 @@ OS.EmitValue(ABS, Size); } +static std::string remapDebugPath(MCStreamer *MCOS, StringRef Path) { + for (const auto &Entry : MCOS->getContext().getDebugPrefixMap()) + if (Path.startswith(Entry.first)) + return (Twine(Entry.second) + Path.substr(Entry.first.size())).str(); + return Path; +} + void MCDwarfLineStr::emitSection(MCStreamer *MCOS) { // Switch to the .debug_line_str section. MCOS->SwitchSection( @@ -332,7 +339,8 @@ void MCDwarfLineTableHeader::emitV2FileDirTables(MCStreamer *MCOS) const { // First the directory table. for (auto &Dir : MCDwarfDirs) { - MCOS->EmitBytes(Dir); // The DirectoryName, and... + const std::string RemappedDir = remapDebugPath(MCOS, Dir); + MCOS->EmitBytes(RemappedDir); // The DirectoryName, and... MCOS->EmitBytes(StringRef("\0", 1)); // its null terminator. } MCOS->EmitIntValue(0, 1); // Terminate the directory list. @@ -391,17 +399,21 @@ // Try not to emit an empty compilation directory. const StringRef CompDir = CompilationDir.empty() ? CtxCompilationDir : StringRef(CompilationDir); + const std::string RemappedCompDir = remapDebugPath(MCOS, CompDir); if (LineStr) { // Record path strings, emit references here. - LineStr->emitRef(MCOS, CompDir); - for (auto &Dir : MCDwarfDirs) - LineStr->emitRef(MCOS, Dir); + LineStr->emitRef(MCOS, RemappedCompDir); + for (const auto &Dir : MCDwarfDirs) { + const std::string RemappedDir = remapDebugPath(MCOS, Dir); + LineStr->emitRef(MCOS, RemappedDir); + } } else { // The list of directory paths. Compilation directory comes first. - MCOS->EmitBytes(CompDir); + MCOS->EmitBytes(RemappedCompDir); MCOS->EmitBytes(StringRef("\0", 1)); - for (auto &Dir : MCDwarfDirs) { - MCOS->EmitBytes(Dir); // The DirectoryName, and... + for (const auto &Dir : MCDwarfDirs) { + const std::string RemappedDir = remapDebugPath(MCOS, Dir); + MCOS->EmitBytes(RemappedDir); // The DirectoryName, and... MCOS->EmitBytes(StringRef("\0", 1)); // its null terminator. } } @@ -955,7 +967,8 @@ // and file table entries. const SmallVectorImpl &MCDwarfDirs = context.getMCDwarfDirs(); if (MCDwarfDirs.size() > 0) { - MCOS->EmitBytes(MCDwarfDirs[0]); + const std::string RemappedDir = remapDebugPath(MCOS, MCDwarfDirs[0]); + MCOS->EmitBytes(RemappedDir); MCOS->EmitBytes(sys::path::get_separator()); } const SmallVectorImpl &MCDwarfFiles = @@ -965,7 +978,8 @@ // AT_comp_dir, the working directory the assembly was done in. if (!context.getCompilationDir().empty()) { - MCOS->EmitBytes(context.getCompilationDir()); + const std::string RemappedCompDir = remapDebugPath(MCOS, context.getCompilationDir()); + MCOS->EmitBytes(RemappedCompDir); MCOS->EmitIntValue(0, 1); // NULL byte to terminate the string. } Index: test/MC/ELF/debug-prefix-map.s =================================================================== --- /dev/null +++ test/MC/ELF/debug-prefix-map.s @@ -0,0 +1,18 @@ +// RUN: mkdir -p %t.foo +// RUN: cp %s %t.foo/src.s +// RUN: cd %t.foo + +// RUN: llvm-mc -triple=x86_64-linux-unknown -g src.s -filetype=obj -o out.o +// RUN: llvm-dwarfdump -v -debug-info out.o | FileCheck --check-prefix=NO_MAP %s + +// NO_MAP: DW_AT_comp_dir [DW_FORM_string] ("{{.*}}.foo") + +// RUN: llvm-mc -triple=x86_64-linux-unknown -g src.s -filetype=obj -o out.o -fdebug-prefix-map=%t.foo=src_root +// RUN: llvm-dwarfdump -v -debug-info out.o | FileCheck --check-prefix=MAP --implicit-check-not ".foo" %s + +// MAP: DW_AT_name [DW_FORM_string] ("src.s") +// MAP: DW_AT_comp_dir [DW_FORM_string] ("src_root") +// MAP: DW_AT_decl_file [DW_FORM_data4] ("src_root/src.s") + +f: + nop Index: tools/llvm-mc/llvm-mc.cpp =================================================================== --- tools/llvm-mc/llvm-mc.cpp +++ tools/llvm-mc/llvm-mc.cpp @@ -152,6 +152,11 @@ DebugCompilationDir("fdebug-compilation-dir", cl::desc("Specifies the debug info's compilation dir")); +static cl::list +DebugPrefixMap("fdebug-prefix-map", + cl::desc("Map file source paths in debug info"), + cl::value_desc("= separated key-value pairs")); + static cl::opt MainFileName("main-file-name", cl::desc("Specifies the name we should consider the input file")); @@ -387,6 +392,10 @@ if (!sys::fs::current_path(CWD)) Ctx.setCompilationDir(CWD); } + for (const auto &Arg : DebugPrefixMap) { + const auto &KV = StringRef(Arg).split('='); + Ctx.addDebugPrefixMapEntry(KV.first, KV.second); + } if (!MainFileName.empty()) Ctx.setMainFileName(MainFileName); if (GenDwarfForAssembly && DwarfVersion >= 5) {