1 | // Licensed to the .NET Foundation under one or more agreements. |
2 | // The .NET Foundation licenses this file to you under the MIT license. |
3 | // See the LICENSE file in the project root for more information. |
4 | |
5 | // ==++== |
6 | // |
7 | |
8 | // |
9 | // ==--== |
10 | #include "exts.h" |
11 | #include "disasm.h" |
12 | #ifndef FEATURE_PAL |
13 | #include "EventCallbacks.h" |
14 | |
15 | #define VER_PRODUCTVERSION_W (0x0100) |
16 | |
17 | // |
18 | // globals |
19 | // |
20 | EXT_API_VERSION ApiVersion = { (VER_PRODUCTVERSION_W >> 8), (VER_PRODUCTVERSION_W & 0xff), EXT_API_VERSION_NUMBER64, 0 }; |
21 | WINDBG_EXTENSION_APIS ExtensionApis; |
22 | |
23 | ULONG PageSize; |
24 | |
25 | OnUnloadTask *OnUnloadTask::s_pUnloadTaskList = NULL; |
26 | |
27 | // |
28 | // Valid for the lifetime of the debug session. |
29 | // |
30 | |
31 | ULONG TargetMachine; |
32 | BOOL Connected; |
33 | ULONG g_TargetClass; |
34 | DWORD_PTR g_filterHint = 0; |
35 | |
36 | PDEBUG_CLIENT g_ExtClient; |
37 | PDEBUG_DATA_SPACES2 g_ExtData2; |
38 | PDEBUG_SYMBOLS2 g_ExtSymbols2; |
39 | PDEBUG_ADVANCED3 g_ExtAdvanced3; |
40 | PDEBUG_CLIENT g_pCallbacksClient; |
41 | |
42 | #else |
43 | |
44 | DebugClient* g_DebugClient; |
45 | ILLDBServices* g_ExtServices; |
46 | |
47 | #endif // FEATURE_PAL |
48 | |
49 | IMachine* g_targetMachine = NULL; |
50 | BOOL g_bDacBroken = FALSE; |
51 | |
52 | PDEBUG_CONTROL2 g_ExtControl; |
53 | PDEBUG_DATA_SPACES g_ExtData; |
54 | PDEBUG_REGISTERS g_ExtRegisters; |
55 | PDEBUG_SYMBOLS g_ExtSymbols; |
56 | PDEBUG_SYSTEM_OBJECTS g_ExtSystem; |
57 | |
58 | #define SOS_ExtQueryFailGo(var, riid) \ |
59 | var = NULL; \ |
60 | if ((Status = client->QueryInterface(__uuidof(riid), \ |
61 | (void **)&var)) != S_OK) \ |
62 | { \ |
63 | goto Fail; \ |
64 | } |
65 | |
66 | // Queries for all debugger interfaces. |
67 | #ifndef FEATURE_PAL |
68 | extern "C" HRESULT |
69 | ExtQuery(PDEBUG_CLIENT client) |
70 | { |
71 | g_ExtClient = client; |
72 | #else |
73 | extern "C" HRESULT |
74 | ExtQuery(ILLDBServices* services) |
75 | { |
76 | g_ExtServices = services; |
77 | DebugClient* client = new DebugClient(services); |
78 | g_DebugClient = client; |
79 | #endif |
80 | HRESULT Status; |
81 | SOS_ExtQueryFailGo(g_ExtControl, IDebugControl2); |
82 | SOS_ExtQueryFailGo(g_ExtData, IDebugDataSpaces); |
83 | SOS_ExtQueryFailGo(g_ExtRegisters, IDebugRegisters); |
84 | SOS_ExtQueryFailGo(g_ExtSymbols, IDebugSymbols); |
85 | SOS_ExtQueryFailGo(g_ExtSystem, IDebugSystemObjects); |
86 | #ifndef FEATURE_PAL |
87 | SOS_ExtQueryFailGo(g_ExtData2, IDebugDataSpaces2); |
88 | SOS_ExtQueryFailGo(g_ExtSymbols2, IDebugSymbols2); |
89 | SOS_ExtQueryFailGo(g_ExtAdvanced3, IDebugAdvanced3); |
90 | #endif // FEATURE_PAL |
91 | return S_OK; |
92 | |
93 | Fail: |
94 | if (Status == E_OUTOFMEMORY) |
95 | ReportOOM(); |
96 | |
97 | ExtRelease(); |
98 | return Status; |
99 | } |
100 | |
101 | extern "C" HRESULT |
102 | ArchQuery(void) |
103 | { |
104 | ULONG targetArchitecture; |
105 | IMachine* targetMachine = NULL; |
106 | |
107 | g_ExtControl->GetExecutingProcessorType(&targetArchitecture); |
108 | |
109 | #ifdef SOS_TARGET_AMD64 |
110 | if(targetArchitecture == IMAGE_FILE_MACHINE_AMD64) |
111 | { |
112 | targetMachine = AMD64Machine::GetInstance(); |
113 | } |
114 | #elif defined(SOS_TARGET_X86) |
115 | if (targetArchitecture == IMAGE_FILE_MACHINE_I386) |
116 | { |
117 | targetMachine = X86Machine::GetInstance(); |
118 | } |
119 | #elif defined(SOS_TARGET_ARM) |
120 | if (targetArchitecture == IMAGE_FILE_MACHINE_ARMNT) |
121 | { |
122 | targetMachine = ARMMachine::GetInstance(); |
123 | } |
124 | #elif defined(SOS_TARGET_ARM64) |
125 | if (targetArchitecture == IMAGE_FILE_MACHINE_ARM64) |
126 | { |
127 | targetMachine = ARM64Machine::GetInstance(); |
128 | } |
129 | #else |
130 | #error "Undefined target architecture" |
131 | #endif |
132 | |
133 | if (targetMachine == NULL) |
134 | { |
135 | g_targetMachine = NULL; |
136 | ExtErr("SOS does not support the current target architecture 0x%llx.\n" , targetArchitecture); |
137 | return E_FAIL; |
138 | } |
139 | |
140 | g_targetMachine = targetMachine; |
141 | return S_OK; |
142 | } |
143 | |
144 | // Cleans up all debugger interfaces. |
145 | void |
146 | ExtRelease(void) |
147 | { |
148 | EXT_RELEASE(g_ExtControl); |
149 | EXT_RELEASE(g_ExtData); |
150 | EXT_RELEASE(g_ExtRegisters); |
151 | EXT_RELEASE(g_ExtSymbols); |
152 | EXT_RELEASE(g_ExtSystem); |
153 | #ifndef FEATURE_PAL |
154 | EXT_RELEASE(g_ExtData2); |
155 | EXT_RELEASE(g_ExtSymbols2); |
156 | EXT_RELEASE(g_ExtAdvanced3); |
157 | g_ExtClient = NULL; |
158 | #else |
159 | EXT_RELEASE(g_DebugClient); |
160 | g_ExtServices = NULL; |
161 | #endif // FEATURE_PAL |
162 | } |
163 | |
164 | #ifndef FEATURE_PAL |
165 | |
166 | BOOL IsMiniDumpFileNODAC(); |
167 | extern HMODULE g_hInstance; |
168 | |
169 | // This function throws an exception that can be caught by the debugger, |
170 | // instead of allowing the default CRT behavior of invoking Watson to failfast. |
171 | void __cdecl _SOS_invalid_parameter( |
172 | const WCHAR * expression, |
173 | const WCHAR * function, |
174 | const WCHAR * file, |
175 | unsigned int line, |
176 | uintptr_t pReserved |
177 | ) |
178 | { |
179 | ExtErr("\nSOS failure!\n" ); |
180 | throw "SOS failure" ; |
181 | } |
182 | |
183 | // Unregisters our windbg event callbacks and releases the client, event callback objects |
184 | void CleanupEventCallbacks() |
185 | { |
186 | if(g_pCallbacksClient != NULL) |
187 | { |
188 | g_pCallbacksClient->Release(); |
189 | g_pCallbacksClient = NULL; |
190 | } |
191 | } |
192 | |
193 | bool g_Initialized = false; |
194 | |
195 | extern "C" |
196 | HRESULT |
197 | CALLBACK |
198 | DebugExtensionInitialize(PULONG Version, PULONG Flags) |
199 | { |
200 | IDebugClient *DebugClient; |
201 | PDEBUG_CONTROL DebugControl; |
202 | HRESULT Hr; |
203 | |
204 | *Version = DEBUG_EXTENSION_VERSION(1, 0); |
205 | *Flags = 0; |
206 | |
207 | if (g_Initialized) |
208 | { |
209 | return S_OK; |
210 | } |
211 | g_Initialized = true; |
212 | |
213 | if ((Hr = DebugCreate(__uuidof(IDebugClient), |
214 | (void **)&DebugClient)) != S_OK) |
215 | { |
216 | return Hr; |
217 | } |
218 | if ((Hr = DebugClient->QueryInterface(__uuidof(IDebugControl), |
219 | (void **)&DebugControl)) != S_OK) |
220 | { |
221 | return Hr; |
222 | } |
223 | |
224 | ExtensionApis.nSize = sizeof (ExtensionApis); |
225 | if ((Hr = DebugControl->GetWindbgExtensionApis64(&ExtensionApis)) != S_OK) |
226 | { |
227 | return Hr; |
228 | } |
229 | |
230 | // Fixes the "Unable to read dynamic function table entries" error messages by disabling the WinDbg security |
231 | // feature that prevents the loading of unknown out of proc tack walkers. |
232 | DebugControl->Execute(DEBUG_OUTCTL_IGNORE, ".settings set EngineInitialization.VerifyFunctionTableCallbacks=false" , |
233 | DEBUG_EXECUTE_NOT_LOGGED | DEBUG_EXECUTE_NO_REPEAT); |
234 | |
235 | ExtQuery(DebugClient); |
236 | if (IsMiniDumpFileNODAC()) |
237 | { |
238 | ExtOut ( |
239 | "----------------------------------------------------------------------------\n" |
240 | "The user dump currently examined is a minidump. Consequently, only a subset\n" |
241 | "of sos.dll functionality will be available. If needed, attaching to the live\n" |
242 | "process or debugging a full dump will allow access to sos.dll's full feature\n" |
243 | "set.\n" |
244 | "To create a full user dump use the command: .dump /ma <filename>\n" |
245 | "----------------------------------------------------------------------------\n" ); |
246 | } |
247 | ExtRelease(); |
248 | |
249 | OnUnloadTask::Register(CleanupEventCallbacks); |
250 | g_pCallbacksClient = DebugClient; |
251 | EventCallbacks* pCallbacksObj = new EventCallbacks(DebugClient); |
252 | IDebugEventCallbacks* pCallbacks = NULL; |
253 | pCallbacksObj->QueryInterface(__uuidof(IDebugEventCallbacks), (void**)&pCallbacks); |
254 | pCallbacksObj->Release(); |
255 | |
256 | if(FAILED(Hr = g_pCallbacksClient->SetEventCallbacks(pCallbacks))) |
257 | { |
258 | ExtOut ("SOS: Failed to register callback events\n" ); |
259 | pCallbacks->Release(); |
260 | return Hr; |
261 | } |
262 | pCallbacks->Release(); |
263 | |
264 | #ifndef _ARM_ |
265 | // Make sure we do not tear down the debugger when a security function fails |
266 | // Since we link statically against CRT this will only affect the SOS module. |
267 | _set_invalid_parameter_handler(_SOS_invalid_parameter); |
268 | #endif |
269 | |
270 | DebugControl->Release(); |
271 | return S_OK; |
272 | } |
273 | |
274 | extern "C" |
275 | void |
276 | CALLBACK |
277 | DebugExtensionNotify(ULONG Notify, ULONG64 /*Argument*/) |
278 | { |
279 | // |
280 | // The first time we actually connect to a target, get the page size |
281 | // |
282 | |
283 | if ((Notify == DEBUG_NOTIFY_SESSION_ACCESSIBLE) && (!Connected)) |
284 | { |
285 | IDebugClient *DebugClient; |
286 | PDEBUG_DATA_SPACES DebugDataSpaces; |
287 | PDEBUG_CONTROL DebugControl; |
288 | HRESULT Hr; |
289 | ULONG64 Page; |
290 | |
291 | if ((Hr = DebugCreate(__uuidof(IDebugClient), |
292 | (void **)&DebugClient)) == S_OK) |
293 | { |
294 | // |
295 | // Get the page size and PAE enable flag |
296 | // |
297 | |
298 | if ((Hr = DebugClient->QueryInterface(__uuidof(IDebugDataSpaces), |
299 | (void **)&DebugDataSpaces)) == S_OK) |
300 | { |
301 | if ((Hr = DebugDataSpaces->ReadDebuggerData( |
302 | DEBUG_DATA_MmPageSize, &Page, |
303 | sizeof(Page), NULL)) == S_OK) |
304 | { |
305 | PageSize = (ULONG)(ULONG_PTR)Page; |
306 | } |
307 | |
308 | DebugDataSpaces->Release(); |
309 | } |
310 | // |
311 | // Get the architecture type. |
312 | // |
313 | |
314 | if ((Hr = DebugClient->QueryInterface(__uuidof(IDebugControl), |
315 | (void **)&DebugControl)) == S_OK) |
316 | { |
317 | if ((Hr = DebugControl->GetActualProcessorType( |
318 | &TargetMachine)) == S_OK) |
319 | { |
320 | Connected = TRUE; |
321 | } |
322 | ULONG Qualifier; |
323 | if ((Hr = DebugControl->GetDebuggeeType(&g_TargetClass, &Qualifier)) == S_OK) |
324 | { |
325 | } |
326 | |
327 | DebugControl->Release(); |
328 | } |
329 | |
330 | DebugClient->Release(); |
331 | } |
332 | } |
333 | |
334 | |
335 | if (Notify == DEBUG_NOTIFY_SESSION_INACTIVE) |
336 | { |
337 | Connected = FALSE; |
338 | PageSize = 0; |
339 | TargetMachine = 0; |
340 | } |
341 | |
342 | return; |
343 | } |
344 | |
345 | extern "C" |
346 | void |
347 | CALLBACK |
348 | DebugExtensionUninitialize(void) |
349 | { |
350 | // execute all registered cleanup tasks |
351 | OnUnloadTask::Run(); |
352 | return; |
353 | } |
354 | |
355 | |
356 | BOOL DllInit( |
357 | HANDLE /*hModule*/, |
358 | DWORD dwReason, |
359 | DWORD /*dwReserved*/ |
360 | ) |
361 | { |
362 | switch (dwReason) { |
363 | case DLL_THREAD_ATTACH: |
364 | break; |
365 | |
366 | case DLL_THREAD_DETACH: |
367 | break; |
368 | |
369 | case DLL_PROCESS_DETACH: |
370 | break; |
371 | |
372 | case DLL_PROCESS_ATTACH: |
373 | break; |
374 | } |
375 | |
376 | return TRUE; |
377 | } |
378 | |
379 | BOOL WINAPI DllMain(HANDLE hInstance, DWORD dwReason, LPVOID lpReserved) |
380 | { |
381 | if (dwReason == DLL_PROCESS_ATTACH) |
382 | { |
383 | g_hInstance = (HMODULE) hInstance; |
384 | } |
385 | return true; |
386 | } |
387 | |
388 | #else // FEATURE_PAL |
389 | |
390 | HRESULT |
391 | DebugClient::QueryInterface( |
392 | REFIID InterfaceId, |
393 | PVOID* Interface |
394 | ) |
395 | { |
396 | if (InterfaceId == __uuidof(IUnknown) || |
397 | InterfaceId == __uuidof(IDebugControl2) || |
398 | InterfaceId == __uuidof(IDebugControl4) || |
399 | InterfaceId == __uuidof(IDebugDataSpaces) || |
400 | InterfaceId == __uuidof(IDebugSymbols) || |
401 | InterfaceId == __uuidof(IDebugSystemObjects) || |
402 | InterfaceId == __uuidof(IDebugRegisters)) |
403 | { |
404 | *Interface = this; |
405 | AddRef(); |
406 | return S_OK; |
407 | } |
408 | else |
409 | { |
410 | *Interface = NULL; |
411 | return E_NOINTERFACE; |
412 | } |
413 | } |
414 | |
415 | ULONG |
416 | DebugClient::AddRef() |
417 | { |
418 | LONG ref = InterlockedIncrement(&m_ref); |
419 | return ref; |
420 | } |
421 | |
422 | ULONG |
423 | DebugClient::Release() |
424 | { |
425 | LONG ref = InterlockedDecrement(&m_ref); |
426 | if (ref == 0) |
427 | { |
428 | m_lldbservices->Release(); |
429 | delete this; |
430 | } |
431 | return ref; |
432 | } |
433 | |
434 | #endif // FEATURE_PAL |
435 | |