#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);
void test(void){
dummy_function();
}
void test1(void){
test();
printf("ok");
}
void
dummy_function (void)
{
//test();
print_trace ();
}
int
main (void)
{
//dummy_function ();
test1();
//print_trace();
return 0;
}
输出:
Obtained 7 stack frames.
./test(print_trace+0x14) [0x804878c]
./test(dummy_function+0xb) [0x8048837]
./test(test+0xb) [0x804880d]
./test(test1+0xb) [0x804881a]
./test(main+0x15) [0x804884e]
/lib/i686/libc.so.6(__libc_start_main+0xc7) [0x4003eb77]
./test(backtrace_symbols+0x31) [0x80486ed]
我理解这个函数只能取得直接调用的轨迹。而无法得到下面这样代码的调用轨迹
没有得到test调用信息
2 #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);
void test(void){
dummy_function();
}
void test1(void){
test();
printf("ok");
}
void
dummy_function (void)
{
//test();
print_trace ();
}
int
main (void)
{
//dummy_function ();
test1();
//print_trace();
return 0;
}
输出:
Obtained 7 stack frames.
./test(print_trace+0x14) [0x804878c]
./test(dummy_function+0xb) [0x8048837]
./test(test+0xb) [0x804880d]
./test(test1+0xb) [0x804881a]
./test(main+0x15) [0x804884e]
/lib/i686/libc.so.6(__libc_start_main+0xc7) [0x4003eb77]
./test(backtrace_symbols+0x31) [0x80486ed]
我理解这个函数只能取得直接调用的轨迹。而无法得到下面这样代码的调用轨迹
暂无评论
#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);
void test(void){
dummy_function();
}
void test1(void){
test();
printf("ok");
}
void
dummy_function (void)
{
//test();
print_trace ();
}
int
main (void)
{
//dummy_function ();
test1();
//print_trace();
return 0;
}
输出:
Obtained 7 stack frames.
./test(print_trace+0x14) [0x804878c]
./test(dummy_function+0xb) [0x8048837]
./test(test+0xb) [0x804880d]
./test(test1+0xb) [0x804881a]
./test(main+0x15) [0x804884e]
/lib/i686/libc.so.6(__libc_start_main+0xc7) [0x4003eb77]
./test(backtrace_symbols+0x31) [0x80486ed]
我理解这个函数只能取得直接调用的轨迹。而无法得到下面这样代码的调用轨迹
#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);
void test(void){
//dummy_function();
}
void test1(void){
test();
printf("ok");
}
void
dummy_function (void)
{
test();
print_trace ();
}
int
main (void)
{
dummy_function ();
test1();
//print_trace();
return 0;
}
输出:
Obtained 5 stack frames.
./test(print_trace+0x14) [0x804878c]
./test(dummy_function+0x10) [0x8048834]
./test(main+0x15) [0x804884b]
/lib/i686/libc.so.6(__libc_start_main+0xc7) [0x4003eb77]
./test(backtrace_symbols+0x31) [0x80486ed]
没有得到test调用信息
2 #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);
void test(void){
dummy_function();
}
void test1(void){
test();
printf("ok");
}
void
dummy_function (void)
{
//test();
print_trace ();
}
int
main (void)
{
//dummy_function ();
test1();
//print_trace();
return 0;
}
输出:
Obtained 7 stack frames.
./test(print_trace+0x14) [0x804878c]
./test(dummy_function+0xb) [0x8048837]
./test(test+0xb) [0x804880d]
./test(test1+0xb) [0x804881a]
./test(main+0x15) [0x804884e]
/lib/i686/libc.so.6(__libc_start_main+0xc7) [0x4003eb77]
./test(backtrace_symbols+0x31) [0x80486ed]
我理解这个函数只能取得直接调用的轨迹。而无法得到下面这样代码的调用轨迹
#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);
void test(void){
//dummy_function();
}
void test1(void){
test();
printf("ok");
}
void
dummy_function (void)
{
test();
print_trace ();
}
int
main (void)
{
dummy_function ();
test1();
//print_trace();
return 0;
}
输出:
Obtained 5 stack frames.
./test(print_trace+0x14) [0x804878c]
./test(dummy_function+0x10) [0x8048834]
./test(main+0x15) [0x804884b]
/lib/i686/libc.so.6(__libc_start_main+0xc7) [0x4003eb77]
./test(backtrace_symbols+0x31) [0x80486ed]
没有得到test调用信息
2 直接BUG
3 调用dump_stack()就会打印当前cpu的堆栈的调用函数了。参考内核源代码
arch/x86_64/kernel/traps.c
/*
* The architecture-independent dump_stack generator
*/
void dump_stack(void)
{
unsigned long dummy;
show_trace(&dummy);
}
/*
* When in-kernel, we also print out the stack and co
* time of the fault..
*/
if (in_kernel) {
printk("Stack: ");
show_stack(NULL, (unsigned long*)rsp);
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include <signal.h>
//signal 函数用法参考http://www.kernel.org/doc/man-pages/online/pages/man2/signal.2.html
//backtrace ,backtrace_symbols函数用法参考 http://www.kernel.org/doc/man-pages/online/pages/man3/backtrace.3.html
static void WidebrightSegvHandler(int signum) {
void *array[10];
size_t size;
char **strings;
size_t i, j;
signal(signum, SIG_DFL); /* 还原默认的信号处理赏罚 handler */
size = backtrace (array, 10);
strings = (char **)backtrace_symbols (array, size);
fprintf(stderr, "widebright received SIGSEGV! Stack trace:\n");
for (i = 0; i < size; i++) {
fprintf(stderr, "%d %s \n",i,strings[i]);
}
free (strings);
exit(1);
}
int invalide_pointer_error(char * p)
{
*p = 'd'; //让这里出现一个拜访非法指针的过错
return 0;
}
void error_2(char * p)
{
invalide_pointer_error(p);
}
void error_1(char * p)
{
error_2(p);
}
void error_0(char * p)
{
error_1(p);
}
int main()
{
//设置 信好的处理赏罚 函数,种种 信号的界说见http://www.kernel.org/doc/man-pages/online/pages/man7/signal.7.html
signal(SIGSEGV, WidebrightSegvHandler); // SIGSEGV 11 Core Invalid memory reference
signal(SIGABRT, WidebrightSegvHandler); // SIGABRT 6 Core Abort signal from
char *a = NULL;
error_0(a);
exit(0);
}
widebright@widebright:~/桌面$ gcc main.c
widebright@widebright:~/桌面$ ./a.out
widebright received SIGSEGV! Stack trace:
0 ./a.out [0x8048580]
1 [0xb807a400]
2 ./a.out [0x8048636]
3 ./a.out [0x8048649]
4 ./a.out [0x804865c]
5 ./a.out [0x80486a9]
6 /lib/tls/i686/cmov/libc.so.6(__libc_start_main+0xe5) [0xb7f19775]
然后为了定位过错,我们必要 加上-g参数重新编译一个带调试信息的版本
widebright@widebright:~/桌面$ gcc -g main.c
widebright@widebright:~/桌面$ ./a.out
widebright received SIGSEGV! Stack trace:
0 ./a.out [0x8048580]
1 [0xb7fb3400]
2 ./a.out [0x8048636]
3 ./a.out [0x8048649]
4 ./a.out [0x804865c]
5 ./a.out [0x80486a9]
6 /lib/tls/i686/cmov/libc.so.6(__libc_start_main+0xe5) [0xb7e52775]
7 ./a.out [0x80484c1]
加上-rdynamic 参数的话,输出的标记更明白一些,不外好像 所在不一样了。
widebright@widebright:~/桌面$ gcc -g -rdynamic main.c
widebright@widebright:~/桌面$ ./a.out
widebright received SIGSEGV! Stack trace:
0 ./a.out [0x8048840]
1 [0xb7f3d400]
2 ./a.out(error_2+0x11) [0x80488f6]
3 ./a.out(error_1+0x11) [0x8048909]
4 ./a.out(error_0+0x11) [0x804891c]
5 ./a.out(main+0x4b) [0x8048969]
6 /lib/tls/i686/cmov/libc.so.6(__libc_start_main+0xe5) [0xb7ddc775]
7 ./a.out [0x8048781]
可以看到有调试信息的时间,过错是一样的。然后就可以用gdb定位和调试过错了:
-----------------------
(gdb) info line *0x8048580
Line 19 of "main.c" starts at address 0x804856d <WidebrightSegvHandler+25>
and ends at 0x8048583 <WidebrightSegvHandler+47>.
(gdb) list *0x8048580
0x8048580 is in WidebrightSegvHandler (main.c:19).
14 char **strings;
15 size_t i, j;
16
17 signal(signum, SIG_DFL); /* 还原默认的信号处理赏罚 handler */
18
19 size = backtrace (array, 10);
20 strings = (char **)backtrace_symbols (array, size);
21
22 fprintf(stderr, "widebright received SIGSEGV! Stack trace:\n");
23 for (i = 0; i < size; i++) {
-----------------
(gdb) list *0x8048636
0x8048636 is in error_2 (main.c:41).
36
37
38 void error_2(char * p)
39 {
40 invalide_pointer_error(p);
41 }
42
43 void error_1(char * p)
44 {
45 error_2(p);
--------------
(gdb) list *0x8048649
0x8048649 is in error_1 (main.c:46).
41 }
42
43 void error_1(char * p)
44 {
45 error_2(p);
46 }
47
48 void error_0(char * p)
49 {
50 error_1(p);
=============
(gdb) br main.c:40
Breakpoint 1 at 0x804862b: file main.c, line 40.
(gdb) run
Starting program: /home/widebright/桌面/a.out
Breakpoint 1, error_2 (p=0x0) at main.c:40
40 invalide_pointer_error(p);
(gdb) stepi
0x0804862e 40 invalide_pointer_error(p);
(gdb) stepi
0x08048631 40 invalide_pointer_error(p);
(gdb) stepi
invalide_pointer_error (p=0x0) at main.c:32
32 {
(gdb) stepi
0x08048616 32 {
(gdb) stepi
33 *p = 'd'; //让这里出现一个拜访非法指针的过错
(gdb) stepi
0x0804861b 33 *p = 'd'; //让这里出现一个拜访非法指针的过错
(gdb) stepi
Program received signal SIGSEGV, Segmentation fault.
0x0804861b in invalide_pointer_error (p=0x0) at main.c:33
33 *p = 'd'; //让这里出现一个拜访非法指针的过错
(gdb) print p
$1 = 0x0
(gdb) print *p
Cannot access memory at address 0x0
===============================================
好像 应用
int sigaction(int signum, const struct sigaction *act,
struct sigaction *oldact);
http://www.kernel.org/doc/man-pages/online/pages/man2/sigaction.2.html
这个函数注册信号的处理赏罚 函数的话,可以得到更多的信息,比如 堕落 时间的寄放器的值等等。
由于他函数 末了一个参数传过来一个ucontext_t *ucontext 的指针
可以看到 “善用backtrace办理大题目 ” http://blog.chinaunix.net/u/3425/showart_263408.html 这个网页上有给出一个例子。
最初看到这个用法的的在redhat的安装措施的anaconda内里的。
------------------------
关于backtrack的原理 的表明 ,参考这个:
从别人blog上拷来的,所在:http://blog.csdn.net/absurd/archive/2005/12/13/551585.aspx
开拓嵌入式软件通常是比拟 贫穷 的事,一些常用的器材每每无法应用,在开拓PC软件时大略 的义务 ,此时变得很繁杂。本日就碰到了如许一件事,折腾了几个小时,仅仅是为知道call stack。
我编译了一个措施放到PDA(ARM9+LINUX+UCLIBC)上面运行,出现了一个ASSERT,并表现了文件名和行号,本来是调用了一个没有实现 的函数,我很想知道是谁调用了它,这看似大略 的题目却让我很头疼,假如有gdb,那好办-用bt下令就可以搞定,假如用的libc,那也好办-用 backtrace函数就可以搞定,题目是两者都没有。
想来想去只有本身写一个backtrace,要实现这个功能并不难,假如我们知道调用堆栈的技俩,就可以很轻易取出上层调用者的指令所在,有了这些上层调用者的指令所在,我们可以通过MAP文件找到指令所在对应的源文件名和行号。
下面扼要 先容一下实现原理:
要得到调用者的所在,有须要先容一下堆栈的技俩:
+---------------------------+ (高所在)
+_参数1__________+
+---------------------------+
+_参数2__________+
+---------------------------+ 参数的序次 凭借于调用行动
+_参数.__________+
+---------------------------+
+_参数N__________+
+---------------------------+
+_eip____________+ 返回本次调用后,下一条指令的所在
+----------------------------+
+_ebp____________+ 这里生涯的调用者的ebp
+----------------------------+
(ebp 指向这里:相等于调用者和被调用者的分边界)
+----------------------------+
+_临时 变量1_______+
+----------------------------+
+_临时 变量2_______+
+----------------------------+
+_临时 变量.________+
+----------------------------+
+----------------------------+
+_临时 变量N_______+
+----------------------------+(低所在)
由于优化、调用行动、编译器的差别 ,上述构造部也许有所差别 ,但一样平常来说,第一个局部变量前是调用者的ebp,ebp前是返回后下一条指令的所在。
知道了这个结构,要得到上层调用的者指令所在就轻易了,我们可以用如下代码仿照glibc供给 的backtrace的功能:
int backtrace (void **BUFFER, int SIZE)
{
int n = 0;
int *p = &n;
int i = 0;
int ebp = p[1];
int eip = p[2];
for(i = 0; i < SIZE; i++)
{
BUFFER[i] = (void*)eip;
p = (int*)ebp;
ebp = p[0];
eip = p[1];
}
return SIZE;
}
附:
通过addr2line可以找到所在对应的文件名和行号,不消手动去查MAP文件了。
=======================
windows体系 上面要实现同样的功能,也许要调用 内里的StackWalk64 等函数。
http://msdn.microsoft.com/en-us/library/ms680650(VS.85).aspx
找到一个应用 StackWalk64 的例子http://www.cppblog.com/kevinlynx/archive/2008/03/28/45628.html
这里又是一个仿照backtrace(stackwalk)函数的例子
http://www.cnblogs.com/lbq1221119/archive/2008/04/18/1159956.html
着实 你可以在措施的任何地方 调用backtrace和 stackwalk函数的,呵呵
#include<string.h>
#include<stdlib.h>
#include <signal.h>
//signal 函数用法参考http://www.kernel.org/doc/man-pages/online/pages/man2/signal.2.html
//backtrace ,backtrace_symbols函数用法参考 http://www.kernel.org/doc/man-pages/online/pages/man3/backtrace.3.html
static void WidebrightSegvHandler(int signum) {
void *array[10];
size_t size;
char **strings;
size_t i, j;
signal(signum, SIG_DFL); /* 还原默认的信号处理赏罚 handler */
size = backtrace (array, 10);
strings = (char **)backtrace_symbols (array, size);
fprintf(stderr, "widebright received SIGSEGV! Stack trace:\n");
for (i = 0; i < size; i++) {
fprintf(stderr, "%d %s \n",i,strings[i]);
}
free (strings);
exit(1);
}
int invalide_pointer_error(char * p)
{
*p = 'd'; //让这里出现一个拜访非法指针的过错
return 0;
}
void error_2(char * p)
{
invalide_pointer_error(p);
}
void error_1(char * p)
{
error_2(p);
}
void error_0(char * p)
{
error_1(p);
}
int main()
{
//设置 信好的处理赏罚 函数,种种 信号的界说见http://www.kernel.org/doc/man-pages/online/pages/man7/signal.7.html
signal(SIGSEGV, WidebrightSegvHandler); // SIGSEGV 11 Core Invalid memory reference
signal(SIGABRT, WidebrightSegvHandler); // SIGABRT 6 Core Abort signal from
char *a = NULL;
error_0(a);
exit(0);
}
widebright@widebright:~/桌面$ gcc main.c
widebright@widebright:~/桌面$ ./a.out
widebright received SIGSEGV! Stack trace:
0 ./a.out [0x8048580]
1 [0xb807a400]
2 ./a.out [0x8048636]
3 ./a.out [0x8048649]
4 ./a.out [0x804865c]
5 ./a.out [0x80486a9]
6 /lib/tls/i686/cmov/libc.so.6(__libc_start_main+0xe5) [0xb7f19775]
然后为了定位过错,我们必要 加上-g参数重新编译一个带调试信息的版本
widebright@widebright:~/桌面$ gcc -g main.c
widebright@widebright:~/桌面$ ./a.out
widebright received SIGSEGV! Stack trace:
0 ./a.out [0x8048580]
1 [0xb7fb3400]
2 ./a.out [0x8048636]
3 ./a.out [0x8048649]
4 ./a.out [0x804865c]
5 ./a.out [0x80486a9]
6 /lib/tls/i686/cmov/libc.so.6(__libc_start_main+0xe5) [0xb7e52775]
7 ./a.out [0x80484c1]
加上-rdynamic 参数的话,输出的标记更明白一些,不外好像 所在不一样了。
widebright@widebright:~/桌面$ gcc -g -rdynamic main.c
widebright@widebright:~/桌面$ ./a.out
widebright received SIGSEGV! Stack trace:
0 ./a.out [0x8048840]
1 [0xb7f3d400]
2 ./a.out(error_2+0x11) [0x80488f6]
3 ./a.out(error_1+0x11) [0x8048909]
4 ./a.out(error_0+0x11) [0x804891c]
5 ./a.out(main+0x4b) [0x8048969]
6 /lib/tls/i686/cmov/libc.so.6(__libc_start_main+0xe5) [0xb7ddc775]
7 ./a.out [0x8048781]
可以看到有调试信息的时间,过错是一样的。然后就可以用gdb定位和调试过错了:
-----------------------
(gdb) info line *0x8048580
Line 19 of "main.c" starts at address 0x804856d <WidebrightSegvHandler+25>
and ends at 0x8048583 <WidebrightSegvHandler+47>.
(gdb) list *0x8048580
0x8048580 is in WidebrightSegvHandler (main.c:19).
14 char **strings;
15 size_t i, j;
16
17 signal(signum, SIG_DFL); /* 还原默认的信号处理赏罚 handler */
18
19 size = backtrace (array, 10);
20 strings = (char **)backtrace_symbols (array, size);
21
22 fprintf(stderr, "widebright received SIGSEGV! Stack trace:\n");
23 for (i = 0; i < size; i++) {
-----------------
(gdb) list *0x8048636
0x8048636 is in error_2 (main.c:41).
36
37
38 void error_2(char * p)
39 {
40 invalide_pointer_error(p);
41 }
42
43 void error_1(char * p)
44 {
45 error_2(p);
--------------
(gdb) list *0x8048649
0x8048649 is in error_1 (main.c:46).
41 }
42
43 void error_1(char * p)
44 {
45 error_2(p);
46 }
47
48 void error_0(char * p)
49 {
50 error_1(p);
=============
(gdb) br main.c:40
Breakpoint 1 at 0x804862b: file main.c, line 40.
(gdb) run
Starting program: /home/widebright/桌面/a.out
Breakpoint 1, error_2 (p=0x0) at main.c:40
40 invalide_pointer_error(p);
(gdb) stepi
0x0804862e 40 invalide_pointer_error(p);
(gdb) stepi
0x08048631 40 invalide_pointer_error(p);
(gdb) stepi
invalide_pointer_error (p=0x0) at main.c:32
32 {
(gdb) stepi
0x08048616 32 {
(gdb) stepi
33 *p = 'd'; //让这里出现一个拜访非法指针的过错
(gdb) stepi
0x0804861b 33 *p = 'd'; //让这里出现一个拜访非法指针的过错
(gdb) stepi
Program received signal SIGSEGV, Segmentation fault.
0x0804861b in invalide_pointer_error (p=0x0) at main.c:33
33 *p = 'd'; //让这里出现一个拜访非法指针的过错
(gdb) print p
$1 = 0x0
(gdb) print *p
Cannot access memory at address 0x0
===============================================
好像 应用
int sigaction(int signum, const struct sigaction *act,
struct sigaction *oldact);
http://www.kernel.org/doc/man-pages/online/pages/man2/sigaction.2.html
这个函数注册信号的处理赏罚 函数的话,可以得到更多的信息,比如 堕落 时间的寄放器的值等等。
由于他函数 末了一个参数传过来一个ucontext_t *ucontext 的指针
可以看到 “善用backtrace办理大题目 ” http://blog.chinaunix.net/u/3425/showart_263408.html 这个网页上有给出一个例子。
最初看到这个用法的的在redhat的安装措施的anaconda内里的。
------------------------
关于backtrack的原理 的表明 ,参考这个:
从别人blog上拷来的,所在:http://blog.csdn.net/absurd/archive/2005/12/13/551585.aspx
开拓嵌入式软件通常是比拟 贫穷 的事,一些常用的器材每每无法应用,在开拓PC软件时大略 的义务 ,此时变得很繁杂。本日就碰到了如许一件事,折腾了几个小时,仅仅是为知道call stack。
我编译了一个措施放到PDA(ARM9+LINUX+UCLIBC)上面运行,出现了一个ASSERT,并表现了文件名和行号,本来是调用了一个没有实现 的函数,我很想知道是谁调用了它,这看似大略 的题目却让我很头疼,假如有gdb,那好办-用bt下令就可以搞定,假如用的libc,那也好办-用 backtrace函数就可以搞定,题目是两者都没有。
想来想去只有本身写一个backtrace,要实现这个功能并不难,假如我们知道调用堆栈的技俩,就可以很轻易取出上层调用者的指令所在,有了这些上层调用者的指令所在,我们可以通过MAP文件找到指令所在对应的源文件名和行号。
下面扼要 先容一下实现原理:
要得到调用者的所在,有须要先容一下堆栈的技俩:
+---------------------------+ (高所在)
+_参数1__________+
+---------------------------+
+_参数2__________+
+---------------------------+ 参数的序次 凭借于调用行动
+_参数.__________+
+---------------------------+
+_参数N__________+
+---------------------------+
+_eip____________+ 返回本次调用后,下一条指令的所在
+----------------------------+
+_ebp____________+ 这里生涯的调用者的ebp
+----------------------------+
(ebp 指向这里:相等于调用者和被调用者的分边界)
+----------------------------+
+_临时 变量1_______+
+----------------------------+
+_临时 变量2_______+
+----------------------------+
+_临时 变量.________+
+----------------------------+
+----------------------------+
+_临时 变量N_______+
+----------------------------+(低所在)
由于优化、调用行动、编译器的差别 ,上述构造部也许有所差别 ,但一样平常来说,第一个局部变量前是调用者的ebp,ebp前是返回后下一条指令的所在。
知道了这个结构,要得到上层调用的者指令所在就轻易了,我们可以用如下代码仿照glibc供给 的backtrace的功能:
int backtrace (void **BUFFER, int SIZE)
{
int n = 0;
int *p = &n;
int i = 0;
int ebp = p[1];
int eip = p[2];
for(i = 0; i < SIZE; i++)
{
BUFFER[i] = (void*)eip;
p = (int*)ebp;
ebp = p[0];
eip = p[1];
}
return SIZE;
}
附:
通过addr2line可以找到所在对应的文件名和行号,不消手动去查MAP文件了。
=======================
windows体系 上面要实现同样的功能,也许要调用 内里的StackWalk64 等函数。
http://msdn.microsoft.com/en-us/library/ms680650(VS.85).aspx
找到一个应用 StackWalk64 的例子http://www.cppblog.com/kevinlynx/archive/2008/03/28/45628.html
这里又是一个仿照backtrace(stackwalk)函数的例子
http://www.cnblogs.com/lbq1221119/archive/2008/04/18/1159956.html
着实 你可以在措施的任何地方 调用backtrace和 stackwalk函数的,呵呵
- 上一篇:gcc/g++中生成map文件
- 下一篇:调试参考网站
暂无评论
- 文章搜索
- 文章分类
- MTK_BD(7)
- 面向对象(5)
- C语言(42)
- 架构(0)
- 设计模式(1)
- 算法(2)
- 人生感悟(2)
- 家庭(0)
- 管理(1)
- good job(0)
- 工作(0)
- link(4)
- linux(5)
- 分布式(0)
- 进阶(1)
- 工具(4)
- C++(5)
- 源码网站(1)
- 牛B大学(3)
- 诗词(3)
- 调试(3)
- linux(0)
- 牛B博客(1)
- 优化(5)
- 汇编(3)
- FSM(6)
- 平台(1)
- 实际调试例子(1)
- VC(4)
- DVD(1)
- 脚本(1)
- 标准_规范(10)
- VC(0)
- 协议(5)
- 小技巧(1)
- 开源(1)
- SOCKET(4)
- google(1)
- GUI(3)
- 内存(1)
- MTK2.0(7)
- android(1)
- WINCE(3)
- 原创(1)
- 电子(1)
- 阅读排行
- 写宏遇到的问题:warning: bac... (115)
- C语言堆栈入门——堆和栈的区别 (99)
- 美国大学计算机专业排名 (97)
- http://people.ece.co... (87)
- 大小端转换 (85)
- 2010 COMPUTER(计算机专业)... (78)
- Linux调用backtrack函数打印...(77)
- 一种嵌入式系统的内存分配方案(zt) (71)
- 展讯平台MMI窗口开发说明书(58)
- linux alarm定时设置 (57)
- 推荐文章
- 最新评论
- 学习MISRA C之三:指针结构体联合体的安全规范
iukhjkk: 顶!!!!!!!
- 评论排行
- 学习MISRA C之三:指针结构体联合体... (1)
- 函数和宏函数 (0)
- MISRA C Rules __官方 (0)
- Linux中的exit()与_exit(... (0)
- 内核源码学习:Gcc嵌入式汇编(一) (0)
- 管道重定向符“|” (0)
- c++实现文件传输之一:框架结构和界面实... (0)
- c++实现文件传输之二 (0)
- ++实现文件传输之三:断点续传与多线程传... (0)
- c++实现文件传输之四:断点传输 (0)