Skip to content

Commit bbc0c79

Browse files
committed
Rather than have a separate .preciseDemangled, just output the backtrace as structured values and let the JSON consumer construct a single string as desired
1 parent 46d74fd commit bbc0c79

File tree

5 files changed

+60
-105
lines changed

5 files changed

+60
-105
lines changed

Sources/Testing/ABI/EntryPoints/EntryPoint.swift

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -441,8 +441,6 @@ public func configurationForEntryPoint(from args: __CommandLineArguments_v0) thr
441441
configuration.backtraceSymbolicationMode = .mangled
442442
case "demangled":
443443
configuration.backtraceSymbolicationMode = .demangled
444-
case "precise-demangled":
445-
configuration.backtraceSymbolicationMode = .preciseDemangled
446444
default:
447445
throw _EntryPointError.invalidArgument("--symbolicate-backtraces", value: symbolicateBacktraces)
448446

Sources/Testing/ABI/v0/Encoded/ABIv0.EncodedBacktrace.swift

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,23 +16,14 @@ extension ABIv0 {
1616
/// assists in converting values to JSON; clients that consume this JSON are
1717
/// expected to write their own decoders.
1818
struct EncodedBacktrace: Sendable {
19-
/// A type describing a frame in the backtrace.
20-
struct Frame: Sendable {
21-
/// The address of the frame.
22-
var address: Backtrace.Address
23-
24-
/// The name of the frame, possibly demangled, if available.
25-
var symbolName: String?
26-
}
27-
2819
/// The frames in the backtrace.
29-
var frames: [Frame]
20+
var symbolicatedAddresses: [Backtrace.SymbolicatedAddress]
3021

3122
init(encoding backtrace: borrowing Backtrace, in eventContext: borrowing Event.Context) {
3223
if let symbolicationMode = eventContext.configuration?.backtraceSymbolicationMode {
33-
frames = zip(backtrace.addresses, backtrace.symbolicate(symbolicationMode)).map(Frame.init)
24+
symbolicatedAddresses = backtrace.symbolicate(symbolicationMode)
3425
} else {
35-
frames = backtrace.addresses.map { Frame(address: $0) }
26+
symbolicatedAddresses = backtrace.addresses.map { Backtrace.SymbolicatedAddress(address: $0) }
3627
}
3728
}
3829
}
@@ -42,12 +33,10 @@ extension ABIv0 {
4233

4334
extension ABIv0.EncodedBacktrace: Codable {
4435
func encode(to encoder: any Encoder) throws {
45-
try frames.encode(to: encoder)
36+
try symbolicatedAddresses.encode(to: encoder)
4637
}
4738

4839
init(from decoder: any Decoder) throws {
49-
self.frames = try [Frame](from: decoder)
40+
self.symbolicatedAddresses = try [Backtrace.SymbolicatedAddress](from: decoder)
5041
}
5142
}
52-
53-
extension ABIv0.EncodedBacktrace.Frame: Codable {}

Sources/Testing/SourceAttribution/Backtrace+Symbolication.swift

Lines changed: 53 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@ private import _TestingInternals
1414
@_spi(ForToolsIntegrationOnly)
1515
extension Backtrace {
1616
/// Demangle a symbol name.
17-
///
17+
///
1818
/// - Parameters:
1919
/// - mangledSymbolName: The symbol name to demangle.
20-
///
20+
///
2121
/// - Returns: The demangled form of `mangledSymbolName` according to the
2222
/// Swift standard library or the platform's C++ standard library, or `nil`
2323
/// if the symbol name could not be demangled.
@@ -31,35 +31,62 @@ extension Backtrace {
3131
return String(validatingCString: demangledSymbolName)
3232
}
3333

34-
/// Symbolicate a sequence of addresses.
35-
///
34+
/// An enumeration describing the symbolication mode to use when handling
35+
/// events containing backtraces.
36+
public enum SymbolicationMode: Sendable {
37+
/// The backtrace should be symbolicated, but no demangling should be
38+
/// performed.
39+
case mangled
40+
41+
/// The backtrace should be symbolicated and Swift and C++ symbols should be
42+
/// demangled if possible.
43+
case demangled
44+
}
45+
46+
/// A type representing an instance of ``Backtrace/Address`` that has been
47+
/// symbolicated by a call to ``Backtrace/symbolicate(_:)``.
48+
public struct SymbolicatedAddress: Sendable {
49+
/// The (unsymbolicated) address from the backtrace.
50+
public var address: Address
51+
52+
/// The offset of ``address`` from the start of the corresponding function,
53+
/// if available.
54+
///
55+
/// If ``address`` could not be resolved to a symbol, the value of this
56+
/// property is `nil`.
57+
public var offset: UInt64?
58+
59+
/// The name of the symbol at ``address``, if available.
60+
///
61+
/// If ``address`` could not be resolved to a symbol, the value of this
62+
/// property is `nil`.
63+
public var symbolName: String?
64+
}
65+
66+
/// Symbolicate the addresses in this backtrace.
67+
///
3668
/// - Parameters:
37-
/// - addresses: The sequence of addresses. These addresses must have
38-
/// originated in the current process.
3969
/// - mode: How to symbolicate the addresses in the backtrace.
40-
///
70+
///
4171
/// - Returns: An array of strings representing the names of symbols in
4272
/// `addresses`.
43-
///
44-
/// If an address in `addresses` cannot be symbolicated, it is converted to a
45-
/// string using ``Swift/String/init(describingForTest:)``.
46-
private static func _symbolicate(addresses: UnsafeBufferPointer<UnsafeRawPointer?>, mode: SymbolicationMode) -> [String] {
47-
let count = addresses.count
48-
var symbolNames = [(String, displacement: UInt)?](repeating: nil, count: count)
73+
///
74+
/// If an address in `addresses` cannot be symbolicated, the corresponding
75+
/// instance of ``SymbolicatedAddress`` in the resulting array has a `nil`
76+
/// value for its ``Backtrace/SymbolicatedAddress/symbolName`` property.
77+
public func symbolicate(_ mode: SymbolicationMode) -> [SymbolicatedAddress] {
78+
var result = addresses.map { SymbolicatedAddress(address: $0) }
4979

5080
#if SWT_TARGET_OS_APPLE
5181
for (i, address) in addresses.enumerated() {
52-
guard let address else {
53-
continue
54-
}
5582
var info = Dl_info()
56-
if 0 != dladdr(address, &info) {
57-
let displacement = UInt(bitPattern: address) - UInt(bitPattern: info.dli_saddr)
83+
if 0 != dladdr(UnsafePointer(bitPattern: UInt(clamping: address)), &info) {
84+
let offset = address - Address(clamping: UInt(bitPattern: info.dli_saddr))
5885
if var symbolName = info.dli_sname.flatMap(String.init(validatingCString:)) {
5986
if mode != .mangled {
60-
symbolName = _demangle(symbolName) ?? symbolName
87+
symbolName = Self._demangle(symbolName) ?? symbolName
6188
}
62-
symbolNames[i] = (symbolName, displacement)
89+
result[i] = SymbolicatedAddress(address: address, offset: offset, symbolName: symbolName)
6390
}
6491
}
6592
}
@@ -77,21 +104,17 @@ extension Backtrace {
77104
return
78105
}
79106
for (i, address) in addresses.enumerated() {
80-
guard let address else {
81-
continue
82-
}
83-
84107
withUnsafeTemporaryAllocation(of: SYMBOL_INFO_PACKAGEW.self, capacity: 1) { symbolInfo in
85108
let symbolInfo = symbolInfo.baseAddress!
86109
symbolInfo.pointee.si.SizeOfStruct = ULONG(MemoryLayout<SYMBOL_INFOW>.stride)
87110
symbolInfo.pointee.si.MaxNameLen = ULONG(MAX_SYM_NAME)
88111
var displacement = DWORD64(0)
89-
if SymFromAddrW(hProcess, DWORD64(clamping: UInt(bitPattern: address)), &displacement, symbolInfo.pointer(to: \.si)!),
112+
if SymFromAddrW(hProcess, DWORD64(clamping: address), &displacement, symbolInfo.pointer(to: \.si)!),
90113
var symbolName = String.decodeCString(symbolInfo.pointer(to: \.si.Name)!, as: UTF16.self)?.result {
91114
if mode != .mangled {
92-
symbolName = _demangle(symbolName) ?? symbolName
115+
symbolName = Self._demangle(symbolName) ?? symbolName
93116
}
94-
symbolNames[i] = (symbolName, UInt(clamping: displacement))
117+
result[i] = SymbolicatedAddress(address: address, offset: displacement, symbolName: symbolName)
95118
}
96119
}
97120
}
@@ -102,67 +125,13 @@ extension Backtrace {
102125
#warning("Platform-specific implementation missing: backtrace symbolication unavailable")
103126
#endif
104127

105-
var result = [String]()
106-
result.reserveCapacity(count)
107-
for (i, address) in addresses.enumerated() {
108-
let formatted = if let (symbolName, displacement) = symbolNames[i] {
109-
if mode == .preciseDemangled {
110-
"\(i) \(symbolName) (\(String(describingForTest: address))+\(displacement))"
111-
} else {
112-
symbolName
113-
}
114-
} else {
115-
String(describingForTest: address)
116-
}
117-
result.append(formatted)
118-
}
119128
return result
120129
}
130+
}
121131

122-
/// An enumeration describing the symbolication mode to use when handling
123-
/// events containing backtraces.
124-
public enum SymbolicationMode: Sendable {
125-
/// The backtrace should be symbolicated, but no demangling should be
126-
/// performed.
127-
case mangled
128-
129-
/// The backtrace should be symbolicated and Swift and C++ symbols should be
130-
/// demangled if possible.
131-
case demangled
132-
133-
/// The backtrace should be symbolicated, Swift and C++ symbols should be
134-
/// demangled if possible, and precise symbol addresses and offsets should
135-
/// be provided if available.
136-
case preciseDemangled
137-
}
132+
// MARK: - Codable
138133

139-
/// Symbolicate the addresses in this backtrace.
140-
///
141-
/// - Parameters:
142-
/// - mode: How to symbolicate the addresses in the backtrace.
143-
///
144-
/// - Returns: An array of strings representing the names of symbols in
145-
/// `addresses`.
146-
///
147-
/// If an address in `addresses` cannot be symbolicated, it is converted to a
148-
/// string using ``Swift/String/init(describingForTest:)``.
149-
public func symbolicate(_ mode: SymbolicationMode) -> [String] {
150-
#if _pointerBitWidth(_64)
151-
// The width of a pointer equals the width of an `Address`, so we can just
152-
// bitcast the memory rather than mapping through UInt first.
153-
addresses.withUnsafeBufferPointer { addresses in
154-
addresses.withMemoryRebound(to: UnsafeRawPointer?.self) { addresses in
155-
Self._symbolicate(addresses: addresses, mode: mode)
156-
}
157-
}
158-
#else
159-
let addresses = addresses.map { UnsafeRawPointer(bitPattern: UInt($0)) }
160-
return addresses.withUnsafeBufferPointer { addresses in
161-
Self._symbolicate(addresses: addresses, mode: mode)
162-
}
163-
#endif
164-
}
165-
}
134+
extension Backtrace.SymbolicatedAddress: Codable {}
166135

167136
#if os(Windows)
168137
// MARK: -

Tests/TestingTests/BacktraceTests.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,13 +150,13 @@ struct BacktraceTests {
150150
}
151151
#endif
152152

153-
@Test("Symbolication", arguments: [Backtrace.SymbolicationMode.mangled, .demangled, .preciseDemangled])
153+
@Test("Symbolication", arguments: [Backtrace.SymbolicationMode.mangled, .demangled])
154154
func symbolication(mode: Backtrace.SymbolicationMode) {
155155
let backtrace = Backtrace.current()
156156
let symbolNames = backtrace.symbolicate(mode)
157157
#expect(backtrace.addresses.count == symbolNames.count)
158158
if testsWithSignificantIOAreEnabled {
159-
print(symbolNames.joined(separator: "\n"))
159+
print(symbolNames.map(String.init(describingForTest:)).joined(separator: "\n"))
160160
}
161161
}
162162
}

Tests/TestingTests/SwiftPMTests.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ struct SwiftPMTests {
4848
(String?.none, Backtrace.SymbolicationMode?.none),
4949
("mangled", .mangled), ("on", .mangled), ("true", .mangled),
5050
("demangled", .demangled),
51-
("precise-demangled", .preciseDemangled),
5251
]
5352
)
5453
func symbolicateBacktraces(argumentValue: String?, expectedMode: Backtrace.SymbolicationMode?) throws {

0 commit comments

Comments
 (0)