Skip to content

Commit 8cd35f0

Browse files
committed
[Runtime] Improved symbolication option for backtracing.
Rather than just on or off, I've changed it to allow "off", "fast", or "full". "fast" means that we'll do symbol lookup, but we won't try to find inline frames and we won't run line number programs (those are the things that are taking considerable time in some cases). rdar://122302117
1 parent 020ce72 commit 8cd35f0

File tree

10 files changed

+267
-71
lines changed

10 files changed

+267
-71
lines changed

docs/Backtracing.rst

+3-2
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,9 @@ follows:
100100
| | | standard error instead of standard output. This |
101101
| | | may be useful in some CI systems. |
102102
+-----------------+---------+--------------------------------------------------+
103-
| symbolicate | yes | Set to ``no`` to disable symbolication. This |
104-
| | | will also disable inline frame lookup. |
103+
| symbolicate | full | Options are ``full``, ``fast``, or ``off``. |
104+
| | | Full means to look up source locations and |
105+
| | | inline frames. Fast just does symbol lookup. |
105106
+-----------------+---------+--------------------------------------------------+
106107
| swift-backtrace | | If specified, gives the full path to the |
107108
| | | swift-backtrace binary to use for crashes. |

stdlib/public/Backtracing/Backtrace.swift

+12-5
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/SymbolicatedBacktrace.swift

