精华内容
下载资源
问答
  • linux 内核 printk 使用

    2015-03-30 11:08:00
    在linux 中,内核打印语句 printk() 会将内核信息输出到内核信息缓冲区中。内核信息缓冲区是一个环形 缓冲区(ring buffer),因此,如果插入的信息过多,...第7级是调试级,在内核中 include/linux/printk.h 中的...

    在linux 中,内核打印语句 printk() 会将内核信息输出到内核信息缓冲区中。内核信息缓冲区是一个环形

    缓冲区(ring buffer),因此,如果插入的信息过多,就会将之前的信息冲刷掉。

     

    printk() 定义了8个消息级别,分为级别0 ~ 7,级别越低(数值越大)的消息越不重要,第0级是紧急事件,

    第7级是调试级,在内核中 include/linux/printk.h 中的定义如下:

    #define KERN_EMERG    "<0>"    /* system is unusable            */
    #define KERN_ALERT    "<1>"    /* action must be taken immediately    */
    #define KERN_CRIT    "<2>"    /* critical conditions            */
    #define KERN_ERR    "<3>"    /* error conditions            */
    #define KERN_WARNING    "<4>"    /* warning conditions            */
    #define KERN_NOTICE    "<5>"    /* normal but significant condition    */
    #define KERN_INFO    "<6>"    /* informational            */
    #define KERN_DEBUG    "<7>"    /* debug-level messages    */

    0级,代表紧急事件,一般是系统崩溃之前提示的消息

    1级,必须立即采取行动

    2级,临界状态,通常涉及严重的硬件或软件操作失败

    3级,用于报告错误状态,设备驱动程序会经常使用KERN_ERR 报告来自硬件的问题

    4级,对可能出现问题的情况进行警告,这类情况通常不会对系统造成严重问题

    5级,有必要进行提示的正常情况,许多与安全相关的状况用这个级别进行提示

    6级,内核提示性信息,很多驱动程序在启动的时候用这个级别打印出它们找到的硬件信息

    7级,用于调试信息

     

    调试时,通常使用封装了 printk 的更高级的宏,其中可替代 printk 的宏如下:

    #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

     

    在打印信息时,如果要打印所出其所在函数,可以使用 __FUNCTION__, 如下示:

    printk("%s: Incorrect IRQ %d from %s\n", __FUNCTION, irq, devname);

     

    转载于:https://www.cnblogs.com/aqing1987/p/4377470.html

    展开全文
  • 这段时间复习了一下内核调试系统,注意看了一下printk的实现以及内核日志的相关知识,这里做一下总结。 一、printk概述 对于做Linux内核开发的人来说,printk实在是再熟悉不过了。内核启动时显示的各种信息...
    这段时间复习了一下内核调试系统,注意看了一下printk的实现以及内核日志的相关知识,这里做一下总结。
     
    一、printk概述
     
        对于做Linux内核开发的人来说,printk实在是再熟悉不过了。内核启动时显示的各种信息大部分都是通过她来实现的,在做内核驱动调试的时候大部分时候使用她就足矣。她之所以用得如此广泛,一个是由于她使用方便,还有一个重要的原因是她的健壮性。它使用范围很广,几乎是内核的任何地方都能调用它。你既可以在中断上下文、进程上下中调用她,也可以在任何持有锁时调用她,更可以在SMP系统中调用她,且调用时连锁都不必使用。这样好的适应性来源于她的设计,一个由三个指针控制的简单“ring buffer”。

       注意上面说到的是:“几乎”在内核的任何地方都可以使用。那什么地方使用会有“问题”?那就是在系统启动过程的早期,终端初始化之前的某些地方虽然可以使用,但是在终端和控制台被初始化之前所有信息都被缓存在printk的简单的ring buffer(环形缓冲区)中,直到终端和控制台被初始化之后,所有缓存信息都被一并输出。
     
         如果你要调试的是启动过程最开始的部分(如setup_arch()),可以依靠此时能够工作的硬件设备(如串口)与外界通信,使用printk()的变体early_printk()函数。她在启动过程初期就具有在终端上打印的能力,功能与prink()类似,区别在于:
    (1)函数名
    (2)能够更早地工作(输出信息)
    (3)她有自己的小缓存(一般为512B)
    (4)一次性输出到硬件设备,不再以ring buffer的形式保留信息。
          但该函数在一些构架上无法实现,所以这种办法缺少可移植性。(大多数构架都可以,包括x86和arm)。
     
         所以,除非要在启动初期在终端上输出,否则我们认为printk()在任何情况下都能工作。这点从内核的启动代码中就可以看出,在已进入start_kernel不久就通过printk打印内核版本信息了: printk(KERN_NOTICE "%s", linux_banner);
     
    二、printk的使用
     
       printk()和C库中的printf()在使用上最主要的区别就是 printk()指定了日志级别。
     
    (1)日志等级
    内核根据日志级别来判断是否在终端(console)上打印消息:内核把级别比某个特定值低的所有消息显示在终端(console)上。但是所有信息都会记录在printk的“ring buffer”中。
     
      printk有8个loglevel,定义在中:
    #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>" /* 调试级别的信息 */
    
    /* 使用默认内核日志级别 */
    #define KERN_DEFAULT ""
    /*
    * 标注为一个“连续”的日志打印输出行(只能用于一个
    * 没有用 \n封闭的行之后). 只能用于启动初期的 core/arch 代码
    * (否则续行是非SMP的安全).
    */
    #define KERN_CONT ""
     如果使用时没有指定日志等级,内核会选用DEFAULT_MESSAGE_LOGLEVEL,这个定义位于kernel/printk.c:
    /* printk's without a loglevel use this.. */
    #define DEFAULT_MESSAGE_LOGLEVEL CONFIG_DEFAULT_MESSAGE_LOGLEVEL
      可以看出,这个等级是可以在内核配置时指定,这种机制是从2.6.39开始有的,如果你不去特别配置,那么默认为<4>,也就是KERN_WARNING。
        内核将最重要的记录等级 KERN_EMERG定为“”,将无关紧要的调试记录等级“KERN_DEBUG”定为“<7>”。
        内核用这些宏指定日志等级和当前终端的记录等级console_loglevel来决定是不是向终端上打印,使用示例如下:
    printk(KERN_EMERG "log_level:%s\n", KERN_EMERG);

     当编译预处理完成之后,前例中的代码实际被编译成成如下格式:

    printk( "<0>" "log_level:%s\n", KERN_EMERG);
     给一个printk()什么日志等级完全取决于你。那些正式、且需要保持的消息应该根据信息的性质给出相应的日志等级。但那些为了解决一个问题临时加得到处都是的调试信息可以有两种做法:
        一种选择是保持终端的默认记录等级不变,给所有调试信息KERN CRIT或更低的等级以保证信息一定会被输出。
        另一种方法则相反,给所有调试信息KERN DEBUG等级,而调整终端的默认记录等级为7,也可以输出所有调试信息。
        两种方法各有利弊。
     
        这里说到了调整内核的默认的日志级别,在我3年半前的学习笔记《 Linux设备驱动程序学习(2)-调试技术 》中有介绍,可以通过 /proc/sys/kernel/printk来改变,或者C程序调用syslog系统调用来实现。但是现在的glibc的函数接口改了,由于 syslog 这个词使用过于广泛,这个函数的名称被修改成 klogctl,所以原来博文中的代码无法使用了,以下是新版的 console_loglevel代码:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <errno.h>
    //#define __LIBRARY__ /* _syscall3 and friends are only available through this */
    //#include <linux/unistd.h>
    /* define the system call, to override the library function */
    //_syscall3(int, syslog, int, type, char *, bufp, int, len);
    
    int main(int argc, char **argv)
    {
          int level;
          if (argc == 2) {
                level = atoi(argv[1]); /* the chosen console */
          } else {
                fprintf(stderr, "%s: need a single arg\n", argv[0]);
                exit(1);
          }
          if (klogctl(8, NULL, level) < 0) {
                fprintf(stderr, "%s: syslog(setlevel): %s\n",
                      argv[0], strerror(errno));
                exit(1);
          }
          exit(0);
    }
    (2)相关辅助宏
        如果确定printk所需要的日志等级,每次都要在其中添加以上宏,似乎有点麻烦了。所以内核黑客们定义了一些宏来方便printk的使用,这些宏在内核代码中也是随处可见:
    #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__)
    
    /* 除非定义了DEBUG ,否则pr_devel()不产生任何代码 */
    #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
    
    /* 如果你在写一个驱动,请使用dev_dbg */
    #if defined(DEBUG)
    #define pr_debug(fmt, ...) \
         printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
    #elif 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__)
    #else
    #define pr_debug(fmt, ...) \
         no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
    #endif
      从上面的代码大家应该就可以知道这些宏的使用了。值得注意的是:pr_devel和 pr_debug这些宏只有在定义了DEBUG之后才会产生实际的printk代码,这样方便了内核开发:在代码中使用这些宏,当调试结束,只要简单地#undef DEBUG就可以消除这些调试使用的代码,无需真正地去删除调试输出代码。
     
    (3)输出速率控制

       在调试的时候,有时某些部分可能printk会产生大量输出, 导致系统无法正常工作,并可能使系统日志ring buffer溢出(旧的信息被快速覆盖)。特别地,当使用一个慢速控制台设备(如串口), 过量输出也能拖慢系统。这样反而难于发现系统出问题的地方。所以你应当非常注意:正常操作时不应当打印任何东西,打印的输出应当是指示需要注意的异常,并小心不要做过头。

       在某些情况下, 最好的做法是设置一个标志变量表示:已经打印过这个了,以后不再打印任何这个信息。而对于打印速率的控制内核已经提供了一个现成的宏:
    #define printk_ratelimit() __printk_ratelimit(__func__)

    这个函数应当在你认为打印一个可能会出现大量重复的消息之前调用,如果这个函数返回非零值, 继续打印你的消息, 否则跳过它。典型的调用如这样:

    if (printk_ratelimit())
        printk(KERN_NOTICE "The printer is still on fire\n");
    printk_ratelimit通过跟踪发向控制台的消息的数量和时间来工作。当输出超过一个限度, printk_ratelimit 开始返回 0 使消息被丢弃。我们可以通过修改 :
     
    1. /proc/sys/kern/printk_ratelimit( 可以看作一个监测周期,在这个周期内只能发出下面的控制量的信息) 
    2. /proc/sys/kernel/printk_ratelimit_burst(以上周期内的最大消息数,如果超过了printk_ratelimit()返回0)
    来控制消息的输出.
       在中还定义了其他的宏,比如printk_ratelimited(fmt, ...)等,有兴趣的朋友就去文件中看看便知,很好理解的。
     
     
    (4)最后特别提醒:
    1、虽然printk很健壮,但是看了源码你就知道,这个函数的效率很低:做字符拷贝时一次只拷贝一个字节,且去调用console输出可能还产生中断。所以如果你的驱动在功能调试完成以后做性能测试或者发布的时候千万记得尽量减少printk输出,做到仅在出错时输出少量信息。否则往console输出无用信息影响性能。我刚开始学驱动的时候就犯过这样的白痴错误,在测试CAN驱动性能的时候居然printk出信息来核对,结果直接宕机。
    2、printk的临时缓存printk_buf只有1K,所有一次printk函数只能记录<1K的信息到log buffer,并且printk使用的“ring buffer”
     
     
    三、printk的内核实现
     
        对于Linux的printk内核日志,常常被称为kernel ring buffer,这是由于printk的缓存实现就是使用了一个简单的ring buffer(环形缓冲区)。但是这里需要注意的是,不要和内核trace系统ring buffer混淆,虽然他们都是为了跟踪调试,但是trace系统的ring buffer实现更加完善复杂,而printk使用的ring buffer则非常简单,其实就定义了一个字符数组:
    static char __log_buf[__LOG_BUF_LEN];

    并使用了一套指针来管理:

    /*
     * 在指向log_buf时并没有用log_buf_len做限制 - 所以他们
     * 在作为下标使用前必须用掩码处理(去除CONFIG_LOG_BUF_SHIFT以上的高位)
     */
     static unsigned log_start; /* log_buf中的索引: 指向由syslog()读取的下一个字符 */
     static unsigned con_start; /* log_buf中的索引: 指向发送到console的下一个字符 */
     static unsigned log_end; /* log_buf中的索引:最近写入的字符地址 + 1 */
     具体的实现CU中已经有一位博友写过了,我这里就不再啰嗦了,我转载备份了一下:《printk实现分析》
     
    四、用户空间访问内核日志
     
        用户空间访问和控制内核日志有两个接口:
       (1)通过glibc的klogctl函数接口调用内核的syslog系统调用
       (2)通过fs/proc/kmsg.c内核模块中导出的procfs接口:/proc/kmsg文件。
        他们其实最终都调用了/kernel/printk.c中的do_syslog函数,实现对__log_buf的访问及相关变量的修改。
        但值得注意的是:从/proc/kmsg中获取数据,那么__log_buf中被读取过的数据就不再保留(也就是会修改log_start指针), 然而 syslog 系统调用返回日志数据并保留数据给其他进程。读取/proc文件是 klogd的默认做法。dmesg命令可用来查看缓存的内容并保留它,其实它是将__log_buf中的所有内容返回给stdout,并不管它是否已经被读取过。
     
        这里我还是推荐大家 RTFSC – Read The Fucking Source Code,自己看这些代码比什么都强,我这里就只引个路。
     
        在用户空间有专门用于记录系统日志的程序,统称为“syslog守护进程”。早期及现在的大部分嵌入式系统使用的是klogd+syslogd组合,现在大多数发行版都使用rsyslogd或者syslogd-ng了。这些用户空间的程序我这里就不分析了,我不擅长,运维的可能比较清楚。我只知道一下他们大致的调用关系就好。
     
        这里我用一张图来总结一下内核printk和日志系统的总体结构:

     

    极力推荐阅读:《内核日志:API 及实现----从内核到用户空间的日志》

     

     

     

     

     

     

     

     

     

    展开全文
  • 分析Linux内核启动流程时可以知道,在调用setup_arch函数之前就已经调用过printk函数了,但是这个时候的printk函数只是将打印信息放在缓存区,并没有打印到控制台上,因为这个时候控制台还没有被初始化。...

          分析Linux内核启动流程时可以知道,在调用setup_arch函数之前就已经调用过printk函数了,但是这个时候的printk函数只是将打印信息放在缓存区中,并没有打印到控制台上,因为这个时候控制台还没有被初始化。

          只有在start_kernel函数中的console_init函数被调用后,控制台才会被注册、初始化,printk函数打印的内容才会被真正地输出到屏幕上。如果想在console_init函数之前打印信息,需要调用early_printk函数。

     

    1. 内核配置

    (1)Kernel hacking  ---> Kernel low-level debugging functions -->   Early printk 

    (2)boot option中需要添加 earlyprintk项。

    类似于:earlyprintk=ttyS0,115200 loglevel=9 initcall_debug=1 console=ttyS0,115200 ramfs

     

    2. 使用

    在需要打印调试信息的地方调用此函数

    early_printk("------------xxx------------\n");

     

    3. A33开发板

    如在./arch/arm/mach-sunxi/sun8i.c 中有如下语句:

    early_printk("[%s]: From boot, get meminfo:\n", __func__);

    启动开发板时串口控制台信息如下:

    在没有启用early_printk之前,串口控制台信息如下:

     

    4. 对early printk的驱动实现的分析

    arch/arm/kernel/early_printk.c文件,上代码:

    1. extern void printch(int);
    2.  
    3. static void early_write(const char *s, unsigned n)
    4. {
    5.         while (n-- > 0) {
    6.                 if (*s == '\n')
    7.                         printch('\r');
    8.                 printch(*s);
    9.                 s++;
    10.         }
    11. }
    12.  
    13. static void early_console_write(struct console *con, const char *s, unsigned n)
    14. {
    15.         early_write(s, n);
    16. }
    17.  
    18. static struct console early_console = {
    19.         .name =                "earlycon",
    20.         .write =        early_console_write,
    21.         .flags =        CON_PRINTBUFFER | CON_BOOT,
    22.         .index =        -1,
    23. };
    24.  
    25. asmlinkage void early_printk(const char *fmt, ...)
    26. {
    27.         char buf[512];
    28.         int n;
    29.         va_list ap;
    30.  
    31.         va_start(ap, fmt);
    32.         n = vscnprintf(buf, sizeof(buf), fmt, ap);
    33.         early_write(buf, n);
    34.         va_end(ap);
    35. }
    36.  
    37. static int __init setup_early_printk(char *buf)
    38. {
    39.         register_console(&early_console);
    40.         return 0;
    41. }
    42.  
    43. early_param("earlyprintk", setup_early_printk);

    其实这段code最终的实现都是靠:extern void printch(int);这个函数。这个函数实现是在:arch/arm/kernel/debug.S中:

    1. ENTRY(printch)
    2.                 addruart_current r3, r1, r2
    3.                 mov        r1, r0
    4.                 mov        r0, #0
    5.                 b        1b
    6.  
    7. ENDPROC(printch)
    8.                 .macro        addruart_current, rx, tmp1, tmp2
    9.                 addruart        \tmp1, \tmp2
    10.                 mrc                p15, 0, \rx, c1, c0
    11.                 tst                \rx, #1
    12.                 moveq                \rx, \tmp1
    13.                 movne                \rx, \tmp2
    14.                 .endm

    printch会调用到 addruart_current函数,而addruart_current函数用调用到:addruart函数,该函数实现是在:arch\arm\mach-s3c64xx\include\mach中的debug-macro.S汇编文件中:

    1.         .macro addruart, rp, rv
    2.                 ldr        \rp, = S3C_PA_UART
    3.                 ldr        \rv, = (S3C_VA_UART + S3C_PA_UART & 0xfffff)
    4. #if CONFIG_DEBUG_S3C_UART != 0
    5.                 add        \rp, \rp, #(0x400 * CONFIG_DEBUG_S3C_UART)
    6.                 add        \rv, \rv, #(0x400 * CONFIG_DEBUG_S3C_UART)
    7. #endif
    8.         .endm

     

     

    我们从上面的代码可以看到S3C_PA_UART, S3C_PA_UART都是实际的6410的串口寄存器物理和虚拟地址,从而进行真正的硬件底层操作。

     

    展开全文
  • printk在内核源码用来记录日志信息的函数,只能在内核源码范围内使用。用法和printf非常相似 printk函数主要做两件事情:第一件就是将信息记录到log,而第二件事就是调用控制台驱动来将信息输出。 1.日志...

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

    printk函数主要做两件事情:第一件就是将信息记录到log中,而第二件事就是调用控制台驱动来将信息输出。

     

    1.日志级别

    printk相比printf来说还多了个:日志级别的设置,用来控制printk打印的这条信息是否在终端上显示的当日志级别的数值小于控制台级别时,printk要打印的信息才会在控制台打印出来,否则不会显示在控制台!

    在我们内核中一共有8种级别,他们分别为

    #define KERN_EMERG "<0>" /* system is unusable */
    #define KERN_ALERT "<1>" /* action must be taken immediately */
    #define KERN_CRIT "<2>" /* critical conditions */
    #define KERN_ERR "<3>" /* error conditions */
    #define KERN_WARNING "<4>" /* warning conditions */
    #define KERN_NOTICE "<5>" /* normal but significant condition */
    #define KERN_INFO "<6>" /* informational */
    #define KERN_DEBUG "<7>" /* debug-level messages */
    

     

    2.控制台级别

    #define MINIMUM_CONSOLE_LOGLEVEL  1   /*可以使用的最小日志级别*/
    #define DEFAULT_CONSOLE_LOGLEVEL  7 /*比KERN_DEBUG 更重要的消息都被打印*/
    #define DEFAULT_MESSAGE_LOGLEVEL 4 /* KERN_WARNING */
    
    int console_printk[4] = {
        DEFAULT_CONSOLE_LOGLEVEL,/*控制台日志级别,优先级高于该值的消息将在控制台显示*/
        /*默认消息日志级别,printk没定义优先级时,打印这个优先级以上的消息*/
        DEFAULT_MESSAGE_LOGLEVEL,
    
        /*最小控制台日志级别,控制台日志级别可被设置的最小值(最高优先级)*/
        MINIMUM_CONSOLE_LOGLEVEL,
        DEFAULT_CONSOLE_LOGLEVEL,/* 默认的控制台日志级别*/
    };
    

    在进行查看的时候,可以使用命令 cat /proc/sys/kernel/printk来查看这四个值

     

    3.printk函数使用

    在使用printk时我们会将日志级别放到最开始的位置,如

    printk(KERN_EMERG "%s", "EMERG\n");

    我们没有设置日志级别时,会为他设一个默认的日志级别:default_message_loglevel。

    当 printk() 中的消息日志级别小于当前控制台日志级别(console_printk[0])时,printk 的信息就会在控制台上显示。

    但无论当前控制台日志级别是何值,即使没有在控制台打印出来,可以通过两种方法查看日志:

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

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

     

    4.日志级别的设置

    printk可以根据设置的日志级别来确定这个语句最后是否能够打印出来。例如我们知道我们默认的控制台级别为4,如何才能更改这个控制台级别呢?

     

    方法1:修改内核源码

    我们可以将default_message_loglevel设为我们想设的值,然后重新编译内核,烧写内核即可。不过不建议直接修改内核源码,因为容易出问题。

     

    方法2:

    在uboot的bootargs中加入“loglevel=X”的语句,而其他的语句不变。其中X就是我们想要设置的console_loglevel的值。他的实现原理其实跟设置“console=ttySAC0”一样。通过__setup来设置console_loglevel:

    __setup("loglevel=", loglevel);

    具体代码我就不分析了。而同时我们会发现还有两个__setup的设置,他们的代码为:

    __setup("debug", debug_kernel);
    __setup("quiet", quiet_kernel);

    而他们的功能我们通过他们相应的函数设置函数可以知道就是分别将console_loglevel设为10和4 。他们的代码说明为:

    static int __init debug_kernel(char *str)
    {
        if (*str)
            return 0;
        console_loglevel = 10;
        return 1;
    }
     
    static int __init quiet_kernel(char *str)
    {
        if (*str)
            return 0;
        console_loglevel = 4;
        return 1;
    }

     

    方法3:修改/proc/sys/kernel/printk文件

    将要设置的值写入到/proc/sys/kernel/printk中。我们要先cat /proc/sys/kernel/printk来看一下这个文件中都有什么值。然后我们再写入。其中这里的格式为:控制台的日志级别、默认消息日志级别、最小控制台日志级别和默认控制台日志级别。而我们要设置的就是第一个控制台的日志级别。我们通过echo “W   X    Y    Z” > /proc/sys/kernel/printk 将我们想要设置的四个值写入到/proc/sys/kernel/printk中。
    但是这种方法要在成功开启内核后才可以使用。

     

    展开全文
  • printk函数  We used the printk function in earlier chapters with the simplifying assumption that it works like printf. Now it's time to introduce some of... 我们在前面章节
  • printk函数Weusedtheprintkfunctioninearlierchapterswiththesimplifyingassumptionthatitworkslikeprintf....我们在前面章节简单地把printk当作printf函数来使用。现在是时候来介绍它的一些不同之处了。Oneofthed...
  • 内核编程只能使用printk而不能使用printf,那我们如何才能查看到我们用printk输出的信息呢? 答案就是在shell中使用dmesg指令!!
  •  在内核调试技术之中,简单的是printk使用了,它的用法和C语言应用程序中的printf使用类似,在应用程序中依靠的是stdio.h中的库,而在linux内核中没有这个库,所以在linux内核中使用这个printk要对内核的实现...
  • 内核中打印函数的使用  printk(打印级别 “格式化输出”,...);  printk(“格式化输出”,...);  打印级别:   #define KERN_EMERG "&lt;0&gt;" /* system is unusable */  #define KERN...
  • Linux内核中printk与日志级别

    万次阅读 2010-04-02 15:13:00
    函数printk使用方法和printf相似,用于内核打印消息。printk根据日志级别(loglevel)对消息进行分类。日志级别用宏定义,日志级别宏展开为一个字符串,在编译时由预处理器将它和消息文本拼接成一个字符串,因此...
  • linux内核调试printk()函数详解

    千次阅读 2012-10-30 14:19:04
    我们在使用printk()函数中使用日志级别为的是使编程人员在编程过程中自定义地进行信息的输出,更加容易地掌握系统当前的状况。 对程序的调试起到了很重要的作用。 (下文中的日志级别和控制台日志控制级别是一个...
  • 参考内核文档: Documentation/printk-...在内核中使用dump_stack的时候可以看到如下用法: static inline void print_ip_sym(unsigned long ip) { printk("[<%px>] %pS\n", (void *) ip, (void *) ip)...
  • linux内核printk调试

    千次阅读 2016-05-05 14:16:52
    函数printk使用方法和printf相似,用于内核打印消息。printk根据日志级别(loglevel)对消息进行分类。 日志级别用宏定义,日志级别宏展开为一个字符串,在编译时由预处理器将它和消息文本拼接成一个字符串,因此...
  • Linux内核printk宏开关

    2019-08-16 17:17:10
    在内核开发时经常使用printk打印调试信息,但是printk又对性能有一定的影响,比如写...在内核中可以使用printk宏开关来控制这些信息的显示: #define DEBUG_A #ifdef DEBUG_A #define DEBUG(fmt, args...) printk...
  • 如何在linux程序中使用printk

    千次阅读 2016-09-22 19:23:09
    From: http://blog.csdn.net/zhenwenxian/article/details/4336211要将linux内核的带级别控制的printk内容打印出来,在命令行 输入 dmesg -n 8 就将所有级别的信息都打印出来Linux命令:dmesg 功能说明:显示开机...
  • 内核中的信息输出使用printk进行输出,在进行调试时比较方便,但级别设置总是忘记,故在此记录下printk的相关内容,方便以后查看。 八个级别 printk 和 printf 在用法上的区别在于 printk 可以通过附加不同的日志...
  • Linux内核调试printk()总结

    千次阅读 2014-10-30 11:27:11
    我们在使用printk()函数中使用日志级别为的是使编程人员在编程过程中自定义地进行信息的输出,更加容易地掌握系统当前的状况。 对程序的调试起到了很重要的作用。 (下文中的日志级别和控制台日志控制级别是一个...
  • printk()函数

    2014-04-29 23:32:25
    在Linux内核中使用printk()函数输出
  • 使用printk的注意点

    千次阅读 2016-09-20 14:26:48
    内核开发使用printk十分常见,但是也要注意,一次队友在开发,想要打印一个大缓冲区的数据,就用printk打印,但是只能打印前约1K的数据,后来发现printk的实现,临时缓冲区确实有LOG_LINE_MAX限制,现在简单...
  • 我们在使用printk()函数中使用日志级别为的是使编程人员在编程过程中自定义地进行信息的输出,更加容易地掌握系统当前的状况。对程序的调试起到了很重要的作用。 控制台级别 在内核代码include/linux/kernel.h中,...
  • 1、内核中打印信息,只能使用printk,不能使用printf。 函数原型: int printk(const char *fmt, ...); 2、printk打印等级 #define KERN_EMERG “&amp;amp;amp;lt;0&amp;amp;amp;gt;” /* system is ...
  • printk内核打印函数

    2019-04-01 20:15:47
    出现这种差异是因为tty_write函数需要使用fs指向的被显示的字符串,而fs是专门用于存放用户态段选择符的,因此,在内核态时,为了配合tty_write函数,printk会把fs修改为内核态数据段选择符ds的值,这样才能正确...
  • 我们在使用printk()函数中使用日志级别为的是使编程人员在编程过程中自定义地进行信息的输出,更加容易地掌握系统当前的状况。 对程序的调试起到了很重要的作用。 (下文中的日志级别和控制台日志控制级别是一个...
  • LINUX 是 C 语言写的,但不能使用 printf 来打印,原因很容易解释,内核中不认识库 文件中的 printf 函数。 最普通的调试技术是监视,即在应用程序中的适当地方调用 printf 显示监视信息,这 是针对普通应用程序而言,...
  • printk信息的输出去向这是在内核的命令行参数console=ttyXXX里指定死了,比如console=tty1表示printk的信息输出到终端1。如果是这种情况,你需要使用Ctrl+Alt+(F1-F6)来切换终端。日志输出级别过低用pr
  • 用函数printk打印内核信息的方法

    千次阅读 2014-02-27 13:30:37
    Linux内核用函数printk打印调试信息,该函数的用法与C库打印函数printf格式类似,但在内核使用。用户可在内核代码的某位置加入函数printk,直接把所关心的信息打打印到屏幕上或日志文件。 函数printk根据日志...

空空如也

空空如也

1 2 3 4 5 ... 18
收藏数 343
精华内容 137
关键字:

内核中使用printk