一个内核调试函数的实现

来源:互联网 发布:小型交易网站源码 编辑:程序博客网 时间:2024/05/22 14:15

最近在研究内核,主要使用printk来跟踪函数的调用过程。但直接使用printk来打印的话,各种信息太多太杂。而且又不想把已经加了的东西删除。于是决定使用打印等级的方式来实现不同各类信息的显示。

思路很简单,使用不同的宏控制打印函数。打印哪些各类的调试信息由用户控制。通过echo方式传递至内核,实际上是32位的数值,每个比特表示一个各类的信息。因此最多有32种,目前看应该是足够了。为了方便查看哪个比特表示哪种打印,同时为了尽量减小添加代码的麻烦,使用了较多宏定义的技巧。

头文件:

// Add by Late Lee 2016.11.15extern int g_ll_debug;enum ll_debug_level{    D_NETCARD = 0, // 网卡层    D_LINK, // 链路层    D_IP, // IP层    D_ICMP, // ICMP    D_ARP,  // ARP    D_UDP,  // UDP    D_TCP,  // TCP    D_SOCKET, // socket通路调试    D_PACKET, // AF_PACKET调试    D_IEEE80211, // 无线调试        // more...    D_VERBOSE = 31,    D_MAX_LEVEL,};struct ll_debug__info_t{    const char* name;    int bit;};extern const struct ll_debug__info_t ll_debug_info[D_MAX_LEVEL];#define __ll_debug(level, format, ...)\do {\if (unlikely(g_ll_debug&ll_debug_info[level].bit))\printk(KERN_ERR "[LL %s %d] " format, __func__, __LINE__, ## __VA_ARGS__);\} while (0)// End 

实现代码:

//////////////////////////////////////// <<<<<<<<<<<<<--- my debug Add by Late Lee 2016.11.15#define PROC_FILE  "lldebug"#define _BIT(x) (1<<x)#define __DEFINE_LEVEL(name) [name] = {#name, _BIT(name)}const struct ll_debug__info_t ll_debug_info[D_MAX_LEVEL] = {    __DEFINE_LEVEL(D_NETCARD),    __DEFINE_LEVEL(D_LINK),    __DEFINE_LEVEL(D_IP),    __DEFINE_LEVEL(D_ICMP),    __DEFINE_LEVEL(D_ARP),    __DEFINE_LEVEL(D_UDP),    __DEFINE_LEVEL(D_TCP),    __DEFINE_LEVEL(D_SOCKET),    __DEFINE_LEVEL(D_PACKET),    __DEFINE_LEVEL(D_IEEE80211),    __DEFINE_LEVEL(D_VERBOSE),};EXPORT_SYMBOL(ll_debug_info);static int my_debug_proc_show(struct seq_file *m, void *v){    int i = 0;    seq_printf(m, "debug info control.\nusage: echo 0xXXX > /proc/%s\n", PROC_FILE);    seq_printf(m, "current debug level: 0x%08x max debug level type: %d\n", g_ll_debug, D_MAX_LEVEL);    for (i = 0; i < D_MAX_LEVEL; i++)    {        seq_printf(m, "bit 0x%02x %s\n", ll_debug_info[i].bit, ll_debug_info[i].name);    }    return 0;     return 0;}static int my_version_proc_open(struct inode *inode, struct file *file){     return single_open(file, my_debug_proc_show, NULL);}static ssize_t my_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_ops){    unsigned char buffer[32] = {0};    int value = 0;    if (copy_from_user(buffer, buf, (count > 32 ? 32: count)))        goto out;    value = simple_strtol(buffer, NULL, 16);    g_ll_debug = value;out:    return count;}static const struct file_operations my_debug_proc_fops = {    .open      = my_version_proc_open,    .read      = seq_read,    .write     = my_write,    .llseek    = seq_lseek,    .release   = single_release,};struct proc_dir_entry* my_proc_entry = NULL; void create_debugproc(void){    if (!my_proc_entry)        my_proc_entry = proc_create(PROC_FILE, 0, NULL, &my_debug_proc_fops); // 在/proc目录下创建}void delete_debugproc(void){    if (my_proc_entry)        proc_remove(my_proc_entry);}// >>>>>>>>>>>>>>>>>>>>>>>>>>>.////////////////////////////////////////////////////

如需要新加调试类型,则在枚举类型ll_debug_level后添加,同时还要在ll_debug_info结构体中定义。


使用

1、在初始化时调用create_debugproc注册到/proc目录。

2、在需要打印调试信息处调用__ll_debug宏定义即可。如__ll_debug(D_IEEE80211, "XXX");

3、将不同数值写到/proc/lldebug文件。数值可组合,如echo 0x28 > /proc/igbdebug表示同时打印ICMP和UDP的调试信息。

下面是所有调试信息等级的说明:

latelee@latelee:~# cat /proc/lldebug debug info control.usage: echo 0xXXX > /proc/lldebugcurrent debug level: 0x00000200 max debug level type: 32bit 0x01 D_NETCARDbit 0x02 D_LINKbit 0x04 D_IPbit 0x08 D_ICMPbit 0x10 D_ARPbit 0x20 D_UDPbit 0x40 D_TCPbit 0x80 D_SOCKETbit 0x100 D_PACKETbit 0x200 D_IEEE80211bit 0x00 (null)bit 0x00 (null)...bit 0x80000000 D_VERBOSE

李迟 2016.11.15 夜

0 0