1. 程式人生 > >linux裝置驅動學習筆記--核心除錯方法之printk

linux裝置驅動學習筆記--核心除錯方法之printk

1,printk類似於使用者態的printf函式,但是比printf函式多了一個日誌級別,核心中最常見的日誌輸出都是通過呼叫printk來實現的,其列印級別有8種可能的記錄字串, 在標頭檔案 <linux/kernel.h> 裡定義:

KERN_EMERG  0用於緊急訊息, 常常是那些崩潰前的訊息.
KERN_ALERT  1需要立刻動作的情形.
KERN_CRIT  2嚴重情況, 常常與嚴重的硬體或者軟體失效有關.
KERN_ERR  3用來報告錯誤情況; 裝置驅動常常使用KERN_ERR 來報告硬體故障.
KERN_WARNING  4有問題的情況的警告, 這些情況自己不會引起系統的嚴重問題.
KERN_NOTICE  5正常情況, 但是仍然值得注意. 在這個級別一些安全相關的情況會報告.
KERN_INFO  6資訊型訊息. 在這個級別, 很多驅動在啟動時列印它們發現的硬體的資訊.
KERN_DEBUG  7用作除錯訊息.

2,資訊格式化與printf一致,可以有以下幾種用法:

                   If variable is of Type,                  useprintk format specifier:
                   int                                      %d or %x
                   unsignedint                              %u or %x
                   long                                     %ld or %lx
                   unsignedlong                             %lu or %lx
                   longlong                                 %lld or %llx
                   unsignedlong long                        %llu or %llx
                   size_t                                   %zu or %zx
                   ssize_t                                  %zd or %zx
                   pointer                                  %p

3,核心有的程式碼執行很快,如果直接用printk列印會導致系統慢或者卡死現象,核心提供了一個日誌流控函式printk_ratelimit,定義及使用如下:

int printk_ratelimit(void);
if (printk_ratelimit())
    printk(KERN_INFO“testprint rate limit.\n”);

4,核心中為了方便列印裝置編號提供了以下兩個函式:
int print_dev_t(char *buffer, dev_t dev);
char *format_dev_t(char *buffer, dev_t dev);


定義見核心程式碼(include\linux\kdev_t.h):

#define print_dev_t(buffer, dev)                 \
    sprintf((buffer),"%u:%u\n", MAJOR(dev), MINOR(dev))
 
#define format_dev_t(buffer, dev)                \
    ({                          \
       sprintf(buffer,"%u:%u", MAJOR(dev), MINOR(dev));    \
       buffer;                         \
    })

5,在linux系統中通過檔案/proc/sys/kernel/printk檔案可以檢視、修改核心的日誌級別,此檔案有四個數值,分別表示:當前記錄級別, 適用沒有明確記錄級別的訊息的預設級別,允許的最小記錄級別, 以及啟動時預設記錄級別。例如

[[email protected] ~]# cat/proc/sys/kernel/printk
4       4      1       7
[[email protected] ~]#

6,不僅可以控制核心的日誌級別,還可以通過下面兩個檔案來控制控制核心通過printk列印的速度。/proc/sys/kernel/{printk_ratelimit ,printk_ratelimit_burst},對應核心程式碼:

核心對/proc/sys下面的檔案會統一匯出,其定義在struct ctl_table kern_table[]中:

        {
                   .procname        = "printk_ratelimit",
                   .data             =&printk_ratelimit_state.interval, //表示printk_ratelimit檔案對應interval值
                   .maxlen             = sizeof(int),
                   .mode                = 0644,
                   .proc_handler  = proc_dointvec_jiffies,
         },
         {
                   .procname        = "printk_ratelimit_burst",
                   .data            =&printk_ratelimit_state.burst,  //<span style="font-family: Arial, Helvetica, sans-serif;">表示printk_ratelimit檔案對應burst值</span>

                   .maxlen             = sizeof(int),
                   .mode                = 0644,
                   .proc_handler  = proc_dointvec,
         },</span>

流控函式printk_ratelimit()的定義在include\linux\printk.h中,

#define printk_ratelimit()  __printk_ratelimit(__func__)

