Print Function Call Stack in Swift?

I'm attempting to print a function call stack in a Swift function. I'm using Swift v5.9 on a Windows 10 system.

According to this post and many others, I should use the callStackSymbols field to acquire my call stack.

I have the following example code:

import Foundation

func test()
{
    print(Thread.callStackSymbols)
}

test()

Compiling & running the code above produces the following output:

["$s10Foundation6ThreadC16callStackSymbolsSaySSGvgZ\0", "", "", "", "BaseThreadInitThunk\0", "RtlUserThreadStart\0"]

It is my understanding that this is a sequence of some sort of symbols, but I don't quite understand what they're supposed to represent. I'm assuming they're symbols standing in for the function names.

After asking on another post, I was referred to "name demangling" and this post. However, it doesn't appear that the Windows instance of Swift has access to the dlsym function, leaving me unable to load the swift_demangle function required for the name demangling.

How do I print a function call stack in Swift, and parse the stack symbols to correspond to my function names on a Windows system?

Thanks for reading my post, any guidance is appreciated.

I didn't try demangling manually but it should not be too hard. The above linked post has a link to an alternative implementation that demangles manually. You'd get "static Foundation.Thread.callStackSymbols.getter : Swift.Array<Swift.String>" in a demangled form for the first symbol. I'd be more concerned about the missing (empty) entries in that array, e.g. there 's no "test".

There is a backtracing library with a very nice API and support for async functions (details here), and I believe it also supports Windows.

You can access it using:

import _Backtracing

(Works on Xcode 15.0/Swift 5.9)

Symbol.name contains the demangled name for a symbol. Example:

import _Backtracing

print(
  try! Backtrace.capture(algorithm: .fast, limit: 1)
       .symbolicated()!
       .frames[0]
       .symbol!.name
)

Be advised:
The library hasn't been through swift-evolution yet, so it is still subject to change, and when it finally lands it will probably drop the leading underscore. So be prepared that your code may need adjustments if you update your toolchain.

Oh, and that also means it is not yet ABI stable. DO NOT use it in any apps or libraries that you ship on Apple platforms yet.

FWIW, it doesn't support Windows at present, though that is something I'd like to remedy. Also, I'll re-iterate the warning that there may be API changes. If you're just playing with it, that won't be a problem, but if you're even thinking of shipping something that depends on it… well, don't do that yet because we might break you.

2 Likes