mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
It's useful to capture the platform and platform version with the image map. Also, display both the platform and architecture information when generating a crash log. rdar://124913332
147 lines
4.4 KiB
Swift
147 lines
4.4 KiB
Swift
//===--- RichFrame.swift --------------------------------------*- swift -*-===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2024 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Defines the default rich frame storage type used by `Backtrace`
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
import Swift
|
|
|
|
@_spi(Internal)
|
|
public enum RichFrame<T: FixedWidthInteger>: CustomStringConvertible, Equatable {
|
|
public typealias Address = T
|
|
|
|
/// A program counter value.
|
|
///
|
|
/// This might come from a signal handler, or an exception or some
|
|
/// other situation in which we have captured the actual program counter.
|
|
///
|
|
/// These can be directly symbolicated, as-is, with no adjustment.
|
|
case programCounter(Address)
|
|
|
|
/// A return address.
|
|
///
|
|
/// Corresponds to a normal function call.
|
|
///
|
|
/// Requires adjustment when symbolicating for a backtrace, because it
|
|
/// points at the address after the one that triggered the child frame.
|
|
case returnAddress(Address)
|
|
|
|
/// An async resume point.
|
|
///
|
|
/// Corresponds to an `await` in an async task.
|
|
///
|
|
/// Can be directly symbolicated, as-is.
|
|
case asyncResumePoint(Address)
|
|
|
|
/// Indicates a discontinuity in the backtrace.
|
|
///
|
|
/// This occurs when you set a limit and a minimum number of frames at
|
|
/// the top. For example, if you set a limit of 10 frames and a minimum
|
|
/// of 4 top frames, but the backtrace generated 100 frames, you will see
|
|
///
|
|
/// 0: frame 100 <----- bottom of call stack
|
|
/// 1: frame 99
|
|
/// 2: frame 98
|
|
/// 3: frame 97
|
|
/// 4: frame 96
|
|
/// 5: ... <----- omittedFrames(92)
|
|
/// 6: frame 3
|
|
/// 7: frame 2
|
|
/// 8: frame 1
|
|
/// 9: frame 0 <----- top of call stack
|
|
///
|
|
/// Note that the limit *includes* the discontinuity.
|
|
///
|
|
/// This is good for handling cases involving deep recursion.
|
|
case omittedFrames(Int)
|
|
|
|
/// Indicates a discontinuity of unknown length.
|
|
///
|
|
/// This can only be present at the end of a backtrace; in other cases
|
|
/// we will know how many frames we have omitted. For instance,
|
|
///
|
|
/// 0: frame 100 <----- bottom of call stack
|
|
/// 1: frame 99
|
|
/// 2: frame 98
|
|
/// 3: frame 97
|
|
/// 4: frame 96
|
|
/// 5: ... <----- truncated
|
|
case truncated
|
|
|
|
/// The program counter, without any adjustment.
|
|
public var originalProgramCounter: Address {
|
|
switch self {
|
|
case let .returnAddress(addr):
|
|
return addr
|
|
case let .programCounter(addr):
|
|
return addr
|
|
case let .asyncResumePoint(addr):
|
|
return addr
|
|
case .omittedFrames, .truncated:
|
|
return 0
|
|
}
|
|
}
|
|
|
|
/// The adjusted program counter to use for symbolication.
|
|
public var adjustedProgramCounter: Address {
|
|
switch self {
|
|
case let .returnAddress(addr):
|
|
return addr - 1
|
|
case let .programCounter(addr):
|
|
return addr
|
|
case let .asyncResumePoint(addr):
|
|
return addr
|
|
case .omittedFrames, .truncated:
|
|
return 0
|
|
}
|
|
}
|
|
|
|
/// A textual description of this frame.
|
|
public var description: String {
|
|
switch self {
|
|
case let .programCounter(addr):
|
|
return "\(hex(addr))"
|
|
case let .returnAddress(addr):
|
|
return "\(hex(addr)) [ra]"
|
|
case let .asyncResumePoint(addr):
|
|
return "\(hex(addr)) [async]"
|
|
case .omittedFrames, .truncated:
|
|
return "..."
|
|
}
|
|
}
|
|
}
|
|
|
|
extension RichFrame: LimitableElement {
|
|
// LimitableElement wants to call this "omitted"
|
|
public static func omitted(_ count: Int) -> Self {
|
|
return .omittedFrames(count)
|
|
}
|
|
}
|
|
|
|
extension Backtrace.Frame {
|
|
init<T>(_ frame: RichFrame<T>) {
|
|
switch frame {
|
|
case let .returnAddress(addr):
|
|
self = .returnAddress(Backtrace.Address(addr)!)
|
|
case let .programCounter(addr):
|
|
self = .programCounter(Backtrace.Address(addr)!)
|
|
case let .asyncResumePoint(addr):
|
|
self = .asyncResumePoint(Backtrace.Address(addr)!)
|
|
case let .omittedFrames(count):
|
|
self = .omittedFrames(count)
|
|
case .truncated:
|
|
self = .truncated
|
|
}
|
|
}
|
|
}
|