在嵌入式Linux开发中,特别是复杂软件,多人协作开发时,当某人无意间写了一个代码bug导致程序崩溃,但又不知道崩溃的具体位置时,单纯靠走读代码,很难快速的定位问题。

本篇就来介绍一种方法,使用backtrace工具,来辅助定位程序崩溃的位置信息。

backtrace是 C/C++ 中用于获取程序调用栈信息的函数,借助backtrace可以排查崩溃并定位代码行号。

1 backtrace分析程序崩溃的原理

在linux系统中,运行程序若发生崩溃,会产生相应的信号,例如访问空指针会触发SIGSEGV(signum:11)。

这时可以使用signal函数来捕获这个信息,捕获信号后,支持自定义的handler函数进行一些处理。

在自定义的handler函数中,可以使用backtrace函数,来打印程序调用栈信息

最后使用addr2line函数,将地址转换为可读的函数名和行号

使用backtrace分析程序崩溃,需要在编译时使用 -g 选项生成的调试信息。

使用addr2line工具,将地址转换为可读的函数名和行号,实例如下:

addr2line -e 程序名 -f -C 0x400526
# 输出:
main
/path/to/main.c:42
  • 1.
  • 2.
  • 3.
  • 4.

2 一些要用到的函数

2.1 signal

2.1.1 函数原型

在 C 和 C++ 中,signal 函数用于设置信号处理方式。

其原型定义在 <signal.h> 头文件中:

typedef void (*sighandler_t)(int);

sighandler_t signal(int signum, sighandler_t handler);
  • 1.
  • 2.
  • 3.

参数说明:

  • int signum:信号编号(整数),如:
  • SIGINT(2):中断信号(Ctrl+C)
  • SIGSEGV(11):段错误
  • SIGILL(4):非法指令
  • SIGTERM(15):终止信号
  • SIGFPE(8):浮点异常
  • sighandler_t handler:信号处理函数指针,有三种取值:
  • 用户定义函数void handler(int signum) 类型的函数
  • SIG_DFL:默认处理(如终止程序)
  • SIG_IGN:忽略该信号

返回值:

  • 成功:返回之前的信号处理函数指针
  • 失败:返回 SIG_ERR,并设置 errno(如 EINVAL 表示无效信号)
2.1.2 常见信号列表

signum

信号名称

默认行为

触发场景

1

SIGHUP

终止程序

终端连接断开(如 SSH 会话结束),或用户登出时通知进程重新加载配置

2

SIGINT

终止程序(Ctrl+C)

用户在终端按下 Ctrl+C,请求中断当前进程

3