您的位置:首页 > 其它

输出CallStack

2015-11-25 14:12 876 查看
在程序异常处理中有时需要输出CallStack,这就要用到DbgHelp

示例代码

#include <Windows.h>
#include <DbgHelp.h>
#include <stdio.h>

#pragma comment(lib, "dbghelp.lib")

void PrintCallStack(const CONTEXT * pContext)
{
HANDLE hProcess = GetCurrentProcess();

if (!SymInitialize(hProcess, NULL, TRUE)) {
exit(0);
}

HANDLE hThread = GetCurrentThread();

CONTEXT Context = *pContext;

struct ReadMemoryRoutine {
static BOOL CALLBACK Proc(HANDLE hProcess, DWORD64 lpBaseAddress, PVOID lpBuffer, DWORD nSize, LPDWORD lpNumberOfBytesRead) {
SIZE_T st;
BOOL bRet = ReadProcessMemory(hProcess, (LPVOID)lpBaseAddress, lpBuffer, nSize, &st);
*lpNumberOfBytesRead = st;
return bRet;
}
};

STACKFRAME64 StackFrame;
ZeroMemory(&StackFrame, sizeof(StackFrame));
StackFrame.AddrPC.Offset    = Context.Eip;
StackFrame.AddrPC.Mode      = AddrModeFlat;
StackFrame.AddrFrame.Offset = Context.Ebp;
StackFrame.AddrFrame.Mode   = AddrModeFlat;
StackFrame.AddrStack.Offset = Context.Esp;
StackFrame.AddrStack.Mode   = AddrModeFlat;
while (1) {
if (!StackWalk64(IMAGE_FILE_MACHINE_I386, hProcess, hThread, &StackFrame, &Context, &ReadMemoryRoutine::Proc, SymFunctionTableAccess64, SymGetModuleBase64, NULL)) {
break;
}
if (StackFrame.AddrPC.Offset == 0) {
break;
}
DWORD64 Displacement64;
ULONG64 buffer[(sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR) + sizeof(ULONG64) - 1) / sizeof(ULONG64)];
PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer;
pSymbol->SizeOfStruct = sizeof(buffer);
pSymbol->MaxNameLen = MAX_SYM_NAME;
if (!SymFromAddr(hProcess, StackFrame.AddrPC.Offset, &Displacement64, pSymbol)) {
strcpy_s(pSymbol->Name, MAX_SYM_NAME, "unknown symbol name");
}
DWORD Displacement;
IMAGEHLP_LINE64 Line;
ZeroMemory(&Line, sizeof(Line));
Line.SizeOfStruct = sizeof(Line);
if (!SymGetLineFromAddr64(hProcess, StackFrame.AddrPC.Offset, &Displacement, &Line)) {
Line.FileName = "unknown file name";
}
printf_s("%s (%u): %s\n", Line.FileName, Line.LineNumber, pSymbol->Name);
}
}

void WriteMiniDump(struct _EXCEPTION_POINTERS * pException) {
HANDLE hFile = CreateFileA("mini_dump.dmp", GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (INVALID_HANDLE_VALUE == hFile) {
exit(0);
}
MINIDUMP_EXCEPTION_INFORMATION cbif;
cbif.ThreadId = GetCurrentThreadId();
cbif.ClientPointers = TRUE;
cbif.ExceptionPointers = pException;
MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpNormal, &cbif, NULL, NULL);
CloseHandle(hFile);
}

static LONG WINAPI MyExceptionFilter(struct _EXCEPTION_POINTERS * pException) {

PrintCallStack(pException->ContextRecord);

WriteMiniDump(pException);

return EXCEPTION_EXECUTE_HANDLER;
}

int main(int argv, char ** argc)
{
SetUnhandledExceptionFilter(MyExceptionFilter);

_asm {cli};

return 0;
}


当需要在某个函数中输出调用堆栈,则可以这样

void foo(void)
{
CONTEXT Context;
RtlCaptureContext(&Context);
PrintCallStack(&Context);
}


但是由于RtlCaptureContext不包含顶层调用堆栈,所以还可以直接从汇编中获取Eip的方式

参见:http://jpassing.com/2008/03/12/walking-the-stack-of-the-current-thread/

void foo(void)
{
CONTEXT Context;
ZeroMemory( &Context, sizeof( CONTEXT ) );
Context.ContextFlags = CONTEXT_CONTROL;
__asm {
Label:
mov [Context.Ebp], ebp;
mov [Context.Esp], esp;
mov eax, [Label];
mov [Context.Eip], eax;
}
PrintCallStack(&Context);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: