Linux 如何使 backtrace()/backtrace_symbols() 打印函数名称?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6934659/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to make backtrace()/backtrace_symbols() print the function names?
提问by Lyke
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:
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] ----------------------
I'd want the first 2 items to also show the function names, foo
and main
我希望前 2 个项目也显示函数名称,foo
并且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;
}
回答by Matthew Slattery
The symbols are taken from the dynamic symbol table; you need the -rdynamic
option to gcc
, which makes it pass a flag to the linker which ensures that allsymbols are placed in the table.
符号取自动态符号表;您需要-rdynamic
选项 to gcc
,这使其将标志传递给链接器,以确保所有符号都放置在表中。
(See the Link Optionspage of the GCC manual, and / or the Backtracespage of the glibc manual.)
回答by Nemo
Use the addr2line commandto map executable addresses to source code filename+line number. Give the -f
option to get function names as well.
使用addr2line 命令将可执行地址映射到源代码文件名+行号。还-f
提供获取函数名称的选项。
Alternatively, try libunwind.
或者,尝试libunwind。
回答by Erwan Legrand
The excellent Libbacktrace by Ian Lance Taylor solves this issue. It handles stack unwinding and supports both ordinary ELF symbols and DWARF debugging symbols.
Ian Lance Taylor 出色的 Libbacktrace 解决了这个问题。它处理堆栈展开并支持普通 ELF 符号和 DWARF 调试符号。
Libbacktrace does not require exporting all symbols, which would be ugly, and ASLR does not break it.
Libbacktrace 不需要导出所有符号,这会很丑陋,而且 ASLR 不会破坏它。
Libbacktrace was originally part of the GCC distribution. Now, a standalone version can be found on Github:
Libbacktrace 最初是 GCC 发行版的一部分。现在,可以在 Github 上找到一个独立版本:
回答by Billg
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)
如果 ret == -1 和 errno 是 EINTER,则顶部的答案有一个错误,您应该再试一次,但不要将 ret 视为已复制(如果您不喜欢它,则不会为此创建帐户)
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) {
if (errno != EINTR))
break;
//else
continue;
}
buf += (size_t) ret;
len -= (size_t) ret;
}
}