内核版本:Linux-3.14

作者:彭东林

邮箱:pengdonglin137@163.com

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  --->

Compile-time checks and compiler options  --->

[*] Debug Filesystem

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默认无法打印出来,需要按照下面介绍的方法。 flags的值对于打印什么和如何打印都非常重要。

此外还定义了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;

  20:     iter_start = iter;

  21:     for (; iter < __stop___verbose; iter++) {

  22:         entries++;

  23:         verbose_bytes += strlen(iter->modname) + strlen(iter->function)

  24:             + strlen(iter->filename) + strlen(iter->format);

  25:  

  26:         if (strcmp(modname, iter->modname)) {

  27:             modct++;

  28:             // 给每个modname(descriptor和modname是一对一(如demo.c中只有一个pr_debug或者dev_dbg)

  29:             // 或者多对一(如demo.c中有多个pr_debug或者dev_dbg)的关系,一个文件对应一个modname,

  30:             // 这些modname相同的descriptor在__verbose中是连续存放的)分配一个struct ddebug_table,

  31:             // 然后将其存放到全局变量ddebug_tables中,这里的n表示modname相同的descriptor的个数

  32:             ret = ddebug_add_module(iter_start, n, modname);

  33:             if (ret)

  34:                 goto out_err;

  35:             n = 0;

  36:             modname = iter->modname;

  37:             iter_start = iter;

  38:         }

  39:         n++;

  40:     }

  41:     ret = ddebug_add_module(iter_start, n, modname);

  42:     if (ret)

  43:         goto out_err;

  44:  

  45:     ddebug_init_success = 1;

  46:     vpr_info("%d modules, %d entries and %d bytes in ddebug tables, %d bytes in (readonly) verbose section\n",

  47:          modct, entries, (int)(modct * sizeof(struct ddebug_table)),

  48:          verbose_bytes + (int)(__stop___verbose - __start___verbose));

  49:  

  50:     /* apply ddebug_query boot param, dont unload tables on err */

  51:     // 如在bootargs中设置了ddebug_query="file unwind.c +p",那么ddebug_setup_string数组中存放的就是"file unwind.c +p"

  52:     // 这个用于处理系统boot过程中的pr_debug或者pr_dev的打印

  53:     if (ddebug_setup_string[0] != '\0') { 

  54:         pr_warn("ddebug_query param name is deprecated, change it to dyndbg\n");

  55:         // 处理"file unwind.c +p"

  56:         ret = ddebug_exec_queries(ddebug_setup_string, NULL);

  57:         if (ret < 0)

  58:             pr_warn("Invalid ddebug boot param %s\n",

  59:                 ddebug_setup_string);

  60:         else

  61:             pr_info("%d changes by ddebug_query\n", ret);

  62:     }

  63:     /* now that ddebug tables are loaded, process all boot args

  64:      * again to find and activate queries given in dyndbg params.

  65:      * While this has already been done for known boot params, it

  66:      * ignored the unknown ones (dyndbg in particular).  Reusing

  67:      * parse_args avoids ad-hoc parsing.  This will also attempt

  68:      * to activate queries for not-yet-loaded modules, which is

  69:      * slightly noisy if verbose, but harmless.

  70:      */

  71:      // 解析bootargs中的参数如有个module的名字是modname是unwind,那么可以是 bootargs 中包含 unwind.dyndbg

  72:     cmdline = kstrdup(saved_command_line, GFP_KERNEL);

  73:     parse_args("dyndbg params", cmdline, NULL,

  74:            0, 0, 0, &ddebug_dyndbg_boot_param_cb);

  75:     kfree(cmdline);

  76:     return 0;

  77:  

  78: out_err:

  79:     ddebug_remove_all_tables();

  80:     return 0;

  81: }

  82: /* Allow early initialization for boot messages via boot param */

  83: early_initcall(dynamic_debug_init);

第32行的n的含义也可以理解为demo.c中pr_debug和dev_dbg的个数;

ddebug_add_module:

   1: int ddebug_add_module(struct _ddebug *tab, unsigned int n,

   2:                  const char *name)

   3: {

   4:     struct ddebug_table *dt;

   5:     char *new_name;

   6:  

   7:     dt = kzalloc(sizeof(*dt), GFP_KERNEL);

   8:     if (dt == NULL)

   9:         return -ENOMEM;

  10:     new_name = kstrdup(name, GFP_KERNEL);

  11:     if (new_name == NULL) {

  12:         kfree(dt);

  13:         return -ENOMEM;

  14:     }

  15:     dt->mod_name = new_name;

  16:     dt->num_ddebugs = n;

  17:     dt->ddebugs = tab;

  18:  

  19:     mutex_lock(&ddebug_lock);

  20:     list_add_tail(&dt->link, &ddebug_tables);

  21:     mutex_unlock(&ddebug_lock);

  22:  

  23:     vpr_info("%u debug prints in module %s\n", n, dt->mod_name);

  24:     return 0;

  25: }

