Skip to content

Commit d72d77d

Browse files
Ilya YanokJohanEngelen
authored andcommitted
Add -fdebug-prefix-map and follow clang's behavior for debuginfo file/dir names.
This is required to have reproducible builds without remapping the source code directory to a fixed location (for example in Bazel, where the source code for every build action will end up in a sandbox directory with some hash in the path name). Try to keep the implementation as close as possible to what clang does.
1 parent 5fa7914 commit d72d77d

5 files changed

Lines changed: 85 additions & 13 deletions

File tree

driver/cl_options.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,32 @@ cl::opt<bool> emitDwarfDebugInfo(
223223
"gdwarf", cl::ZeroOrMore,
224224
cl::desc("Emit DWARF debuginfo (instead of CodeView) for MSVC targets"));
225225

226+
// Prefix map for filenames in DWARF debuginfo
227+
std::map<std::string, std::string> debugPrefixMap;
228+
229+
struct DwarfPrefixParser : public cl::parser<std::string> {
230+
explicit DwarfPrefixParser(cl::Option &O) : cl::parser<std::string>(O) {}
231+
232+
bool parse(cl::Option &O, llvm::StringRef /*ArgName*/, llvm::StringRef Arg,
233+
std::string & /*Val*/) {
234+
auto [from, to] = Arg.split('=');
235+
if (from.empty() || to.empty()) {
236+
return O.error("invalid debug prefix map: " + Arg);
237+
}
238+
auto fromStr = std::string(from);
239+
if (debugPrefixMap.find(fromStr) != debugPrefixMap.end()) {
240+
return O.error("debug prefix map already contains: " + fromStr);
241+
}
242+
debugPrefixMap[fromStr] = std::string(to);
243+
return false;
244+
}
245+
};
246+
247+
static cl::opt<std::string, false, DwarfPrefixParser> fdebugPrefixMap(
248+
"fdebug-prefix-map", cl::ZeroOrMore,
249+
cl::desc("Prefix map for filenames in DWARF debuginfo"),
250+
cl::value_desc("<old>=<new>"));
251+
226252
cl::opt<bool> noAsm("noasm", cl::desc("Disallow use of inline assembler"),
227253
cl::ZeroOrMore);
228254

driver/cl_options.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "llvm/Support/CodeGen.h"
2222
#include "llvm/Support/CommandLine.h"
2323
#include <deque>
24+
#include <map>
2425
#include <vector>
2526

2627
namespace llvm {
@@ -46,6 +47,7 @@ extern cl::list<std::string> runargs;
4647
extern cl::opt<bool> invokedByLDMD;
4748
extern cl::opt<bool> compileOnly;
4849
extern cl::opt<bool> emitDwarfDebugInfo;
50+
extern std::map<std::string, std::string> debugPrefixMap; // Prefix map for filenames in DWARF debuginfo
4951
extern cl::opt<bool> noAsm;
5052
extern cl::opt<bool> dontWriteObj;
5153
extern cl::opt<std::string> objectFile;

gen/dibuilder.cpp

Lines changed: 48 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -218,27 +218,62 @@ void DIBuilder::SetValue(Loc loc, llvm::Value *value,
218218
IR->scopebb());
219219
}
220220

221+
std::string DIBuilder::remapDIPath(llvm::StringRef path) {
222+
for (const auto &[from, to] : opts::debugPrefixMap) {
223+
if (path.startswith(from)) {
224+
return to + path.substr(from.size()).str();
225+
}
226+
}
227+
return std::string(path);
228+
}
229+
221230
DIFile DIBuilder::CreateFile(const char *filename) {
222231
if (!filename)
223232
filename = IR->dmodule->srcfile.toChars();
224233

225-
// clang appears to use the curent working dir as 'directory' for relative
226-
// source paths, and the root path for absolute ones:
227-
// clang -g -emit-llvm -S ..\blub.c =>
228-
// !DIFile(filename: "..\\blub.c", directory: "C:\\LDC\\ninja-ldc", ...)
229-
// !DIFile(filename: "Program
230-
// Files\\LLVM\\lib\\clang\\11.0.1\\include\\stddef.h", directory: "C:\\",
231-
// ...)
232-
233-
if (llvm::sys::path::is_absolute(filename)) {
234-
return DBuilder.createFile(llvm::sys::path::relative_path(filename),
235-
llvm::sys::path::root_path(filename));
236-
}
234+
// Mimic clang's behavior as much as possible, including fdebug-prefix-map
235+
// remap behavior. See LLVM source clang/lib/CodeGen/CGDebugInfo.cpp
236+
237+
auto remappedFile = remapDIPath(filename);
237238

238239
llvm::SmallString<128> cwd;
239240
llvm::sys::fs::current_path(cwd);
241+
auto currentDir = remapDIPath(cwd);
242+
243+
llvm::StringRef debuginfoDir;
244+
llvm::StringRef debuginfoFile;
245+
246+
llvm::SmallString<128> DirBuf;
247+
llvm::SmallString<128> FileBuf;
248+
if (llvm::sys::path::is_absolute(remappedFile)) {
249+
// Strip the common prefix (if it is more than just "/" or "C:\") from
250+
// current directory and filename for a more space-efficient encoding.
251+
auto FileIt = llvm::sys::path::begin(remappedFile);
252+
auto FileE = llvm::sys::path::end(remappedFile);
253+
auto CurDirIt = llvm::sys::path::begin(currentDir);
254+
auto CurDirE = llvm::sys::path::end(currentDir);
255+
for (; CurDirIt != CurDirE && *CurDirIt == *FileIt; ++CurDirIt, ++FileIt)
256+
llvm::sys::path::append(DirBuf, *CurDirIt);
257+
if (llvm::sys::path::root_path(DirBuf) == DirBuf) {
258+
// Don't strip the common prefix if it is only the root ("/" or "C:\")
259+
// since that would make diagnostic locations confusing.
260+
debuginfoDir = {};
261+
debuginfoFile = remappedFile;
262+
} else {
263+
for (; FileIt != FileE; ++FileIt)
264+
llvm::sys::path::append(FileBuf, *FileIt);
265+
debuginfoDir = DirBuf;
266+
debuginfoFile = FileBuf;
267+
}
268+
} else {
269+
if (!llvm::sys::path::is_absolute(filename))
270+
debuginfoDir = currentDir;
271+
debuginfoFile = remappedFile;
272+
}
240273

241-
return DBuilder.createFile(filename, cwd);
274+
// TODO: If debug file creation turns out to cost a lot of time, implement a
275+
// caching mechanism like clang does.
276+
return DBuilder.createFile(debuginfoFile, debuginfoDir);
242277
}
243278

244279
DIFile DIBuilder::CreateFile(Loc loc) {

gen/dibuilder.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ class DIBuilder {
163163
llvm::SmallVector<llvm::Metadata *, 16> &elems);
164164
void AddStaticMembers(AggregateDeclaration *sd, ldc::DIFile file,
165165
llvm::SmallVector<llvm::Metadata *, 16> &elems);
166+
std::string remapDIPath(llvm::StringRef path);
166167
DIFile CreateFile(const char *filename = nullptr);
167168
DIFile CreateFile(Loc loc);
168169
DIFile CreateFile(Dsymbol *decl);
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// RUN: %ldc -g -fdebug-prefix-map=%S=/blablabla -output-ll -of=%t.ll %s
2+
// RUN: FileCheck %s < %t.ll
3+
4+
// CHECK: !DIFile(filename: "/blablabla
5+
6+
void foo()
7+
{
8+
}

0 commit comments

Comments
 (0)