最近在研究内核,主要使用printk来跟踪函数的调用过程。但直接使用printk来打印的话,各种信息太多太杂。而且又不想把已经加了的东西删除。于是决定使用打印等级的方式来实现不同各类信息的显示。
思路很简单,使用不同的宏控制打印函数。打印哪些各类的调试信息由用户控制。通过echo方式传递至内核,实际上是32位的数值,每个比特表示一个各类的信息。因此最多有32种,目前看应该是足够了。为了方便查看哪个比特表示哪种打印,同时为了尽量减小添加代码的麻烦,使用了较多宏定义的技巧。
头文件:
// Add by Late Lee 2016.11.15
extern 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< /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/lldebug
current debug level: 0x00000200 max debug level type: 32
bit 0x01 D_NETCARD
bit 0x02 D_LINK
bit 0x04 D_IP
bit 0x08 D_ICMP
bit 0x10 D_ARP
bit 0x20 D_UDP
bit 0x40 D_TCP
bit 0x80 D_SOCKET
bit 0x100 D_PACKET
bit 0x200 D_IEEE80211
bit 0x00 (null)
bit 0x00 (null)
...
bit 0x80000000 D_VERBOSE
李迟 2016.11.15 夜