S390 除錯特性

檔案
  • arch/s390/kernel/debug.c

  • arch/s390/include/asm/debug.h

描述:

此特性的目標是提供一個核心除錯日誌 API,在該 API 中,日誌記錄可以有效地儲存在記憶體中,每個元件(例如裝置驅動程式)可以擁有一個單獨的除錯日誌。其中一個目的是在生產系統崩潰後檢查除錯日誌,以便分析崩潰的原因。

如果系統仍在執行,但僅使用 dbf 的子元件出現故障,則可以透過 Linux debugfs 檔案系統在活動系統上檢視除錯日誌。

除錯特性對於核心和驅動程式開發也可能非常有用。

設計:

核心元件(例如裝置驅動程式)可以透過函式呼叫 debug_register() 在除錯特性中註冊自身。此函式為呼叫者初始化除錯日誌。對於每個除錯日誌,都存在多個除錯區域,並且一次只有一個處於活動狀態。每個除錯區域都由記憶體中連續的頁面組成。除錯區域中儲存了由事件和異常呼叫寫入的除錯條目(日誌記錄)。

事件呼叫將指定的除錯條目寫入活動除錯區域,並更新活動區域的日誌指標。如果到達活動除錯區域的末尾,則會進行環繞(環形緩衝區),並且下一個除錯條目將寫入活動除錯區域的開頭。

異常呼叫將指定的除錯條目寫入日誌,並切換到下一個除錯區域。這樣做是為了確保在當前區域發生環繞時,描述異常來源的記錄不會被覆蓋。

除錯區域本身也以環形緩衝區的形式排序。如果在最後一個除錯區域中引發異常,則以下除錯條目將再次寫入第一個區域。

事件和異常呼叫有四個版本:一個用於記錄原始資料,一個用於文字,一個用於數字(無符號 int 和 long),一個用於 sprintf 類似的格式化字串。

每個除錯條目都包含以下資料

  • 時間戳

  • 呼叫任務的 CPU 編號

  • 除錯條目的級別 (0...6)

  • 到呼叫者的返回地址

  • 標誌,指示條目是否為異常

可以透過 debugfs 檔案系統中的條目在活動系統中檢查除錯日誌。在頂層目錄 “s390dbf” 下,每個註冊元件都有一個目錄,其名稱類似於相應的元件。debugfs 通常應掛載到 /sys/kernel/debug,因此可以在 /sys/kernel/debug/s390dbf 下訪問除錯特性。

目錄的內容是表示除錯日誌的不同檢視的檔案。每個元件都可以透過使用函式 debug_register_view() 註冊它們來決定應使用哪些檢視。提供了用於十六進位制/ASCII 和 sprintf 資料的預定義檢視。也可以定義其他檢視。只需讀取相應的 debugfs 檔案即可檢查檢視的內容。

所有除錯日誌都有一個實際的除錯級別(範圍從 0 到 6)。預設級別為 3。事件和異常函式都有一個 level 引數。只有級別低於或等於實際級別的除錯條目才會寫入日誌。這意味著,在寫入事件時,高優先順序日誌條目應具有較低的級別值,而低優先順序條目應具有較高的級別值。可以使用 debugfs 檔案系統透過將數字字串“x”寫入為每個除錯日誌提供的 level debugfs 檔案來更改實際的除錯級別。可以使用 level debugfs 檔案上的“-”完全關閉除錯。

示例

> echo "-" > /sys/kernel/debug/s390dbf/dasd/level

也可以為每個除錯日誌全域性停用除錯特性。您可以使用 /proc/sys/s390dbf 中的 2 個 sysctl 引數來更改行為

目前有 2 個可能的觸發器,它們會全域性停止除錯特性。第一種可能性是使用 debug_active sysctl。如果設定為 1,則除錯特性正在執行。如果 debug_active 設定為 0,則除錯特性已關閉。

