diff options
author | dotnet-bot <dotnet-bot@microsoft.com> | 2015-01-30 14:14:42 -0800 |
---|---|---|
committer | dotnet-bot <dotnet-bot@microsoft.com> | 2015-01-30 14:14:42 -0800 |
commit | ef1e2ab328087c61a6878c1e84f4fc5d710aebce (patch) | |
tree | dee1bbb89e9d722e16b0d1485e3cdd1b6c8e2cfa /src/debug/shim | |
download | coreclr-ef1e2ab328087c61a6878c1e84f4fc5d710aebce.tar.gz coreclr-ef1e2ab328087c61a6878c1e84f4fc5d710aebce.tar.bz2 coreclr-ef1e2ab328087c61a6878c1e84f4fc5d710aebce.zip |
Initial commit to populate CoreCLR repo
[tfs-changeset: 1407945]
Diffstat (limited to 'src/debug/shim')
-rw-r--r-- | src/debug/shim/.gitmirror | 1 | ||||
-rw-r--r-- | src/debug/shim/CMakeLists.txt | 13 | ||||
-rw-r--r-- | src/debug/shim/debugshim.cpp | 618 | ||||
-rw-r--r-- | src/debug/shim/debugshim.h | 89 | ||||
-rw-r--r-- | src/debug/shim/debugshim.props | 19 | ||||
-rw-r--r-- | src/debug/shim/dirs.proj | 16 |
6 files changed, 756 insertions, 0 deletions
diff --git a/src/debug/shim/.gitmirror b/src/debug/shim/.gitmirror new file mode 100644 index 0000000000..f507630f94 --- /dev/null +++ b/src/debug/shim/.gitmirror @@ -0,0 +1 @@ +Only contents of this folder, excluding subfolders, will be mirrored by the Git-TFS Mirror.
\ No newline at end of file diff --git a/src/debug/shim/CMakeLists.txt b/src/debug/shim/CMakeLists.txt new file mode 100644 index 0000000000..c444a12049 --- /dev/null +++ b/src/debug/shim/CMakeLists.txt @@ -0,0 +1,13 @@ +add_definitions(-DHOST_IS_WINDOWS_OS) + +if(WIN32) + #use static crt + add_definitions(-MT) +endif(WIN32) + +set(DEBUGSHIM_SOURCES + debugshim.cpp +) + + +add_library(debugshim STATIC ${DEBUGSHIM_SOURCES})
\ No newline at end of file diff --git a/src/debug/shim/debugshim.cpp b/src/debug/shim/debugshim.cpp new file mode 100644 index 0000000000..7f1de80f38 --- /dev/null +++ b/src/debug/shim/debugshim.cpp @@ -0,0 +1,618 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// +//***************************************************************************** +// debugshim.cpp +// + +// +//***************************************************************************** + +#include "debugshim.h" +#include "dbgutil.h" +#include <crtdbg.h> +#include <clrinternal.h> //has the CLR_ID_V4_DESKTOP guid in it +#include "palclr.h" + +#ifndef IMAGE_FILE_MACHINE_ARMNT +#define IMAGE_FILE_MACHINE_ARMNT 0x01c4 // ARM Thumb-2 Little-Endian +#endif + +#ifndef IMAGE_FILE_MACHINE_ARM64 +#define IMAGE_FILE_MACHINE_ARM64 0xAA64 // ARM64 Little-Endian +#endif + +// making the defines very clear, these represent the host architecture - aka +// the arch on which this code is running +#if defined(_X86_) +#define _HOST_X86_ +#elif defined(_AMD64_) +#define _HOST_AMD64_ +#elif defined(_ARM_) +#define _HOST_ARM_ +#elif defined(_ARM64_) +#define _HOST_ARM64_ +#endif + +//***************************************************************************** +// CLRDebuggingImpl implementation (ICLRDebugging) +//***************************************************************************** + +typedef HRESULT (__stdcall *OpenVirtualProcessImplFnPtr)(ULONG64 clrInstanceId, + IUnknown * pDataTarget, + HMODULE hDacDll, + CLR_DEBUGGING_VERSION * pMaxDebuggerSupportedVersion, + REFIID riid, + IUnknown ** ppInstance, + CLR_DEBUGGING_PROCESS_FLAGS * pdwFlags); + +typedef HRESULT (__stdcall *OpenVirtualProcess2FnPtr)(ULONG64 clrInstanceId, + IUnknown * pDataTarget, + HMODULE hDacDll, + REFIID riid, + IUnknown ** ppInstance, + CLR_DEBUGGING_PROCESS_FLAGS * pdwFlags); + +// Implementation of ICLRDebugging::OpenVirtualProcess +// +// Arguments: +// moduleBaseAddress - the address of the module which might be a CLR +// pDataTarget - the data target for inspecting the process +// pLibraryProvider - a callback for locating DBI and DAC +// pMaxDebuggerSupportedVersion - the max version of the CLR that this debugger will support debugging +// riidProcess - the IID of the interface that should be passed back in ppProcess +// ppProcess - output for the ICorDebugProcess# if this module is a CLR +// pVersion - the CLR version if this module is a CLR +// pFlags - output, see the CLR_DEBUGGING_PROCESS_FLAGS for more details. Right now this has only one possible +// value which indicates this runtime had an unhandled exception +STDMETHODIMP CLRDebuggingImpl::OpenVirtualProcess( + ULONG64 moduleBaseAddress, + IUnknown * pDataTarget, + ICLRDebuggingLibraryProvider * pLibraryProvider, + CLR_DEBUGGING_VERSION * pMaxDebuggerSupportedVersion, + REFIID riidProcess, + IUnknown ** ppProcess, + CLR_DEBUGGING_VERSION * pVersion, + CLR_DEBUGGING_PROCESS_FLAGS * pFlags) +{ + //PRECONDITION(CheckPointer(pDataTarget)); + + HRESULT hr = S_OK; + ICorDebugDataTarget * pDt = NULL; + HMODULE hDbi = NULL; + HMODULE hDac = NULL; + DWORD dbiTimestamp; + DWORD dbiSizeOfImage; + WCHAR dbiName[MAX_PATH]; + DWORD dacTimestamp; + DWORD dacSizeOfImage; + WCHAR dacName[MAX_PATH]; + CLR_DEBUGGING_VERSION version; + BOOL versionSupportedByCaller = FALSE; + + + + // argument checking + if( (ppProcess != NULL || pFlags != NULL) && pLibraryProvider == NULL) + { + hr = E_POINTER; // the library provider must be specified if either + // ppProcess or pFlags is non-NULL + } + else if( (ppProcess != NULL || pFlags != NULL) && pMaxDebuggerSupportedVersion == NULL) + { + hr = E_POINTER; // the max supported version must be specified if either + // ppProcess or pFlags is non-NULL + } + else if(pVersion != NULL && pVersion->wStructVersion != 0) + { + hr = CORDBG_E_UNSUPPORTED_VERSION_STRUCT; + } + else if(FAILED(pDataTarget->QueryInterface(__uuidof(ICorDebugDataTarget), (void**) &pDt))) + { + hr = CORDBG_E_MISSING_DATA_TARGET_INTERFACE; + } + + if(SUCCEEDED(hr)) + { + // get CLR version + // The expectation is that new versions of the CLR will continue to use the same GUID + // (unless there's a reason to hide them from older shims), but debuggers will tell us the + // CLR version they're designed for and mscordbi.dll can decide whether or not to accept it. + version.wStructVersion = 0; + hr = GetCLRInfo(pDt, + moduleBaseAddress, + &version, + &dbiTimestamp, + &dbiSizeOfImage, + dbiName, + MAX_PATH, + &dacTimestamp, + &dacSizeOfImage, + dacName, + MAX_PATH); + } + + // If we need to fetch either the process info or the flags info then we need to find + // mscordbi and DAC and do the version specific OVP work + if(SUCCEEDED(hr) && (ppProcess != NULL || pFlags != NULL)) + { + // ask library provider for dbi + if(FAILED(pLibraryProvider->ProvideLibrary(dbiName, dbiTimestamp, dbiSizeOfImage, &hDbi)) || + hDbi == NULL) + { + hr = CORDBG_E_LIBRARY_PROVIDER_ERROR; + } + + if(SUCCEEDED(hr)) + { + // Adjust the timestamp and size of image if this DAC is a known buggy version and needs to be retargeted + RetargetDacIfNeeded(&dacTimestamp, &dacSizeOfImage); + + // ask library provider for dac + if(FAILED(pLibraryProvider->ProvideLibrary(dacName, dacTimestamp, dacSizeOfImage, &hDac)) || + hDac == NULL) + { + hr = CORDBG_E_LIBRARY_PROVIDER_ERROR; + } + } + + if(SUCCEEDED(hr)) + { + // get access to OVP and call it + OpenVirtualProcessImplFnPtr ovpFn = (OpenVirtualProcessImplFnPtr) GetProcAddress(hDbi, "OpenVirtualProcessImpl"); + if(ovpFn == NULL) + { + // Fallback to CLR v4 Beta1 path, but skip some of the checking we'd normally do (maxSupportedVersion, etc.) + OpenVirtualProcess2FnPtr ovp2Fn = (OpenVirtualProcess2FnPtr) GetProcAddress(hDbi, "OpenVirtualProcess2"); + if (ovp2Fn == NULL) + { + hr = CORDBG_E_LIBRARY_PROVIDER_ERROR; + } + else + { + hr = ovp2Fn(moduleBaseAddress, pDataTarget, hDac, riidProcess, ppProcess, pFlags); + } + } + else + { + // Have a CLR v4 Beta2+ DBI, call it and let it do the version check + hr = ovpFn(moduleBaseAddress, pDataTarget, hDac, pMaxDebuggerSupportedVersion, riidProcess, ppProcess, pFlags); + if(FAILED(hr)) + { + _ASSERTE(ppProcess == NULL || *ppProcess == NULL); + _ASSERTE(pFlags == NULL || *pFlags == 0); + } + } + } + } + + //version is still valid in some failure cases + if(pVersion != NULL && + (SUCCEEDED(hr) || + (hr == CORDBG_E_UNSUPPORTED_DEBUGGING_MODEL) || + (hr == CORDBG_E_UNSUPPORTED_FORWARD_COMPAT))) + { + memcpy(pVersion, &version, sizeof(CLR_DEBUGGING_VERSION)); + } + + // free the data target we QI'ed earlier + if(pDt != NULL) + { + pDt->Release(); + } + + return hr; +} + +// Checks to see if this DAC is one of a known set of old DAC builds which contains an issue. +// If so we retarget to a newer compatible version which has the bug fixed. This is done +// by changing the PE information used to lookup the DAC. +// +// Arguments +// pdwTimeStamp - on input, the timestamp of DAC as embedded in the CLR image +// on output, a potentially new timestamp for an updated DAC to use +// instead +// pdwSizeOfImage - on input, the sizeOfImage of DAC as embedded in the CLR image +// on output, a potentially new sizeOfImage for an updated DAC to use +// instead +VOID CLRDebuggingImpl::RetargetDacIfNeeded(DWORD* pdwTimeStamp, + DWORD* pdwSizeOfImage) +{ + + // This code is auto generated by the CreateRetargetTable tool + // on 3/4/2011 6:35 PM + // and then copy-pasted here. + // + // + // + // Retarget the GDR1 amd64 build + if( (*pdwTimeStamp == 0x4d536868) && (*pdwSizeOfImage == 0x17b000)) + { + *pdwTimeStamp = 0x4d71a160; + *pdwSizeOfImage = 0x17b000; + } + // Retarget the GDR1 x86 build + else if( (*pdwTimeStamp == 0x4d5368f2) && (*pdwSizeOfImage == 0x120000)) + { + *pdwTimeStamp = 0x4d71a14f; + *pdwSizeOfImage = 0x120000; + } + // Retarget the RTM amd64 build + else if( (*pdwTimeStamp == 0x4ba21fa7) && (*pdwSizeOfImage == 0x17b000)) + { + *pdwTimeStamp = 0x4d71a13c; + *pdwSizeOfImage = 0x17b000; + } + // Retarget the RTM x86 build + else if( (*pdwTimeStamp == 0x4ba1da25) && (*pdwSizeOfImage == 0x120000)) + { + *pdwTimeStamp = 0x4d71a128; + *pdwSizeOfImage = 0x120000; + } + // This code is auto generated by the CreateRetargetTable tool + // on 8/17/2011 1:28 AM + // and then copy-pasted here. + // + // + // + // Retarget the GDR2 amd64 build + else if( (*pdwTimeStamp == 0x4da428c7) && (*pdwSizeOfImage == 0x17b000)) + { + *pdwTimeStamp = 0x4e4b7bc2; + *pdwSizeOfImage = 0x17b000; + } + // Retarget the GDR2 x86 build + else if( (*pdwTimeStamp == 0x4da3fe52) && (*pdwSizeOfImage == 0x120000)) + { + *pdwTimeStamp = 0x4e4b7bb1; + *pdwSizeOfImage = 0x120000; + } + // End auto-generated code +} + +#define PE_FIXEDFILEINFO_SIGNATURE 0xFEEF04BD + +// The format of the special debugging resource we embed in CLRs starting in +// v4 +struct CLR_DEBUG_RESOURCE +{ + DWORD dwVersion; + GUID signature; + DWORD dwDacTimeStamp; + DWORD dwDacSizeOfImage; + DWORD dwDbiTimeStamp; + DWORD dwDbiSizeOfImage; +}; + +// Checks to see if a module is a CLR and if so, fetches the debug data +// from the embedded resource +// +// Arguments +// pDataTarget - dataTarget for the process we are inspecting +// moduleBaseAddress - base address of a module we should inspect +// pVersion - output, the version of the CLR detected if this is a CLR +// pdwDbiTimeStamp - the timestamp of DBI as embedded in the CLR image +// pdwDbiSizeOfImage - the SizeOfImage of DBI as embedded in the CLR image +// pDbiName - output, the filename of DBI (as calculated by this function but that might change) +// dwDbiNameCharCount - input, the number of WCHARs in the buffer pointed to by pDbiName +// pdwDacTimeStampe - the timestamp of DAC as embedded in the CLR image +// pdwDacSizeOfImage - the SizeOfImage of DAC as embedded in the CLR image +// pDacName - output, the filename of DAC (as calculated by this function but that might change) +// dwDacNameCharCount - input, the number of WCHARs in the buffer pointed to by pDacName +HRESULT CLRDebuggingImpl::GetCLRInfo(ICorDebugDataTarget* pDataTarget, + ULONG64 moduleBaseAddress, + CLR_DEBUGGING_VERSION* pVersion, + DWORD* pdwDbiTimeStamp, + DWORD* pdwDbiSizeOfImage, + __out_z __inout_ecount(dwDbiNameCharCount) WCHAR* pDbiName, + DWORD dwDbiNameCharCount, + DWORD* pdwDacTimeStamp, + DWORD* pdwDacSizeOfImage, + __out_z __inout_ecount(dwDacNameCharCount) WCHAR* pDacName, + DWORD dwDacNameCharCount) +{ + WORD imageFileMachine = 0; + DWORD resourceSectionRVA = 0; + HRESULT hr = GetMachineAndResourceSectionRVA(pDataTarget, moduleBaseAddress, &imageFileMachine, &resourceSectionRVA); + + // We want the version resource which has type = RT_VERSION = 16, name = 1, language = 0x409 + DWORD versionResourceRVA = 0; + DWORD versionResourceSize = 0; + if(SUCCEEDED(hr)) + { + hr = GetResourceRvaFromResourceSectionRva(pDataTarget, moduleBaseAddress, resourceSectionRVA, 16, 1, 0x409, + &versionResourceRVA, &versionResourceSize); + } + + // At last we get our version info + VS_FIXEDFILEINFO fixedFileInfo = {0}; + if(SUCCEEDED(hr)) + { + // The version resource has 3 words, then the unicode string "VS_VERSION_INFO" + // (16 WCHARS including the null terminator) + // then padding to a 32-bit boundary, then the VS_FIXEDFILEINFO struct + DWORD fixedFileInfoRVA = ((versionResourceRVA + 3*2 + 16*2 + 3)/4)*4; + hr = ReadFromDataTarget(pDataTarget, moduleBaseAddress + fixedFileInfoRVA, (BYTE*)&fixedFileInfo, sizeof(fixedFileInfo)); + } + + //Verify the signature on the version resource + if(SUCCEEDED(hr) && fixedFileInfo.dwSignature != PE_FIXEDFILEINFO_SIGNATURE) + { + hr = CORDBG_E_NOT_CLR; + } + + // Record the version information + if(SUCCEEDED(hr)) + { + pVersion->wMajor = (WORD) (fixedFileInfo.dwProductVersionMS >> 16); + pVersion->wMinor = (WORD) (fixedFileInfo.dwProductVersionMS & 0xFFFF); + pVersion->wBuild = (WORD) (fixedFileInfo.dwProductVersionLS >> 16); + pVersion->wRevision = (WORD) (fixedFileInfo.dwProductVersionLS & 0xFFFF); + } + + // Now grab the special clr debug info resource + // We may need to scan a few different names searching though... + // 1) CLRDEBUGINFO<host_os><host_arch> where host_os = 'WINDOWS' or 'CORESYS' and host_arch = 'X86' or 'ARM' or 'AMD64' + // 2) For back-compat if the host os is windows and the host architecture matches the target then CLRDEBUGINFO is used with no suffix. + DWORD debugResourceRVA = 0; + DWORD debugResourceSize = 0; + BOOL useCrossPlatformNaming = FALSE; + if(SUCCEEDED(hr)) + { + // the initial state is that we haven't found a proper resource + HRESULT hrGetResource = E_FAIL; + + // First check for the resource which has type = RC_DATA = 10, name = "CLRDEBUGINFO<host_os><host_arch>", language = 0 + // So far we only support windows x86 and coresys x86 (we are building some other architectures, but they aren't tested and turned on yet it appears) +#if defined (HOST_IS_WINDOWS_OS) && defined(_HOST_X86_) + hrGetResource = GetResourceRvaFromResourceSectionRvaByName(pDataTarget, moduleBaseAddress, resourceSectionRVA, 10, W("CLRDEBUGINFOWINDOWSX86"), 0, + &debugResourceRVA, &debugResourceSize); + useCrossPlatformNaming = SUCCEEDED(hrGetResource); +#endif + +#if !defined (HOST_IS_WINDOWS_OS) && defined(_HOST_X86_) + hrGetResource = GetResourceRvaFromResourceSectionRvaByName(pDataTarget, moduleBaseAddress, resourceSectionRVA, 10, W("CLRDEBUGINFOCORESYSX86"), 0, + &debugResourceRVA, &debugResourceSize); + useCrossPlatformNaming = SUCCEEDED(hrGetResource); +#endif + + +#if defined(HOST_IS_WINDOWS_OS) && (defined(_HOST_X86_) || defined(_HOST_AMD64_) || defined(_HOST_ARM_)) + #if defined(_HOST_X86_) + #define _HOST_MACHINE_TYPE IMAGE_FILE_MACHINE_I386 + #elif defined(_HOST_AMD64_) + #define _HOST_MACHINE_TYPE IMAGE_FILE_MACHINE_AMD64 + #elif defined(_HOST_ARM_) + #define _HOST_MACHINE_TYPE IMAGE_FILE_MACHINE_ARMNT + #endif + + // if this is windows, and if host_arch matches target arch then we can fallback to searching for CLRDEBUGINFO on failure + if(FAILED(hrGetResource) && (imageFileMachine == _HOST_MACHINE_TYPE)) + { + hrGetResource = GetResourceRvaFromResourceSectionRvaByName(pDataTarget, moduleBaseAddress, resourceSectionRVA, 10, W("CLRDEBUGINFO"), 0, + &debugResourceRVA, &debugResourceSize); + } + + #undef _HOST_MACHINE_TYPE +#endif + // if the search failed, we don't recognize the CLR + if(FAILED(hrGetResource)) + hr = CORDBG_E_NOT_CLR; + } + + CLR_DEBUG_RESOURCE debugResource; + if(SUCCEEDED(hr) && debugResourceSize != sizeof(debugResource)) + { + hr = CORDBG_E_NOT_CLR; + } + + // Get the special debug resource from the image and return the results + if(SUCCEEDED(hr)) + { + hr = ReadFromDataTarget(pDataTarget, moduleBaseAddress + debugResourceRVA, (BYTE*)&debugResource, sizeof(debugResource)); + } + if(SUCCEEDED(hr) && (debugResource.dwVersion != 0)) + { + hr = CORDBG_E_NOT_CLR; + } + + // The signature needs to match m_skuId exactly, except for m_skuId=CLR_ID_ONECORE_CLR which is + // also compatible with the older CLR_ID_PHONE_CLR signature. + if(SUCCEEDED(hr) && + (debugResource.signature != m_skuId) && + !( (debugResource.signature == CLR_ID_PHONE_CLR) && (m_skuId == CLR_ID_ONECORE_CLR) )) + { + hr = CORDBG_E_NOT_CLR; + } + + if(SUCCEEDED(hr) && + (debugResource.signature != CLR_ID_ONECORE_CLR) && + useCrossPlatformNaming) + { + FormatLongDacModuleName(pDacName, dwDacNameCharCount, imageFileMachine, &fixedFileInfo); + swprintf_s(pDbiName, dwDbiNameCharCount, W("%s_%s.dll"), MAIN_DBI_MODULE_NAME_W, W("x86")); + } + else + { + if(m_skuId == CLR_ID_V4_DESKTOP) + swprintf_s(pDacName, dwDacNameCharCount, W("%s.dll"), CLR_DAC_MODULE_NAME_W); + else + swprintf_s(pDacName, dwDacNameCharCount, W("%s.dll"), CORECLR_DAC_MODULE_NAME_W); + swprintf_s(pDbiName, dwDbiNameCharCount, W("%s.dll"), MAIN_DBI_MODULE_NAME_W); + } + + if(SUCCEEDED(hr)) + { + *pdwDbiTimeStamp = debugResource.dwDbiTimeStamp; + *pdwDbiSizeOfImage = debugResource.dwDbiSizeOfImage; + *pdwDacTimeStamp = debugResource.dwDacTimeStamp; + *pdwDacSizeOfImage = debugResource.dwDacSizeOfImage; + } + + // any failure should be interpreted as this module not being a CLR + if(FAILED(hr)) + { + return CORDBG_E_NOT_CLR; + } + else + { + return S_OK; + } +} + +// Formats the long name for DAC +HRESULT CLRDebuggingImpl::FormatLongDacModuleName(__out_z __inout_ecount(cchBuffer) WCHAR * pBuffer, + DWORD cchBuffer, + DWORD targetImageFileMachine, + VS_FIXEDFILEINFO * pVersion) +{ + +#ifndef HOST_IS_WINDOWS_OS + _ASSERTE(!"NYI"); + return E_NOTIMPL; +#endif + +#if defined(_HOST_X86_) + WCHAR* pHostArch = W("x86"); +#elif defined(_HOST_AMD64_) + WCHAR* pHostArch = W("amd64"); +#elif defined(_HOST_ARM_) + WCHAR* pHostArch = W("arm"); +#elif defined(_HOST_ARM64_) + WCHAR* pHostArch = W("arm64"); +#else + _ASSERTE(!"Unknown host arch"); + return E_NOTIMPL; +#endif + + WCHAR* pDacBaseName = NULL; + if(m_skuId == CLR_ID_V4_DESKTOP) + pDacBaseName = CLR_DAC_MODULE_NAME_W; + else if(m_skuId == CLR_ID_CORECLR || m_skuId == CLR_ID_PHONE_CLR || m_skuId == CLR_ID_ONECORE_CLR) + pDacBaseName = CORECLR_DAC_MODULE_NAME_W; + else + { + _ASSERTE(!"Unknown SKU id"); + return E_UNEXPECTED; + } + + WCHAR* pTargetArch = NULL; + if(targetImageFileMachine == IMAGE_FILE_MACHINE_I386) + { + pTargetArch = W("x86"); + } + else if(targetImageFileMachine == IMAGE_FILE_MACHINE_AMD64) + { + pTargetArch = W("amd64"); + } + else if(targetImageFileMachine == IMAGE_FILE_MACHINE_ARMNT) + { + pTargetArch = W("arm"); + } + else if(targetImageFileMachine == IMAGE_FILE_MACHINE_ARM64) + { + pTargetArch = W("arm64"); + } + else + { + _ASSERTE(!"Unknown target image file machine type"); + return E_INVALIDARG; + } + + WCHAR* pBuildFlavor = W(""); + if(pVersion->dwFileFlags & VS_FF_DEBUG) + { + if(pVersion->dwFileFlags & VS_FF_SPECIALBUILD) + pBuildFlavor = W(".dbg"); + else + pBuildFlavor = W(".chk"); + } + + // WARNING: if you change the formatting make sure you recalculate the maximum + // possible size string and verify callers pass a big enough buffer. This doesn't + // have to be a tight estimate, just make sure its >= the biggest possible DAC name + // and it can be calculated statically + DWORD minCchBuffer = + (DWORD) wcslen(CLR_DAC_MODULE_NAME_W) + (DWORD) wcslen(CORECLR_DAC_MODULE_NAME_W) + // max name + 10 + // max host arch + 10 + // max target arch + 40 + // max version + 10 + // max build flavor + (DWORD) wcslen(W("name_host_target_version.flavor.dll")) + // max intermediate formatting chars + 1; // null terminator + + // validate the output buffer is larger than our estimate above + _ASSERTE(cchBuffer >= minCchBuffer); + if(!(cchBuffer >= minCchBuffer)) return E_INVALIDARG; + + swprintf_s(pBuffer, cchBuffer, W("%s_%s_%s_%u.%u.%u.%02u%s.dll"), + pDacBaseName, + pHostArch, + pTargetArch, + pVersion->dwProductVersionMS >> 16, + pVersion->dwProductVersionMS & 0xFFFF, + pVersion->dwProductVersionLS >> 16, + pVersion->dwProductVersionLS & 0xFFFF, + pBuildFlavor); + return S_OK; +} + +// An implementation of ICLRDebugging::CanUnloadNow +// +// Arguments: +// hModule - a handle to a module provided earlier by ProvideLibrary +// +// Returns: +// S_OK if the library is no longer in use and can be unloaded, S_FALSE otherwise +// +STDMETHODIMP CLRDebuggingImpl::CanUnloadNow(HMODULE hModule) +{ + // In V4 at least we don't support any unloading. + HRESULT hr = S_FALSE; + + return hr; +} + + + +STDMETHODIMP CLRDebuggingImpl::QueryInterface(REFIID riid, void **ppvObject) +{ + HRESULT hr = S_OK; + + if (riid == __uuidof(IUnknown)) + { + IUnknown *pItf = static_cast<IUnknown *>(this); + pItf->AddRef(); + *ppvObject = pItf; + } + else if (riid == __uuidof(ICLRDebugging)) + { + ICLRDebugging *pItf = static_cast<ICLRDebugging *>(this); + pItf->AddRef(); + *ppvObject = pItf; + } + else + hr = E_NOINTERFACE; + + return hr; +} + +// Standard AddRef implementation +ULONG CLRDebuggingImpl::AddRef() +{ + return InterlockedIncrement(&m_cRef); +} + +// Standard Release implementation. +ULONG CLRDebuggingImpl::Release() +{ + _ASSERTE(m_cRef > 0); + + ULONG cRef = InterlockedDecrement(&m_cRef); + + if (cRef == 0) + delete this; // Relies on virtual dtor to work properly. + + return cRef; +} diff --git a/src/debug/shim/debugshim.h b/src/debug/shim/debugshim.h new file mode 100644 index 0000000000..c83b86c4d1 --- /dev/null +++ b/src/debug/shim/debugshim.h @@ -0,0 +1,89 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// +//***************************************************************************** +// debugshim.h +// + +// +//***************************************************************************** + +#ifndef _DEBUG_SHIM_ +#define _DEBUG_SHIM_ + +#include <metahost.h> +#include "cor.h" +#include "cordebug.h" +#include <wchar.h> + +#define CORECLR_DAC_MODULE_NAME_W W("mscordaccore") +#define CLR_DAC_MODULE_NAME_W W("mscordacwks") +#define MAIN_DBI_MODULE_NAME_W W("mscordbi") + +// forward declaration +struct ICorDebugDataTarget; + +// ICLRDebugging implementation. +class CLRDebuggingImpl : public ICLRDebugging +{ + +public: + CLRDebuggingImpl(GUID skuId) : m_cRef(0), m_skuId(skuId) + { + } + +public: + // ICLRDebugging methods: + STDMETHOD(OpenVirtualProcess( + ULONG64 moduleBaseAddress, + IUnknown * pDataTarget, + ICLRDebuggingLibraryProvider * pLibraryProvider, + CLR_DEBUGGING_VERSION * pMaxDebuggerSupportedVersion, + REFIID riidProcess, + IUnknown ** ppProcess, + CLR_DEBUGGING_VERSION * pVersion, + CLR_DEBUGGING_PROCESS_FLAGS * pFlags)); + + STDMETHOD(CanUnloadNow(HMODULE hModule)); + + //IUnknown methods: + STDMETHOD(QueryInterface( + REFIID riid, + void **ppvObject)); + + // Standard AddRef implementation + STDMETHOD_(ULONG, AddRef()); + + // Standard Release implementation. + STDMETHOD_(ULONG, Release()); + + + +private: + VOID RetargetDacIfNeeded(DWORD* pdwTimeStamp, + DWORD* pdwSizeOfImage); + + HRESULT GetCLRInfo(ICorDebugDataTarget * pDataTarget, + ULONG64 moduleBaseAddress, + CLR_DEBUGGING_VERSION * pVersion, + DWORD * pdwDbiTimeStamp, + DWORD * pdwDbiSizeOfImage, + __out_z __inout_ecount(dwDbiNameCharCount) WCHAR * pDbiName, + DWORD dwDbiNameCharCount, + DWORD * pdwDacTimeStamp, + DWORD * pdwDacSizeOfImage, + __out_z __inout_ecount(dwDacNameCharCount) WCHAR * pDacName, + DWORD dwDacNameCharCount); + + HRESULT FormatLongDacModuleName(__out_z __inout_ecount(cchBuffer) WCHAR * pBuffer, + DWORD cchBuffer, + DWORD targetImageFileMachine, + VS_FIXEDFILEINFO * pVersion); + + volatile LONG m_cRef; + GUID m_skuId; + +}; // class CLRDebuggingImpl + +#endif diff --git a/src/debug/shim/debugshim.props b/src/debug/shim/debugshim.props new file mode 100644 index 0000000000..8d3bb3fe65 --- /dev/null +++ b/src/debug/shim/debugshim.props @@ -0,0 +1,19 @@ +<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="dogfood"> + <PropertyGroup> + <TargetType>LIBRARY</TargetType> + <OutputPath>$(ClrLibDest)</OutputPath> + <LinkSubsystem>windows</LinkSubsystem> + <UseMsvcrt /> + <ExceptionHandling>$(Sehonly)</ExceptionHandling> + <UserIncludes>$(UserIncludes); + ..\; + ..\..\inc; + ..\..\..\inc; + </UserIncludes> + <CDefines>$(CDefines);UNICODE;_UNICODE</CDefines> + <CDefines Condition="$(HostMachineOS)=='windows'">$(CDefines);HOST_IS_WINDOWS_OS</CDefines> + </PropertyGroup> + <ItemGroup> + <CppCompile Include="..\debugshim.cpp" /> + </ItemGroup> +</Project> diff --git a/src/debug/shim/dirs.proj b/src/debug/shim/dirs.proj new file mode 100644 index 0000000000..45798d6237 --- /dev/null +++ b/src/debug/shim/dirs.proj @@ -0,0 +1,16 @@ +<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.props" /> + + <PropertyGroup> + <BuildInPhase1>true</BuildInPhase1> + <BuildInPhaseDefault>false</BuildInPhaseDefault> + <BuildCoreBinaries>true</BuildCoreBinaries> + <BuildSysBinaries>true</BuildSysBinaries> + </PropertyGroup> + + <ItemGroup Condition="'$(BuildExePhase)' == '1'"> + <ProjectFile Include="HostLocal\debugshim.nativeproj" /> + </ItemGroup> + + <Import Project="$(_NTDRIVE)$(_NTROOT)\tools\Microsoft.DevDiv.Traversal.targets" /> +</Project> |