2 // Copyright (c) Microsoft. All rights reserved.
3 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
5 //*****************************************************************************
10 // Dll* routines for entry points, and support for COM framework. The class
11 // factory and other routines live in this module.
13 //*****************************************************************************
15 #include "classfactory.h"
18 #include "metadataexports.h"
19 #if defined(FEATURE_DBGIPC_TRANSPORT_DI)
20 #include "dbgtransportsession.h"
21 #include "dbgtransportmanager.h"
22 #endif // FEATURE_DBGIPC_TRANSPORT_DI
24 //********** Globals. *********************************************************
26 HINSTANCE g_hInst; // Instance handle to this piece of code.
29 //-----------------------------------------------------------------------------
30 // SxS Versioning story for Mscordbi (ICorDebug + friends)
31 //-----------------------------------------------------------------------------
33 //-----------------------------------------------------------------------------
34 // In v1.0, we declared that mscordbi was a "shared" component, which means
35 // that we promised to provide it from now until the end of time. So every CLR implementation
36 // needs an Mscordbi that implements the everett guids for CorDebug + CorPublish.
38 // This works fine for CorPublish, which is truly shared.
39 // CorDebug however is "versioned" not "shared" - each version of the CLR has its own disjoint copy.
41 // Thus creating a CorDebug object requires a version parameter.
42 // CoCreateInstance doesn't have a the version param, so we use the new (v2.0+)
43 // shim interface CreateDebuggingInterfaceFromVersion.
45 // ** So in summary: **
46 // - Dlls don't do self-registration; they're registered by setup using .vrg files.
47 // - All CLR versions (past + future) must have the same registry footprint w.r.t mscordbi.
48 // This just means that all CLRs have the same mscordbi.vrg file.
49 // - CorDebug is in fact versioned and each CLR version has its own copy.
50 // - In v1.0/1.1, CorDebug was a CoClass. In v2.0+, it is not a CoClass and is created via the
51 // CreateDebuggingInterfaceFromVersion shim API, which takes a version parameter.
52 // - CorDebug must be SxS. V1.1 must only get the V1.1 version, and V2.0 must only get the V2.0 version.
53 // V1.1: Clients will cocreate to get CorDebug. v1.1 will be the only mscordbi!DllGetClassObject
54 // that provides a CorDebug, so CoCreateInstance will guarantee getting a v1.1 object.
55 // V2.0: Clients use the new version-aware shim API, so it's not an issue.
57 // ** Preparing for Life in a Single-CLR world: **
58 // In Orcas (v3), we expect to run on single-CLR. There will only be 1 mscordbi, and it will service all versions.
59 // For whidbey (v2), we want to be able to flip a knob and pretend to be orcas (for testing purposes).
61 // Here's how to do that:
62 // - copy whidbey mscordbi & dac over the everett mscordbi.
63 // - When VS cocreates w/ the everett-guid, it will load the mscordbi on the everett path (
64 // which will be whidbey dll), and ask for the everett guid.
65 // - re-add CorDebug to the g_CoClasses list.
68 //********** Locals. **********************************************************
71 //********** Code. ************************************************************
74 //*****************************************************************************
75 // Standard public helper to create a Cordb object (ICorDebug instance).
76 // This is used by the shim to get the Cordb object out of this module.
77 // This is the creation path for V2.0+ for CorDebug using the in-process debugging
78 // architecture (ICorDebug). In CLR v4+ debugger may choose to use the out-of-process
79 // architecture to get an ICorDebugProcess directly (IClrDebugging::OpenVirtualProcess).
81 // This was used by the Mix07 release of Silverlight, but it didn't properly support versioning
82 // and we no longer support it's debugger protocol so we require callers to use
83 // code:CoreCLRCreateCordbObject instead.
85 // This is also still used on Mac - multi-instance debugging and debugger
86 // versioning isn't really implemented there yet. This probably needs to change.
87 //*****************************************************************************
88 STDAPI CreateCordbObject(int iDebuggerVersion, IUnknown ** ppCordb)
90 #if defined(FEATURE_CORECLR) && !defined(FEATURE_DBGIPC_TRANSPORT_DI) && !defined(FEATURE_CORESYSTEM)
91 // This API should not be called for Windows CoreCLR unless we are doing interop-debugging
92 // (which is only supported internally). Use code:CoreCLRCreateCordbObject instead.
93 if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_DbgEnableMixedModeDebugging) == 0)
95 _ASSERTE(!"Deprecated entry point CreateCordbObject() is called on Windows CoreCLR\n");
98 #endif // FEATURE_CORECLR && !FEATURE_DBGIPC_TRANSPORT_DI
104 if (iDebuggerVersion != CorDebugVersion_2_0 && iDebuggerVersion != CorDebugVersion_4_0)
109 return Cordb::CreateObject((CorDebugInterfaceVersion)iDebuggerVersion, IID_ICorDebug, (void **) ppCordb);
112 #if defined(FEATURE_CORECLR)
115 // Telesto Creation path - only way to debug multi-instance.
116 // This supercedes code:CreateCordbObject
119 // iDebuggerVersion - version of ICorDebug interfaces that the debugger is requesting
120 // pid - pid of debuggee that we're attaching to.
121 // hmodTargetCLR - module handle to clr in target pid that we're attaching to.
122 // ppCordb - (out) the resulting ICorDebug object.
125 // It's inconsistent that this takes a (handle, pid) but hands back an ICorDebug instead of an ICorDebugProcess.
126 // Callers will need to call *ppCordb->DebugActiveProcess(pid).
127 STDAPI CoreCLRCreateCordbObject(int iDebuggerVersion, DWORD pid, HMODULE hmodTargetCLR, IUnknown ** ppCordb)
133 if ((iDebuggerVersion < CorDebugVersion_2_0) ||
134 (iDebuggerVersion > CorDebugLatestVersion))
140 // Create the ICorDebug object
142 RSExtSmartPtr<ICorDebug> pCordb;
143 Cordb::CreateObject((CorDebugInterfaceVersion)iDebuggerVersion, IID_ICorDebug, (void **) &pCordb);
145 // @dbgtodo - we should stash the pid and validate that it's the same pid we're attaching to in ICorDebug::DebugActiveProcess.
148 // Associate it with the target instance
150 HRESULT hr = static_cast<Cordb*>(pCordb.GetValue())->SetTargetCLR(hmodTargetCLR);
157 // Assign to out parameter.
159 hr = pCordb->QueryInterface(IID_IUnknown, (void**) ppCordb);
161 // Implicit release of pUnk, pCordb
165 #endif // FEATURE_CORECLR
170 //*****************************************************************************
171 // The main dll entry point for this module. This routine is called by the
172 // OS when the dll gets loaded. Control is simply deferred to the main code.
173 //*****************************************************************************
174 BOOL WINAPI DbgDllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
176 // Save off the instance handle for later use.
180 case DLL_PROCESS_ATTACH:
185 int err = PAL_InitializeDLL();
193 static int BreakOnDILoad = -1;
194 if (BreakOnDILoad == -1)
195 BreakOnDILoad = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_BreakOnDILoad);
199 _ASSERTE(!"DI Loaded");
205 WCHAR rcFile[_MAX_PATH];
206 WszGetModuleFileName(hInstance, rcFile, NumItems(rcFile));
207 LOG((LF_CORDB, LL_INFO10000,
208 "DI::DbgDllMain: load right side support from file '%s'\n",
215 DbgRSThread::s_TlsSlot = TlsAlloc();
216 _ASSERTE(DbgRSThread::s_TlsSlot != TLS_OUT_OF_INDEXES);
219 #if defined(FEATURE_DBGIPC_TRANSPORT_DI)
220 g_pDbgTransportTarget = new (nothrow) DbgTransportTarget();
221 if (g_pDbgTransportTarget == NULL)
224 if (FAILED(g_pDbgTransportTarget->Init()))
226 #endif // FEATURE_DBGIPC_TRANSPORT_DI
230 case DLL_THREAD_DETACH:
233 StressLog::ThreadDetach((ThreadStressLog*) ClrFlsGetValue(TlsIdx_StressLog));
237 // DbgRSThread are lazily created when we call GetThread(),
238 // So we don't need to do anything in DLL_THREAD_ATTACH,
239 // But this is our only chance to destroy the thread object.
240 DbgRSThread * p = DbgRSThread::GetThread();
247 case DLL_PROCESS_DETACH:
249 #if defined(FEATURE_DBGIPC_TRANSPORT_DI)
250 if (g_pDbgTransportTarget != NULL)
252 g_pDbgTransportTarget->Shutdown();
253 delete g_pDbgTransportTarget;
254 g_pDbgTransportTarget = NULL;
256 #endif // FEATURE_DBGIPC_TRANSPORT_DI
259 TlsFree(DbgRSThread::s_TlsSlot);
260 DbgRSThread::s_TlsSlot = TLS_OUT_OF_INDEXES;
270 // The obsolete v1 CLSID - see comment above for details.
271 static const GUID CLSID_CorDebug_V1 = {0x6fef44d0,0x39e7,0x4c77, { 0xbe,0x8e,0xc9,0xf8,0xcf,0x98,0x86,0x30}};
273 #if defined(FEATURE_DBGIPC_TRANSPORT_DI)
275 // GUID for pipe-based debugging (Unix platforms)
276 const GUID CLSID_CorDebug_Telesto = {0x8bd1daae, 0x188e, 0x42f4, {0xb0, 0x09, 0x08, 0xfa, 0xfd, 0x17, 0x81, 0x3b}};
278 // The debug engine needs to implement an internal Visual Studio debugger interface (defined by the CPDE)
279 // which augments launch and attach requests so that we can obtain information from the port supplier (the
280 // network address of the target in our case). See RSPriv.h for the definition of the interface. (We have to
281 // hard code the IID and interface definition because VS does not export it, but it's not much of an issue
282 // since COM interfaces are completely immutable).
283 const GUID IID_IDebugRemoteCorDebug = {0x83C91210, 0xA34F, 0x427c, {0xB3, 0x5F, 0x79, 0xC3, 0x99, 0x5B, 0x3C, 0x14}};
284 #endif // FEATURE_DBGIPC_TRANSPORT_DI
286 //*****************************************************************************
287 // Called by COM to get a class factory for a given CLSID. If it is one we
288 // support, instantiate a class factory object and prepare for create instance.
289 //*****************************************************************************
290 STDAPI DllGetClassObjectInternal( // Return code.
291 REFCLSID rclsid, // The class to desired.
292 REFIID riid, // Interface wanted on class factory.
293 LPVOID FAR *ppv) // Return interface pointer here.
296 CClassFactory *pClassFactory; // To create class factory object.
297 PFN_CREATE_OBJ pfnCreateObject = NULL;
300 #if defined(FEATURE_DBG_PUBLISH)
301 if (rclsid == CLSID_CorpubPublish)
303 pfnCreateObject = CorpubPublish::CreateObject;
307 #if defined(FEATURE_DBGIPC_TRANSPORT_DI)
308 if (rclsid == CLSID_CorDebug_Telesto)
310 pfnCreateObject = Cordb::CreateObjectTelesto;
312 #else // !FEATURE_DBGIPC_TRANSPORT_DI
313 if(rclsid == CLSID_CorDebug_V1)
315 if (0) // if (IsSingleCLR())
317 // Don't allow creating backwards objects until we ensure that the v2.0 Right-side
318 // is backwards compat. This may involve using CordbProcess::SupportsVersion to conditionally
319 // emulate old behavior.
320 // If emulating V1.0, QIs for V2.0 interfaces should fail.
321 _ASSERTE(!"Ensure that V2.0 RS is backwards compat");
322 pfnCreateObject = Cordb::CreateObjectV1;
325 #endif // FEATURE_DBGIPC_TRANSPORT_DI
327 if (pfnCreateObject == NULL)
328 return (CLASS_E_CLASSNOTAVAILABLE);
330 // Allocate the new factory object. The ref count is set to 1 in the constructor.
331 pClassFactory = new (nothrow) CClassFactory(pfnCreateObject);
333 return (E_OUTOFMEMORY);
335 // Pick the v-table based on the caller's request.
336 hr = pClassFactory->QueryInterface(riid, ppv);
338 // Always release the local reference, if QI failed it will be
339 // the only one and the object gets freed.
340 pClassFactory->Release();
345 #if defined(FEATURE_DBGIPC_TRANSPORT_DI)
346 // In V2 we started hiding DllGetClassObject because activation was no longer performed through COM directly
347 // (we went through the shim). CoreCLR doesn't have a shim and we go back to the COM model so we re-expose
348 // DllGetClassObject to make that work.
350 STDAPI DllGetClassObject( // Return code.
351 REFCLSID rclsid, // The class to desired.
352 REFIID riid, // Interface wanted on class factory.
353 LPVOID FAR *ppv) // Return interface pointer here.
355 return DllGetClassObjectInternal(rclsid, riid, ppv);
357 #endif // FEATURE_DBGIPC_TRANSPORT_DI
360 //*****************************************************************************
362 //********** Class factory code.
364 //*****************************************************************************
367 //*****************************************************************************
368 // QueryInterface is called to pick a v-table on the co-class.
369 //*****************************************************************************
370 HRESULT STDMETHODCALLTYPE CClassFactory::QueryInterface(
379 // Pick the right v-table based on the IID passed in.
380 if (riid == IID_IUnknown)
381 *ppvObject = (IUnknown *) this;
382 else if (riid == IID_IClassFactory)
383 *ppvObject = (IClassFactory *) this;
385 // If successful, add a reference for out pointer and return.
397 //*****************************************************************************
398 // CreateInstance is called to create a new instance of the coclass for which
399 // this class was created in the first place. The returned pointer is the
400 // v-table matching the IID if there.
401 //*****************************************************************************
402 HRESULT STDMETHODCALLTYPE CClassFactory::CreateInstance(
411 _ASSERTE(m_pfnCreateObject);
413 // Aggregation is not supported by these objects.
415 return (CLASS_E_NOAGGREGATION);
417 // Ask the object to create an instance of itself, and check the iid.
418 hr = (*m_pfnCreateObject)(riid, ppvObject);
423 HRESULT STDMETHODCALLTYPE CClassFactory::LockServer(
426 //<TODO>@todo: hook up lock server logic.</TODO>
431 //*****************************************************************************
432 // This helper provides access to the instance handle of the loaded image.
433 //*****************************************************************************
435 HINSTANCE GetModuleInst()
442 //-----------------------------------------------------------------------------
443 // Substitute for mscoree
446 // Mscordbi does not link with mscoree, provide a stub implementation.
447 // Callers are in dead-code paths, but we still need to provide a stub. Ideally, we'd factor
448 // out the callers too and then we wouldn't need an E_NOTIMPL stub.
449 STDAPI GetRequestedRuntimeInfo(LPCWSTR pExe,
451 LPCWSTR pConfigurationFile,
453 DWORD runtimeInfoFlags,
454 __out_ecount_opt(dwDirectory) LPWSTR pDirectory,
456 DWORD *dwDirectoryLength,
457 __out_ecount_opt(cchBuffer) LPWSTR pVersion,
461 _ASSERTE(!"GetRequestedRuntimeInfo not impl");
465 //-----------------------------------------------------------------------------
466 // Replacement for legacy shim API GetCORRequiredVersion(...) used in linked libraries.
467 // Used in code:TiggerStorage::GetDefaultVersion#CallTo_CLRRuntimeHostInternal_GetImageVersionString.
470 // Mscordbi does not statically link to mscoree.dll.
471 // This is used in EnC for IMetadataEmit2::GetSaveSize to computer size of header.
472 // see code:TiggerStorage::GetDefaultVersion.
474 // Implemented by returning the version we're built for. Mscordbi.dll has a tight coupling with
475 // the CLR version, so this will match exactly the build version we're debugging.
476 // One potential caveat is that the build version doesn't necessarily match the install string
477 // (eg. we may install as "v4.0.x86chk" but that's not captured in the build version). But this should
478 // be internal scenarios only, and shouldn't actually matter here. If it did, we could instead get
479 // the last components of the directory name the current mscordbi.dll is located in.
482 CLRRuntimeHostInternal_GetImageVersionString(
483 __out_ecount_part(*pcchBuffer, *pcchBuffer) LPWSTR wszBuffer,
486 // Construct the cannoncial version string we're built as - eg. "v4.0.1234"
487 const WCHAR k_wszBuiltFor[] = W("v") VER_PRODUCTVERSION_NO_QFE_STR_L;
489 // Copy our buffer in
490 HRESULT hr = HRESULT_FROM_WIN32(wcscpy_s(wszBuffer, *pcchBuffer, k_wszBuiltFor));
492 // Hand out length regardless of success - like GetCORRequiredVersion
493 *pcchBuffer = _countof(k_wszBuiltFor);
496 } // CLRRuntimeHostInternal_GetImageVersionString
501 DbiGetThreadContext(HANDLE hThread,
502 DT_CONTEXT *lpContext)
504 // if we aren't local debugging this isn't going to work
505 #if !defined(_ARM_) || defined(FEATURE_DBGIPC_TRANSPORT_DI)
506 _ASSERTE(!"Can't use local GetThreadContext remotely, this needed to go to datatarget");
510 if (((ULONG)lpContext) & ~0x10)
512 CONTEXT *ctx = (CONTEXT*)_aligned_malloc(sizeof(CONTEXT), 16);
515 ctx->ContextFlags = lpContext->ContextFlags;
516 if (::GetThreadContext(hThread, ctx))
518 *lpContext = *(DT_CONTEXT*)ctx;
526 // malloc does not set the last error, but the caller of GetThreadContext
527 // will expect it to be set on failure.
528 SetLastError(ERROR_OUTOFMEMORY);
533 res = ::GetThreadContext(hThread, (CONTEXT*)lpContext);
541 DbiSetThreadContext(HANDLE hThread,
542 const DT_CONTEXT *lpContext)
544 #if !defined(_ARM_) || defined(FEATURE_DBGIPC_TRANSPORT_DI)
545 _ASSERTE(!"Can't use local GetThreadContext remotely, this needed to go to datatarget");
549 if (((ULONG)lpContext) & ~0x10)
551 CONTEXT *ctx = (CONTEXT*)_aligned_malloc(sizeof(CONTEXT), 16);
554 *ctx = *(CONTEXT*)lpContext;
555 res = ::SetThreadContext(hThread, ctx);
560 // malloc does not set the last error, but the caller of SetThreadContext
561 // will expect it to be set on failure.
562 SetLastError(ERROR_OUTOFMEMORY);
567 res = ::SetThreadContext(hThread, (CONTEXT*)lpContext);