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

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. */
void
print_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. */
void
dummy_function (void)
{
  print_trace ();
}

int
main (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
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值