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// debugshim.cpp
6//
7
8//
9//*****************************************************************************
10
11#include "debugshim.h"
12#include "dbgutil.h"
13#include <crtdbg.h>
14#include <clrinternal.h> //has the CLR_ID_V4_DESKTOP guid in it
15#include "palclr.h"
16
17#ifndef IMAGE_FILE_MACHINE_ARMNT
18#define IMAGE_FILE_MACHINE_ARMNT 0x01c4 // ARM Thumb-2 Little-Endian
19#endif
20
21#ifndef IMAGE_FILE_MACHINE_ARM64
22#define IMAGE_FILE_MACHINE_ARM64 0xAA64 // ARM64 Little-Endian
23#endif
24
25// making the defines very clear, these represent the host architecture - aka
26// the arch on which this code is running
27#if defined(_X86_)
28#define _HOST_X86_
29#elif defined(_AMD64_)
30#define _HOST_AMD64_
31#elif defined(_ARM_)
32#define _HOST_ARM_
33#elif defined(_ARM64_)
34#define _HOST_ARM64_
35#endif
36
37//*****************************************************************************
38// CLRDebuggingImpl implementation (ICLRDebugging)
39//*****************************************************************************
40
41typedef HRESULT (STDAPICALLTYPE *OpenVirtualProcessImpl2FnPtr)(ULONG64 clrInstanceId,
42 IUnknown * pDataTarget,
43 LPCWSTR pDacModulePath,
44 CLR_DEBUGGING_VERSION * pMaxDebuggerSupportedVersion,
45 REFIID riid,
46 IUnknown ** ppInstance,
47 CLR_DEBUGGING_PROCESS_FLAGS * pdwFlags);
48
49typedef HRESULT (STDAPICALLTYPE *OpenVirtualProcessImplFnPtr)(ULONG64 clrInstanceId,
50 IUnknown * pDataTarget,
51 HMODULE hDacDll,
52 CLR_DEBUGGING_VERSION * pMaxDebuggerSupportedVersion,
53 REFIID riid,
54 IUnknown ** ppInstance,
55 CLR_DEBUGGING_PROCESS_FLAGS * pdwFlags);
56
57typedef HRESULT (STDAPICALLTYPE *OpenVirtualProcess2FnPtr)(ULONG64 clrInstanceId,
58 IUnknown * pDataTarget,
59 HMODULE hDacDll,
60 REFIID riid,
61 IUnknown ** ppInstance,
62 CLR_DEBUGGING_PROCESS_FLAGS * pdwFlags);
63
64typedef HMODULE (STDAPICALLTYPE *LoadLibraryWFnPtr)(LPCWSTR lpLibFileName);
65
66// Implementation of ICLRDebugging::OpenVirtualProcess
67//
68// Arguments:
69// moduleBaseAddress - the address of the module which might be a CLR
70// pDataTarget - the data target for inspecting the process
71// pLibraryProvider - a callback for locating DBI and DAC
72// pMaxDebuggerSupportedVersion - the max version of the CLR that this debugger will support debugging
73// riidProcess - the IID of the interface that should be passed back in ppProcess
74// ppProcess - output for the ICorDebugProcess# if this module is a CLR
75// pVersion - the CLR version if this module is a CLR
76// pFlags - output, see the CLR_DEBUGGING_PROCESS_FLAGS for more details. Right now this has only one possible
77// value which indicates this runtime had an unhandled exception
78STDMETHODIMP CLRDebuggingImpl::OpenVirtualProcess(
79 ULONG64 moduleBaseAddress,
80 IUnknown * pDataTarget,
81 ICLRDebuggingLibraryProvider * pLibraryProvider,
82 CLR_DEBUGGING_VERSION * pMaxDebuggerSupportedVersion,
83 REFIID riidProcess,
84 IUnknown ** ppProcess,
85 CLR_DEBUGGING_VERSION * pVersion,
86 CLR_DEBUGGING_PROCESS_FLAGS * pFlags)
87{
88 //PRECONDITION(CheckPointer(pDataTarget));
89
90 HRESULT hr = S_OK;
91 ICorDebugDataTarget * pDt = NULL;
92 HMODULE hDbi = NULL;
93 HMODULE hDac = NULL;
94 LPWSTR pDacModulePath = NULL;
95 LPWSTR pDbiModulePath = NULL;
96 DWORD dbiTimestamp;
97 DWORD dbiSizeOfImage;
98 WCHAR dbiName[MAX_PATH_FNAME] = { 0 };
99 DWORD dacTimestamp;
100 DWORD dacSizeOfImage;
101 WCHAR dacName[MAX_PATH_FNAME] = { 0 };
102 CLR_DEBUGGING_VERSION version;
103 BOOL versionSupportedByCaller = FALSE;
104
105 // argument checking
106 if ((ppProcess != NULL || pFlags != NULL) && pLibraryProvider == NULL)
107 {
108 hr = E_POINTER; // the library provider must be specified if either
109 // ppProcess or pFlags is non-NULL
110 }
111 else if ((ppProcess != NULL || pFlags != NULL) && pMaxDebuggerSupportedVersion == NULL)
112 {
113 hr = E_POINTER; // the max supported version must be specified if either
114 // ppProcess or pFlags is non-NULL
115 }
116 else if (pVersion != NULL && pVersion->wStructVersion != 0)
117 {
118 hr = CORDBG_E_UNSUPPORTED_VERSION_STRUCT;
119 }
120 else if (FAILED(pDataTarget->QueryInterface(__uuidof(ICorDebugDataTarget), (void**)&pDt)))
121 {
122 hr = CORDBG_E_MISSING_DATA_TARGET_INTERFACE;
123 }
124
125 if (SUCCEEDED(hr))
126 {
127 // get CLR version
128 // The expectation is that new versions of the CLR will continue to use the same GUID
129 // (unless there's a reason to hide them from older shims), but debuggers will tell us the
130 // CLR version they're designed for and mscordbi.dll can decide whether or not to accept it.
131 version.wStructVersion = 0;
132 hr = GetCLRInfo(pDt,
133 moduleBaseAddress,
134 &version,
135 &dbiTimestamp,
136 &dbiSizeOfImage,
137 dbiName,
138 MAX_PATH_FNAME,
139 &dacTimestamp,
140 &dacSizeOfImage,
141 dacName,
142 MAX_PATH_FNAME);
143 }
144
145 // If we need to fetch either the process info or the flags info then we need to find
146 // mscordbi and DAC and do the version specific OVP work
147 if (SUCCEEDED(hr) && (ppProcess != NULL || pFlags != NULL))
148 {
149 ICLRDebuggingLibraryProvider2* pLibraryProvider2;
150 if (SUCCEEDED(pLibraryProvider->QueryInterface(__uuidof(ICLRDebuggingLibraryProvider2), (void**)&pLibraryProvider2)))
151 {
152 if (FAILED(pLibraryProvider2->ProvideLibrary2(dbiName, dbiTimestamp, dbiSizeOfImage, &pDbiModulePath)) ||
153 pDbiModulePath == NULL)
154 {
155 hr = CORDBG_E_LIBRARY_PROVIDER_ERROR;
156 }
157
158 if (SUCCEEDED(hr))
159 {
160 hDbi = LoadLibraryW(pDbiModulePath);
161 if (hDbi == NULL)
162 {
163 hr = HRESULT_FROM_WIN32(GetLastError());
164 }
165 }
166
167 if (SUCCEEDED(hr))
168 {
169 // Adjust the timestamp and size of image if this DAC is a known buggy version and needs to be retargeted
170 RetargetDacIfNeeded(&dacTimestamp, &dacSizeOfImage);
171
172 // Ask library provider for dac
173 if (FAILED(pLibraryProvider2->ProvideLibrary2(dacName, dacTimestamp, dacSizeOfImage, &pDacModulePath)) ||
174 pDacModulePath == NULL)
175 {
176 hr = CORDBG_E_LIBRARY_PROVIDER_ERROR;
177 }
178
179 if (SUCCEEDED(hr))
180 {
181 hDac = LoadLibraryW(pDacModulePath);
182 if (hDac == NULL)
183 {
184 hr = HRESULT_FROM_WIN32(GetLastError());
185 }
186 }
187 }
188
189 pLibraryProvider2->Release();
190 }
191 else {
192 // Ask library provider for dbi
193 if (FAILED(pLibraryProvider->ProvideLibrary(dbiName, dbiTimestamp, dbiSizeOfImage, &hDbi)) ||
194 hDbi == NULL)
195 {
196 hr = CORDBG_E_LIBRARY_PROVIDER_ERROR;
197 }
198
199 if (SUCCEEDED(hr))
200 {
201 // Adjust the timestamp and size of image if this DAC is a known buggy version and needs to be retargeted
202 RetargetDacIfNeeded(&dacTimestamp, &dacSizeOfImage);
203
204 // ask library provider for dac
205 if (FAILED(pLibraryProvider->ProvideLibrary(dacName, dacTimestamp, dacSizeOfImage, &hDac)) ||
206 hDac == NULL)
207 {
208 hr = CORDBG_E_LIBRARY_PROVIDER_ERROR;
209 }
210 }
211 }
212
213 *ppProcess = NULL;
214
215 if (SUCCEEDED(hr) && pDacModulePath != NULL)
216 {
217 // Get access to the latest OVP implementation and call it
218 OpenVirtualProcessImpl2FnPtr ovpFn = (OpenVirtualProcessImpl2FnPtr)GetProcAddress(hDbi, "OpenVirtualProcessImpl2");
219 if (ovpFn != NULL)
220 {
221 hr = ovpFn(moduleBaseAddress, pDataTarget, pDacModulePath, pMaxDebuggerSupportedVersion, riidProcess, ppProcess, pFlags);
222 if (FAILED(hr))
223 {
224 _ASSERTE(ppProcess == NULL || *ppProcess == NULL);
225 _ASSERTE(pFlags == NULL || *pFlags == 0);
226 }
227 }
228#ifdef FEATURE_PAL
229 else
230 {
231 // On Linux/MacOS the DAC module handle needs to be re-created using the DAC PAL instance
232 // before being passed to DBI's OpenVirtualProcess* implementation. The DBI and DAC share
233 // the same PAL where dbgshim has it's own.
234 LoadLibraryWFnPtr loadLibraryWFn = (LoadLibraryWFnPtr)GetProcAddress(hDac, "LoadLibraryW");
235 if (loadLibraryWFn != NULL)
236 {
237 hDac = loadLibraryWFn(pDacModulePath);
238 if (hDac == NULL)
239 {
240 hr = E_HANDLE;
241 }
242 }
243 else
244 {
245 hr = E_HANDLE;
246 }
247 }
248#endif // FEATURE_PAL
249 }
250
251 // If no errors so far and "OpenVirtualProcessImpl2" doesn't exist
252 if (SUCCEEDED(hr) && *ppProcess == NULL)
253 {
254 // Get access to OVP and call it
255 OpenVirtualProcessImplFnPtr ovpFn = (OpenVirtualProcessImplFnPtr)GetProcAddress(hDbi, "OpenVirtualProcessImpl");
256 if (ovpFn == NULL)
257 {
258 // Fallback to CLR v4 Beta1 path, but skip some of the checking we'd normally do (maxSupportedVersion, etc.)
259 OpenVirtualProcess2FnPtr ovp2Fn = (OpenVirtualProcess2FnPtr)GetProcAddress(hDbi, "OpenVirtualProcess2");
260 if (ovp2Fn == NULL)
261 {
262 hr = CORDBG_E_LIBRARY_PROVIDER_ERROR;
263 }
264 else
265 {
266 hr = ovp2Fn(moduleBaseAddress, pDataTarget, hDac, riidProcess, ppProcess, pFlags);
267 }
268 }
269 else
270 {
271 // Have a CLR v4 Beta2+ DBI, call it and let it do the version check
272 hr = ovpFn(moduleBaseAddress, pDataTarget, hDac, pMaxDebuggerSupportedVersion, riidProcess, ppProcess, pFlags);
273 if (FAILED(hr))
274 {
275 _ASSERTE(ppProcess == NULL || *ppProcess == NULL);
276 _ASSERTE(pFlags == NULL || *pFlags == 0);
277 }
278 }
279 }
280 }
281
282 //version is still valid in some failure cases
283 if (pVersion != NULL &&
284 (SUCCEEDED(hr) ||
285 (hr == CORDBG_E_UNSUPPORTED_DEBUGGING_MODEL) ||
286 (hr == CORDBG_E_UNSUPPORTED_FORWARD_COMPAT)))
287 {
288 memcpy(pVersion, &version, sizeof(CLR_DEBUGGING_VERSION));
289 }
290
291 if (pDacModulePath != NULL)
292 {
293#ifdef FEATURE_PAL
294 free(pDacModulePath);
295#else
296 CoTaskMemFree(pDacModulePath);
297#endif
298 }
299
300 if (pDbiModulePath != NULL)
301 {
302#ifdef FEATURE_PAL
303 free(pDbiModulePath);
304#else
305 CoTaskMemFree(pDbiModulePath);
306#endif
307 }
308
309 // free the data target we QI'ed earlier
310 if (pDt != NULL)
311 {
312 pDt->Release();
313 }
314
315 return hr;
316}
317
318// Checks to see if this DAC is one of a known set of old DAC builds which contains an issue.
319// If so we retarget to a newer compatible version which has the bug fixed. This is done
320// by changing the PE information used to lookup the DAC.
321//
322// Arguments
323// pdwTimeStamp - on input, the timestamp of DAC as embedded in the CLR image
324// on output, a potentially new timestamp for an updated DAC to use
325// instead
326// pdwSizeOfImage - on input, the sizeOfImage of DAC as embedded in the CLR image
327// on output, a potentially new sizeOfImage for an updated DAC to use
328// instead
329VOID CLRDebuggingImpl::RetargetDacIfNeeded(DWORD* pdwTimeStamp,
330 DWORD* pdwSizeOfImage)
331{
332
333 // This code is auto generated by the CreateRetargetTable tool
334 // on 3/4/2011 6:35 PM
335 // and then copy-pasted here.
336 //
337 //
338 //
339 // Retarget the GDR1 amd64 build
340 if( (*pdwTimeStamp == 0x4d536868) && (*pdwSizeOfImage == 0x17b000))
341 {
342 *pdwTimeStamp = 0x4d71a160;
343 *pdwSizeOfImage = 0x17b000;
344 }
345 // Retarget the GDR1 x86 build
346 else if( (*pdwTimeStamp == 0x4d5368f2) && (*pdwSizeOfImage == 0x120000))
347 {
348 *pdwTimeStamp = 0x4d71a14f;
349 *pdwSizeOfImage = 0x120000;
350 }
351 // Retarget the RTM amd64 build
352 else if( (*pdwTimeStamp == 0x4ba21fa7) && (*pdwSizeOfImage == 0x17b000))
353 {
354 *pdwTimeStamp = 0x4d71a13c;
355 *pdwSizeOfImage = 0x17b000;
356 }
357 // Retarget the RTM x86 build
358 else if( (*pdwTimeStamp == 0x4ba1da25) && (*pdwSizeOfImage == 0x120000))
359 {
360 *pdwTimeStamp = 0x4d71a128;
361 *pdwSizeOfImage = 0x120000;
362 }
363 // This code is auto generated by the CreateRetargetTable tool
364 // on 8/17/2011 1:28 AM
365 // and then copy-pasted here.
366 //
367 //
368 //
369 // Retarget the GDR2 amd64 build
370 else if( (*pdwTimeStamp == 0x4da428c7) && (*pdwSizeOfImage == 0x17b000))
371 {
372 *pdwTimeStamp = 0x4e4b7bc2;
373 *pdwSizeOfImage = 0x17b000;
374 }
375 // Retarget the GDR2 x86 build
376 else if( (*pdwTimeStamp == 0x4da3fe52) && (*pdwSizeOfImage == 0x120000))
377 {
378 *pdwTimeStamp = 0x4e4b7bb1;
379 *pdwSizeOfImage = 0x120000;
380 }
381 // End auto-generated code
382}
383
384#define PE_FIXEDFILEINFO_SIGNATURE 0xFEEF04BD
385
386// The format of the special debugging resource we embed in CLRs starting in
387// v4
388struct CLR_DEBUG_RESOURCE
389{
390 DWORD dwVersion;
391 GUID signature;
392 DWORD dwDacTimeStamp;
393 DWORD dwDacSizeOfImage;
394 DWORD dwDbiTimeStamp;
395 DWORD dwDbiSizeOfImage;
396};
397
398// Checks to see if a module is a CLR and if so, fetches the debug data
399// from the embedded resource
400//
401// Arguments
402// pDataTarget - dataTarget for the process we are inspecting
403// moduleBaseAddress - base address of a module we should inspect
404// pVersion - output, the version of the CLR detected if this is a CLR
405// pdwDbiTimeStamp - the timestamp of DBI as embedded in the CLR image
406// pdwDbiSizeOfImage - the SizeOfImage of DBI as embedded in the CLR image
407// pDbiName - output, the filename of DBI (as calculated by this function but that might change)
408// dwDbiNameCharCount - input, the number of WCHARs in the buffer pointed to by pDbiName
409// pdwDacTimeStampe - the timestamp of DAC as embedded in the CLR image
410// pdwDacSizeOfImage - the SizeOfImage of DAC as embedded in the CLR image
411// pDacName - output, the filename of DAC (as calculated by this function but that might change)
412// dwDacNameCharCount - input, the number of WCHARs in the buffer pointed to by pDacName
413HRESULT CLRDebuggingImpl::GetCLRInfo(ICorDebugDataTarget* pDataTarget,
414 ULONG64 moduleBaseAddress,
415 CLR_DEBUGGING_VERSION* pVersion,
416 DWORD* pdwDbiTimeStamp,
417 DWORD* pdwDbiSizeOfImage,
418 __out_z __inout_ecount(dwDbiNameCharCount) WCHAR* pDbiName,
419 DWORD dwDbiNameCharCount,
420 DWORD* pdwDacTimeStamp,
421 DWORD* pdwDacSizeOfImage,
422 __out_z __inout_ecount(dwDacNameCharCount) WCHAR* pDacName,
423 DWORD dwDacNameCharCount)
424{
425#ifndef FEATURE_PAL
426 WORD imageFileMachine = 0;
427 DWORD resourceSectionRVA = 0;
428 HRESULT hr = GetMachineAndResourceSectionRVA(pDataTarget, moduleBaseAddress, &imageFileMachine, &resourceSectionRVA);
429
430 // We want the version resource which has type = RT_VERSION = 16, name = 1, language = 0x409
431 DWORD versionResourceRVA = 0;
432 DWORD versionResourceSize = 0;
433 if(SUCCEEDED(hr))
434 {
435 hr = GetResourceRvaFromResourceSectionRva(pDataTarget, moduleBaseAddress, resourceSectionRVA, 16, 1, 0x409,
436 &versionResourceRVA, &versionResourceSize);
437 }
438
439 // At last we get our version info
440 VS_FIXEDFILEINFO fixedFileInfo = {0};
441 if(SUCCEEDED(hr))
442 {
443 // The version resource has 3 words, then the unicode string "VS_VERSION_INFO"
444 // (16 WCHARS including the null terminator)
445 // then padding to a 32-bit boundary, then the VS_FIXEDFILEINFO struct
446 DWORD fixedFileInfoRVA = ((versionResourceRVA + 3*2 + 16*2 + 3)/4)*4;
447 hr = ReadFromDataTarget(pDataTarget, moduleBaseAddress + fixedFileInfoRVA, (BYTE*)&fixedFileInfo, sizeof(fixedFileInfo));
448 }
449
450 //Verify the signature on the version resource
451 if(SUCCEEDED(hr) && fixedFileInfo.dwSignature != PE_FIXEDFILEINFO_SIGNATURE)
452 {
453 hr = CORDBG_E_NOT_CLR;
454 }
455
456 // Record the version information
457 if(SUCCEEDED(hr))
458 {
459 pVersion->wMajor = (WORD) (fixedFileInfo.dwProductVersionMS >> 16);
460 pVersion->wMinor = (WORD) (fixedFileInfo.dwProductVersionMS & 0xFFFF);
461 pVersion->wBuild = (WORD) (fixedFileInfo.dwProductVersionLS >> 16);
462 pVersion->wRevision = (WORD) (fixedFileInfo.dwProductVersionLS & 0xFFFF);
463 }
464
465 // Now grab the special clr debug info resource
466 // We may need to scan a few different names searching though...
467 // 1) CLRDEBUGINFO<host_os><host_arch> where host_os = 'WINDOWS' or 'CORESYS' and host_arch = 'X86' or 'ARM' or 'AMD64'
468 // 2) For back-compat if the host os is windows and the host architecture matches the target then CLRDEBUGINFO is used with no suffix.
469 DWORD debugResourceRVA = 0;
470 DWORD debugResourceSize = 0;
471 BOOL useCrossPlatformNaming = FALSE;
472 if(SUCCEEDED(hr))
473 {
474 // the initial state is that we haven't found a proper resource
475 HRESULT hrGetResource = E_FAIL;
476
477 // First check for the resource which has type = RC_DATA = 10, name = "CLRDEBUGINFO<host_os><host_arch>", language = 0
478#if defined (HOST_IS_WINDOWS_OS) && defined(_HOST_X86_)
479 const WCHAR * resourceName = W("CLRDEBUGINFOWINDOWSX86");
480#endif
481
482#if !defined (HOST_IS_WINDOWS_OS) && defined(_HOST_X86_)
483 const WCHAR * resourceName = W("CLRDEBUGINFOCORESYSX86");
484#endif
485
486#if defined (HOST_IS_WINDOWS_OS) && defined(_HOST_AMD64_)
487 const WCHAR * resourceName = W("CLRDEBUGINFOWINDOWSAMD64");
488#endif
489
490#if !defined (HOST_IS_WINDOWS_OS) && defined(_HOST_AMD64_)
491 const WCHAR * resourceName = W("CLRDEBUGINFOCORESYSAMD64");
492#endif
493
494#if defined (HOST_IS_WINDOWS_OS) && defined(_HOST_ARM64_)
495 const WCHAR * resourceName = W("CLRDEBUGINFOWINDOWSARM64");
496#endif
497
498#if !defined (HOST_IS_WINDOWS_OS) && defined(_HOST_ARM64_)
499 const WCHAR * resourceName = W("CLRDEBUGINFOCORESYSARM64");
500#endif
501
502#if defined (HOST_IS_WINDOWS_OS) && defined(_HOST_ARM_)
503 const WCHAR * resourceName = W("CLRDEBUGINFOWINDOWSARM");
504#endif
505
506#if !defined (HOST_IS_WINDOWS_OS) && defined(_HOST_ARM_)
507 const WCHAR * resourceName = W("CLRDEBUGINFOCORESYSARM");
508#endif
509
510 hrGetResource = GetResourceRvaFromResourceSectionRvaByName(pDataTarget, moduleBaseAddress, resourceSectionRVA, 10, resourceName, 0,
511 &debugResourceRVA, &debugResourceSize);
512 useCrossPlatformNaming = SUCCEEDED(hrGetResource);
513
514
515#if defined(HOST_IS_WINDOWS_OS) && (defined(_HOST_X86_) || defined(_HOST_AMD64_) || defined(_HOST_ARM_))
516 #if defined(_HOST_X86_)
517 #define _HOST_MACHINE_TYPE IMAGE_FILE_MACHINE_I386
518 #elif defined(_HOST_AMD64_)
519 #define _HOST_MACHINE_TYPE IMAGE_FILE_MACHINE_AMD64
520 #elif defined(_HOST_ARM_)
521 #define _HOST_MACHINE_TYPE IMAGE_FILE_MACHINE_ARMNT
522 #endif
523
524 // if this is windows, and if host_arch matches target arch then we can fallback to searching for CLRDEBUGINFO on failure
525 if(FAILED(hrGetResource) && (imageFileMachine == _HOST_MACHINE_TYPE))
526 {
527 hrGetResource = GetResourceRvaFromResourceSectionRvaByName(pDataTarget, moduleBaseAddress, resourceSectionRVA, 10, W("CLRDEBUGINFO"), 0,
528 &debugResourceRVA, &debugResourceSize);
529 }
530
531 #undef _HOST_MACHINE_TYPE
532#endif
533 // if the search failed, we don't recognize the CLR
534 if(FAILED(hrGetResource))
535 hr = CORDBG_E_NOT_CLR;
536 }
537
538 CLR_DEBUG_RESOURCE debugResource;
539 if(SUCCEEDED(hr) && debugResourceSize != sizeof(debugResource))
540 {
541 hr = CORDBG_E_NOT_CLR;
542 }
543
544 // Get the special debug resource from the image and return the results
545 if(SUCCEEDED(hr))
546 {
547 hr = ReadFromDataTarget(pDataTarget, moduleBaseAddress + debugResourceRVA, (BYTE*)&debugResource, sizeof(debugResource));
548 }
549 if(SUCCEEDED(hr) && (debugResource.dwVersion != 0))
550 {
551 hr = CORDBG_E_NOT_CLR;
552 }
553
554 // The signature needs to match m_skuId exactly, except for m_skuId=CLR_ID_ONECORE_CLR which is
555 // also compatible with the older CLR_ID_PHONE_CLR signature.
556 if(SUCCEEDED(hr) &&
557 (debugResource.signature != m_skuId) &&
558 !( (debugResource.signature == CLR_ID_PHONE_CLR) && (m_skuId == CLR_ID_ONECORE_CLR) ))
559 {
560 hr = CORDBG_E_NOT_CLR;
561 }
562
563 if(SUCCEEDED(hr) &&
564 (debugResource.signature != CLR_ID_ONECORE_CLR) &&
565 useCrossPlatformNaming)
566 {
567 FormatLongDacModuleName(pDacName, dwDacNameCharCount, imageFileMachine, &fixedFileInfo);
568 swprintf_s(pDbiName, dwDbiNameCharCount, W("%s_%s.dll"), MAIN_DBI_MODULE_NAME_W, W("x86"));
569 }
570 else
571 {
572 if(m_skuId == CLR_ID_V4_DESKTOP)
573 swprintf_s(pDacName, dwDacNameCharCount, W("%s.dll"), CLR_DAC_MODULE_NAME_W);
574 else
575 swprintf_s(pDacName, dwDacNameCharCount, W("%s.dll"), CORECLR_DAC_MODULE_NAME_W);
576 swprintf_s(pDbiName, dwDbiNameCharCount, W("%s.dll"), MAIN_DBI_MODULE_NAME_W);
577 }
578
579 if(SUCCEEDED(hr))
580 {
581 *pdwDbiTimeStamp = debugResource.dwDbiTimeStamp;
582 *pdwDbiSizeOfImage = debugResource.dwDbiSizeOfImage;
583 *pdwDacTimeStamp = debugResource.dwDacTimeStamp;
584 *pdwDacSizeOfImage = debugResource.dwDacSizeOfImage;
585 }
586
587 // any failure should be interpreted as this module not being a CLR
588 if(FAILED(hr))
589 {
590 return CORDBG_E_NOT_CLR;
591 }
592 else
593 {
594 return S_OK;
595 }
596#else
597 swprintf_s(pDacName, dwDacNameCharCount, W("%s"), MAKEDLLNAME_W(CORECLR_DAC_MODULE_NAME_W));
598 swprintf_s(pDbiName, dwDbiNameCharCount, W("%s"), MAKEDLLNAME_W(MAIN_DBI_MODULE_NAME_W));
599
600 pVersion->wMajor = 0;
601 pVersion->wMinor = 0;
602 pVersion->wBuild = 0;
603 pVersion->wRevision = 0;
604
605 *pdwDbiTimeStamp = 0;
606 *pdwDbiSizeOfImage = 0;
607 *pdwDacTimeStamp = 0;
608 *pdwDacSizeOfImage = 0;
609
610 return S_OK;
611#endif // FEATURE_PAL
612}
613
614// Formats the long name for DAC
615HRESULT CLRDebuggingImpl::FormatLongDacModuleName(__out_z __inout_ecount(cchBuffer) WCHAR * pBuffer,
616 DWORD cchBuffer,
617 DWORD targetImageFileMachine,
618 VS_FIXEDFILEINFO * pVersion)
619{
620
621#ifndef HOST_IS_WINDOWS_OS
622 _ASSERTE(!"NYI");
623 return E_NOTIMPL;
624#endif
625
626#if defined(_HOST_X86_)
627 const WCHAR* pHostArch = W("x86");
628#elif defined(_HOST_AMD64_)
629 const WCHAR* pHostArch = W("amd64");
630#elif defined(_HOST_ARM_)
631 const WCHAR* pHostArch = W("arm");
632#elif defined(_HOST_ARM64_)
633 const WCHAR* pHostArch = W("arm64");
634#else
635 _ASSERTE(!"Unknown host arch");
636 return E_NOTIMPL;
637#endif
638
639 const WCHAR* pDacBaseName = NULL;
640 if(m_skuId == CLR_ID_V4_DESKTOP)
641 pDacBaseName = CLR_DAC_MODULE_NAME_W;
642 else if(m_skuId == CLR_ID_CORECLR || m_skuId == CLR_ID_PHONE_CLR || m_skuId == CLR_ID_ONECORE_CLR)
643 pDacBaseName = CORECLR_DAC_MODULE_NAME_W;
644 else
645 {
646 _ASSERTE(!"Unknown SKU id");
647 return E_UNEXPECTED;
648 }
649
650 const WCHAR* pTargetArch = NULL;
651 if(targetImageFileMachine == IMAGE_FILE_MACHINE_I386)
652 {
653 pTargetArch = W("x86");
654 }
655 else if(targetImageFileMachine == IMAGE_FILE_MACHINE_AMD64)
656 {
657 pTargetArch = W("amd64");
658 }
659 else if(targetImageFileMachine == IMAGE_FILE_MACHINE_ARMNT)
660 {
661 pTargetArch = W("arm");
662 }
663 else if(targetImageFileMachine == IMAGE_FILE_MACHINE_ARM64)
664 {
665 pTargetArch = W("arm64");
666 }
667 else
668 {
669 _ASSERTE(!"Unknown target image file machine type");
670 return E_INVALIDARG;
671 }
672
673 const WCHAR* pBuildFlavor = W("");
674 if(pVersion->dwFileFlags & VS_FF_DEBUG)
675 {
676 if(pVersion->dwFileFlags & VS_FF_SPECIALBUILD)
677 pBuildFlavor = W(".dbg");
678 else
679 pBuildFlavor = W(".chk");
680 }
681
682 // WARNING: if you change the formatting make sure you recalculate the maximum
683 // possible size string and verify callers pass a big enough buffer. This doesn't
684 // have to be a tight estimate, just make sure its >= the biggest possible DAC name
685 // and it can be calculated statically
686 DWORD minCchBuffer =
687 (DWORD) wcslen(CLR_DAC_MODULE_NAME_W) + (DWORD) wcslen(CORECLR_DAC_MODULE_NAME_W) + // max name
688 10 + // max host arch
689 10 + // max target arch
690 40 + // max version
691 10 + // max build flavor
692 (DWORD) wcslen(W("name_host_target_version.flavor.dll")) + // max intermediate formatting chars
693 1; // null terminator
694
695 // validate the output buffer is larger than our estimate above
696 _ASSERTE(cchBuffer >= minCchBuffer);
697 if(!(cchBuffer >= minCchBuffer)) return E_INVALIDARG;
698
699 swprintf_s(pBuffer, cchBuffer, W("%s_%s_%s_%u.%u.%u.%02u%s.dll"),
700 pDacBaseName,
701 pHostArch,
702 pTargetArch,
703 pVersion->dwProductVersionMS >> 16,
704 pVersion->dwProductVersionMS & 0xFFFF,
705 pVersion->dwProductVersionLS >> 16,
706 pVersion->dwProductVersionLS & 0xFFFF,
707 pBuildFlavor);
708 return S_OK;
709}
710
711// An implementation of ICLRDebugging::CanUnloadNow
712//
713// Arguments:
714// hModule - a handle to a module provided earlier by ProvideLibrary
715//
716// Returns:
717// S_OK if the library is no longer in use and can be unloaded, S_FALSE otherwise
718//
719STDMETHODIMP CLRDebuggingImpl::CanUnloadNow(HMODULE hModule)
720{
721 // In V4 at least we don't support any unloading.
722 HRESULT hr = S_FALSE;
723
724 return hr;
725}
726
727
728
729STDMETHODIMP CLRDebuggingImpl::QueryInterface(REFIID riid, void **ppvObject)
730{
731 HRESULT hr = S_OK;
732
733 if (riid == __uuidof(IUnknown))
734 {
735 IUnknown *pItf = static_cast<IUnknown *>(this);
736 pItf->AddRef();
737 *ppvObject = pItf;
738 }
739 else if (riid == __uuidof(ICLRDebugging))
740 {
741 ICLRDebugging *pItf = static_cast<ICLRDebugging *>(this);
742 pItf->AddRef();
743 *ppvObject = pItf;
744 }
745 else
746 hr = E_NOINTERFACE;
747
748 return hr;
749}
750
751// Standard AddRef implementation
752ULONG CLRDebuggingImpl::AddRef()
753{
754 return InterlockedIncrement(&m_cRef);
755}
756
757// Standard Release implementation.
758ULONG CLRDebuggingImpl::Release()
759{
760 _ASSERTE(m_cRef > 0);
761
762 ULONG cRef = InterlockedDecrement(&m_cRef);
763
764 if (cRef == 0)
765 delete this; // Relies on virtual dtor to work properly.
766
767 return cRef;
768}
769