标签:
使用空指针和缓冲区溢出是产生oops的两个最常见原因。
1、直接查看oops信息,首先查找源代码发生oops的位置,通过查看指令寄存器EIP的值,可以找到位置。再查找函数调用栈可以得到更多的信息。从函数调用栈可辨别出局部变量,全局变量和函数参数。较为重要的信息就是指令指针(EIP),即出错指令的地址。
例如:在函数faulty_read的oops信息的函数调用栈中,栈顶为ffffffff,栈顶值应为一个小于ffffffff的值,为此值,说明再找不回调用函数地址,说明有可能因缓冲区溢出等原因造成指针错误。
如果oops信息显示触发oops的地址为0xa5a5a5a5,则说明很可能是因为没有初始化动态内存引起的。
2、使用\prebuilts\gcc\linux-x86\arm\arm-eabi-4.7\bin\arm-eabi-addr2line命令找到地址对应的程序位置,显示对应的程序文件名和行号。
1.arm-eabi-addr2line 将类似libxxx.so 0x00012345的调用栈16进制值翻译成文件名和函数名
arm-eabi-addr2line -e libxxx.so 0x00012345
2.arm-eabi-nm 列出文件的符号信息
arm-eabi-nm -l -C -n -S libdvm.so > dvm.data
3.arm-eabi-objdump 列出文件的详细信息
arm-eabi-objdump -C -d libc.so > libc.s
通过以上工具的分析 ,我们可以得到较完整的调用栈以及调用逻辑的汇编码。
addr2line -e -f libc.so 0001173c
objdump -S -D libc.so > deassmble_libc.txt
打开这个反汇编过后的重定向文件,在查询的时候输入1173c这个偏移地址,你会看到在茫茫人海中
00011684 <pthread_create>:
11684: e92d4ff0 push {r4, r5, r6, r7, r8, r9, sl, fp, lr}
11688: e24dd01c sub sp, sp, #28 ; 0x1c
1168c: e1a06001 mov r6, r1
11690: e1a08002 mov r8, r2
11694: e1a09003 mov r9, r3
11698: e3a04001 mov r4, #1 ; 0x1
1169c: e59f521c ldr r5, [pc, #540] ; 118c0 <pthread_create+0x23c>
116a0: e58d000c str r0, [sp, #12]
116a4: eb009a35 bl 37f80 <strncmp+0x20>
116a8: e59f2214 ldr r2, [pc, #532] ; 118c4 <pthread_create+0x240>
116ac: e1a03000 mov r3, r0
116b0: e1a01004 mov r1, r4
116b4: e593c000 ldr ip, [r3]
116b8: e3a0003c mov r0, #60 ; 0x3c
116bc: e08f3005 add r3, pc, r5
116c0: e7933002 ldr r3, [r3, r2]
116c4: e5834000 str r4, [r3]
116c8: e58dc010 str ip, [sp, #16]
116cc: eb009a3b bl 37fc0 <strncmp+0x60>
...
1173c: ebffec2b bl c7f0 <__pthread_clone>-->就是他了,对你成功了。
...
3、在分析转储映像之前,用户应重启动进入一个稳定的内核。用户可以用GDB对拷贝出的转储进行有限分析。编译vmlinux时应加上-g选项,才能生成调试用的符号,然后,用下面的命令调试vmlinux:
gdb vmlinux <dump-file>
首先 objdump -D vmlinx 反汇编你的内核
然后 你可以通过以下几个寄存器来判断:
1. epc 挂在哪个函数里
2. ra 函数的返回地址,
3. Cause 通过这个寄存器可以分析是什么类型的异常.
4、通过cat /proc/modules获得模块内核链接基地址,用死机地址减去链接基地址得到模块内偏移,再反汇编,找该偏移对应的函数就找到了死机函数。
用objdump -d test.ko > test.asm的话。可以将模块文件反汇编。但是因为模块是目标文件,所以会看到,text段的地址是从0开始的。而该模块在内核在运行的时候,该模块的代码段显然不是在0地址。另外,该代码段中你会看到函数间调用,以及函数内部跳转都是用的b开头的分支指令(仅限于mips和arm的体系结构的讨论),分支指令跳转是以pc为基准值前后跳转的。除非,跳转符号不属于这个模块,则需要32位的跳转。实际上,模块链接到内核的时候,模块的代码段是作为一个整体链接到内核,所以我们只需要知道模块链接到的基地址,再用死机的地址减去这个基地址这就得到了,该地址在模块中代码段的偏移,再通过刚才的反汇编文件就找到了是死在那个函数中。而要得到各个模块的链接地址就很简单了,直接cat /proc/modules就得到了。需要注意的是用__init修饰了的模块初始化函数,是放在单独的段的,通常叫.init.text 。该段会在模块初始化完成后内存就释放掉了
5、google提供了一个python脚本,可以从 http://code.google.com/p/android-ndk-stacktrace-analyzer/ 下载这个python脚本,然后使用
adb logcat -d > logfile 导出 crash 的log,
使用 arm-eabi-objdump (位于build/prebuilt/linux-x86/arm-eabi-4.2.1/bin下面)把so或exe转换成汇编代码,如:
arm-eabi-objdump -S mylib.so > mylib.asm,
然后使用脚本
python parse_stack.py <asm-file> <logcat-file>
http://blog.csdn.net/lickylin/article/details/19172725
如上崩溃信息,可知发生崩溃的函数为rb_init_debugfs,崩溃的地址为0x804386f8
1>在linux下,到工程的如下目录下:kernel/linux,找到文件vmlinux,执行命令gdb vmlinux:
在gdb命令下执行如下命令即可查找到出错函数所在的文件与行数
(gdb) b *0x804386f8
2>如果不确定崩溃的地址是否是0x804386f8,可以在文件System.map中
查找函数rb_init_debugfs获取该函数的地址,然后加上偏移地址(本例中偏移地址为0x14 rb_init_debugfs+0x14/0x70)即可。
3>直接函数名加偏移量也可以
(gdb) b *rb_init_debugfs+0x14
上面是出错模块是编译进内核的,对于编译进内核的模块可以通过gdb vmlinux来确定出错函数所在的文件与行数。
那如果出错模块是动态加载进内核的该怎么办呢?
这就需要使用objdump进行反汇编操作了,使用如下命令,就会将C语言与汇编语言同时显示(需要加-g命令)
#objdump -S **.o -g
如果使用上面命令,还是只显示汇编,而没有c语言的话,不用担心,在你编译驱动模块的Makefile中,编译成.o文件时,增加-g选项,
对于新生成的.o文件再使用上面的命令就 可以看到汇编与c语言共存了。然后根据kernel panic提示中显示的函数名加上偏移量就能找到出错行了。
http://blog.csdn.net/wuruixn/article/details/38320643
2. 启动GDB, 直接在主机(开发机)控制台运行gdb工具(或./mips-linux-uclibc-gdb),然后敲入 file ...../vmlinux启动带调试信息的内核,注意此时要配置内核debug开关重新编译内核生成文件vmlinux(比之前的文件大10倍左右,50M以上),配置内核debug开关如下,
注:如果list*(0x80xxxxxx)命令提示如下信息:No source file for address 0x80xxxxxx. 原因是没有在make menuconfig中打开对应的调试开关进行编译。
标签:
原文地址:http://www.cnblogs.com/thjfk/p/4383803.html