讀取和篩選偵錯訊息
DbgPrintEx、vDbgPrintEx、vDbgPrintExWithPrefix 和 KdPrintEx 例程會在您指定的條件下,將訊息傳送至核心調試程式。 此程式可讓您篩選出低優先順序的訊息。
備註
Microsoft Windows Server 2003 和舊版 Windows 中, DbgPrint 和 KdPrint 例程會無條件地將訊息傳送至核心調試程式。 在 Windows Vista 和更新版本的 Windows 中,這些例程會有條件地傳送訊息,例如 DbgPrintEx 和 KdPrintEx。 無論您使用的 Windows 版本為何,都應該使用 DbgPrintEx、vDbgPrintEx、vDbgPrintExWithPrefix 和 KdPrintEx,因為這些例程可讓您控制訊息傳送的條件。
篩選偵錯訊息
針對您要傳送至除錯程式的每個訊息,請在驅動程式的程式代碼中使用 DbgPrintEx、vDbgPrintEx、vDbgPrintExWithPrefix 或 KdPrintEx。 將適當的元件名稱傳遞至 ComponentId 參數,並將值傳遞至 Level 參數,以反映此訊息的嚴重性或本質。 訊息本身會使用與 printf 相同的語法傳遞至 Format 和自變數參數。
設定適當 元件篩選遮罩的值。 每個元件都有不同的遮罩。 遮罩值會決定顯示該元件的哪些訊息。 您可以使用登錄編輯器或在記憶體中使用內核調試程式,在登錄中設定元件篩選遮罩。
將核心調試程式附加至計算機。 每當驅動程式將訊息傳遞給 DbgPrintEx、vDbgPrintEx、vDbgPrintExWithPrefix 或 KdPrintEx 時,傳遞至 ComponentId 和 Level 的值都會與對應元件篩選遮罩的值進行比較。 如果這些值符合特定準則,訊息會傳送至核心調試程序並顯示。 否則,不會傳送任何訊息。
備註
此頁面對 DbgPrintEx 的所有參考都同樣適用於 KdPrintEx、vDbgPrintEx 和 vDbgPrintExWithPrefix。
識別元件名稱
每個元件都有個別的篩選遮罩。 這可讓調試程式個別設定每個元件的篩選。
每個元件的稱呼會因上下文而異。 在 DbgPrintEx 的 ComponentId 參數中,元件名稱前面加上 「DPFLTR_」,後綴為 「_ID」。。 在登錄中,元件篩選遮罩的名稱與元件本身相同。 在調試程式中,元件篩選遮罩的前綴為「Kd_」,後綴為「_Mask」。
Microsoft Windows 驅動程式套件 (WDK) 標頭 dpfilter.h 中有所有元件名稱的完整清單(DPFLTR_XXXX_ID格式)。 這些元件名稱大部分都保留給 Windows,以及Microsoft所撰寫的驅動程式。
有六個元件名稱保留給獨立硬體廠商。 若要避免將驅動程序的輸出與 Windows 元件的輸出混合,您應該使用下列其中一個元件名稱:
元件名稱 | 驅動程式類型 |
---|---|
IHVVIDEO | 視訊驅動程式 |
IHVAUDIO | 音訊驅動程式 |
IHVNETWORK | 網路驅動程式 |
IHVSTREAMING | 核心串流驅動程式 |
IHVBUS | 公交車司機 |
IHVDRIVER | 任何其他類型的驅動程式 |
例如,如果您要撰寫視訊驅動程式,您會使用 DPFLTR_IHVVIDEO_ID 作為 DbgPrintEx 的 ComponentId 參數、在登錄中使用值名稱 IHVVIDEO,並在調試程式中參考Kd_IHVVIDEO_Mask。
DbgPrint 和 KdPrint 傳送的所有訊息都會與 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。 如果設定此位,每當有人將核心調試程式附加至驅動程序執行所在的計算機時,就會檢視您的訊息。
警告、追蹤和資訊層級應該在適當情況下使用。 其他位可以自由用於您認為有用的任何目的。 這可讓您有各種不同的訊息類型,可選擇性地看到或隱藏。
DbgPrint 和 KdPrint 所傳送的所有訊息都與 Level 等於 DPFLTR_INFO_LEVEL 的 DbgPrintEx 和 KdPrintEx 訊息類似。 換句話說,這些訊息的其重要性位元欄位的第三位已設定。
設定元件過濾遮罩
有兩種方式可以設定元件篩選遮罩:
您可以在登錄檔機碼中存取元件篩選遮罩 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。 事實上,尚未設定篩選遮罩的元件(例如 IHVSTREAMING 或 DEFAULT)將具有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、DbgPrintEx、vDbgPrintEx、vDbgPrintExWithPrefix、KdPrint 或 KdPrintEx 例程將訊息傳送至調試程式時,格式化的字串會傳送至 DbgPrint 緩衝區。 除非您使用 GFlags 的 Buffer DbgPrint Output 選項停用此顯示,否則此緩衝區的內容會立即顯示在 [調試程式命令] 視窗中。
在本機核心偵錯期間,以及此顯示已停用的任何其他時間,只能使用 !dbgprint 擴充功能命令來檢視 DbgPrint 緩衝區的內容。
對 DbgPrint、DbgPrintEx、vDbgPrintEx、vDbgPrintExWithPrefix、KdPrint 或 KdPrintEx 的任何單一呼叫只會傳輸 512 位元組的資訊。 超過 512 個字節的任何輸出都遺失。 DbgPrint 緩衝區本身在自由組建的 Windows 上最多可保存 4 KB 的數據,而在檢查組建的 Windows 上最多可保存 32 KB 的數據。 在 Windows Server 2003 和更新版本的 Windows 上,您可以使用 KDbgCtrl 工具來改變 DbgPrint 緩衝區的大小。 此工具是適用於 Windows 的偵錯工具的一部分。
備註
在 Windows 10 版本 1803 之前,檢查過的組建可在舊版 Windows 上使用。 使用驅動程式驗證程式和 GFlags 之類的工具,檢查更新版本中的驅動程式程式代碼。
如果訊息因為 其 ComponentId 和 Level 值而篩選掉,就不會在偵錯連線之間傳輸。 因此,在調試程式中無法顯示此訊息。