dynamic debug log输出机制

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 必须,在kernelconfig文件(kernel/arch/arm/configs/semc_lotus_deconfig)中有CONFIG_DEBUG_FS=y

3. 如果需要使用Dynamic debug机制,需要在kernelconfig文件(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_HASHDEBUG_HASH2的定义在kernel/scripts/makefile.lib

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

                                DEBUG_HASH2=$(shell ./scripts/basic/hash r5 $(@D)$(modname))         //利用r5 hash算法,计算modnameDEBUG_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_queryddebug_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 _ddebugflag字段,还有根据struct _ddebug中的primary_hashsecondary_hash,来标志global value dynamic_debug_enableddynamic_debug_enabled2 对应的位,会在__dynamic_dbg_enabledkernel/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_enableddynamic_debug_enabled2kernel/lib/dynamic_debugc,用于标志某个mod(可包含一个或多个文件,比如ab8500_fg mod,目前只包含ab8500_fg.c file)是否可以输出debug log的模块最多可以标志64*64=4096dev_debug/dynamic_dev_dbg.

9. 是否输出dev_log/dynamic_dev_dbglog, 关键是如下判断,@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_enableddynamic_debug_enabled2就是前面分析的是否输出该modname的两个long long的组合标志位

                b. DEBUG_HASHDEBUG_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

这段代码是一个 DHCP(Dynamic Host Configuration Protocol)服务器中的函数,用于将一个 DHCP 选项添加到一个选项列表中。函数的输入参数包括一个指向选项列表指针的指针 opt_list,一个指向 DHCP 选项结构体的指针 option,以及一个指向数据缓冲区的指针 buffer 和数据长度 length。 函数首先会查找选项列表中是否已经存在与要添加的 DHCP 选项相同的选项,如果存在,则将数据添加到该选项的数据缓冲区中,如果不存在,则创建一个新的选项,并将其插入到选项列表中。 如果要添加的 DHCP 选项是一个选项列表(多个值),则函数会检查是否能够将新的数据添加到已存在的选项数据缓冲区中,如果可以,则将数据添加到缓冲区中,否则将忽略这些数据。如果要添加的 DHCP 选项不是一个选项列表,则将忽略新的数据。 具体的实现过程如下: ``` struct option_set *existing, *new, **curr; // 查找选项列表中是否已经存在与要添加的 DHCP 选项相同的选项 if ((existing = find_option(*opt_list, option->code))) { // 如果存在,则将数据添加到该选项的数据缓冲区中 if (option->flags & OPTION_LIST) { if (existing->data[OPT_LEN] + length <= 255) { existing->data = realloc(existing->data, existing->data[OPT_LEN] + length + 2); memcpy(existing->data + existing->data[OPT_LEN] + 2, buffer, length); existing->data[OPT_LEN] += length; } // else, ignore the data, we could put this in a second option in the future } // else, ignore the new data } else { // 如果不存在,则创建一个新的选项,并将其插入到选项列表中 new = malloc(sizeof(struct option_set)); new->data = malloc(length + 2); new->data[OPT_CODE] = option->code; new->data[OPT_LEN] = length; memcpy(new->data + 2, buffer, length); curr = opt_list; // 将新的选项插入到选项列表中的正确位置,以保证选项列表的有序性 while (*curr && (*curr)->data[OPT_CODE] < option->code) curr = &(*curr)->next; new->next = *curr; *curr = new; } ``` 其中,find_option 函数用于查找选项列表中是否已经存在与要添加的 DHCP 选项相同的选项。OPT_CODE 和 OPT_LEN 是 DHCP 选项中的两个字段,分别表示选项的代码和数据长度。由于 DHCP 选项的数据部分长度不固定,因此需要动态分配内存来存储选项的数据缓冲区。最后,函数返回一个指向新的选项结构体的指针。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值