Skip to content

Commit de30596

Browse files
authored
Merge pull request #17665 from allevato/debug-prefix-map-wip
Implement -debug-prefix-map flag.
2 parents d684dac + aade5fb commit de30596

File tree

10 files changed

+133
-17
lines changed

10 files changed

+133
-17
lines changed

include/swift/AST/DiagnosticsFrontend.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,10 @@ WARNING(cannot_assign_value_to_conditional_compilation_flag,none,
246246
ERROR(error_optimization_remark_pattern, none, "%0 in '%1'",
247247
(StringRef, StringRef))
248248

249+
ERROR(error_invalid_debug_prefix_map, none,
250+
"invalid argument '%0' to -debug-prefix-map; it must be of the form "
251+
"'original=remapped'", (StringRef))
252+
249253
#ifndef DIAG_NO_UNDEF
250254
# if defined(DIAG)
251255
# undef DIAG

include/swift/AST/IRGenOptions.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#define SWIFT_AST_IRGENOPTIONS_H
2020

2121
#include "swift/AST/LinkLibrary.h"
22+
#include "swift/Basic/PathRemapper.h"
2223
#include "swift/Basic/Sanitizers.h"
2324
#include "swift/Basic/OptionSet.h"
2425
#include "swift/Basic/OptimizationMode.h"
@@ -109,6 +110,9 @@ class IRGenOptions {
109110
/// What type of debug info to generate.
110111
IRGenDebugInfoFormat DebugInfoFormat : 2;
111112

113+
/// Path prefixes that should be rewritten in debug info.
114+
PathRemapper DebugPrefixMap;
115+
112116
/// \brief Whether we're generating IR for the JIT.
113117
unsigned UseJIT : 1;
114118

include/swift/Basic/PathRemapper.h

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
//===--- PathRemapper.h - Transforms path prefixes --------------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// This file defines a data structure that stores a string-to-string
14+
// mapping used to transform file paths based on a prefix mapping. It
15+
// is optimized for the common case, which is that there will be
16+
// extremely few mappings (i.e., one or two).
17+
//
18+
// Remappings are stored such that they are applied in the order they
19+
// are passed on the command line. This would only matter if one
20+
// source mapping was a prefix of another.
21+
//
22+
//===----------------------------------------------------------------------===//
23+
24+
#ifndef SWIFT_BASIC_PATHREMAPPER_H
25+
#define SWIFT_BASIC_PATHREMAPPER_H
26+
27+
#include "llvm/ADT/SmallVector.h"
28+
#include "llvm/ADT/Twine.h"
29+
30+
#include <string>
31+
#include <utility>
32+
33+
namespace swift {
34+
35+
class PathRemapper {
36+
SmallVector<std::pair<std::string, std::string>, 2> PathMappings;
37+
38+
public:
39+
/// Adds a mapping such that any paths starting with `FromPrefix` have that
40+
/// portion replaced with `ToPrefix`.
41+
void addMapping(StringRef FromPrefix, StringRef ToPrefix) {
42+
PathMappings.emplace_back(FromPrefix, ToPrefix);
43+
}
44+
45+
/// Returns a remapped `Path` if it starts with a prefix in the map; otherwise
46+
/// the original path is returned.
47+
std::string remapPath(StringRef Path) const {
48+
// Clang's implementation of this feature also compares the path string
49+
// directly instead of treating path segments as indivisible units. The
50+
// latter would arguably be more accurate, but we choose to preserve
51+
// compatibility with Clang (especially because we propagate the flag to
52+
// ClangImporter as well).
53+
for (const auto &Mapping : PathMappings)
54+
if (Path.startswith(Mapping.first))
55+
return (Twine(Mapping.second) +
56+
Path.substr(Mapping.first.size())).str();
57+
return Path.str();
58+
}
59+
};
60+
61+
} // end namespace swift
62+
63+
#endif // SWIFT_BASIC_PATHREMAPPER_H

include/swift/Option/Options.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,9 @@ def gline_tables_only : Flag<["-"], "gline-tables-only">,
468468
def gdwarf_types : Flag<["-"], "gdwarf-types">,
469469
Group<g_Group>, Flags<[FrontendOption]>,
470470
HelpText<"Emit full DWARF type info.">;
471+
def debug_prefix_map : Separate<["-"], "debug-prefix-map">,
472+
Flags<[FrontendOption]>,
473+
HelpText<"Remap source paths in debug info">;
471474

472475
def debug_info_format : Joined<["-"], "debug-info-format=">,
473476
Flags<[FrontendOption]>,

lib/Driver/Driver.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,12 @@ static void validateDebugInfoArgs(DiagnosticEngine &diags,
198198
diag::verify_debug_info_requires_debug_option);
199199
}
200200
}
201+
202+
// Check for any -debug-prefix-map options that aren't of the form
203+
// 'original=remapped' (either side can be empty, however).
204+
for (auto A : args.getAllArgValues(options::OPT_debug_prefix_map))
205+
if (A.find('=') == StringRef::npos)
206+
diags.diagnose(SourceLoc(), diag::error_invalid_debug_prefix_map, A);
201207
}
202208