第16行的num_ddebugs表示modname相同的descriptor的个数,将来在ddebug_change中会依次索引,这里只需要存放这些descriptor中的第一个;

接下来分析一下数组ddebug_setup_string的赋值:

/lib/dynamic_debug.c

   1: #define DDEBUG_STRING_SIZE 1024

   2: static __initdata char ddebug_setup_string[DDEBUG_STRING_SIZE];

   3:  

   4: static __init int ddebug_setup_query(char *str)

   5: {

   6:     if (strlen(str) >= DDEBUG_STRING_SIZE) {

   7:         pr_warn("ddebug boot param string too large\n");

   8:         return 0;

   9:     }

  10:     strlcpy(ddebug_setup_string, str, DDEBUG_STRING_SIZE);

  11:     return 1;

  12: }

  13:  

  14: __setup("ddebug_query=", ddebug_setup_query);

第14行代码表示的意思是如果cmdline(也就是u-boot传给kernel的参数)中如果有ddebug_query=”file demo.c +p”的部分,那么在kernel启动的时候就会调用函数ddebug_setup_query,然后将”file demo.c +p”拷贝到这个ddebug_setup_debug数组中。

ddebug_exec_queries:

   1: /* handle multiple queries in query string, continue on error, return

   2:    last error or number of matching callsites.  Module name is either

   3:    in param (for boot arg) or perhaps in query string.

   4: */

   5: // 我们以query指向的缓冲区内容是"file demo.c +p"为例, modname是NULL

   6: static int ddebug_exec_queries(char *query, const char *modname)

   7: {

   8:     char *split;

   9:     int i, errs = 0, exitcode = 0, rc, nfound = 0;

  10:  

  11:     for (i = 0; query; query = split) {

  12:         split = strpbrk(query, ";\n"); // NULL

  13:         if (split)

  14:             *split++ = '\0';

  15:  

  16:         query = skip_spaces(query);

  17:         if (!query || !*query || *query == '#')

  18:             continue;

  19:  

  20:         vpr_info("query %d: \"%s\"\n", i, query);

  21:  

  22:         // query指向"file demo.c +p",modname是NULL, 如果找到匹配项并设置成功返回值大于0

  23:         rc = ddebug_exec_query(query, modname);

  24:         if (rc < 0) {

  25:             errs++;

  26:             exitcode = rc;

  27:         } else {

  28:             nfound += rc;

  29:         }

  30:         i++;

  31:     }

  32:     vpr_info("processed %d queries, with %d matches, %d errs\n",

  33:          i, nfound, errs);

  34:  

  35:     if (exitcode)

  36:         return exitcode;

  37:     return nfound;

  38: }

ddebug_exec_query:

   1: static int ddebug_exec_query(char *query_string, const char *modname)

   2: {

   3:     unsigned int flags = 0, mask = 0;

   4:     struct ddebug_query query;

   5: #define MAXWORDS 9

   6:     int nwords, nfound;

   7:     char *words[MAXWORDS];

   8:  

   9:     // 这个函数完成的功能是以空格为分隔符,对query_string进行分割,然后将分割出来的

  10:     // 每个项的首地址存放到words中,即words每个元素指向分割出来的一项,返回值是项数

  11:     // 对于我们的例子就是:

  12:     // words[0] --- "file"

  13:     // words[1] --- "demo.c"

  14:     // words[2] --- "+p"

  15:     // nwords的值是3

  16:     nwords = ddebug_tokenize(query_string, words, MAXWORDS);

  17:     if (nwords <= 0) {

  18:         pr_err("tokenize failed\n");

  19:         return -EINVAL;

  20:     }

  21:     /* check flags 1st (last arg) so query is pairs of spec,val */

  22:     // 解析"+p",然后据此给flags和mask赋值

  23:     // +p 对应的是 flags |= _DPRINTK_FLAGS_PRINT, mask是~0U

  24:     // -p 对应的是 flags = 0  mask = ~_DPRINTK_FLAGS_PRINT

  25:     if (ddebug_parse_flags(words[nwords-1], &flags, &mask)) {

  26:         pr_err("flags parse failed\n");

  27:         return -EINVAL;

  28:     }

  29:     

  30:     // 解析 "file" 和 "demo.c",并给query赋值

  31:     // query->filename 就是 "demo.c"

  32:     if (ddebug_parse_query(words, nwords-1, &query, modname)) {

  33:         pr_err("query parse failed\n");

  34:         return -EINVAL;

  35:     }

  36:     

  37:     /* actually go and implement the change */

  38:     // 改变demo.c中的pr_debug或者dev_dbg对应的descriptor的flags的值

  39:     nfound = ddebug_change(&query, flags, mask);

  40:     vpr_info_dq(&query, nfound ? "applied" : "no-match");

  41:  

  42:     return nfound;

  43: }

