异常debug之GNU工具使用

来源:互联网 发布:vb控件随窗体变化 编辑:程序博客网 时间:2024/05/20 22:02

先看看前面写的例子test.c:

  1 #include <stdio.h>  2   3 void func4()  4 {  5     char *p = NULL;  6     *p = 0x5;//出错地方;  7 }  8   9 void func3() 10 { 11     int var4 = 4; 12 } 13  14  15 void func2() 16 { 17     int var3 = 3; 18     func3(); 19     func4(); 20 } 21  22 void func1() 23 { 24     int var1,var2; 25     var1 = 2; 26 } 27  28 void main() 29 { 30     int var0 = 1; 31     func1(); 32     func2(); 33     return; 34 } 35

反汇编出来的代码test.S:

00000738 <func4>:     738:   b081        sub sp, #4     73a:   2000        movs    r0, #0     73c:   9000        str r0, [sp, #0]     73e:   2105        movs    r1, #5     740:   7001        strb    r1, [r0, #0]     742:   b001        add sp, #4     744:   4770        bx  lr00000746 <func3>:     746:   b081        sub sp, #4     748:   2004        movs    r0, #4     74a:   9000        str r0, [sp, #0]     74c:   b001        add sp, #4     74e:   4770        bx  lr00000750 <func2>:     750:   b580        push    {r7, lr}     752:   b082        sub sp, #8     754:   2003        movs    r0, #3     756:   9001        str r0, [sp, #4]     758:   f7ff fff5   bl  746 <func3>     75c:   f7ff ffec   bl  738 <func4>     760:   b002        add sp, #8     762:   bd80        pop {r7, pc}00000764 <func1>:     764:   b082        sub sp, #8     766:   2002        movs    r0, #2     768:   9001        str r0, [sp, #4]     76a:   b002        add sp, #8     76c:   4770        bx  lr0000076e <main>:     76e:   b580        push    {r7, lr}     770:   b082        sub sp, #8     772:   2001        movs    r0, #1     774:   9001        str r0, [sp, #4]     776:   f7ff fff5   bl  764 <func1>     77a:   f7ff ffe9   bl  750 <func2>     77e:   b002        add sp, #8     780:   bd80        pop {r7, pc}

发生问题的backtrace:

Backtrace:     #00 pc 00000740  /system/bin/test    #01 pc 0000075d  /system/bin/test    #02 pc 0000077b  /system/bin/test    #03 pc 0001708c  /system/lib/libc.so (__libc_init+84)    #04 pc 00000660  /system/bin/test

(1)addr2line

将地址转换为地址所在的文件及行数:

$ ./arm-linux-androideabi-addr2line -e symbols/test -f 00000740func4/proc/self/cwd/vendor/libtest/test.c:6

所以可以定位test.c第6行出现问题;

(2)nm

列出该文件的符号(函数,变量,文件等),包含名字、地址、大小;

-D, –dynamic: 只显示动态符号;
-g, –extern-only: 只显示外部符号;
-u, –undefined-only: 只显示未定义的符号;
-C, –demangle[=STYLE]: 反重整符号为可读方式自动识别格式;
-l, –line-numbers:多显示符号所在文件和行数;

$ ./arm-linux-androideabi-nm -C -l -g symbols/test          U abort         U __aeabi_memclr8         U __aeabi_memcpy00004000 A __bss_start         U __cxa_atexit         U dladdr00004000 A _edata00004005 A _end00003e3c T __FINI_ARRAY__         U fprintf00000764 T func1    /proc/self/cwd/vendor/libtest/test.c:2200000750 T func2    /proc/self/cwd/vendor/libtest/test.c:1500000746 T func3    /proc/self/cwd/vendor/libtest/test.c:900000738 T func4    /proc/self/cwd/vendor/libtest/test.c:3         U __gnu_Unwind_Find_exidx00003e34 T __INIT_ARRAY__         U __libc_init0000076e T main /proc/self/cwd/vendor/external/libtest/test.c:2800003e2c D __PREINIT_ARRAY__         U __register_atfork         U __snprintf_chk         U __stack_chk_fail         U __stack_chk_guard         U stderr

(3)objdump

查看对象文件(.so/.a或应用程序)的内容信息;

-a, –archive-headers: 显示库(*.a)成员信息
-f, –file-headers:显示obj中每个文件的整体头部摘要信息
-h, –[section-]headers:显示目标文件各个section的头部摘要信息
-x, –all-headers: 显示所有头部摘要信息
-d, –disassemble:反汇编代码段
-D, –disassemble-all: 反汇编所有段
-S, –source:反汇编出源代码,额外有debug信息,隐含-d,如果编译时有-g,效果
更明显
-t, –syms: 显示符号表
-r, –reloc: 显示重定位记录
-C, –demangle[=STYLE]: 反重整符号为可读方式

$ ./arm-linux-androideabi-objdump -f symbols/testsymbols/test:     file format elf32-littlearmarchitecture: arm, flags 0x00000150:HAS_SYMS, DYNAMIC, D_PAGEDstart address 0x00000600

(4)readelf

看elf文件(.so/.a或应用程序)的内容信息;

-a, –all: 显示所有可显示的内容
-h –file-header: 显示ELF文件头
-l –segments: 显示程序头组
-S –sections: 显示节头组
-t: 显示节头细节
-e –headers: 等效于-h -l -S
-s –syms: 显示符号表
-n –notes: 显示内核说明
-r –relocs: 显示重定位信息
-u –unwind: 显示解栈信息
-d –dynamic: 显示动态节
-p –string-dump=

