backtrace调试方式

最近项目出现了断错误,由于程序deamon运行在arm上,所以想找到一种方式,找到端错误的出错位置,然后找到了backtrace,但是后来发现安卓的NDK不支持execinfo.h,要想使用的话就要自己去提取相关的库到NDK中了,日后有空在去搞吧,虽然在本项目上面用不到,但是还是总结一下把,下一篇去介绍gdb在arm平台上的使用。

实例程序
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <stddef.h>
#include <execinfo.h>

void signal_handle()
{
  void *buf[32] = {0};
  char **strings;
  int i;
  size_t size;

  size = backtrace(buf, 32);
  if (size < 0)
      printf("backtrace error\n");
  else
      fprintf(stdout, "backtrace size %zd\n", size);
  strings = backtrace_symbols(buf, size);
  if (strings == NULL) {
      perror("backtrace_symbols.");
      exit(EXIT_FAILURE);
  }
  for(i = 0; i < size; i++) {
    fprintf(stdout, "%s\n", strings[i]);
  }
  free(strings);
  strings = NULL;
  exit(0);
}

void func_c()
{
    *((volatile char *)0x0) = 0x9999;
}

void func_b()
{
    func_c();
}

void func_a()
{
    func_b();
}

int main()
{
    if (signal(SIGSEGV, signal_handle) == SIG_ERR)
        perror("cat not catch signal");
    
    func_a();

    return 0;
}
int backtrace(void **buffer, int size);backtrace()函数的返回值为buffer中的条目数量,这个值不一定等于size,因为如果为得到完整回溯信息而将size设置的足够大,则该函数的返回值为buffer中实际得到的返回地址数量。
char **backtrace_symbols(void *const *buffer, int size);通过backtrace()函数得到buffer之后,backtrace_symbols()可以将其中的返回地址都对应到具体的函数名,参数size为buffer中的条目数。backtrace_symbols()函数可以将每一个返回值都翻译成“函数名+函数内偏移量+函数返回值”,经过翻译后的函数回溯信息放到backtrace_symbols()的返回值中,如果失败则返回NULL。需要注意,返回值本身是在backtrace_symbols()函数内部进行malloc的,所以必须在后续显式地free掉
void backtrace_symbols_fd(void *const *buffer, int size, int fd);backtrace_symbols_fd()的buffer和size参数和backtrace_symbols()函数相同,只是它翻译后的函数回溯信息不是放到返回值中,而是一行一行的放到文件描述符fd对应的文件中

声明:

  • 1、在编译过程在不能添加非零的优化等级,否则会使得不能得到正确的程序栈信息,加-g将关闭所有优化信息
  • 2、在编译的时候需要加上-rdynamic选项让链接器将所有符号添加到动态符号表中,这样才能将函数地址翻译成函数名。另外,这个选项不会处理static函数,所以,static函数的符号无法得到
  • 3、内联函数没有栈帧,它在编译过程中被展开在调用的位置
  • 4、尾调用优化(Tail-call Optimization)将复用当前函数栈,而不再生成新的函数栈,这将导致栈信息不能正确被获取
生成backtrace
  • cjj@cjj-MyThink:~/mytoy/调试方式/backtrace$: gcc -g -rdynamic test.c -o backtrace

  • cjj@cjj-MyThink:~/mytoy/调试方式/backtrace$ ./backtrace

backtrace size 8
./backtrace(signal_handle+0x45) [0x400a9b]
/lib/x86_64-linux-gnu/libc.so.6(+0x354b0) [0x7f16044024b0]
./backtrace(func_c+0x9) [0x400b8a]
./backtrace(func_b+0xe) [0x400b9e]
./backtrace(func_a+0xe) [0x400baf]
./backtrace(main+0x2d) [0x400bdf]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0) [0x7f16043ed830]
./backtrace(_start+0x29) [0x400989]
  • cjj@cjj-MyThink:~/mytoy/调试方式/backtrace$ addr2line -e backtrace 0x400b8a
/home/cjj/mytoy/调试方式/backtrace/test.c:34

可以看出来在test.c文件的第34行出现了断错误

**后续:**如果能够看到这里,那么我再多说一点,之前说在arm上面没有找到去backtrace调试断错误,但是后来我发现可以在arm上去调试。

上方式:
一般在安卓下出现程序断错误,可以通过logcat去看,在main log里面,关键字是“DEBUG”
一般文件是被保存在/data/tombstones/里面,名字为tombstones_xxx

工具及使用说明:

使用cjj@cjj-MyThink:~$ arm-linux-androideabi-addr2line 
这里我用的是安卓板子里面跑得测试程序,这个测试程序是使用arm-linux-androideabi-gcc编译的
该工具可以根据
debug信息中提供的address(如#00 PC xxxxxxxx),直接定位到代码行。使用及分析过程如下:在debug信息中看到,
#00 pc 0000bb96 /system/lib/libreference-ril.so 

#01 pc 000049e6 /system/lib/libreference-ril.so 

#02 pc 000070d0 /system/lib/libreference-ril.so 

#03 pc 000052a6 /system/lib/libril.so 

查看第一条出错信息:

arm-linux-androideabi-addr2line –f –e libreference-ril.so 0000bb96

at_response_free

atchannel_mch.c: 1071

这告诉我们出错的代码在文件
atchannel_mch.c的at_response_free中,在1071行;

**注意:**
如果出现转换的地址显示为 " ? ? 0 “(一个so库的错误地址信息跑到另外一个so库去查,当然查不到,除非两个错误位置在两个so库中的堆栈地址相同,查不到的时候,就会输出” ? ? 0 "),所以`一定要用跟你调试应用程序相同的库文件`.PC上自带的有addr2line,直接去调试也能显示哪个函数出现的断错误,但是我自己发现不能打印行号,以后找找原因,方式与使用NDK的调试工具相同`addr2line –f –e libreference-ril.so 0000bb96 `。


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值