共用方式為


讀取和篩選偵錯訊息

DbgPrintEx、vDbgPrintExvDbgPrintExWithPrefixKdPrintEx 例程會在您指定的條件下,將訊息傳送至核心調試程式。 此程式可讓您篩選出低優先順序的訊息。

備註

Microsoft Windows Server 2003 和舊版 Windows 中, DbgPrintKdPrint 例程會無條件地將訊息傳送至核心調試程式。 在 Windows Vista 和更新版本的 Windows 中,這些例程會有條件地傳送訊息,例如 DbgPrintExKdPrintEx。 無論您使用的 Windows 版本為何,都應該使用 DbgPrintExvDbgPrintEx、vDbgPrintExWithPrefixKdPrintEx,因為這些例程可讓您控制訊息傳送的條件。

篩選偵錯訊息

  1. 針對您要傳送至除錯程式的每個訊息,請在驅動程式的程式代碼中使用 DbgPrintExvDbgPrintEx、vDbgPrintExWithPrefixKdPrintEx 將適當的元件名稱傳遞至 ComponentId 參數,並將值傳遞至 Level 參數,以反映此訊息的嚴重性或本質。 訊息本身會使用與 printf 相同的語法傳遞至 Format自變數參數。

  2. 設定適當 元件篩選遮罩的值。 每個元件都有不同的遮罩。 遮罩值會決定顯示該元件的哪些訊息。 您可以使用登錄編輯器或在記憶體中使用內核調試程式,在登錄中設定元件篩選遮罩。

  3. 將核心調試程式附加至計算機。 每當驅動程式將訊息傳遞給 DbgPrintEx、vDbgPrintExvDbgPrintExWithPrefixKdPrintEx 時,傳遞至 ComponentIdLevel 的值都會與對應元件篩選遮罩的值進行比較。 如果這些值符合特定準則,訊息會傳送至核心調試程序並顯示。 否則,不會傳送任何訊息。

備註

此頁面對 DbgPrintEx 的所有參考都同樣適用於 KdPrintExvDbgPrintEx 和 vDbgPrintExWithPrefix

識別元件名稱

每個元件都有個別的篩選遮罩。 這可讓調試程式個別設定每個元件的篩選。

每個元件的稱呼會因上下文而異。 在 DbgPrintExComponentId 參數中,元件名稱前面加上 「DPFLTR_」,後綴為 「_ID」。。 在登錄中,元件篩選遮罩的名稱與元件本身相同。 在調試程式中,元件篩選遮罩的前綴為「Kd_」,後綴為「_Mask」。

Microsoft Windows 驅動程式套件 (WDK) 標頭 dpfilter.h 中有所有元件名稱的完整清單(DPFLTR_XXXX_ID格式)。 這些元件名稱大部分都保留給 Windows,以及Microsoft所撰寫的驅動程式。

有六個元件名稱保留給獨立硬體廠商。 若要避免將驅動程序的輸出與 Windows 元件的輸出混合,您應該使用下列其中一個元件名稱:

元件名稱 驅動程式類型
IHVVIDEO 視訊驅動程式
IHVAUDIO 音訊驅動程式
IHVNETWORK 網路驅動程式
IHVSTREAMING 核心串流驅動程式
IHVBUS 公交車司機
IHVDRIVER 任何其他類型的驅動程式

例如,如果您要撰寫視訊驅動程式,您會使用 DPFLTR_IHVVIDEO_ID 作為 DbgPrintExComponentId 參數、在登錄中使用值名稱 IHVVIDEO,並在調試程式中參考Kd_IHVVIDEO_Mask

DbgPrintKdPrint 傳送的所有訊息都會與 DEFAULT 元件相關聯。

選擇正確的層級

DbgPrintEx 例程的 Level 參數的類型為 DWORD。 它用來判斷重要性位元欄位Level 參數與此位字段之間的連線取決於 Level 的大小:

  • 如果 Level 等於介於 0 到 31 之間的數字,則會將其解譯為位元移位。 重要性位元欄位設定為值 1 <<Level。 因此,針對 Level 選擇介於 0 到 31 之間的值會產生一個只有一位被設定的位元欄位。 如果 Level 為 0,則位字段相當於0x00000001;如果 Level 為 31,則位字段相當於0x80000000。

  • 如果 Level 是介於 32 和 0xFFFFFFFF 之間的數位,則重要性位欄位元元會設定為 Level 本身的值。

