如何通过 code/windows API 获取 BSOD 错误检查代码文本描述

How can I get the BSOD bugcheck code text description by code/windows API

我可以获得一个 BSOD 的 bugcheck 代码和参数。

然后我可以从 Bug Check Code Reference.

获取文本描述

但是我如何使用一些 windows API 或 c++ 代码从错误检查代码和参数中获取此类文本描述。

例如,对于 bugcheck 代码 0x9F,我怎样才能得到文本

DRIVER_POWER_STATE_FAILURE (9f) A driver has failed to complete a power IRP within a specific time.

使用某些 windows API 或从某些 DLL 中读取。

或者说,如何实现类似WinDbg的功能:

1: kd> !analyze -show 0x9F 0x3
DRIVER_POWER_STATE_FAILURE (9f)
A driver has failed to complete a power IRP within a specific time.
Arguments:
Arg1: 0000000000000003, A device object has been blocking an Irp for too long a time
Arg2: 0000000000000000, Physical Device Object of the stack
Arg3: 0000000000000000, nt!TRIAGE_9F_POWER on Win7 and higher, otherwise the Functional Device Object of the stack
Arg4: 0000000000000000, The blocked IRP

我看到有 API 像 KeGetBugMessageText(),但它被 Windows 自己保存了。

有人可以帮助解决这个问题并提供一些线索或建议吗?

更新: 用于执行带有 'blabb' 建议的命令的主要代码部分:

#pragma comment ( lib ,"dbgeng.lib")
#include <iostream>
#include <dbgeng.h>
#include "StdioOutputCallbacks.h"

//#include <wdbgexts.h>
//WINDBG_EXTENSION_APIS64 ExtensionApis;
StdioOutputCallbacks g_OutputCb;
int main()
{
    IDebugClient* DebugClient = NULL;
    HRESULT Hr = S_OK;

    if ((Hr = DebugCreate(__uuidof(IDebugClient),
       (void**)&DebugClient)) != S_OK) {
       return Hr;
    }
    
    PDEBUG_CONTROL DebugControl;
    if ((Hr = DebugClient->QueryInterface(__uuidof(IDebugControl),
       (void**)&DebugControl)) == S_OK) {
       DebugClient->SetOutputCallbacks(&g_OutputCb);

       Hr = DebugClient->OpenDumpFile("C:\Dev\Deem\bug\dcp938\MEMORY.DMP");
       if (Hr != S_OK) {
          return Hr;
       }
       
       DebugControl->Execute(DEBUG_OUTCTL_THIS_CLIENT, "!analyze -show 9f 3", DEBUG_EXECUTE_DEFAULT);
       DebugControl->Release();
    }
    // done
    DebugClient->Release();
}
and in outputcallback, kept as the msdn sample:
STDMETHODIMP
StdioOutputCallbacks::Output(
   THIS_
   _In_ ULONG Mask,
   _In_ PCSTR Text
)
{
   UNREFERENCED_PARAMETER(Mask);
   fputs(Text, stdout);
   return S_OK;
}

但是执行"!analyze -show 9f 3"(fputs()中Text的内容)的结果是"No export analyze found"。 我还尝试了命令“.opendump C:\...MEMORY.DMP;!analyze -show 9f 3”,opendump 命令正确执行,加载了 dmp 并得到文本输出,包括“用于分析此文件,运行 !analyze -v”,但“!analyze -v”和“!analyze -show ...”都得到“未找到导出分析”。 不带 '!' 的命令会导致命令解析错误。

我不确定你在找什么。 所有这些都是#defined in bugcodes.h in windows sdk/ddk

C:\Program Files (x86)\Windows Kits\Include>pss DRIVER_POWER_STATE_FAILURE
..0.17763.0\shared\bugcodes.h
1505:// MessageId: DRIVER_POWER_STATE_FAILURE
1509://  DRIVER_POWER_STATE_FAILURE
1511:#define DRIVER_POWER_STATE_FAILURE       ((ULONG)0x0000009FL)

或者反过来

C:\Program Files (x86)\Windows Kits\Include>grep -ir #define.*0x0000009fl --include *.h *
10.0.17763.0/shared/bugcodes.h:#define DRIVER_POWER_STATE_FAILURE       ((ULONG)0x0000009FL)  

或者使用 DbgEng 编写 WinDbg 扩展或独立的可执行文件。

