mirror of
https://github.com/reactos/reactos.git
synced 2025-08-06 00:12:57 +00:00
[DRWTSN32] Implement basic crash report functionality
On application crash, drwtsn32 will attach to the application and try to get a dump, consisting of: - List of loaded modules - List of loaded threads - Per thread, a stacktrace - Per thread, a small hexdump from the stack - Per thread, a dump of the most common registers This dump is saved to the desktop, and the user is notified of the dump being dropped there. CORE-14180 #145
This commit is contained in:
parent
59aa6b9e74
commit
280d7a9775
8 changed files with 749 additions and 0 deletions
139
base/applications/drwtsn32/stacktrace.cpp
Normal file
139
base/applications/drwtsn32/stacktrace.cpp
Normal file
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
* PROJECT: Dr. Watson crash reporter
|
||||
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
|
||||
* PURPOSE: Print a stacktrace
|
||||
* COPYRIGHT: Copyright 2017 Mark Jansen (mark.jansen@reactos.org)
|
||||
*/
|
||||
|
||||
#include "precomp.h"
|
||||
#include <dbghelp.h>
|
||||
|
||||
|
||||
void BeginStackBacktrace(DumpData& data)
|
||||
{
|
||||
DWORD symOptions = SymGetOptions();
|
||||
symOptions |= SYMOPT_UNDNAME | SYMOPT_AUTO_PUBLICS | SYMOPT_DEFERRED_LOADS;
|
||||
SymSetOptions(symOptions);
|
||||
SymInitialize(data.ProcessHandle, NULL, TRUE);
|
||||
}
|
||||
|
||||
void EndStackBacktrace(DumpData& data)
|
||||
{
|
||||
SymCleanup(data.ProcessHandle);
|
||||
}
|
||||
|
||||
static char ToChar(UCHAR data)
|
||||
{
|
||||
if (data < 0xa)
|
||||
return '0' + data;
|
||||
else if (data <= 0xf)
|
||||
return 'a' + data - 0xa;
|
||||
return '?';
|
||||
}
|
||||
|
||||
void PrintStackBacktrace(FILE* output, DumpData& data, ThreadData& thread)
|
||||
{
|
||||
DWORD MachineType;
|
||||
STACKFRAME64 StackFrame = { { 0 } };
|
||||
|
||||
#ifdef _M_X64
|
||||
MachineType = IMAGE_FILE_MACHINE_AMD64;
|
||||
StackFrame.AddrPC.Offset = thread.Context.Rip;
|
||||
StackFrame.AddrPC.Mode = AddrModeFlat;
|
||||
StackFrame.AddrStack.Offset = thread.Context.Rsp;
|
||||
StackFrame.AddrStack.Mode = AddrModeFlat;
|
||||
StackFrame.AddrFrame.Offset = thread.Context.Rbp;
|
||||
StackFrame.AddrFrame.Mode = AddrModeFlat;
|
||||
#else
|
||||
MachineType = IMAGE_FILE_MACHINE_I386;
|
||||
StackFrame.AddrPC.Offset = thread.Context.Eip;
|
||||
StackFrame.AddrPC.Mode = AddrModeFlat;
|
||||
StackFrame.AddrStack.Offset = thread.Context.Esp;
|
||||
StackFrame.AddrStack.Mode = AddrModeFlat;
|
||||
StackFrame.AddrFrame.Offset = thread.Context.Ebp;
|
||||
StackFrame.AddrFrame.Mode = AddrModeFlat;
|
||||
#endif
|
||||
|
||||
|
||||
#define STACKWALK_MAX_NAMELEN 512
|
||||
char buf[sizeof(SYMBOL_INFO) + STACKWALK_MAX_NAMELEN] = {0};
|
||||
SYMBOL_INFO* sym = (SYMBOL_INFO *)buf;
|
||||
IMAGEHLP_MODULE64 Module = { 0 };
|
||||
sym->SizeOfStruct = sizeof(sym);
|
||||
|
||||
/* FIXME: Disasm function! */
|
||||
|
||||
xfprintf(output, NEWLINE "*----> Stack Back Trace <----*" NEWLINE NEWLINE);
|
||||
bool first = true;
|
||||
ULONG_PTR LastFrame = StackFrame.AddrFrame.Offset - 8;
|
||||
while(StackWalk64(MachineType, data.ProcessHandle, thread.Handle, &StackFrame, &thread.Context,
|
||||
NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL))
|
||||
{
|
||||
if (!StackFrame.AddrPC.Offset)
|
||||
break;
|
||||
|
||||
if (LastFrame >= StackFrame.AddrFrame.Offset)
|
||||
break;
|
||||
|
||||
LastFrame = StackFrame.AddrFrame.Offset;
|
||||
|
||||
if (first)
|
||||
{
|
||||
xfprintf(output, "FramePtr ReturnAd Param#1 Param#2 Param#3 Param#4 Function Name" NEWLINE);
|
||||
first = false;
|
||||
}
|
||||
|
||||
Module.SizeOfStruct = sizeof(Module);
|
||||
DWORD64 ModBase = SymGetModuleBase64(data.ProcessHandle, StackFrame.AddrPC.Offset);
|
||||
if (!SymGetModuleInfo64(data.ProcessHandle, ModBase, &Module))
|
||||
strcpy(Module.ModuleName, "<nomod>");
|
||||
|
||||
memset(sym, '\0', sizeof(*sym) + STACKWALK_MAX_NAMELEN);
|
||||
sym->SizeOfStruct = sizeof(*sym);
|
||||
sym->MaxNameLen = STACKWALK_MAX_NAMELEN;
|
||||
DWORD64 displacement;
|
||||
|
||||
if (!SymFromAddr(data.ProcessHandle, StackFrame.AddrPC.Offset, &displacement, sym))
|
||||
strcpy(sym->Name, "<nosymbols>");
|
||||
|
||||
xfprintf(output, "%p %p %p %p %p %p %s!%s" NEWLINE,
|
||||
(ULONG_PTR)StackFrame.AddrFrame.Offset, (ULONG_PTR)StackFrame.AddrPC.Offset,
|
||||
(ULONG_PTR)StackFrame.Params[0], (ULONG_PTR)StackFrame.Params[1],
|
||||
(ULONG_PTR)StackFrame.Params[2], (ULONG_PTR)StackFrame.Params[3],
|
||||
Module.ModuleName, sym->Name);
|
||||
}
|
||||
|
||||
UCHAR stackData[0x10 * 10];
|
||||
DWORD dwSizeRead;
|
||||
if (!ReadProcessMemory(data.ProcessHandle, (LPCVOID)thread.Context.Esp, stackData, sizeof(stackData), &dwSizeRead))
|
||||
return;
|
||||
|
||||
xfprintf(output, NEWLINE "*----> Raw Stack Dump <----*" NEWLINE NEWLINE);
|
||||
for (size_t n = 0; n < sizeof(stackData); n += 0x10)
|
||||
{
|
||||
char HexData1[] = "?? ?? ?? ?? ?? ?? ?? ??";
|
||||
char HexData2[] = "?? ?? ?? ?? ?? ?? ?? ??";
|
||||
char AsciiData1[] = "????????";
|
||||
char AsciiData2[] = "????????";
|
||||
|
||||
for (size_t j = 0; j < 8; ++j)
|
||||
{
|
||||
size_t idx = j + n;
|
||||
if (idx < dwSizeRead)
|
||||
{
|
||||
HexData1[j * 3] = ToChar(stackData[idx] >> 4);
|
||||
HexData1[j * 3 + 1] = ToChar(stackData[idx] & 0xf);
|
||||
AsciiData1[j] = isprint(stackData[idx]) ? stackData[idx] : '.';
|
||||
}
|
||||
idx += 8;
|
||||
if (idx < dwSizeRead)
|
||||
{
|
||||
HexData2[j * 3] = ToChar(stackData[idx] >> 4);
|
||||
HexData2[j * 3 + 1] = ToChar(stackData[idx] & 0xf);
|
||||
AsciiData2[j] = isprint(stackData[idx]) ? stackData[idx] : '.';
|
||||
}
|
||||
}
|
||||
|
||||
xfprintf(output, "%p %s - %s %s%s" NEWLINE, thread.Context.Esp+n, HexData1, HexData2, AsciiData1, AsciiData2);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue