Skip to content

Commit dd0b826

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 6c7aeeb commit dd0b826

File tree

10 files changed

+267
-71
lines changed

10 files changed

+267
-71
lines changed

docs/Backtracing.rst

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,9 @@ follows:
9696
| | | standard error instead of standard output. This |
9797
| | | may be useful in some CI systems. |
9898
+-----------------+---------+--------------------------------------------------+
99-
| symbolicate | yes | Set to ``no`` to disable symbolication. This |
100-
| | | will also disable inline frame lookup. |
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. |
101102
+-----------------+---------+--------------------------------------------------+
102103
| swift-backtrace | | If specified, gives the full path to the |
103104
| | | swift-backtrace binary to use for crashes. |

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/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: 53 additions & 8 deletions
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

Lines changed: 60 additions & 12 deletions
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)