|
1
|
1 #include "shared.h"
|
|
|
2 #include <imagehlp.h>
|
|
|
3
|
|
|
4 #ifdef _M_ARM64EC
|
|
|
5 typedef ARM64EC_NT_CONTEXT myCONTEXT;
|
|
|
6 #else
|
|
|
7 typedef CONTEXT myCONTEXT;
|
|
|
8 #endif
|
|
|
9 struct DumpState {
|
|
|
10 int state;
|
|
|
11 myCONTEXT*context;
|
|
|
12 };
|
|
|
13
|
|
|
14 __declspec(noinline) static bool safeRead(volatile const void* addr, size_t& dest)
|
|
|
15 {
|
|
|
16 __try {
|
|
|
17 dest = *(const volatile size_t*)addr;
|
|
|
18 return true;
|
|
|
19 }
|
|
|
20 __except (1) {
|
|
|
21 return false;
|
|
|
22 }
|
|
|
23 }
|
|
|
24
|
|
|
25 __declspec(noinline) static bool safeTestReadAccess(volatile const void* addr)
|
|
|
26 {
|
|
|
27 size_t dummy;
|
|
|
28 return safeRead(addr, dummy);
|
|
|
29 }
|
|
|
30
|
|
|
31 #if defined(_M_ARM64) || defined(_M_ARM64EC)
|
|
|
32
|
|
|
33 BOOL WINAPI MiniDumpCallback(PVOID CallbackParam,
|
|
|
34 const PMINIDUMP_CALLBACK_INPUT CallbackInput,
|
|
|
35 PMINIDUMP_CALLBACK_OUTPUT CallbackOutput)
|
|
|
36 {
|
|
|
37 static const unsigned STACK_SEARCH_SIZE = 0x400;
|
|
|
38 static const unsigned MEM_BLOCK_SIZE = 0x400;
|
|
|
39
|
|
|
40 if (CallbackInput->CallbackType == MemoryCallback) {
|
|
|
41 // Called to get user defined blocks of memory to write until
|
|
|
42 // callback returns FALSE or CallbackOutput->MemorySize == 0.
|
|
|
43
|
|
|
44 DumpState* ds = (DumpState*)CallbackParam;
|
|
|
45 switch (ds->state) {
|
|
|
46 // Save memory referenced by registers.
|
|
|
47 case 0: CallbackOutput->MemoryBase = ds->context->X0; ds->state++; break;
|
|
|
48 case 1: CallbackOutput->MemoryBase = ds->context->X1; ds->state++; break;
|
|
|
49 case 2: CallbackOutput->MemoryBase = ds->context->X2; ds->state++; break;
|
|
|
50 case 3: CallbackOutput->MemoryBase = ds->context->X3; ds->state++; break;
|
|
|
51 case 4: CallbackOutput->MemoryBase = ds->context->X4; ds->state++; break;
|
|
|
52 case 5: CallbackOutput->MemoryBase = ds->context->X5; ds->state++; break;
|
|
|
53 case 6: CallbackOutput->MemoryBase = ds->context->X6; ds->state++; break;
|
|
|
54 case 7: CallbackOutput->MemoryBase = ds->context->X7; ds->state++; break;
|
|
|
55 case 8: CallbackOutput->MemoryBase = ds->context->X8; ds->state++; break;
|
|
|
56 case 9: CallbackOutput->MemoryBase = ds->context->X9; ds->state++; break;
|
|
|
57 case 10: CallbackOutput->MemoryBase = ds->context->X10; ds->state++; break;
|
|
|
58 case 11: CallbackOutput->MemoryBase = ds->context->X11; ds->state++; break;
|
|
|
59 case 12: CallbackOutput->MemoryBase = ds->context->X12; ds->state++; break;
|
|
|
60 #ifndef _M_ARM64EC
|
|
|
61 case 13: CallbackOutput->MemoryBase = ds->context->X13; ds->state++; break;
|
|
|
62 case 14: CallbackOutput->MemoryBase = ds->context->X14; ds->state++; break;
|
|
|
63 case 15: CallbackOutput->MemoryBase = ds->context->X15; ds->state++; break;
|
|
|
64 case 16: CallbackOutput->MemoryBase = ds->context->X16; ds->state++; break;
|
|
|
65 case 17: CallbackOutput->MemoryBase = ds->context->X17; ds->state++; break;
|
|
|
66 case 18: CallbackOutput->MemoryBase = ds->context->X18; ds->state++; break;
|
|
|
67 case 19: CallbackOutput->MemoryBase = ds->context->X19; ds->state++; break;
|
|
|
68 case 20: CallbackOutput->MemoryBase = ds->context->X20; ds->state++; break;
|
|
|
69 case 21: CallbackOutput->MemoryBase = ds->context->X21; ds->state++; break;
|
|
|
70 case 22: CallbackOutput->MemoryBase = ds->context->X22; ds->state++; break;
|
|
|
71 case 23: CallbackOutput->MemoryBase = ds->context->X23; ds->state++; break;
|
|
|
72 case 24: CallbackOutput->MemoryBase = ds->context->X24; ds->state++; break;
|
|
|
73 case 25: CallbackOutput->MemoryBase = ds->context->X25; ds->state++; break;
|
|
|
74 case 26: CallbackOutput->MemoryBase = ds->context->X26; ds->state++; break;
|
|
|
75 case 27: CallbackOutput->MemoryBase = ds->context->X27; ds->state++; break;
|
|
|
76 case 28: CallbackOutput->MemoryBase = ds->context->X28; ds->state++; break;
|
|
|
77 #endif
|
|
|
78
|
|
|
79 // Save memory referenced by values in stack.
|
|
|
80 default:
|
|
|
81 if (ds->state < 0x1000)
|
|
|
82 ds->state = 0x1000;
|
|
|
83
|
|
|
84 size_t addr;
|
|
|
85 do {
|
|
|
86 if (ds->state > 0x1000 + STACK_SEARCH_SIZE)
|
|
|
87 return FALSE;
|
|
|
88
|
|
|
89 if (!safeRead((void*)((ds->context->Sp & ~7) + ds->state - 0x1000), addr))
|
|
|
90 return FALSE;
|
|
|
91
|
|
|
92 ds->state += 4;
|
|
|
93 } while (addr < 0x1000 || !safeTestReadAccess((void*)addr));
|
|
|
94
|
|
|
95 CallbackOutput->MemoryBase = addr;
|
|
|
96 break;
|
|
|
97 }
|
|
|
98
|
|
|
99 if (CallbackOutput->MemoryBase >= MEM_BLOCK_SIZE / 2)
|
|
|
100 CallbackOutput->MemoryBase -= MEM_BLOCK_SIZE / 2;
|
|
|
101 CallbackOutput->MemorySize = MEM_BLOCK_SIZE;
|
|
|
102
|
|
|
103 // No need to perform additional checks here, the minidump engine
|
|
|
104 // safely clips the addresses to valid memory pages only.
|
|
|
105 // Also seems to apply for overlapped areas etc.
|
|
|
106 }
|
|
|
107
|
|
|
108 return TRUE;
|
|
|
109 }
|
|
|
110
|
|
|
111 #elif defined(_M_IX86)
|
|
|
112
|
|
|
113 BOOL WINAPI MiniDumpCallback(PVOID CallbackParam,
|
|
|
114 const PMINIDUMP_CALLBACK_INPUT CallbackInput,
|
|
|
115 PMINIDUMP_CALLBACK_OUTPUT CallbackOutput)
|
|
|
116 {
|
|
|
117 static const unsigned STACK_SEARCH_SIZE = 0x400;
|
|
|
118 static const unsigned MEM_BLOCK_SIZE = 0x400;
|
|
|
119
|
|
|
120 if (CallbackInput->CallbackType == MemoryCallback) {
|
|
|
121 // Called to get user defined blocks of memory to write until
|
|
|
122 // callback returns FALSE or CallbackOutput->MemorySize == 0.
|
|
|
123
|
|
|
124 DumpState* ds = (DumpState*)CallbackParam;
|
|
|
125 switch (ds->state) {
|
|
|
126 // Save memory referenced by registers.
|
|
|
127 case 0: CallbackOutput->MemoryBase = ds->context->Eax; ds->state++; break;
|
|
|
128 case 1: CallbackOutput->MemoryBase = ds->context->Ebx; ds->state++; break;
|
|
|
129 case 2: CallbackOutput->MemoryBase = ds->context->Ecx; ds->state++; break;
|
|
|
130 case 3: CallbackOutput->MemoryBase = ds->context->Edx; ds->state++; break;
|
|
|
131 case 4: CallbackOutput->MemoryBase = ds->context->Esi; ds->state++; break;
|
|
|
132 case 5: CallbackOutput->MemoryBase = ds->context->Edi; ds->state++; break;
|
|
|
133 case 6: CallbackOutput->MemoryBase = ds->context->Ebp; ds->state++; break;
|
|
|
134 case 7: CallbackOutput->MemoryBase = ds->context->Esp; ds->state++; break;
|
|
|
135 case 8: CallbackOutput->MemoryBase = ds->context->Eip; ds->state++; break;
|
|
|
136
|
|
|
137 // Save memory referenced by values in stack.
|
|
|
138 default:
|
|
|
139 if (ds->state < 0x1000)
|
|
|
140 ds->state = 0x1000;
|
|
|
141
|
|
|
142 size_t addr;
|
|
|
143 do {
|
|
|
144 if (ds->state > 0x1000 + STACK_SEARCH_SIZE)
|
|
|
145 return FALSE;
|
|
|
146
|
|
|
147 if (!safeRead((void*)((ds->context->Esp & ~3) + ds->state - 0x1000), addr))
|
|
|
148 return FALSE;
|
|
|
149
|
|
|
150 ds->state += 4;
|
|
|
151 } while (addr < 0x1000 || !safeTestReadAccess((void*)addr));
|
|
|
152
|
|
|
153 CallbackOutput->MemoryBase = addr;
|
|
|
154 break;
|
|
|
155 }
|
|
|
156
|
|
|
157 if (CallbackOutput->MemoryBase >= MEM_BLOCK_SIZE / 2)
|
|
|
158 CallbackOutput->MemoryBase -= MEM_BLOCK_SIZE / 2;
|
|
|
159 CallbackOutput->MemorySize = MEM_BLOCK_SIZE;
|
|
|
160
|
|
|
161 // No need to perform additional checks here, the minidump engine
|
|
|
162 // safely clips the addresses to valid memory pages only.
|
|
|
163 // Also seems to apply for overlapped areas etc.
|
|
|
164 }
|
|
|
165
|
|
|
166 return TRUE;
|
|
|
167 }
|
|
|
168
|
|
|
169 #elif defined(_M_X64)
|
|
|
170
|
|
|
171 BOOL WINAPI MiniDumpCallback(PVOID CallbackParam,
|
|
|
172 const PMINIDUMP_CALLBACK_INPUT CallbackInput,
|
|
|
173 PMINIDUMP_CALLBACK_OUTPUT CallbackOutput)
|
|
|
174 {
|
|
|
175 static const unsigned STACK_SEARCH_SIZE = 0x400;
|
|
|
176 static const unsigned MEM_BLOCK_SIZE = 0x400;
|
|
|
177
|
|
|
178 if (CallbackInput->CallbackType == MemoryCallback) {
|
|
|
179 // Called to get user defined blocks of memory to write until
|
|
|
180 // callback returns FALSE or CallbackOutput->MemorySize == 0.
|
|
|
181
|
|
|
182 DumpState* ds = (DumpState*)CallbackParam;
|
|
|
183 switch (ds->state) {
|
|
|
184 // Save memory referenced by registers.
|
|
|
185 case 0: CallbackOutput->MemoryBase = ds->context->Rax; ds->state++; break;
|
|
|
186 case 1: CallbackOutput->MemoryBase = ds->context->Rbx; ds->state++; break;
|
|
|
187 case 2: CallbackOutput->MemoryBase = ds->context->Rcx; ds->state++; break;
|
|
|
188 case 3: CallbackOutput->MemoryBase = ds->context->Rdx; ds->state++; break;
|
|
|
189 case 4: CallbackOutput->MemoryBase = ds->context->Rsi; ds->state++; break;
|
|
|
190 case 5: CallbackOutput->MemoryBase = ds->context->Rdi; ds->state++; break;
|
|
|
191 case 6: CallbackOutput->MemoryBase = ds->context->Rsp; ds->state++; break;
|
|
|
192 case 7: CallbackOutput->MemoryBase = ds->context->Rbp; ds->state++; break;
|
|
|
193 case 8: CallbackOutput->MemoryBase = ds->context->R8; ds->state++; break;
|
|
|
194 case 9: CallbackOutput->MemoryBase = ds->context->R9; ds->state++; break;
|
|
|
195 case 10: CallbackOutput->MemoryBase = ds->context->R10; ds->state++; break;
|
|
|
196 case 11: CallbackOutput->MemoryBase = ds->context->R11; ds->state++; break;
|
|
|
197 case 12: CallbackOutput->MemoryBase = ds->context->R12; ds->state++; break;
|
|
|
198 case 13: CallbackOutput->MemoryBase = ds->context->R13; ds->state++; break;
|
|
|
199 case 14: CallbackOutput->MemoryBase = ds->context->R14; ds->state++; break;
|
|
|
200 case 15: CallbackOutput->MemoryBase = ds->context->R15; ds->state++; break;
|
|
|
201
|
|
|
202 // Save memory referenced by values in stack.
|
|
|
203 default:
|
|
|
204 if (ds->state < 0x1000)
|
|
|
205 ds->state = 0x1000;
|
|
|
206
|
|
|
207 size_t addr;
|
|
|
208 do {
|
|
|
209 if (ds->state > 0x1000 + STACK_SEARCH_SIZE)
|
|
|
210 return FALSE;
|
|
|
211
|
|
|
212 if (!safeRead((void*)((ds->context->Rsp & ~7) + ds->state - 0x1000), addr))
|
|
|
213 return FALSE;
|
|
|
214
|
|
|
215 ds->state += 4;
|
|
|
216 } while (addr < 0x1000 || !safeTestReadAccess((void*)addr));
|
|
|
217
|
|
|
218 CallbackOutput->MemoryBase = addr;
|
|
|
219 break;
|
|
|
220 }
|
|
|
221
|
|
|
222 if (CallbackOutput->MemoryBase >= MEM_BLOCK_SIZE / 2)
|
|
|
223 CallbackOutput->MemoryBase -= MEM_BLOCK_SIZE / 2;
|
|
|
224 CallbackOutput->MemorySize = MEM_BLOCK_SIZE;
|
|
|
225
|
|
|
226 // No need to perform additional checks here, the minidump engine
|
|
|
227 // safely clips the addresses to valid memory pages only.
|
|
|
228 // Also seems to apply for overlapped areas etc.
|
|
|
229 }
|
|
|
230
|
|
|
231 return TRUE;
|
|
|
232 }
|
|
|
233
|
|
|
234 #endif // _M_X64
|
|
|
235
|
|
|
236
|
|
|
237
|
|
|
238
|
|
|
239 BOOL WriteMiniDumpHelper(HANDLE hDump, LPEXCEPTION_POINTERS param) {
|
|
|
240 MINIDUMP_EXCEPTION_INFORMATION exception = {};
|
|
|
241 exception.ThreadId = GetCurrentThreadId();
|
|
|
242 exception.ExceptionPointers = param;
|
|
|
243 exception.ClientPointers = FALSE;
|
|
|
244 DumpState ds;
|
|
|
245 ds.state = 0;
|
|
|
246 ds.context = reinterpret_cast<myCONTEXT*>(param->ContextRecord);
|
|
|
247 MINIDUMP_CALLBACK_INFORMATION mci;
|
|
|
248 mci.CallbackRoutine = &MiniDumpCallback;
|
|
|
249 mci.CallbackParam = (void*)&ds;
|
|
|
250 return MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hDump, (MINIDUMP_TYPE)(MiniDumpWithUnloadedModules), &exception, NULL, &mci);
|
|
|
251 }
|