Skip to content
Open
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
26 changes: 26 additions & 0 deletions driver/cl_options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,32 @@ cl::opt<bool> emitDwarfDebugInfo(
"gdwarf", cl::ZeroOrMore,
cl::desc("Emit DWARF debuginfo (instead of CodeView) for MSVC targets"));

// Prefix map for filenames in DWARF debuginfo
std::map<std::string, std::string> debugPrefixMap;

struct DwarfPrefixParser : public cl::parser<std::string> {
explicit DwarfPrefixParser(cl::Option &O) : cl::parser<std::string>(O) {}

bool parse(cl::Option &O, llvm::StringRef /*ArgName*/, llvm::StringRef Arg,
std::string & /*Val*/) {
auto [from, to] = Arg.split('=');
if (from.empty() || to.empty()) {
return O.error("invalid debug prefix map: " + Arg);
}
auto fromStr = std::string(from);
if (debugPrefixMap.find(fromStr) != debugPrefixMap.end()) {
return O.error("debug prefix map already contains: " + fromStr);
}
debugPrefixMap[fromStr] = std::string(to);
return false;
}
};

static cl::opt<std::string, false, DwarfPrefixParser> fdebugPrefixMap(
"fdebug-prefix-map", cl::ZeroOrMore,
cl::desc("Prefix map for filenames in DWARF debuginfo"),
cl::value_desc("<old>=<new>"));

cl::opt<bool> noAsm("noasm", cl::desc("Disallow use of inline assembler"),
cl::ZeroOrMore);

Expand Down
2 changes: 2 additions & 0 deletions driver/cl_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "llvm/Support/CodeGen.h"
#include "llvm/Support/CommandLine.h"
#include <deque>
#include <map>
#include <vector>

namespace llvm {
Expand All @@ -46,6 +47,7 @@ extern cl::list<std::string> runargs;
extern cl::opt<bool> invokedByLDMD;
extern cl::opt<bool> compileOnly;
extern cl::opt<bool> emitDwarfDebugInfo;
extern std::map<std::string, std::string> debugPrefixMap; // Prefix map for filenames in DWARF debuginfo
extern cl::opt<bool> noAsm;
extern cl::opt<bool> dontWriteObj;
extern cl::opt<std::string> objectFile;
Expand Down
69 changes: 56 additions & 13 deletions gen/dibuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -218,27 +218,70 @@ void DIBuilder::SetValue(Loc loc, llvm::Value *value,
IR->scopebb());
}

std::string DIBuilder::remapDIPath(llvm::StringRef path) {
#if LDC_LLVM_VER >= 1800
#define startswith starts_with
#endif

for (const auto &[from, to] : opts::debugPrefixMap) {
if (path.startswith(from)) {
return to + path.substr(from.size()).str();
}
}
return std::string(path);

#if LDC_LLVM_VER >= 1800
#undef startswith
#endif
}

DIFile DIBuilder::CreateFile(const char *filename) {
if (!filename)
filename = IR->dmodule->srcfile.toChars();

// clang appears to use the curent working dir as 'directory' for relative
// source paths, and the root path for absolute ones:
// clang -g -emit-llvm -S ..\blub.c =>
// !DIFile(filename: "..\\blub.c", directory: "C:\\LDC\\ninja-ldc", ...)
// !DIFile(filename: "Program
// Files\\LLVM\\lib\\clang\\11.0.1\\include\\stddef.h", directory: "C:\\",
// ...)

if (llvm::sys::path::is_absolute(filename)) {
return DBuilder.createFile(llvm::sys::path::relative_path(filename),
llvm::sys::path::root_path(filename));
}
// Mimic clang's behavior as much as possible, including fdebug-prefix-map
// remap behavior. See LLVM source clang/lib/CodeGen/CGDebugInfo.cpp

auto remappedFile = remapDIPath(filename);

llvm::SmallString<128> cwd;
llvm::sys::fs::current_path(cwd);
auto currentDir = remapDIPath(cwd);

llvm::StringRef debuginfoDir;
llvm::StringRef debuginfoFile;

llvm::SmallString<128> DirBuf;
llvm::SmallString<128> FileBuf;
if (llvm::sys::path::is_absolute(remappedFile)) {
// Strip the common prefix (if it is more than just "/" or "C:\") from
// current directory and filename for a more space-efficient encoding.
auto FileIt = llvm::sys::path::begin(remappedFile);
auto FileE = llvm::sys::path::end(remappedFile);
auto CurDirIt = llvm::sys::path::begin(currentDir);
auto CurDirE = llvm::sys::path::end(currentDir);
for (; CurDirIt != CurDirE && *CurDirIt == *FileIt; ++CurDirIt, ++FileIt)
llvm::sys::path::append(DirBuf, *CurDirIt);
if (llvm::sys::path::root_path(DirBuf) == DirBuf) {
// Don't strip the common prefix if it is only the root ("/" or "C:\")
// since that would make diagnostic locations confusing.
debuginfoDir = {};
debuginfoFile = remappedFile;
} else {
for (; FileIt != FileE; ++FileIt)
llvm::sys::path::append(FileBuf, *FileIt);
debuginfoDir = DirBuf;
debuginfoFile = FileBuf;
}
} else {
if (!llvm::sys::path::is_absolute(filename))
debuginfoDir = currentDir;
debuginfoFile = remappedFile;
}

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

DIFile DIBuilder::CreateFile(Loc loc) {
Expand Down
1 change: 1 addition & 0 deletions gen/dibuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ class DIBuilder {
llvm::SmallVector<llvm::Metadata *, 16> &elems);
void AddStaticMembers(AggregateDeclaration *sd, ldc::DIFile file,
llvm::SmallVector<llvm::Metadata *, 16> &elems);
std::string remapDIPath(llvm::StringRef path);
DIFile CreateFile(const char *filename = nullptr);
DIFile CreateFile(Loc loc);
DIFile CreateFile(Dsymbol *decl);
Expand Down
8 changes: 8 additions & 0 deletions tests/debuginfo/fdebug_prefix_map.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// RUN: %ldc -g -fdebug-prefix-map=%S=/blablabla -output-ll -of=%t.ll %s
// RUN: FileCheck %s < %t.ll

// CHECK: !DIFile(filename: "/blablabla

void foo()
{
}
Loading