http://lxr.free-electrons.com/source/tools/perf/util/symbol-elf.c#L810
RTTI与type_info
C++在编译时开启RTTI(Run-Time Type Identification,通过运行时类型识别)特性时,可以在代码中使用typeid操作符(当然还需要包含<typeinfo>),此符号可以对一个变量或者一个类名使用,返回一个type_info对象的引用。编译时会为每种使用到RTTI的特性的C++类都建立一个唯一的type_info对象,并且会包含继承关系,dynamic_cast便是根据这个对象来判断某个基类对象的指针能否向下转换成子类对象的指针。下面为一个使用typeid的例子:
- #include <iostream> #include <string>
- #include <typeinfo>
- using namespace std;
- int main()
- {
- string s;
- if(typeid(s) == typeid(string))
- {
- cout<<"same type"<<endl;
- }
- else
- {
- cout<<"different type"<<endl;
- }
- return 0;
- }
mangle
但是我们今天关注的不是RTTI,而是关注与通过type_info获取到的名称信息,type_info有一个name()的方法,返回const char*,但是这个name到底是什么在C++规范中没有限定,因此不同编译器返回的结果不同,例如下面的代码:
cout<<typeid(std::string)<<endl;
如果使用vc编译器进行编译,将返回:
class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >
而g++编译执行时返回的却是:
Ss
后者很难理解,因为这是mangle后的符号名,而VC编译器返回的是demangle后的结果。使用C++的类与函数编译成obj文件后,都是使用mangle后的符号名。例如:假如我们编译了某个linux静态库,可以用nm工具查看其内部包含接口的符号(windows下可以使用dumpbin):
nm libmyfunc.a
其会返回许多mangle后的符号名,它们其实就是我们在库中编写的函数接口。
如何将这类符号名转换为可读的名称呢?其实不同编译器都提供了“解析”函数,我们可以如下编码:
- #include <typeinfo>
- #include <string>
- #ifdef _MSC_VER
- #ifndef WIN32_LEAN_AND_MEAN
- #define WIN32_LEAN_AND_MEAN
- #endif
- #ifndef _WIN32_WINNT
- #define _WIN32_WINNT 0x0501
- #endif
- #include <windows.h>
- #include <Dbghelp.h>
- std::string CxxDemangle(const char* name)
- {
- char buffer[1024];
- DWORD length = UnDecorateSymbolName(name, buffer, sizeof(buffer), 0);
- if (length > 0)
- return std::string(buffer, length);
- else
- return name;
- }
- #pragma comment(lib, "DbgHelp")
- #elif defined __GNUC__
- #include <cxxabi.h>
- std::string CxxDemangle(const char* name)
- {
- char buffer[1024] = {0};
- size_t size = sizeof(buffer);
- int status;
- char *ret;
- if (ret = abi::__cxa_demangle(name, buffer, &size, &status))
- return std::string(ret);
- else
- return name;
- }
- #endif
- #include <iostream>
- #include <string>
- #include <typeinfo>
- using namespace std;
- int main()
- {
- string s;
- if(typeid(s) == typeid(string))
- cout<<typeid(std::string).name()<<endl;
- cout<<CxxDemangle(typeid(std::string).name())<<endl;
- return 0;
- }
上面的CxxDemangle函数便可以用来解析符号名。
关于获取stacktrace以及demangle等相关技术可以参看glog、google perftools等相关开源项目的代码