203209
static void validateCompilationConditionArgs(DiagnosticEngine &diags,

lib/Driver/ToolChains.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,9 @@ static void addCommonFrontendArgs(const ToolChain &TC, const OutputInfo &OI,
220220
// Pass on any build config options
221221
inputArgs.AddAllArgs(arguments, options::OPT_D);
222222

223+
// Pass on file paths that should be remapped in debug info.
224+
inputArgs.AddAllArgs(arguments, options::OPT_debug_prefix_map);
225+
223226
// Pass through the values passed to -Xfrontend.
224227
inputArgs.AddAllArgValues(arguments, options::OPT_Xfrontend);
225228

lib/Frontend/CompilerInvocation.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,16 @@ static bool ParseClangImporterArgs(ClangImporterOptions &Opts,
393393
Opts.ExtraArgs.push_back(A->getValue());
394394
}
395395

396+
for (auto A : Args.getAllArgValues(OPT_debug_prefix_map)) {
397+
// Forward -debug-prefix-map arguments from Swift to Clang as
398+
// -fdebug-prefix-map. This is required to ensure DIFiles created there,
399+
// like "<swift-imported-modules>", have their paths remapped properly.
400+
// (Note, however, that Clang's usage of std::map means that the remapping
401+
// may not be applied in the same order, which can matter if one mapping is
402+
// a prefix of another.)
403+
Opts.ExtraArgs.push_back("-fdebug-prefix-map=" + A);
404+
}
405+
396406
if (!workingDirectory.empty()) {
397407
// Provide a working directory to Clang as well if there are any -Xcc
398408
// options, in case some of them are search-related. But do it at the
@@ -819,6 +829,11 @@ static bool ParseIRGenArgs(IRGenOptions &Opts, ArgList &Args,
819829
: "-gdwarf_types");
820830
}
821831

832+
for (auto A : Args.getAllArgValues(options::OPT_debug_prefix_map)) {
833+
auto SplitMap = StringRef(A).split('=');
834+
Opts.DebugPrefixMap.addMapping(SplitMap.first, SplitMap.second);
835+
}
836+
822837
for (const Arg *A : Args.filtered(OPT_Xcc)) {
823838
StringRef Opt = A->getValue();
824839
if (Opt.startswith("-D") || Opt.startswith("-U"))

lib/IRGen/IRGenDebugInfo.cpp

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
6969
SourceManager &SM;
7070
llvm::DIBuilder DBuilder;
7171
IRGenModule &IGM;
72+
const PathRemapper &DebugPrefixMap;
7273

7374
/// Used for caching SILDebugScopes without inline information.
7475
using LocalScopeHash = std::pair<const void *, const void *>;
@@ -351,7 +352,8 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
351352
StringRef File = llvm::sys::path::filename(Filename);
352353
llvm::SmallString<512> Path(Filename);
353354
llvm::sys::path::remove_filename(Path);
354-
llvm::DIFile *F = DBuilder.createFile(File, Path);
355+
llvm::DIFile *F = DBuilder.createFile(DebugPrefixMap.remapPath(File),
356+
DebugPrefixMap.remapPath(Path));
355357

356358
// Cache it.
357359
DIFileCache[Filename] = llvm::TrackingMDNodeRef(F);
@@ -559,8 +561,9 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
559561
return cast<llvm::DIModule>(Val->second);
560562

561563
StringRef Sysroot = IGM.Context.SearchPathOpts.SDKPath;
562-
auto M =
563-
DBuilder.createModule(Parent, Name, ConfigMacros, IncludePath, Sysroot);
564+
auto M = DBuilder.createModule(
565+
Parent, Name, ConfigMacros, DebugPrefixMap.remapPath(IncludePath),
566+
Sysroot);
564567
DIModuleCache.insert({Key, llvm::TrackingMDNodeRef(M)});
565568
return M;
566569
}
@@ -1480,18 +1483,15 @@ IRGenDebugInfoImpl::IRGenDebugInfoImpl(const IRGenOptions &Opts,
14801483
llvm::Module &M,
14811484
StringRef MainOutputFilenameForDebugInfo)
14821485
: Opts(Opts), CI(CI), SM(IGM.Context.SourceMgr), DBuilder(M),
1483-
IGM(IGM), MetadataTypeDecl(nullptr), InternalType(nullptr),
1484-
LastDebugLoc({}), LastScope(nullptr) {
1486+
IGM(IGM), DebugPrefixMap(Opts.DebugPrefixMap), MetadataTypeDecl(nullptr),
1487+
InternalType(nullptr), LastDebugLoc({}), LastScope(nullptr) {
14851488
assert(Opts.DebugInfoLevel > IRGenDebugInfoLevel::None &&
14861489
"no debug info should be generated");
1487-
StringRef SourceFileName = MainOutputFilenameForDebugInfo;
1488-
llvm::SmallString<256> AbsMainFile;
1489-
if (SourceFileName.empty())
1490-
AbsMainFile = "<unknown>";
1491-
else {
1492-
AbsMainFile = SourceFileName;
1493-
llvm::sys::fs::make_absolute(AbsMainFile);
1494-
}
1490+
llvm::SmallString<256> SourcePath;
1491+
if (MainOutputFilenameForDebugInfo.empty())
1492+
SourcePath = "<unknown>";
1493+
else
1494+
SourcePath = MainOutputFilenameForDebugInfo;
14951495

14961496
unsigned Lang = llvm::dwarf::DW_LANG_Swift;
14971497
std::string Producer = version::getSwiftFullVersion(
@@ -1506,12 +1506,14 @@ IRGenDebugInfoImpl::IRGenDebugInfoImpl(const IRGenOptions &Opts,
15061506
// Note that File + Dir need not result in a valid path.
15071507
// Clang is doing the same thing here.
15081508
TheCU = DBuilder.createCompileUnit(
1509-
Lang, DBuilder.createFile(AbsMainFile, Opts.DebugCompilationDir),
1509+
Lang, DBuilder.createFile(
1510+
DebugPrefixMap.remapPath(SourcePath),
1511+
DebugPrefixMap.remapPath(Opts.DebugCompilationDir)),
15101512
Producer, Opts.shouldOptimize(), Flags, MajorRuntimeVersion, SplitName,
15111513
Opts.DebugInfoLevel > IRGenDebugInfoLevel::LineTables
15121514
? llvm::DICompileUnit::FullDebug
15131515
: llvm::DICompileUnit::LineTablesOnly);
1514-
MainFile = getOrCreateFile(BumpAllocatedString(AbsMainFile));
1516+
MainFile = getOrCreateFile(BumpAllocatedString(SourcePath));
15151517

15161518
// Because the swift compiler relies on Clang to setup the Module,
15171519
// the clang CU is always created first. Several dwarf-reading
@@ -1528,8 +1530,8 @@ IRGenDebugInfoImpl::IRGenDebugInfoImpl(const IRGenOptions &Opts,
15281530

15291531
// Create a module for the current compile unit.
15301532
auto *MDecl = IGM.getSwiftModule();
1531-
llvm::sys::path::remove_filename(AbsMainFile);
1532-
MainModule = getOrCreateModule(MDecl, TheCU, Opts.ModuleName, AbsMainFile);
1533+
llvm::sys::path::remove_filename(SourcePath);
1534+
MainModule = getOrCreateModule(MDecl, TheCU, Opts.ModuleName, SourcePath);
15331535
DBuilder.createImportedModule(MainFile, MainModule, MainFile, 0);
15341536

15351537
// Macro definitions that were defined by the user with "-Xcc -D" on the

test/DebugInfo/debug_prefix_map.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// RUN: %swiftc_driver -g -debug-prefix-map %S=/var/empty %s -emit-ir -o - | %FileCheck %s
2+
3+
func square(_ n: Int) -> Int {
4+
return n * n
5+
}
6+
7+
// CHECK: !DIFile(filename: "/var/empty/debug_prefix_map.swift"

test/Driver/debug-prefix-map.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// RUN: not %target-swiftc_driver -debug-prefix-map old %s 2>&1 | %FileCheck %s -check-prefix CHECK-INVALID
2+
// RUN: %target-swiftc_driver -### -debug-prefix-map old=new %s 2>&1 | %FileCheck %s -check-prefix CHECK-SIMPLE
3+
// RUN: %target-swiftc_driver -### -debug-prefix-map old=n=ew %s 2>&1 | %FileCheck %s -check-prefix CHECK-COMPLEX
4+
// RUN: %target-swiftc_driver -### -debug-prefix-map old= %s 2>&1 | %FileCheck %s -check-prefix CHECK-EMPTY
5+
6+
// CHECK-INVALID: error: invalid argument 'old' to -debug-prefix-map
7+
// CHECK-SIMPLE: debug-prefix-map old=new
8+
// CHECK-COMPLEX: debug-prefix-map old=n=ew
9+
// CHECK-EMPTY: debug-prefix-map old=

0 commit comments

Comments
 (0)