1. 内核自带的trace方法:
a. 直接在内核中添加printk()调用。
c. Oops, 基本上是用来显示内核出错的瞬间寄存器的内容。参见内核文档.kernel-Oops.txt
2. 无源内核调试器:
a. kdb,使用SysRq键中断后,进行内核内存和寄存器的检查。需要在内核源码上打kdb补丁。也可以用一个串口终端程序。
b. Kprobes, 通过编写一个简单的module,获取任何内核数据结构。 使用Alt+SysRq+W键可以启用kprobed的module,进行内核内存和寄存器的检查。2.5.26以上内核内置Kprobes支持,不需打补丁。
需要配置:
CONFIG_KPROBES=y
CONFIG_MAGIC_SYSRQ=y
module例程:
/* include/linux/kprobes.h */ struct kprobe kp; /* specify pre_handler address */ kp.pre_handler=handler_pre; /* specify post_handler address */ kp.post_handler=handler_post; /* specify fault_handler address */ kp.fault_handler=handler_fault; /* specify the address/offset where you want to insert probe. * You can get the address using one of the methods described above. */ kp.addr = (kprobe_opcode_t *) kallsyms_lookup_name("do_fork"); /* check if the kallsyms_lookup_name() returned the correct value. */ if (kp.add == NULL) { printk("kallsyms_lookup_name could not find address for the specified symbol name/n"); return 1; } /* or specify address directly. * $grep "do_fork" /usr/src/linux/System.map * or * $cat /proc/kallsyms |grep do_fork # need CONFIG_KALLSYMS * or * $nm vmlinuz |grep do_fork */ /* 实际上可以在任何指令位置停下来,只要设置正确的指令地址 然后修改或printk任何东西 */ kp.addr = (kprobe_opcode_t *) 0xc01441d0; /* All set to register with Kprobes */ register_kprobe(&kp);
3. 源码级内核调试器:
a. kgdb。需要两台电脑,使用串口线或网线连接。需要在内核添加补丁。支持硬件断点。kgdb无法调试启动阶段的内核。
1. 设置两台机器的串口速度:
stty ispeed 115200 ospeed 115200 -F /dev/ttyS0
2. 测试:
开发机:echo hello > /dev/ttyS0
目标机:cat /dev/ttyS0 #目标机显示hello
3. 编译内核需要带调试符号,内核不能进行代码优化,如-O2。
4. 内核启动参数:kgdbwait将使kgdb在内核执行第一个内核线程时停下来,scheuler或init。
串口方式:kgdbwait kgdb8250=1,115200 # 端口号,速度
网口方式:kgdbwait [email protected].0.2/,@192.168. 0.3/ # local(target),remote(dev)
5. 开始调试:
gdb
file vmlinux # 源码目录的未压缩内核,有符号
set remotebaud 115200
target remote /dev/ttyS0
b. SkyEye。一个开发板或类似虚拟机的硬件模拟器,内置gdb的支持。非常适合调试内核,多用于调试嵌入式系统。配置过程较繁琐。
c. UML。即(User Mode Linux,用户模式Linux),就是作为应用程序运行的linux内核。>=2.6.9的内核内置UML,不需要打补丁。但要选择进行编译。在arch/um下。
1. gdb vmlinux,然后run就可以调试。
2. UML无法访问物理硬件,不适合开发驱动。但适合Linux内核其他方面的调试,比如启动,内存管理,调度。等等。
注:除了修改内核Makefile文件外,直接使用CONFIG_DEBUG_INFO=y,就可以产生内核调试符号=-g.