打开转储->WaitForEvent->Executecommands !bugdump .bug****

或者您也可以探索 IDebugDataSpaces::****tag**** 阅读、开始、下一步、结束等方法。

编辑

Scott Noone 可能表示 ext.dll 内置的 windbg 扩展

如我所述,您可能需要编写 windbg 分析扩展作为扩展或独立
其中大部分是未记录或措辞不佳的文档

这里是在 ext.dll 中编译的 bugcheck 代码的转储,这可能是 scott noone 在他的回答中指出的。

0:000> dps ext!g_BugCheckApiRefs l10
00007ff9`4a45ccc0  00000000`00000001
00007ff9`4a45ccc8  00007ff9`49efead0 ext!BugCheckAPC_INDEX_MISMATCH
00007ff9`4a45ccd0  00000000`00000002
00007ff9`4a45ccd8  00007ff9`49efeb60 ext!BugCheckDEVICE_QUEUE_NOT_BUSY
00007ff9`4a45cce0  00000000`00000003
00007ff9`4a45cce8  00007ff9`49efebc0 ext!BugCheckINVALID_AFFINITY_SET
00007ff9`4a45ccf0  00000000`00000004
00007ff9`4a45ccf8  00007ff9`49efec20 ext!BugCheckINVALID_DATA_ACCESS_TRAP
00007ff9`4a45cd00  00000000`00000005
00007ff9`4a45cd08  00007ff9`49efec80 ext!BugCheckINVALID_PROCESS_ATTACH_ATTEMPT
00007ff9`4a45cd10  00000000`00000006
00007ff9`4a45cd18  00007ff9`49efece0 ext!BugCheckINVALID_PROCESS_DETACH_ATTEMPT
00007ff9`4a45cd20  00000000`00000007
00007ff9`4a45cd28  00007ff9`49efed40 ext!BugCheckINVALID_SOFTWARE_INTERRUPT
00007ff9`4a45cd30  00000000`00000008
00007ff9`4a45cd38  00007ff9`49efeda0 ext!BugCheckIRQL_NOT_DISPATCH_LEVEL
0:000>  

或者你的电源故障

0:000> .shell -ci "dps ext!g_BugCheckApiRefs l150" grep -A 1 -i 09f
00007ff9`4a45d600  00000000`0000009f
00007ff9`4a45d608  00007ff9`49f04450 ext!BugCheckDRIVER_POWER_STATE_FAILURE
.shell: Process exited
0:000>  

这里有一个完整的调用堆栈引导您查询有关 !analyze -show 9f 3

Child-SP          RetAddr           Call Site
000000d3`6d67b768 00007ff9`49fa302a ext!GetBugCheckDescription
000000d3`6d67b770 00007ff9`49f822c2 ext!DebugFailureAnalysis::ParseInputArgs+0xc66
000000d3`6d67bb00 00007ff9`49f549c5 ext!AnalyzeBugCheck+0x10a
000000d3`6d67bbd0 00007ff9`4ae0187d ext!analyze+0x4e5
000000d3`6d67bd90 00007ff9`4ae01a31 dbgeng!ExtensionInfo::CallA+0x27d
000000d3`6d67be50 00007ff9`4ae01d0e dbgeng!ExtensionInfo::Call+0x121
000000d3`6d67c050 00007ff9`4adff9d8 dbgeng!ExtensionInfo::CallAny+0x17a
000000d3`6d67c570 00007ff9`4ae43662 dbgeng!ParseBangCmd+0xe0c
000000d3`6d67cd30 00007ff9`4ae44635 dbgeng!ProcessCommands+0xcd6
000000d3`6d67ce20 00007ff9`4ad6baf7 dbgeng!ProcessCommandsAndCatch+0x79
000000d3`6d67ce90 00007ff9`4ad6be04 dbgeng!Execute+0x2bb
000000d3`6d67d380 00007ff6`4c7b62dc dbgeng!DebugClient::ExecuteWide+0x94
000000d3`6d67d3e0 00007ff6`4c7b879a kd!MainLoop+0x514
000000d3`6d67f460 00007ff6`4c7bb55d kd!wmain+0x3e6
000000d3`6d67f700 00007ff9`857c7c24 kd!__wmainCRTStartup+0x14d
000000d3`6d67f740 00007ff9`85d8d721 KERNEL32!BaseThreadInitThunk+0x14
000000d3`6d67f770 00000000`00000000 ntdll!RtlUserThreadStart+0x21
0:000>                                                            

