-
哄骗backtrace和backtrace_symbols函数打印调用栈信息
添加时间:2013-8-8 点击量:在头文件execinfo.h中声了然三个函数用于获取当火线程的函数调用客栈。
#include <execinfo.h>
int backtrace(void buffer, int size);
char backtrace_symbols(void const buffer, int size);
void backtrace_symbols_fd(void const buffer, int size, int fd);
man 帮助:
DESCRIPTION
backtrace() returns a backtrace for the calling program, in the array
pointed to by buffer. A backtrace is the series of currently active
function calls for the program. Each item in the array pointed to by
buffer is of type void , and is the return address the
corresponding stack frame. The size argument specifies the maximum
number of addresses that can be stored in buffer. If the backtrace
is larger than size, then the addresses corresponding to the size
most recent function calls are returned; to obtain the complete
backtrace, make sure that buffer and size are large enough.
Given the set of addresses returned by backtrace() in buffer,
backtrace_symbols() translates the addresses into an array of strings
that describe the addresses symbolically. The size argument
specifies the number of addresses in buffer. The symbolic
representation of each address consists of the function name (if this
can be determined), a hexadecimal offset into the function, and the
actual return address (in hexadecimal). The address of the array of
string pointers is returned as the function result of
backtrace_symbols(). This array is malloc(3)ed by
backtrace_symbols(), and must be freed by the caller. (The strings
pointed to by the array of pointers need not and should not be
freed.)
backtrace_symbols_fd() takes the same buffer and size arguments as
backtrace_symbols(), but instead of returning an array of strings to
the caller, it writes the strings, one per line, to the file
descriptor fd. backtrace_symbols_fd() does not call malloc(3), and
so can be employed in situations where the latter function might
fail.
int backtrace(void buffer,int size)
该函数用与获取当火线程的调用客栈,获取的信息将会被存放在buffer中,它是一个指针数组。参数 size 用来指定buffer中可以保存几许个void 元素。函数返回值是实际获取的指针个数,最大不跨越size大小在buffer中的指针实际是从客栈中获取的返回地址,每一个客栈框架有一个返回地址。
重视某些编译器的优化选项对获取正确的调用客栈有干扰,别的内联函数没有客栈框架;删除框架指针也会使无确解析客栈内容
char backtrace_symbols (void const buffer, int size)
backtrace_symbols将从backtrace函数获取的信息转化为一个字符串数组. 参数buffer应当是从backtrace函数获取的数组指针,size是该数组中的元素个数(backtrace的返回值),函数返回值是一个指向字符串数组的指针,它的大小同buffer雷同.每个字符串包含了一个相对于buffer中对应元素的可打印信息.它包含函数名,函数的偏移地址,和实际的返回地址
如今,只有应用ELF二进制格局的法度和苦处才干获取函数名称和偏移地址.在其他体系,只有16进制的返回地址能被获取.别的,你可能须要传递响应的标记给链接器,以能支撑函数名功能(比如,在应用GNU ld的体系中,你须要传递(-rdynamic))
backtrace_symbols生成的字符串都是malloc出来的,然则不要最后一个一个的free,因为backtrace_symbols是按照backtrace给出的call stack层数,一次性的malloc出来一块内存来存放成果字符串的,所以,像上方代码一样,只须要在最后,free backtrace_symbols的返回指针就OK了。这一点backtrace的manual中也是希罕提到的。
重视:若是不克不及为字符串获取足够的空间函数的返回值将会为NULL
void backtrace_symbols_fd (void const buffer, int size, int fd)
backtrace_symbols_fd与backtrace_symbols 函数具有雷同的功能,不合的是它不会给调用者返回字符串数组,而是将成果写入文件描述符为fd的文件中,每个函数对应一行.它不须要调用malloc函数,是以实用于有可能调用该函数会失败的景象。man手册中示例:
#include <execinfo.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void
myfunc3(void)
{
int j, nptrs;
#define SIZE 100
void buffer[100];
char strings;
nptrs = backtrace(buffer, SIZE);
printf(backtrace() returned %d addresses\n, nptrs);
/ The call backtrace_symbols_fd(buffer, nptrs, STDOUT_FILENO)
would produce similar output to the following: /
strings = backtrace_symbols(buffer, nptrs);
if (strings == NULL) {
perror(backtrace_symbols);
exit(EXIT_FAILURE);
}
for (j = 0; j < nptrs; j++)
printf(%s\n, strings[j]);
free(strings);
}
static void / static means dont export the symbol... /
myfunc2(void)
{
myfunc3();
}
void
myfunc(int ncalls)
{
if (ncalls > 1)
myfunc(ncalls - 1);
else
myfunc2();
}
int
main(int argc, char argv[])
{
if (argc != 2) {
fprintf(stderr, %s num-calls\n, argv[0]);
exit(EXIT_FAILURE);
}
myfunc(atoi(argv[1]));
exit(EXIT_SUCCESS);
}成果:
总结:应用以下几个函数既可完成客栈信息的打印
int backtrace (void buffer, int size)
char backtrace_symbols (void const buffer, int size)
char abi::__cxa_demangle
(
const char mangled_name,char output_buffer,
size_t length,
int status
)
1. backtrace可以在法度运行的任何处所被调用,返回各个调用函数的返回地址,可以限制最大调用栈返回层数。
2. 在backtrace拿到函数返回地址之后,backtrace_symbols可以将其转换为编译符号,这些符号是编译时代就断定的
3. 按照backtrace_symbols返回的编译符号,abi::__cxa_demangle可以找到具体地函数办法
所有随风而逝的都属于昨天的,所有历经风雨留下来的才是面向未来的。—— 玛格丽特·米切尔 《飘》