ddebug_tokenize:

   1: /*

   2:  * Split the buffer `buf' into space-separated words.

   3:  * Handles simple " and ' quoting, i.e. without nested,

   4:  * embedded or escaped \".  Return the number of words

   5:  * or <0 on error.

   6:  */

   7: static int ddebug_tokenize(char *buf, char *words[], int maxwords)

   8: {

   9:     int nwords = 0;

  10:  

  11:     while (*buf) {

  12:         char *end;

  13:  

  14:         /* Skip leading whitespace */

  15:         buf = skip_spaces(buf);

  16:         if (!*buf)

  17:             break;    /* oh, it was trailing whitespace */

  18:         if (*buf == '#')

  19:             break;    /* token starts comment, skip rest of line */

  20:  

  21:         /* find `end' of word, whitespace separated or quoted */

  22:         if (*buf == '"' || *buf == '\'') {

  23:             int quote = *buf++;

  24:             for (end = buf; *end && *end != quote; end++)

  25:                 ;

  26:             if (!*end) {

  27:                 pr_err("unclosed quote: %s\n", buf);

  28:                 return -EINVAL;    /* unclosed quote */

  29:             }

  30:         } else {

  31:             for (end = buf; *end && !isspace(*end); end++)

  32:                 ;

  33:             BUG_ON(end == buf);

  34:         }

  35:  

  36:         /* `buf' is start of word, `end' is one past its end */

  37:         if (nwords == maxwords) {

  38:             pr_err("too many words, legal max <=%d\n", maxwords);

  39:             return -EINVAL;    /* ran out of words[] before bytes */

  40:         }

  41:         if (*end)

  42:             *end++ = '\0';    /* terminate the word */

  43:         words[nwords++] = buf;

  44:         buf = end;

  45:     }

  46:  

  47:     if (verbose) {

  48:         int i;

  49:         pr_info("split into words:");

  50:         for (i = 0; i < nwords; i++)

  51:             pr_cont(" \"%s\"", words[i]);

  52:         pr_cont("\n");

  53:     }

  54:  

  55:     return nwords;

  56: }

ddebug_parse_flags:

   1: static struct { unsigned flag:8; char opt_char; } opt_array[] = {

   2:     { _DPRINTK_FLAGS_PRINT, 'p' },

   3:     { _DPRINTK_FLAGS_INCL_MODNAME, 'm' },

   4:     { _DPRINTK_FLAGS_INCL_FUNCNAME, 'f' },

   5:     { _DPRINTK_FLAGS_INCL_LINENO, 'l' },

   6:     { _DPRINTK_FLAGS_INCL_TID, 't' },

   7:     { _DPRINTK_FLAGS_NONE, '_' },

   8: };

   9:  

  10:  

  11: /*

  12:  * Parse `str' as a flags specification, format [-+=][p]+.

  13:  * Sets up *maskp and *flagsp to be used when changing the

  14:  * flags fields of matched _ddebug's.  Returns 0 on success

  15:  * or <0 on error.

  16:  */

  17: static int ddebug_parse_flags(const char *str, unsigned int *flagsp,

  18:                    unsigned int *maskp)

  19: {

  20:     unsigned flags = 0;

  21:     int op = '=', i;

  22:  

  23:     switch (*str) {

  24:     case '+':

  25:     case '-':

  26:     case '=':

  27:         op = *str++;

  28:         break;

  29:     default:

  30:         pr_err("bad flag-op %c, at start of %s\n", *str, str);

  31:         return -EINVAL;

  32:     }

  33:     vpr_info("op='%c'\n", op);

  34:  

  35:     for (; *str ; ++str) {

  36:         for (i = ARRAY_SIZE(opt_array) - 1; i >= 0; i--) {

  37:             if (*str == opt_array[i].opt_char) {

  38:                 flags |= opt_array[i].flag;

  39:                 break;

  40:             }

  41:         }

  42:         if (i < 0) {

  43:             pr_err("unknown flag '%c' in \"%s\"\n", *str, str);

  44:             return -EINVAL;

  45:         }

  46:     }

  47:     vpr_info("flags=0x%x\n", flags);

  48:  

  49:     /* calculate final *flagsp, *maskp according to mask and op */

  50:     switch (op) {

  51:     case '=':

  52:         *maskp = 0;

  53:         *flagsp = flags;

  54:         break;

  55:     case '+':

  56:         *maskp = ~0U;

  57:         *flagsp = flags;

  58:         break;

  59:     case '-':

  60:         *maskp = ~flags;

  61:         *flagsp = 0;

  62:         break;

  63:     }

  64:     vpr_info("*flagsp=0x%x *maskp=0x%x\n", *flagsp, *maskp);

  65:     return 0;

  66: }

