特别声明:
建议使用google游览器,火狐也可以
论坛处于测试阶段,一切资料都为测试资料,在论坛正式运行的时候,会尽量保存网友的劳动成果!
HelloWorld论坛秉持互惠互利,共同学习与进步,一个人的梦想大家实现的理想,一直坚持着,望广大网友多多支持,提供宝贵意见
来论坛做什么?
可以先转载你平时学习查找的资料(先论坛查找),自己可以写写体会
把平时碰到的问题,如何解决可以先记录在论坛,以备后来的人学习
可以和会员一起参加一些开源项目的学习,汉化,推广,甚至可以加入团队
|
|
可以给自己的程序都加上这个东西,便于快速的找到错误吧,看到别人都是这么用的 #include<stdio.h> #include<string.h> #include<stdlib.h> #include<signal.h> #include<execinfo.h> #include<time.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 #if 0 static void WidebrightSegvHandler(int signum) { void *array[10]; size_t size; char **strings; size_t i, j; // 获取当前时间 struct tm *newtime; char tmpbuf[128]={0}; time_t lt1; lt1=time(NULL); newtime=localtime(<1); strftime(tmpbuf, 128, "Today is %A, day %d of %B in the year %Y.\n", newtime); fprintf(stderr,tmpbuf); 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, "%zu %s \n",i,strings[i]); } free (strings); exit(1); } #else // 写文件 static void WidebrightSegvHandler(int signum) { void *array[10]; size_t size; char **strings; size_t i, j; FILE * pFile = fopen ("./backtrace", "a" ); if (pFile == NULL) { return ; } // 获取当前时间 struct tm *newtime; char tmpbuf[128]={0}; time_t lt1; lt1=time(NULL); newtime=localtime(<1); strftime(tmpbuf, 128, "Today is %A, day %d of %B in the year %Y.\n", newtime); fprintf(pFile,tmpbuf); signal(signum, SIG_DFL); /* 还原默认的信号处理handler */ size = backtrace (array, 10); strings = (char **)backtrace_symbols (array, size); fprintf(pFile, "widebright received SIGSEGV! Stack trace:\n"); for (i = 0; i < size; i++) { fprintf(pFile, "%zu %s \n",i,strings[i]); } free (strings); fclose(pFile); exit(1); } #endif 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 ===============================================
好像使用
开发嵌入式软件通常是比较麻烦的事,一些常用的工具往往无法使用,在开发PC软件时简单的任务,此时变得很复杂。今天就遇到了这样一件事,折腾了几个小时,仅仅是为知道call stack。 我编译了一个程序放到PDA(ARM9+LINUX+UCLIBC)上面运行,出现了一个ASSERT,并显示了文件名和行号,原来是调用了一个没有实现 的函数,我很想知道是谁调用了它,这看似简单的问题却让我很头疼,如果有gdb,那好办-用bt命令就可以搞定,如果用的libc,那也好办-用 backtrace函数就可以搞定,问题是两者都没有。 想来想去只有自己写一个backtrace,要实现这个功能并不难,如果我们知道调用堆栈的格式,就可以很容易取出上层调用者的指令地址,有了这些上层调用者的指令地址,我们可以通过MAP文件找到指令地址对应的源文件名和行号。 下面简要介绍一下实现原理: 要获得调用者的地址,有必要介绍一下堆栈的格式:
+---------------------------+ (高地址)
知道了这个结构,要获得上层调用的者指令地址就容易了,我们可以用如下代码模拟glibc提供的backtrace的功能:
int ebp = p[1];
for(i = 0; i < SIZE; i++)
return SIZE;
附:
|
[审核人]初学MPEG |
|
|
Please Login (or Sign Up) to leave a comment |