+57-31
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ public struct SymbolicatedBacktrace: CustomStringConvertible {
336336
with owner: CSSymbolOwnerRef,
337337
isInline: Bool,
338338
symbol: CSSymbolRef,
339-
sourceInfo: CSSourceInfoRef,
339+
sourceInfo: CSSourceInfoRef?,
340340
images: [Backtrace.Image]) -> Frame {
341341
if CSIsNull(symbol) {
342342
return Frame(captured: capturedFrame, symbol: nil)
@@ -349,7 +349,7 @@ public struct SymbolicatedBacktrace: CustomStringConvertible {
349349

350350
let location: SourceLocation?
351351

352-
if !CSIsNull(sourceInfo) {
352+
if let sourceInfo = sourceInfo, !CSIsNull(sourceInfo) {
353353
let path = CSSourceInfoGetPath(sourceInfo) ?? "<unknown>"
354354
let line = CSSourceInfoGetLineNumber(sourceInfo)
355355
let column = CSSourceInfoGetColumn(sourceInfo)
@@ -390,6 +390,7 @@ public struct SymbolicatedBacktrace: CustomStringConvertible {
390390
images: [Backtrace.Image]?,
391391
sharedCacheInfo: Backtrace.SharedCacheInfo?,
392392
showInlineFrames: Bool,
393+
showSourceLocations: Bool,
393394
useSymbolCache: Bool)
394395
-> SymbolicatedBacktrace? {
395396

@@ -449,7 +450,7 @@ public struct SymbolicatedBacktrace: CustomStringConvertible {
449450

450451
first = false
451452
}
452-
} else {
453+
} else if showSourceLocations {
453454
let symbol = CSSymbolOwnerGetSymbolWithAddress(owner, address)
454455
let sourceInfo = CSSymbolOwnerGetSourceInfoWithAddress(owner,
455456
address)
@@ -460,6 +461,15 @@ public struct SymbolicatedBacktrace: CustomStringConvertible {
460461
symbol: symbol,
461462
sourceInfo: sourceInfo,
462463
images: theImages))
464+
} else {
465+
let symbol = CSSymbolOwnerGetSymbolWithAddress(owner, address)
466+
467+
frames.append(buildFrame(from: frame,
468+
with: owner,
469+
isInline: false,
470+
symbol: symbol,
471+
sourceInfo: nil,
472+
images: theImages))
463473
}
464474
}
465475
}
@@ -500,21 +510,29 @@ public struct SymbolicatedBacktrace: CustomStringConvertible {
500510
}
501511

502512
if let theSymbol = elf32Image?.lookupSymbol(address: relativeAddress) {
503-
var location = try? elf32Image!.sourceLocation(for: relativeAddress)
513+
var location: SourceLocation?
504514

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

520538
symbol = Symbol(imageIndex: imageNdx,
@@ -523,21 +541,29 @@ public struct SymbolicatedBacktrace: CustomStringConvertible {
523541
offset: theSymbol.offset,
524542
sourceLocation: location)
525543
} else if let theSymbol = elf64Image?.lookupSymbol(address: relativeAddress) {
526-
var location = try? elf64Image!.sourceLocation(for: relativeAddress)
544+
var location: SourceLocation?
527545

528-
for inline in elf64Image!.inlineCallSites(at: relativeAddress) {
529-
let fakeSymbol = Symbol(imageIndex: imageNdx,
530-
imageName: theImages[imageNdx].name,
531-
rawName: inline.rawName ?? "<unknown>",
532-
offset: 0,
533-
sourceLocation: location)
534-
frames.append(Frame(captured: frame,
535-
symbol: fakeSymbol,
536-
inlined: true))
537-
538-
location = SourceLocation(path: inline.filename,
539-
line: inline.line,
540-
column: inline.column)
546+
if showSourceLocations || showInlineFrames {
547+
location = try? elf64Image!.sourceLocation(for: relativeAddress)
548+
} else {
549+
location = nil
550+
}
551+
552+
if showInlineFrames {
553+
for inline in elf64Image!.inlineCallSites(at: relativeAddress) {
554+
let fakeSymbol = Symbol(imageIndex: imageNdx,
555+
imageName: theImages[imageNdx].name,
556+
rawName: inline.rawName ?? "<unknown>",
557+
offset: 0,
558+
sourceLocation: location)
559+
frames.append(Frame(captured: frame,
560+
symbol: fakeSymbol,
561+
inlined: true))
562+
563+
location = SourceLocation(path: inline.filename,
564+
line: inline.line,
565+
column: inline.column)
566+
}
541567
}
542568

543569
symbol = Symbol(imageIndex: imageNdx,

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

+53-8
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ class Target {
111111
}
112112

113113
init(crashInfoAddr: UInt64, limit: Int?, top: Int, cache: Bool,
114-
symbolicate: Bool) {
114+
symbolicate: SwiftBacktrace.Symbolication) {
115115
// fd #4 is reserved for the memory server
116116
let memserverFd: CInt = 4
117117

@@ -150,7 +150,8 @@ class Target {
150150
/// uninterruptible wait, we won't have a ucontext for it.
151151
func fetchThreads(
152152
threadListHead: Address,
153-
limit: Int?, top: Int, cache: Bool, symbolicate: Bool
153+
limit: Int?, top: Int, cache: Bool,
154+
symbolicate: SwiftBacktrace.Symbolication
154155
) throws {
155156
var next = threadListHead
156157

@@ -172,10 +173,30 @@ class Target {
172173
limit: limit,
173174
top: top)
174175

175-
if symbolicate {
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
192+
}
193+
194+
if shouldSymbolicate {
176195
guard let symbolicated
177196
= backtrace.symbolicated(with: images,
178197
sharedCacheInfo: nil,
198+
showInlineFrames: showInlineFrames,
199+
showSourceLocations: showSourceLocations,
179200
useSymbolCache: cache) else {
180201
print("unable to symbolicate backtrace for thread \(t.tid)")
181202
exit(1)
@@ -208,7 +229,10 @@ class Target {
208229
}
209230
}
210231

211-
func redoBacktraces(limit: Int?, top: Int, cache: Bool, symbolicate: Bool) {
232+
func redoBacktraces(
233+
limit: Int?, top: Int, cache: Bool,
234+
symbolicate: SwiftBacktrace.Symbolication
235+
) {
212236
for (ndx, thread) in threads.enumerated() {
213237
guard let context = thread.context else {
214238
continue
@@ -223,10 +247,31 @@ class Target {
223247
continue
224248
}
225249

226-
if symbolicate {
227-
guard let symbolicated = backtrace.symbolicated(with: images,
228-
sharedCacheInfo: nil,
229-
useSymbolCache: cache) else {
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
266+
}
267+
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 {
230275
print("unable to symbolicate backtrace from context for thread \(ndx)")
231276
continue
232277
}

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

+60-12
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ class Target {
140140
}
141141

142142
init(crashInfoAddr: UInt64, limit: Int?, top: Int, cache: Bool,
143-
symbolicate: Bool) {
143+
symbolicate: SwiftBacktrace.Symbolication) {
144144
pid = getppid()
145145

146146
if Self.isPlatformBinary(pid: pid) {
@@ -194,7 +194,10 @@ class Target {
194194
fetchThreads(limit: limit, top: top, cache: cache, symbolicate: symbolicate)
195195
}
196196

197-
func fetchThreads(limit: Int?, top: Int, cache: Bool, symbolicate: Bool) {
197+
func fetchThreads(
198+
limit: Int?, top: Int, cache: Bool,
199+
symbolicate: SwiftBacktrace.Symbolication
200+
) {
198201
var threadPorts: thread_act_array_t? = nil
199202
var threadCount: mach_msg_type_number_t = 0
200203
let kr = task_threads(task,
@@ -266,10 +269,31 @@ class Target {
266269
exit(1)
267270
}
268271

269-
if symbolicate {
270-
guard let symbolicated = backtrace.symbolicated(with: images,
271-
sharedCacheInfo: sharedCacheInfo,
272-
useSymbolCache: cache) else {
272+
let shouldSymbolicate: Bool
273+
let showInlineFrames: Bool
274+
let showSourceLocations: Bool
275+
switch symbolicate {
276+
case .off:
277+
shouldSymbolicate = false
278+
showInlineFrames = false
279+
showSourceLocations = false
280+
case .fast:
281+
shouldSymbolicate = true
282+
showInlineFrames = false
283+
showSourceLocations = false
284+
case .full:
285+
shouldSymbolicate = true
286+
showInlineFrames = true
287+
showSourceLocations = true
288+
}
289+
290+
if shouldSymbolicate {
291+
guard let symbolicated = backtrace.symbolicated(
292+
with: images,
293+
sharedCacheInfo: sharedCacheInfo,
294+
showInlineFrames: showInlineFrames,
295+
showSourceLocations: showSourceLocations,
296+
useSymbolCache: cache) else {
273297
print("unable to symbolicate backtrace from context for thread \(ndx)",
274298
to: &standardError)
275299
exit(1)
@@ -290,8 +314,11 @@ class Target {
290314
}
291315
}
292316

293-
public func redoBacktraces(limit: Int?, top: Int,
294-
cache: Bool, symbolicate: Bool) {
317+
public func redoBacktraces(
318+
limit: Int?, top: Int,
319+
cache: Bool,
320+
symbolicate: SwiftBacktrace.Symbolication
321+
) {
295322
for (ndx, thread) in threads.enumerated() {
296323
guard let context = thread.context else {
297324
continue
@@ -307,10 +334,31 @@ class Target {
307334
continue
308335
}
309336

310-
if symbolicate {
311-
guard let symbolicated = backtrace.symbolicated(with: images,
312-
sharedCacheInfo: sharedCacheInfo,
313-
useSymbolCache: cache) else {
337+
let shouldSymbolicate: Bool
338+
let showInlineFrames: Bool
339+
let showSourceLocations: Bool
340+
switch symbolicate {
341+
case .off:
342+
shouldSymbolicate = false
343+
showInlineFrames = false
344+
showSourceLocations = false
345+
case .fast:
346+
shouldSymbolicate = true
347+
showInlineFrames = false
348+
showSourceLocations = false
349+
case .full:
350+
shouldSymbolicate = true
351+
showInlineFrames = true
352+
showSourceLocations = true
353+
}
354+
355+
if shouldSymbolicate {
356+
guard let symbolicated = backtrace.symbolicated(
357+
with: images,
358+
sharedCacheInfo: sharedCacheInfo,
359+
showInlineFrames: showInlineFrames,
360+
showSourceLocations: showSourceLocations,
361+
useSymbolCache: cache) else {
314362
print("swift-backtrace: unable to symbolicate backtrace from context for thread \(ndx)",
315363
to: &standardError)
316364
continue

0 commit comments

Comments
 (0)