Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Demangling in MSVC

Tags:

c++

winapi

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?

like image 949
FrozenHeart Avatar asked Dec 08 '12 12:12

FrozenHeart


3 Answers

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.

like image 184
zhaorufei Avatar answered Nov 11 '22 17:11

zhaorufei


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)
like image 8
Igor Skochinsky Avatar answered Nov 11 '22 15:11

Igor Skochinsky


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

like image 4
bilbo Avatar answered Nov 11 '22 15:11

bilbo