这个函数用于解析"+p",他的含义是是否可以打印。此外,这里还可以是"+pmfl",这个参数打印的是最全的。如果要打印"+p"一定是要有的,"fmlt"可以根据需要任选。

其中, m 表示把模块名也打印出来;

f 表示把调用pr_debug的函数名也打印出来;

l 表示把pr_debug的行号也打印出来;

t 表示把进程号打印出来;

如下所示:

aaarticlea/png;base64,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" alt="" />

ddebug_parse_query:

   1: /*

   2:  * Parse words[] as a ddebug query specification, which is a series

   3:  * of (keyword, value) pairs chosen from these possibilities:

   4:  *

   5:  * func <function-name>

   6:  * file <full-pathname>

   7:  * file <base-filename>

   8:  * module <module-name>

   9:  * format <escaped-string-to-find-in-format>

  10:  * line <lineno>

  11:  * line <first-lineno>-<last-lineno> // where either may be empty

  12:  *

  13:  * Only 1 of each type is allowed.

  14:  * Returns 0 on success, <0 on error.

  15:  */

  16: static int ddebug_parse_query(char *words[], int nwords,

  17:             struct ddebug_query *query, const char *modname)

  18: {

  19:     unsigned int i;

  20:     int rc = 0;

  21:  

  22:     /* check we have an even number of words */

  23:     if (nwords % 2 != 0) {

  24:         pr_err("expecting pairs of match-spec <value>\n");

  25:         return -EINVAL;

  26:     }

  27:     memset(query, 0, sizeof(*query));

  28:  

  29:     if (modname)

  30:         /* support $modname.dyndbg=<multiple queries> */

  31:         query->module = modname;

  32:  

  33:     for (i = 0; i < nwords; i += 2) {

  34:         if (!strcmp(words[i], "func")) {

  35:             rc = check_set(&query->function, words[i+1], "func");

  36:         } else if (!strcmp(words[i], "file")) {

  37:             rc = check_set(&query->filename, words[i+1], "file");

  38:         } else if (!strcmp(words[i], "module")) {

  39:             rc = check_set(&query->module, words[i+1], "module");

  40:         } else if (!strcmp(words[i], "format")) {

  41:             string_unescape_inplace(words[i+1], UNESCAPE_SPACE |

  42:                                 UNESCAPE_OCTAL |

  43:                                 UNESCAPE_SPECIAL);

  44:             rc = check_set(&query->format, words[i+1], "format");

  45:         } else if (!strcmp(words[i], "line")) {

  46:             char *first = words[i+1];

  47:             char *last = strchr(first, '-');

  48:             if (query->first_lineno || query->last_lineno) {

  49:                 pr_err("match-spec: line used 2x\n");

  50:                 return -EINVAL;

  51:             }

  52:             if (last)

  53:                 *last++ = '\0';

  54:             if (parse_lineno(first, &query->first_lineno) < 0)

  55:                 return -EINVAL;

  56:             if (last) {

  57:                 /* range <first>-<last> */

  58:                 if (parse_lineno(last, &query->last_lineno) < 0)

  59:                     return -EINVAL;

  60:  

  61:                 if (query->last_lineno < query->first_lineno) {

  62:                     pr_err("last-line:%d < 1st-line:%d\n",

  63:                         query->last_lineno,

  64:                         query->first_lineno);

  65:                     return -EINVAL;

  66:                 }

  67:             } else {

  68:                 query->last_lineno = query->first_lineno;

  69:             }

  70:         } else {

  71:             pr_err("unknown keyword \"%s\"\n", words[i]);

  72:             return -EINVAL;

  73:         }

  74:         if (rc)

  75:             return rc;

  76:     }

  77:     vpr_info_dq(query, "parsed");

  78:     return 0;

  79: }

这个函数用于解析"file" "demo.c",然后构造出一个过滤器query,对于这个例子,将来query->filename会赋值为"demo.c".如果在bootargs中设置了demo.dyndbg="func xxx",表示打印模块demo中函数xxx中的pr_debug或者dev_dbg,此时query->function会被赋值为"xxx".当然也可以使用echo -n 'file demo.c line 1603 +p' > /sys/kernel/debug/dynamic_debug/control,其中:

