当前位置:Gxlcms > 数据库问题 > pr_debug、dev_dbg等动态调试一

pr_debug、dev_dbg等动态调试一

时间:2021-07-01 10:21:17 帮助过:2人阅读

 

pr_debug:

#if defined(CONFIG_DYNAMIC_DEBUG)
/* dynamic_pr_debug() uses pr_fmt() internally so we don‘t need it here */
#define pr_debug(fmt, ...) \
    dynamic_pr_debug(fmt, ##__VA_ARGS__)
#elif defined(DEBUG)
#define pr_debug(fmt, ...) \
    printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
#else
#define pr_debug(fmt, ...) \
    no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
#endif

dev_dbg:

#if defined(CONFIG_DYNAMIC_DEBUG)
#define dev_dbg(dev, format, ...)             \
do {                             \
    dynamic_dev_dbg(dev, format, ##__VA_ARGS__); \
} while (0)
#elif defined(DEBUG)
#define dev_dbg(dev, format, arg...)        \
    dev_printk(KERN_DEBUG, dev, format, ##arg)
#else
#define dev_dbg(dev, format, arg...)                \
({                                \
    if (0)                            \
        dev_printk(KERN_DEBUG, dev, format, ##arg);    \
    0;                            \
})
#endif

从上面的宏定义可以看出,要使用dynamic_*的话需要配置CONFIG_DYNAMIC_DEBUG。

Kernel hacking  --->

    printk and dmesg options  --->

        [*] Enable dynamic printk() support

在[*] Enable dynamic printk() support 上点击h,可以看到帮助信息。

我们以pr_debug为例分析,

   1: #define DEFINE_DYNAMIC_DEBUG_METADATA(name, fmt)        \
   2:     static struct _ddebug  __aligned(8)            \
   3:     __attribute__((section("__verbose"))) name = {        \
   4:         .modname = KBUILD_MODNAME,            \
   5:         .function = __func__,                \
   6:         .filename = __FILE__,                \
   7:         .format = (fmt),                \
   8:         .lineno = __LINE__,                \
   9:         .flags =  _DPRINTK_FLAGS_DEFAULT,        \
  10:     }
  11:  
  12: #define dynamic_pr_debug(fmt, ...)                \
  13: do {                                \
  14:     DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, fmt);        \
  15:     if (unlikely(descriptor.flags & _DPRINTK_FLAGS_PRINT))    \
  16:         __dynamic_pr_debug(&descriptor, pr_fmt(fmt),    \
  17:                    ##__VA_ARGS__);        \
  18: } while (0)

pr_fmt:

   1: #ifndef pr_fmt
   2: #define pr_fmt(fmt) fmt
   3: #endif

所以,如果把pr_debug展开,那么就是:

   1: do {
   2:     static struct _ddebug  __aligned(8)            \
   3:     __attribute__((section("__verbose"))) descriptor = {        \
   4:         .modname = KBUILD_MODNAME,            \
   5:         .function = __func__,                \
   6:         .filename = __FILE__,                \
   7:         .format = (fmt),                \
   8:         .lineno = __LINE__,                \
   9:         .flags =  _DPRINTK_FLAGS_DEFAULT,        \
  10:     }
  11:     if (unlikely(descriptor.flags & _DPRINTK_FLAGS_PRINT))    \
  12:         __dynamic_pr_debug(&descriptor, fmt,    \
  13:                    ##__VA_ARGS__);        \
  14: } while (0)

其中flags的赋值_DPRINTK_FLAGS_DEFAULT依赖DEBUG宏,

   1: #if defined DEBUG
   2: #define _DPRINTK_FLAGS_DEFAULT _DPRINTK_FLAGS_PRINT
   3: #else
   4: #define _DPRINTK_FLAGS_DEFAULT 0
   5: #endif

即,如果没有定义DEBUG宏,pr_debug默认无法打印出来,需要按照下面介绍的方法。

此外还定义了static类型的变量descriptor,它在编译链接时会被放到__verbose段,可以看看arch/arm/kernel/vmlinux.lds:

   1: OUTPUT_ARCH(arm)
   2: ENTRY(stext)
   3: jiffies = jiffies_64;
   4: SECTIONS
   5: {
   6:  /*
   7:      * XXX: The linker does not define how output sections are
   8:      * assigned to input sections when there are multiple statements
   9:      * matching the same input section name.  There is no documented
  10:      * order of matching.
  11:      *
  12:      * unwind exit sections must be discarded before the rest of the
  13:      * unwind sections get included.
  14:      */
  15:  /DISCARD/ : {
  16:   *(.ARM.exidx.exit.text)
  17:   *(.ARM.extab.exit.text)
  18:   *(.ARM.exidx.cpuexit.text)
  19:   *(.ARM.extab.cpuexit.text)
  20:  
  21:  
  22:   *(.exitcall.exit)
  23:   *(.alt.smp.init)
  24:   *(.discard)
  25:   *(.discard.*)
  26:  }
  27:  . = 0xC0000000 + 0x00008000;
  28:  .head.text : {
  29:   _text = .;
  30:   *(.head.text)
  31:  }
  32:  .text : { /* Real text segment        */
  33:   _stext = .; /* Text and read-only data    */
  34:    __exception_text_start = .;
  35:    *(.exception.text)
  36:    __exception_text_end = .;
  37:   
  38:    . = ALIGN(8); *(.text.hot) *(.text) *(.ref.text) *(.text.unlikely)
  39:    . = ALIGN(8); __sched_text_start = .; *(.sched.text) __sched_text_end = .;
  40:    . = ALIGN(8); __lock_text_start = .; *(.spinlock.text) __lock_text_end = .;
  41:    . = ALIGN(8); __kprobes_text_start = .; *(.kprobes.text) __kprobes_text_end = .;
  42:    . = ALIGN(8); __idmap_text_start = .; *(.idmap.text) __idmap_text_end = .; . = ALIGN(32); __hyp_idmap_text_start = .; *(.hyp.idmap.text) __hyp_idmap_text_end = .;
  43:    *(.fixup)
  44:    *(.gnu.warning)
  45:    *(.glue_7)
  46:    *(.glue_7t)
  47:   . = ALIGN(4);
  48:   *(.got) /* Global offset table        */
  49:   
  50:  }
  51:  . = ALIGN(((1 << 12))); .rodata : AT(ADDR(.rodata) - 0) { __start_rodata = .; *(.rodata) *(.rodata.*) *(__vermagic) . = ALIGN(8); __start___tracepoints_ptrs = .; *(__tracepoints_ptrs) __stop___tracepoints_ptrs = .; *(__tracepoints_strings) } .rodata1 : AT(ADDR(.rodata1) - 0) { *(.rodata1) } . = ALIGN(8); __bug_table : AT(ADDR(__bug_table) - 0) { __start___bug_table = .; *(__bug_table) __stop___bug_table = .; } .pci_fixup : AT(ADDR(.pci_fixup) - 0) { __start_pci_fixups_early = .; *(.pci_fixup_early) __end_pci_fixups_early = .; __start_pci_fixups_header = .; *(.pci_fixup_header) __end_pci_fixups_header = .; __start_pci_fixups_final = .; *(.pci_fixup_final) __end_pci_fixups_final = .; __start_pci_fixups_enable = .; *(.pci_fixup_enable) __end_pci_fixups_enable = .; __start_pci_fixups_resume = .; *(.pci_fixup_resume) __end_pci_fixups_resume = .; __start_pci_fixups_resume_early = .; *(.pci_fixup_resume_early) __end_pci_fixups_resume_early = .; __start_pci_fixups_suspend = .; *(.pci_fixup_suspend) __end_pci_fixups_suspend = .; } .builtin_fw : AT(ADDR(.builtin_fw) - 0) { __start_builtin_fw = .; *(.builtin_fw) __end_builtin_fw = .; } __ksymtab : AT(ADDR(__ksymtab) - 0) { __start___ksymtab = .; *(SORT(___ksymtab+*)) __stop___ksymtab = .; } __ksymtab_gpl : AT(ADDR(__ksymtab_gpl) - 0) { __start___ksymtab_gpl = .; *(SORT(___ksymtab_gpl+*)) __stop___ksymtab_gpl = .; } __ksymtab_unused : AT(ADDR(__ksymtab_unused) - 0) { __start___ksymtab_unused = .; *(SORT(___ksymtab_unused+*)) __stop___ksymtab_unused = .; } __ksymtab_unused_gpl : AT(ADDR(__ksymtab_unused_gpl) - 0) { __start___ksymtab_unused_gpl = .; *(SORT(___ksymtab_unused_gpl+*)) __stop___ksymtab_unused_gpl = .; } __ksymtab_gpl_future : AT(ADDR(__ksymtab_gpl_future) - 0) { __start___ksymtab_gpl_future = .; *(SORT(___ksymtab_gpl_future+*)) __stop___ksymtab_gpl_future = .; } __kcrctab : AT(ADDR(__kcrctab) - 0) { __start___kcrctab = .; *(SORT(___kcrctab+*)) __stop___kcrctab = .; } __kcrctab_gpl : AT(ADDR(__kcrctab_gpl) - 0) { __start___kcrctab_gpl = .; *(SORT(___kcrctab_gpl+*)) __stop___kcrctab_gpl = .; } __kcrctab_unused : AT(ADDR(__kcrctab_unused) - 0) { __start___kcrctab_unused = .; *(SORT(___kcrctab_unused+*)) __stop___kcrctab_unused = .; } __kcrctab_unused_gpl : AT(ADDR(__kcrctab_unused_gpl) - 0) { __start___kcrctab_unused_gpl = .; *(SORT(___kcrctab_unused_gpl+*)) __stop___kcrctab_unused_gpl = .; } __kcrctab_gpl_future : AT(ADDR(__kcrctab_gpl_future) - 0) { __start___kcrctab_gpl_future = .; *(SORT(___kcrctab_gpl_future+*)) __stop___kcrctab_gpl_future = .; } __ksymtab_strings : AT(ADDR(__ksymtab_strings) - 0) { *(__ksymtab_strings) } __init_rodata : AT(ADDR(__init_rodata) - 0) { *(.ref.rodata) } __param : AT(ADDR(__param) - 0) { __start___param = .; *(__param) __stop___param = .; } __modver : AT(ADDR(__modver) - 0) { __start___modver = .; *(__modver) __stop___modver = .; . = ALIGN(((1 << 12))); __end_rodata = .; } . = ALIGN(((1 << 12)));
  52:  . = ALIGN(4);
  53:  __ex_table : AT(ADDR(__ex_table) - 0) {
  54:   __start___ex_table = .;
  55:   *(__ex_table)
  56:   __stop___ex_table = .;
  57:  }
  58:  /*
  59:      * Stack unwinding tables
  60:      */
  61:  . = ALIGN(8);
  62:  .ARM.unwind_idx : {
  63:   __start_unwind_idx = .;
  64:   *(.ARM.exidx*)
  65:   __stop_unwind_idx = .;
  66:  }
  67:  .ARM.unwind_tab : {
  68:   __start_unwind_tab = .;
  69:   *(.ARM.extab*)
  70:   __stop_unwind_tab = .;
  71:  }
  72:  .notes : AT(ADDR(.notes) - 0) { __start_notes = .; *(.note.*) __stop_notes = .; }
  73:  _etext = .; /* End of text and rodata section */
  74:  . = ALIGN((1 << 12));
  75:  __init_begin = .;
  76:  /*
  77:      * The vectors and stubs are relocatable code, and the
  78:      * only thing that matters is their relative offsets
  79:      */
  80:  __vectors_start = .;
  81:  .vectors 0 : AT(__vectors_start) {
  82:   *(.vectors)
  83:  }
  84:  . = __vectors_start + SIZEOF(.vectors);
  85:  __vectors_end = .;
  86:  __stubs_start = .;
  87:  .stubs 0x1000 : AT(__stubs_start) {
  88:   *(.stubs)
  89:  }
  90:  . = __stubs_start + SIZEOF(.stubs);
  91:  __stubs_end = .;
  92:  . = ALIGN(8); .init.text : AT(ADDR(.init.text) - 0) { _sinittext = .; *(.init.text) *(.meminit.text) _einittext = .; }
  93:  .exit.text : {
  94:   *(.exit.text) *(.memexit.text)
  95:  }
  96:  .init.proc.info : {
  97:   . = ALIGN(4); __proc_info_begin = .; *(.proc.info.init) __proc_info_end = .;
  98:  }
  99:  .init.arch.info : {
 100:   __arch_info_begin = .;
 101:   *(.arch.info.init)
 102:   __arch_info_end = .;
 103:  }
 104:  .init.tagtable : {
 105:   __tagtable_begin = .;
 106:   *(.taglist.init)
 107:   __tagtable_end = .;
 108:  }
 109:  .init.pv_table : {
 110:   __pv_table_begin = .;
 111:   *(.pv_table)
 112:   __pv_table_end = .;
 113:  }
 114:  .init.data : {
 115:   *(.init.data) *(.meminit.data) *(.init.rodata) *(.meminit.rodata) . = ALIGN(32); __dtb_start = .; *(.dtb.init.rodata) __dtb_end = .;
 116:   . = ALIGN(16); __setup_start = .; *(.init.setup) __setup_end = .;
 117:   __initcall_start = .; *(.initcallearly.init) __initcall0_start = .; *(.initcall0.init) *(.initcall0s.init) __initcall1_start = .; *(.initcall1.init) *(.initcall1s.init) __initcall2_start = .; *(.initcall2.init) *(.initcall2s.init) __initcall3_start = .; *(.initcall3.init) *(.initcall3s.init) __initcall4_start = .; *(.initcall4.init) *(.initcall4s.init) __initcall5_start = .; *(.initcall5.init) *(.initcall5s.init) __initcallrootfs_start = .; *(.initcallrootfs.init) *(.initcallrootfss.init) __initcall6_start = .; *(.initcall6.init) *(.initcall6s.init) __initcall7_start = .; *(.initcall7.init) *(.initcall7s.init) __initcall_end = .;
 118:   __con_initcall_start = .; *(.con_initcall.init) __con_initcall_end = .;
 119:   __security_initcall_start = .; *(.security_initcall.init) __security_initcall_end = .;
 120:   . = ALIGN(4); __initramfs_start = .; *(.init.ramfs) . = ALIGN(8); *(.init.ramfs.info)
 121:  }
 122:  .exit.data : {
 123:   *(.exit.data) *(.memexit.data) *(.memexit.rodata)
 124:  }
 125:  __init_end = .;
 126:  . = ALIGN(8192);
 127:  __data_loc = .;
 128:  .data : AT(__data_loc) {
 129:   _data = .; /* address in memory */
 130:   _sdata = .;
 131:   /*
 132:          * first, the init task union, aligned
 133:          * to an 8192 byte boundary.
 134:          */
 135:   . = ALIGN(8192); *(.data..init_task)
 136:   . = ALIGN((1 << 12)); __nosave_begin = .; *(.data..nosave) . = ALIGN((1 << 12)); __nosave_end = .;
 137:   . = ALIGN((1 << 5)); *(.data..cacheline_aligned)
 138:   . = ALIGN((1 << 5)); *(.data..read_mostly) . = ALIGN((1 << 5));
 139:   /*
 140:          * and the usual data section
 141:          */
 142:   *(.data) *(.ref.data) *(.data..shared_aligned) *(.data.unlikely) . = ALIGN(32); *(__tracepoints) . = ALIGN(8); __start___jump_table = .; *(__jump_table) __stop___jump_table = .; . = ALIGN(8);__start___verbose = .; *(__verbose) __stop___verbose = .;
 143:   CONSTRUCTORS
 144:   _edata = .;
 145:  }
 146:  _edata_loc = __data_loc + SIZEOF(.data);
 147:  . = ALIGN(0); __bss_start = .; . = ALIGN(0); .sbss : AT(ADDR(.sbss) - 0) { *(.sbss) *(.scommon) } . = ALIGN(0); .bss : AT(ADDR(.bss) - 0) { *(.bss..page_aligned) *(.dynbss) *(.bss) *(COMMON) } . = ALIGN(0); __bss_stop = .;
 148:  _end = .;
 149:  .stab 0 : { *(.stab) } .stabstr 0 : { *(.stabstr) } .stab.excl 0 : { *(.stab.excl) } .stab.exclstr 0 : { *(.stab.exclstr) } .stab.index 0 : { *(.stab.index) } .stab.indexstr 0 : { *(.stab.indexstr) } .comment 0 : { *(.comment) }
 150:  .comment 0 : { *(.comment) }
 151: }

可以看到,将__verbose段链接到了__start__verbose和__stop__verbose之间,也就是将来可以利用__start_verbose和__stop_verbose这两个符号来找到__verbose段。

 

一般我们使用debugfs的时候,在系统启动时挂载debugfs文件系统:

   1: [root@TQ2440 /]# mount
   2: rootfs on / type rootfs (rw)
   3: /dev/root on / type yaffs2 (rw,relatime)
   4: proc on /proc type proc (rw,relatime)
   5: tmpfs on /tmp type tmpfs (rw,relatime)
   6: sysfs on /sys type sysfs (rw,relatime)
   7: tmpfs on /dev type tmpfs (rw,relatime)
   8: debugfs on /sys/kernel/debug type debugfs (rw,relatime)
   9: devpts on /dev/pts type devpts (rw,relatime,mode=600)

上面我们将debugfs挂载到了/sys/kernel/debug目录下面。

如果我们想打开某个文件中的pr_debug,如demo.c,可以如下操作:

echo -n "file demo.c +p" > /sys/kernel/debug/dynamic_debug/control

关闭的话:

echo -n "file demo.c -p" > /sys/kernel/debug/dynamic_debug/control

如果想分析一下为什么这样操作就可以实现将某个文件中的pr_debug打开,就需要分析背后的原理,如control节点的创建.

上面pr_debug展开后的descriptor变量被链接到了__verbose段,那么系统一定会有解析这个段的代码。

具体的代码位置是lib/dynamic_debug.c

__verbose的解析:

   1: static int __init dynamic_debug_init(void)
   2: {
   3:     struct _ddebug *iter, *iter_start;
   4:     const char *modname = NULL;
   5:     char *cmdline;
   6:     int ret = 0;
   7:     int n = 0, entries = 0, modct = 0;
   8:     int verbose_bytes = 0;
   9:     
  10:     // __start___verbose 和 __stop___verbose 之间存放的都是struct _ddebug类型的静态变量,
  11:     // pr_debug展开后的descriptor就在这里。
  12:     if (__start___verbose == __stop___verbose) {
  13:         pr_warn("_ddebug table is empty in a CONFIG_DYNAMIC_DEBUG build\n");
  14:         return 1;
  15:     }
  16:     
  17:     // 下面这段代码完成的任务是解析__verbose段。
  18:     iter = __start___verbose;
  19:     modname = iter->modname;

                        
                    

人气教程排行