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//
20EXT_API_VERSION ApiVersion = { (VER_PRODUCTVERSION_W >> 8), (VER_PRODUCTVERSION_W & 0xff), EXT_API_VERSION_NUMBER64, 0 };
21WINDBG_EXTENSION_APIS ExtensionApis;
22
23ULONG PageSize;
24
25OnUnloadTask *OnUnloadTask::s_pUnloadTaskList = NULL;
26
27//
28// Valid for the lifetime of the debug session.
29//
30
31ULONG TargetMachine;
32BOOL Connected;
33ULONG g_TargetClass;
34DWORD_PTR g_filterHint = 0;
35
36PDEBUG_CLIENT g_ExtClient;
37PDEBUG_DATA_SPACES2 g_ExtData2;
38PDEBUG_SYMBOLS2 g_ExtSymbols2;
39PDEBUG_ADVANCED3 g_ExtAdvanced3;
40PDEBUG_CLIENT g_pCallbacksClient;
41
42#else
43
44DebugClient* g_DebugClient;
45ILLDBServices* g_ExtServices;
46
47#endif // FEATURE_PAL
48
49IMachine* g_targetMachine = NULL;
50BOOL g_bDacBroken = FALSE;
51
52PDEBUG_CONTROL2 g_ExtControl;
53PDEBUG_DATA_SPACES g_ExtData;
54PDEBUG_REGISTERS g_ExtRegisters;
55PDEBUG_SYMBOLS g_ExtSymbols;
56PDEBUG_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
68extern "C" HRESULT
69ExtQuery(PDEBUG_CLIENT client)
70{
71 g_ExtClient = client;
72#else
73extern "C" HRESULT
74ExtQuery(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
101extern "C" HRESULT
102ArchQuery(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.
145void
146ExtRelease(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
166BOOL IsMiniDumpFileNODAC();
167extern 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.
171void __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
184void CleanupEventCallbacks()
185{
186 if(g_pCallbacksClient != NULL)
187 {
188 g_pCallbacksClient->Release();
189 g_pCallbacksClient = NULL;
190 }
191}
192
193bool g_Initialized = false;
194
195extern "C"
196HRESULT
197CALLBACK
198DebugExtensionInitialize(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
274extern "C"
275void
276CALLBACK
277DebugExtensionNotify(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
345extern "C"
346void
347CALLBACK
348DebugExtensionUninitialize(void)
349{
350 // execute all registered cleanup tasks
351 OnUnloadTask::Run();
352 return;
353}
354
355
356BOOL 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
379BOOL 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
390HRESULT
391DebugClient::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
415ULONG
416DebugClient::AddRef()
417{
418 LONG ref = InterlockedIncrement(&m_ref);
419 return ref;
420}
421
422ULONG
423DebugClient::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