linux下利用backtrace追踪函数调用堆栈以及定位段错误
该函数用于获取当前线程的调用堆栈,获取的信息将会被存放在buffer中,它是一个指针列表。参数 size 用来指定buffer中可以保存多少个void* 元素。函数返回值是实际获取的指针个数,最大不超过size大小
在buffer中的指针实际是从堆栈中获取的返回地址,每一个堆栈框架有一个返回地址
注意:某些编译器的优化选项对获取正确的调用堆栈有干扰,另外内联函数没有堆栈框架;删除框架指针也会导致无法正确解析堆栈内容
backtrace_symbols将从backtrace函数获取的信息转化为一个字符串数组. 参数buffer应该是从backtrace函数获取的指针数组,size是该数组中的元素个数(backtrace的返回值)
函数返回值是一个指向字符串数组的指针,它的大小同buffer相同.每个字符串包含了一个相对于buffer中对应元素的可打印信息.它包括函数名,函数的偏移地址,和实际的返回地址
现在,只有使用ELF二进制格式的程序才能获取函数名称和偏移地址.在其他系统,只有16进制的返回地址能被获取.另外,你可能需要传递相应的符号给链接器,以能支持函数名功能(比如,在使用GNU ld链接器的系统中,你需要传递(-rdynamic), -rdynamic可用来通知链接器将所有符号添加到动态符号表中,如果你的链接器支持-rdynamic的话,建议将其加上!)
该函数的返回值是通过malloc函数申请的空间,因此调用者必须使用free函数来释放指针.
注意:如果不能为字符串获取足够的空间函数的返回值将会为NULL
backtrace_symbols_fd与backtrace_symbols 函数具有相同的功能,不同的是它不会给调用者返回字符串数组,而是将结果写入文件描述符为fd的文件中,每个函数对应一行.它不需要调用malloc函数,因此适用于有可能调用该函数会失败的情况
下面是glibc中的实例(稍有修改):
/* A dummy function to make the backtrace more interesting. */ void dummy_function (void) print_trace (); int main (int argc, char *argv[]) dummy_function (); return 0;
./execinfo() [0x8048556] /lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf3) [0x70a113]
我们还可以利用这backtrace来定位段错误位置。
通常情况系,程序发生段错误时系统会发送SIGSEGV信号给程序,缺省处理是退出函数。我们可以使用 signal(SIGSEGV, your_function);函数来接管SIGSEGV信号的处理,程序在发生段错误后,自动调用我们准备好的函数,从而在那个函数里来获取当前函数调用栈。
举例如下:
size = backtrace(buffer, 30); fprintf(stdout, "Obtained %zd stack frames.nm\n", size); strings = backtrace_symbols(buffer, 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(int argc, const char *argv[]) if (signal(SIGSEGV, dump) == SIG_ERR) perror("cant catch SIGSEGV"); func_a(); return 0;
./backstrace_debug(main+0x33)[0x80488cb] /lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf3)[0x129113]
(这里有个疑问: 多次运行的结果是/lib/i368-linux-gnu/libc.so.6和[0x468400]的返回地址是变化的,但不变的是后三位, 不知道为什么)
接着:
objdump -d test test.s
在test.s中搜索804888c如下:
8048885: 89 e5 mov %esp, %ebp 8048887: e8 eb ff ff ff call 8048877 func_c 804888c: 5d pop %ebp 804888d: c3 ret
其中80488c时调用(call 8048877)C函数后的地址,虽然并没有直接定位到C函数,通过汇编代码, 基本可以推出是C函数出问题了(pop指令不会导致段错误的)。
我们也可以通过addr2line来查看
《Linux内核设计的艺术:图解Linux操作系统架构设计与实现原理》——1.3 开始向32位模式转变,为main函数的调用做准备 本节书摘来自华章计算机《Linux内核设计的艺术:图解Linux操作系统架构设计与实现原理》一书中的第1章,第1.3节,作者:新设计团队著, 更多章节内容可以访问云栖社区“华章计算机”公众号查看。
在Linux中打印函数调用堆栈【原创】 本人学习笔记,代码参考如下网址 参考http://www.cnblogs.com/dma1982/archive/2012/02/08/2342215.html zhangbh@prolin-srv: gcc -rdynamic -o my a.
一般察看函数运行时堆栈的方法是使用GDB(bt命令)之类的外部调试器,但是,有些时候为了分析程序的BUG,(主要针对长时间运行程序的分析),在程序出错时打印出函数的调用堆栈是非常有用的。
Linux的进程调度时机(Schedule函数何时调用) Linux在众多进程中是怎么进行调度的,这个牵涉到Linux进程调度时机的概念,由Linux内核中Schedule()的函数来决定是否要进行进程的切换,如果要切换的话,切换到哪个进程等等。
相关文章
- linux进入root模式
- linux No module named yum错误的解决办法
- 安卓 和 Linux 之间传输文件的 8 个应用程序
- Linux Command who、whois、whoami
- Linux shell标准输入,标准输出,错误输出
- Linux find
- (超详细)Linux Shell 编程
- Linux - grep命令详解
- Linux命令之cat
- 解决"No toolchains found in the NDK toolchains folder for ABI with prefix: mips64el-linux-android"错误
- linux压缩打包
- Qt编写物联网管理平台(支持win/linux/mac/嵌入式linux/modbus等)
- [LINUX]VMWARE_TOOLS安装- CD-ROM锁定错误
- Linux中scanf类型匹配错误,特指scanf("%d", &c ) ,导致死循环的解决方法 —— fflush(stdin)和getchar()的使用
- Linux—yum的python版本错误——初级解决方案
- linux ------ 使用 screen 后 SSH 断开后程序依旧能在后台运行
- Linux pip错误分析 (Running pip as the ‘root‘ user can result in broken permissions and conflict)
- linux 常用指令
- 【正点原子Linux连载】第四章 SDK包的使用 摘自【正点原子】ATK-DLRV1126系统开发手册
- Linux进程间通信(IPC)
- 10.24的注意事项——解决linux_jni编译错误的问题