停止除錯特性的第二個觸發器是核心 oops。這樣可以防止除錯特性覆蓋在 oops 之前發生的除錯資訊。在發生 oops 後,您可以透過將 1 管道傳輸到 /proc/sys/s390dbf/debug_active 來重新啟用除錯特性。但是,不建議在生產環境中使用 oopsed 核心。

如果您想禁止停用除錯特性,您可以使用 debug_stoppable sysctl。如果您將 debug_stoppable 設定為 0,則無法停止除錯特性。如果除錯特性已停止,它將保持停用狀態。

核心介面:

bool debug_next_entry(file_private_info_t *p_info)

轉到下一個條目

引數

file_private_info_t *p_info

正在操作的私有資訊

描述

p_info 中的當前位置設定為下一個條目。如果不存在更多條目,則當前位置將設定為末尾之後的位置,並且返回值指示不存在更多條目。

返回

如果存在更多後續條目,則為 True,否則為 False

void debug_to_act_entry(file_private_info_t *p_info)

轉到當前活動條目

引數

file_private_info_t *p_info

正在操作的私有資訊

描述

p_info 中的當前位置設定為 p_info->debug_info_snap 的當前活動條目

bool debug_prev_entry(file_private_info_t *p_info)

轉到上一個條目

引數

file_private_info_t *p_info

正在操作的私有資訊

描述

p_info 中的當前位置設定為上一個條目。如果不存在上一個條目,則當前位置將保留為 DEBUG_PROLOG_ENTRY,並且返回值指示不存在上一個條目。

返回

如果存在更多上一個條目,則為 True,否則為 False

bool debug_move_entry(file_private_info_t *p_info, bool reverse)

向前或向後移動到下一個條目

引數

file_private_info_t *p_info

正在操作的私有資訊

bool reverse

如果為 True,則反向移動到下一個條目,即上一個

描述

p_info 中的當前位置設定為下一個(reverse == false)或上一個(reverse == true)條目。

返回

如果該方向上存在更多條目,則為 True,否則為 False。

ssize_t debug_dump(debug_info_t *id, struct debug_view *view, char *buf, size_t buf_size, bool reverse)

獲取除錯資訊的文字表示形式,或儘可能多的資訊

引數

debug_info_t *id

要使用的除錯資訊

struct debug_view *view

用於轉儲除錯資訊的檢視

char *buf

寫入文字除錯資料表示形式的緩衝區

size_t buf_size

緩衝區的大小,包括尾部的“0”位元組

bool reverse

從上次寫入的條目向後移動

描述

只要需要除錯資訊的文字表示形式而無需使用 s390dbf 檔案,就可以使用此函式。

注意

呼叫者有責任提供與除錯資訊資料相容的檢視。

返回

成功時,返回寫入緩衝區的位元組數,不包括尾部的“0”位元組。如果 bug_size == 0,則該函式返回 0。失敗時,返回小於 0 的錯誤程式碼。

debug_info_t *debug_register_mode(const char *name, int pages_per_area, int nr_areas, int buf_size, umode_t mode, uid_t uid, gid_t gid)

建立和初始化除錯區域。

引數

const char *name

除錯日誌的名稱(例如,用於 debugfs 條目)

int pages_per_area

每個區域將分配的頁數

int nr_areas

除錯區域的數量

int buf_size

每個除錯條目中資料區域的大小

umode_t mode

debugfs 檔案的檔案模式。例如,S_IRWXUGO

uid_t uid

debugfs 檔案的使用者 ID。當前僅支援 0。

gid_t gid

debugfs 檔案的組 ID。當前僅支援 0。

返回

  • 生成的除錯區域的控制代碼

  • 如果註冊失敗,則為 NULL

描述

為除錯日誌分配記憶體。不得在中斷處理程式中呼叫。

debug_info_t *debug_register(const char *name, int pages_per_area, int nr_areas, int buf_size)

使用預設檔案模式建立和初始化除錯區域。