因此,如果您想要將位字段設定為 0x00004000,您可以將 Level 指定為 0x00004000,或直接指定為 14。 請注意,這個系統無法產生某些位元欄位的值,包括完全為零的位元欄位。

下列常數可用於設定 Level 的值。 它們定義於 Microsoft Windows Driver Kit (WDK) 標頭 dpfilter.h 和 Windows SDK 標頭 ntrtl.h:

#define   DPFLTR_ERROR_LEVEL     0
#define   DPFLTR_WARNING_LEVEL   1
#define   DPFLTR_TRACE_LEVEL     2
#define   DPFLTR_INFO_LEVEL      3
#define   DPFLTR_MASK   0x80000000

使用 Level 參數的一個簡單方式是始終使用介於 0 到 31 之間的值——用第 0、1、2、3 位來符合 DPFLTR_XXXX_LEVEL 所給予的意義,並用其他位來表示您選擇的任何含義。

使用 Level 參數的另一個簡單方式是一律使用明確位字段。 如果您選擇此方法,您可能會想將 DPFLTR_MASK 值與您的位欄使用位或運算;這可確保您不會意外地使用小於 32 的值。

若要讓您的驅動程式與 Windows 使用訊息層級的方式相容,您應該只在發生嚴重錯誤時,設定重要性位字段的最低位 (0x1)。 如果您使用 Level 值小於 32,這會對應至 DPFLTR_ERROR_LEVEL。 如果設定此位,每當有人將核心調試程式附加至驅動程序執行所在的計算機時,就會檢視您的訊息。

警告、追蹤和資訊層級應該在適當情況下使用。 其他位可以自由用於您認為有用的任何目的。 這可讓您有各種不同的訊息類型,可選擇性地看到或隱藏。

DbgPrintKdPrint 所傳送的所有訊息都與 Level 等於 DPFLTR_INFO_LEVEL 的 DbgPrintExKdPrintEx 訊息類似。 換句話說,這些訊息的其重要性位元欄位的第三位已設定。

設定元件過濾遮罩

有兩種方式可以設定元件篩選遮罩:

  • 您可以在登錄檔機碼中存取元件篩選遮罩 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Debug Print Filter。 使用登錄編輯器,建立或開啟此機碼。 在此機碼下,創建一個以大寫字母命名的所需元件名稱的值。 將它設定為您想要作為組件篩選掩碼使用的 DWORD 整數值。

  • 如果核心偵錯工具為使用中,它可以存取元件篩選掩碼值,方法是取值儲存在符號 Kd_XXXX_Mask,其中 XXXX 是所需的元件名稱。 您可以使用 dd (Display DWORD) 命令在 WinDbg 或 KD 中顯示此遮罩的值,或使用 ed (Enter DWORD) 命令輸入新的元件篩選遮罩。 如果有符號模棱兩可的危險,您可能想要將此符號指定為 nt!Kd_XXXX_Mask

儲存在登錄中的篩選遮罩會在開機期間生效。 調試程式所建立的篩選遮罩會立即生效,並持續到 Windows 重新啟動為止。 調試程式可以覆寫登錄中設定的值,但如果系統重新啟動,元件篩選遮罩會傳回登錄中指定的值。

還有一個全系統遮罩,名為WIN2000。 這預設等於0x1,不過它可以透過登錄或調試程序變更,就像所有其他元件一樣。 執行篩選時,將每個元件篩選遮罩先與 WIN2000 遮罩進行 OR 運算。 特別是,這表示從未指定過遮罩的元件預設為0x1。

顯示訊息的準則

在內核模式程式代碼中呼叫 DbgPrintEx 時,Windows 會比較 Level 所指定的訊息重要性位字段與 ComponentId 所指定元件的篩選遮罩。

備註

回想一下,當 Level 參數介於 0 到 31 之間時,重要性位字段等於 1 <<Level。 但是,當 Level 參數為 32 或更高時,重要性位字段就等於 Level

Windows 會在重要性位字段和元件篩選遮罩上執行 AND 作業。 如果結果為非零,訊息會傳送至調試程式。

偵錯篩選範例

假設在上次開機之前,您已在 [ 偵錯列印篩選 ] 索引鍵中建立下列值:

  • IHVVIDEO,其值等於 DWORD 0x2

  • IHVBUS,等於 DWORD 0x7FF

現在,您會在核心調試程序中發出下列命令:

kd> ed Kd_IHVVIDEO_Mask 0x8 
kd> ed Kd_IHVAUDIO_Mask 0x7 

