Skip to content

Instantly share code, notes, and snippets.

Forked from harlanhaskins/trace.swift
Created August 20, 2021 04:56
Show Gist options
  • Save Guang1234567/5280a3524cb36150f7a9932b1f11d9ee to your computer and use it in GitHub Desktop.
Save Guang1234567/5280a3524cb36150f7a9932b1f11d9ee 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 {
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!
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)
return demangledName
return mangledName
/// backtrace is included on macOS and Linux, with the same ABI.
func backtrace(_: UnsafeMutablePointer<UnsafeMutableRawPointer?>!, _: UInt32) -> UInt32
Copy link

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