一、内核开发的配置选项
1.CONFIG_DEBUG_KERNEL
该选项仅仅使得其他的调试选项可以。我们应该打开该选项,但它本身不会打开所以的调试功能。
2.CONFIG_DEBUG_SLAB
这是一个非常重要的选项,他打开内核内存分配函数中的多个类型检查:打开该检查后,就可以检测许多内存溢出及忘记初始化的错误。在将已分配内存返回给调用者之前,内核将把其中的每个字节设置为0xa5,而在释放后将其设置为0x6b。可在自己去的程序的输出或用过在oops信息中看字符判断问题所在。在打开调试选项后,内核还会在每个已分配内存对象的前面或后面防止特殊防护值。这样,当防护值发生改变是,内核就可以知道有些代码超出了内存的正常访问范围,并警报。
3.CONFIG_DEBUG_PAGELLOC
在释放时,全部内存页从内核地址空间移出。该选项大大降低了运行速度,但可以快速定位特定的内存损坏错误的所在位置。
4.CONFIG_DEBUG_SPINLOCK_SLEEP
该选项将检查用于自旋锁时的休眠企图。若调用可能引起休眠的函数,这个选项也会生效,即使该函数可能不会导致真正的休眠。
5.CONFIG_INIT_DEBUG
标记为_ init(或 _initdata)的符号将会在系统初始化或模块装载后被丢弃。该选项用来检查初始化后对于初始化的内存空间的访问企图。
6.CONFIG_DEBUG_INFO
该选项使内核的构造包含完整到的调试信息。若用gdb调试内核,则需要这些消息,当使用gdb时,还需要打开CONFIG_FRAME_POINTER选项。
7.CONFIG_DEBUG_* || CONFIG_DEBUG_STACK_USAGE
这些选项可帮助跟踪内核栈的溢出问题。栈溢出的确切信号是不包含任何合理的反向跟踪信息的oops清单。第一个选项将在内核中增加明确的溢出检查。第二个选项将让内核监视栈的使用,并通过SysRq按键输出一些统计信息。
8.CONFIG_KALLSYMS
该选项出现在General setup/Standard features菜单中,将在内核中包含符号信息。该选项默认是打开的,该符号信息用于调试上下文。
9.CONFIG_IKCONFIG || COFIG_IKCONFIG_PROC
这些选项出现在General setup菜单中,会让完整的内核配置状态包含到内核中,可通过/proc访问。
10.CONFIG_ACPI_DEBUG
该选项出现在Power management/ACPI菜单中。该选项在打开ACPI(Advanced Configuration and Power Interface,高级配置和电源接口)中的详细调试信息。
11.CONFIG_DEBUG_DRIVER
在Device drivers菜单中,该选项打开驱动程序核心中的调试信息,帮助追踪底层支持代码中的问题。
12.CONFIG_SCSI_CONSTANTS
该选项出现在Device drivers/SCSI device support菜单中,它将打开详细的SCSI错误信息。
13.CONFIG_INPUT_EVBUG
该选项在Device drivers/Input device support中找到,它会打开对输入事件的详细记录。若要求针对输入设备编写驱动程序,则可以使用该选项。该选项会记录键入的任何东西,会导致安全问题。
14.CONFIG_PROFILING
该现象可在Profiling support(剖析支持)菜单中找到,剖析通常用于系统性能的调节,但对跟踪内核挂起及相关问题也会有所帮助。
二、通过打印调试
调试内核代码是,利用printk来完成调试。
printk可以通过附加不同的日志级别,或者消息优先级来根据这些级别锁表示的严重程序对消息进行分类。
在编译时将表示日志级别的宏和消息文本拼接在一起,无逗号。
例如:
调试信息:
printk(KERN_DEBUG "Here I am:%s:%i\n",_ _FILE _ _, _ _LINE _ _);
临界信息:
printk(KERN_CRIT "I'm trashed; giving up on %p\n",ptr);
八种可用的日志级别字符串:
1.KERN_EMERC
用于紧急事件消息,一般是系统崩溃前的提示信息。
2.KERN_ALERT
用于需要立即采取动作的情况。
3.KERN_CRIT
临界状态,通常涉及严重的硬件或软件操作失败。
4.KERN_ERR
用于报告错误状态。设备驱动程序会经常使用KERN_ERR来报告来自硬件的问题。
5.KERN_WARNING
对可能出现的情况进行警告,但着了情况通常不会对系统造成严重问题。
6.KERN_NOTICE
有必要进行提示的正常情况。许多与安全相关的状况用这个级别进行汇报。
7.KERN_INFO
提示性信息,很多驱动程序在启动的时候以这个级别来打印出它们找到的硬件信息。
8.KERN_DEBUG
用于调试信息
三、控制台消息
内核可以将消息发送到一个指定的虚拟控制台。控制台就是当前的虚拟终端,可以在任何一个控制台设备上调用ioctl(TIOCLINUX)来指定接收消息的其他虚拟终端。
可选择专门用来接收内核消息的控制台
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/ioctl.h>
int main(int argc, char **argv)
{
char bytes[2] = {11,0}; /* 11 is the TIOCLINUX cmd number */
if (argc==2) bytes[1] = atoi(argv[1]); /* the chosen console */
else {
fprintf(stderr, "%s: need a single arg\n",argv[0]); exit(1);
}
if (ioctl(STDIN_FILENO, TIOCLINUX, bytes)<0) { /* use stdin */
fprintf(stderr,"%s: ioctl(stdin, TIOCLINUX): %s\n",
argv[0], strerror(errno));
exit(1);
}
exit(0);
}
消息被记录的过程:
printk函数将消息写到一个长度为_ LOG_BUF_LEN字节的循环缓冲区中(在配置内核时为 _LOG_BUF_LEN指定4KB-1KB之间的值),该函数会唤醒任何正在等待消息的进程(即睡眠在syslog系统调用上的进程)。
注:两种方法比较
①对/proc/kmsg进行读写操作时,日志缓冲区中被读取的数据不再保留。在读取进程时阻塞在该文件上,以便获得更多数据。dmesg命令可以在不刷新缓冲区的情况下获得缓冲区的内容。
②syslog系统调用却能通过选项返回日志数据并保留这些方法,以便其他进程也能使用。