網(wǎng)站首頁 編程語言 正文
文章目錄
- DPC_WATCHDOG_VIOLATION藍(lán)屏分析
- 1. 原理
- 1.1 DPC WATCHDOG
- 1.2 DPC超時時間獲取
- 2. 實(shí)例
- 2.1 分析
- 3. 總結(jié)
DPC_WATCHDOG_VIOLATION藍(lán)屏分析
在Windows 10之下,引入了DPC_WATCHDOG_VIOLATION
藍(lán)屏錯誤,這個錯誤引入的原因是為了防止內(nèi)核代碼處于錯誤狀態(tài)在DPC以及以上級別執(zhí)行太久,影響系統(tǒng)的穩(wěn)定性。
對于DPC_WATCHDOG_VIOLATION
這個藍(lán)屏錯誤碼,存在兩種類型(使用第一個參數(shù)來區(qū)分):
- 第一個參數(shù)為0表示單個DPC例程執(zhí)行超時了(A single DPC or ISR exceeded its time allotment)。
- 第一個參數(shù)為1表示系統(tǒng)在DPC上面執(zhí)行超時了(The system cumulatively spent an extended period of time at IRQL DISPATCH_LEVEL or above)。
這兩種藍(lán)屏代碼分別如下:
DPC_WATCHDOG_VIOLATION (133)
The DPC watchdog detected a prolonged run time at an IRQL of DISPATCH_LEVEL
or above.
Arguments:
Arg1: 0000000000000000, A single DPC or ISR exceeded its time allotment. The offending
component can usually be identified with a stack trace.
Arg2: 0000000000000501, The DPC time count (in ticks).
Arg3: 0000000000000500, The DPC time allotment (in ticks).
Arg4: fffff8077ff73358, cast to nt!DPC_WATCHDOG_GLOBAL_TRIAGE_BLOCK, which contains
additional information regarding this single DPC timeout
DPC_WATCHDOG_VIOLATION (133)
The DPC watchdog detected a prolonged run time at an IRQL of DISPATCH_LEVEL
or above.
Arguments:
Arg1: 0000000000000001, The system cumulatively spent an extended period of time at
DISPATCH_LEVEL or above. The offending component can usually be
identified with a stack trace.
Arg2: 0000000000001e00, The watchdog period.
Arg3: fffff80080705330, cast to nt!DPC_WATCHDOG_GLOBAL_TRIAGE_BLOCK, which contains
additional information regarding the cumulative timeout
Arg4: 0000000000000000
下面我們通過要給實(shí)例來探討一下DPC_WATCHDOG_VIOLATION
的基本原理以及分析過程。
1. 原理
1.1 DPC WATCHDOG
Windows對于系統(tǒng)運(yùn)行在DPC和中斷的時間做了相關(guān)限定,一般來說DPC不能運(yùn)行超過100MS,IRS不能運(yùn)行超過25MS(但是實(shí)際值卻比這個要高)。
在Windows中,通過KeAccumulateTicks
對運(yùn)行時間做相關(guān)限定,如下:
__int64 __fastcall KeAccumulateTicks(...)
{
//...
if (pcrb->NestingLevel == 2 && pcrb->DpcRoutineActive)
{
DpcTimeCount = pcrb->DpcTimeCount;
pcrb->DpcTime += KernelTime;
NewDpcTimeCount = DpcTimeCount + 1;
DpcTimeLimit = pcrb->DpcTimeLimit;
pcrb->DpcTimeCount = NewDpcTimeCount;
if (DpcTimeLimit)
{
//...
if (NewDpcTimeCount > DpcTimeLimit)
{
if (KeEnableWatchdogTimeout)
{
HvlInvokeHypervisorDebugger(3i64, 0i64);
if (!(_BYTE)KdDebuggerEnabled || (_BYTE)KdDebuggerNotPresent)
KeBugCheckEx(
0x133u,
0i64,
pcrb->DpcTimeCount,
pcrb->DpcTimeLimit,
(ULONG_PTR)&KeDpcWatchdogProfileGlobalTriageBlock);
}
pcrb->DpcTimeCount = 0;
KiResetGlobalDpcWatchdogProfiler(pcrb);
}
}
}
//...
if (Irql < 2u)
{
DpcWatchdogProfile = pcrb->DpcWatchdogProfile;
pcrb->DpcWatchdogCount = 0;
//...
goto Over;
}
DpcWatchdogPeriod = pcrb->DpcWatchdogPeriod;
NewDpcWatchdogCount = pcrb->DpcWatchdogCount + 1;
pcrb->DpcWatchdogCount = NewDpcWatchdogCount;
if (DpcWatchdogPeriod)
{
//...
if (DpcWatchdogCount >= DpcWatchdogPeriod)
{
if (KeEnableWatchdogTimeout)
{
HvlInvokeHypervisorDebugger(2i64, 0i64);
if (!(_BYTE)KdDebuggerEnabled || (_BYTE)KdDebuggerNotPresent)
KeBugCheckEx(0x133u,
1ui64,
pcrb->DpcWatchdogPeriod,
(ULONG_PTR)&KeDpcWatchdogProfileGlobalTriageBlock,
0i64);
}
}
}
//...
}
從這里看,如果超過時間并且KeEnableWatchdogTimeout
為真的話,那么引發(fā)133藍(lán)屏。那么KeEnableWatchdogTimeout
這個是什么時候初始化的呢?我們可以看到初始化的代碼如下:
char __fastcall KeInitSystem(int a1)
{
//...
if (!HviIsAnyHypervisorPresent())
KeEnableWatchdogTimeout = 1;
//...
}
HviIsAnyHypervisorPresent
這個函數(shù)返回cpuid指令是否由hypervisor實(shí)現(xiàn),如果不是的話,那么開啟WatchDog。
在上述中KeBugCheckEx
存在兩種情況:
- 如果是
pcrb->DpcRoutineActive
在DPC例程中,那么判斷是否DPC例程超時,DPC例程判斷使用的是PRCB中的DpcTimeCount
和DpcTimeLimitTicks
比較。 - 接著是判斷整體是否運(yùn)行在DPC基本下面,使用的是PRCB中的
DpcWatchdogCount
和DpcWatchdogPeriodTicks
。
由于DpcTimeCount
表示的是單個DPC例程的執(zhí)行時間,因此每一個DPC執(zhí)行的時候都會設(shè)置改值為0。
__int64 __fastcall KiExecuteAllDpcs(...)
{
//...
a1->DpcTimeCount = 0;
//...
}
1.2 DPC超時時間獲取
通過KeQueryDpcWatchdogInformation
可以獲取到當(dāng)前處理器的DPC超時時間信息,如下:
NTSTATUS KeQueryDpcWatchdogInformation(
PKDPC_WATCHDOG_INFORMATION WatchdogInformation
);
typedef struct _KDPC_WATCHDOG_INFORMATION {
ULONG DpcTimeLimit;
ULONG DpcTimeCount;
ULONG DpcWatchdogLimit;
ULONG DpcWatchdogCount;
ULONG Reserved;
} KDPC_WATCHDOG_INFORMATION, *PKDPC_WATCHDOG_INFORMATION;
其中:
-
DpcTimeLimit
: 當(dāng)前處理器單個延遲過程調(diào)用的時間限制。如果已禁用DPC超時,則此值設(shè)置為0。 -
DpcTimeCount
: 如果已啟用DPC超時,則本次延遲過程調(diào)用的使用時間。 -
DpcWatchdogLimit
: 一系列延遲過程調(diào)用所允許的總時間限制。如果已禁用DPC看門狗,則此值設(shè)置為零。 -
DpcWatchdogCount
: 如果啟用DPC看門狗,則當(dāng)前連續(xù)延遲過程調(diào)用序列的剩余時間值。
例如我們可以看到如下:
0: kd> dt nt!_KPRCB fffff8007bfe9180 DPC*
+0x3310 DpcRuntimeHistoryHashTable : 0xffffaf0c`1f0d5690 _RTL_HASH_TABLE
+0x3318 DpcRuntimeHistoryHashTableCleanupDpc : 0xffffaf0c`1f122c40 _KDPC
+0x3338 DpcDelegateThread : 0xffffaf0c`1f150140 _KTHREAD
+0x3340 DpcData : [2] _KDPC_DATA
+0x33a0 DpcStack : 0xfffff800`7c395fb0 Void
+0x33ac DpcRequestRate : 0
+0x33b4 DpcLastCount : 0x67518e
+0x33ba DpcRoutineActive : 0 ''
+0x33bc DpcRequestSummary : 0n131174
+0x33bc DpcRequestSlot : [2] 0n102
+0x33bc DpcNormalProcessingActive : 0y0
+0x33bc DpcNormalProcessingRequested : 0y1
+0x33bc DpcNormalThreadSignal : 0y1
+0x33bc DpcNormalTimerExpiration : 0y0
+0x33bc DpcNormalDpcPresent : 0y0
+0x33bc DpcNormalLocalInterrupt : 0y1
+0x33bc DpcNormalPriorityAntiStarvation : 0y1
+0x33bc DpcNormalSwapToDpcDelegate : 0y0
+0x33bc DpcNormalSpare : 0y00000000 (0)
+0x33bc DpcThreadActive : 0y0
+0x33bc DpcThreadRequested : 0y1
+0x33bc DpcThreadSpare : 0y00000000000000 (0)
+0x7e40 DpcGate : _KGATE
+0x7ea8 DpcWatchdogPeriodTicks : 0n7680
+0x7eac DpcWatchdogCount : 0n7680
+0x7eb4 DpcWatchdogProfileCumulativeDpcThresholdTicks : 0x1b80
+0x7eec DpcWatchdogSequenceNumber : 0x18794c
+0x814c DpcTime : 0x4c56
+0x815c DpcTimeCount : 0
+0x8160 DpcTimeLimitTicks : 0x500
+0x8240 DpcWatchdogProfileSingleDpcThresholdTicks : 0x496
+0x85d8 DpcWatchdogDpc : _KDPC
+0x8618 DpcWatchdogTimer : _KTIMER
+0x88a8 DpcWatchdogProfile : 0xffffaf0c`1f16a000 -> 0x00000000`00000011 Void
+0x88b0 DpcWatchdogProfileCurrentEmptyCapture : 0xffffaf0c`1f181cf8 -> (null)
綜上,針對DPC的監(jiān)控有兩個:
- 使用
DpcTimeCount
和DpcTimeLimitTicks
來監(jiān)控單個DPC例程執(zhí)行的時間,防止DPC例程執(zhí)行過長。 - 使用
DpcWatchdogCount
和DpcWatchdogPeriodTicks
來監(jiān)控CPU執(zhí)行的DPC時間總和,防止CPU一直執(zhí)行一系列DPC函數(shù)。
2. 實(shí)例
下面我們通過一個DPC_WATCHDOG_VIOLATION
藍(lán)屏轉(zhuǎn)儲文件來進(jìn)行實(shí)例分析。
2.1 分析
我們先來看一下藍(lán)屏代碼DPC_WATCHDOG_VIOLATION
,如下:
DPC_WATCHDOG_VIOLATION (133)
The DPC watchdog detected a prolonged run time at an IRQL of DISPATCH_LEVEL
or above.
Arguments:
Arg1: 0000000000000001, The system cumulatively spent an extended period of time at
DISPATCH_LEVEL or above. The offending component can usually be
identified with a stack trace.
Arg2: 0000000000001e00, The watchdog period.
Arg3: fffff80080705330, cast to nt!DPC_WATCHDOG_GLOBAL_TRIAGE_BLOCK, which contains
additional information regarding the cumulative timeout
Arg4: 0000000000000000
此時調(diào)用堆棧如下:
0: kd> k
# Child-SP RetAddr Call Site
00 fffff800`7c39cdd8 fffff800`7fc31c8f nt!KeBugCheckEx
01 fffff800`7c39cde0 fffff800`7fc318a1 nt!KeAccumulateTicks+0x20f
02 fffff800`7c39ce50 fffff800`7fc2fa8a nt!KiUpdateRunTime+0x61
03 fffff800`7c39ceb0 fffff800`7fc2f876 nt!KeClockInterruptNotify+0x11a
04 fffff800`7c39cf40 fffff800`7fc14650 nt!HalpTimerClockIpiRoutine+0x16
05 fffff800`7c39cf70 fffff800`7fe1e05a nt!KiCallInterruptServiceRoutine+0xa0
06 fffff800`7c39cfb0 fffff800`7fe1e8c7 nt!KiInterruptSubDispatchNoLockNoEtw+0xfa
07 fffff882`a7a57430 fffff800`7fd67972 nt!KiInterruptDispatchNoLockNoEtw+0x37
08 fffff882`a7a575c0 fffff800`7fc6cb64 nt!KiAcquireKobjectLockSafe+0x32
09 fffff882`a7a575f0 fffff800`7fc44136 nt!KeSetEvent+0x64
0a fffff882`a7a57680 fffff800`7fc18496 nt!IopCompleteRequest+0x396
0b fffff882`a7a57760 fffff800`7fc70846 nt!KiDeliverApc+0x1b6
0c fffff882`a7a57820 fffff800`7fc72169 nt!KiSwapThread+0x936
0d fffff882`a7a57900 fffff800`7fc75e26 nt!KiCommitThreadWait+0x159
0e fffff882`a7a579a0 fffff800`8cce1cc1 nt!KeDelayExecutionThread+0x416
0f fffff882`a7a57a30 fffff800`8cce3b7a xxxDrv_x64+0x1cc1
10 fffff882`a7a57a60 fffff800`7fd54295 xxxDrv_x64+0x3b7a
11 fffff882`a7a57af0 fffff800`7fe20e34 nt!PspSystemThreadStartup+0x55
12 fffff882`a7a57b40 00000000`00000000 nt!KiStartSystemThread+0x34
這里我們可以得出的是藍(lán)屏并不是執(zhí)行某個DPC例程導(dǎo)致的時間夠長,而是該CPU在DPC模式下面執(zhí)行過長。
此時我們看到DCP的時間如下:
0: kd> dt nt!_KPRCB fffff8007bfe9180 DPC*
+0x7ea8 DpcWatchdogPeriodTicks : 0n7680
+0x7eac DpcWatchdogCount : 0n7680
+0x815c DpcTimeCount : 0
+0x8160 DpcTimeLimitTicks : 0x500
從這里我們也可以發(fā)現(xiàn):
-
DpcTimeCount
為0,說明我們沒有執(zhí)行DPC例程。 -
DpcWatchdogCount
和DpcWatchdogPeriodTicks
相等,說明CPU在DPC下面執(zhí)行時間過長。
我們可以看一下當(dāng)前DPC的信息,如下:
0: kd> !dpcs 0
CPU Type KDPC Function
0: Normal : 0xffffaf0c32787278 0xfffff8007fe56420 nt!IopPassiveInterruptDpc
0: Normal : 0xffffaf0c21e7b520 0xfffff80082092550 Wdf01000!FxInterrupt::_InterruptDpcThunk
0: Normal : 0xffffaf0c23ce9808 0xfffff80082c314d0 ndis!ndisInterruptDpc
0: Normal : 0xffffaf0c21eb26e8 0xfffff800858666c0 dxgkrnl!DpiFdoDpcForIsr
0: Normal : 0xfffff882acf91f60 0xfffff8007fc13ff0 nt!PopExecuteProcessorCallback
0: Normal : 0xfffff8007bff15d8 0xfffff8007fc26b60 nt!PpmPerfAction
0: Normal : 0xffffaf0c2173a0c8 0xfffff80082ec51d0 tcpip!TcpPeriodicTimeoutHandler
0: Normal : 0xffffaf0c211f71e8 0xfffff80082732000 stornvme!NVMeCompletionDpcRoutine
0: Normal : 0xfffff8007bff1c68 0xfffff8007fd4c800 nt!KiEntropyDpcRoutine
0: Normal : 0xfffff882a8ab6f60 0xfffff8007fc13ff0 nt!PopExecuteProcessorCallback
0: Normal : 0xfffff882ad376f60 0xfffff8007fc13ff0 nt!PopExecuteProcessorCallback
0: Normal : 0xffffaf0c1f122c40 0xfffff8007fd3fd30 nt!KiDpcRuntimeHistoryHashTableCleanupDpcRoutine
0: Normal : 0xffffaf0c231d0de0 0xfffff80082092550 Wdf01000!FxInterrupt::_InterruptDpcThunk
0: Normal : 0xffffaf0c21d93db0 0xfffff800b332b470 i8042prt!I8042KeyboardIsrDpc
0: Normal : 0xffffaf0c23ce9a48 0xfffff80082c314d0 ndis!ndisInterruptDpc
0: Normal : 0xfffff882a8476f60 0xfffff8007fc13ff0 nt!PopExecuteProcessorCallback
0: Normal : 0xffffaf0c21233000 0xfffff8008278c0f0 storport!RaidpAdapterRedirectDpcRoutine
0: Normal : 0xffffaf0c23081270 0xfffff800ae096d90 Ndu!NduQueryStatisticsDpc
0: Normal : 0xfffff882a7f26f60 0xfffff8007fc13ff0 nt!PopExecuteProcessorCallback
0: Normal : 0xfffff882ac1a6f60 0xfffff8007fc13ff0 nt!PopExecuteProcessorCallback
0: Threaded: 0xfffff8007bff1758 0xfffff8007fd59dc0 nt!KiDpcWatchdog
發(fā)現(xiàn)大量DPC,為什么呢?導(dǎo)致DPC執(zhí)行不了的一個原因是CPU一直處于高IRQL下面,例如中斷,是不是CPU一直處于中斷下面呢?
我們可以使用!dpcwatchdog
查看dpcwatchdog的情況,如下:
0: kd> !dpcwatchdog
All durations are in seconds (1 System tick = 15.625000 milliseconds)
Circular Kernel Context Logger history: !logdump 0x2
DPC and ISR stats: !intstats /d
--------------------------------------------------
CPU#0
--------------------------------------------------
Current DPC: No Active DPC
Pending DPCs:
----------------------------------------
CPU Type KDPC Function
0: Normal : 0xffffaf0c32787278 0xfffff8007fe56420 nt!IopPassiveInterruptDpc
0: Normal : 0xffffaf0c21e7b520 0xfffff80082092550 Wdf01000!FxInterrupt::_InterruptDpcThunk
0: Normal : 0xffffaf0c23ce9808 0xfffff80082c314d0 ndis!ndisInterruptDpc
0: Normal : 0xffffaf0c21eb26e8 0xfffff800858666c0 dxgkrnl!DpiFdoDpcForIsr
0: Normal : 0xfffff882acf91f60 0xfffff8007fc13ff0 nt!PopExecuteProcessorCallback
0: Normal : 0xfffff8007bff15d8 0xfffff8007fc26b60 nt!PpmPerfAction
0: Normal : 0xffffaf0c2173a0c8 0xfffff80082ec51d0 tcpip!TcpPeriodicTimeoutHandler
0: Normal : 0xffffaf0c211f71e8 0xfffff80082732000 stornvme!NVMeCompletionDpcRoutine
0: Normal : 0xfffff8007bff1c68 0xfffff8007fd4c800 nt!KiEntropyDpcRoutine
0: Normal : 0xfffff882a8ab6f60 0xfffff8007fc13ff0 nt!PopExecuteProcessorCallback
0: Normal : 0xfffff882ad376f60 0xfffff8007fc13ff0 nt!PopExecuteProcessorCallback
0: Normal : 0xffffaf0c1f122c40 0xfffff8007fd3fd30 nt!KiDpcRuntimeHistoryHashTableCleanupDpcRoutine
0: Normal : 0xffffaf0c231d0de0 0xfffff80082092550 Wdf01000!FxInterrupt::_InterruptDpcThunk
0: Normal : 0xffffaf0c21d93db0 0xfffff800b332b470 i8042prt!I8042KeyboardIsrDpc
0: Normal : 0xffffaf0c23ce9a48 0xfffff80082c314d0 ndis!ndisInterruptDpc
0: Normal : 0xfffff882a8476f60 0xfffff8007fc13ff0 nt!PopExecuteProcessorCallback
0: Normal : 0xffffaf0c21233000 0xfffff8008278c0f0 storport!RaidpAdapterRedirectDpcRoutine
0: Normal : 0xffffaf0c23081270 0xfffff800ae096d90 Ndu!NduQueryStatisticsDpc
0: Normal : 0xfffff882a7f26f60 0xfffff8007fc13ff0 nt!PopExecuteProcessorCallback
0: Normal : 0xfffff882ac1a6f60 0xfffff8007fc13ff0 nt!PopExecuteProcessorCallback
0: Threaded: 0xfffff8007bff1758 0xfffff8007fd59dc0 nt!KiDpcWatchdog
c0000094 Exception in kdexts.dpcwatchdog debugger extension.
PC: 00007ffa`507625c0 VA: 00000000`00000000 R/W: 0 Parameter: 00000000`00000000
同樣也可以看到大量Pending DPCs,Current DPC: No Active DPC。
3. 總結(jié)
DPC_WATCHDOG_VIOLATION
有兩種藍(lán)屏情況:
-
Parameter 1 = 0
說明當(dāng)前正在執(zhí)行DPC例程,并且超時了,可以直接看到DPC超時的原因(或者由于其他線程導(dǎo)致該DPC一直無法退出)。 -
Parameter 1 = 1
說明此時該CPU一直處于DPC狀態(tài)執(zhí)行,這個原因需要具體分析。
有兩個WinDBG命令可以協(xié)助分析該藍(lán)屏:
-
!dpcwatchdog
查看所有cpu的dpcwatchdog信息。 -
!dpcs
查看指定cpu的dpc例程信息。
原文鏈接:https://blog.csdn.net/xsinlink/article/details/133760020
- 上一篇:沒有了
- 下一篇:沒有了
相關(guān)推薦
- 2022-08-25 R語言行篩選的方法之filter函數(shù)詳解_R語言
- 2022-07-03 C++超詳細(xì)講解隱藏私有屬性和方法的兩種實(shí)現(xiàn)方式_C 語言
- 2022-04-09 IDEA中命令行安裝git報(bào)錯:error: failed to push some refs to
- 2022-03-19 Android使用DocumentFile讀寫外置存儲的問題_Android
- 2022-12-14 正則表達(dá)式(?=)正向先行斷言實(shí)戰(zhàn)案例_正則表達(dá)式
- 2022-04-20 Python設(shè)計(jì)模式結(jié)構(gòu)型享元模式_python
- 2022-08-27 一文讀懂Android?Kotlin的數(shù)據(jù)流_Android
- 2023-01-09 Pyscript使用本地Pyodide配置步驟_python
- 欄目分類
-
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支