驱动程序的调试
一. 打印: prink, 自制proc文件
UBOOT传入console=ttySAC0 console=tty1
-
内核处理UBOOT传入的参数
console_setup
add_preferred_console // 我想用名为"ttySAC0"的控制台,先记录下来 -
硬件驱动的入口函数里:
drivers/serial/s3c2410.c
register_console(&s3c24xx_serial_console); -
printk
vprintk
/* Emit the output into the temporary buffer */
// 先把输出信息放入临时BUFFER
vscnprintf// Copy the output into log_buf. // 把临时BUFFER里的数据稍作处理,再写入log_buf // 比如printk("abc")会得到"<4>abc", 再写入log_buf // 可以用dmesg命令把log_buf里的数据打印出来重现内核的输出信息 // 调用硬件的write函数输出 release_console_sem(); call_console_drivers(_con_start, _log_end); // 从log_buf得到数据,算出打印级别 _call_console_drivers(start_print, cur_index, msg_level); // 如果可以级别够格打印 if ((msg_log_level < console_loglevel __call_console_drivers con->write(con, &LOG_BUF(start), end - start);
二. 根据内核打印的段错误信息分析
a. 作为模块:
- 根据pc值确定该指令属于内核还是外加的模块
pc=0xbf000018 它属于什么的地址?是内核还是通过insmod加载的驱动程序?
先判断是否属于内核的地址: 看System.map确定内核的函数的地址范围:c0004000~c03265a4
如果不属于System.map里的范围,则它属于insmod加载的驱动程序
-
假设它是加载的驱动程序引入的错误,怎么确定是哪一个驱动程序?
先看看加载的驱动程序的函数的地址范围
cat /proc/kallsyms (内核函数、加载的函数的地址)
从这些信息里找到一个相近的地址, 这个地址<=0xbf000018
比如找到了:
bf000000 t first_drv_open [first_drv] -
找到了first_drv.ko
在PC上反汇编它: arm-linux-objdump -D first_drv.ko > frist_drv.dis
在dis文件里找到first_drv_openfirst_drv.dis文件里 insmod后
00000000 <first_drv_open>: bf000000 t first_drv_open [first_drv]
00000018 pc = bf000018
./firstdrvtest on
Unable to handle kernel