linux的用户态程序栈的跟踪方法

来源:互联网 发布:sound软件 编辑:程序博客网 时间:2024/06/09 14:16

linux的用户态程序栈的跟踪方法

  • GNU C中的libc相关函数介绍
  • 实例分析

GNU C中的libc相关函数介绍

这一部分文章来源于GNU C的在线帮助文档

实例分析

将下面的代码保存为main.c文件,然后用gcc编译

#include <execinfo.h>#include <stdio.h>#include <stdlib.h>/* Obtain a backtrace and print it to stdout. */voidprint_trace (void){  void *array[10];  size_t size;  char **strings;  size_t i;  size = backtrace (array, 10);  strings = backtrace_symbols (array, size);  printf ("Obtained %zd 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. */voiddummy_function (void){  print_trace ();}intmain (void){  dummy_function ();  return 0;}

然后编译并运行:

[ycwang@ycwang-desktop:backtrace-test]$ gcc -g main.c

[ycwang@ycwang-desktop:backtrace-test]$ ./a.out
Obtained 5 stack frames.
./a.out() [0x4006fe]
./a.out() [0x400795]
./a.out() [0x4007a1]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0) [0x7f06a6ef2ac0]
./a.out() [0x400609]

可以看到,程序运行之后,把stack frames完全打印出来了。
我们可以定位各个栈了。
然后用objdump来把反汇编文件导出到一个文件中

[ycwang@ycwang-desktop:backtrace-test]$ objdump -D a.out > dump

然后打开dump文件,查找函数在内存中的虚拟地址。

450 00000000004006d6 <print_trace>: 451   4006d6:   55                      push   %rbp 452   4006d7:   48 89 e5                mov    %rsp,%rbp 453   4006da:   48 83 c4 80             add    $0xffffffffffffff80,%rsp 454   4006de:   64 48 8b 04 25 28 00    mov    %fs:0x28,%rax 455   4006e5:   00 00  456   4006e7:   48 89 45 f8             mov    %rax,-0x8(%rbp) 457   4006eb:   31 c0                   xor    %eax,%eax 458   4006ed:   48 8d 45 a0             lea    -0x60(%rbp),%rax 459   4006f1:   be 0a 00 00 00          mov    $0xa,%esi 460   4006f6:   48 89 c7                mov    %rax,%rdi 461   4006f9:   e8 92 fe ff ff          callq  400590 <backtrace@plt> 462   4006fe:   48 98                   cltq    463   400700:   48 89 45 90             mov    %rax,-0x70(%rbp) 464   400704:   48 8b 45 90             mov    -0x70(%rbp),%rax

可以看出:0x4006fe在print_trace函数里面,这也是函数栈的栈顶。
接下来查找另外几个地址。得到:

地址0x400795:

 503 000000000040078c <dummy_function>: 504   40078c:   55                      push   %rbp 505   40078d:   48 89 e5                mov    %rsp,%rbp 506   400790:   e8 41 ff ff ff          callq  4006d6 <print_trace> 507   400795:   90                      nop 508   400796:   5d                      pop    %rbp 509   400797:   c3                      retq

地址0x4007a1:

 511 0000000000400798 <main>: 512   400798:   55                      push   %rbp 513   400799:   48 89 e5                mov    %rsp,%rbp 514   40079c:   e8 eb ff ff ff          callq  40078c <dummy_function> 515   4007a1:   b8 00 00 00 00          mov    $0x0,%eax 516   4007a6:   5d                      pop    %rbp 517   4007a7:   c3                      retq 518   4007a8:   0f 1f 84 00 00 00 00    nopl   0x0(%rax,%rax,1) 519   4007af:   00

接下来的两个栈对于我们的程序分析没有意义,暂时不讨论。

然后我们可以得到栈的层次为

print_trace()dummy_function()main()

跟我们写出的函数的栈完全相同。

这种调试方法适用于不能打断点的一些程序的调试。

0 0