Skip to content

Commit 9d2dcb5

Browse files
authored
Merge pull request #71386 from al45tair/eng/PR-122302117
[Runtime] Add an option to produce non-symbolicated backtraces.
2 parents 2c77947 + dd0b826 commit 9d2dcb5

File tree

12 files changed

+458
-124
lines changed

12 files changed

+458
-124
lines changed

docs/Backtracing.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,10 @@ follows:
9696
| | | standard error instead of standard output. This |
9797
| | | may be useful in some CI systems. |
9898
+-----------------+---------+--------------------------------------------------+
99+
| symbolicate | full | Options are ``full``, ``fast``, or ``off``. |
100+
| | | Full means to look up source locations and |
101+
| | | inline frames. Fast just does symbol lookup. |
102+
+-----------------+---------+--------------------------------------------------+
99103
| swift-backtrace | | If specified, gives the full path to the |
100104
| | | swift-backtrace binary to use for crashes. |
101105
| | | Otherwise, Swift will locate the binary relative |

docs/contents.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ Contents
66
.. toctree::
77
:maxdepth: 1
88

9+
Backtracing
910
Generics
1011
StoredAndComputedVariables
1112
SIL

stdlib/public/Backtracing/Backtrace.swift

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -613,20 +613,27 @@ public struct Backtrace: CustomStringConvertible, Sendable {
613613
/// running on, add virtual frames to show inline
614614
/// function calls.
615615
///
616+
/// @param showSourceLocation If `true`, look up the source location for
617+
/// each address.
618+
///
616619
/// @param useSymbolCache If the system we are on has a symbol cache,
617620
/// says whether or not to use it.
618621
///
619622
/// @returns A new `SymbolicatedBacktrace`.
620623
public func symbolicated(with images: [Image]? = nil,
621624
sharedCacheInfo: SharedCacheInfo? = nil,
622625
showInlineFrames: Bool = true,
626+
showSourceLocations: Bool = true,
623627
useSymbolCache: Bool = true)
624628
-> SymbolicatedBacktrace? {
625-
return SymbolicatedBacktrace.symbolicate(backtrace: self,
626-
images: images,
627-
sharedCacheInfo: sharedCacheInfo,
628-
showInlineFrames: showInlineFrames,
629-
useSymbolCache: useSymbolCache)
629+
return SymbolicatedBacktrace.symbolicate(
630+
backtrace: self,
631+
images: images,
632+
sharedCacheInfo: sharedCacheInfo,
633+
showInlineFrames: showInlineFrames,
634+
showSourceLocations: showSourceLocations,
635+
useSymbolCache: useSymbolCache
636+
)
630637
}
631638

632639
/// Provide a textual version of the backtrace.

stdlib/public/Backtracing/BacktraceFormatter.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -545,12 +545,12 @@ public struct BacktraceFormatter {
545545
if let index = index {
546546
columns.append(options._theme.frameIndex("\(index)"))
547547
}
548-
columns.append(options._theme.programCounter(pc))
549548
if options._showFrameAttributes {
550549
columns.append(attrs.map(
551550
options._theme.frameAttribute
552551
).joined(separator: " "))
553552
}
553+
columns.append(options._theme.programCounter(pc))
554554

555555
return columns
556556
}

stdlib/public/Backtracing/SymbolicatedBacktrace.swift

Lines changed: 57 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,7 @@ public struct SymbolicatedBacktrace: CustomStringConvertible {
341341
with owner: CSSymbolOwnerRef,
342342
isInline: Bool,
343343
symbol: CSSymbolRef,
344-
sourceInfo: CSSourceInfoRef,
344+
sourceInfo: CSSourceInfoRef?,
345345
images: [Backtrace.Image]) -> Frame {
346346
if CSIsNull(symbol) {
347347
return Frame(captured: capturedFrame, symbol: nil)
@@ -354,7 +354,7 @@ public struct SymbolicatedBacktrace: CustomStringConvertible {
354354

355355
let location: SourceLocation?
356356

357-
if !CSIsNull(sourceInfo) {
357+
if let sourceInfo = sourceInfo, !CSIsNull(sourceInfo) {
358358
let path = CSSourceInfoGetPath(sourceInfo) ?? "<unknown>"
359359
let line = CSSourceInfoGetLineNumber(sourceInfo)
360360
let column = CSSourceInfoGetColumn(sourceInfo)
@@ -395,6 +395,7 @@ public struct SymbolicatedBacktrace: CustomStringConvertible {
395395
images: [Backtrace.Image]?,
396396
sharedCacheInfo: Backtrace.SharedCacheInfo?,
397397
showInlineFrames: Bool,
398+
showSourceLocations: Bool,
398399
useSymbolCache: Bool)
399400
-> SymbolicatedBacktrace? {
400401

@@ -454,7 +455,7 @@ public struct SymbolicatedBacktrace: CustomStringConvertible {
454455

455456
first = false
456457
}
457-
} else {
458+
} else if showSourceLocations {
458459
let symbol = CSSymbolOwnerGetSymbolWithAddress(owner, address)
459460
let sourceInfo = CSSymbolOwnerGetSourceInfoWithAddress(owner,
460461
address)
@@ -465,6 +466,15 @@ public struct SymbolicatedBacktrace: CustomStringConvertible {
465466
symbol: symbol,
466467
sourceInfo: sourceInfo,
467468
images: theImages))
469+
} else {
470+
let symbol = CSSymbolOwnerGetSymbolWithAddress(owner, address)
471+
472+
frames.append(buildFrame(from: frame,
473+
with: owner,
474+
isInline: false,
475+
symbol: symbol,
476+
sourceInfo: nil,
477+
images: theImages))
468478
}
469479
}
470480
}
@@ -505,21 +515,29 @@ public struct SymbolicatedBacktrace: CustomStringConvertible {
505515
}
506516

507517
if let theSymbol = elf32Image?.lookupSymbol(address: relativeAddress) {
508-
var location = try? elf32Image!.sourceLocation(for: relativeAddress)
518+
var location: SourceLocation?
509519

510-
for inline in elf32Image!.inlineCallSites(at: relativeAddress) {
511-
let fakeSymbol = Symbol(imageIndex: imageNdx,
512-
imageName: theImages[imageNdx].name,
513-
rawName: inline.rawName ?? "<unknown>",
514-
offset: 0,
515-
sourceLocation: location)
516-
frames.append(Frame(captured: frame,
517-
symbol: fakeSymbol,
518-
inlined: true))
519-
520-
location = SourceLocation(path: inline.filename,
521-
line: inline.line,
522-
column: inline.column)
520+
if showSourceLocations || showInlineFrames {
521+
location = try? elf32Image!.sourceLocation(for: relativeAddress)
522+
} else {
523+
location = nil
524+
}
525+
526+
if showInlineFrames {
527+
for inline in elf32Image!.inlineCallSites(at: relativeAddress) {
528+
let fakeSymbol = Symbol(imageIndex: imageNdx,
529+
imageName: theImages[imageNdx].name,
530+
rawName: inline.rawName ?? "<unknown>",
531+
offset: 0,
532+
sourceLocation: location)
533+
frames.append(Frame(captured: frame,
534+
symbol: fakeSymbol,
535+
inlined: true))
536+
537+
location = SourceLocation(path: inline.filename,
538+
line: inline.line,
539+
column: inline.column)
540+
}
523541
}
524542

525543
symbol = Symbol(imageIndex: imageNdx,
@@ -528,21 +546,29 @@ public struct SymbolicatedBacktrace: CustomStringConvertible {
528546
offset: theSymbol.offset,
529547
sourceLocation: location)
530548
} else if let theSymbol = elf64Image?.lookupSymbol(address: relativeAddress) {
531-
var location = try? elf64Image!.sourceLocation(for: relativeAddress)
549+
var location: SourceLocation?
532550

533-
for inline in elf64Image!.inlineCallSites(at: relativeAddress) {
534-
let fakeSymbol = Symbol(imageIndex: imageNdx,
535-
imageName: theImages[imageNdx].name,
536-
rawName: inline.rawName ?? "<unknown>",
537-
offset: 0,
538-
sourceLocation: location)
539-
frames.append(Frame(captured: frame,
540-
symbol: fakeSymbol,
541-
inlined: true))
542-
543-
location = SourceLocation(path: inline.filename,
544-
line: inline.line,
545-
column: inline.column)
551+
if showSourceLocations || showInlineFrames {
552+
location = try? elf64Image!.sourceLocation(for: relativeAddress)
553+
} else {
554+
location = nil
555+
}
556+
557+
if showInlineFrames {
558+
for inline in elf64Image!.inlineCallSites(at: relativeAddress) {
559+
let fakeSymbol = Symbol(imageIndex: imageNdx,
560+
imageName: theImages[imageNdx].name,
561+
rawName: inline.rawName ?? "<unknown>",
562+
offset: 0,
563+
sourceLocation: location)
564+
frames.append(Frame(captured: frame,
565+
symbol: fakeSymbol,
566+
inlined: true))
567+
568+
location = SourceLocation(path: inline.filename,
569+
line: inline.line,
570+
column: inline.column)
571+
}
546572
}
547573

548574
symbol = Symbol(imageIndex: imageNdx,

stdlib/public/libexec/swift-backtrace/TargetLinux.swift

Lines changed: 85 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,18 @@ import _Backtracing
2727

2828
@_implementationOnly import Runtime
2929

30+
enum SomeBacktrace {
31+
case raw(Backtrace)
32+
case symbolicated(SymbolicatedBacktrace)
33+
}
34+
3035
struct TargetThread {
3136
typealias ThreadID = pid_t
3237

3338
var id: ThreadID
3439
var context: HostContext?
3540
var name: String
36-
var backtrace: SymbolicatedBacktrace
41+
var backtrace: SomeBacktrace
3742
}
3843

3944
class Target {
@@ -105,7 +110,8 @@ class Target {
105110
return trimmed
106111
}
107112

108-
init(crashInfoAddr: UInt64, limit: Int?, top: Int, cache: Bool) {
113+
init(crashInfoAddr: UInt64, limit: Int?, top: Int, cache: Bool,
114+
symbolicate: SwiftBacktrace.Symbolication) {
109115
// fd #4 is reserved for the memory server
110116
let memserverFd: CInt = 4
111117

@@ -130,7 +136,8 @@ class Target {
130136

131137
do {
132138
try fetchThreads(threadListHead: Address(crashInfo.thread_list),
133-
limit: limit, top: top, cache: cache)
139+
limit: limit, top: top, cache: cache,
140+
symbolicate: symbolicate)
134141
} catch {
135142
print("swift-backtrace: failed to fetch thread information: \(error)")
136143
exit(1)
@@ -143,7 +150,8 @@ class Target {
143150
/// uninterruptible wait, we won't have a ucontext for it.
144151
func fetchThreads(
145152
threadListHead: Address,
146-
limit: Int?, top: Int, cache: Bool
153+
limit: Int?, top: Int, cache: Bool,
154+
symbolicate: SwiftBacktrace.Symbolication
147155
) throws {
148156
var next = threadListHead
149157

@@ -164,18 +172,46 @@ class Target {
164172
images: images,
165173
limit: limit,
166174
top: top)
167-
guard let symbolicated
168-
= backtrace.symbolicated(with: images,
169-
sharedCacheInfo: nil,
170-
useSymbolCache: cache) else {
171-
print("unable to symbolicate backtrace for thread \(t.tid)")
172-
exit(1)
175+
176+
let shouldSymbolicate: Bool
177+
let showInlineFrames: Bool
178+
let showSourceLocations: Bool
179+
switch symbolicate {
180+
case .off:
181+
shouldSymbolicate = false
182+
showInlineFrames = false
183+
showSourceLocations = false
184+
case .fast:
185+
shouldSymbolicate = true
186+
showInlineFrames = false
187+
showSourceLocations = false
188+
case .full:
189+
shouldSymbolicate = true
190+
showInlineFrames = true
191+
showSourceLocations = true
173192
}
174193

175-
threads.append(TargetThread(id: TargetThread.ThreadID(t.tid),
176-
context: context,
177-
name: getThreadName(tid: t.tid),
178-
backtrace: symbolicated))
194+
if shouldSymbolicate {
195+
guard let symbolicated
196+
= backtrace.symbolicated(with: images,
197+
sharedCacheInfo: nil,
198+
showInlineFrames: showInlineFrames,
199+
showSourceLocations: showSourceLocations,
200+
useSymbolCache: cache) else {
201+
print("unable to symbolicate backtrace for thread \(t.tid)")
202+
exit(1)
203+
}
204+
205+
threads.append(TargetThread(id: TargetThread.ThreadID(t.tid),
206+
context: context,
207+
name: getThreadName(tid: t.tid),
208+
backtrace: .symbolicated(symbolicated)))
209+
} else {
210+
threads.append(TargetThread(id: TargetThread.ThreadID(t.tid),
211+
context: context,
212+
name: getThreadName(tid: t.tid),
213+
backtrace: .raw(backtrace)))
214+
}
179215
}
180216

181217
// Sort the threads by thread ID; the main thread always sorts
@@ -193,7 +229,10 @@ class Target {
193229
}
194230
}
195231

196-
func redoBacktraces(limit: Int?, top: Int, cache: Bool) {
232+
func redoBacktraces(
233+
limit: Int?, top: Int, cache: Bool,
234+
symbolicate: SwiftBacktrace.Symbolication
235+
) {
197236
for (ndx, thread) in threads.enumerated() {
198237
guard let context = thread.context else {
199238
continue
@@ -208,14 +247,39 @@ class Target {
208247
continue
209248
}
210249

211-
guard let symbolicated = backtrace.symbolicated(with: images,
212-
sharedCacheInfo: nil,
213-
useSymbolCache: cache) else {
214-
print("unable to symbolicate backtrace from context for thread \(ndx)")
215-
continue
250+
let shouldSymbolicate: Bool
251+
let showInlineFrames: Bool
252+
let showSourceLocations: Bool
253+
switch symbolicate {
254+
case .off:
255+
shouldSymbolicate = false
256+
showInlineFrames = false
257+
showSourceLocations = false
258+
case .fast:
259+
shouldSymbolicate = true
260+
showInlineFrames = false
261+
showSourceLocations = false
262+
case .full:
263+
shouldSymbolicate = true
264+
showInlineFrames = true
265+
showSourceLocations = true
216266
}
217267

218-
threads[ndx].backtrace = symbolicated
268+
if shouldSymbolicate {
269+
guard let symbolicated = backtrace.symbolicated(
270+
with: images,
271+
sharedCacheInfo: nil,
272+
showInlineFrames: showInlineFrames,
273+
showSourceLocations: showSourceLocations,
274+
useSymbolCache: cache) else {
275+
print("unable to symbolicate backtrace from context for thread \(ndx)")
276+
continue
277+
}
278+
279+
threads[ndx].backtrace = .symbolicated(symbolicated)
280+
} else {
281+
threads[ndx].backtrace = .raw(backtrace)
282+
}
219283
}
220284
}
221285

0 commit comments

Comments
 (0)