如何让 backtrace()/backtrace_symbols() 打印函数名称?
Linux 特定的 backtrace()
和 backtrace_symbols()
允许您生成程序的调用跟踪。但是,它只打印函数地址,而不打印我的程序的名称。我怎样才能让他们也打印函数名称?我尝试使用 -g
以及 -ggdb
编译程序。下面的测试用例仅打印以下内容:
BACKTRACE ------------ ./a.out() [0x8048616] ./a.out() [0x8048623] /lib/libc.so.6(__libc_start_main+0xf3) [0x4a937413] ./a.out() [0x8048421] ----------------------
我希望前两项也显示函数名称, foo
和 main
代码:
#include <execinfo.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
static void full_write(int fd, const char *buf, size_t len)
{
while (len > 0) {
ssize_t ret = write(fd, buf, len);
if ((ret == -1) && (errno != EINTR))
break;
buf += (size_t) ret;
len -= (size_t) ret;
}
}
void print_backtrace(void)
{
static const char start[] = "BACKTRACE ------------\n";
static const char end[] = "----------------------\n";
void *bt[1024];
int bt_size;
char **bt_syms;
int i;
bt_size = backtrace(bt, 1024);
bt_syms = backtrace_symbols(bt, bt_size);
full_write(STDERR_FILENO, start, strlen(start));
for (i = 1; i < bt_size; i++) {
size_t len = strlen(bt_syms[i]);
full_write(STDERR_FILENO, bt_syms[i], len);
full_write(STDERR_FILENO, "\n", 1);
}
full_write(STDERR_FILENO, end, strlen(end));
free(bt_syms);
}
void foo()
{
print_backtrace();
}
int main()
{
foo();
return 0;
}
The Linux specific backtrace()
and backtrace_symbols()
allows you to produce a call trace of the program. However, it only prints function addresses, not their names for my program. How can I make them print the function names as well ? I've tried compiling the program with -g
as well as -ggdb
. The test case below just prints this:
BACKTRACE ------------ ./a.out() [0x8048616] ./a.out() [0x8048623] /lib/libc.so.6(__libc_start_main+0xf3) [0x4a937413] ./a.out() [0x8048421] ----------------------
I'd want the first 2 items to also show the function names, foo
and main
Code:
#include <execinfo.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
static void full_write(int fd, const char *buf, size_t len)
{
while (len > 0) {
ssize_t ret = write(fd, buf, len);
if ((ret == -1) && (errno != EINTR))
break;
buf += (size_t) ret;
len -= (size_t) ret;
}
}
void print_backtrace(void)
{
static const char start[] = "BACKTRACE ------------\n";
static const char end[] = "----------------------\n";
void *bt[1024];
int bt_size;
char **bt_syms;
int i;
bt_size = backtrace(bt, 1024);
bt_syms = backtrace_symbols(bt, bt_size);
full_write(STDERR_FILENO, start, strlen(start));
for (i = 1; i < bt_size; i++) {
size_t len = strlen(bt_syms[i]);
full_write(STDERR_FILENO, bt_syms[i], len);
full_write(STDERR_FILENO, "\n", 1);
}
full_write(STDERR_FILENO, end, strlen(end));
free(bt_syms);
}
void foo()
{
print_backtrace();
}
int main()
{
foo();
return 0;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
符号取自动态符号表;您需要
gcc
的-rdynamic
选项,这使得它将一个标志传递给链接器,以确保所有符号都放置在表中。(请参阅 链接选项 页面.org/onlinedocs/gcc/">GCC 手册,和/或 Backtraces< /a> glibc 手册。)
The symbols are taken from the dynamic symbol table; you need the
-rdynamic
option togcc
, which makes it pass a flag to the linker which ensures that all symbols are placed in the table.(See the Link Options page of the GCC manual, and / or the Backtraces page of the glibc manual.)
使用addr2line命令将可执行文件地址映射到源代码文件名+行号。提供
-f
选项也可以获取函数名称。或者,尝试 libunwind。
Use the addr2line command to map executable addresses to source code filename+line number. Give the
-f
option to get function names as well.Alternatively, try libunwind.
Ian Lance Taylor 出色的 Libbacktrace 解决了这个问题。它处理堆栈展开并支持普通 ELF 符号和 DWARF 调试符号。
Libbacktrace 不需要导出所有符号,这会很难看,并且 ASLR 不会破坏它。
Libbacktrace 最初是 GCC 发行版的一部分。现在,可以在 Github 上找到独立版本:
https://github.com/ianlancetaylor/libbacktrace
The excellent Libbacktrace by Ian Lance Taylor solves this issue. It handles stack unwinding and supports both ordinary ELF symbols and DWARF debugging symbols.
Libbacktrace does not require exporting all symbols, which would be ugly, and ASLR does not break it.
Libbacktrace was originally part of the GCC distribution. Now, a standalone version can be found on Github:
https://github.com/ianlancetaylor/libbacktrace
Boost backtrace
非常方便,因为它同时打印:
自动为您
。用法摘要:
我在以下位置提供了一个最小的可运行示例以及许多其他方法: 用 C 或 C++ 打印调用堆栈
Boost backtrace
Very convenient because it prints both:
automatically for you.
Usage summary:
I have provided a minimal runnable example for it and many other methods at: print call stack in C or C++
上面的答案有一个错误
如果 ret == -1 并且 errno 是 EINTER 你应该再试一次,但不要将 ret 算作复制
(如果你不喜欢它,就不会为此创建一个帐户)
the answer on the top has a bug
if ret == -1 and errno is EINTER you should try again, but not count ret as copied
(not going to make an account just for this, if you don't like it tough)