解决MSVC问题

时间:2012-12-08 12:59:29

标签: c++ winapi

我如何在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 个答案:

答案 0 :(得分:12)

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"

获取demangled名称的另一种方法是使用/ FAsc /FAyour_source.asm编译器选项,它将生成程序集列表,其中每个受损名称都使用它的解码名称进行评论。请参阅This link for reference

答案 1 :(得分:6)

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

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

1)跳过错位名称中的前导句点(即从'?'开始) 2)而不是0,使用标志值0x2800(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)

答案 2 :(得分:1)

UndecorateSymbolName也不能满足我的期望。如果要迭代结构或类的成员,请使用boost fusion在C ++中实现反射。

答案 3 :(得分:1)

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