Linux内核调试--打印调试信息的一种方法


Linux内核调试--打印调试信息的一种方法

在console_init()之前是不能通过printk来打印信息的,如何定位问题?

最先运行的是head.S文件中的一段汇编程序,在这里只能使用汇编语言写死循环语句了,如果cpu停住了,说明运行到这里了,如果没有停住就

会重启。那有没有这种情况,cpu没有停住,而是死了或者说不动了?不会,cpu一定是在一直运行着代码,不然就会重启了。

例如:

1: li t0, 0

li t1, 1

bne t0, t1, b1

接下来运行的就是C语言程序了,可以使用for(;;)加入死循环,看cpu是否会停住,在console_init()之后就可以使用printk()输出信息了。

其实在console_init()之前也是可以通过串口输出信息的,串口的输出实际上就是往串口寄存器写字符,再由串口输出。linux启动前,

bootloader肯定已经将串口配置好了,我们做的只是去写那个字符就可以了。

串口的输出大同小异,一般有两个寄存器,一个是data,一个是status。data是来收发字符的寄存器,status是反应收发状态的寄存器,两者

配合使用就能够从串口打印出信息,而不用调用printk()这么高级的函数。

从实际的例子出发,这里有data寄存器,地址为0xfffe0114,status寄存器,地址为0xfffe0110,其0x20位表示是否发送完成。所以在

console_init()之前的c语言函数中我们可以添加如下代码打印'#'。

*(volatile unsigned int *)(0xfffe0114) = '#';

while (!(*(volatile unsigned int *)(0xfffe0110) & 0x20));

这里同样也支持'\n', '\r'等换行退格的输出形式。

如何找到data和status寄存器的地址,还有至于status寄存器的哪一位表示发送完成,这些都可以通过看手册得到。

如果没有手册,也有办法,请按照如下轨迹去找:

/init/main.c -> start_kernel() -> console_init() -> xxxx_console_init() -> register_console()看参数的.write成

员函数,找到字符发送的地方就可以找到了。如果是2.6内核,请查找console_initcall,同样找到 xxxx_console_init() 后面就一样了。

当然,在最开始的汇编代码中也可以这样做,可以自己研究一下,应该不难。

Linuxidc免责声明:本文仅代表作者个人观点,与帮客之家(Linuxidc)无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。

相关内容