words[0] --- "file"

words[1] --- "demo.c"

words[2] --- "line"

words[3] --- "1603"

words[4] --- "+p"

表示打印文件demo.c中第1603行的pr_debug或者dev_dbg.

ddebug_change:

   1: /*

   2:  * Search the tables for _ddebug's which match the given `query' and

   3:  * apply the `flags' and `mask' to them.  Returns number of matching

   4:  * callsites, normally the same as number of changes.  If verbose,

   5:  * logs the changes.  Takes ddebug_lock.

   6:  */

   7: static int ddebug_change(const struct ddebug_query *query,

   8:             unsigned int flags, unsigned int mask)

   9: {

  10:     int i;

  11:     struct ddebug_table *dt;

  12:     unsigned int newflags;

  13:     unsigned int nfound = 0;

  14:     char flagbuf[10];

  15:  

  16:     /* search for matching ddebugs */

  17:     mutex_lock(&ddebug_lock);

  18:     list_for_each_entry(dt, &ddebug_tables, link) {

  19:  

  20:         /* match against the module name */

  21:         // match_wildcard 如果匹配成功返回true

  22:         if (query->module &&

  23:             !match_wildcard(query->module, dt->mod_name))

  24:             continue;

  25:  

  26:         for (i = 0; i < dt->num_ddebugs; i++) {

  27:             struct _ddebug *dp = &dt->ddebugs[i]; // modname相同的descriptor是连续存放的

  28:  

  29:             /* match against the source filename */

  30:             if (query->filename &&

  31:                 !match_wildcard(query->filename, dp->filename) &&

  32:                 !match_wildcard(query->filename,

  33:                        kbasename(dp->filename)) &&

  34:                 !match_wildcard(query->filename,

  35:                        trim_prefix(dp->filename)))

  36:                 continue;

  37:  

  38:             /* match against the function */

  39:             if (query->function &&

  40:                 !match_wildcard(query->function, dp->function))

  41:                 continue;

  42:  

  43:             /* match against the format */

  44:             if (query->format &&

  45:                 !strstr(dp->format, query->format))

  46:                 continue;

  47:  

  48:             /* match against the line number range */

  49:             if (query->first_lineno &&

  50:                 dp->lineno < query->first_lineno)

  51:                 continue;

  52:             if (query->last_lineno &&

  53:                 dp->lineno > query->last_lineno)

  54:                 continue;

  55:  

  56:             nfound++; // 找到了匹配项

  57:  

  58:             newflags = (dp->flags & mask) | flags; // 赋值

  59:             if (newflags == dp->flags)

  60:                 continue;

  61:             dp->flags = newflags; // 将descriptor的flags修改成新的值,在打印是会判断

  62:             vpr_info("changed %s:%d [%s]%s =%s\n",

  63:                  trim_prefix(dp->filename), dp->lineno,

  64:                  dt->mod_name, dp->function,

  65:                  ddebug_describe_flags(dp, flagbuf,

  66:                                sizeof(flagbuf)));

  67:         }

  68:     }

  69:     mutex_unlock(&ddebug_lock);

  70:  

  71:     if (!nfound && verbose)

  72:         pr_info("no matches for query\n");

  73:  

  74:     return nfound;

  75: }

函数match_wildcard支持通配符匹配,比如我想打印文件demo_driver.c中的pr_debug,那么我可以这样来:

echo -n "file demo_dri* +p" > /sys/kernel/debug/dynamic_debug/control

上面query可以认为是过滤器,如果以上面的demo_driver.c为例,那么"file demo_driver.c +p",最后的处理结果是将demo_driver.c中所有的pr_debug和dev_dbg对应的descriptor的flags的值都设置为_DPRINTK_FLAGS_PRINT,那么就可以打印出来了。

match_wildcard:

   1: /**

   2:  * match_wildcard: - parse if a string matches given wildcard pattern

   3:  * @pattern: wildcard pattern

   4:  * @str: the string to be parsed

   5:  *

   6:  * Description: Parse the string @str to check if matches wildcard

   7:  * pattern @pattern. The pattern may contain two type wildcardes:

   8:  *   '*' - matches zero or more characters

   9:  *   '?' - matches one character

  10:  * If it's matched, return true, else return false.

  11:  */

  12: bool match_wildcard(const char *pattern, const char *str)

  13: {

  14:     const char *s = str;

  15:     const char *p = pattern;

  16:     bool star = false;

  17:  

  18:     while (*s) {

  19:         switch (*p) {

  20:         case '?':

  21:             s++;

  22:             p++;

  23:             break;

  24:         case '*':

  25:             star = true;

  26:             str = s;

  27:             if (!*++p)

  28:                 return true;

  29:             pattern = p;

  30:             break;

  31:         default:

  32:             if (*s == *p) {

  33:                 s++;

  34:                 p++;

  35:             } else {

  36:                 if (!star)

  37:                     return false;

  38:                 str++;

  39:                 s = str;

  40:                 p = pattern;

  41:             }

  42:             break;

  43:         }

  44:     }

  45:  

  46:     if (*p == '*')

  47:         ++p;

  48:     return !*p;

  49: }

