异常debug之GNU工具使用

xiaoxiao2021-02-28  98

先看看前面写的例子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 lr 00000746 <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 lr 00000750 <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 lr 0000076e <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 00000740 func4 /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_memcpy 00004000 A __bss_start U __cxa_atexit U dladdr 00004000 A _edata 00004005 A _end 00003e3c T __FINI_ARRAY__ U fprintf 00000764 T func1 /proc/self/cwd/vendor/libtest/test.c:22 00000750 T func2 /proc/self/cwd/vendor/libtest/test.c:15 00000746 T func3 /proc/self/cwd/vendor/libtest/test.c:9 00000738 T func4 /proc/self/cwd/vendor/libtest/test.c:3 U __gnu_Unwind_Find_exidx 00003e34 T __INIT_ARRAY__ U __libc_init 0000076e T main /proc/self/cwd/vendor/external/libtest/test.c:28 00003e2c 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/test symbols/test: file format elf32-littlearm architecture: arm, flags 0x00000150: HAS_SYMS, DYNAMIC, D_PAGED start 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_legacy22AudioPolicyManagerBase17set SystemPropertyEPKcS2 android_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:6 6 in vendor/libtest/test.c (gdb) info frame Stack 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:19 19 in vendor/libtest/test.c (gdb) info frame Stack 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 locals p = 0

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

//frame 0 (gdb) info registers r0 0x0 0 r1 0x5 5 r2 0xfffefa2c 4294900268 r3 0x0 0 r4 0xaaaaa76f 2863310703 r5 0xfffefa24 4294900260 r6 0x1 1 r7 0xfffefa2c 4294900268 r8 0x0 0 r9 0x0 0 r10 0x0 0 r11 0xfffefa00 4294900224 r12 0xf759b85c 4149852252 sp 0xfffef9d0 0xfffef9d0 lr 0xaaaaa761 -1431656607 pc 0xaaaaa760 0xaaaaa760 <func2+16> cpsr 0x70030 458800 //frame 1 (gdb) info registers r0 0x0 0 r1 0x5 5 r2 0xfffefa2c 4294900268 r3 0x0 0 r4 0xaaaaa76f 2863310703 r5 0xfffefa24 4294900260 r6 0x1 1 r7 0xfffefa2c 4294900268 r8 0x0 0 r9 0x0 0 r10 0x0 0 r11 0xfffefa00 4294900224 r12 0xf759b85c 4149852252 sp 0xfffef9cc 0xfffef9cc lr 0xaaaaa761 -1431656607 pc 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 0x00000005 0xfffef9e8: 0xfffefa2c /*b表示单字节,h表示双字节,w表示四字节,g表示八字节*/ /* x 按十六进制格式显示变量。 d 按十进制格式显示变量。 u 按十六进制格式显示无符号整型。 o 按八进制格式显示变量。 t 按二进制格式显示变量。 a 按十六进制格式显示变量。 c 按字符格式显示变量。 f 按浮点数格式显示变量。 */
转载请注明原文地址: https://www.6miu.com/read-54244.html

最新回复(0)