11

How can i demangle name in MSVC? There's abi::__cxa_demangle function in gcc. In MSDN i've found UnDecorateSymbolName:

http://msdn.microsoft.com/ru-ru/library/windows/desktop/ms681400%28v=vs.85%29.aspx

Unfortunately, this function can't undecorate even such symbol:

#include <Windows.h>
#include <DbgHelp.h>

#include <cstdlib>
#include <iostream>
#include <typeinfo>

int main()
{
    SymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS);

    if (!SymInitialize(GetCurrentProcess(), NULL, TRUE))
    {
        std::cout << "SymInitialize returned error: " << GetLastError() << '\n';
        return EXIT_FAILURE;
    }

    class Foo {};
    Foo instance;

    const char* decorated_name = typeid(instance).name();
    char undecorated_name[1024];
    if (!UnDecorateSymbolName(decorated_name, undecorated_name, sizeof(undecorated_name) / sizeof(*undecorated_name), UNDNAME_COMPLETE))
    {
        std::cout << "UnDecorateSymbolName returned error: " << GetLastError() << '\n';
        return EXIT_FAILURE;
    }

    std::cout << "Decorated name: " << decorated_name << '\n'
              << "Undecorated name: " << undecorated_name << '\n';
}

Output

Decorated name: ?AVFoo@?4?main@

Undecorated name: ?AVFoo@?4?main@

If i am doing it wrong?

I've heard somewhere about _unDName function, but i can't find any example with it. In which header file it is defined?

Community
  • 1
  • 1
FrozenHeart
  • 19,844
  • 33
  • 126
  • 242
  • The ability UnDecorateSymbolName function is limited. It cannot un-decorate every name. The best you can do is to get the latest dbghelp.dll. – fefe Dec 08 '12 at 13:03
  • @fefe Where can i see the full list of the supported symbols to demangling with this function? – FrozenHeart Dec 08 '12 at 13:06
  • I don't know. I tried this function to a bunch of symbols from the listing files of a project, some of them never get undecorated. Upgrading dbghelp.dll helps, but still not all of them got undecorated. – fefe Dec 08 '12 at 13:10
  • @fefe Am i really correctly use this function in example? – FrozenHeart Dec 08 '12 at 13:20
  • Try a function symbol: ?h@@YAXH@Z – fefe Dec 08 '12 at 13:40
  • @fefe Yes, for this example it is works – FrozenHeart Dec 08 '12 at 14:03
  • 2
    You can use the undname.exe utility from the Visual Studio Command Prompt. It will also tell you that this mangled name is meaningless. – Hans Passant Dec 08 '12 at 14:29
  • @Hans Passant I want to use it in my program always – FrozenHeart Dec 08 '12 at 14:31
  • 1
    Not the point of course. Whatever you do, you cannot magically demangle bad mangled names. Garbage in, garbage out. At least document how you got that name. Be specific about compiler version, the actual declaration and what you did to read the name. – Hans Passant Dec 08 '12 at 14:35
  • By the look of it, that particular symbol is `class \`main'::\`5'::Foo`, or something like that. It looks similar to a local static variable's scope, actually. ...I can only read it due to experimenting with the MSVC name mangler, but I figure `UNDNAME 0x2000 ?AVFoo@?4?main@` might be able to tell you what you want. – Justin Time - Reinstate Monica Apr 29 '16 at 19:39
  • Actually, now that I look at it, it looks like the undecorated name is being truncated somewhere. It should actually be something like `?AVFoo@?4??main@@YAHXZ@`, for `class \`int __cdecl main(void)'::\`5'::Foo`. Just checked, and `UnDecorateSymbolName` is able to correctly parse that. – Justin Time - Reinstate Monica Apr 29 '16 at 20:00
  • Here's a quick-and-dirty trick you can use to get the full symbol in situations like that: make a template function `template T f(T t) { return t; }`, compile the code, use `dumpbin /symbols source_file_name.obj > source_file_name.txt` to get the symbol list, and look for an hideous abomination like `??$f@VCL@?1??func@@YAXXZ@@@YA?AVCL@?1??func@@YAXXZ@V0?1??1@YAXXZ@@Z` (`f()` called with `T` as `class CL` defined in `void func()`). From this monstrosity, you can easily retrieve the function-local class' mangled name; it'll come immediately after `??$f@`, and be followed by `@@`. – Justin Time - Reinstate Monica Apr 29 '16 at 20:29
  • Alternatively, you can look for the `@@@YA`; the function-local class' mangled name will come immediately after this, and be followed by `V0`. These methods get you `VCL@?1??func@@YAXXZ@` and `?AVCL@?1??func@@YAXXZ@`, respectively, where the `?A` at the start of the latter is pointer/reference syntax and means "non-pointer/reference, non-cv-qualified". – Justin Time - Reinstate Monica Apr 29 '16 at 20:32
  • Doing this for an instance of `class Foo` defined in `int main()`, the result is (when compiled on a 32-bit system, with Studio 2010)... `??$f@VFoo@?1?main@@@YA?AVFoo@?1??main@@9@V0?1??1@9@@Z`. That's... actually pretty interesting, and explains why the name was truncated & couldn't be undecorated. `T` expanded to `VFoo@?1?main@` as a template parameter, but `?AVFoo@?1??main@@9@` as a return type. It would appear that the reason it was mangled in a way that `UnDecorateSymbolName` couldn't recognise is that `main()` is being mangled as if it were `extern "C"`. – Justin Time - Reinstate Monica Apr 29 '16 at 20:37
  • Unfortunately, since `main()` is being mangled as a C name, it loses out on all of the function information (`near`/`far` (always `near` except on 16-bit systems) & member/non-member stuff, return type, parameter list, throw-specifier (always `Z`)) that it needs to unmangle `main()` as a C++ name, which would appear to be the cause of the problem. I suspect this happens because the CRT needs to be able to latch onto the entry point, so the entry point (generally `main()`) is mangled as a C name so it can do so, although I may be wrong. – Justin Time - Reinstate Monica Apr 29 '16 at 20:54
  • It should technically be `?main@@YAHXZ` (`int __cdecl ::main(void) throw(...)`), or at least it would have to be for `UnDecorateSymbolName()` and related to parse the function-local class name properly. – Justin Time - Reinstate Monica Apr 29 '16 at 20:56

