异常debug之GNU工具使用

先看看前面写的例子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 按浮点数格式显示变量。
*/
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值