该函数是一个简单的比较 return 例程,如

while array[i] != 0x9f skip 
return String array[i]+0x8 

详细说明由

完成
void PrintBugDescription(_BUGCHECK_ANALYSIS *param_1,DebugFailureAnalysis *param_2)

编辑 自从我上次发表评论以来,我一直在想

  1. 我如何在不编写代码的情况下处理这种情况
  2. 没有可操作的内核内存转储
  3. 可能可扩展到未知的远程机器

我想出了一个使用 sysinternals livekd.exe

的小型 python 包装器

脚本

:\>cat liv.py
import subprocess
import regex
foo = subprocess.run(
    [r"f:\sysint\livekd", "-b" ,"-c \"!analyze -show 9f 03;q\""],
    stdout=subprocess.PIPE,
    universal_newlines=True
    )
resta = regex.search("Reading" , foo.stdout).start()
reend = regex.search("quit:" , foo.stdout).end()
print(foo.stdout[resta:reend])

脚本执行结果

:\>python liv.py
Reading initial command '!analyze -show 9f 03;q'
*** ERROR: Module load completed but symbols could not be loaded for LiveKdD.SYS
DRIVER_POWER_STATE_FAILURE (9f)
A driver has failed to complete a power IRP within a specific time.
Arguments:
Arg1: 0000000000000003, A device object has been blocking an Irp for too long a time
Arg2: 0000000000000000, Physical Device Object of the stack
Arg3: 0000000000000000, nt!TRIAGE_9F_POWER on Win7 and higher, otherwise the Functional Device Object of the stack
Arg4: 0000000000000000, The blocked IRP
*******************************************************************************
*                                                                             *
*                        Bugcheck Analysis                                    *
*                                                                             *
*******************************************************************************

Use !analyze -v to get detailed debugging information.

BugCheck 0, {0, 0, 0, 0}

Probably caused by : LiveKdD.SYS ( LiveKdD+2f4f )

Followup:     MachineOwner
---------

quit:

添加另一个答案,因为先前的答案太混乱和评论。

预编译链接目录内容

F:\bugdesc>ls -lg
-rw-r--r-- 1 197121 156689581 Aug 17 23:49 MEMORY.DMP                                                                   
-rw-r--r-- 1 197121       600 Aug 26 01:22 bugdesc.cpp
-rw-r--r-- 1 197121       109 Aug 19 00:04 complink.bat
-rw-r--r-- 1 197121      1019 Aug 26 01:21 stdioimpl.h

bat 文件的内容

F:\bugdesc>cat complink.bat
cl  /nologo /W4 /Od  /Zi /EHsc /I"C:\Program Files (x86)\Windows Kits\Debuggers\inc" %1.cpp /link /RELEASE

包含 StdioOutputCallbacks 实现的文件

F:\bugdesc>cat stdioimpl.h
#include <windows.h>
#include <stdio.h>
#include <dbgeng.h>
#pragma comment(lib, "dbgeng.lib")
class StdioOutputCallbacks : public IDebugOutputCallbacks {
public:
    STDMETHOD(QueryInterface)(THIS_ _In_ REFIID ifid, _Out_ PVOID *iface);
    STDMETHOD_(ULONG, AddRef)(THIS);
    STDMETHOD_(ULONG, Release)(THIS);
    STDMETHOD(Output)(THIS_ IN ULONG Mask, IN PCSTR Text);
};
STDMETHODIMP
StdioOutputCallbacks::QueryInterface(THIS_ _In_ REFIID ifid, _Out_ PVOID *iface){
    *iface = NULL;
    if (IsEqualIID(ifid, __uuidof(IDebugOutputCallbacks))){
        *iface = (IDebugOutputCallbacks *)this;
        AddRef();
        return S_OK;
    }    else    {
        return E_NOINTERFACE;
    }
}
STDMETHODIMP_(ULONG)
StdioOutputCallbacks::AddRef(THIS) { return 1; }
STDMETHODIMP_(ULONG)
StdioOutputCallbacks::Release(THIS) { return 0; }
STDMETHODIMP StdioOutputCallbacks::Output(THIS_ IN ULONG, IN PCSTR Text){
    fputs(Text, stdout);
    return S_OK;
}

主要源文件的内容

