Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I demangle a Swift class name dynamically?

Tags:

I'm aware of the swift-demangle command line utility. I'm looking for something that will let me do this from Swift itself.

I got excited when I saw this after running :target modules dump symtab from the Swift REPL, but I don't know how to call swift_demangleSimpleClass.

module dump

It seems that there's an @asmname command that would allow calling private Swift functions, but I haven't been able to get that to work.

I'll probably just end up writing a regex-based parser for this, but calling something in the Swift framework itself seems a bit safer.

like image 244
jpsim Avatar asked Jun 20 '14 07:06

jpsim


1 Answers

Swift 5

You can use Swift's swift_demangle function to demangle names but it's not exported by default so you need to import first:

import Darwin

typealias Swift_Demangle = @convention(c) (_ mangledName: UnsafePointer<UInt8>?,
                                           _ mangledNameLength: Int,
                                           _ outputBuffer: UnsafeMutablePointer<UInt8>?,
                                           _ outputBufferSize: UnsafeMutablePointer<Int>?,
                                           _ flags: UInt32) -> UnsafeMutablePointer<Int8>?

func swift_demangle(_ mangled: String) -> String? {
    let RTLD_DEFAULT = dlopen(nil, RTLD_NOW)
    if let sym = dlsym(RTLD_DEFAULT, "swift_demangle") {
        let f = unsafeBitCast(sym, to: Swift_Demangle.self)
        if let cString = f(mangled, mangled.count, nil, nil, 0) {
            defer { cString.deallocate() }
            return String(cString: cString)
        }
    }
    return nil
}

// How to use
if let s = swift_demangle("$s20MyPlayground_Sources4TestC4testSSyF") {
    print(s) // MyPlayground_Sources.Test.test() -> Swift.String
}

like image 76
iUrii Avatar answered Sep 17 '22 06:09

iUrii