dmp文件的分析,可以借助各种工具,比如WinDbg, CDB , NTSD,KD等。Windbg提供了窗口接口,而CDB , NTSD是基于命令行的工具,它们都使用了同样的调试引擎Dbgeng.dll,该调试引擎就是 “Windows 调试程序”。
dbgeng.dll 可以在基于x86,x64 或ARM的处理器上运行,并且可以调试在那些相同体系结构上运行的代码。
dbgeng.dll 的使用:
out.hpp
#ifndef __OUT_HPP__ #define __OUT_HPP__ #include <DbgEng.h> class StdioOutputCallbacks : public IDebugOutputCallbacks { public: // IUnknown. STDMETHOD(QueryInterface)( THIS_ _In_ REFIID InterfaceId, _Out_ PVOID* Interface ); STDMETHOD_(ULONG, AddRef)( THIS ); STDMETHOD_(ULONG, Release)( THIS ); // IDebugOutputCallbacks. STDMETHOD(Output)( THIS_ _In_ ULONG Mask, _In_ PCSTR Text ); }; extern StdioOutputCallbacks g_OutputCb; #endif // #ifndef __OUT_HPP__
out.cpp
#include <stdio.h> #include <windows.h> #include <dbgeng.h> #include "out.hpp" StdioOutputCallbacks g_OutputCb; FILE *fp = NULL; STDMETHODIMP StdioOutputCallbacks::QueryInterface( THIS_ _In_ REFIID InterfaceId, _Out_ PVOID* Interface ) { if (!fp) { fp = fopen("D:/ZZZ/analyze.txt", "w+"); } *Interface = NULL; if (IsEqualIID(InterfaceId, __uuidof(IUnknown)) || IsEqualIID(InterfaceId, __uuidof(IDebugOutputCallbacks))) { *Interface = (IDebugOutputCallbacks *)this; AddRef(); return S_OK; } else { return E_NOINTERFACE; } } STDMETHODIMP_(ULONG) StdioOutputCallbacks::AddRef( THIS ) { // This class is designed to be static so // there\'s no true refcount. return 1; } STDMETHODIMP_(ULONG) StdioOutputCallbacks::Release( THIS ) { // This class is designed to be static so // there\'s no true refcount. //fclose(fp); return 0; } STDMETHODIMP StdioOutputCallbacks::Output( THIS_ _In_ ULONG Mask, _In_ PCSTR Text ) { UNREFERENCED_PARAMETER(Mask); //fputs(Text, fp); fputs(Text, stdout); return S_OK; }
main.cpp
#include "out.hpp" #include <stdlib.h> #include <stdio.h> #include <stdarg.h>
#include <windows.h> #include <dbgeng.h>
PSTR g_DumpFile; IDebugClient* g_Client; IDebugControl* g_Control; IDebugSymbols3* g_Symbols3; void Exit(int Code, _In_ _Printf_format_string_ PCSTR Format, ...) { // Clean up any resources. if (g_Symbols3 != NULL) { g_Symbols3->Release(); } if (g_Control != NULL) { g_Control->Release(); } if (g_Client != NULL) { g_Client->SetOutputCallbacks(NULL); g_Client->EndSession(DEBUG_END_PASSIVE); g_Client->Release(); } // Output an error message if given. if (Format != NULL) { va_list Args; va_start(Args, Format); vfprintf(stderr, Format, Args); va_end(Args); } exit(Code); } void CreateInterfaces(void) { HRESULT Status; // Start things off by getting an initial interface from // the engine. This can be any engine interface but is // generally IDebugClient as the client interface is // where sessions are started. if ((Status = DebugCreate(__uuidof(IDebugClient), (void**)&g_Client)) != S_OK) { Exit(1, "DebugCreate failed, 0x%X\n", Status); } // Query for some other interfaces that we\'ll need. if ((Status = g_Client->QueryInterface(__uuidof(IDebugControl), (void**)&g_Control)) != S_OK || (Status = g_Client->QueryInterface(__uuidof(IDebugSymbols3), (void**)&g_Symbols3)) != S_OK) { Exit(1, "QueryInterface failed, 0x%X\n", Status); } } //typedef _Null_terminated_ CHAR *TTPSTR; void ParseCommandLine(int Argc, _In_reads_(Argc) PSTR* Argv) { int i; while (--Argc > 0) { Argv++; if (!strcmp(Argv[0], "-z")) { Argv++; Argc--; if (Argc > 0) { g_DumpFile = Argv[0]; } else { Exit(1, "-z missing argument\n"); } } else { //Exit(1, "Unknown command line argument \'%s\'\n", Argv[0]); } } if (g_DumpFile == NULL) { Exit(1, "No dump file specified, use -z <file>\n"); } } void ApplyCommandLineArguments(void) { HRESULT Status; // Install output callbacks so we get any output that the // later calls produce. if ((Status = g_Client->SetOutputCallbacks(&g_OutputCb)) != S_OK) { Exit(1, "SetOutputCallbacks failed, 0x%X\n", Status); } // Everything\'s set up so open the dump file. if ((Status = g_Client->OpenDumpFile(g_DumpFile)) != S_OK) { Exit(1, "OpenDumpFile failed, 0x%X\n", Status); } // Finish initialization by waiting for the event that // caused the dump. This will return immediately as the // dump file is considered to be at its event. if ((Status = g_Control->WaitForEvent(DEBUG_WAIT_DEFAULT, INFINITE)) != S_OK) { Exit(1, "WaitForEvent failed, 0x%X\n", Status); } // Everything is now initialized and we can make any // queries we want. } void DumpStack(void) { HRESULT Status; DEBUG_STACK_FRAME Frames[3] = { 0 }; ULONG Filled; g_Symbols3->SetScopeFromStoredEvent(); if (Frames == NULL) { Exit(1, "Unable to allocate stack frames\n"); } if ((Status = g_Control-> GetStackTrace(0, 0, 0, Frames, 3, &Filled)) != S_OK) { Exit(1, "GetStackTrace failed, 0x%X\n", Status); } printf("\nFirst %d frames of the call stack:\n", Filled); //// Print the call stack. if ((Status = g_Control-> OutputStackTrace(DEBUG_OUTCTL_ALL_CLIENTS, Frames, Filled, DEBUG_STACK_ARGUMENTS | DEBUG_STACK_SOURCE_LINE | DEBUG_STACK_FRAME_ADDRESSES | DEBUG_STACK_COLUMN_NAMES | DEBUG_STACK_FRAME_NUMBERS)) != S_OK) { Exit(1, "OutputStackTrace failed, 0x%X\n", Status); } } int main(int argc, char *argv[]) { CreateInterfaces(); ParseCommandLine(argc, argv); ApplyCommandLineArguments(); DumpStack(); return 0; }