下面是如果在bootargs中设置了诸如”demo.dyndbg”或者”demo.dyndbg=+/-p”或者"demo.dyndbg="func xxx_write line 10 +p""那么下面的这个函数就会在执行parse_args的时候被调用

ddebug_dyndbg_param_cb:

   1: 如在bootargs中设置了: demo.dyndbg 或者 demo.dyndbg=+p,那么demo.c的pr_debug就会打开

   2:  

   3: /* handle both dyndbg and $module.dyndbg params at boot */

   4: static int ddebug_dyndbg_boot_param_cb(char *param, char *val,

   5:                 const char *unused)

   6: {

   7:     vpr_info("%s=\"%s\"\n", param, val);

   8:     return ddebug_dyndbg_param_cb(param, val, NULL, 0);

   9: }

  10:  

  11: /* helper for ddebug_dyndbg_(boot|module)_param_cb */

  12: static int ddebug_dyndbg_param_cb(char *param, char *val,

  13:                 const char *modname, int on_err)

  14: {

  15:     char *sep;

  16:  

  17:     sep = strchr(param, '.');

  18:     if (sep) {

  19:         /* needed only for ddebug_dyndbg_boot_param_cb */

  20:         *sep = '\0';

  21:         modname = param;

  22:         param = sep + 1;

  23:     }

  24:     if (strcmp(param, "dyndbg"))

  25:         return on_err; /* determined by caller */

  26:     // 如果val是空的话(即只有demo.dyndbg),默认打开pr_debug

  27:     ddebug_exec_queries((val ? val : "+p"), modname); 

  28:  

  29:     return 0; /* query failure shouldnt stop module load */

  30: }

  31:  

先分析到这里,接下请看下一篇博客,主要分析一下:

echo –n “file demo.c +p”> /sys/kernel/debug/dynamic_debug/control 的原理。

==========================================================================================

转载:http://blog.csdn.net/pillarbuaa/article/details/7634546

dynamic debug log输出机制

0. 注意该机制只对 dev_dbg -> dynamic_dev_dbg 定义的debug log输出加以控制

1. 如何使用:(kernel/Documentation/dynamic-debug-howto.txt)

mkdir /data/debugfs

mount -t debugfs none /data/debugfs

echo -n 'file ab8500_fg.c +p' > /data/debugfs/dynamic_debug/control  //增加该文件dynamic debug的输出

echo -n 'file ab8500_fg.c -p' > /data/debugfs/dynamic_debug/control   //去掉该文件dynamic debug的输出

2. 如果想使用debugfs 必须,在kernel的config文件(kernel/arch/arm/configs/semc_lotus_deconfig)中有

CONFIG_DEBUG_FS=y

3. 如果需要使用Dynamic debug机制,需要在kernel的config文件(kernel/arch/arm/configs/semc_lotus_deconfig)中有

CONFIG_DYNAMIC_DEBUG=y

4. dev_dbg@kernel/include/linux/device.h ->dynamic_dev_dbg@kernel/include/linux/dynamic_debug.h

#define dynamic_dev_dbg(dev, fmt, ...) do {                      \
static struct _ddebug descriptor \
__used \
__attribute__((section("__verbose"), aligned(8))) = \
{ KBUILD_MODNAME, __func__, __FILE__, fmt, DEBUG_HASH, \
DEBUG_HASH2, __LINE__, _DPRINTK_FLAGS_DEFAULT }; \
if (__dynamic_dbg_enabled(descriptor)) \
dev_printk(KERN_DEBUG, dev, fmt, ##__VA_ARGS__); \
} while (0)

a. 该define 最终会展开在被调用dev_dbg函数的c文件中,也就是KBUILD_MODNAME, __func__, __FILE__, __LINE__ 会有对应的字符串

b. _DPRINTK_FLAGS_DEFAULT=0;

c. DEBUG_HASH和DEBUG_HASH2的定义在kernel/scripts/makefile.lib中

