undname: A Microsoft symbol demangler
https://crates.io/crates/undname
What is this?
undname is new library written entirely in Rust, whose purpose is to turn symbols mangled by the MSVC compiler (e.g. ?world@@YA?AUhello@@XZ) into their demangled/human readable form (e.g. struct hello __cdecl world(void)).
Why did you write this?
I work a lot with mangled symbols, and I am unsatisfied with existing solutions available to Rust users:
The first option is to use the classic
UnDecorateSymbolNamefrom Win32's Dbghelp api. The issue with this avenue is as follows:- Passing mangled strings to
UnDecorateSymbolNamerequires you to convert their encoding to utf-16. Mangled strings can come from a wide variety of sources, and while it is common in the modern era for these strings to be utf-8 encoded, that is not always the case. Often their encoding is ambiguous, and you just have to hope for the best. UnDecorateSymbolNameis notoriously buggy. It does not play nicely with mangled strings from all sources (e.g. it behaves differently depending on whether the mangled string comes from an image file, or from a pdb), it often misses things that are encoded in the mangled string (e.g. Microsoft'sundnamedemangles?x@@3QEAHEAasint * __ptr64 __ptr64 x, when the correct demangling isint *const x), and its flags sometimes do not play well with each other.- Dbghelp is notoriously one of the remaining single-threaded Win32 apis, and it is very hard/impossible to synchronize access across crates.
- Passing mangled strings to
The second option is
msvc-demangler, which while being a native Rust crate, is still deficient for the following reasons:- Inputs to the demangle method are required to be utf-8. For the same reasons as listed for
UnDecorateSymbolName, this is a major point of contention when dealing with mangled strings from ambiguous sources. Having written my own demangler, I can say that there really is no reason that an explicit encoding is required to demangle strings, other than the convenience of using the built-instrtype. msvc-demangleris missing support for a wide variety of mangled strings, and I legitimately need support for these things. Take the mangled name.?AVtype_info@@for example. Microsoft'sundnamecan demangle it as follows:undname 0x2000 ?AVtype_info@@=>class type_info. Howevermsvc-demangleris completely incapable of demangling them. For those who are not in the know, Microsoft's implementation ofstd::type_info::nameworks by passing strings just like these directly toUnDecorateSymbolName, so they're very common to find in image files. It's startling to see a demangler not support these strings.
- Inputs to the demangle method are required to be utf-8. For the same reasons as listed for
However, while these options may be the only ones available to Rust users, there are still more options available outside of the Rust ecosystem. In particular, I know of llvm-undname which is LLVM's own implementation of a Microsoft symbol demangler, and it is the single most accurate, freely available implementation I know of. The only caveat being that it is a part of the LLVM ecosystem, and written in C++ to boot. I am no stranger to writing bindings to C++, but LLVM is a behemoth to compile, and would integrate awkwardly with any Rust code. Thus, I set out to port LLVM's implementation (a design that heavily leverages inheritance for polymorphism) to Rust (a language without inheritance). The result is this library. My benchmarks show undname performs slightly faster than msvc-demangler, while having a much greater level of support for the wide variety of mangled string formats available in wild. It also supports most of the flags you can pass to UnDecorateSymbolName, so it is a fairly frictionless drop-in replacement for existing applications wishing to migrate from Dbghelp.
So why would I use this?
The primary reason to use this library over its contemporaries is its accuracy. As mentioned in my gripes with UnDecorateSymbolName, Microsoft's own implementation is difficult to work with, and fails to pick up on things present in the mangled string. This library has no such issues. Additionally, this library boasts excellent support for the wide variety of mangled strings you may find in the wild, unlike msvc-demangler which lacks support for even common cases. Finally, my benchmarks show this library outperforms the competition both in one-off, and bulk demangling applications. The only caveat is this library is available under the Apache 2.0 license only, since it is such a close port of LLVM's implementation.