11

如何在 MSVC 中对名称进行解码?gcc 中有 abi::__cxa_demangle 函数。在 MSDN 中,我找到了 UnDecorateSymbolName:

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

不幸的是,这个函数甚至不能取消装饰这样的符号:

#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';
}

输出

修饰名称:?AVFoo@?4?main@

未修饰名称:?AVFoo@?4?main@

如果我做错了?

我在某处听说过 _unDName 函数,但找不到任何示例。在哪个头文件中定义?

4

4 回答 4

18

Visual Studio 已经发布了一个名为 undname 的实用程序。对于我的 VS2010 和 VS2013 安装,它安装到 %VSINSTALL%\vc\bin 目录。对于 x64 平台,在 %VSINSTALL%\vc\amd64\bin 目录中。

示例用法是:

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"

获得去错名称的另一种方法是使用/FAsc /Faoutput.asm 编译器选项,它会生成程序集列表,其中每个错的名称都用它的去错名称进行注释。请参阅此链接以供参考

于 2014-04-27T02:52:42.463 回答
8

似乎UndecorateSymbolName/__unDName无法处理函数本地名称。如果您将类定义移动到全局范围,.name()将返回已解构的名称(用于.raw_name()获取已解构的名称)。

要手动分解(全局)原始名称,您需要对代码进行两项更改:

1) 跳过损坏名称中的前导句点(即从 开始'?')。
2) 使用标志值 0x2800 ( ) 代替 0 UNDNAME_32_BIT_DECODE | UNDNAME_TYPE_ONLY

我从 VS2012 的 CRT 资源中发现了这一点:

  if ((pTmpUndName = __unDName(NULL, (this->_M_d_name)+1, 0,
         &_malloc_base, &_free_base, 
         UNDNAME_32_BIT_DECODE | UNDNAME_TYPE_ONLY)) == NULL)
于 2013-10-28T14:41:44.610 回答
3

Visual Studio 2019 更新。

(1) typeid(instance).name() - 在请求中使用 - 已经返回未修饰的名称:在这种情况下不需要进一步的去修饰

(2) bin 文件夹中提供的命令 UNDNAME.EXE 不能正常工作,即使我们去掉初始点。例如“.?AVFoo@?1??main@@YAHXZ@”被解构为“?? int __cdecl main(void)'::2'::AVFoo”,给出了一个无效的名字AVFoo。正确的名字必须是 Foo

(3) dbghelp API UnDecorateSymbolName() 也不起作用

(4) 可以从编译器为指令 typeid() 生成的程序集中推导出正确的代码

这是一个小程序,它将正确地取消装饰所有 C++ 损坏的符号:

// 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;
}

例如:

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

修饰名称:.?AVFoo@?1??main@@YAHXZ@

未修饰名称:class int __cdecl main(void)'::2'::Foo

于 2020-04-17T09:12:38.320 回答
1

UndecorateSymbolName 也没有按我的预期工作。如果要迭代结构或类的成员,请使用 boost fusion 在 C++ 中实现反射。

于 2013-10-26T10:48:32.497 回答