glibc 知:手册34:调试支持

本文介绍了GNU C Library提供的调试支持,特别是backtrace、backtrace_symbols和backtrace_symbols_fd函数,用于获取和解析线程回溯,帮助开发者定位问题。通过实例演示了如何使用这些函数获取和处理程序的堆栈跟踪信息。

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;
}

3. 参考

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

canpool

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值