此時, IHVVIDEO 元件具有0x8的篩選遮罩、 IHVAUDIO 元件具有0x7的篩選遮罩,而 IHVBUS 元件具有0x7FF的篩選遮罩。

不過,由於這些遮罩會自動與 WIN2000 全系統遮罩進行邏輯 OR 結合(通常等於 0x1),因此 IHVVIDEO 遮罩實際上等於 0x9。 事實上,尚未設定篩選遮罩的元件(例如 IHVSTREAMINGDEFAULT)將具有0x1的篩選遮罩。

現在假設下列函式呼叫發生在各種驅動程式中:

DbgPrintEx( DPFLTR_IHVVIDEO_ID,  DPFLTR_INFO_LEVEL,   "First message.\n");
DbgPrintEx( DPFLTR_IHVAUDIO_ID,  7,                   "Second message.\n");
DbgPrintEx( DPFLTR_IHVBUS_ID,    DPFLTR_MASK | 0x10,  "Third message.\n");
DbgPrint( "Fourth message.\n");

第一則訊息的 Level 參數等於 DPFLTR_INFO_LEVEL,也就是 3。 由於這小於 32,因此會被視為位元移位,結果產生的重要性位字段為 0x8。 然後,這個值會與有效的 IHVVIDEO 元件篩選遮罩 0x9 進行與運算,並產生非零的結果。 因此,第一則訊息會傳送至調試程式。

第二則訊息的 Level 參數等於 7。 同樣地,這會被視為位元移位的結果,結果為重要性位字段0x80。 然後,這會使用 0x7 的 IHVAUDIO 元件篩選遮罩進行 ANDed,併產生零的結果。 因此,不會傳輸第二則訊息。

第三則訊息的 Level 參數等於 DPFLTR_MASK |0x10。 這大於 31,因此重要性位字段會設定為等於 Level 的值,換句話說,為 0x80000010。 接下來,這個值會與 0x7FF 的 IHVBUS 元件篩選遮罩進行 AND 運算,使結果不為零。 因此,第三則訊息會傳送至調試程式。

第四則訊息會傳遞至 DbgPrint ,而不是 DbgPrintEx。 在 Windows Server 2003 和舊版 Windows 中,傳遞至此例程的訊息一律會傳送。 在 Windows Vista 和更新版本的 Windows 中,傳遞至此例程的訊息一律會獲得預設篩選條件。 重要性位元欄位等於 1 << DPFLTR_INFO_LEVEL,也就是 0x00000008。 此例程的元件為 DEFAULT。 由於您尚未設定 DEFAULT 元件篩選遮罩,因此其值為 0x1。 當這與重要性位欄位進行 AND 運算時,結果為零。 因此,不會傳輸第四則訊息。

DbgPrint 緩衝區和調試程式

DbgPrint、DbgPrintExvDbgPrintEx、vDbgPrintExWithPrefixKdPrint 或 KdPrintEx 例程將訊息傳送至調試程式時,格式化的字串會傳送至 DbgPrint 緩衝區。 除非您使用 GFlags 的 Buffer DbgPrint Output 選項停用此顯示,否則此緩衝區的內容會立即顯示在 [調試程式命令] 視窗中。

在本機核心偵錯期間,以及此顯示已停用的任何其他時間,只能使用 !dbgprint 擴充功能命令來檢視 DbgPrint 緩衝區的內容。

DbgPrint、DbgPrintExvDbgPrintExvDbgPrintExWithPrefixKdPrint 或 KdPrintEx 的任何單一呼叫只會傳輸 512 位元組的資訊。 超過 512 個字節的任何輸出都遺失。 DbgPrint 緩衝區本身在自由組建的 Windows 上最多可保存 4 KB 的數據,而在檢查組建的 Windows 上最多可保存 32 KB 的數據。 在 Windows Server 2003 和更新版本的 Windows 上,您可以使用 KDbgCtrl 工具來改變 DbgPrint 緩衝區的大小。 此工具是適用於 Windows 的偵錯工具的一部分。

備註

在 Windows 10 版本 1803 之前,檢查過的組建可在舊版 Windows 上使用。 使用驅動程式驗證程式和 GFlags 之類的工具,檢查更新版本中的驅動程式程式代碼。

如果訊息因為 其 ComponentIdLevel 值而篩選掉,就不會在偵錯連線之間傳輸。 因此,在調試程式中無法顯示此訊息。