引數

const char *name

除錯日誌的名稱(例如,用於 debugfs 條目)

int pages_per_area

每個區域將分配的頁數

int nr_areas

除錯區域的數量

int buf_size

每個除錯條目中資料區域的大小

返回

  • 生成的除錯區域的控制代碼

  • 如果註冊失敗,則為 NULL

描述

為除錯日誌分配記憶體。debugfs 檔案模式訪問許可權對於使用者是讀寫許可權。不得在中斷處理程式中呼叫。

void debug_register_static(debug_info_t *id, int pages_per_area, int nr_areas)

註冊靜態除錯區域

引數

debug_info_t *id

靜態除錯區域的控制代碼

int pages_per_area

每個區域的頁數

int nr_areas

除錯區域的數量

描述

註冊使用 DEFINE_STATIC_DEBUG_INFO 定義的 debug_info_t。

注意

此函式透過 initcall 自動呼叫,initcall 由

DEFINE_STATIC_DEBUG_INFO 生成。

void debug_unregister(debug_info_t *id)

交還除錯區域。

引數

debug_info_t *id

除錯日誌的控制代碼

返回

void debug_set_level(debug_info_t *id, int new_level)

如果 new_level 有效,則設定新的實際除錯級別。

引數

debug_info_t *id

除錯日誌的控制代碼

int new_level

新的除錯級別

返回

void debug_stop_all(void)

如果允許停止,則停止除錯特性。

引數

void

無引數

返回

描述

當前用於核心 oops 的情況。

void debug_set_critical(void)

event/exception 函式嘗試鎖定而不是自旋。

引數

void

無引數

返回

描述

當前用於停止除當前 CPU 之外的所有 CPU 的情況。一旦處於此狀態,用於為事件或異常寫入除錯條目的函式將不再在除錯區域鎖上自旋,而僅嘗試獲取它,如果它們沒有獲得鎖,則會失敗。

int debug_register_view(debug_info_t *id, struct debug_view *view)

註冊新的除錯檢視並建立 debugfs 目錄條目

引數

debug_info_t *id

除錯日誌的控制代碼

struct debug_view *view

指向除錯檢視結構的指標

返回

  • 0:ok

  • < 0:錯誤

int debug_unregister_view(debug_info_t *id, struct debug_view *view)

取消註冊除錯檢視並刪除 debugfs 目錄條目

引數

debug_info_t *id

除錯日誌的控制代碼

struct debug_view *view

指向除錯檢視結構的指標

返回

  • 0:ok

  • < 0:錯誤

bool debug_level_enabled(debug_info_t *id, int level)

如果將記錄指定級別的除錯事件,則返回 true。否則返回 false。

引數

debug_info_t *id

除錯日誌的控制代碼

int level

除錯級別

返回

  • 如果級別小於或等於當前除錯級別,則為 true

debug_entry_t *debug_event(debug_info_t *id, int level, void *data, int length)

將二進位制除錯條目寫入活動除錯區域 (如果 level <= 實際除錯級別)

引數

debug_info_t *id

除錯日誌的控制代碼

int level

除錯級別

void *data

指向除錯條目資料的指標

int length

資料長度(位元組)

返回

  • 寫入的除錯條目的地址

  • 出錯時返回 NULL

debug_entry_t *debug_int_event(debug_info_t *id, int level, unsigned int tag)

將無符號整數除錯條目寫入活動除錯區域 (如果 level <= 實際除錯級別)

引數

debug_info_t *id

除錯日誌的控制代碼

int level

除錯級別

unsigned int tag

除錯條目的整數值

返回

  • 寫入的除錯條目的地址

  • 出錯時返回 NULL

debug_entry_t *debug_long_event(debug_info_t *id, int level, unsigned long tag)

將無符號長整數除錯條目寫入活動除錯區域 (如果 level <= 實際除錯級別)

引數

debug_info_t *id

