0
点赞
收藏
分享

微信扫一扫

ldd3学习之四:调试技术

芷兮离离 2022-11-15 阅读 78


内核中的调试支持

内核开发者一般都已经建立了多项用于调试的功能。但是由于这些功能会造成额外的输出,并导致能下降,因此发行版厂商通常会禁止发行版内核中的调试功能。


为了实现内核调试,我在内核配置上增加了几项:


Kernel hacking  --->    


        [*] Magic SysRq key


        [*] Kernel debugging


        [*]   Debug slab memory allocations 


        [*]   Spinlock and rw-lock debugging: basic checks


        [*]   Spinlock debugging: sleep-inside-spinlock checking


        [*]   Compile the kernel with debug info 


        [*] Magic SysRq key


Device Drivers  ---> 


        Generic Driver Options  --->


          [*] Driver Core verbose debug messages


General setup  --->


       [*] Configure standard kernel features (for small systems)  --->


          [*]   Load all symbols for debugging/ksymoops


书上介绍的还有其他配置。


方法一:printk


① 首先,printk有8个loglevel,定义在 中:


#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   */


未指定优先级的默认级别定义在/kernel/printk.c中:

  1. /* printk's without a loglevel use this.. */
  2. #define DEFAULT_MESSAGE_LOGLEVEL 4 /* KERN_WARNING */


当优先级的值小于console_loglevel这个整数变量的值,信息才能显示出来。而console_loglevel的初始值DEFAULT_CONSOLE_LOGLEVEL也定义在/kernel/printk.c中:


#define DEFAULT_CONSOLE_LOGLEVEL 7 /* anything MORE serious than KERN_DEBUG */


还可以通过对/proc/sys/kernel/printk的访问来改变console_loglevel的值


​​

ldd3学习之四:调试技术_linux

​​


四个数字的含义:当前的loglevel、默认loglevel、最小允许的loglevel、引导时的默认loglevel。


Linux消息处理方法的一个特点是: 可以在任何地方调用printk,甚至在终端处理函数里也可以调用,而且对数据量的大小没有限制,唯一缺点是可能丢失某些数据。


fdfdf


②为了方便的打开和关闭调试信息,ldd3提供以下源码:


  1. /* Macros to help debugging */
  2. #undef PDEBUG /* undef it, just in case */
  3. #ifdef SCULL_DEBUG
  4. # ifdef __KERNEL__
  5. /* This one if debugging is on, and kernel space */
  6. # define PDEBUG(fmt, args...) printk( KERN_DEBUG "scull: " fmt, ## args)
  7. # else /* 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
  14. #define PDEBUGG(fmt, args...) /* nothing: it's a placeholder */


Makefile中要添加的语句:



  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. = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines
  6. else
  7. = -O2
  8. endif

  9. CFLAGS += $(DEBFLAGS)



这些宏是很有用的,仅有的缺点是每次开启和关闭消息显示时,都要重新编译模块。

③为了避免printk重复输出过快而阻塞系统,内核使用以下函数跳过部分输出



  1. int printk_ratelimit(void);



  1. if (printk_ratelimit( ))
  2. (KERN_NOTICE "The printer is still on fire\n");



可以通过修改/proc/sys/kernel/printk_ratelimit(重开信息前应等待的秒数)和/proc/sys/kernel/printk_ratelimit_burst(在速度限制前可接受的信息数)来定制printk_ratelimit的行为。Linux还提供了打印设备编号的宏(在 中定义):



  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返回缓冲区指针。注意缓冲区char *buffer的大小应至少有20B。



方法二:oops



1.Oops是内核级的Segmentation Fault。



应用程序-->访问非法内存或非法指令-->Segment信号-->行为是coredump



kernel-->打印Oops信息



2.分析步骤



①错误提示原因



②调用栈(对照反汇编代码)  back tree:



③寄存器。 PC is at fun+0x1c/0x30



           PC-->fun函数0x1c偏移处,0x30是fun长度


举报

相关推荐

0 条评论