Skip to content

Implement -debug-prefix-map flag. #17665

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jul 25, 2018
Merged
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
4 changes: 4 additions & 0 deletions include/swift/AST/DiagnosticsFrontend.def
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,10 @@ WARNING(cannot_assign_value_to_conditional_compilation_flag,none,
ERROR(error_optimization_remark_pattern, none, "%0 in '%1'",
(StringRef, StringRef))

ERROR(error_invalid_debug_prefix_map, none,
"invalid argument '%0' to -debug-prefix-map; it must be of the form "
"'original=remapped'", (StringRef))

#ifndef DIAG_NO_UNDEF
# if defined(DIAG)
# undef DIAG
Expand Down
4 changes: 4 additions & 0 deletions include/swift/AST/IRGenOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#define SWIFT_AST_IRGENOPTIONS_H

#include "swift/AST/LinkLibrary.h"
#include "swift/Basic/PathRemapper.h"
#include "swift/Basic/Sanitizers.h"
#include "swift/Basic/OptionSet.h"
#include "swift/Basic/OptimizationMode.h"
Expand Down Expand Up @@ -109,6 +110,9 @@ class IRGenOptions {
/// What type of debug info to generate.
IRGenDebugInfoFormat DebugInfoFormat : 2;

/// Path prefixes that should be rewritten in debug info.
PathRemapper DebugPrefixMap;

/// \brief Whether we're generating IR for the JIT.
unsigned UseJIT : 1;

Expand Down
63 changes: 63 additions & 0 deletions include/swift/Basic/PathRemapper.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
//===--- PathRemapper.h - Transforms path prefixes --------------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file defines a data structure that stores a string-to-string
// mapping used to transform file paths based on a prefix mapping. It
// is optimized for the common case, which is that there will be
// extremely few mappings (i.e., one or two).
//
// Remappings are stored such that they are applied in the order they
// are passed on the command line. This would only matter if one
// source mapping was a prefix of another.
//
//===----------------------------------------------------------------------===//

#ifndef SWIFT_BASIC_PATHREMAPPER_H
#define SWIFT_BASIC_PATHREMAPPER_H

#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Twine.h"

#include <string>
#include <utility>

namespace swift {

class PathRemapper {
SmallVector<std::pair<std::string, std::string>, 2> PathMappings;

public:
/// Adds a mapping such that any paths starting with `FromPrefix` have that
/// portion replaced with `ToPrefix`.
void addMapping(StringRef FromPrefix, StringRef ToPrefix) {
PathMappings.emplace_back(FromPrefix, ToPrefix);
}

/// Returns a remapped `Path` if it starts with a prefix in the map; otherwise
/// the original path is returned.
std::string remapPath(StringRef Path) const {
// Clang's implementation of this feature also compares the path string
// directly instead of treating path segments as indivisible units. The
// latter would arguably be more accurate, but we choose to preserve
// compatibility with Clang (especially because we propagate the flag to
// ClangImporter as well).
for (const auto &Mapping : PathMappings)
if (Path.startswith(Mapping.first))
return (Twine(Mapping.second) +
Path.substr(Mapping.first.size())).str();
return Path.str();
}
};

} // end namespace swift

#endif // SWIFT_BASIC_PATHREMAPPER_H
3 changes: 3 additions & 0 deletions include/swift/Option/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,9 @@ def gline_tables_only : Flag<["-"], "gline-tables-only">,
def gdwarf_types : Flag<["-"], "gdwarf-types">,
Group<g_Group>, Flags<[FrontendOption]>,
HelpText<"Emit full DWARF type info.">;
def debug_prefix_map : Separate<["-"], "debug-prefix-map">,
Flags<[FrontendOption]>,
HelpText<"Remap source paths in debug info">;

def debug_info_format : Joined<["-"], "debug-info-format=">,
Flags<[FrontendOption]>,
Expand Down
6 changes: 6 additions & 0 deletions lib/Driver/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,12 @@ static void validateDebugInfoArgs(DiagnosticEngine &diags,
diag::verify_debug_info_requires_debug_option);
}
}

// Check for any -debug-prefix-map options that aren't of the form
// 'original=remapped' (either side can be empty, however).
for (auto A : args.getAllArgValues(options::OPT_debug_prefix_map))
if (A.find('=') == StringRef::npos)
diags.diagnose(SourceLoc(), diag::error_invalid_debug_prefix_map, A);
}