DEBUG_HASH=$(shell ./scripts/basic/hash djb2 $(@D)$(modname))   //利用djb2 hash算法,计算modname的DEBUG_HASH value;

DEBUG_HASH2=$(shell ./scripts/basic/hash r5 $(@D)$(modname))         //利用r5 hash算法,计算modname的DEBUG_HASH2 value;

d. 分析 kernel/scripts/basic/hash.c,会生成out/target/product/lotus/obj/kernel/scripts/basic/hash, shell可执行文件

e. 在编译连接完成后,该 descriptor 值会被保存到 data section的 __verbose区

5. dynamic_debug_init@kernel/lib/dynamic_debug.c

a. dir = debugfs_create_dir("dynamic_debug", NULL);

b. file = debugfs_create_file("control", 0644, dir, NULL, &ddebug_proc_fops); //在debugfs文件系统中创建dynamic_debug/control 文件

c. 通过__start___verbose__stop___verbose@kernel/include/asm-generic/vmlinux.lds.h中,实际上是获取保存在__verbose区的 struct _ddebug 数据(就是前面编译后添加到data section的__verbose)

d. 如果是不同的modname,就添加到ddebug_tables 中,也就是所有dynamic_dev_dbg的模块(modname),文件(__FILE__),行(__LINE__),函数(__func__),是否输出的flag,对应的hash value都会逐条保存到ddebug_tables中

6. 分析 echo -n 'file ab8500_charger.c +p' > /data/debugfs/dynamic_debug/control 的实际操作

a. 通过system call,debugfs文件系统会调用到ddebug_proc_write,ddebug_parse_query和ddebug_parse_flags@kernel/lib/dynamic_debug.c分析传入的参数字符串

b. 在ddebug_change@kernel/lib/dynamic_debug.c中,会根据modname, __FILE__, __LINE__, __func__信息在ddebug_tables找到对应的item.

c. 然后根据输入的是 +p或-p ,来标志struct _ddebug中flag字段,还有根据struct _ddebug中的primary_hash和secondary_hash,来标志global value dynamic_debug_enabled和dynamic_debug_enabled2 对应的位,会在__dynamic_dbg_enabled@kernel/include/linux/dynamic_debug.h用到

7. 分析 #cat /data/debugfs/dynamic_debug/control的实际操作

a. 先ddebug_proc_open中有err = seq_open(file, &ddebug_proc_seqops);应用了seq file的读写机制

b. 然后seq_read,利用seq file机制逐个读出和显示ddebug_tables中的内容

8. long long dynamic_debug_enabled和dynamic_debug_enabled2@kernel/lib/dynamic_debugc,用于标志某个mod(可包含一个或多个文件,比如ab8500_fg mod,目前只包含ab8500_fg.c file)是否可以输出debug log的模块.  最多可以标志64*64=4096个dev_debug/dynamic_dev_dbg.

9. 是否输出dev_log/dynamic_dev_dbg的log, 关键是如下判断,@kernel/include/linux/dynamic_debug.h

#define __dynamic_dbg_enabled(dd)  ({                  \
int __ret = 0; \
if (unlikely((dynamic_debug_enabled & (1LL << DEBUG_HASH)) && \
(dynamic_debug_enabled2 & (1LL << DEBUG_HASH2)))) \
if (unlikely(dd.flags)) \
__ret = 1; \
__ret; })

a. dynamic_debug_enabled和dynamic_debug_enabled2就是前面分析的是否输出该modname的两个long long的组合标志位

b. DEBUG_HASH和DEBUG_HASH2 如前面所解释

c. dd.flag 默认为_DPRINTK_FLAGS_DEFAULT,但通过debugfs文件系统,最终操作ddebug_proc_write函数,会设置为_DPRINTK_FLAGS_PRIN或_DPRINTK_FLAGS_DEFAULT

10. debugfs 文件系统中的内容保存在那?????内存中,类似proc

11. 小结:如果你需要用到dynamic debug info, 你需要在你的 .c 文件中查看是否用到了dev_log 输出log。

