写一下关于函数调用栈的一些相关知识,对于在Linux下面进行c/c++开发,在问题定位时 查看调用栈信息是一个非常常用的定位方法,因为根据调用关系,可以知道程序的执行流程是什么样子。如果 不能查看调用栈,光知道程序在某个函数出错,还是比较难定位,假如这个函数在很多地方被调用,就很难知道是由于什么场景导致错误发生的。所以通过查看调用栈,就可以知道调用关系,当然就知道是什么场景导致问题发生。
在gdb里面常用的命令式:bt 或全称“backtrace”就可以打印出当前函数执行的调用栈。如下面程序
(gdb) bt
#0 0x080486da in func_3 ()
#1 0x08048766 in func_int ()
#2 0x080487ae in func_str ()
#3 0x080487ff in main ()
前面数字式层次关系,#0表示最上面,即当前函数。除了第0层前面的地址表示是当前pc值,其他地址信息都表示函数调用的返回地址,例如上面:func_int() -->func_3() ,func_3执行完成后,接着会执行0x08048766地址的指令。
上面简单介绍了一下Linux下面通过调用栈来定位问题,但调用栈的获取原理,以及如何获取,估计还是有些人会不知道的。之所以要介绍这个,因为对于一些大型系统,完善的日志功能是必不可少的,否则系统出了问题,没有相关日志,是非常痛苦的。尤其是在某些环境下,如电信领域,大多数是服务器或应用程序都是跑在单板上,出现问题了,不会像我们调试小程序那样直接用gdb进行调试。虽然某些情况下可以使用gdb attach上出问题的进程,但大多数服务器单板没有相关调试工具。所以要定位问题,基本上都是通过分析日志。还有一种情况,就是那种随机性问题,如果没有日志,那就更加痛苦了,就算你能够使用gdb也无能为力。所以log重要,但是log中通常需要记录哪些信息呢?通常情况会保护函数调用出错时,把传入该函数的参数信息,或者一些关键全局变量信息,有些时候会记录日期,对于服务器程序,日期一般都会记录。另外还有一个也相对重要的就是调用栈信息。
在gdb里面常用的命令式:bt 或全称“backtrace”就可以打印出当前函数执行的调用栈。如下面程序
(gdb) bt
#0 0x080486da in func_3 ()
#1 0x08048766 in func_int ()
#2 0x080487ae in func_str ()
#3 0x080487ff in main ()
前面数字式层次关系,#0表示最上面,即当前函数。除了第0层前面的地址表示是当前pc值,其他地址信息都表示函数调用的返回地址,例如上面:func_int() -->func_3() ,func_3执行完成后,接着会执行0x08048766地址的指令。
上面简单介绍了一下Linux下面通过调用栈来定位问题,但调用栈的获取原理,以及如何获取,估计还是有些人会不知道的。之所以要介绍这个,因为对于一些大型系统,完善的日志功能是必不可少的,否则系统出了问题,没有相关日志,是非常痛苦的。尤其是在某些环境下,如电信领域,大多数是服务器或应用程序都是跑在单板上,出现问题了,不会像我们调试小程序那样直接用gdb进行调试。虽然某些情况下可以使用gdb attach上出问题的进程,但大多数服务器单板没有相关调试工具。所以要定位问题,基本上都是通过分析日志。还有一种情况,就是那种随机性问题,如果没有日志,那就更加痛苦了,就算你能够使用gdb也无能为力。所以log重要,但是log中通常需要记录哪些信息呢?通常情况会保护函数调用出错时,把传入该函数的参数信息,或者一些关键全局变量信息,有些时候会记录日期,对于服务器程序,日期一般都会记录。另外还有一个也相对重要的就是调用栈信息。