Skip to content

[Backtracing] Add an option to output to stderr. #64639

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 1 commit into from
May 24, 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
4 changes: 4 additions & 0 deletions docs/Backtracing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,10 @@ follows:
| | | only has effect on platforms that have a symbol |
| | | cache that can be controlled by the runtime. |
+-----------------+---------+--------------------------------------------------+
| output-to | stdout | Set to ``stderr`` to send the backtrace to the |
| | | standard error instead of standard output. This |
| | | may be useful in some CI systems. |
+-----------------+---------+--------------------------------------------------+
| swift-backtrace | | If specified, gives the full path to the |
| | | swift-backtrace binary to use for crashes. |
| | | Otherwise, Swift will locate the binary relative |
Expand Down
6 changes: 6 additions & 0 deletions include/swift/Runtime/Backtrace.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ enum class SanitizePaths {
On = 1
};

enum class OutputTo {
Stdout = 0,
Stderr = 2,
};

struct BacktraceSettings {
UnwindAlgorithm algorithm;
OnOffTty enabled;
Expand All @@ -112,6 +117,7 @@ struct BacktraceSettings {
SanitizePaths sanitize;
Preset preset;
bool cache;
OutputTo outputTo;
const char *swiftBacktracePath;
};

Expand Down
29 changes: 18 additions & 11 deletions stdlib/public/libexec/swift-backtrace/Target.swift
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ class Target {
do {
crashInfo = try reader.fetch(from: crashInfoAddr, as: CrashInfo.self)
} catch {
print("swift-backtrace: unable to fetch crash info.")
print("swift-backtrace: unable to fetch crash info.", to: &standardError)
exit(1)
}

Expand All @@ -175,7 +175,7 @@ class Target {

guard let mctx: MContext = try? reader.fetch(from: crashInfo.mctx,
as: MContext.self) else {
print("swift-backtrace: unable to fetch mcontext.")
print("swift-backtrace: unable to fetch mcontext.", to: &standardError)
exit(1)
}

Expand All @@ -195,12 +195,13 @@ class Target {
&threadCount)

if kr != KERN_SUCCESS {
print("swift-backtrace: failed to enumerate threads - \(kr)")
print("swift-backtrace: failed to enumerate threads - \(kr)",
to: &standardError)
exit(1)
}

guard let ports = threadPorts else {
print("swift-backtrace: thread array is nil")
print("swift-backtrace: thread array is nil", to: &standardError)
exit(1)
}

Expand All @@ -209,12 +210,13 @@ class Target {
var kr = mach_thread_info(ports[Int(ndx)], THREAD_IDENTIFIER_INFO,
&threadIdInfo)
if kr != KERN_SUCCESS {
print("swift-backtrace: unable to get thread info for thread \(ndx) - \(kr)")
print("swift-backtrace: unable to get thread info for thread \(ndx) - \(kr)",
to: &standardError)
exit(1)
}

guard let info = threadIdInfo else {
print("swift-backtrace: thread info is nil")
print("swift-backtrace: thread info is nil", to: &standardError)
exit(1)
}

Expand All @@ -228,7 +230,8 @@ class Target {
if kr == KERN_SUCCESS {
threadName = extInfo.pth_swiftName
} else {
print("unable to fetch ext info \(kr)")
print("swift-backtrace: unable to fetch ext info \(kr)",
to: &standardError)
threadName = ""
}

Expand All @@ -250,14 +253,16 @@ class Target {
using: reader,
limit: limit,
top: top) else {
print("unable to capture backtrace from context for thread \(ndx)")
print("swift-backtrace: unable to capture backtrace from context for thread \(ndx)",
to: &standardError)
exit(1)
}

guard let symbolicated = backtrace.symbolicated(with: images,
sharedCacheInfo: sharedCacheInfo,
useSymbolCache: cache) else {
print("unable to symbolicate backtrace from context for thread \(ndx)")
print("unable to symbolicate backtrace from context for thread \(ndx)",
to: &standardError)
exit(1)
}

Expand All @@ -280,14 +285,16 @@ class Target {
using: reader,
limit: limit,
top: top) else {
print("unable to capture backtrace from context for thread \(ndx)")
print("swift-backtrace: unable to capture backtrace from context for thread \(ndx)",
to: &standardError)
continue
}

guard let symbolicated = backtrace.symbolicated(with: images,
sharedCacheInfo: sharedCacheInfo,
useSymbolCache: cache) else {
print("unable to symbolicate backtrace from context for thread \(ndx)")
print("swift-backtrace: unable to symbolicate backtrace from context for thread \(ndx)",
to: &standardError)
continue
}

Expand Down
15 changes: 15 additions & 0 deletions stdlib/public/libexec/swift-backtrace/Utils.swift
Original file line number Diff line number Diff line change
Expand Up @@ -139,4 +139,19 @@ internal func spawn(_ path: String, args: [String]) throws {
}
}

struct CFileStream: TextOutputStream {
var fp: UnsafeMutablePointer<FILE>

public func write(_ string: String) {
fputs(string, fp)
}

public func flush() {
fflush(fp)
}
}

var standardOutput = CFileStream(fp: stdout)
var standardError = CFileStream(fp: stderr)

#endif // os(macOS)
Loading