内核调试方法

1 .打印

       跟普通应用程序一样,打印信息是最直接的调试手段,通过打印信息来获得内核运行的情况和状态。

1.1 printk

       功能:通过控制台把内核信息按照日志级别打印出来。
       查看当前的系统的打印等级: cat /proc/sys/kernel/printk >7 4 1 7这里四个参数的意义:如下
        7:当前控制台命令级别,只要小于这个的命令级别才能够被打印出来。
        4:默认printk打印等级,即printk(“hello world”)函数不带命令等级的时候默认的等级,这里的是4比7小,则会打印。
        1:控制台级别可被设置的最小值(最高优先级)这里的1表示我控制台级别最高可以设置到1,那么级别为0的就一直会被打印
        7:默认的控制台日志级别,当没有设置控制台级别是就是默认的7级别
       修改打印级别:# echo 3 > /proc/sys/kernel/printk或者echo “3 4 1 7” > /proc/sys/kernel/printk

1.2 dmesg

       printk低级别的打印信息并没有被内核所丢弃,而是跟其他的信息一起存放在buffer里,通过dmesg可以把这些消息打印出来

基本用法:(1)直接输入dmesg,打印logbuffer中缓存所有信息,利用管道组合grep可以查找带XXX信息打印,dmesg | grep XXX ;(2)dmesg -C 显示的同时清空buffer数据,重新开始记录 (3)dmesg -n 打印级别,设置记录控制台输出最低级别;

1.3 仿照/proc/kmsg文件来自制一个文件,把打印信息打印到对应的文件中去

2 根据内核打印OOPS信息

有些会直接解析打印出来,有些只有pc值和栈信息,那么就要根据这些原始的值得出问题

2.1 根据PC值

        确定该指令是内核还是加载的模块:通过内核编译目录下的System.map确定内核的函数地址范围,如果不属于这里则属于加载的程序
①,在map内属于内核的函数
②,不在map内属于模块程序:cat /proc/kallsysms命令把所有的函数(内核函数、加载的函数)的地址都打印出来,在这里找一个相近的地址,保证是在这个函数内。
        反汇编对应的程序: 内核或者是驱动模块:arm-xilinx-linux-dump得到相应反汇编文件:
①,找到对应的函数
②,找到对应的语句,通过汇编得到对应的c语言位置
③,分析出错的原因

2.2 根据栈信息

Stack: (0xc3c7be88 to 0xc3c7c000) be80: c3c7bebc
c3c7be98 c008d888 bf000010 00000000 c049abc0 bea0: c3e740c0 c008d73c
c0474e20 c3e766a8 c3c7bee4 c3c7bec0 c0089e48 c008d74c bec0: c049abc0
c3c7bf04 00000003 ffffff9c c002c044 c3d10000 c3c7befc c3c7bee8 bee0:
c0089f64 c0089d58 00000000 00000002 c3c7bf68 c3c7bf00 c0089fb8
c0089f40 bf00: c3c7bf04 c3e766a8 c0474e20 00000000 00000000 c3eb1000
00000101 00000001 bf20: 00000000 c3c7a000 c04a7468 c04a7460 ffffffe8
c3d10000 c3c7bf68 c3c7bf48 bf40: c008a16c c009fc70 00000003 00000000
c049abc0 00000002 bec1fee0 c3c7bf94 bf60: c3c7bf6c c008a2f4 c0089f88
00008520 bec1fed4 0000860c 00008670 00000005 bf80: c002c044 4013365c
c3c7bfa4 c3c7bf98 c008a3a8 c008a2b0 00000000 c3c7bfa8 bfa0: c002bea0
c008a394 bec1fed4 0000860c 00008720 00000002 bec1fee0 00000001 bfc0:
bec1fed4 0000860c 00008670 00000002 00008520 00000000 4013365c
bec1fea8 bfe0: 00000000 bec1fe84 0000266c 400c98e0 60000010 00008720
00000000 00000000

利用打印出来的栈信息通过指令解析得到函数调用过程,以及在最后在哪里挂掉的。

3 通过修改内核定位系统僵死问题

        通过系统定时器中断:当系统卡死的时候定时器中断还是会一直产生中断。当进入中断的时候一直是同一个pid:current->pid可以获取当前的pid得到卡死的进程;
        进入中断的时候都会保存现场: 即会把当前的arm寄存器保存起来,其中就有pc指针,得到PC指针可以推算出卡死的位置:在中断总入口处添加代码
if当前中断等于系统定时器中断
{
如果前一个pid等于当前的pid且持续时间超过几s的时间,则已经在这里卡死。
打印出进入中断时的pc值regs->ARM_pc。
}
cat /proc/kallsysms得到所有函数的地址,通过pc值分析卡死的位置

猜你喜欢

转载自blog.csdn.net/weixin_43369409/article/details/84331374