Skip to content

Instantly share code, notes, and snippets.

@harlanhaskins
Created October 6, 2016 17:50
Show Gist options
  • Save harlanhaskins/32831b09fe57bd2e8df25821072a43c0 to your computer and use it in GitHub Desktop.
Save harlanhaskins/32831b09fe57bd2e8df25821072a43c0 to your computer and use it in GitHub Desktop.
Pure Swift stack trace
struct StackFrame {
let symbol: String
let file: String
let address: UInt64
let symbolAddress: UInt64
var demangledSymbol: String {
return _stdlib_demangleName(symbol)
}
}
struct StackTrace {
static var frames: [StackFrame] {
var symbols = [StackFrame]()
let stackSize: UInt32 = 256
let addrs = UnsafeMutablePointer<UnsafeMutableRawPointer?>.allocate(capacity: Int(stackSize))
defer { addrs.deallocate(capacity: 256) }
let frameCount = backtrace(addrs, stackSize)
let buf = UnsafeBufferPointer(start: addrs, count: Int(frameCount))
for addr in buf {
guard let addr = addr else { continue }
var dlInfoPtr = UnsafeMutablePointer<Dl_info>.allocate(capacity: 1)
defer { dlInfoPtr.deallocate(capacity: 1) }
guard dladdr(addr, dlInfoPtr) != 0 else {
continue
}
let info = dlInfoPtr.pointee
let symbol = String(cString: info.dli_sname)
let filename = String(cString: info.dli_fname)
let symAddrValue = unsafeBitCast(info.dli_saddr, to: UInt64.self)
let addrValue = unsafeBitCast(addr, to: UInt64.self)
symbols.append(StackFrame(symbol: symbol, file: filename, address: addrValue, symbolAddress: symAddrValue))
}
return symbols
}
}
/// Here be dragons! _stdlib_demangleImpl is linked into the stdlib. Use at your own risk!
@_silgen_name("swift_demangle")
public
func _stdlib_demangleImpl(
mangledName: UnsafePointer<CChar>?,
mangledNameLength: UInt,
outputBuffer: UnsafeMutablePointer<CChar>?,
outputBufferSize: UnsafeMutablePointer<UInt>?,
flags: UInt32
) -> UnsafeMutablePointer<CChar>?
func _stdlib_demangleName(_ mangledName: String) -> String {
return mangledName.utf8CString.withUnsafeBufferPointer {
(mangledNameUTF8CStr) in
let demangledNamePtr = _stdlib_demangleImpl(
mangledName: mangledNameUTF8CStr.baseAddress,
mangledNameLength: UInt(mangledNameUTF8CStr.count - 1),
outputBuffer: nil,
outputBufferSize: nil,
flags: 0)
if let demangledNamePtr = demangledNamePtr {
let demangledName = String(cString: demangledNamePtr)
free(demangledNamePtr)
return demangledName
}
return mangledName
}
}
/// backtrace is included on macOS and Linux, with the same ABI.
@_silgen_name("backtrace")
func backtrace(_: UnsafeMutablePointer<UnsafeMutableRawPointer?>!, _: UInt32) -> UInt32
@Guang1234567
Copy link

Guang1234567 commented Aug 20, 2021

Hello harlanhaskins:

How to parse the line number of StackFrame on iOS, Linux platform? Is possible? Thanks.

https://web.stanford.edu/class/archive/cs/cs106b/cs106b.1176/lectures/27-Inheritance/code/Inheritance/lib/StanfordCPPLib/system/call_stack_gcc.cpp ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment