1. 前言
The GNU C Library Reference Manual for version 2.35
2. 调试支持
Debugging support
应用程序通常使用专用调试器程序进行调试。但有时这是不可能的,无论如何,在遇到问题时向开发人员提供尽可能多的信息是有用的。出于这个原因,提供了一些功能,程序可以使用这些功能来帮助开发人员更轻松地定位问题。
2.1. 回溯
Backtraces
回溯是线程中当前处于活动状态的函数调用的列表。检查程序回溯的常用方法是使用外部调试器,例如 gdb。但是,有时从程序中以编程方式获取回溯是有用的,例如,出于日志记录或诊断的目的。
头文件 execinfo.h 声明了三个函数,用于获取和操作当前线程的回溯。
函数:int backtrace (void **buffer, int size)
Preliminary: | MT-Safe | AS-Unsafe init heap dlopen plugin lock | AC-Unsafe init mem lock fd | See POSIX Safety Concepts.
backtrace 函数获取当前线程的回溯,作为指针列表,并将信息放入缓冲区。参数大小应该是适合缓冲区的 void * 元素的数量。返回值是实际获得的buffer的条目数,最多为size。
放置在缓冲区中的指针实际上是通过检查堆栈获得的返回地址,每个堆栈帧一个返回地址。
请注意,某些编译器优化可能会干扰获得有效的回溯。函数内联导致内联函数没有堆栈帧;尾调用优化将一个堆栈帧替换为另一个;帧指针消除将阻止回溯正确解释堆栈内容。
函数:char ** backtrace_symbols (void *const *buffer, int size)
Preliminary: | MT-Safe | AS-Unsafe heap | AC-Unsafe mem lock | See POSIX Safety Concepts.
backtrace_symbols 函数将从 backtrace 函数获得的信息转换为字符串数组。参数缓冲区应该是指向通过回溯函数获得的地址数组的指针,大小是该数组中的条目数(回溯的返回值)。
返回值是一个指向字符串数组的指针,该数组具有大小条目,就像数组缓冲区一样。每个字符串都包含缓冲区相应元素的可打印表示。它包括函数名(如果可以确定的话)、函数的偏移量和实际的返回地址(十六进制)。
目前,函数名和偏移量只能在对程序和库使用 ELF 二进制格式的系统上获取。在其他系统上,只会出现十六进制返回地址。此外,您可能需要将其他标志传递给链接器,以使函数名称可用于程序。(例如,在使用 GNU ld 的系统上,您必须传递 -rdynamic。)
backtrace_symbols 的返回值是一个通过 malloc 函数获得的指针,调用者负责释放该指针。请注意,只需要释放返回值,而不是单个字符串。
如果无法为字符串获取足够的内存,则返回值为 NULL。
函数:void backtrace_symbols_fd (void *const *buffer, int size, int fd)
Preliminary: | MT-Safe | AS-Safe | AC-Unsafe lock | See POSIX Safety Concepts.
backtrace_symbols_fd 函数执行与函数 backtrace_symbols 函数相同的转换。它不是将字符串返回给调用者,而是将字符串写入文件描述符 fd,每行一个。它不使用 malloc 函数,因此可以在该函数可能失败的情况下使用。
下面的程序说明了这些函数的使用。请注意,包含由 backtrace 返回的返回地址的数组是在堆栈上分配的。因此,这样的代码可用于通过 malloc 处理内存不再起作用的情况(在这种情况下,backtrace_symbols 也必须由 backtrace_symbols_fd 调用替换)。返回地址的数量通常不是很大。即使是复杂的程序也很少有超过 50 的嵌套级别,如果有 200 个可能的条目,可能所有程序都应该被覆盖。
#include <execinfo.h>
#include <stdio.h>
#include <stdlib.h>
/* Obtain a backtrace and print it to stdout. */
void
print_trace (void)
{
void *array[10];
char **strings;
int size, i;
size = backtrace (array, 10);
strings = backtrace_symbols (array, size);
if (strings != NULL)
{
printf ("Obtained %d stack frames.\n", size);
for (i = 0; i < size; i++)
printf ("%s\n", strings[i]);
}
free (strings);
}
/* A dummy function to make the backtrace more interesting. */
void
dummy_function (void)
{
print_trace ();
}
int
main (void)
{
dummy_function ();
return 0;
}
本文介绍了GNU C Library提供的调试支持,特别是backtrace、backtrace_symbols和backtrace_symbols_fd函数,用于获取和解析线程回溯,帮助开发者定位问题。通过实例演示了如何使用这些函数获取和处理程序的堆栈跟踪信息。
437

被折叠的 条评论
为什么被折叠?



