5c93f7883488c4373f3c0c8b2d4cf19d5c68251c
[reactos.git] / base / applications / drwtsn32 / stacktrace.cpp
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 }