首先参考:https://blog.csdn.net/gongmin856/article/details/79192259
接下来是我复制下来的代码,命名ttt.c
#include
#include
#include /* for signal */
#include /* for backtrace() */
#define BACKTRACE_SIZE 16
int divide(int num)
{
int ret = 0x00;
int *pTemp = NULL;
if(0 != num)
{
printf("num is not 0 !\n");
}
*pTemp = 0x01; /* 这将导致一个段错误,致使程序崩溃退出 */
ret = num + *pTemp;
return ret;
return 0;
}
void dump(void)
{
int j, nptrs;
void *buffer[BACKTRACE_SIZE];
char **strings;
nptrs = backtrace(buffer, BACKTRACE_SIZE);
printf("backtrace() returned %d addresses\n", nptrs);
strings = backtrace_symbols(buffer, nptrs);
if (strings == NULL) {
perror("backtrace_symbols");
exit(EXIT_FAILURE);
}
for (j = 0; j < nptrs; j++)
printf(" [%02d] %s\n", j, strings[j]);
free(strings);
}
void signal_handler(int signo)
{
#if 0
char buff[64] = {0x00};
sprintf(buff,"cat /proc/%d/maps", getpid());
system((const char*) buff);
#endif
printf("\n=========>>>catch signal %d <<<=========\n", signo);
printf("Dump stack start...\n");
dump();
printf("Dump stack end...\n");
signal(signo, SIG_DFL); /* 恢复信号默认处理 */
raise(signo); /* 重新发送信号 */
}
int main()
{
//fprintf(stdout, "input value\n");
int a = 3, b = 0;
char *p = NULL;
signal(SIGSEGV, signal_handler); /* 为SIGSEGV信号安装新的处理函数 */
signal(SIGUSR1, signal_handler); /* 为SIGSEGV信号安装新的处理函数 */
signal(SIGFPE, signal_handler); /* 为SIGSEGV信号安装新的处理函数 */
signal(SIGILL, signal_handler); /* 为SIGSEGV信号安装新的处理函数 */
signal(SIGQUIT, signal_handler); /* 为SIGSEGV信号安装新的处理函数 */
signal(SIGBUS, signal_handler); /* 为SIGSEGV信号安装新的处理函数 */
signal(SIGABRT, signal_handler); /* 为SIGSEGV信号安装新的处理函数 */
signal(SIGSYS, signal_handler); /* 为SIGSEGV信号安装新的处理函数 */
//&a = b;
//memcpy(p , &a, 8);
divide(0);
//fprintf(stdout, "div value: %d\n", div);
return 0;
}
几个命令:
/opt/toolchain/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc -g -rdynamic -funwind-tables -fasynchronous-unwind-tables ttt.c -o test_ttt
注:
-rdynamic 该参数是链接选项,不是编译选项。这主要是对可执行程序(elf)而言的,而编译动态库时,即使没有rdynamic选项,默认也会将非静态函数放入动态符号表中(刻意隐藏的函数除外)。默认情况下,可执行程序(非动态库)文件内我们定义的非静态函数,是不放到动态符号表中的,链接时只有加上"-rdynamic"才能将所有非静态函数加到动态符号表中。这个参数很多文章里都有写。
-funwind-tables -fasynchronous-unwind-tables:这几个参数比较恶心,很多文章里都没提到,其实很重要,作用是为了backtrace这个函数,如果不加这几个参数,那么backtrace函数会返回1,那么程序test_ttt运行时的栈回溯信息里就只有一个了,如下:
=========>>>catch signal 11 <<<=========
Dump stack start...
backtrace() returned 6 addresses
[00] /mnt/usr/zc/temp/RB1/test_ttt(dump+0x14) [0x400be8] //就会仅仅只有这一行了
[01] /mnt/usr/zc/temp/RB1/test_ttt(signal_handler+0x2c) [0x400cb8]
[02] linux-vdso.so.1(__kernel_rt_sigreturn+0) [0x7f9234a270]
[03] /mnt/usr/zc/temp/RB1/test_ttt(divide+0x34) [0x400bb0]
[04] /mnt/usr/zc/temp/RB1/test_ttt(main+0xc0) [0x400da4]
[05] /lib/libc.so.6(__libc_start_main+0xe4) [0x7f921f3824]
Dump stack end...
在使用addr2line查问题的时候就是看0x400bb0这个值了
/opt/toolchain/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-addr2line -e ~/smba_share/nfs/temp/RB1/test_ttt 0x400bb0
定位行数:
/home/zhaocan/smba_share/nfs/temp/RB1/ttt.c:18
如果此时使用objdump方法:
/opt/toolchain/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-objdump -S -l ~/smba_share/nfs/temp/RB1/test_ttt > info.txt
注:
-l --line-numbers
用文件名和行号标注相应的目标代码,仅仅和-d、-D或者-r一起使用使用-ld和使用-d的区别不是很大,在源码级调试的时候有用,要求编译时使用了-g之类的调试编译选项。
-S --source
尽可能反汇编出源代码,尤其当编译的时候指定了-g这种调试参数时,效果比较明显。隐含了-d参数。
由上面可以看出问题发生在divide函数里,打开info.txt文件,从下往上看
0000000000400b7c <divide>: //0x400b7c + 0X34 = 0x400bb0
divide():
/home/zhaocan/smba_share/nfs/temp/RB1/ttt.c:9
#include
#define BACKTRACE_SIZE 16
int divide(int num)
{
400b7c:a9bd7bfd stpx29, x30, [sp, #-48]!
400b80:910003fd movx29, sp
400b84:b9001fa0 strw0, [x29, #28]
/home/zhaocan/smba_share/nfs/temp/RB1/ttt.c:10
int ret = 0x00;
400b88:b9002fbf strwzr, [x29, #44]
/home/zhaocan/smba_share/nfs/temp/RB1/ttt.c:11
int *pTemp = NULL;
400b8c:f90013bf strxzr, [x29, #32]
/home/zhaocan/smba_share/nfs/temp/RB1/ttt.c:13
if(0 != num)
400b90:b9401fa0 ldrw0, [x29, #28]
400b94:7100001f cmpw0, #0x0
400b98:54000080 b.eq400ba8
/home/zhaocan/smba_share/nfs/temp/RB1/ttt.c:15
{
printf("num is not 0 !\n");
400b9c:90000000 adrpx0, 400000 <_init-0x988>
400ba0:91398000 addx0, x0, #0xe60
400ba4:97ffffa7 bl400a40
/home/zhaocan/smba_share/nfs/temp/RB1/ttt.c:18 //行数和addr2line查出来的一致
}
*pTemp = 0x01; /* 这将导致一个段错误,致使程序崩溃退出 */
400ba8:f94013a0 ldrx0, [x29, #32]
400bac:52800021 movw1, #0x1 // #1
400bb0:b9000001 strw1, [x0]
/home/zhaocan/smba_share/nfs/temp/RB1/ttt.c:20
ret = num + *pTemp;
400bb4:f94013a0 ldrx0, [x29, #32]
400bb8:b9400000 ldrw0, [x0]
400bbc:b9401fa1 ldrw1, [x29, #28]
400bc0:0b000020 addw0, w1, w0
400bc4:b9002fa0 strw0, [x29, #44]
/home/zhaocan/smba_share/nfs/temp/RB1/ttt.c:22
return ret;
400bc8:b9402fa0 ldrw0, [x29, #44]
/home/zhaocan/smba_share/nfs/temp/RB1/ttt.c:25
return 0;
}