__printk_ratelimit()函式定義在include\linux\printk.c中
int __printk_ratelimit(const char *func)
{
	return ___ratelimit(&printk_ratelimit_state, func);
}
EXPORT_SYMBOL(__printk_ratelimit);
最終呼叫到函式__ratelimit,此函式在lib\ratelimit.c中實現,從實現中可以看出interval控制時間長度,burst控制列印的條數,即呼叫printk_ratelimit的結果是:在/proc/sys/kernel/printk_ratelimit對應的時間段內(單位秒),列印不超過/proc/sys/kernel/printk_ratelimit_burst對應的條數。
int ___ratelimit(struct ratelimit_state*rs, const char *func)
{
         unsignedlong flags;
         intret;
 
         if(!rs->interval)       //從上面可以這個就對應/proc下面的print_ratelimit檔案的值

                   return1;
 
         /*
          * If we contend on this state's lock thenalmost
          * by definition we are too busy to print amessage,
          * in addition to the one that will be printedby
          * the entity that is holding the lock already:
          */
         if(!raw_spin_trylock_irqsave(&rs->lock, flags))
                   return0;
 
         if(!rs->begin)
                   rs->begin= jiffies;
 
         if(time_is_before_jiffies(rs->begin + rs->interval)) {
                   if(rs->missed)
                            printk(KERN_WARNING"%s: %d callbacks suppressed\n",
                                     func,rs->missed);
                   rs->begin   = 0;
                   rs->printed= 0;
                   rs->missed  = 0;
         }
         if(rs->burst && rs->burst > rs->printed) {  //對應前面的proc檔案中print_ratelimit_burst檔案的值

                   rs->printed++;
                   ret= 1;
         }else {
                   rs->missed++;
                   ret= 0;
         }
         raw_spin_unlock_irqrestore(&rs->lock,flags);
 
         return ret;
}



相關推薦

linux裝置驅動學習筆記--核心除錯方法printk

1,printk類似於使用者態的printf函式,但是比printf函式多了一個日誌級別,核心中最常見的日誌輸出都是通過呼叫printk來實現的,其列印級別有8種可能的記錄字串, 在標頭檔案 <linux/kernel.h> 裡定義: KERN_EMERG

linux裝置驅動學習筆記--核心除錯方法proc(補充seq_file)

上一節中的proc實現對於開關檔案,控制檔案,以及顯示很少資訊的檔案來說還是比較簡單的,但是對於需要輸出大量資訊像meminfo,或者結構化的資訊像cpuinfo等時就會顯得很笨拙,並且程式碼也很不好理解與維護。核心為了簡化這種proc檔案的實現提供了另外一種方案----s

linux裝置驅動學習筆記--核心除錯方法proc

/proc 檔案系統是 GNU/Linux 特有的。它是一個虛擬的檔案系統,因此在該目錄中的所有檔案都不會消耗磁碟空間。通過它能夠非常簡便地瞭解系統資訊,尤其是其中的大部分檔案是人類可閱讀的(不過還是需要一些幫助)。許多程式實際上只是從 /proc 的檔案中收集資訊,然後按

linux I2C 裝置驅動學習筆記

一:I2C 概述           I2C是philips提出的外設匯流排.使用SCL時鐘線,SDA序列資料線這兩根訊號線就實現了裝置之間的資料互動,被非常廣泛地應用在CPU與EEPROM,實時鐘,小型LCD等裝置通訊中。  二:在linux下的驅動思路     linu

嵌入式Linux裝置驅動開發筆記(一)

一、Linux裝置的分類 字元裝置、塊裝置、網路裝置,三種裝置之間的區別是資料的互動模式,分別為: 位元組流、資料塊、資料包。 二、VFS核心結構體 VFS核心結構體定義在”linux/fs.h”標頭檔案中。 1、struct inode結構體 記

linux裝置驅動學習(6) 高階字元驅動學習--阻塞型I/0

提出問題:若驅動程式無法立即滿足請求,該如何響應? 比如:當資料不可用時呼叫read,或是在緩衝區已滿時,呼叫write 解決問題:驅動程式應該(預設)該阻塞程序,將其置入休眠狀態直到請求可繼續。 休眠: 當一個程序被置入休眠時,它會被標記為一種特殊狀態並從排程器執行佇列

宋寶華:Linux裝置驅動框架裡的設計模式——模板方法(Template Method)

本文系轉載,著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。 作者: 宋寶華 來源: 微信公眾號linux閱碼場(id: linuxdev) 前言 《設計模式》這本經典的書裡面定義了20多種設計模式,雖然都是面向物件的,似乎需要C++、Java這樣的語言才能實現,但是根據筆者前面反覆

手把手教你寫Linux裝置驅動---定時器(一)(基於友善臂4412開發板)