static void validateCompilationConditionArgs(DiagnosticEngine &diags,
Expand Down
3 changes: 3 additions & 0 deletions lib/Driver/ToolChains.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,9 @@ static void addCommonFrontendArgs(const ToolChain &TC, const OutputInfo &OI,
// Pass on any build config options
inputArgs.AddAllArgs(arguments, options::OPT_D);

// Pass on file paths that should be remapped in debug info.
inputArgs.AddAllArgs(arguments, options::OPT_debug_prefix_map);

// Pass through the values passed to -Xfrontend.
inputArgs.AddAllArgValues(arguments, options::OPT_Xfrontend);

Expand Down
15 changes: 15 additions & 0 deletions lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,16 @@ static bool ParseClangImporterArgs(ClangImporterOptions &Opts,
Opts.ExtraArgs.push_back(A->getValue());
}

for (auto A : Args.getAllArgValues(OPT_debug_prefix_map)) {
// Forward -debug-prefix-map arguments from Swift to Clang as
// -fdebug-prefix-map. This is required to ensure DIFiles created there,
// like "<swift-imported-modules>", have their paths remapped properly.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. I feel like I would have missed this. :-)

Note that Clang does not preserve the order of options today; it probably should in the future. At least that's backwards-compatible.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point; I updated the comment to mention the (admittedly rare?) situations where the difference matters.

// (Note, however, that Clang's usage of std::map means that the remapping
// may not be applied in the same order, which can matter if one mapping is
// a prefix of another.)
Opts.ExtraArgs.push_back("-fdebug-prefix-map=" + A);
}

if (!workingDirectory.empty()) {
// Provide a working directory to Clang as well if there are any -Xcc
// options, in case some of them are search-related. But do it at the
Expand Down Expand Up @@ -819,6 +829,11 @@ static bool ParseIRGenArgs(IRGenOptions &Opts, ArgList &Args,
: "-gdwarf_types");
}

for (auto A : Args.getAllArgValues(options::OPT_debug_prefix_map)) {
auto SplitMap = StringRef(A).split('=');
Opts.DebugPrefixMap.addMapping(SplitMap.first, SplitMap.second);
}

for (const Arg *A : Args.filtered(OPT_Xcc)) {
StringRef Opt = A->getValue();
if (Opt.startswith("-D") || Opt.startswith("-U"))
Expand Down
36 changes: 19 additions & 17 deletions lib/IRGen/IRGenDebugInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
SourceManager &SM;
llvm::DIBuilder DBuilder;
IRGenModule &IGM;
const PathRemapper &DebugPrefixMap;

/// Used for caching SILDebugScopes without inline information.
using LocalScopeHash = std::pair<const void *, const void *>;
Expand Down Expand Up @@ -338,7 +339,8 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
StringRef File = llvm::sys::path::filename(Filename);
llvm::SmallString<512> Path(Filename);
llvm::sys::path::remove_filename(Path);
llvm::DIFile *F = DBuilder.createFile(File, Path);
llvm::DIFile *F = DBuilder.createFile(DebugPrefixMap.remapPath(File),
DebugPrefixMap.remapPath(Path));

// Cache it.
DIFileCache[Filename] = llvm::TrackingMDNodeRef(F);
Expand Down Expand Up @@ -540,8 +542,9 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
return cast<llvm::DIModule>(Val->second);

StringRef Sysroot = IGM.Context.SearchPathOpts.SDKPath;
auto M =
DBuilder.createModule(Parent, Name, ConfigMacros, IncludePath, Sysroot);
auto M = DBuilder.createModule(
Parent, Name, ConfigMacros, DebugPrefixMap.remapPath(IncludePath),
Sysroot);
DIModuleCache.insert({Key, llvm::TrackingMDNodeRef(M)});
return M;
}
Expand Down Expand Up @@ -1459,18 +1462,15 @@ IRGenDebugInfoImpl::IRGenDebugInfoImpl(const IRGenOptions &Opts,
llvm::Module &M,
StringRef MainOutputFilenameForDebugInfo)
: Opts(Opts), CI(CI), SM(IGM.Context.SourceMgr), DBuilder(M),
IGM(IGM), MetadataTypeDecl(nullptr), InternalType(nullptr),
LastDebugLoc({}), LastScope(nullptr) {
IGM(IGM), DebugPrefixMap(Opts.DebugPrefixMap), MetadataTypeDecl(nullptr),
InternalType(nullptr), LastDebugLoc({}), LastScope(nullptr) {
assert(Opts.DebugInfoLevel > IRGenDebugInfoLevel::None &&
"no debug info should be generated");
StringRef SourceFileName = MainOutputFilenameForDebugInfo;
llvm::SmallString<256> AbsMainFile;
if (SourceFileName.empty())
AbsMainFile = "<unknown>";
else {
AbsMainFile = SourceFileName;
llvm::sys::fs::make_absolute(AbsMainFile);
}
llvm::SmallString<256> SourcePath;
if (MainOutputFilenameForDebugInfo.empty())
SourcePath = "<unknown>";
else
SourcePath = MainOutputFilenameForDebugInfo;

unsigned Lang = llvm::dwarf::DW_LANG_Swift;
std::string Producer = version::getSwiftFullVersion(
Expand All @@ -1485,12 +1485,14 @@ IRGenDebugInfoImpl::IRGenDebugInfoImpl(const IRGenOptions &Opts,
// Note that File + Dir need not result in a valid path.
// Clang is doing the same thing here.
TheCU = DBuilder.createCompileUnit(
Lang, DBuilder.createFile(AbsMainFile, Opts.DebugCompilationDir),
Lang, DBuilder.createFile(
DebugPrefixMap.remapPath(SourcePath),
DebugPrefixMap.remapPath(Opts.DebugCompilationDir)),
Producer, Opts.shouldOptimize(), Flags, MajorRuntimeVersion, SplitName,
Opts.DebugInfoLevel > IRGenDebugInfoLevel::LineTables
? llvm::DICompileUnit::FullDebug
: llvm::DICompileUnit::LineTablesOnly);
MainFile = getOrCreateFile(BumpAllocatedString(AbsMainFile));
MainFile = getOrCreateFile(BumpAllocatedString(SourcePath));

// Because the swift compiler relies on Clang to setup the Module,
// the clang CU is always created first. Several dwarf-reading
Expand All @@ -1507,8 +1509,8 @@ IRGenDebugInfoImpl::IRGenDebugInfoImpl(const IRGenOptions &Opts,

// Create a module for the current compile unit.
auto *MDecl = IGM.getSwiftModule();
llvm::sys::path::remove_filename(AbsMainFile);
MainModule = getOrCreateModule(MDecl, TheCU, Opts.ModuleName, AbsMainFile);
llvm::sys::path::remove_filename(SourcePath);
MainModule = getOrCreateModule(MDecl, TheCU, Opts.ModuleName, SourcePath);
DBuilder.createImportedModule(MainFile, MainModule, MainFile, 0);

// Macro definitions that were defined by the user with "-Xcc -D" on the
Expand Down
7 changes: 7 additions & 0 deletions test/DebugInfo/debug_prefix_map.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// RUN: %swiftc_driver -g -debug-prefix-map %S=/var/empty %s -emit-ir -o - | %FileCheck %s

func square(_ n: Int) -> Int {
return n * n
}

// CHECK: !DIFile(filename: "/var/empty/debug_prefix_map.swift"
9 changes: 9 additions & 0 deletions test/Driver/debug-prefix-map.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// RUN: not %target-swiftc_driver -debug-prefix-map old %s 2>&1 | %FileCheck %s -check-prefix CHECK-INVALID
// RUN: %target-swiftc_driver -### -debug-prefix-map old=new %s 2>&1 | %FileCheck %s -check-prefix CHECK-SIMPLE
// RUN: %target-swiftc_driver -### -debug-prefix-map old=n=ew %s 2>&1 | %FileCheck %s -check-prefix CHECK-COMPLEX
// RUN: %target-swiftc_driver -### -debug-prefix-map old= %s 2>&1 | %FileCheck %s -check-prefix CHECK-EMPTY

// CHECK-INVALID: error: invalid argument 'old' to -debug-prefix-map
// CHECK-SIMPLE: debug-prefix-map old=new
// CHECK-COMPLEX: debug-prefix-map old=n=ew
// CHECK-EMPTY: debug-prefix-map old=