1 /* 2 * PROJECT: Dr. Watson crash reporter 3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) 4 * PURPOSE: Print a stacktrace 5 * COPYRIGHT: Copyright 2017 Mark Jansen (mark.jansen@reactos.org) 6 */ 7 8 #include "precomp.h" 9 #include <dbghelp.h> 10 11 12 void BeginStackBacktrace(DumpData& data) 13 { 14 DWORD symOptions = SymGetOptions(); 15 symOptions |= SYMOPT_UNDNAME | SYMOPT_AUTO_PUBLICS | SYMOPT_DEFERRED_LOADS; 16 SymSetOptions(symOptions); 17 SymInitialize(data.ProcessHandle, NULL, TRUE); 18 } 19 20 void EndStackBacktrace(DumpData& data) 21 { 22 SymCleanup(data.ProcessHandle); 23 } 24 25 static char ToChar(UCHAR data) 26 { 27 if (data < 0xa) 28 return '0' + data; 29 else if (data <= 0xf) 30 return 'a' + data - 0xa; 31 return '?'; 32 } 33 34 void PrintStackBacktrace(FILE* output, DumpData& data, ThreadData& thread) 35 { 36 DWORD MachineType; 37 STACKFRAME64 StackFrame = { { 0 } }; 38 39 #ifdef _M_X64 40 MachineType = IMAGE_FILE_MACHINE_AMD64; 41 StackFrame.AddrPC.Offset = thread.Context.Rip; 42 StackFrame.AddrPC.Mode = AddrModeFlat; 43 StackFrame.AddrStack.Offset = thread.Context.Rsp; 44 StackFrame.AddrStack.Mode = AddrModeFlat; 45 StackFrame.AddrFrame.Offset = thread.Context.Rbp; 46 StackFrame.AddrFrame.Mode = AddrModeFlat; 47 #else 48 MachineType = IMAGE_FILE_MACHINE_I386; 49 StackFrame.AddrPC.Offset = thread.Context.Eip; 50 StackFrame.AddrPC.Mode = AddrModeFlat; 51 StackFrame.AddrStack.Offset = thread.Context.Esp; 52 StackFrame.AddrStack.Mode = AddrModeFlat; 53 StackFrame.AddrFrame.Offset = thread.Context.Ebp; 54 StackFrame.AddrFrame.Mode = AddrModeFlat; 55 #endif 56 57 58 #define STACKWALK_MAX_NAMELEN 512 59 char buf[sizeof(SYMBOL_INFO) + STACKWALK_MAX_NAMELEN] = {0}; 60 SYMBOL_INFO* sym = (SYMBOL_INFO *)buf; 61 IMAGEHLP_MODULE64 Module = { 0 }; 62 sym->SizeOfStruct = sizeof(sym); 63 64 /* FIXME: Disasm function! */ 65 66 xfprintf(output, NEWLINE "*----> Stack Back Trace <----*" NEWLINE NEWLINE); 67 bool first = true; 68 ULONG_PTR LastFrame = StackFrame.AddrFrame.Offset - 8; 69 while(StackWalk64(MachineType, data.ProcessHandle, thread.Handle, &StackFrame, &thread.Context, 70 NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL)) 71 { 72 if (!StackFrame.AddrPC.Offset) 73 break; 74 75 if (LastFrame >= StackFrame.AddrFrame.Offset) 76 break; 77 78 LastFrame = StackFrame.AddrFrame.Offset; 79 80 if (first) 81 { 82 xfprintf(output, "FramePtr ReturnAd Param#1 Param#2 Param#3 Param#4 Function Name" NEWLINE); 83 first = false; 84 } 85 86 Module.SizeOfStruct = sizeof(Module); 87 DWORD64 ModBase = SymGetModuleBase64(data.ProcessHandle, StackFrame.AddrPC.Offset); 88 if (!SymGetModuleInfo64(data.ProcessHandle, ModBase, &Module)) 89 strcpy(Module.ModuleName, "<nomod>"); 90 91 memset(sym, '\0', sizeof(*sym) + STACKWALK_MAX_NAMELEN); 92 sym->SizeOfStruct = sizeof(*sym); 93 sym->MaxNameLen = STACKWALK_MAX_NAMELEN; 94 DWORD64 displacement; 95 96 if (!SymFromAddr(data.ProcessHandle, StackFrame.AddrPC.Offset, &displacement, sym)) 97 strcpy(sym->Name, "<nosymbols>"); 98 99 xfprintf(output, "%p %p %p %p %p %p %s!%s" NEWLINE, 100 (ULONG_PTR)StackFrame.AddrFrame.Offset, (ULONG_PTR)StackFrame.AddrPC.Offset, 101 (ULONG_PTR)StackFrame.Params[0], (ULONG_PTR)StackFrame.Params[1], 102 (ULONG_PTR)StackFrame.Params[2], (ULONG_PTR)StackFrame.Params[3], 103 Module.ModuleName, sym->Name); 104 } 105 106 UCHAR stackData[0x10 * 10]; 107 SIZE_T sizeRead; 108 #if defined(_M_IX86) 109 ULONG_PTR stackPointer = thread.Context.Esp; 110 #elif defined(_M_AMD64) 111 ULONG_PTR stackPointer = thread.Context.Rsp; 112 #else 113 #error Unknown architecture 114 #endif 115 if (!ReadProcessMemory(data.ProcessHandle, (PVOID)stackPointer, stackData, sizeof(stackData), &sizeRead)) 116 return; 117 118 xfprintf(output, NEWLINE "*----> Raw Stack Dump <----*" NEWLINE NEWLINE); 119 for (size_t n = 0; n < sizeof(stackData); n += 0x10) 120 { 121 char HexData1[] = "?? ?? ?? ?? ?? ?? ?? ??"; 122 char HexData2[] = "?? ?? ?? ?? ?? ?? ?? ??"; 123 char AsciiData1[] = "????????"; 124 char AsciiData2[] = "????????"; 125 126 for (size_t j = 0; j < 8; ++j) 127 { 128 size_t idx = j + n; 129 if (idx < sizeRead) 130 { 131 HexData1[j * 3] = ToChar(stackData[idx] >> 4); 132 HexData1[j * 3 + 1] = ToChar(stackData[idx] & 0xf); 133 AsciiData1[j] = isprint(stackData[idx]) ? stackData[idx] : '.'; 134 } 135 idx += 8; 136 if (idx < sizeRead) 137 { 138 HexData2[j * 3] = ToChar(stackData[idx] >> 4); 139 HexData2[j * 3 + 1] = ToChar(stackData[idx] & 0xf); 140 AsciiData2[j] = isprint(stackData[idx]) ? stackData[idx] : '.'; 141 } 142 } 143 144 xfprintf(output, "%p %s - %s %s%s" NEWLINE, stackPointer+n, HexData1, HexData2, AsciiData1, AsciiData2); 145 } 146 } 147