./arm-linux-androideabi-readelf -h symbols/test ELF Header:  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00   Class:                             ELF32  Data:                              2's complement, little endian  Version:                           1 (current)  OS/ABI:                            UNIX - System V  ABI Version:                       0  Type:                              DYN (Shared object file)  Machine:                           ARM  Version:                           0x1  Entry point address:               0x600  Start of program headers:          52 (bytes into file)  Start of section headers:          96780 (bytes into file)  Flags:                             0x5000200, Version5 EABI, soft-float ABI  Size of this header:               52 (bytes)  Size of program headers:           32 (bytes)  Number of program headers:         9  Size of section headers:           40 (bytes)  Number of section headers:         39  Section header string table index: 38

(5)c++filt

反重整C++符号为可读方式;

$ ./arm-linux-androideabi-c++filt _ZN20android_audio_legacy22AudioPolicyManagerBase17setSystemPropertyEPKcS2android_audio_legacy::AudioPolicyManagerBase::setSystemProperty(char const*, char const*)

(5)gdb

gdb调试在前获取带有符号的bin文件,从AEE log当中获取的coredump来调试,这里主要讲静态调试,当发生coredump的时候,通过带有符号信息的bin文件和coredump来分析问题;

$ ./arm-linux-androideabi-gdb symbols/test PROCESS_COREDUMP(gdb) set solib-search-path out/target/product/xxx/symbols/system/lib/(gdb) set solib-absolute-prefix out/target/product/xxx/symbols/

这样设置之后就可以通过gdb调试这个程序了;

(gdb) bt  //堆栈信息#0  0xaaaaa740 in func4 () at vendor/libtest/test.c:6 //当前栈;#1  0xaaaaa760 in func2 () at vendor/libtest/test.c:19#2  0xaaaaa77e in main () at vendor/libtest/test.c:32

info f:打印出更为详细的当前栈层的信息(目前的函数是由什么样的程序语言写成的、函数参数地址及值、局部变量的地址等等):

(gdb) frame 0#0  0xaaaaa740 in func4 () at vendor/libtest/test.c:66   in vendor/libtest/test.c(gdb) info frameStack level 0, frame at 0xfffef9d0: pc = 0xaaaaa740 in func4 (vendor/libtest/test.c:6); saved pc 0xaaaaa760 called by frame at 0xfffef9e0 source language c. Arglist at 0xfffef9cc, args:  Locals at 0xfffef9cc, Previous frame's sp is 0xfffef9d0(gdb) frame 1#1  0xaaaaa760 in func2 () at vendor/libtest/test.c:1919  in vendor/libtest/test.c(gdb) info frameStack level 1, frame at 0xfffef9e0: pc = 0xaaaaa760 in func2 (vendor/libtest/test.c:19); saved pc 0xaaaaa77e called by frame at 0xfffef9f0, caller of frame at 0xfffef9d0 source language c. Arglist at 0xfffef9d0, args:  Locals at 0xfffef9d0, Previous frame's sp is 0xfffef9e0 Saved registers:  r7 at 0xfffef9d8, lr at 0xfffef9dc

info args:打印出当前函数的参数名及其值。info locals:打印出当前函数中所有局部变量及其值。

(gdb) info localsp = 0

info registers:打印出所有寄存器的值;

//frame 0(gdb) info registersr0             0x0  0r1             0x5  5r2             0xfffefa2c   4294900268r3             0x0  0r4             0xaaaaa76f   2863310703r5             0xfffefa24   4294900260r6             0x1  1r7             0xfffefa2c   4294900268r8             0x0  0r9             0x0  0r10            0x0  0r11            0xfffefa00   4294900224r12            0xf759b85c   4149852252sp             0xfffef9d0   0xfffef9d0lr             0xaaaaa761   -1431656607pc             0xaaaaa760   0xaaaaa760 <func2+16>cpsr           0x70030  458800//frame 1(gdb) info registersr0             0x0  0r1             0x5  5r2             0xfffefa2c   4294900268r3             0x0  0r4             0xaaaaa76f   2863310703r5             0xfffefa24   4294900260r6             0x1  1r7             0xfffefa2c   4294900268r8             0x0  0r9             0x0  0r10            0x0  0r11            0xfffefa00   4294900224r12            0xf759b85c   4149852252sp             0xfffef9cc   0xfffef9cclr             0xaaaaa761   -1431656607pc             0xaaaaa740   0xaaaaa740 <func4+8>cpsr           0x70030  458800

根据上面的信息可以大概画出当前栈的情况:

这里写图片描述

查看存储器状态:

(gdb) p a //定义了一个数组:a[3]$1 = {5, 5, 5}(gdb) p &a$2 = (int (*)[3]) 0xfffef9d8(gdb) p &a[2]$4 = (int *) 0xfffef9e0(gdb) p &a[1]$5 = (int *) 0xfffef9dc(gdb) p &a[0]$6 = (int *) 0xfffef9d8(gdb) x/5wx 0xfffef9d8    //显示5个单元,w四字节一个单元,x十六进制显示0xfffef9d8: 0x00000005  0x00000005  0x00000005  0x000000050xfffef9e8: 0xfffefa2c/*b表示单字节,h表示双字节,w表示四字节,g表示八字节*//*x 按十六进制格式显示变量。d 按十进制格式显示变量。u 按十六进制格式显示无符号整型。o 按八进制格式显示变量。t 按二进制格式显示变量。a 按十六进制格式显示变量。c 按字符格式显示变量。f 按浮点数格式显示变量。*/
原创粉丝点击