這個專題我們來說下Linux中的定時器。在Linux核心中,有這樣的一個定時器,叫做核心定時器,核心定時器用於控制某個函式,也就是定時器將要處理的函式在未來的某個特定的時間內執行。核心定時器註冊的處理函

linux裝置驅動開發》,基於最新的linux 4.0核心-----筆記

第二章 Linux 的核心結構及構建 ---->這一章是自己總結的 1、核心結構(主要是下面這幾個部分) 系統呼叫介面<–>System call interface 程序管理<------>Process manag

Linux裝置驅動開發學習筆記

2016.6.25 這部門主要是之前學習linux裝置驅動開發時候的一些筆記,主要學習的參考書是《Linux裝置驅動開發詳解第2版》 書連結:http://note.youdao.com/noteshare?id=bbf134da309035b2093c5abcd5c7c8ac&

深入linux裝置驅動程式核心機制(第九章) 讀書筆記

第9章 linux裝置驅動模型       本文歡迎轉載, 請標明出處        本文出處: http://blog.csdn.net/dyron 9.1 sysfs檔案系統          sysfs檔案系統可以取代ioctl的功能.     sysfs檔案系統

核心程式除錯手段 >>Linux裝置驅動程式

文章目錄 [0x100]常用核心除錯方式 [0x110]核心的DEBUG選項 [0x120]核心列印函式 >>printk [0x121]預設規則 [0x122]終端列印日誌級別配置 [0x12

Linux裝置驅動第一天學習筆記(如何將系統在開發板上執行起來、驅動開發基本步驟)

如何將系統在開發板上執行起來? 4.0 交叉編譯器的獲取?廠家提供 網上下載(廠家確認) 4.1 uboot進行操作? 1,解壓廠家原始碼 2,進入原始碼 3,make distclean 徹底刪除原始碼的目標、臨時檔案 4,make xxx_c

Arm+Linux核心驅動學習筆記

韋東山老師幫我們把框架搭建起來了,我們先來看一下: 框架: app:      open,read,write "1.txt" ---------------------------------------------  檔案的讀寫 檔案系統: vfat, ext2,

Linux裝置驅動程式學習(7)-核心的資料型別

由於前面的學習中有用到 第十一章 核心資料結構型別 的知識,所以我先看了。要點如下: 將linux 移植到新的體系結構時,開發者遇到的若干問題都與不正確的資料型別有關。堅持使用嚴格的資料型別和使用 -Wall -Wstrict-prototypes 進行編譯可能避免大部分

linux裝置驅動第四篇:從如何定位oops的程式碼行談驅動除錯方法

上一篇我們大概聊瞭如何寫一個簡單的字元裝置驅動,我們不是神,寫程式碼肯定會出現問題,我們需要在編寫程式碼的過程中不斷除錯。在普通的c應用程式中,我們經常使用printf來輸出資訊,或者使用gdb來除錯程式,那麼驅動程式如何除錯呢?我們知道在除錯程式時經常遇到的問題就是野指標

linux裝置驅動:從如何定位oops的程式碼行談驅動除錯方法

在普通的c應用程式中,我們經常使用printf來輸出資訊,或者使用gdb來除錯程式,那麼驅動程式如何除錯呢?我們知道在除錯程式時經常遇到的問題就是野指標或者陣列越界帶來的問題,在應用程式中執行這種程式就會報segmentation fault的錯誤,而由於驅動程

Linux裝置驅動學習筆記(概述)

由於在下能力相當有限,有不當之處,還望批評指正^_^一、概述在核心中,匯流排/裝置/驅動模型實現了對匯流排/裝置/驅動的管理。涉及的概念有struct bus_type(匯流排型別)。核心並不關心每種匯流排的實現細節,也未預先定義一共有哪些具體的匯流排型別。因此,開發者甚至可

Linux裝置驅動程式學習筆記7--時間、延遲及延緩操作

#include <linux/timer.h>struct timer_list {    struct list_head entry;    unsigned long expires;/*期望定時器執行的絕對 jiffies 值,不是一個 jiffies_64 值,因為定時器不被期望在將來

Linux運維學習筆記之一:運維的原則和學習方法

linux 運維 筆記 一直在用Linux,但從未系統學習過,從1月1日開始學習到7月16日結束,近七個月學習,讓自已對Linux有了新的認識,老男孩老師的課真的不錯,實戰性很強。由於只能中午和晚上10點以後才有時間,所以所有的實驗是在不同電腦上完成的,文中IP可能有點問題,但應該不會影響實驗。同時,為了保證