http://blog.chinaunix.net/uid-29401328-id-4932947.html
下面再来测试一次:
# insmod syst.kos_init success!
# ./test // 卡死了,等10s会打印如下信息
asm_do_IRQ -> s3c2410_timer_irq : pid = 635 , task_name = test , pc = bf0d700c
asm_do_IRQ -> s3c2410_timer_irq : pid = 635 , task_name = test , pc =bf0d700c
我们一眼就看出来了,问题出现在test这个程序上,但具体出在哪不清楚,就要根据PC值去分析了,分析方法和之前博文讲的一样。
下面再唠叨一遍:
1. 找到bf0d700c所在的函数。
现在的系统僵死了,我们没办法继续下去,只有重启系统。这里注意一个问题,重启系统使用的内核要和僵死时使用的内核是同一个。
因为如果内核变了,我们就很难还原僵死前的状态了,新内核pc = bf0d700c可能代表不同的代码。
用tftp启动刚才的内核,插入模块 sy.ko。
先去查看内核源码下的 System.map 文件,看PC地址是否属于其中,这里不属于(那里面是内核函数,地址都是以C开头) 。
然后查看开发板的模块地址:cat cat /proc/kallsyms >kall.txt 或者 cat /proc/kallsyms | grep bf0d700c 管道过滤
00000000 a system_dead.c [sydead]
bf0d7000 t $a [system_dead]
bf0d7000 t sysdead_test_open [sydead]
bf0d7010 t sysdead_drv_exit [sydead]
可知 pc = bf0d70 0c位于 sy_open函数中。接下来去分析这个函数
2. 分析发生错误的函数
因为我们这里的代码很短,所以可以很快的定位出问题,但当代码很长时,可能就需要看汇编了。这里给出方法
反汇编 sy_open函数 位于的模块 sy.ko :
arm-none-linux-gnueabi-objdump sy.ko -D > sy.dis
打开 sy.dis:(贴出对我们有用的那段)
00000000 :
0: e1a0c00d mov ip, sp
4: e92dd800 push {fp, ip, lr, pc}
8: e24cb004 sub fp, ip, #4 ; 0x4
c: eafffffe b c
到这里就需要用汇编去分析了,我们这里的错误比较明显,就是一直跳转到自己这个函数里,调不出去了。
注:有可能两次发生僵死时PC值不一样,就算僵死在同一段代码,PC值也可能不一样。因为 如 果死循环是一段代码,
那么僵死时,程序可能正在执行这段代码当中的任意一句。
2 OOPS
Oops 中包含的重要信息对于所有体系结构都是完全相同的 : 寄存器上下文和回溯线索 . 回溯线索显示了导致错误发生的函数调用链 . 寄存器上下文信息可能同样有用 , 尽管使用起来不那么方便 . 如果你有函数的汇编代码 , 这些寄存器数据可以帮助你重建引发问题的现场 . 在寄存器中一个本不应该出现的数值可能会在黑暗中给你带来第一丝光明 .
[1] ksymoops
提供编译内核是产生的 System.map 和模块信息 ( 如何你使用的是模块 ) 把 OOPS 信息解码 .
$ ksymoops saved_oops.txt
[2] kallsysms
开发版的 2.5 内核引入了 kallsysms 特性 , 它可以通过定义 CONFIG_KALLSYMS 配置选项启用 . 该选项可以载入内核镜像对应的内存地址的符号名称 , 所以内核可以打印解码好的跟踪线索 . 相应地 , 解码 oops 也不再需要 system.map 或者 ksysmoops 工具了 .
3 内核调试配置选
这些选项都在内核配置编辑器的内核开发 (Kernel Hacking) 菜单中 , 他们都依赖于 CONFIG_DEBUG_KERNEL. 当你开发内核的时候 , 作为一种练习 , 不妨都打开这些选项 .
[1] 调试原子操作
把内核配置成一旦在原子操作过程中进程进入休眠或者做了一些可能引起休眠的操作 , 就打印警告信息并提供追踪线索 .
CONFIG_PREEMPT = y
CONFIG_DEBUG_KERNEL = y
CONFIG_KALLSYMS = y
CONFIG_SPINLOCK_SLEEP = y
4 引发 bug 并打印信息
BUG() BUG_NO() 被调用时引发 oops, 导致栈的回溯和错误信息的打印
panic() 不但会打印错误信息 , 而且会挂起整个系统
dump_stack() 在终端上打印寄存器上下文和函数跟踪线索 .
5 神奇的 SysRq
神奇系统请求键是另外一根救命稻草 , 该功能可以通过定义 CONFIG_MAGIC_SYSRQ 配置选项开启用 . 当该功能被启用的时候 , 无论内核处于什么状态 , 你都可以通过特殊的组合键跟内核进行通信 .
6 内核调试器的传奇
[1] gdb
$ gdb vmlinux /proc/kcore
> p global_variable
> disassemble function
[2] kgdb
[3] kdb
http://blog.chinaunix.net/uid-26923078-id-3327126.html