pr_debug、dev_dbg等动态调试一的更多相关文章

  1. pr_debug、dev_dbg等动态调试三

    内核版本:Linux-3.14 作者:彭东林 邮箱:pengdonglin137@163.com 如果没有使用CONFIG_DYNAMIC_DEBUG,那么就需要定义DEBUG,那么此时pr_debu ...

  2. pr_debug、dev_dbg等动态调试二

    内核版本:Linux-3.14 作者:彭东林 邮箱:pengdonglin137@163.com 下面我们简要分析 1: echo -n "file demo.c +p" > ...

  3. linux内核动态调试技术

    动态调试功能就是你可以决定在程序运行过程中是否要 pr_debug(), dev_dbg(), print_hex_dump_debug(), print_hex_dump_bytes() 这些函数正 ...

  4. apk逆向 - smali动态调试

    author: Dlive date: 2016/10/6 0x00 前言 ​ 之前有人问过smali的动态调试方法,其实网上已经有很多文章讲这些内容,但是为了方便大家学习,我还是写一下让大家少走点坑 ...

  5. 安卓动态调试七种武器之离别钩 – Hooking(下)

    0x00 序 随着移动安全越来越火,各种调试工具也都层出不穷,但因为环境和需求的不同,并没有工具是万能的.另外工具是死的,人是活的,如果能搞懂工具的原理再结合上自身的经验,你也可以创造出属于自己的调试 ...

  6. 安卓动态调试七种武器之离别钩 – Hooking(上)

    安卓动态调试七种武器之离别钩 – Hooking(上) 作者:蒸米@阿里聚安全 0x00 序 随着移动安全越来越火,各种调试工具也都层出不穷,但因为环境和需求的不同,并没有工具是万能的.另外工具是死的 ...

  7. 安卓动态调试七种武器之孔雀翎 – Ida Pro

    安卓动态调试七种武器之孔雀翎 – Ida Pro 作者:蒸米@阿里聚安全 0x00 序 随着移动安全越来越火,各种调试工具也都层出不穷,但因为环境和需求的不同,并没有工具是万能的.另外工具是死的,人是 ...

  8. 安卓动态调试七种武器之长生剑 - Smali Instrumentation

    安卓动态调试七种武器之长生剑 - Smali Instrumentation 作者:蒸米@阿里聚安全 0x00 序 随着移动安全越来越火,各种调试工具也都层出不穷,但因为环境和需求的不同,并没有工具是 ...

  9. Android动态方式破解apk前奏篇(Eclipse动态调试smail源码)

    一.前言 今天我们开始apk破解的另外一种方式:动态代码调试破解,之前其实已经在一篇文章中说到如何破解apk了: Android中使用静态方式破解Apk  主要采用的是静态方式,步骤也很简单,首先使用 ...

随机推荐

  1. 团队Alpha(八)冲刺

    目录 组员情况 组员1(组长):胡绪佩 组员2:胡青元 组员3:庄卉 组员4:家灿 组员5:凯琳 组员6:翟丹丹 组员7:何家伟 组员8:政演 组员9:黄鸿杰 组员10:刘一好 组员11:何宇恒 展示 ...

  2. linux运维文章

    运维中关键技术点解剖:1 大量高并发网站的设计方案 :2 高可靠.高可伸缩性网络架构设计:3 网站安全问题,如何避免被黑?4 南北互联问题,动态CDN解决方案:5 海量数据存储架构 一.什么是大型网站 ...

  3. 如何修改win10管理员账户

    首先按下win+x组合键,如下图所示   在弹出菜单选择运行,如下图所示   在运行框中输入netplwiz后点击确定按钮   将下图中要使用本计算机必须输入用户名和密码前面的勾去掉,点击下方应用按钮 ...

  4. python 下划线转驼峰

    # 下划线转驼峰 def str2Hump(text): arr = filter(None, text.lower().split('_')) res = '' j = 0 for i in arr ...

  5. 寻宝游戏(bzoj 3991)

    Description 小B最近正在玩一个寻宝游戏,这个游戏的地图中有N个村庄和N-1条道路,并且任何两个村庄之间有且仅有一条路径可达.游戏开始时,玩家可以任意选择一个村庄,瞬间转移到这个村庄,然后可 ...

  6. [网络流24题] COGS 750 栅格网络流

    750. 栅格网络流 ★★☆   输入文件:flowa.in   输出文件:flowa.out   简单对比时间限制:1 s   内存限制:128 MB [问题描述] Bob 觉得一般图的最大流问题太 ...

  7. 创建型设计模式之建造者模式(Builder)

    结构 意图 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示. 适用性 当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时. 当构造过程必须允许被构造的对象有不 ...

  8. Application binary interface and method of interfacing binary application program to digital computer

    An application binary interface includes linkage structures for interfacing a binary application pro ...

  9. MFC中使用sqlite3操作数据库

    需要用到的文件有sqlite3.h .sqlite3.dll.sqlite3.lib.网上很多人分享下载地址这里不再赘述. 将这三个文件拷贝到自己新建MFC项目目录下,在解决方案窗口下 添加现有项,选 ...

  10. create a large size empty file to measure transfer speed

    OS : Windows open cmd fsutil file createnew file_name 1073741824 // 1GB fsutil file createnew file_n ...