4 Answers4

22

Visual studio already shipped a utility called undname. For my VS2010 and VS2013 install, it's installed to %VSINSTALL%\vc\bin directory. And for x64 platform, in %VSINSTALL%\vc\amd64\bin directory.

The example usage is:

D:\work\VS2013>undname "?static_x@?1??getX@@YAAAUX@@XZ@4U2@A"
Microsoft (R) C++ Name Undecorator
Copyright (C) Microsoft Corporation. All rights reserved.

Undecoration of :- "?static_x@?1??getX@@YAAAUX@@XZ@4U2@A"
is :- "struct X `struct X & __cdecl getX(void)'::`2'::static_x"

Another way to get the demangled name is use /FAsc /Faoutput.asm compiler option, which will produce the assembly list, in which each mangled name is commented with it's demangled name. See This link for reference.

Orwellophile
  • 13,235
  • 3
  • 69
  • 45
zhaorufei
  • 2,045
  • 19
  • 18
  • For Visual Studio 2019, start the Visual Studio Developer Command Prompt. This opens a command prompt that knows the location of the undname utility, so you can use the undname utility without prefixing a folder name. In my VS2019 system, the undname utility is located at _C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.27.29110\bin\HostX86\x86\undname.EXE_. – Louis Strous Oct 01 '20 at 07:30
  • In my VS2019 system, undname is also at _C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\BIN\undname.EXE_, – Louis Strous Oct 01 '20 at 07:41
8

It seems UndecorateSymbolName/__unDName can't handle function-local names. If you move the class definition to the global scope, .name() will return already demangled name (use .raw_name() to get the mangled name).

To demangle the (global) raw name manually, you need two changes to your code:

1) skip the leading period in the mangled name (i.e. start at the '?').
2) instead of 0, use the flag value 0x2800 (UNDNAME_32_BIT_DECODE | UNDNAME_TYPE_ONLY).

I found this out from the CRT sources of VS2012:

  if ((pTmpUndName = __unDName(NULL, (this->_M_d_name)+1, 0,
         &_malloc_base, &_free_base, 
         UNDNAME_32_BIT_DECODE | UNDNAME_TYPE_ONLY)) == NULL)
Igor Skochinsky
  • 24,629
  • 2
  • 72
  • 109
  • 1
    From my tests, it can handle function-local classes decently, it's `int main()`-local classes it has trouble with. You can test by passing a function-local class to `template T f(T t) { return t; }`, using `dumpbin /symbols` on the object file to get the symbol list, and searching for `?$f@`, which will contain the function-local class name 3 times (the third one is abbreviated). I commented on the question itself to explain how to extract the class name from `f()`'s name. – Justin Time - Reinstate Monica Apr 29 '16 at 20:41
7

Update for Visual Studio 2019.

(1) typeid(instance).name() - used in the request - already returns the undecorated name: further demangling is not required in this case

(2) the command UNDNAME.EXE, provided in the bin folders, does not work correctly, even if we take off the initial dot. For example ".?AVFoo@?1??main@@YAHXZ@" is unmangled as " ?? int __cdecl main(void)'::2'::AVFoo", giving an invalid name AVFoo. The correct name must be Foo

(3) the dbghelp API UnDecorateSymbolName() does not work either

(4) the correct code can be deduced from the assembly generated by the compiler for the directive typeid()

Here is a little program which will undecorate correctly all the C++ mangled symbols:

// compile as: cl -W3 und.c

#include <windows.h>
#include "dbghelp.h"
#include <stdio.h>

#pragma comment(lib, "dbghelp.lib")

extern char *__unDName(char*, const char*, int, void*, void*, int);

int
main(int argc, char **argv)
{
    const char *decorated_name = 0;
    char undecorated_name[1024];

    if (argc == 2) decorated_name = argv[1];
    else {
        printf("usage: %s <decorated_name>\n", argv[0]);
        return 1;
        }

    __unDName(undecorated_name, decorated_name+1, 1024, malloc, free, 0x2800);

    printf("Decorated name: %s\n", decorated_name);
    printf("Undecorated name: %s\n", undecorated_name);
    return 0;
}

For example:

und ".?AVFoo@?1??main@@YAHXZ@"

Decorated name: .?AVFoo@?1??main@@YAHXZ@

Undecorated name: class int __cdecl main(void)'::2'::Foo

Community
  • 1
  • 1
bilbo
  • 111
  • 1
  • 3
0

UndecorateSymbolName also does not work as my expectation. If you want to iterate over members of struct or class, use boost fusion to implement reflection in C++.

Alan Yang
  • 65
  • 4