除錯日誌的控制代碼

int level

除錯級別

unsigned long tag

除錯條目的長整數值

返回

  • 寫入的除錯條目的地址

  • 出錯時返回 NULL

debug_entry_t *debug_text_event(debug_info_t *id, int level, const char *txt)

將 ASCII 格式的字串除錯條目寫入活動除錯區域 (如果 level <= 實際除錯級別)

引數

debug_info_t *id

除錯日誌的控制代碼

int level

除錯級別

const char *txt

除錯條目的字串

返回

  • 寫入的除錯條目的地址

  • 出錯時返回 NULL

debug_sprintf_event

debug_sprintf_event (_id, _level, _fmt, ...)

使用格式字串和可變引數 (longs) 將除錯條目寫入活動除錯區域 (如果 level $<=$ 實際除錯級別)。

引數

_id

除錯日誌的控制代碼

_level

除錯級別

_fmt

除錯條目的格式字串

...

可變引數的使用方式與 sprintf() 相同

返回

  • 寫入的除錯條目的地址

  • 出錯時返回 NULL

描述

浮點數和 long long 資料型別不能用作可變引數。

debug_entry_t *debug_exception(debug_info_t *id, int level, void *data, int length)

將二進位制除錯條目寫入活動除錯區域 (如果 level <= 實際除錯級別) 並切換到下一個除錯區域

引數

debug_info_t *id

除錯日誌的控制代碼

int level

除錯級別

void *data

指向除錯條目資料的指標

int length

資料長度(位元組)

返回

  • 寫入的除錯條目的地址

  • 出錯時返回 NULL

debug_entry_t *debug_int_exception(debug_info_t *id, int level, unsigned int tag)

將無符號整數除錯條目寫入活動除錯區域 (如果 level <= 實際除錯級別) 並切換到下一個除錯區域

引數

debug_info_t *id

除錯日誌的控制代碼

int level

除錯級別

unsigned int tag

除錯條目的整數值

返回

  • 寫入的除錯條目的地址

  • 出錯時返回 NULL

debug_entry_t *debug_long_exception(debug_info_t *id, int level, unsigned long tag)

將長整數除錯條目寫入活動除錯區域 (如果 level <= 實際除錯級別) 並切換到下一個除錯區域

引數

debug_info_t *id

除錯日誌的控制代碼

int level

除錯級別

unsigned long tag

除錯條目的長整數值

返回

  • 寫入的除錯條目的地址

  • 出錯時返回 NULL

debug_entry_t *debug_text_exception(debug_info_t *id, int level, const char *txt)

將 ASCII 格式的字串除錯條目寫入活動除錯區域 (如果 level <= 實際除錯級別) 並切換到下一個除錯區域

引數

debug_info_t *id

除錯日誌的控制代碼

int level

除錯級別

const char *txt

除錯條目的字串

返回

  • 寫入的除錯條目的地址

  • 出錯時返回 NULL

debug_sprintf_exception

debug_sprintf_exception (_id, _level, _fmt, ...)

使用格式字串和可變引數 (longs) 將除錯條目寫入活動除錯區域 (如果 level <= 實際除錯級別) 並切換到下一個除錯區域。

引數

_id

除錯日誌的控制代碼

_level

除錯級別

_fmt

除錯條目的格式字串

...

可變引數的使用方式與 sprintf() 相同

返回

  • 寫入的除錯條目的地址

  • 出錯時返回 NULL

描述

浮點數和 long long 資料型別不能用作可變引數。

DEFINE_STATIC_DEBUG_INFO

DEFINE_STATIC_DEBUG_INFO (var, name, pages, nr_areas, buf_size, view)

定義靜態 debug_info_t

引數

var

debug_info_t 變數的名稱

name

除錯日誌的名稱(例如,用於 debugfs 條目)

pages

每個區域的頁數

nr_areas

除錯區域的數量

buf_size

