Skip to content

pass -fno-omit-frame-pointer in support of new backtracer #7042

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 4 commits into from
Nov 1, 2023
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
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,17 @@ public final class ClangTargetBuildDescription {
args += ["-flto=thin"]
}

// rdar://117578677
// Pass -fno-omit-frame-pointer to support backtraces
// this can be removed once the backtracer uses DWARF instead of frame pointers
if let omitFramePointers = self.buildParameters.debuggingParameters.omitFramePointers {
if omitFramePointers {
args += ["-fomit-frame-pointer"]
} else {
args += ["-fno-omit-frame-pointer"]
}
}

// Pass default include paths from the toolchain.
for includeSearchPath in self.buildParameters.toolchain.includeSearchPaths {
args += ["-I", includeSearchPath.pathString]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,17 @@ public final class SwiftTargetBuildDescription {

args += self.packageNameArgumentIfSupported(with: self.package, packageAccess: self.target.packageAccess)
args += try self.macroArguments()

// rdar://117578677
// Pass -fno-omit-frame-pointer to support backtraces
// this can be removed once the backtracer uses DWARF instead of frame pointers
if let omitFramePointers = self.buildParameters.debuggingParameters.omitFramePointers {
if omitFramePointers {
args += ["-Xcc", "-fomit-frame-pointer"]
} else {
args += ["-Xcc", "-fno-omit-frame-pointer"]
}
}

return args
}
Expand Down
5 changes: 5 additions & 0 deletions Sources/CoreCommands/Options.swift
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,11 @@ public struct BuildOptions: ParsableArguments {
@Flag(inversion: .prefixedEnableDisable, help: .hidden)
public var getTaskAllowEntitlement: Bool? = nil

// Whether to omit frame pointers
// this can be removed once the backtracer uses DWARF instead of frame pointers
@Flag(inversion: .prefixedNo, help: .hidden)
public var omitFramePointers: Bool? = nil

// @Flag works best when there is a default value present
// if true, false aren't enough and a third state is needed
// nil should not be the goto. Instead create an enum
Expand Down
3 changes: 2 additions & 1 deletion Sources/CoreCommands/SwiftTool.swift
Original file line number Diff line number Diff line change
Expand Up @@ -703,7 +703,8 @@ public final class SwiftTool {
debugInfoFormat: options.build.debugInfoFormat.buildParameter,
targetTriple: targetTriple,
shouldEnableDebuggingEntitlement:
options.build.getTaskAllowEntitlement ?? (options.build.configuration == .debug)
options.build.getTaskAllowEntitlement ?? (options.build.configuration == .debug),
omitFramePointers: options.build.omitFramePointers
),
driverParameters: .init(
canRenameEntrypointFunctionName: driverSupport.checkSupportedFrontendFlags(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,36 @@ extension BuildParameters {
public init(
debugInfoFormat: DebugInfoFormat = .dwarf,
targetTriple: Triple,
shouldEnableDebuggingEntitlement: Bool
shouldEnableDebuggingEntitlement: Bool,
omitFramePointers: Bool?
) {
self.debugInfoFormat = debugInfoFormat

// Per rdar://112065568 for backtraces to work on macOS a special entitlement needs to be granted on the final
// executable.
self.shouldEnableDebuggingEntitlement = targetTriple.isMacOSX && shouldEnableDebuggingEntitlement
// rdar://117578677: frame-pointer to support backtraces
// this can be removed once the backtracer uses DWARF instead of frame pointers
if let omitFramePointers {
// if set, we respect user's preference
self.omitFramePointers = omitFramePointers
} else if targetTriple.isLinux() {
// on Linux we preserve frame pointers by default
self.omitFramePointers = false
} else {
// otherwise, use the platform default
self.omitFramePointers = nil
}
}

public var debugInfoFormat: DebugInfoFormat

/// Whether the produced executable should be codesigned with the debugging entitlement, enabling enhanced
/// backtraces on macOS.
public var shouldEnableDebuggingEntitlement: Bool

/// Whether to omit frame pointers
public var omitFramePointers: Bool?
}

/// Represents the debugging strategy.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,8 @@ public struct BuildParameters: Encodable {
let targetTriple = try targetTriple ?? .getHostTriple(usingSwiftCompiler: toolchain.swiftCompilerPath)
self.debuggingParameters = debuggingParameters ?? .init(
targetTriple: targetTriple,
shouldEnableDebuggingEntitlement: configuration == .debug
shouldEnableDebuggingEntitlement: configuration == .debug,
omitFramePointers: nil
)

self.dataPath = dataPath
Expand Down
87 changes: 82 additions & 5 deletions Tests/BuildTests/BuildPlanTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1189,6 +1189,10 @@ final class BuildPlanTests: XCTestCase {
#endif

args += [hostTriple.isWindows() ? "-gdwarf" : "-g"]

if hostTriple.isLinux() {
args += ["-fno-omit-frame-pointer"]
}

XCTAssertEqual(try ext.basicArguments(isCXX: false), args)
XCTAssertEqual(try ext.objects, [buildPath.appending(components: "extlib.build", "extlib.c.o")])
Expand Down Expand Up @@ -1219,6 +1223,11 @@ final class BuildPlanTests: XCTestCase {
args += ["-fmodules-cache-path=\(buildPath.appending(components: "ModuleCache"))"]
#endif
args += [hostTriple.isWindows() ? "-gdwarf" : "-g"]

if hostTriple.isLinux() {
args += ["-fno-omit-frame-pointer"]
}

XCTAssertEqual(try exe.basicArguments(isCXX: false), args)
XCTAssertEqual(try exe.objects, [buildPath.appending(components: "exe.build", "main.c.o")])
XCTAssertEqual(exe.moduleMap, nil)
Expand Down Expand Up @@ -1514,6 +1523,11 @@ final class BuildPlanTests: XCTestCase {
args += ["-fmodules-cache-path=\(buildPath.appending(components: "ModuleCache"))"]
#endif
args += [hostTriple.isWindows() ? "-gdwarf" : "-g"]

if hostTriple.isLinux() {
args += ["-fno-omit-frame-pointer"]
}

XCTAssertEqual(try lib.basicArguments(isCXX: false), args)
XCTAssertEqual(try lib.objects, [buildPath.appending(components: "lib.build", "lib.c.o")])
XCTAssertEqual(lib.moduleMap, buildPath.appending(components: "lib.build", "module.modulemap"))
Expand Down Expand Up @@ -2509,6 +2523,11 @@ final class BuildPlanTests: XCTestCase {
#endif

expectedExeBasicArgs += [triple.isWindows() ? "-gdwarf" : "-g"]

if triple.isLinux() {
expectedExeBasicArgs += ["-fno-omit-frame-pointer"]
}

XCTAssertEqual(try exe.basicArguments(isCXX: false), expectedExeBasicArgs)
XCTAssertEqual(try exe.objects, [buildPath.appending(components: "exe.build", "main.c.o")])
XCTAssertEqual(exe.moduleMap, nil)
Expand All @@ -2530,6 +2549,11 @@ final class BuildPlanTests: XCTestCase {
triple.isWindows() ? "-gdwarf" : "-g",
triple.isWindows() ? "-gdwarf" : "-g",
]

if triple.isLinux() {
expectedLibBasicArgs += ["-fno-omit-frame-pointer"]
}

XCTAssertEqual(try lib.basicArguments(isCXX: true), expectedLibBasicArgs)

XCTAssertEqual(try lib.objects, [buildPath.appending(components: "lib.build", "lib.cpp.o")])
Expand Down Expand Up @@ -3059,7 +3083,7 @@ final class BuildPlanTests: XCTestCase {
"-fblocks", "-fmodules", "-fmodule-name=lib",
"-I", Pkg.appending(components: "Sources", "lib", "include").pathString,
"-fmodules-cache-path=\(buildPath.appending(components: "ModuleCache"))",
"-g",
"-g"
Copy link
Member

Choose a reason for hiding this comment

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

Why remove the trailing ,? It is convenient.

]
XCTAssertEqual(try lib.basicArguments(isCXX: false), args)
XCTAssertEqual(try lib.objects, [buildPath.appending(components: "lib.build", "lib.c.o")])
Expand Down Expand Up @@ -3136,7 +3160,10 @@ final class BuildPlanTests: XCTestCase {

func createResult(for triple: Basics.Triple) throws -> BuildPlanResult {
try BuildPlanResult(plan: BuildPlan(
buildParameters: mockBuildParameters(canRenameEntrypointFunctionName: true, targetTriple: triple),
buildParameters: mockBuildParameters(
canRenameEntrypointFunctionName: true,
targetTriple: triple
),
graph: graph,
fileSystem: fs,
observabilityScope: observability.topScope
Expand Down Expand Up @@ -3511,18 +3538,68 @@ final class BuildPlanTests: XCTestCase {
XCTAssertMatch(dep, [.anySequence, "-DDEP", .anySequence])

let cbar = try result.target(for: "cbar").clangTarget().basicArguments(isCXX: false)
XCTAssertMatch(cbar, [.anySequence, "-DCCC=2", "-I\(A.appending(components: "Sources", "cbar", "Sources", "headers"))", "-I\(A.appending(components: "Sources", "cbar", "Sources", "cppheaders"))", "-Icfoo", "-L", "cbar", "-Icxxfoo", "-L", "cxxbar", "-g", .end])
XCTAssertMatch(cbar, [.anySequence, "-DCCC=2", "-I\(A.appending(components: "Sources", "cbar", "Sources", "headers"))", "-I\(A.appending(components: "Sources", "cbar", "Sources", "cppheaders"))", "-Icfoo", "-L", "cbar", "-Icxxfoo", "-L", "cxxbar", "-g", "-fno-omit-frame-pointer", .end])
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this correct?

Copy link
Contributor Author

@tomerd tomerd Nov 1, 2023

Choose a reason for hiding this comment

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

i think so, why not?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

for reference this is for .x86_64Linux


let bar = try result.target(for: "bar").swiftTarget().compileArguments()
XCTAssertMatch(bar, [.anySequence, "-DLINUX", "-Isfoo", "-L", "sbar", "-cxx-interoperability-mode=default", "-enable-upcoming-feature", "BestFeature", "-g", "-Xcc", "-g", .end])
XCTAssertMatch(bar, [.anySequence, "-DLINUX", "-Isfoo", "-L", "sbar", "-cxx-interoperability-mode=default", "-enable-upcoming-feature", "BestFeature", "-g", "-Xcc", "-g", "-Xcc", "-fno-omit-frame-pointer", .end])

let exe = try result.target(for: "exe").swiftTarget().compileArguments()
XCTAssertMatch(exe, [.anySequence, "-DFOO", "-g", "-Xcc", "-g", .end])
XCTAssertMatch(exe, [.anySequence, "-DFOO", "-g", "-Xcc", "-g", "-Xcc", "-fno-omit-frame-pointer", .end])

let linkExe = try result.buildProduct(for: "exe").linkArguments()
XCTAssertMatch(linkExe, [.anySequence, "-lsqlite3", "-llibz", "-Ilfoo", "-L", "lbar", "-g", .end])
}

// omit frame pointers explicitly set to true
do {
let result = try BuildPlanResult(plan: BuildPlan(
buildParameters: mockBuildParameters(
targetTriple: .x86_64Linux,
omitFramePointers: true
),
graph: graph,
fileSystem: fs,
observabilityScope: observability.topScope
))

let dep = try result.target(for: "t1").swiftTarget().compileArguments()
XCTAssertMatch(dep, [.anySequence, "-DDEP", .anySequence])

let cbar = try result.target(for: "cbar").clangTarget().basicArguments(isCXX: false)
XCTAssertMatch(cbar, [.anySequence, "-DCCC=2", "-I\(A.appending(components: "Sources", "cbar", "Sources", "headers"))", "-I\(A.appending(components: "Sources", "cbar", "Sources", "cppheaders"))", "-Icfoo", "-L", "cbar", "-Icxxfoo", "-L", "cxxbar", "-g", "-fomit-frame-pointer", .end])

let bar = try result.target(for: "bar").swiftTarget().compileArguments()
XCTAssertMatch(bar, [.anySequence, "-DLINUX", "-Isfoo", "-L", "sbar", "-cxx-interoperability-mode=default", "-enable-upcoming-feature", "BestFeature", "-g", "-Xcc", "-g", "-Xcc", "-fomit-frame-pointer", .end])

let exe = try result.target(for: "exe").swiftTarget().compileArguments()
XCTAssertMatch(exe, [.anySequence, "-DFOO", "-g", "-Xcc", "-g", "-Xcc", "-fomit-frame-pointer", .end])
}

// omit frame pointers explicitly set to false
do {
let result = try BuildPlanResult(plan: BuildPlan(
buildParameters: mockBuildParameters(
targetTriple: .x86_64Linux,
omitFramePointers: false
),
graph: graph,
fileSystem: fs,
observabilityScope: observability.topScope
))

let dep = try result.target(for: "t1").swiftTarget().compileArguments()
XCTAssertMatch(dep, [.anySequence, "-DDEP", .anySequence])

let cbar = try result.target(for: "cbar").clangTarget().basicArguments(isCXX: false)
XCTAssertMatch(cbar, [.anySequence, "-DCCC=2", "-I\(A.appending(components: "Sources", "cbar", "Sources", "headers"))", "-I\(A.appending(components: "Sources", "cbar", "Sources", "cppheaders"))", "-Icfoo", "-L", "cbar", "-Icxxfoo", "-L", "cxxbar", "-g", "-fno-omit-frame-pointer", .end])

let bar = try result.target(for: "bar").swiftTarget().compileArguments()
XCTAssertMatch(bar, [.anySequence, "-DLINUX", "-Isfoo", "-L", "sbar", "-cxx-interoperability-mode=default", "-enable-upcoming-feature", "BestFeature", "-g", "-Xcc", "-g", "-Xcc", "-fno-omit-frame-pointer", .end])

let exe = try result.target(for: "exe").swiftTarget().compileArguments()
XCTAssertMatch(exe, [.anySequence, "-DFOO", "-g", "-Xcc", "-g", "-Xcc", "-fno-omit-frame-pointer", .end])
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Not sure I like that we're making these tests even more unmaintainable by copy-pasting two extra times, but I guess it's fine...


do {
let result = try createResult(for: .x86_64MacOS)

Expand Down
8 changes: 7 additions & 1 deletion Tests/BuildTests/MockBuildTestHelper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ func mockBuildParameters(
indexStoreMode: BuildParameters.IndexStoreMode = .off,
useExplicitModuleBuild: Bool = false,
linkerDeadStrip: Bool = true,
linkTimeOptimizationMode: BuildParameters.LinkTimeOptimizationMode? = nil
linkTimeOptimizationMode: BuildParameters.LinkTimeOptimizationMode? = nil,
omitFramePointers: Bool? = nil
) -> BuildParameters {
return try! BuildParameters(
dataPath: buildPath,
Expand All @@ -90,6 +91,11 @@ func mockBuildParameters(
pkgConfigDirectories: [],
workers: 3,
indexStoreMode: indexStoreMode,
debuggingParameters: .init(
targetTriple: targetTriple,
shouldEnableDebuggingEntitlement: config == .debug,
omitFramePointers: omitFramePointers
),
driverParameters: .init(
canRenameEntrypointFunctionName: canRenameEntrypointFunctionName,
useExplicitModuleBuild: useExplicitModuleBuild
Expand Down