F:\bugdesc>cat bugdesc.cpp
#include "stdioimpl.h"
//implement proper error handling and release of Interfaces
void __cdecl main(void)
{
    IDebugClient *g_Client;
    IDebugControl *g_Control;
    StdioOutputCallbacks g_OutputCb;
    DebugCreate(__uuidof(IDebugClient), (void **)&g_Client);
    g_Client->QueryInterface(__uuidof(IDebugControl), (void **)&g_Control);
    g_Client->SetOutputCallbacks(&g_OutputCb);
    g_Client->SetOutputCallbacks(&g_OutputCb);
    g_Client->OpenDumpFile("F:\bugdesc\memory.dmp");
    g_Control->WaitForEvent(0, INFINITE);
    g_Control->Execute(0, "!analyze -show 9f 3", 0);
}

编译并与 vs-community 2017 链接为 x64

F:\bugdesc>complink.bat bugdesc

F:\bugdesc>cl  /nologo /W4 /Od  /Zi /EHsc /I"C:\Program Files (x86)\Windows Kits\Debuggers\inc" bugdesc.cpp /link /RELEASE
bugdesc.cpp

目录内容post编译和链接

F:\bugdesc>ls -lg
total 159485
-rw-r--r-- 1 197121 156689581 Aug 17 23:49 MEMORY.DMP
-rw-r--r-- 1 197121       600 Aug 26 01:22 bugdesc.cpp
-rwxr-xr-x 1 197121    406016 Aug 26 01:25 bugdesc.exe
-rw-r--r-- 1 197121     30072 Aug 26 01:25 bugdesc.obj
-rw-r--r-- 1 197121   5992448 Aug 26 01:25 bugdesc.pdb
-rw-r--r-- 1 197121       109 Aug 19 00:04 complink.bat
-rw-r--r-- 1 197121      1019 Aug 26 01:21 stdioimpl.h
-rw-r--r-- 1 197121    176128 Aug 26 01:25 vc140.pdb

在没有正确的 dll 和失败的情况下执行

F:\bugdesc>bugdesc.exe
No .natvis files found at C:\WINDOWS\SYSTEM32\Visualizers.
xxxxxxxxxxxxxxxxxxxxxxxxxxx snip 
Microsoft (R) Windows Debugger Version 10.0.18362.1 AMD64
xxxxxxxxxxxxxxxxxxxxxxxxxxx snip
Loading Dump File [F:\bugdesc\memory.dmp]
xxxxxxxxxxxxxxxxxxxxxxxxxxx snip
***    Type referenced: nt!_MMPTE_TRANSITION                          ***
xxxxxxxxxxxxxxxxxxxxxxxxxxx snip
For analysis of this file, run !analyze -v
No export analyze found<<<<<<<<<<<<<<<<<<

正在从 windbg 安装文件夹中复制相关的 dll

F:\bugdesc>copy ..\windbg_dlls\*.* .
..\windbg_dlls\dbgeng.dll
..\windbg_dlls\dbghelp.dll
..\windbg_dlls\ext.dll
..\windbg_dlls\symsrv.dll
        4 file(s) copied.

执行并成功

F:\bugdesc>bugdesc.exe

Microsoft (R) Windows Debugger Version 10.0.17763.132 AMD64
xxxxxxxxxxxxxxxxxxxxxxxxxxx snip
Loading Dump File [F:\bugdesc\memory.dmp]
xxxxxxxxxxxxxxxxxxxxxxxxxxx snip
*******************************************************************************
*                                                                             *
*                        Bugcheck Analysis                                    *
*                                                                             *
*******************************************************************************

Use !analyze -v to get detailed debugging information.

BugCheck E2, {0, 0, 0, 0}

Probably caused by : Unknown_Image
 *** Followup info cannot be found !!! Please contact "BADEV"

---------

DRIVER_POWER_STATE_FAILURE (9f)<<<<<<<<<<<<<<<<<<<<<<<
A driver has failed to complete a power IRP within a specific time.
Arguments:
Arg1: 0000000000000003, A device object has been blocking an Irp for too long a time
Arg2: 0000000000000000, Physical Device Object of the stack
Arg3: 0000000000000000, nt!TRIAGE_9F_POWER on Win7 and higher, otherwise the Functional Device Object of the stack
Arg4: 0000000000000000, The blocked IRP
xxxxxxxxxxxxxxxxxxxxxxxxxxx snip