Linux设备驱动程序(第三版)学习之内核的调试技术(三)_1

先说明几点:

**对于内核编程,内核有它自己独特的调试技术

**内核代码无法轻易地在一个调试器下运行,也无法轻易地被跟踪,原因在于在内核中许多进程的运行不存在一定的关联性,往往是独立的.

**内核代码错误特别难以重现,这些错误会牵连整个系统与它们一起失效(也就是系统奔溃)

1. 使用printk()函数将调试信息打印出来

a. printk()函数相当于C语言库的printf()函数,但是printk()有它独特之处.

b. printk的独特之处在于:通过在消息上附加不同的记录级别或优先级,允许对消息分类.

c. 记录级别的宏定义在<linux/kernel.h>头文件中,如下所示(数值越小,优先级越大)

#define KERN_EMERG"<0>" /* system is unusable*/#define KERN_ALERT"<1>" /* action must be taken immediately*/#define KERN_CRIT"<2>" /* critical conditions*/#define KERN_ERR"<3>" /* error conditions*/#define KERN_WARNING"<4>" /* warning conditions*/#define KERN_NOTICE"<5>" /* normal but significant condition*/#define KERN_INFO"<6>" /* informational*/#define KERN_DEBUG"<7>" /* debug-level messages*/

printk示例:

printk(KERN_DEBUG "Here I am: %s:%i\n", __FILE__, __LINE__);

d.

KERN_EMERG-------------------------------------->用于紧急消息,常常是那些奔溃前的消息

KERN_ALERT--------------------------------------->需要立刻动作的情况

KERN_CRIT------------------------------------------>严重情况,常常与严重的硬件或者软件失效有关

KERN_ERR------------------------------------------>用来报告错误情况,设备驱动常常使用KERN_ERR来报告硬件故障

KERN_WARING------------------------------------>有问题时的警告

KERN_NOTICE------------------------------------->正常情况,在这个级别一些安全相关的情况会报告

KERN_INFO------------------------------------------>信息型消息,在这个级别,很多驱动在启动时打印它们发现的硬件信息

KERN_DEBUG-------------------------------------->用作调试信息

e. printk缺省的优先级别是DEFAULT_MESSAGE_LOGLEVEL(也就是KERN_WARNING)在kernel/printk.c文件中

f. 记录级别的作用是可定向输出内核打印的消息打印到当前控制台,

1). 打印到一个文本模式终端

2). 串口

3). 并口打印机

g. 当优先级小于整型值DEFAULT_CONSOLE_LOGLEVEL也就是7时,消息将被传递到控制台(注意在消息后要加\n)

h. 如果klogd和syslogd都在系统中运行,那么内核消息将会追加到/var/log/messages文件中.

2.

3. 消息的记录方式

a. printk函数将消息写入一个__LOG_BUF_LEN字节长的环形缓冲中,缓存的大小在4KB---1M,在配置内核时可以选择.

b. printk函数可以换醒任何在等待消息的进程,说白了,也就是这些进程接收这些打印的消息,

例如读取/proc/kmsg文件的进程,

[root@linux ~]# cat   /proc/kmsg       --------->当内核有打印消息的时候,该进程就会由阻塞阻塞状态转化为运行状态,将消息打印在终端上.

c. 从/proc/kmsg中读取是从缓存日志中将数据拿走,也就是说/proc/kmsg中的数据被拿走之后就没有了

d. syslog可以再读取完后会将数据保留,以便其他进程可以用

e. dmesg命令可以用来查看缓存中的内容,删除缓存中的内容执行dmesg -c.

f. 如果环形缓存填满,printk会绕回在缓存的开头增加新数据,将旧数据覆盖掉.

g. 环形缓存允许系统即便没有一个日志进程也可以运行,在没有人读取它的时候可已通过覆盖旧数据浪费最少的内存.

h. klogd进程将获取来的内核消息交给syslogd进程,syslogd通过检查/etc/syslog.conf来决定如何去处理这些内核消息.

4. 启动printk的消息打印和关闭printk的消息打印

全局性的打开或关闭你地调试信息和打开或关闭单个消息的技术------------>这个技术依靠于定义宏来实现.

功能说明:

***同过去除或添加单个字符到宏定义的名字, 每个printk语句可以打开或关闭

***通过在编译前改变CFLAGS变量的值,  所有的printk可以马上关闭

***对于同一个printk语句可以在内核代码和用户代码中使用,

#undef  PDEBUG  //undef  it , just in case
#ifdef   SCULL_DEBUG
#ifdef  __KERNEL
#define  PDEBUG(fmt, args...)  printk( KERN_DEBUG "scull:" fmt, ## args)
#else
#define  PDEBUG(FMT, args...) fprintf(  stderr, fmt, ## args)
#endif
#else
#define PDEBUG(fmt, args...)
#endif
#undef  PDEBUG #define PDEBUG(fmt, args...)
对Makefile的编写
# Comment/uncomment the following line  to  disable/enable debugging
DEBUG = y
# Add your debugging flags(or not) to CFLAGS
ifeq($(DEBUG), y)
DEBFLAGS = -O -g -DSCULL_DEBUG

else
   DEBUGFLAGS =-O2
endif
CFLAGS += $(DEBFLAGS)

5.为了避免printk循环产生过量的打印消息以至于拖垮系统正确的做法是在printk前调用printk_ratelimit(void)来判定

if (printk_ratelimit())  

printk(KERN_NOTICE "The printer is still on fire\n");

printk_ratelimit说明:

***通过跟踪有多少消息发向控制台而工作,当输出达到一个限度时,printk_ratelimi开始返回0并使消息被扔掉.

***通过修改/proc/sys/kernel/printk_rate_limit来决定printk_ratelimit等待的秒数

***通过修改/proc/sys/kernel/printk_ratelimit_burst来决定printk_ratelimit可接收的消息的个数.

6. 两个将设备号转换成字符串的宏函数--------->在<linux/kdev_t.h>中

int  print_dev_t (char *buffer, dev_t dev);---------->返回打印的字节数

char * format_dev_t(char *buffer, dev_t dev);----------->返回转换后的字符串.









  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值