调试技术

1845阅读 0评论2012-12-14 Helianthus_lu
分类:

仅介绍一些基本的,kernel hacking" 菜单中的相关内容暂时跳过
最常用的调试技术是监视
    编写程序的时候经常使用printf来打印信息,帮助调试
    在调试内核代码的时候可以用printk来实现
    一个不同是 printk 允许你根据消息的严重程度对其分类, 通过附加不同的记录级别或者优先级在消息上. 你常常用一个宏定义来指示记录级别.
    
有 8 种可能的记录字串, 在头文件 里定义; 我们按照严重性递减的顺序列出它们:

KERN_EMERG      用于紧急消息, 常常是那些崩溃前的消息.
KERN_ALERT      需要立刻动作的情形.
KERN_CRIT       严重情况, 常常与严重的硬件或者软件失效有关.
KERN_ERR        用来报告错误情况; 设备驱动常常使用 KERN_ERR 来报告硬件故障.
KERN_WARNING    有问题的情况的警告, 这些情况自己不会引起系统的严重问题.
KERN_NOTICE     正常情况, 但是仍然值得注意. 在这个级别一些安全相关的情况会报告.
KERN_INFO       信息型消息. 在这个级别, 很多驱动在启动时打印它们发现的硬件的信息.
KERN_DEBUG      用作调试消息.

    每个字串( 在宏定义扩展里 )代表一个在角括号中的整数. 整数的范围从 0 到 7, 越小的数表示越大的优先级.一条没有指定优先级的 printk 语句缺省是 DEFAULT_MESSAGE_LOGLEVEL, 在 kernel/printk.c 里指定作为一个整数. 在 2.6.10 内核中, DEFAULT_MESSAGE_LOGLEVEL 是 KERN_WARNING。如果优先级小于整型值 console_loglevel, 消息被递交给控制台, 一次一行( 除非提供一个新行结尾, 否则什么都不发送 ).
    可以通过文本文件 /proc/sys/kernel/printk 读写控制台记录级别. 这个文件有 4 个整型值: 当前记录级别, 适用没有明确记录级别的消息的缺省级别, 允许的最小记录级别, 以及启动时缺省记录级别. 写一个单个值到这个文件就改变当前记录级别成这个值; 因此, 例如, 你可以使所有内核消息出现在控制台, 通过简单地输入:
# echo 8 > /proc/sys/kernel/printk


打开和关闭消息

    这里我们展示一种编码 printk 调用的方法, 你可以单独或全局地打开或关闭它们; 这个技术依靠定义一个宏, 在你想使用它时就转变成一个 printk (或者 printf)调用.每个 printk 语句可以打开或关闭, 通过去除或添加单个字符到宏定义的名子.所有消息可以马上关闭, 通过在编译前改变 CFLAGS 变量的值.同一个 print 语句可以在内核代码和用户级代码中使用, 因此对于格外的消息, 驱动和测试程序能以同样的方式被管理.

下面的代码片断实现了这些特性, 直接来自头文件 scull.h:

  1. #undef PDEBUG /* undef it, just in case */
  2. #ifdef SCULL_DEBUG
  3. # ifdef __KERNEL__

  4. /* This one if debugging is on, and kernel space */
  5. # define PDEBUG(fmt, args...) printk( KERN_DEBUG "scull: " fmt, ## args)
  6. # else

  7. /* This one for user space */
  8. # define PDEBUG(fmt, args...) fprintf(stderr, fmt, ## args)
  9. # endif
  10. #else
  11. # define PDEBUG(fmt, args...) /* not debugging: nothing */
  12. #endif

  13. #undef PDEBUGG #define PDEBUGG(fmt, args...) /* nothing: it's a placeholder */

符号 PDEBUG 定义和去定义, 取决于 SCULL_DEBUG 是否定义, 和以何种方式显示消息适合代码运行的环境: 当它在内核中就使用内核调用 printk, 在用户空间运行就使用 libc 调用 fprintf 到标准错误输出. PDEBUGG 符号, 换句话说, 什么不作; 他可用来轻易地"注释" print 语句, 而不用完全去掉它们.

为进一步简化过程, 添加下面的行到你的 makfile 里:

  1. # Comment/uncomment the following line to disable/enable debugging
  2. DEBUG = y

  3. # Add your debugging flag (or not) to CFLAGS
  4. ifeq ($(DEBUG),y)
  5.  DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines
  6. else
  7.  DEBFLAGS = -O2
  8. endif

  9. CFLAGS += $(DEBFLAGS)


打印设备编号
    当从一个驱动打印消息, 你会想打印与感兴趣的硬件相关联的设备号. 打印主次编号不是特别难, 但是, 为一致性考虑, 内核提供了一些实用的宏定义( 在 中定义)用于这个目的:

  1. int print_dev_t(char *buffer, dev_t dev);
  2. char *format_dev_t(char *buffer, dev_t dev);


两个宏定义都将设备号编码进给定的缓冲区; 唯一的区别是 print_dev_t 返回打印的字符数, 而 format_dev_t 返回缓存区; 因此, 它可以直接用作 printk 调用的参数

 

其他部分还未实践过,暂时略过,以后再补充

上一篇:关于module_param()
下一篇:亲历多家名企C语言面试题