驅動程式調試方法之printk——printk的原理與直接使用

來源:互聯網
上載者:User

標籤:

1、基本原理(1)在UBOOT裡設定console=ttySAC0或者console=tty1這裡是設定控制終端,tySAC0 表示串口, tty1 表示lcd
(2)核心用printk列印核心就會根據命令列參數來找到對應的硬體操作函數,並將資訊通過對應的硬體終端列印出來!  2、printk的使用 (1)printk函數的資訊如何才能在終端顯示出來在核心代碼include/linux/kernel.h中,定義了控制台的層級:extern int console_printk[];#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]) 我們在到kernel/printk.c裡找到console_printk的定義: /* 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 */ DECLARE_WAIT_QUEUE_HEAD(log_wait); 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 */}; 於是我們知道控制台的層級是:7   4     1     7我們當然可以再這裡修改,但是還有一個更簡單的修改方法,即在使用者空間使用下面的命令: echo “1 4 1 7” > /proc/sys/kernel/printk 將1 4 1 7寫入 /proc/sys/kernel/printk即可! 當我們使用printk函數時往往要加上資訊層級,比如: printk(KERN_WARNING"there is a warning here!\n") 其中KERN_WARNING就表示資訊的層級,相關宏在函數include/linux/kernel.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                 */ 如果沒有指明資訊層級的話,就會採用預設的資訊層級,這個預設的資訊層級我們在上面見到過的,就是:#define default_message_loglevel (console_printk[1])沒有改動的情況下是4 上面我們說到了資訊層級和控制台層級,下面我們要說到重點了!當資訊層級的數值小於控制台的層級時,printk要列印的資訊才會在終端列印出來,否則不會顯示在終端!   (2)串口控制台printk        vprintk(fmt, args);                 vscnprintf(printk_buf, sizeof(printk_buf), fmt, args);                          vsnprintf(buf,size,fmt,args);//先把輸出資訊輸入到臨時buffer                          //把臨時buffer裡面的資料稍作處理,寫入log_buffer                          //可以將資訊層級與資訊合并                          //在使用者空間使用命令dmesg可以把log_buffer裡面的資料列印出來                          release_console_sem();                                  call_console_drivers(_con_start, _log_end);                                          _call_console_drivers(start_print, cur_index, msg_level);                                                   __call_console_drivers(start, end);                                                            con->write(con, &LOG_BUF(start), end - start);//調用具體的輸出函數 這個輸出函數要把資料從串口輸出的話,肯定要調用到串口硬體相關的函數我們到檔案:drivers/serial/s3c2410.c裡面去這裡有個串口初始化函數: s3c24xx_serial_initconsole       register_console(&s3c24xx_serial_console); 我們來看看它的註冊函數:static struct console s3c24xx_serial_console ={ .name = S3C24XX_SERIAL_NAME, .device = uart_console_device, .flags = CON_PRINTBUFFER, .index = -1, .write = s3c24xx_serial_console_write, .setup = s3c24xx_serial_console_setup};裡面的確有個write函數! 但是我們還不知道printk選擇的控制台為什麼是串口呢? 我們知道uboot傳入了參數:console=ttySAC0 或者 console=tty1 核心就通過如下的函數來處理傳入的參數:__setup("console=", console_setup);這是個宏 ,它的作用就是用函數console_setup來處理我們傳入的參數console_ setup         //先解碼字串為:name, idx, options,然後就使用這些:name, idx, options        add_preferred_console(name, idx, options);                  strcmp(console_cmdline[i].name, name)                  console_cmdline[i].index == idx   //將索引和名字都記錄在了console_cmdline數組中了 我們記住這個數組,回過頭來再來看: register_console(&s3c24xx_serial_console);         if (strcmp(console_cmdline[i].name, console->name) != 0)                 continue;我們看到在註冊串口控制台的時候,會將串口控制台的名字與uboot傳進來的參數相比較,一旦匹配才會註冊。這樣的話,只有與uboot傳進來的控制台參數相一致的控制台才能註冊成功。那麼也就是說,printk會通過uboot設定的控制台的write函數,將資訊列印出來! 另外還有一點需要牢記的就是,printk輸出的資訊會先儲存在緩衝區log_buf中,所以我們當然可以通過查看log_buf來看輸出資訊了!而這個查看命令就是:dmesg實際上,dmesg這個命令的作用就是去讀/proc/kmsg這個檔案。也就是說log_buf裡面的內容是存放在/proc/kmsg這個檔案裡面的!


(3)使用printk 方法一:我們可以再核心中使用如下列印語句: #define DEG_PRINTK printk //#define DEG_PRINTK(x...)   DEG_PRINTK("%s %s %d\n",_FILE_,_FUNCTION_,_LINE_);這行列印語句的意思就是講本行代碼所在的檔案的名(包括路徑)、所在的函數、所在的行列印出來!當我們需要調試的時候,就使用 #define DEG_PRINTK printk這個宏,當不需要調試的時候,就使用 # define DEG_PRINTK(x...)這個宏。其中#define DEG_PRINTK(x...)裡面的"..."的意思是DEG_PRINTK的參數是可變的!當代碼比較少的時候,我們可以在每一行都加上這個列印語句,這樣很容易就會發現錯誤的位置!當代碼比較多的時候,我們可以採用對半尋找的方法!先在代碼中間加上列印語句!然後判斷出錯位置在列印語句之前還是之後,如果出現在之前,就在之前的代碼代碼裡面再次採用對半尋找!  方法二:上面我們說到過,要列印的資訊會存放在log_buf中,通過檔案/proc/kmsg可以來訪問這個buf,然後將資訊列印出來。由此我們就想了,我們是否可以構造這樣一個mylog_buf,裡面存放我們所需要的列印資訊,通過一個/proc/kmsg檔案可以訪問該buf,然後列印出來?答案是肯定的!下面我們就一步步來完成!

驅動程式調試方法之printk——printk的原理與直接使用

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.