linux的用户态程序栈的跟踪方法
Posted 王玉成的博客
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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()
跟我们写出的函数的栈完全相同。
这种调试方法适用于不能打断点的一些程序的调试。
以上是关于linux的用户态程序栈的跟踪方法的主要内容,如果未能解决你的问题,请参考以下文章
Linux内核态用户态简介与IntelCPU特权级别--Ring0-3