From 534d3c3307377f94382cc451ac54124e472dbabc Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Mon, 27 Jan 2025 17:28:05 +0000 Subject: [PATCH 1/2] [SE-0419] Tweak proposal slightly. Added an `ImageMap` type to hold the list of loaded images. This is neater and allows for some optimizations as well as make it easier to support `Codable` for `Backtrace`. This also removes the `captureImages()` API in favour of `ImageMap.capture()`, which is more natural. Also exposed the ability to construct a `Backtrace.Address` from a `FixedWidthInteger`, write-protected `Backtrace.architecture`, and switch `SymbolicatedBacktrace` back to an explicit `Array` of `Frame`s as we aren't trying to minimise space for the symbolicated version. --- proposals/0419-backtrace-api.md | 68 ++++++++++++++++++++++++--------- 1 file changed, 50 insertions(+), 18 deletions(-) diff --git a/proposals/0419-backtrace-api.md b/proposals/0419-backtrace-api.md index d185267a86..6500579d20 100644 --- a/proposals/0419-backtrace-api.md +++ b/proposals/0419-backtrace-api.md @@ -180,7 +180,7 @@ public struct Backtrace: CustomStringConvertible, Codable, Sendable { } /// The architecture of the process to which this backtrace refers. - public var architecture: String + public var architecture: String { get } /// A `Sequence` of captured frame information. /// @@ -194,8 +194,8 @@ public struct Backtrace: CustomStringConvertible, Codable, Sendable { /// Some backtracing algorithms may require this information, in which case /// it will be filled in by the `capture()` method. Other algorithms may /// not, in which case it will be `nil` and you can capture an image list - /// separately yourself using `captureImages()`. - public var images: [Image]? + /// separately yourself using `ImageMap.capture()`. + public var images: ImageMap? /// Capture a backtrace from the current program location. /// @@ -222,12 +222,6 @@ public struct Backtrace: CustomStringConvertible, Codable, Sendable { offset: Int = 0, top: Int = 16) throws -> Backtrace - /// Capture a list of the images currently mapped into the calling - /// process. - /// - /// @returns A list of `Image`s. - public static func captureImages() -> [Image] - /// Specifies options for the `symbolicated` method. public struct SymbolicationOptions: OptionSet { public let rawValue: Int @@ -259,7 +253,7 @@ public struct Backtrace: CustomStringConvertible, Codable, Sendable { /// @param options Symbolication options; see `SymbolicationOptions`. /// /// @returns A new `SymbolicatedBacktrace`. - public func symbolicated(with images: [Image]? = nil, + public func symbolicated(with images: ImageMap? = nil, options: SymbolicationOptions = .default) -> SymbolicatedBacktrace? @@ -283,6 +277,43 @@ extension FixedWidthInteger { } ``` +We also allow conversion of a `FixedWidthInteger` to an address: + +```swift +extension Backtrace.Address { + /// Convert from a FixedWidthInteger. + /// + /// This initializer will return nil if the address width is not one that is + /// currently supported by `Backtrace.Address`. + /// + /// @param value The value to convert. + public init?(_ value: T) +} +``` + +The `ImageMap` type represents a captured list of loaded images, and +implements the `Collection` protocol so can be indexed like an array: + +```swift +public struct ImageMap: Collection, Sendable, Hashable, CustomStringConvertible { + + /// Capture the image map for the current process. + public static func capture() -> ImageMap + + /// The name of the platform that captured this image map. + public private(set) var platform: String + + /// Look-up an image by address. + public func indexOfImage(at address: Backtrace.Address) -> Int? + +} +``` + +The `platform` string starts with a token identifying the operating +system (e.g. `macOS`, `iOS`, `tvOS`, `watchOS`, `visionOS`, `Linux`, +`Windows`) and may contain additional platform-specific version +information thereafter. + _Symbolication_, by which we mean the process of looking up the symbols associated with addresses in a backtrace, is in general an expensive process, and for efficiency reasons is normally performed for a backtrace @@ -385,10 +416,10 @@ public struct SymbolicatedBacktrace: CustomStringConvertible, Codable, Sendable } /// A list of captured frame information. - public var frames: some Sequence { get } + public var frames: [Frame] { get } /// A list of images found in the process. - public var images: [Backtrace.Image] + public var images: ImageMap { get } /// True if this backtrace is a Swift runtime failure. public var isSwiftRuntimeFailure: Bool { get } @@ -451,12 +482,13 @@ of existentials; or it could have been a generic parameter, but doing that makes it difficult to cope with a backtrace unless you already know what kind of addresses it contains at compile time. -The `frames` member variables could have been arrays, but implementing -them instead as a sequence means that we have the flexibility to use -a different backing store where doing so makes sense. An example where -we might want that is where we're capturing very large numbers of -backtraces, in which case doing some kind of delta compression on the -frame addresses might enable us to save significant amounts of memory. +The `frames` member variable on `Backtrace` could have been an array, +but implementing it instead as a sequence means that we have the +flexibility to use a different backing store where doing so makes +sense. An example where we might want that is where we're capturing +very large numbers of backtraces, in which case doing some kind of +delta compression on the frame addresses might enable us to save +significant amounts of memory. Some desirable features are intentionally left out of this proposal; the intent is that while some of these may even be implemented, they From df8de5619e0e9366bd3c260e1d09b3b4a6103342 Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Thu, 29 May 2025 10:47:27 +0100 Subject: [PATCH 2/2] [SE-0419] Update headers. This should be marked as implemented in Swift 6.2, and you no longer want to look at the `_Backtracing` module. --- proposals/0419-backtrace-api.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/proposals/0419-backtrace-api.md b/proposals/0419-backtrace-api.md index 6500579d20..dd2b26a5b6 100644 --- a/proposals/0419-backtrace-api.md +++ b/proposals/0419-backtrace-api.md @@ -3,8 +3,7 @@ * Proposal: [SE-0419](0419-backtrace-api.md) * Authors: [Alastair Houghton](https://github.com/al45tair) * Review Manager: [Steve Canon](https://github.com/stephentyrone) -* Status: **Accepted** -* Implementation: Implemented on main, requires explicit `_Backtracing` import. +* Status: **Implemented (Swift 6.2)** * Review: ([pitch](https://forums.swift.org/t/pitch-swift-backtracing-api/62741)) ([review](https://forums.swift.org/t/se-0419-swift-backtracing-api/69595)) ([acceptance](https://forums.swift.org/t/accepted-with-modifications-se-0419-swift-backtracing-api/70318)) ## Introduction