abi::__cxa_demangle 无法分解符号?
abi::__cxa_demangle cannot demangle symbols?
我不确定为什么这无法分解符号:
#include <cxxabi.h>
void _debugBacktrace(code_part part)
{
#if defined(WZ_OS_LINUX) && defined(__GLIBC__)
void *btv[20];
unsigned num = backtrace(btv, sizeof(btv) / sizeof(*btv));
char **btc = backtrace_symbols(btv, num);
unsigned i;
char buffer[255];
for (i = 1; i + 2 < num; ++i)
{
int status = -1;
size_t demangledLen = 0;
memset(buffer, 0, 255);
char *readableName = abi::__cxa_demangle(btc[i], buffer, &demangledLen, &status);
if (status == 0)
{
_debug(0, part, "BT", "%s", readableName);
}
else
{
_debug(0, part, "BT", "%s [status: %i]", btc[i], status);
}
}
free(btc);
#else
// debugBacktrace not implemented.
#endif
}
标准输出:
error |02:25:21: [BT:0] ./src/warzone2100(_ZNK5EcKey4signEPKvm+0x98) [0x16405da] [status: -2]
error |02:25:21: [BT:0] ./src/warzone2100(_Z8recvPing8NETQUEUE+0x1ab) [0x126bc2d] [status: -2]
error |02:25:21: [BT:0] ./src/warzone2100(_ZN27WzMultiplayerOptionsTitleUI21frontendMultiMessagesEb+0x7d9) [0x11ce219] [status: -2]
error |02:25:21: [BT:0] ./src/warzone2100(_ZN27WzMultiplayerOptionsTitleUI3runEv+0x45) [0x11cf32b] [status: -2]
error |02:25:21: [BT:0] ./src/warzone2100(_Z9titleLoopv+0x1aa) [0x1480b35] [status: -2]
error |02:25:21: [BT:0] ./src/warzone2100() [0x1169cbc] [status: -2]
...
...
### BUT this works?
> addr2line -f 0x16405da -C -e ./src/warzone2100
EcKey::sign(void const*, unsigned long) const
/home/docker/code/lib/framework/crc.cpp:284
在 docker 下编译 (C++11) 使用:
docker@b12fbaed9c6c:~/code> g++ --version
g++ (SUSE Linux) 11.2.1 20210816 [revision 056e324ce46a7924b5cf10f61010cf9dd2ca10e9]
docker@b12fbaed9c6c:~/code> ld --version
GNU ld (GNU Binutils; openSUSE Tumbleweed) 2.37.20210803-1
在主机上执行:
> g++ --version
g++ (SUSE Linux) 11.2.1 20220103 [revision d4a1d3c4b377f1d4acb34fe1b55b5088a3f293f6]
> ld -version
GNU ld (GNU Binutils; openSUSE Tumbleweed) 2.37.20211112-3
一方面,您没有正确调用 __cxa_demangle
。 Documentation 说:
output_buffer
A region of memory, allocated with malloc, of *length
bytes, into which the demangled name is stored. If output_buffer
is not long enough, it is expanded using realloc
. output_buffer
may instead be NULL
; in that case, the demangled name is placed in a region of memory allocated with malloc
.
您传递的是 堆栈 buffer
。摆脱它(和毫无意义的 memset
),改为这样做:
for (i = 1; i + 2 < num; ++i)
{
int status = -1;
char *readableName = abi::__cxa_demangle(btc[i], NULL, NULL, &status);
if (status == 0)
{
_debug(0, part, "BT", "%s", readableName);
}
else
{
_debug(0, part, "BT", "%s [status: %i]", btc[i], status);
}
free(readableName);
}
更新:
第二个问题是,您似乎期望 __cxa_demangle()
会忽略任何不属于损坏名称的字符,并分解其余的字符。 (您没有显示 btc[i]
的实际内容是什么,但从输出来看它似乎包含 ./src/warzone2100(_ZNK5EcKey4signEPKvm+0x98) [0x16405da]
之类的字符串)。
(Re-reading你贴的代码,btc[i]
来自backtrace_symbols
,也就是documented到return的函数
名称,函数的十六进制偏移量,以及实际的 return 地址,所以肯定会有一些“额外”的东西 __cxa_demangle()
不期望。)
如以下测试所示,__cxa_demangle()
不会 忽略任何内容;它需要损坏的名称,而不是“包含损坏名称的东西”。
#include <cxxabi.h>
#include <string.h>
#include <array>
#include <iostream>
int main()
{
const std::array<const char *, 5> bt = {
"./src/warzone2100(_ZNK5EcKey4signEPKvm+0x98) [0x16405da]",
"./src/warzone2100(_Z8recvPing8NETQUEUE+0x1ab) [0x126bc2d]",
"./src/warzone2100(_ZN27WzMultiplayerOptionsTitleUI21frontendMultiMessagesEb+0x7d9) [0x11ce219]",
"./src/warzone2100(_ZN27WzMultiplayerOptionsTitleUI3runEv+0x45) [0x11cf32b]",
"./src/warzone2100(_Z9titleLoopv+0x1aa) [0x1480b35]",
};
std::cout << "Wrong way:" << std::endl << std::endl;
for (const char* p : bt) {
int status;
char *demangled = abi::__cxa_demangle(p, NULL, NULL, &status);
std::cout << p << " " << status << std::endl;
free(demangled);
}
auto trim = [](const char *in, char *out) {
const char *begin = strchr(in, '_');
const char *end = strchr(begin, '+');
memcpy(out, begin, end - begin);
out[end - begin] = '[=11=]';
};
std::cout << std::endl << "Right way:" << std::endl << std::endl;
for (const char* p : bt) {
int status;
char buf[1024];
trim(p, buf);
char *demangled = abi::__cxa_demangle(buf, NULL, NULL, &status);
std::cout << buf << " -> " << demangled << " " << status << std::endl;
free(demangled);
}
}
使用 (Debian 11.2.0-14)
,我得到:
g++ -g foo.cc && ./a.out
Wrong way:
./src/warzone2100(_ZNK5EcKey4signEPKvm+0x98) [0x16405da] -2
./src/warzone2100(_Z8recvPing8NETQUEUE+0x1ab) [0x126bc2d] -2
./src/warzone2100(_ZN27WzMultiplayerOptionsTitleUI21frontendMultiMessagesEb+0x7d9) [0x11ce219] -2
./src/warzone2100(_ZN27WzMultiplayerOptionsTitleUI3runEv+0x45) [0x11cf32b] -2
./src/warzone2100(_Z9titleLoopv+0x1aa) [0x1480b35] -2
Right way:
_ZNK5EcKey4signEPKvm -> EcKey::sign(void const*, unsigned long) const 0
_Z8recvPing8NETQUEUE -> recvPing(NETQUEUE) 0
_ZN27WzMultiplayerOptionsTitleUI21frontendMultiMessagesEb -> WzMultiplayerOptionsTitleUI::frontendMultiMessages(bool) 0
_ZN27WzMultiplayerOptionsTitleUI3runEv -> WzMultiplayerOptionsTitleUI::run() 0
_Z9titleLoopv -> titleLoop() 0
我不确定为什么这无法分解符号:
#include <cxxabi.h>
void _debugBacktrace(code_part part)
{
#if defined(WZ_OS_LINUX) && defined(__GLIBC__)
void *btv[20];
unsigned num = backtrace(btv, sizeof(btv) / sizeof(*btv));
char **btc = backtrace_symbols(btv, num);
unsigned i;
char buffer[255];
for (i = 1; i + 2 < num; ++i)
{
int status = -1;
size_t demangledLen = 0;
memset(buffer, 0, 255);
char *readableName = abi::__cxa_demangle(btc[i], buffer, &demangledLen, &status);
if (status == 0)
{
_debug(0, part, "BT", "%s", readableName);
}
else
{
_debug(0, part, "BT", "%s [status: %i]", btc[i], status);
}
}
free(btc);
#else
// debugBacktrace not implemented.
#endif
}
标准输出:
error |02:25:21: [BT:0] ./src/warzone2100(_ZNK5EcKey4signEPKvm+0x98) [0x16405da] [status: -2]
error |02:25:21: [BT:0] ./src/warzone2100(_Z8recvPing8NETQUEUE+0x1ab) [0x126bc2d] [status: -2]
error |02:25:21: [BT:0] ./src/warzone2100(_ZN27WzMultiplayerOptionsTitleUI21frontendMultiMessagesEb+0x7d9) [0x11ce219] [status: -2]
error |02:25:21: [BT:0] ./src/warzone2100(_ZN27WzMultiplayerOptionsTitleUI3runEv+0x45) [0x11cf32b] [status: -2]
error |02:25:21: [BT:0] ./src/warzone2100(_Z9titleLoopv+0x1aa) [0x1480b35] [status: -2]
error |02:25:21: [BT:0] ./src/warzone2100() [0x1169cbc] [status: -2]
...
...
### BUT this works?
> addr2line -f 0x16405da -C -e ./src/warzone2100
EcKey::sign(void const*, unsigned long) const
/home/docker/code/lib/framework/crc.cpp:284
在 docker 下编译 (C++11) 使用:
docker@b12fbaed9c6c:~/code> g++ --version
g++ (SUSE Linux) 11.2.1 20210816 [revision 056e324ce46a7924b5cf10f61010cf9dd2ca10e9]
docker@b12fbaed9c6c:~/code> ld --version
GNU ld (GNU Binutils; openSUSE Tumbleweed) 2.37.20210803-1
在主机上执行:
> g++ --version
g++ (SUSE Linux) 11.2.1 20220103 [revision d4a1d3c4b377f1d4acb34fe1b55b5088a3f293f6]
> ld -version
GNU ld (GNU Binutils; openSUSE Tumbleweed) 2.37.20211112-3
一方面,您没有正确调用 __cxa_demangle
。 Documentation 说:
output_buffer
A region of memory, allocated with malloc, of*length
bytes, into which the demangled name is stored. Ifoutput_buffer
is not long enough, it is expanded usingrealloc
.output_buffer
may instead beNULL
; in that case, the demangled name is placed in a region of memory allocated withmalloc
.
您传递的是 堆栈 buffer
。摆脱它(和毫无意义的 memset
),改为这样做:
for (i = 1; i + 2 < num; ++i)
{
int status = -1;
char *readableName = abi::__cxa_demangle(btc[i], NULL, NULL, &status);
if (status == 0)
{
_debug(0, part, "BT", "%s", readableName);
}
else
{
_debug(0, part, "BT", "%s [status: %i]", btc[i], status);
}
free(readableName);
}
更新:
第二个问题是,您似乎期望 __cxa_demangle()
会忽略任何不属于损坏名称的字符,并分解其余的字符。 (您没有显示 btc[i]
的实际内容是什么,但从输出来看它似乎包含 ./src/warzone2100(_ZNK5EcKey4signEPKvm+0x98) [0x16405da]
之类的字符串)。
(Re-reading你贴的代码,btc[i]
来自backtrace_symbols
,也就是documented到return的函数
名称,函数的十六进制偏移量,以及实际的 return 地址,所以肯定会有一些“额外”的东西 __cxa_demangle()
不期望。)
如以下测试所示,__cxa_demangle()
不会 忽略任何内容;它需要损坏的名称,而不是“包含损坏名称的东西”。
#include <cxxabi.h>
#include <string.h>
#include <array>
#include <iostream>
int main()
{
const std::array<const char *, 5> bt = {
"./src/warzone2100(_ZNK5EcKey4signEPKvm+0x98) [0x16405da]",
"./src/warzone2100(_Z8recvPing8NETQUEUE+0x1ab) [0x126bc2d]",
"./src/warzone2100(_ZN27WzMultiplayerOptionsTitleUI21frontendMultiMessagesEb+0x7d9) [0x11ce219]",
"./src/warzone2100(_ZN27WzMultiplayerOptionsTitleUI3runEv+0x45) [0x11cf32b]",
"./src/warzone2100(_Z9titleLoopv+0x1aa) [0x1480b35]",
};
std::cout << "Wrong way:" << std::endl << std::endl;
for (const char* p : bt) {
int status;
char *demangled = abi::__cxa_demangle(p, NULL, NULL, &status);
std::cout << p << " " << status << std::endl;
free(demangled);
}
auto trim = [](const char *in, char *out) {
const char *begin = strchr(in, '_');
const char *end = strchr(begin, '+');
memcpy(out, begin, end - begin);
out[end - begin] = '[=11=]';
};
std::cout << std::endl << "Right way:" << std::endl << std::endl;
for (const char* p : bt) {
int status;
char buf[1024];
trim(p, buf);
char *demangled = abi::__cxa_demangle(buf, NULL, NULL, &status);
std::cout << buf << " -> " << demangled << " " << status << std::endl;
free(demangled);
}
}
使用 (Debian 11.2.0-14)
,我得到:
g++ -g foo.cc && ./a.out
Wrong way:
./src/warzone2100(_ZNK5EcKey4signEPKvm+0x98) [0x16405da] -2
./src/warzone2100(_Z8recvPing8NETQUEUE+0x1ab) [0x126bc2d] -2
./src/warzone2100(_ZN27WzMultiplayerOptionsTitleUI21frontendMultiMessagesEb+0x7d9) [0x11ce219] -2
./src/warzone2100(_ZN27WzMultiplayerOptionsTitleUI3runEv+0x45) [0x11cf32b] -2
./src/warzone2100(_Z9titleLoopv+0x1aa) [0x1480b35] -2
Right way:
_ZNK5EcKey4signEPKvm -> EcKey::sign(void const*, unsigned long) const 0
_Z8recvPing8NETQUEUE -> recvPing(NETQUEUE) 0
_ZN27WzMultiplayerOptionsTitleUI21frontendMultiMessagesEb -> WzMultiplayerOptionsTitleUI::frontendMultiMessages(bool) 0
_ZN27WzMultiplayerOptionsTitleUI3runEv -> WzMultiplayerOptionsTitleUI::run() 0
_Z9titleLoopv -> titleLoop() 0