Windows下如何通过IDebugClient编程从dump文件中获取进程名称
Windows调试API直接获取进程名及崩溃相关模块名的方案
1 获取PROCESS_NAME
PROCESS_NAME对应Dump文件中被调试进程的主可执行文件名称,有两种可靠实现方式,优先级从高到低:
1.1 直接调用系统对象接口获取(最优方案)
通过IDebugSystemObjects4接口的GetCurrentProcessExecutableName方法直接获取,返回结果和WinDbg的!analyze -v输出的PROCESS_NAME完全一致,不需要遍历模块。
示例代码:
#include <dbgeng.h> #pragma comment(lib, "dbgeng.lib") // 此处省略IDebugClient、IDebugControl等基础接口初始化逻辑 IDebugSystemObjects4* pSysObj = nullptr; HRESULT hr = pDebugClient->QueryInterface(__uuidof(IDebugSystemObjects4), (void**)&pSysObj); if (SUCCEEDED(hr)) { char procName[MAX_PATH] = {0}; ULONG nameSize = 0; hr = pSysObj->GetCurrentProcessExecutableName(procName, MAX_PATH, &nameSize); if (SUCCEEDED(hr)) { // procName即为所需的PROCESS_NAME printf("PROCESS_NAME: %s\n", procName); } pSysObj->Release(); }
1.2 遍历模块兜底方案
如果部分精简Minidump不支持上述接口,可以通过以下逻辑定位主模块:
- 调用
IDebugSystemObjects::GetCurrentProcessPeb获取进程PEB地址,读取PEB的ImageBaseAddress字段拿到主模块基址 - 用拿到的主模块基址调用
GetModuleNames获取可执行文件名,结果和PROCESS_NAME一致
2 获取IMAGE_NAME和MODULE_NAME
WinDbg的!analyze -v输出中,IMAGE_NAME是触发崩溃的指令所在模块的完整镜像名,MODULE_NAME是该模块的短名称,获取逻辑如下:
- 调用
IDebugControl::GetLastEventInformation获取崩溃事件的异常信息,拿到崩溃发生时的指令指针(RIP/EIP/PC) - 调用
IDebugSymbols3::GetModuleByOffset,传入指令指针地址,查询到该地址所属的模块基址和索引 - 调用
GetModuleNames传入上述模块基址,返回的ImageNameBuffer即为IMAGE_NAME,ModuleNameBuffer即为MODULE_NAME
示例代码:
DEBUG_LAST_EVENT_INFO_EXCEPTION exceptionInfo = {0}; ULONG infoSize = 0; // 先查询异常信息大小 hr = pDebugControl->GetLastEventInformation(NULL, NULL, NULL, 0, NULL, &infoSize, NULL, 0, NULL); if (SUCCEEDED(hr) && infoSize >= sizeof(DEBUG_LAST_EVENT_INFO_EXCEPTION)) { // 读取异常详情 hr = pDebugControl->GetLastEventInformation(NULL, NULL, NULL, sizeof(exceptionInfo), &exceptionInfo, NULL, NULL, 0, NULL); if (SUCCEEDED(hr)) { ULONG64 crashIp = (ULONG64)exceptionInfo.ExceptionRecord.ExceptionAddress; ULONG moduleIndex = 0; ULONG64 moduleBase = 0; // 根据崩溃指令地址查询所属模块 hr = pSymbols->GetModuleByOffset(crashIp, 0, &moduleIndex, &moduleBase); if (SUCCEEDED(hr)) { char ImageNameBuffer[MAX_PATH] = {0}, ModuleNameBuffer[MAX_PATH] = {0}; ULONG ImageNameSize = 0, ModuleNameSize = 0; hr = pSymbols->GetModuleNames(DEBUG_ANY_ID, moduleBase, ImageNameBuffer, MAX_PATH, &ImageNameSize, ModuleNameBuffer, MAX_PATH, &ModuleNameSize, NULL, 0, NULL); if (SUCCEEDED(hr)) { printf("IMAGE_NAME: %s\n", ImageNameBuffer); printf("MODULE_NAME: %s\n", ModuleNameBuffer); } } } }
注意事项
不要直接遍历所有模块按索引取名称,只有定位到对应业务场景的模块(主进程模块/崩溃触发模块)后查询的名称,才会和WinDbg的!analyze输出完全匹配。
内容的提问来源于stack exchange,提问作者Infant
相关产品推荐
相关产品推荐