每個除錯條目中資料區域的大小

view

指向除錯檢視結構的指標

描述

為早期跟蹤定義一個靜態 debug_info_t。關聯的 debugfs 日誌會自動使用指定的除錯檢視註冊。

重要提示:此宏的使用者不得為此 debug_info_t 呼叫任何 debug_register/_unregister() 函式!

注意

跟蹤將從固定數量的初始頁面和區域開始。除錯區域將被更改為在 arch_initcall 期間使用指定的數字。

預定義檢視:

extern struct debug_view debug_hex_ascii_view;

extern struct debug_view debug_sprintf_view;

示例

/*
 * hex_ascii-view Example
 */

#include <linux/init.h>
#include <asm/debug.h>

static debug_info_t *debug_info;

static int init(void)
{
    /* register 4 debug areas with one page each and 4 byte data field */

    debug_info = debug_register("test", 1, 4, 4 );
    debug_register_view(debug_info, &debug_hex_ascii_view);

    debug_text_event(debug_info, 4 , "one ");
    debug_int_exception(debug_info, 4, 4711);
    debug_event(debug_info, 3, &debug_info, 4);

    return 0;
}

static void cleanup(void)
{
    debug_unregister(debug_info);
}

module_init(init);
module_exit(cleanup);
/*
 * sprintf-view Example
 */

#include <linux/init.h>
#include <asm/debug.h>

static debug_info_t *debug_info;

static int init(void)
{
    /* register 4 debug areas with one page each and data field for */
    /* format string pointer + 2 varargs (= 3 * sizeof(long))       */

    debug_info = debug_register("test", 1, 4, sizeof(long) * 3);
    debug_register_view(debug_info, &debug_sprintf_view);

    debug_sprintf_event(debug_info, 2 , "first event in %s:%i\n",__FILE__,__LINE__);
    debug_sprintf_exception(debug_info, 1, "pointer to debug info: %p\n",&debug_info);

    return 0;
}

static void cleanup(void)
{
    debug_unregister(debug_info);
}

module_init(init);
module_exit(cleanup);

Debugfs 介面

可以透過讀取相應的 debugfs 檔案來調查除錯日誌的檢視

示例

> ls /sys/kernel/debug/s390dbf/dasd
flush  hex_ascii  level pages
> cat /sys/kernel/debug/s390dbf/dasd/hex_ascii | sort -k2,2 -s
00 00974733272:680099 2 - 02 0006ad7e  07 ea 4a 90 | ....
00 00974733272:682210 2 - 02 0006ade6  46 52 45 45 | FREE
00 00974733272:682213 2 - 02 0006adf6  07 ea 4a 90 | ....
00 00974733272:682281 1 * 02 0006ab08  41 4c 4c 43 | EXCP
01 00974733272:682284 2 - 02 0006ab16  45 43 4b 44 | ECKD
01 00974733272:682287 2 - 02 0006ab28  00 00 00 04 | ....
01 00974733272:682289 2 - 02 0006ab3e  00 00 00 20 | ...
01 00974733272:682297 2 - 02 0006ad7e  07 ea 4a 90 | ....
01 00974733272:684384 2 - 00 0006ade6  46 52 45 45 | FREE
01 00974733272:684388 2 - 00 0006adf6  07 ea 4a 90 | ....

有關上述輸出的說明,請參見有關預定義檢視的部分!

更改除錯級別

示例

> cat /sys/kernel/debug/s390dbf/dasd/level
3
> echo "5" > /sys/kernel/debug/s390dbf/dasd/level
> cat /sys/kernel/debug/s390dbf/dasd/level
5

重新整理除錯區域

可以透過將所需區域的編號 (0...n) 透過管道傳遞到 debugfs 檔案 “flush” 來重新整理除錯區域。當使用 “-” 時,所有除錯區域都將被重新整理。

