【LINUX】pr_info函数开发摸索
1、打印开关可随时控制,开机如果要修改是否打印日志的话,需要修改代码重新编译内核才行,其实如果真要搞,应该有其他方法;
2、打印次数,当前代码里边写的是1000次,其实可以根据传参动态修改打印日志次数,不过没有开发,只是大概展示了下;
3、函数未来可扩展;
运行效果:
代码:
include/linux/printk_self.h · r77683962/linux-6.9.0 - Gitee.comhttps://gitee.com/r77683962/linux-6.9.0/blob/70652d2129aae756fde3f9c440dd21177d9890cd/include/linux/printk_self.hinclude/linux/printk_self.h
#ifndef __KERNEL_PRINTK_SELF__
#define __KERNEL_PRINTK_SELF__
#include <linux/stdarg.h>
#include <linux/init.h>
#include <linux/kern_levels.h>
#include <linux/linkage.h>
#include <linux/ratelimit_types.h>
#include <linux/once_lite.h>
typedef enum
{
PRINT_LOG_STATE_NONE = 0,
PRINT_LOG_STATE_LESS,
PRINT_LOG_STATE_DEFAULT,
PRINT_LOG_STATE_MORE,
PRINT_LOG_STATE_TIMES
}PRINT_LOG_STATE_EN;
extern int iGlobalLogPrintLevel;
extern int iGlobalLogPrintTimes;
void GlobalLogPrintTimesSet(unsigned int value);
void GlobalLogPrintLevelSet(int value);
/**
* pr_info - Print an info-level message
* @fmt: format string
* @...: arguments for the format string
*
* This macro expands to a printk with KERN_INFO loglevel. It uses pr_fmt() to
* generate the format string.
*/
#define pr_info_self(fmt, ...) \
({ \
if (iGlobalLogPrintLevel == PRINT_LOG_STATE_DEFAULT) \
printk(KERN_INFO "[%s %s %d DEFAULT] "pr_fmt(fmt), __FILE__, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
else if (iGlobalLogPrintLevel == PRINT_LOG_STATE_LESS) \
printk(KERN_INFO "[LESS] "pr_fmt(fmt), ##__VA_ARGS__); \
else if (iGlobalLogPrintLevel == PRINT_LOG_STATE_MORE) \
printk(KERN_INFO "[%s %s %d MORE] "pr_fmt(fmt), __FILE__, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
else if (iGlobalLogPrintLevel == PRINT_LOG_STATE_TIMES && iGlobalLogPrintTimes > 0) \
{ \
printk(KERN_INFO "[%s %s %d TIMES: %d ] "pr_fmt(fmt), __FILE__, __FUNCTION__, __LINE__, iGlobalLogPrintTimes, ##__VA_ARGS__); \
iGlobalLogPrintTimes--; \
} \
})
#endif
这个枚举是可以扩展的,比如自己想添加其他类型的打印类型,像java log打印就比较复杂;
另外就是pr_info_self这里也可以扩展,不过这里的语法比较复杂,什么斜杠,fmt,双引号什么的,修改代码的时候要注意
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/stdarg.h>
#include <linux/init.h>
#include <linux/kern_levels.h>
#include <linux/linkage.h>
#include <linux/ratelimit_types.h>
#include <linux/once_lite.h>
#include <linux/printk_self.h>
int iGlobalLogPrintLevel;
EXPORT_SYMBOL(iGlobalLogPrintLevel);
int iGlobalLogPrintTimes;
EXPORT_SYMBOL(iGlobalLogPrintTimes);
void GlobalLogPrintTimesSet(unsigned int value)
{
iGlobalLogPrintTimes = value;
}
EXPORT_SYMBOL(GlobalLogPrintTimesSet);
void GlobalLogPrintLevelSet(int value)
{
iGlobalLogPrintLevel = value;
}
EXPORT_SYMBOL(GlobalLogPrintLevelSet);
这就是实现的一点点封装,类似面向对象编译的类。
这里要注意export_symbol这个宏不能少。
不然编译不会有问题,链接会报错。
static long do_sys_openat2(int dfd, const char __user *filename,
struct open_how *how)
{
struct open_flags op;
int fd = build_open_flags(how, &op);
struct filename *tmp;
pr_info_self("");
if (fd)
return fd;
tmp = getname(filename);
if (IS_ERR(tmp))
return PTR_ERR(tmp);
if (strncmp_self(tmp->name, "log_none", 8) == 0)
{
GlobalLogPrintLevelSet(PRINT_LOG_STATE_NONE);
pr_info_self("log_none filename: %s", tmp->name);
}
else if (strncmp_self(tmp->name, "log_less", 8) == 0)
{
GlobalLogPrintLevelSet(PRINT_LOG_STATE_LESS);
pr_info_self("log_less filename: %s", tmp->name);
}
else if (strncmp_self(tmp->name, "log_default", 11) == 0)
{
GlobalLogPrintLevelSet(PRINT_LOG_STATE_DEFAULT);
pr_info_self("log_default filename: %s", tmp->name);
}
else if (strncmp_self(tmp->name, "log_more", 8) == 0)
{
GlobalLogPrintLevelSet(PRINT_LOG_STATE_MORE);
pr_info_self("log_more filename: %s", tmp->name);
}
else if (strncmp_self(tmp->name, "log_times", 9) == 0)
{
GlobalLogPrintTimesSet(1000);
GlobalLogPrintLevelSet(PRINT_LOG_STATE_TIMES);
pr_info_self("log_times filename: %s", tmp->name);
}
fd = get_unused_fd_flags(how->flags);
if (fd >= 0) {
struct file *f = do_filp_open(dfd, tmp, &op);
if (IS_ERR(f)) {
put_unused_fd(fd);
fd = PTR_ERR(f);
} else {
fd_install(fd, f);
}
}
putname(tmp);
return fd;
}
这里边就是根据文件名(其实视频里边操作的都是创建文件的文件名),来修改内核日志打印的状态。
初始化:
include/linux/printk.h · r77683962/linux-6.9.0 - Gitee.comhttps://gitee.com/r77683962/linux-6.9.0/blob/master/include/linux/printk.h如果想让内核在起动的时候就打开,需要修改iGlobalLogPrintLevel = PRINT_LOG_STATE_NONE;
static inline void setup_log_buf(int early)
{
iGlobalLogPrintLevel = PRINT_LOG_STATE_NONE;
iGlobalLogPrintTimes = 0;
}
这就是变量初始化。
# SPDX-License-Identifier: GPL-2.0-only
obj-y= printk.o printk_self.o
obj-$(CONFIG_PRINTK)+= printk_safe.o nbcon.o
obj-$(CONFIG_A11Y_BRAILLE_CONSOLE)+= braille.o
obj-$(CONFIG_PRINTK_INDEX)+= index.o
obj-$(CONFIG_PRINTK) += printk_support.o
printk_support-y := printk_ringbuffer.o
printk_support-$(CONFIG_SYSCTL) += sysctl.o
这就是Makefile的第一行,因为我们新增了两个文件,要新生成对应的.o文件
代码比较简单。
原文地址:https://blog.csdn.net/r77683962/article/details/139896552
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!