精华内容
下载资源
问答
  • 内核中使用printk
    2021-05-11 10:34:29

    记住printk_ratelimited就好,

    网上有原理说明,内核中有示例代码。

    unsigned int status;

    status = port->serial_in(port, UART_LSR);

    printk_limited(KERR "LSR = %x\n", status);

     

    注意调用的位置,位置不当易导致内核卡死。

    原因待查。

    更多相关内容
  • printk 内核打印

    2021-05-15 01:50:07
    printk 在内核源码用来记录日志信息的函数,只能在内核源码范围内使用,用法类似于 printf 函数。 printk 函数主要做两件事情: 将信息记录到 log ; 调用控制台驱动来将信息输出。 printk 介绍 printk内核...

    printk 在内核源码中用来记录日志信息的函数,只能在内核源码范围内使用,用法类似于 printf 函数。

    printk 函数主要做两件事情:

    1. 将信息记录到 log 中;
    2. 调用控制台驱动来将信息输出。

    printk 介绍

    printk 将内核信息输出到内核信息缓冲区中,内核缓冲区在 kernel/printk/printk.c 中定义:

    static char __log_buf[__LOG_BUF_LEN] __aligned(LOG_ALIGN);
    

    内核信息缓冲区是一个环形缓冲区(Ring Buffer),因此,如果塞入的消息过多,则就会将之前的消息冲刷掉。

    消息级别

    Linux 内核共提供了八种不同的消息级别,分为级别 0~7。数值越大,表示级别越低,对应的消息越不重要。相应的宏定义在 include/linux/kern_levels.h 文件中。

    #define KERN_SOH	"\001"		/* ASCII Start Of Header */
    #define KERN_SOH_ASCII	'\001'
    
    #define KERN_EMERG      KERN_SOH "0"	/* system is unusable */
    #define KERN_ALERT      KERN_SOH "1"	/* action must be taken immediately */
    #define KERN_CRIT       KERN_SOH "2"	/* critical conditions */
    #define KERN_ERR        KERN_SOH "3"	/* error conditions */
    #define KERN_WARNING    KERN_SOH "4"	/* warning conditions */
    #define KERN_NOTICE     KERN_SOH "5"	/* normal but significant condition */
    #define KERN_INFO       KERN_SOH "6"	/* informational */
    #define KERN_DEBUG      KERN_SOH "7"	/* debug-level messages */
    

    说明:

    • KERN_EMERG 表示紧急事件,一般是系统崩溃之前提示的消息;
    • KERN_ALERT 表示必须立即采取行动的消息;
    • KERN_CRIT 表示临界状态,通常涉及严重的硬件或软件操作失败;
    • KERN_ERR 用于报告错误状态,设备驱动程序会经常使用该级别来报告来自硬件的问题;
    • KERN_WARNING 对可能出现问题的情况进行警告,这类情况通常不会对系统造成严重的问题;
    • KERN_NOTICE 表示有必要进行提示的正常情形,许多与安全相关的状况用这个级别进行汇报;
    • KERN_INFO 表示内核提示信息,很多驱动程序在启动的时候,用这个级别打印出它们找到的硬件信息;
    • KERN_DEBUG 用于调试信息。

    内核 printk 文件

    通过 /proc/sys/kernel/printk 文件可以调节 printk 的输出等级,该文件有 4 个数字值。例如,在 Ubuntu 上的值如下:

    $ cat /proc/sys/kernel/printk
    4       4       1       7
    

    四个数值的含义如下:

    1. 控制台日志级别:优先级高于该值的消息将被打印至控制台;
    2. 默认的消息日志级别:将用该优先级来打印没有优先级的消息;
    3. 最低的控制台日志级别:控制台日志级别可被设置的最小值(最高优先级);
    4. 默认的控制台日志级别:控制台日志级别的缺省值。

    这四个值是在 kernel/printk/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 */
    };
    EXPORT_SYMBOL_GPL(console_printk);
    

    调整打印级别

    在 menuconfig 中修改

    修改 CONFIG_MESSAGE_LOGLEVEL_DEFAULT 的值,然后重新编译,更新内核。menuconfig 配置路径如下:

    Kernel hacking  --->
        printk and dmesg options  --->
            (4) Default message log level (1-7)
    

    在系统中修改

    在系统运行期间,可以通过修改 /proc/sys/kernel/printk 中的值来改变内核打印效果。例如,屏蔽掉所有的内核 printk 打印,只需要把第一个数值调到最小值1或者0。

    echo 1       4       1      7 > /proc/sys/kernel/printk
    

    使用示例

    在使用 printk 时我们会将消息级别放到最开始的位置,例如:

    printk(KERN_EMERG   "GetIot: KERN_EMERG\n");
    printk(KERN_ALERT   "GetIot: KERN_ALERT\n");
    printk(KERN_CRIT    "GetIot: KERN_CRIT\n");
    printk(KERN_ERR     "GetIot: KERN_ERR\n");
    printk(KERN_WARNING "GetIot: KERN_WARNING\n");
    printk(KERN_NOTICE  "GetIot: KERN_NOTICE\n");
    printk(KERN_INFO    "GetIot: KERN_INFO\n");
    printk(KERN_DEBUG   "GetIot: KERN_DEBUG\n");
    

    如果没有设置消息的日志级别,默认使用 default_message_loglevel 级别(该值可在 menuconfig 中修改)。

    当 printk 中的消息日志级别小于当前控制台的日志级别(console_printk[0])时,printk 的信息就会在控制台上显示。但无论当前控制台日志级别是何值,即使没有在控制台打印出来,都可以通过下面两种方法查看日志:

    • 第一种是使用 dmesg 命令打印;
    • 第二种是通过 cat /proc/kmsg 来打印。

    另外如果配置好并运行了 syslogd 或 klogd,没有在控制台上显示的 printk 的信息也会追加到 /var/log/messages.log 中。

    查看打印

    将上述示例代码添加到 最简单的内核模块hello_init 函数中,编译并执行 insmod hello.ko 安装模块。

    dmesg

    执行 dmesg | tail 将会看到如下打印:

    [20120.194934] module init success
    [20120.194935] GetIot: KERN_EMERG
    [20120.194937] GetIot: KERN_ALERT
    [20120.194938] GetIot: KERN_CRIT
    [20120.194939] GetIot: KERN_ERR
    [20120.194940] GetIot: KERN_WARNING
    [20120.194940] GetIot: KERN_NOTICE
    [20120.194940] GetIot: KERN_INFO
    [20120.194941] GetIot: KERN_DEBUG
    

    /proc/kmsg

    也可以执行 cat /proc/kmsg 等待内核打印:

    $ sudo cat /proc/kmsg 
    <6>[20120.194934] module init success
    <0>[20120.194935] GetIot: KERN_EMERG
    <1>[20120.194937] GetIot: KERN_ALERT
    <2>[20120.194938] GetIot: KERN_CRIT
    <3>[20120.194939] GetIot: KERN_ERR
    <4>[20120.194940] GetIot: KERN_WARNING
    <5>[20120.194940] GetIot: KERN_NOTICE
    <6>[20120.194940] GetIot: KERN_INFO
    <7>[20120.194941] GetIot: KERN_DEBUG
    

    其他用法

    pr_xxx

    除了直接使用 printk 加消息级别的方式,在 <linux/printk.h> 中还定义了 pr_notice、pr_info、pr_warn、pr_err 等接口。使用这些 pr_xxx 接口,就可以省去指定消息级别的麻烦。

    #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_devel(fmt, ...)     printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
    #define pr_debug(fmt, ...)     printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
    

    需要注意的是,其他 pr_XXX() 函数能无条件地打印,但 pr_debug() 却不能。因为默认情况下它不会被编译,除非定义了 DEBUG 或设定了 CONFIG_DYNAMIC_DEBUG

    dev_xxx

    对于驱动程序,在 <linux/device.h> 里也提供了一些驱动模型诊断宏,例如 dev_err、dev_warn、dev_info 等等。使用它们,不仅可以按标记的消息级别打印,还会打印对应的设备和驱动信息,这对于驱动调试来说相当重要。

    #define dev_emerg(dev, fmt, ...)  _dev_emerg(dev, dev_fmt(fmt), ##__VA_ARGS__)
    #define dev_crit(dev, fmt, ...)   _dev_crit(dev, dev_fmt(fmt), ##__VA_ARGS__)
    #define dev_alert(dev, fmt, ...)  _dev_alert(dev, dev_fmt(fmt), ##__VA_ARGS__)
    #define dev_err(dev, fmt, ...)    _dev_err(dev, dev_fmt(fmt), ##__VA_ARGS__)
    #define dev_warn(dev, fmt, ...)   _dev_warn(dev, dev_fmt(fmt), ##__VA_ARGS__)
    #define dev_notice(dev, fmt, ...) _dev_notice(dev, dev_fmt(fmt), ##__VA_ARGS__)
    #define dev_info(dev, fmt, ...)   _dev_info(dev, dev_fmt(fmt), ##__VA_ARGS__)
    
    #if defined(CONFIG_DYNAMIC_DEBUG)
    #define dev_dbg(dev, fmt, ...)   dynamic_dev_dbg(dev, dev_fmt(fmt), ##__VA_ARGS__)
    #elif defined(DEBUG)
    #define dev_dbg(dev, fmt, ...)   dev_printk(KERN_DEBUG, dev, dev_fmt(fmt), ##__VA_ARGS__)
    #else
    #define dev_dbg(dev, fmt, ...)	\
    ({								\
    	if (0)						\
    		dev_printk(KERN_DEBUG, dev, dev_fmt(fmt), ##__VA_ARGS__); \
    })
    #endif
    

    同样需要注意,deb_dbg() 也不是无条件打印的,除非定义了 DEBUG 或设定了 CONFIG_DYNAMIC_DEBUG。一个相关约定是在已经开启了 DEBUG 时,使用 VERBOSE_DEBUG 来添加 dev_vdbg()

    展开全文
  •  在内核调试技术之,简单的是printk使用了,它的用法和C语言应用程序的printf使用类似,在应用程序依靠的是stdio.h的库,而在linux内核中没有这个库,所以在linux内核中使用这个printk要对内核的实现...
  • 内核开发调试printk

    2020-11-24 21:44:37
    在进行驱动开发的过程往往要打印一些信息来查看是否正确类似于printf,以下将介绍在内核开发常用的调试方法。.(第一次写文章,内容可能不咋样勿喷呀) 内容 一、printk介绍 二、如何查看并修改消息级别 在应用...

    进行内核开发调试

    在进行驱动开发的过程中往往要打印一些信息来查看是否正确类似于printf,以下将介绍在内核开发常用的调试方法。.(第一次写文章,内容可能不咋样勿喷呀)

    内容

    一、printk介绍
    二、如何查看并修改消息级别

    在应用程序采用printf打印调试、内核驱动采用printk打印调试。
    printk函数打印数据到console缓冲区,打印的格式方类似printf。

    printk函数说明
    头文件:<linux/kernel.h>

    int printk(KERN_XXX const char *fmt , …)
    @param[in] fmt 格式化参数,如:%d
    @return 打印出来的字符个数

    例子:

    printk(“hello_init\n”);
    printk(“hello_init = %d\n”,i);
    printk(KERN_ALERT"hello_init=%d\n",i);
    printk("<1>"“hello_init=%d”,i);
    KERN_ALERT 等效于“<1>”
    通过修改KERN_ALERT来修改优先级

    优先级打印级别 0最高,7最低
    0、 KERN_EMERG “<0>” 用于紧急消息, 常常是那些崩溃前的消息
    1、 KERN_ALERT “<1>” 需要立刻动作的情形
    2、 KERN_CRIT “<2>” 严重情况, 常常与严重的硬件或者软件失效有关
    3、 KERN_ERR “<3>” 用来报告错误情况; 设备驱动常常使用 KERN_ERR 来报告硬件故障
    4、 KERN_WARNING “<4>” 有问题的情况的警告, 这些情况自己不会引起系统的严重问题
    5、 KERN_NOTICE “<5>” 正常情况, 但是仍然值得注意. 在这个级别一些安全相关的情况会报告
    6、 KERN_INFO “<6>” 信息型消息. 在这个级别, 很多驱动在启动时打印它们发现的硬件的信息
    7、 KERN_DEBUG “<7>” 用作调试消息

    格式化符

    符合说明
    %d十进制打印
    %x十六进制
    %u无符号整数
    %lu无符号长整数
    %lx十六进制无符号长整数
    %lld64bit整数值
    %llx64bit16进制整数值
    %zusize_t 10进制打印
    %zxsize_t 16进制打印
    %zdssize_t 10进制打印
    %p指针原值输出

    日志守护进程
    【klogd&syslogd】

    klogd	内核日志守护进程,将内核消息放入/var/log/messages中
    syslogd	系统日志守护进程,将程序消息放入/var/log/messages中
    

    通过命令#dmesg 可以查看消息
    也可以通过命令cat /var/log/messages查看消息

    【console_loglevel】
    if (打印消息级别 < console_loglevel)
    打印到当前控制台

    可以通过读/proc/sys/kernel/printk来查看控制台消息级别
    如,# cat /proc/sys/kernel/printk 出现 4 4 1 7
    该文件有四个数字值,它们根据日志记录消息的重要性,定义将其发送到何处。上面显示的4个数据分别对应:
    1、控制台日志级别:优先级高于该值的消息将被打印至控制台
    2、默认的消息日志级别:将用该优先级来打印没有优先级的消息(未指定日志级别的printk() 采用的默认级别 )
    3、最低的控制台日志级别:控制台日志级别可被设置的最小值(最高优先级)
    4、默认的控制台日志级别:控制台日志级别的缺省值

    可以通过写 /proc/sys/kernel/printk 来修改控制台消息级别
    了解了上面的这些知识后,我们就应该知道如何手动控制printk打印了。
    例如,我想屏蔽掉所有的内核printk打印,那么我只需要把第一个数值调到最小值1或者0。

    方法一:
    #echo 1 4 1 7 > /proc/sys/kernel/printk
    方法二:
    #klogd -c 1

    …写得很乱

    展开全文
  • Linux内核printk 打印

    千次阅读 2022-04-20 22:55:46
    Linux 内核printk 打印


    前言

    printk 在内核源码中用来记录日志信息的函数,只能在内核源码范围内使用,用法类似于 printf 函数。

    printk 函数主要做两件事情:

    1、将信息记录到 log 中;
    2、调用控制台驱动来将信息输出。


    一、printk 介绍

    printk 将内核信息输出到内核信息缓冲区中,内核缓冲区在 kernel/printk/printk.c 中定义:

    static char __log_buf[__LOG_BUF_LEN] __aligned(LOG_ALIGN);
    

    1. printk 消息级别

    Linux 内核共提供了八种不同的消息级别,分为级别 0~7。数值越大,表示级别越低,对应的消息越不重要。相应的宏定义在 include/linux/kern_levels.h 文件中。

    #define KERN_SOH   "\001"      /* ASCII Start Of Header */
    #define KERN_SOH_ASCII '\001'
    
    #define KERN_EMERG      KERN_SOH "0"   /* system is unusable */
    #define KERN_ALERT      KERN_SOH "1"   /* action must be taken immediately */
    #define KERN_CRIT       KERN_SOH "2"   /* critical conditions */
    #define KERN_ERR        KERN_SOH "3"   /* error conditions */
    #define KERN_WARNING    KERN_SOH "4"   /* warning conditions */
    #define KERN_NOTICE     KERN_SOH "5"   /* normal but significant condition */
    #define KERN_INFO       KERN_SOH "6"   /* informational */
    #define KERN_DEBUG      KERN_SOH "7"   /* debug-level messages */
    

    说明:

    • KERN_EMERG 表示紧急事件,一般是系统崩溃之前提示的消息;
    • KERN_ALERT 表示必须立即采取行动的消息;
    • KERN_CRIT 表示临界状态,通常涉及严重的硬件或软件操作失败;
    • KERN_ERR 用于报告错误状态,设备驱动程序会经常使用该级别来报告来自硬件的问题;
    • KERN_WARNING 对可能出现问题的情况进行警告,这类情况通常不会对系统造成严重的问题;
    • KERN_NOTICE 表示有必要进行提示的正常情形,许多与安全相关的状况用这个级别进行汇报;
    • KERN_INFO 表示内核提示信息,很多驱动程序在启动的时候,用这个级别打印出它们找到的硬件信息;
    • KERN_DEBUG 用于调试信息。

    2.内核 printk 文件

    通过 /proc/sys/kernel/printk 文件可以调节 printk 的输出等级,该文件有 4 个数字值。例如,在 Ubuntu 上的值如下:

    $ cat /proc/sys/kernel/printk
    4       4       1       7
    

    四个数值的含义如下:
    控制台日志级别:优先级高于该值的消息将被打印至控制台;
    默认的消息日志级别:将用该优先级来打印没有优先级的消息(即 printk 没有指定消息级别);
    最低的控制台日志级别:控制台日志级别可被设置的最小值(最高优先级);
    默认的控制台日志级别:控制台日志级别的缺省值。

    这四个值是在 kernel/printk/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 */
    };
    EXPORT_SYMBOL_GPL(console_printk);
    

    二、调整打印级别

    调整 printk 打印级别可以使得在印 Log 时控制输出 Log 的信息量以及控制自己想要输出的信息级别,下面则介绍调整 printk 打印级别的几种方法:

    1.在 menuconfig 中修改

    修改 CONFIG_MESSAGE_LOGLEVEL_DEFAULT 的值,然后重新编译,更新内核。menuconfig 配置路径如下:

    Kernel hacking  --->
        printk and dmesg options  --->
            (4) Default message log level (1-7)
    

    2.在系统中修改(常用)

    在系统运行期间,可以通过修改 /proc/sys/kernel/printk 中的值来改变内核打印效果。例如,屏蔽掉所有的内核 printk 打印,只需要把第一个数值调到最小值1或者0,此时可以敲如下 cmd:

    echo 1       4       1      7 > /proc/sys/kernel/printk
    

    echo 1 > /proc/sys/kernel/printk # 表示只修改第一个值
    

    三、使用示例

    在使用 printk 时我们会将消息级别放到最开始的位置,例如:

    printk(KERN_EMERG   "GetIot: KERN_EMERG\n");
    printk(KERN_ALERT   "GetIot: KERN_ALERT\n");
    printk(KERN_CRIT    "GetIot: KERN_CRIT\n");
    printk(KERN_ERR     "GetIot: KERN_ERR\n");
    printk(KERN_WARNING "GetIot: KERN_WARNING\n");
    printk(KERN_NOTICE  "GetIot: KERN_NOTICE\n");
    printk(KERN_INFO    "GetIot: KERN_INFO\n");
    printk(KERN_DEBUG   "GetIot: KERN_DEBUG\n");
    

    如果没有设置消息的日志级别,默认使用 default_message_loglevel 级别(该值可由上述两种方式修改,即第二个数值)。

    当 printk 中的消息日志级别小于当前控制台的日志级别(console_printk[0])时,printk 的信息就会在控制台上显示。但无论当前控制台日志级别是何值,即使没有在控制台打印出来,都可以通过下面两种方法查看日志:

    • 第一种是使用 dmesg 命令打印;
    • 第二种是通过 cat /proc/kmsg 来打印。

    另外如果配置好并运行了 syslogd 或 klogd,没有在控制台上显示的 printk 的信息也会追加到 /var/log/messages.log 中。

    四、查看打印

    将上述示例代码添加到 最简单的内核模块 的 hello_init 函数中,编译并执行 insmod hello.ko 安装模块。

    1.dmesg

    执行 dmesg | tail 将会看到如下打印:

    [20120.194934] module init success
    [20120.194935] GetIot: KERN_EMERG
    [20120.194937] GetIot: KERN_ALERT
    [20120.194938] GetIot: KERN_CRIT
    [20120.194939] GetIot: KERN_ERR
    [20120.194940] GetIot: KERN_WARNING
    [20120.194940] GetIot: KERN_NOTICE
    [20120.194940] GetIot: KERN_INFO
    [20120.194941] GetIot: KERN_DEBUG
    

    2./proc/kmsg

    也可以执行 cat /proc/kmsg 等待内核打印:

    $ sudo cat /proc/kmsg 
    <6>[20120.194934] module init success
    <0>[20120.194935] GetIot: KERN_EMERG
    <1>[20120.194937] GetIot: KERN_ALERT
    <2>[20120.194938] GetIot: KERN_CRIT
    <3>[20120.194939] GetIot: KERN_ERR
    <4>[20120.194940] GetIot: KERN_WARNING
    <5>[20120.194940] GetIot: KERN_NOTICE
    <6>[20120.194940] GetIot: KERN_INFO
    <7>[20120.194941] GetIot: KERN_DEBUG
    

    五、其他常见的用法

    1.pr_xx 用法

    在 Linux 内核中除了直接使用 printk 加消息级别的方式,在 <linux/printk.h> 中还定义了 pr_notice、pr_info、pr_warn、pr_err 等接口。使用这些 pr_xxx 接口,就可以省去指定消息级别的麻烦。

    #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__)
    
    #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
    #if defined(CONFIG_DYNAMIC_DEBUG)
    #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
    

    如上各 pr_xx 定义,都是对 printk + 级别的封装,故都能和 prink 一样在 Linux 内核中直接使用,但是对于 pr_devel() 需要在定义了 DEBUG 宏,pr_debug() 需要在定义了 DEBUGCONFIG_DYNAMIC_DEBUG 宏才有实意。

    2.dev_xxx 用法

    对于 Linux 驱动程序,在 <linux/dev_printk.h> 里也提供了一些驱动模型诊断宏,例如 dev_errdev_warndev_info 等等。使用它们,不仅可以按标记的消息级别打印,还会打印对应的设备和驱动信息,这对于驱动调试来说相当重要。

    #define dev_emerg(dev, fmt, ...) \
    	dev_printk_index_wrap(_dev_emerg, KERN_EMERG, dev, dev_fmt(fmt), ##__VA_ARGS__)
    #define dev_crit(dev, fmt, ...) \
    	dev_printk_index_wrap(_dev_crit, KERN_CRIT, dev, dev_fmt(fmt), ##__VA_ARGS__)
    #define dev_alert(dev, fmt, ...) \
    	dev_printk_index_wrap(_dev_alert, KERN_ALERT, dev, dev_fmt(fmt), ##__VA_ARGS__)
    #define dev_err(dev, fmt, ...) \
    	dev_printk_index_wrap(_dev_err, KERN_ERR, dev, dev_fmt(fmt), ##__VA_ARGS__)
    #define dev_warn(dev, fmt, ...) \
    	dev_printk_index_wrap(_dev_warn, KERN_WARNING, dev, dev_fmt(fmt), ##__VA_ARGS__)
    #define dev_notice(dev, fmt, ...) \
    	dev_printk_index_wrap(_dev_notice, KERN_NOTICE, dev, dev_fmt(fmt), ##__VA_ARGS__)
    #define dev_info(dev, fmt, ...) \
    	dev_printk_index_wrap(_dev_info, KERN_INFO, dev, dev_fmt(fmt), ##__VA_ARGS__)
    
    #if defined(CONFIG_DYNAMIC_DEBUG) || \
    	(defined(CONFIG_DYNAMIC_DEBUG_CORE) && defined(DYNAMIC_DEBUG_MODULE))
    #define dev_dbg(dev, fmt, ...)						\
    	dynamic_dev_dbg(dev, dev_fmt(fmt), ##__VA_ARGS__)
    #elif defined(DEBUG)
    #define dev_dbg(dev, fmt, ...)						\
    	dev_printk(KERN_DEBUG, dev, dev_fmt(fmt), ##__VA_ARGS__)
    #else
    #define dev_dbg(dev, fmt, ...)						\
    ({									\
    	if (0)								\
    		dev_printk(KERN_DEBUG, dev, dev_fmt(fmt), ##__VA_ARGS__); \
    })
    #endif
    

    如上 dev_xx 定义,其和 pr_xx 类似,都可以直接理解为 printk + 级别的封装,一般在 Linux 驱动程序中使用,同样需要注意,dev_dbg() 也不是无条件打印的,除非定义了 DEBUG 或设定了 CONFIG_DYNAMIC_DEBUG。一个相关约定是在已经开启了 DEBUG 时,使用 VERBOSE_DEBUG 来添加 dev_vdbg()。

    补充:
    menuconfig 中开启动态调试:

    Kernel hacking  --->
        printk and dmesg options  --->
            [*] Enable dynamic printk() support
    

    目前在 kernel 驱动代码中,都不再建议直接使用 printk 直接添加打印信息,而是使用 dev_info、dev_dbg、dev_err 之类的函数代替,虽然这些 dev_xxx 函数的本质还是使用 printk 打印的,但是相比起 printk,dev_xxx 的好处是:

    • 支持打印模块信息、dev 信息;
    • 支持动态调试(dynamic debug)方式。

    3.动态打印调试方法

    打开内核动态调试开关,make menuconfig 选中 CONFIG_DYNAMIC_DEBUG 以及 CONFIG_DEBUG_FS。Linux 启动后,使用命令行挂载上 dbgfs。

    mkdir /mnt/dbg
    mount -t debugfs none /mnt/dbg
    

    使用下面方式控制你想输出 dev_dbg() 信息

    • 控制某个文件所有 dev_dbg()
    echo -n "file xxx.c +p" > /mnt/dbg/dynamic_debug/control
    
    • 控制某个函数所有 dev_dbg()
    echo -n "func xxx +p" > /mnt/dbg/dynamic_debug/control
    

    运行程序,使用 dmesg 则可以看到相应 dev_dbg() 的输出信息。当调试结束,不再想输出 dev_dbg() 信息了,使用下面命令关闭即可。

    echo -n "file xxx.c -p" > /mnt/dbg/dynamic_debug/control
    echo -n "func xxx -p" > /mnt/dbg/dynamic_debug/control
    

    动态打印调试的原理是,当编译选项 CONFIG_DYNAMIC_DEBUG 打开的时候,在编译阶段,kernel 会把所有使用 dev_dbg() 的信息记录在一个 table 中,这些信息我们可以从 /mnt/dbg/dynamic_debug/control 解析出来。

    • 开发版本,打开 CONFIG_DYNAMIC_DEBUGCONFIG_DEBUG_FS,配合 dbgfs 动态观测和调试内核代码;
    • 正式版本,关闭 CONFIG_DYNAMIC_DEBUGCONFIG_DEBUG_FS,所有 dbgfs 以及 dev_dbg 信息都从编译阶段自动移除。

    参考链接

    展开全文
  • 在Linux内核中没有printf函数,那么内核是怎么打印调试信息的呢,这里我们用到的是printk函数,在内核中想要向控制台输出或者显示一些内容,必须需要printk函数,这个函数。不同之处在于, printk可以根据日志级别对消息...
  • 这段时间复习了一下内核调试系统,注意看了一下printk的实现以及内核日志的相关知识,这里做一下总结。 一、printk概述 对于做Linux内核开发的人来说,printk实在是再熟悉不过了。内核启动时显示的各种信息...
  • 最简单的就是printk使用了,它的用法和C语言应用程序的printf使用类似,在应用程序依靠的是stdio.h的库,而在linux内核中没有这个库,所以在linux内核中使用这个printk就要对内核的实现有一定的了解。...
  • linux内核printk使用方法
  • 内核打印信息——printk()

    千次阅读 2021-07-09 17:52:10
    在Linux,内核打印语句printk()会将内核信息输出到内核信息缓冲区,内核缓冲区是在 kernel/printk.c通过如下语句静态定义的: static char __log_buf[__LOG_BUF_LEN] __aligned(LOG_ALIGN); 内核信息缓冲区是一...
  • 1.linux 内核打印函数printk一、函数有头文件二、定义的关键宏三、函数原型合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容...
  • 内核printk打印等级

    千次阅读 2021-05-18 16:18:14
    为了确认内核打印等级以及prink 参数对打印的分级,在led驱动初始化代码【以及exit出口】加入如下代码。每次insmod 、rmmod led模块时,根据打印等级的设置,得到不同的打印结果:static int __init s3c24xx_leds_...
  • 打开内核源文件 注释掉call_consol_driver 该函数的的con->write()部分。 接下来来解决,uboot的打印信息(待更新)
  • 这段时间复习了一下内核调试系统,注意看了一下printk的实现以及内核日志的相关知识,这里做一下总结。 1、问题的引出: 做DPDK项目时,调试rte_kni.ko时,发现printk并不会向我们想想的那样把log信息显示在我们的...
  • 内核打印函数printk

    千次阅读 2017-09-12 15:51:05
    printk函数以及内核打印级别介绍
  • linux内核printk调试

    2021-05-15 12:13:20
    不过用于内核的东西总该有些特色,printk添加了一些日志级别(loglevel),具体日志级别定义的宏在。(printk的格式:printk(KERN_ALERT"The process is \"%s\"(pid%i)\n",current->comm,current->pid)) ...
  • 修改内核printk函数打印等级

    千次阅读 2021-12-05 20:36:22
    于是内核有了打印优先级的机制,在用printk()打印信息时需要设置优先级,如果不设置优先级也会有一个默认的优先级。只有打印优先级高于控制台输出的优先级时打印信息才会被打印出来,于是我们可以通过修改控制台输出...
  • linux 内核 printk 使用

    2022-01-02 19:21:48
    Linux内核printk
  • 通常,在调试linux驱动时,我们常用到printk函数来输出一些关键信息,来作为调试手段。但不知道大家有没有想过,内核中printk是如何打印到我们的串口控制台的呢?
  •  这段时间复习了一下内核调试系统,注意看了一下printk的实现以及内核日志的相关知识,这里做一下总结。 一、printk概述  对于做Linux内核开发的人来说,printk实在是再熟悉不过了。内核启动时显示...
  • 这里写自定义目录标题欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、...
  • 内核使用printk打印,应用层调用C库的printf打印。在内核层是调用不了文件系统C库的printf只能用printk。  两者之间的一个显著区别在于printk允许通过指定一个标志来设置优先级(在include/linux/kern_levels.h...
  • 内核打印调试printk学习笔记

    千次阅读 2020-10-26 15:14:57
    内核打印调试printk学习笔记Printk打印格式与打印等级打印数据打印等级日志级别(loglevel)修改控制台打印等级控制台、终端和串口之间的关系终端(terminal)与控制台(console)控制台与串口嵌入式平台下的console查看和...
  • linux内核中printk的打印级别

    万次阅读 2018-07-31 13:46:28
    内核中预定义的内核log等级 // include/linux/kern_levels.h #define KERN_SOH "\001" /* ASCII Start Of Header */ #define KERN_SOH_ASCII '\001' #define KERN_EMERG KERN_SOH "0" /* ...
  • 根据内核文档整理而成,具体格式含义可查看内核文档,或点击如何获得正确的printk格式占位符(v5.15)或如何获得正确的printk格式占位符(latest)查看。 linux-5.15相关内核文档路径如下: Documentation/core-api/...
  • 内核打印printk优先级

    2021-05-11 15:11:42
    修改 /proc/sys/kernel/printk(系统起来后才能设置) cat /proc/sys/kernel/printk 7 1 4 7 #关注第一个数字7即可,它就是默认的输出级别,只要是小于7的printk信息都可以输出 echo 8 > /proc/sys/kernel/printk #...
  • 一直都知道内核printk分级机制,但是没有去了解过,前段时间和一个同事聊到开机启动打印太多,只需要设置一下等级即可;另外今天看驱动源码,也看到类似于Printk(KERN_ERR “…”)的打印信息,以前用都是直接printk...
  • linux 内核打印函数 printk 用法

    千次阅读 2019-10-22 10:57:17
    printk在内核源码用来记录日志信息的函数,只能在内核源码范围内使用。用法和printf非常相似 printk函数主要做两件事情:第一件就是将信息记录到log,而第二件事就是调用控制台驱动来将信息输出。 1.日志...
  • 如果你有了解过Linux内核,那么你应该对printk函数有了一定的了解,那么对于没接触过printk函数的朋友来说,printk()究竟要如何使用呢?下面小编通过一个例子来讲解printk()的使用,以便大家有更深入的了解。实例:...
  • linux内核printk %p 地址打印问题

    千次阅读 2021-06-01 14:35:20
    在linux内核中,直接使用%p打印出的地址时经过哈希运算的,为了防止直接暴露内核地址为攻击者提供了有关内核布局的敏感信息。 要打印内核的虚拟地址,可以使用 %pK。 详细讲解请参考: linux printk ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 55,071
精华内容 22,028
热门标签
关键字:

内核中使用printk