示例

  1. 重新整理除錯區域 0

    > echo "0" > /sys/kernel/debug/s390dbf/dasd/flush
    
  2. 重新整理所有除錯區域

    > echo "-" > /sys/kernel/debug/s390dbf/dasd/flush
    

更改除錯區域的大小

可以透過將頁面數量透過管道傳遞到 debugfs 檔案 “pages” 來更改除錯區域的大小。調整大小請求也會重新整理除錯區域。

示例

為除錯功能 “dasd” 的除錯區域定義 4 個頁面

> echo "4" > /sys/kernel/debug/s390dbf/dasd/pages

停止除錯功能

示例

  1. 檢查是否允許停止

    > cat /proc/sys/s390dbf/debug_stoppable
    
  2. 停止除錯功能

    > echo 0 > /proc/sys/s390dbf/debug_active
    

crash 介面

自 v5.1.0 以來的 crash 工具具有內建命令 s390dbf 來顯示所有除錯日誌或將其匯出到檔案系統。使用此工具,可以在即時系統上和系統崩潰後的記憶體轉儲中調查除錯日誌。

調查原始記憶體

在即時系統上和系統崩潰後調查除錯日誌的最後一種可能性是在 VM 下或在服務元素中檢視原始記憶體。 可以透過系統對映中的 debug_area_first 符號找到除錯日誌的錨點。 然後,必須遵循 debug.h 中定義的資料結構的正確指標,並在記憶體中找到除錯區域。 通常,使用除錯功能的模組也將具有一個全域性變數,該變數帶有指向除錯日誌的指標。 遵循此指標也將可以在記憶體中找到除錯日誌。

對於此方法,建議對 debug_register() 中的資料欄位長度使用 '16 * x + 4' 位元組 (x = 0..n),以便更好地格式化除錯條目。

預定義檢視

有兩種預定義的檢視:hex_ascii 和 sprintf。hex_ascii 檢視以十六進位制和 ASCII 格式顯示資料欄位(例如 45 43 4b 44 | ECKD)。

sprintf 檢視以與 sprintf 函式相同的方式格式化除錯條目。 sprintf event/exception 函式將指向格式字串(大小 = sizeof(long))的指標以及每個可變引數的長整型值寫入除錯條目。 因此,例如,對於具有格式字串加上兩個可變引數的除錯條目,需要在 debug_register() 函式中分配一個 (3 * sizeof(long)) 位元組的資料區域。

重要提示

在 sprintf event 函式中使用 “%s” 是危險的。 只有在傳遞字串的記憶體在除錯功能存在期間可用時,才能在 sprintf event 函式中使用 “%s”。 其背後的原因是,出於效能考慮,只有指向字串的指標儲存在除錯功能中。 如果記錄的字串在之後被釋放,則在檢查除錯功能時會發生 OOPS,因為除錯功能會訪問已釋放的記憶體。

注意

如果使用 sprintf 檢視,請不要使用 sprintf-event 和 -exception 函式以外的其他 event/exception 函式。

hex_ascii 和 sprintf 檢視的格式如下

  • 區域編號

  • 時間戳(格式為自 1970 年 1 月 1 日協調世界時 (UTC) 00:00:00 以來的秒數和微秒數)

  • 除錯條目的級別

  • 異常標誌 (* = 異常)

  • 呼叫任務的 CPU 編號

  • 到呼叫者的返回地址

  • 資料欄位

hex_ascii 檢視的典型行將如下所示(第一行僅用於解釋,在 “cating” 檢視時不會顯示)

area  time           level exception cpu caller    data (hex + ascii)
--------------------------------------------------------------------------
00    00964419409:440690 1 -         00  88023fe

定義檢視

檢視使用 “debug_view” 結構指定。 定義了用於讀取和寫入 debugfs 檔案的回撥函式

struct debug_view {
      char name[DEBUG_MAX_PROCF_LEN];
      debug_prolog_proc_t* prolog_proc;
      debug_header_proc_t* header_proc;
      debug_format_proc_t* format_proc;
      debug_input_proc_t*  input_proc;
      void*                private_data;
};

