MSVC 中的拆解
Posted
技术标签:
【中文标题】MSVC 中的拆解【英文标题】:Demangling in MSVC 【发布时间】:2012-12-08 12:59:28 【问题描述】:如何在 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 函数,但我找不到任何关于它的示例。是在哪个头文件中定义的?
【问题讨论】:
UnDecorateSymbolName 功能的能力有限。它不能取消装饰每个名字。最好的办法是获取最新的 dbghelp.dll。 @fefe 我在哪里可以看到支持符号的完整列表以使用此功能进行解构? 我不知道。我对项目列表文件中的一堆符号尝试了这个功能,其中一些从未被修饰过。升级 dbghelp.dll 会有所帮助,但并非所有这些都没有修饰。 您可以使用 Visual Studio 命令提示符中的 undname.exe 实用程序。它还会告诉你这个乱七八糟的名字毫无意义。 当然不是重点。无论你做什么,你都不能神奇地破解坏名字。垃圾进垃圾出。至少记录下你是如何得到这个名字的。具体说明编译器版本、实际声明以及您为读取名称所做的操作。 【参考方案1】: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
编译器选项,它会生成程序集列表,其中每个被改名的名称都用它的去错名称进行注释。见This link for reference。
【讨论】:
对于 Visual Studio 2019,启动 Visual Studio 开发人员命令提示符。这将打开一个知道 undname 实用程序位置的命令提示符,因此您可以使用 undname 实用程序而无需在文件夹名称前加上前缀。在我的 VS2019 系统中,undname 实用程序位于 C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.27.29110\bin\HostX86\x86\undname.EXE . 在我的VS2019系统中,undname也在C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\BIN\undname.EXE,【参考方案2】:似乎UndecorateSymbolName
/__unDName
无法处理函数本地名称。如果您将类定义移至全局范围,.name()
将返回已解构的名称(使用 .raw_name()
获取已解构的名称)。
要手动分解(全局)原始名称,您需要对代码进行两处更改:
1) 跳过损坏名称中的前导句点(即从 '?'
开始)。
2) 使用标志值 0x2800 (UNDNAME_32_BIT_DECODE | UNDNAME_TYPE_ONLY
) 代替 0。
我是从 VS2012 的 CRT 源码中发现的:
if ((pTmpUndName = __unDName(NULL, (this->_M_d_name)+1, 0,
&_malloc_base, &_free_base,
UNDNAME_32_BIT_DECODE | UNDNAME_TYPE_ONLY)) == NULL)
【讨论】:
从我的测试来看,它可以很好地处理函数本地类,它是int main()
-local 类,它有问题。您可以通过将函数本地类传递给template<typename T> T f(T t) return t;
进行测试,在目标文件上使用dumpbin /symbols
获取符号列表,然后搜索?$f@
,其中将包含函数本地类名称3 次(第三次)一个是缩写的)。我对问题本身进行了评论,以解释如何从f()
的名称中提取类名。【参考方案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@
未修饰名称:类
int __cdecl main(void)'::
2'::Foo
【讨论】:
【参考方案4】:UndecorateSymbolName 也没有按我的预期工作。如果要迭代结构或类的成员,请使用 boost fusion 在 C++ 中实现反射。
【讨论】:
以上是关于MSVC 中的拆解的主要内容,如果未能解决你的问题,请参考以下文章