内核打印函数介绍
来源:互联网 发布:关于人工智能的书 编辑:程序博客网 时间:2024/04/27 03:30
我们先来看dev_dbg的定义
在linux/device.h文件中:
#ifdef DEBUG#define dev_dbg(dev, format, arg...) \ dev_printk(KERN_DEBUG , dev , format , ## arg)#elsestatic inline int __attribute__ ((format (printf, 2, 3)))dev_dbg(struct device * dev, const char * fmt, ...){ return 0;}#endif那我们在包含该头文件之前,需要声明一下DEBUG。
#define DEBUG#include <linux/kernel.h>#include <linux/init.h>#include <linux/clk.h>#include <linux/module.h>#include <linux/platform_device.h>但是这个打开了之后,也不能顺利的输出信息,原因是printk有默认的信息级别。在include/linux/kernel.h文件中
#define KERN_EMERG "<0>" #define KERN_ALERT "<1>" #define KERN_CRIT "<2>" #define KERN_ERR "<3>" #define KERN_WARNING "<4>" #define KERN_NOTICE "<5>" #define KERN_INFO "<6>" #define KERN_DEBUG "<7>"可以看到KERN_DEBUG是级别最低的。
2、修改文件include/linux/printk.h文件
#define DEFAULT_MESSAGE_LOGLEVEL 4#define MINIMUM_CONSOLE_LOGLEVEL 1#define DEFAULT_CONSOLE_LOGLEVEL 8
kernel/printk.c
int console_printk[4] = {CONSOLE_LOGLEVEL_DEFAULT,/* console_loglevel */MESSAGE_LOGLEVEL_DEFAULT,/* default_message_loglevel */CONSOLE_LOGLEVEL_MIN,/* minimum_console_loglevel */CONSOLE_LOGLEVEL_DEFAULT,/* default_console_loglevel */};
该数组的信息可通过cat /proc/sys/kernel/printk节点来查看。当然,也可以通过写上述节点的方法来更改打印级别。
其中DEFAULT_CONSOLE_LOGLEVEL 为终端console输出的最低级别,比这严重的都将输出。原来该值为7,则调试信息无法输出,修改为8则全部有输出。
对于dev_vdbg函数,查看源码
#ifdef VERBOSE_DEBUG#define dev_vdbg dev_dbg#else#define dev_vdbg(dev, format, arg...) \({ \ if (0) \ dev_printk(KERN_DEBUG, dev, format, ##arg); \ 0; \})#endif
则需要在头文件之前多加一个VERBOSE_DEBUG声明。
对应内核常见的其他打印函数,收集到的信息如下
对应pr_xxx()API的好处是,可以在文件最开头通过pr_fmt定义一个打印格式,比如在kernel/watchdog.c的最开头通过如下定义保证以后watchdog.c调用的
所以pr_xxx()打印的信息都自动带有" NMI watchdog: "的前缀。(linux/include/printk.h)
#define pr_fmt(fmt) " NMI watchdog: " fmt
#ifndef pr_fmt#define pr_fmt(fmt) fmt#endif#define pr_emerg(fmt, ...) \ printk(KERN_EMERG pr_fmt(fmt), ##__VA_ARGS__)#define pr_alert(fmt, ...) \ printk(KERN_ALERT pr_fmt(fmt), ##__VA_ARGS__)#define pr_crit(fmt, ...) \ printk(KERN_CRIT pr_fmt(fmt), ##__VA_ARGS__)#define pr_err(fmt, ...) \ printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__)#define pr_warning(fmt, ...) \ printk(KERN_WARNING pr_fmt(fmt), ##__VA_ARGS__)#define pr_warn pr_warning#define pr_notice(fmt, ...) \ printk(KERN_NOTICE pr_fmt(fmt), ##__VA_ARGS__)#define pr_info(fmt, ...) \ printk(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)#define pr_cont(fmt, ...) \ printk(KERN_CONT fmt, ##__VA_ARGS__)/* pr_devel() should produce zero code unless DEBUG is defined */#ifdef DEBUG#define pr_devel(fmt, ...) \ printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)#else#define pr_devel(fmt, ...) \ no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)#endif#include <linux/dynamic_debug.h>/* If you are writing a driver, please use dev_dbg instead */#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_xxx()族API打印的时候,设备名称对自动加到打印信息的前头。 (drivers/base/core.c)
static int __dev_printk(const char *level, const struct device *dev,struct va_format *vaf){if (!dev)return printk("%s(NULL device *): %pV", level, vaf);return dev_printk_emit(level[1] - '0', dev, "%s %s: %pV", dev_driver_string(dev), dev_name(dev), vaf);}int dev_printk(const char *level, const struct device *dev, const char *fmt, ...){struct va_format vaf;va_list args;int r;va_start(args, fmt);vaf.fmt = fmt;vaf.va = &args;r = __dev_printk(level, dev, &vaf);va_end(args);return r;}EXPORT_SYMBOL(dev_printk);#define define_dev_printk_level(func, kern_level)\int func(const struct device *dev, const char *fmt, ...)\{\struct va_format vaf;\va_list args;\int r;\\va_start(args, fmt);\\vaf.fmt = fmt;\vaf.va = &args;\\r = __dev_printk(kern_level, dev, &vaf);\\va_end(args);\\return r;\}\EXPORT_SYMBOL(func);define_dev_printk_level(dev_emerg, KERN_EMERG);define_dev_printk_level(dev_alert, KERN_ALERT);define_dev_printk_level(dev_crit, KERN_CRIT);define_dev_printk_level(dev_err, KERN_ERR);define_dev_printk_level(dev_warn, KERN_WARNING);define_dev_printk_level(dev_notice, KERN_NOTICE);define_dev_printk_level(_dev_info, KERN_INFO);
此外,打印中还经常看到pr_debug函数,可以动态的打印调试信息(http://blog.csdn.net/weiqifa0/article/details/44038907)
如要打开该函数,只需在内核中配置CONFIG_DYNAMIC_DEBUG,并且将debugfs挂载到某个文件夹mount -t debugfs none /sys/kernel/debug/,
就可以通过echo -n "file xxxxxx.c +p" > /sys/kernel/debug/dynamic_debug/control来打开调试信息啦。
#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
下面的程序printk_test.c用来测试上面的打印函数,如下
#define pr_fmt(fmt) KBUILD_MODNAME " pr_test::::::" fmt#define DEBUG#define VERBOSE_DEBUG#include <linux/module.h>#include <linux/platform_device.h>#include <linux/miscdevice.h>#include <asm/uaccess.h>#include <linux/sched.h>#include <linux/fs.h>#include <linux/device.h>#include <linux/delay.h>static struct miscdevice dev;#define GTP_INFO(fmt,arg...) printk("<<-GTP-INFO->> "fmt"\n",##arg)#define DEVICE_NAME "printk"static int printk_test(struct device *dev){printk(KERN_INFO KBUILD_MODNAME " %d\n",__LINE__);dev_emerg(dev,"dev_emerg %d\n",__LINE__);dev_alert(dev,"dev_alert %d\n",__LINE__);dev_crit(dev,"dev_crit %d\n",__LINE__);dev_err(dev,"dev_err %d\n",__LINE__);dev_warn(dev,"dev_warn %d\n",__LINE__);dev_notice(dev,"dev_notice %d\n",__LINE__);dev_info(dev,"dev_info %d\n",__LINE__);_dev_info(dev,"_dev_info %d\n",__LINE__);pr_emerg("pr_emerg %d\n",__LINE__);pr_alert("pr_alert %d\n",__LINE__);pr_crit("pr_crit %d\n",__LINE__);pr_err("pr_err %d\n",__LINE__);pr_warning("pr_warning %d\n",__LINE__);pr_warn("pr_warn %d\n",__LINE__);pr_notice("pr_notice %d\n",__LINE__);pr_info("pr_info %d\n",__LINE__);pr_cont("pr_cont %d\n",__LINE__);GTP_INFO("%d\n",__LINE__);msleep(8000);pr_debug("pr_debug\n");dev_dbg(dev,"dev_dbg %d\n",__LINE__);dev_vdbg(dev,"dev_vdbg %d\n",__LINE__);return 0;}static struct miscdevice dev = {.minor = MISC_DYNAMIC_MINOR,.name = DEVICE_NAME,};static int __init printk_init(void){int ret;printk("%s\n",__func__);ret = misc_register(&dev);ret = printk_test(dev.this_device);return ret;}static void __exit printk_exit(void){misc_deregister(&dev);printk("%s\n",__func__);}module_init(printk_init);module_exit(printk_exit);MODULE_LICENSE("GPL");
编译并安装驱动,修改打印级别echo 8 >/proc/sys/kernel/printk,打印信息为
这里的pr_debug函数也打印出来了,因为把DEBUG的声明放在CONFIG_DYNAMIC_DEBUG声明之前,pr_debug走的是printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__),
如果没有声明DEBUG,可通过echo -n "file printk_test.c +p" > /sys/kernel/debug/dynamic_debug/control来打开调试信息。
- 内核打印函数介绍
- 内核打印函数printk
- Linux 内核堆栈打印函数
- 内核函数前缀简单介绍
- Linux内核打印函数printk的使用说明
- 编写自己的内核打印函数
- Linux内核打印函数printk的使用说明 .
- linux内核函数功能介绍收集
- 如何打印内核调用堆栈及函数名
- 用函数printk打印内核信息的方法
- 用函数printk打印内核信息的方法
- 内核调试常会打印 文件名 函数名 行号
- linux内核中打印栈回溯信息 - dump_stack()函数分析
- linux内核中打印栈回溯信息 - dump_stack()函数分析
- 手动调整内核printk打印级别 && 内核模块初始化入口函数的优先级
- fgets()函数介绍,很方便实现逐行打印
- Linux内核中常见内存分配函数介绍
- 禁止内核打印信息
- UVA488 - Triangle Wave
- linux设备树device tree学习
- android 框架之Cordova 集成开发过程
- Android常用实例——实现修改用户头像功能
- ToolBar左上角一个返回按钮的实现
- 内核打印函数介绍
- HTML5-定制input元素
- NYOJ 16 矩形嵌套 [DAGdp或spfa]
- CSU 1573 最多的数字
- linux vi编辑器使用总结
- 关于CentOs7 u盘安装出现dracut:/#解决方案
- Android开发———如何去掉标题栏
- 个人学习_Android四大组件
- 事件驱动程序设计-窗口事件