其中

typedef int (debug_header_proc_t) (debug_info_t* id,
                                   struct debug_view* view,
                                   int area,
                                   debug_entry_t* entry,
                                   char* out_buf);

typedef int (debug_format_proc_t) (debug_info_t* id,
                                   struct debug_view* view, char* out_buf,
                                   const char* in_buf);
typedef int (debug_prolog_proc_t) (debug_info_t* id,
                                   struct debug_view* view,
                                   char* out_buf);
typedef int (debug_input_proc_t) (debug_info_t* id,
                                  struct debug_view* view,
                                  struct file* file, const char* user_buf,
                                  size_t in_buf_size, loff_t* offset);

“private_data” 成員可用作指向檢視特定資料的指標。 它不被除錯功能本身使用。

從 debugfs 讀取檢視時,輸出結構如下

"prolog_proc output"

"header_proc output 1"  "format_proc output 1"
"header_proc output 2"  "format_proc output 2"
"header_proc output 3"  "format_proc output 3"
...

從 debugfs 讀取檢視時,除錯功能會呼叫一次 'prolog_proc' 來寫入 prolog。 然後為每個現有的除錯條目呼叫 'header_proc' 和 'format_proc'。

input_proc 可用於實現寫入檢視時的功能(例如 echo "0" > /sys/kernel/debug/s390dbf/dasd/level)。

對於 header_proc,可以使用 debug.h 中定義的預設函式 debug_dflt_header_fn(),該函式產生與預定義檢視相同的標頭輸出。 例如

00 00964419409:440761 2 - 00 88023ec

為了瞭解如何使用回撥函式,請檢查預設檢視的實現!

示例

#include <asm/debug.h>

#define UNKNOWNSTR "data: %08x"

const char* messages[] =
{"This error...........\n",
 "That error...........\n",
 "Problem..............\n",
 "Something went wrong.\n",
 "Everything ok........\n",
 NULL
};

static int debug_test_format_fn(
   debug_info_t *id, struct debug_view *view,
   char *out_buf, const char *in_buf
)
{
  int i, rc = 0;

  if (id->buf_size >= 4) {
     int msg_nr = *((int*)in_buf);
     if (msg_nr < sizeof(messages) / sizeof(char*) - 1)
        rc += sprintf(out_buf, "%s", messages[msg_nr]);
     else
        rc += sprintf(out_buf, UNKNOWNSTR, msg_nr);
  }
  return rc;
}

struct debug_view debug_test_view = {
  "myview",                 /* name of view */
  NULL,                     /* no prolog */
  &debug_dflt_header_fn,    /* default header for each entry */
  &debug_test_format_fn,    /* our own format function */
  NULL,                     /* no input function */
  NULL                      /* no private data */
};

測試:

debug_info_t *debug_info;
int i;
...
debug_info = debug_register("test", 0, 4, 4);
debug_register_view(debug_info, &debug_test_view);
for (i = 0; i < 10; i ++)
  debug_int_event(debug_info, 1, i);
> cat /sys/kernel/debug/s390dbf/test/myview
00 00964419734:611402 1 - 00 88042ca   This error...........
00 00964419734:611405 1 - 00 88042ca   That error...........
00 00964419734:611408 1 - 00 88042ca   Problem..............
00 00964419734:611411 1 - 00 88042ca   Something went wrong.
00 00964419734:611414 1 - 00 88042ca   Everything ok........
00 00964419734:611417 1 - 00 88042ca   data: 00000005
00 00964419734:611419 1 - 00 88042ca   data: 00000006
00 00964419734:611422 1 - 00 88042ca   data: 00000007
00 00964419734:611425 1 - 00 88042ca   data: 00000008
00 00964419734:611428 1 - 00 88042ca   data: 00000009