首頁 > 系統教程 > Linux > 主體

Linux核心中的偵錯輸出函數:printk詳解

PHPz
發布: 2024-02-14 20:33:14
轉載
1255 人瀏覽過

printk是Linux核心中最常用的偵錯函數之一,它用來向內核緩衝區或控制台輸出偵錯訊息,如變數的值,函數的執行流程,錯誤的原因等。 printk的優點是簡單易用,不需要額外的設備或驅動。 printk的實作涉及到核心緩衝區,日誌等級,格式化字串等概念。在本文中,我們將介紹Linux核心調試技術之printk的原理和方法,並舉例說明它們的使用方法和注意事項。

Linux核心中的偵錯輸出函數:printk詳解

#1、簡介(基於s3c2440 linux)

在內核偵錯技術之中,最簡單的就是printk的使用了,它的用法和C語言應用程式中的printf使用類似,在應用程式中依賴的是stdio.h中的函式庫,而在linux核心中沒有這個函式庫,所以在linux核心中,使用這個printk就要對核心的實作有一定的了解。

printf和printk的差別:printk會在開頭處加上””樣式的字符,N的範圍是0~7,表示這個資訊的等級。

當printk(“”…);中的n

在核心檔案中Printk.c (kernel) 初始化這個console_loglevel 的等級為7.

/* printk's without a loglevel use this.. */
#define DEFAULT_MESSAGE_LOGLEVEL 4 /* KERN_WARNING */

/* We show everything that is MORE important than this.. */
#define MINIMUM_CONSOLE_LOGLEVEL 1 /* Minimum loglevel we let people use */
#define DEFAULT_CONSOLE_LOGLEVEL 7 /* anything MORE serious than KERN_DEBUG
 */int console_printk[4] = {
    DEFAULT_CONSOLE_LOGLEVEL,    /* console_loglevel */
    DEFAULT_MESSAGE_LOGLEVEL,    /* default_message_loglevel */
    MINIMUM_CONSOLE_LOGLEVEL,    /* minimum_console_loglevel */
    DEFAULT_CONSOLE_LOGLEVEL,    /* default_console_loglevel */
};
登入後複製

2、透過指令cat /proc/sys/kernel/printk查看等級設定:

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

其中的 7 4 1 7,分別對應與:console_loglevel、default_message_loglevel、minimum_console_loglevel、default_console_loglevel

3、修改等級配置:

#echo “1 4 1 7”>/proc/sys/kernel/printk 改變這四個值,當被console_loglevel設定為1的時候,所有的偵錯資訊都會被印出來。

4、printk函數記錄的名稱及使用

在核心檔案:Kernel.h (include\linux) 定義了0~7這8個等級的名稱

#define   KERN_EMERG   ""    /* system is unusable */
#define    KERN_ALERT    ""  
  /* action must be taken immediately */
#define    KERN_CRIT     ""    /* critical
 conditions */
#define    KERN_ERR      ""    /* error conditions */
#define   
 KERN_WARNING  ""    /* warning conditions */
#define    KERN_NOTICE   ""  
  /* normal but significant condition*/
#define    KERN_INFO     ""   
 /* informational*/
#define    KERN_DEBUG    ""    /* debug-level messages 
*/
#define console_loglevel      (console_printk[0])
#define 
default_message_loglevel (console_printk[1])
#define minimum_console_loglevel 
(console_printk[2])
#define default_console_loglevel (console_printk[3])
登入後複製

使用printk:

① printk(KERN_WARNING"there is a warning here!\n");//注意,中间没有逗号间隔。

② printk(KERN_DEBUG"%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
登入後複製

在①和②中,我們需要查看緩衝區log_buf中的數據,才能看到列印出來的資訊。需要使用指令 #dmesg

#``# dmesg``Linux version 2.6.22.6 (book@book-desktop) (gcc version 3.4.5) #19 Thu
 Dec 8 14:06:03 CST 2016``CPU: ARM920T
 [41129200] revision 0 (ARMv4T), cr=c0007177``Machine: SMDK2440``Memory policy: 
ECC disabled, Data cache writeback``On node 0 totalpages: 16384`` ``DMA zone: 128 
pages used ``for` `memmap`` ``DMA zone: 0 pages reserved`` ``DMA zone: 16256 pages,
 LIFO batch:3`` ``Normal zone: 0 pages used ``for` `memmap``CPU S3C2440A (id 0x32440001)................................
登入後複製

也可以使用 cat /proc/kmsg& 後台運行,即時列印出偵錯資訊。在②中,__FILE__, FUNCTION, __LINE__分別對應的是那個文件,那個函數,第幾行。非常實用。

# cat /proc/kmsg&``# ./firstdrvtest on``/work/LinuxDrives/20.printk_debug/first_drv.c
 first_drv_open 23``/work/LinuxDrives/20.printk_debug/first_drv.c first_drv_open 25``
/work/LinuxDrives/20.printk_debug/first_drv.c first_drv_open 27``# ./firstdrvtest off`
`/work/LinuxDrives/20.printk_debug/first_drv.c first_drv_open 23``/work/LinuxDrives/
20.printk_debug/first_drv.c first_drv_open 25``/work/LinuxDrives/20.printk_debug
/first_drv.c first_drv_open 27
登入後複製

5、串列埠與printk函數的關係:

#
printk
    vprintk
        vscnprintf //先把输出信息放入临时BUFFER
                // Copy the output into log_buf.
                // 把临时BUFFER里的数据稍作处理,再写入log_buf
                // 比如printk("abc")会得到"abc", 再写入log_buf
                // 可以用dmesg命令把log_buf里的数据打印出来重现内核的输出信息

        // 调用硬件的write函数输出
        release_console_sem    
            call_console_drivers
          //从log_buf得到数据,算出打印级别
                _call_console_drivers
                    if ((msg_log_level write //con是console_drivers链表中的项,对用具体的输出函

数 在drives/serial/s3c2410.c中查看

在该函数中注册一个console结构体
static void s3c24xx_serial_console_write(struct console *co, const char *s,
unsigned int count)
{
uart_console_write(cons_uart, s, count, s3c24xx_serial_console_putchar);
}
登入後複製

串口輸出函數,會呼叫s3c24xx_serial_console_putchar函數

static int s3c24xx_serial_initconsole(void)
{
    ...........................
    register_console(&s3c24xx_serial_console);
    return 0;
}
static struct console s3c24xx_serial_console =
{
.name = S3C24XX_SERIAL_NAME,//这个宏被定义为:TTYSAC
.device = uart_console_device, //init进程,用户程序打开/dev/console的时候会调用
.flags = CON_PRINTBUFFER,//打印还没有初始化化console前保存在log_buf里面的数据
.index = -1,//选择那个串口,由uboot中的命令决定
.write = s3c24xx_serial_console_write,//控制台输出函数
.setup = s3c24xx_serial_console_setup //串口设置函数
}; 
登入後複製

這個函數和硬體相關,讀取暫存器,看資料是否被傳送完成,最後將資料一個位元組一個位元組的寫入暫存器,s3c2440的串列控制器會自動把資料送出去

static void s3c24xx_serial_console_putchar(struct uart_port *port, int ch)

{
unsigned int ufcon = rd_regl(cons_uart, S3C2410_UFCON);
while (!s3c24xx_serial_console_txrdy(port, ufcon))
barrier();
wr_regb(cons_uart, S3C2410_UTXH, ch);
}
登入後複製

uboot的console=ttySAC0如果在linux中被辨識出來是串口0的,在/kernel/printk.c中有一下程式碼,

__setup("console=", console_setup);

static int __init console_setup(char *str)
{
........
  add_preferred_console(name, idx, options);
} 
登入後複製

核心開始執行時,會發現「console=…」的命令列參數時候,就會呼叫console_setup函數進行資料解析,對於命令列參數」console=ttySAC0″,會解析出:裝置名稱(name)為ttySAC,索引index為0,這些資訊被保存在類型為console_cmdline、名稱為console_cmdline的全域數組中(注意:數組名稱和數組的類型相同)

在後面的register_console(&s3c24xx_serial_console);的時候,會將s3c24xx_serial_console結構和console_cmdline數組中的設備進行比較。

①解析出來的name為S3C24XX_SERIAL_NAME 既“ttySAC”,而console_cmdline中的指令中的name也為“ttySAC”

②s3c24xx_serial_console結構體中的索引index為-1,表示使用命令列參數「console=ttySAC0」中的索引,index = 0

Through this article, we have learned about the principles and methods of printk, the Linux kernel debugging technology, which can be used to debug and output the kernel. We should choose the appropriate method based on actual needs and follow some basic principles, such as using the correct log level, using the correct format string, using the correct output function, etc. Printk is one of the simplest and most effective debugging functions in the Linux kernel. It can realize feedback and monitoring of the kernel, and can also improve the maintainability and scalability of the kernel. I hope this article can be helpful and inspiring to you.

以上是Linux核心中的偵錯輸出函數:printk詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

來源:lxlinux.net
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!