Merge pull request #3270 from CarolEidt/x86TypeCtxtOnFrame
[platform/upstream/coreclr.git] / src / debug / di / cordb.cpp
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 // CorDB.cpp
6 // 
7
8 //
9 // Dll* routines for entry points, and support for COM framework.  The class
10 // factory and other routines live in this module.
11 //
12 //*****************************************************************************
13 #include "stdafx.h"
14 #include "classfactory.h"
15 #include "corsym.h"
16 #include "contract.h"
17 #include "metadataexports.h"
18 #if defined(FEATURE_DBGIPC_TRANSPORT_DI)
19 #include "dbgtransportsession.h"
20 #include "dbgtransportmanager.h"
21 #endif // FEATURE_DBGIPC_TRANSPORT_DI
22
23 //********** Globals. *********************************************************
24 #ifndef FEATURE_PAL
25 HINSTANCE       g_hInst;                // Instance handle to this piece of code.
26 #endif
27
28 //-----------------------------------------------------------------------------
29 // SxS Versioning story for Mscordbi (ICorDebug + friends)
30 //-----------------------------------------------------------------------------
31
32 //-----------------------------------------------------------------------------
33 // In v1.0, we declared that mscordbi was a "shared" component, which means
34 // that we promised to provide it from now until the end of time. So every CLR implementation
35 // needs an Mscordbi that implements the everett guids for CorDebug + CorPublish.
36 //
37 // This works fine for CorPublish, which is truly shared.
38 // CorDebug however is "versioned" not "shared" - each version of the CLR has its own disjoint copy.
39 //
40 // Thus creating a CorDebug object requires a version parameter.
41 // CoCreateInstance doesn't have a the version param, so we use the new (v2.0+)
42 // shim interface CreateDebuggingInterfaceFromVersion.
43 //
44 // ** So in summary: **
45 // - Dlls don't do self-registration; they're registered by setup using .vrg files.
46 // - All CLR versions (past + future) must have the same registry footprint w.r.t mscordbi.
47 //     This just means that all CLRs have the same mscordbi.vrg file.
48 // - CorDebug is in fact versioned and each CLR version has its own copy.
49 // - In v1.0/1.1, CorDebug was a CoClass. In v2.0+, it is not a CoClass and is created via the
50 //     CreateDebuggingInterfaceFromVersion shim API, which takes a version parameter.
51 // - CorDebug must be SxS. V1.1 must only get the V1.1 version, and V2.0 must only get the V2.0 version.
52 //     V1.1: Clients will cocreate to get CorDebug. v1.1 will be the only mscordbi!DllGetClassObject
53 //           that provides a CorDebug, so CoCreateInstance will guarantee getting a v1.1 object.
54 //     V2.0: Clients use the new version-aware shim API, so it's not an issue.
55 //
56 // ** Preparing for Life in a Single-CLR world: **
57 // In Orcas (v3), we expect to run on single-CLR. There will only be 1 mscordbi, and it will service all versions.
58 // For whidbey (v2), we want to be able to flip a knob and pretend to be orcas (for testing purposes).
59 //
60 // Here's how to do that:
61 // - copy whidbey mscordbi & dac over the everett mscordbi.
62 // - When VS cocreates w/ the everett-guid, it will load the mscordbi on the everett path (
63 //   which will be whidbey dll), and ask for the everett guid.
64 // - re-add CorDebug to the g_CoClasses list.
65
66
67 //********** Locals. **********************************************************
68
69
70 //********** Code. ************************************************************
71
72
73 //*****************************************************************************
74 // Standard public helper to create a Cordb object (ICorDebug instance).
75 // This is used by the shim to get the Cordb object out of this module.
76 // This is the creation path for V2.0+ for CorDebug using the in-process debugging
77 // architecture (ICorDebug).  In CLR v4+ debugger may choose to use the out-of-process
78 // architecture to get an ICorDebugProcess directly (IClrDebugging::OpenVirtualProcess).
79 //
80 // This was used by the Mix07 release of Silverlight, but it didn't properly support versioning
81 // and we no longer support it's debugger protocol so we require callers to use 
82 // code:CoreCLRCreateCordbObject instead.
83 // 
84 // This is also still used on Mac - multi-instance debugging and debugger
85 // versioning isn't really implemented there yet.  This probably needs to change.
86 //*****************************************************************************
87 STDAPI CreateCordbObject(int iDebuggerVersion, IUnknown ** ppCordb)
88 {
89 #if defined(FEATURE_CORECLR) && !defined(FEATURE_DBGIPC_TRANSPORT_DI) && !defined(FEATURE_CORESYSTEM)
90     // This API should not be called for Windows CoreCLR unless we are doing interop-debugging
91     // (which is only supported internally).  Use code:CoreCLRCreateCordbObject instead.
92     if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_DbgEnableMixedModeDebugging) == 0)
93     {
94         _ASSERTE(!"Deprecated entry point CreateCordbObject() is called on Windows CoreCLR\n");
95         return E_NOTIMPL;
96     }
97 #endif // FEATURE_CORECLR && !FEATURE_DBGIPC_TRANSPORT_DI
98
99     if (ppCordb == NULL)
100     {
101         return E_INVALIDARG;
102     }
103     if (iDebuggerVersion != CorDebugVersion_2_0 && iDebuggerVersion != CorDebugVersion_4_0)
104     {
105         return E_INVALIDARG;
106     }
107
108     return Cordb::CreateObject((CorDebugInterfaceVersion)iDebuggerVersion, IID_ICorDebug, (void **) ppCordb);
109 }
110
111 #if defined(FEATURE_CORECLR)
112 //
113 // Public API.  
114 // Telesto Creation path - only way to debug multi-instance.  
115 // This supercedes code:CreateCordbObject
116 // 
117 // Arguments:
118 //    iDebuggerVersion - version of ICorDebug interfaces that the debugger is requesting
119 //    pid - pid of debuggee that we're attaching to.
120 //    hmodTargetCLR - module handle to clr in target pid that we're attaching to.
121 //    ppCordb - (out) the resulting ICorDebug object.
122 //
123 // Notes:
124 //    It's inconsistent that this takes a (handle, pid) but hands back an ICorDebug instead of an ICorDebugProcess.
125 //    Callers will need to call *ppCordb->DebugActiveProcess(pid).
126 STDAPI CoreCLRCreateCordbObject(int iDebuggerVersion, DWORD pid, HMODULE hmodTargetCLR, IUnknown ** ppCordb)
127 {
128     if (ppCordb == NULL)
129     {
130         return E_INVALIDARG;
131     }
132     if ((iDebuggerVersion < CorDebugVersion_2_0) ||
133         (iDebuggerVersion > CorDebugLatestVersion))
134     {
135         return E_INVALIDARG;
136     }
137
138     //
139     // Create the ICorDebug object
140     // 
141     RSExtSmartPtr<ICorDebug> pCordb;
142     Cordb::CreateObject((CorDebugInterfaceVersion)iDebuggerVersion, IID_ICorDebug, (void **) &pCordb);
143
144     // @dbgtodo - we should stash the pid and validate that it's the same pid we're attaching to in ICorDebug::DebugActiveProcess.
145     
146     //
147     // Associate it with the target instance
148     //
149     HRESULT hr = static_cast<Cordb*>(pCordb.GetValue())->SetTargetCLR(hmodTargetCLR);
150     if (FAILED(hr))
151     {
152         return hr;
153     }
154
155     //
156     // Assign to out parameter.
157     // 
158     hr = pCordb->QueryInterface(IID_IUnknown, (void**) ppCordb);
159
160     // Implicit release of pUnk, pCordb
161     return hr;
162 }
163
164 #endif // FEATURE_CORECLR
165
166
167
168
169 //*****************************************************************************
170 // The main dll entry point for this module.  This routine is called by the
171 // OS when the dll gets loaded.  Control is simply deferred to the main code.
172 //*****************************************************************************
173 BOOL WINAPI DbgDllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
174 {
175     // Save off the instance handle for later use.
176     switch (dwReason)
177     {
178
179         case DLL_PROCESS_ATTACH:
180         {
181 #ifndef FEATURE_PAL
182             g_hInst = hInstance;
183 #else
184             int err = PAL_InitializeDLL();
185             if(err != 0)
186             {
187                 return FALSE;
188             }
189 #endif
190
191 #if defined(_DEBUG)
192             static int BreakOnDILoad = -1;
193             if (BreakOnDILoad == -1)
194                 BreakOnDILoad = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_BreakOnDILoad);
195
196             if (BreakOnDILoad)
197             {
198                 _ASSERTE(!"DI Loaded");
199             }
200 #endif
201
202 #if defined(LOGGING)
203             {
204                 PathString rcFile;
205                 WszGetModuleFileName(hInstance, rcFile);
206                 LOG((LF_CORDB, LL_INFO10000,
207                     "DI::DbgDllMain: load right side support from file '%s'\n",
208                      rcFile.GetUnicode()));
209             }
210 #endif
211
212 #ifdef RSCONTRACTS
213             // alloc a TLS slot
214             DbgRSThread::s_TlsSlot = TlsAlloc();
215             _ASSERTE(DbgRSThread::s_TlsSlot != TLS_OUT_OF_INDEXES);
216 #endif
217
218 #if defined(FEATURE_DBGIPC_TRANSPORT_DI)
219             g_pDbgTransportTarget = new (nothrow) DbgTransportTarget();
220             if (g_pDbgTransportTarget == NULL)
221                 return FALSE;
222
223             if (FAILED(g_pDbgTransportTarget->Init()))
224                 return FALSE;
225 #endif // FEATURE_DBGIPC_TRANSPORT_DI
226         }
227         break;
228
229         case DLL_THREAD_DETACH:
230         {
231 #ifdef STRESS_LOG
232             StressLog::ThreadDetach((ThreadStressLog*) ClrFlsGetValue(TlsIdx_StressLog));
233 #endif
234
235 #ifdef RSCONTRACTS
236             // DbgRSThread are lazily created when we call GetThread(),
237             // So we don't need to do anything in DLL_THREAD_ATTACH,
238             // But this is our only chance to destroy the thread object.
239             DbgRSThread * p = DbgRSThread::GetThread();
240
241             p->Destroy();
242 #endif
243         }
244         break;
245
246         case DLL_PROCESS_DETACH:
247         {
248 #if defined(FEATURE_DBGIPC_TRANSPORT_DI)
249             if (g_pDbgTransportTarget != NULL)
250             {
251                 g_pDbgTransportTarget->Shutdown();
252                 delete g_pDbgTransportTarget;
253                 g_pDbgTransportTarget = NULL;
254             }
255 #endif // FEATURE_DBGIPC_TRANSPORT_DI
256             
257 #ifdef RSCONTRACTS
258             TlsFree(DbgRSThread::s_TlsSlot);
259             DbgRSThread::s_TlsSlot = TLS_OUT_OF_INDEXES;
260 #endif
261         }
262         break;
263     }
264
265     return TRUE;
266 }
267
268
269 // The obsolete v1 CLSID - see comment above for details.
270 static const GUID CLSID_CorDebug_V1 = {0x6fef44d0,0x39e7,0x4c77, { 0xbe,0x8e,0xc9,0xf8,0xcf,0x98,0x86,0x30}};
271
272 #if defined(FEATURE_DBGIPC_TRANSPORT_DI)
273
274 // GUID for pipe-based debugging (Unix platforms)
275 const GUID CLSID_CorDebug_Telesto = {0x8bd1daae, 0x188e, 0x42f4, {0xb0, 0x09, 0x08, 0xfa, 0xfd, 0x17, 0x81, 0x3b}};
276
277 // The debug engine needs to implement an internal Visual Studio debugger interface (defined by the CPDE)
278 // which augments launch and attach requests so that we can obtain information from the port supplier (the
279 // network address of the target in our case). See RSPriv.h for the definition of the interface. (We have to
280 // hard code the IID and interface definition because VS does not export it, but it's not much of an issue
281 // since COM interfaces are completely immutable).
282 const GUID IID_IDebugRemoteCorDebug = {0x83C91210, 0xA34F, 0x427c, {0xB3, 0x5F, 0x79, 0xC3, 0x99, 0x5B, 0x3C, 0x14}};
283 #endif // FEATURE_DBGIPC_TRANSPORT_DI
284
285 //*****************************************************************************
286 // Called by COM to get a class factory for a given CLSID.  If it is one we
287 // support, instantiate a class factory object and prepare for create instance.
288 //*****************************************************************************
289 STDAPI DllGetClassObjectInternal(               // Return code.
290     REFCLSID    rclsid,                 // The class to desired.
291     REFIID      riid,                   // Interface wanted on class factory.
292     LPVOID FAR  *ppv)                   // Return interface pointer here.
293 {
294     HRESULT         hr;
295     CClassFactory   *pClassFactory;         // To create class factory object.
296     PFN_CREATE_OBJ  pfnCreateObject = NULL;
297
298
299 #if defined(FEATURE_DBG_PUBLISH)
300     if (rclsid == CLSID_CorpubPublish)
301     {
302         pfnCreateObject = CorpubPublish::CreateObject;
303     }
304     else
305 #endif
306 #if defined(FEATURE_DBGIPC_TRANSPORT_DI)
307     if (rclsid == CLSID_CorDebug_Telesto)
308     {
309         pfnCreateObject = Cordb::CreateObjectTelesto;
310     }
311 #else  // !FEATURE_DBGIPC_TRANSPORT_DI
312     if(rclsid == CLSID_CorDebug_V1)
313     {
314         if (0) // if (IsSingleCLR())
315         {
316             // Don't allow creating backwards objects until we ensure that the v2.0 Right-side
317             // is backwards compat. This may involve using CordbProcess::SupportsVersion to conditionally
318             // emulate old behavior.
319             // If emulating V1.0, QIs for V2.0 interfaces should fail.
320             _ASSERTE(!"Ensure that V2.0 RS is backwards compat");
321             pfnCreateObject = Cordb::CreateObjectV1;
322         }
323     }
324 #endif // FEATURE_DBGIPC_TRANSPORT_DI
325
326     if (pfnCreateObject == NULL)
327         return (CLASS_E_CLASSNOTAVAILABLE);
328
329     // Allocate the new factory object.  The ref count is set to 1 in the constructor.
330     pClassFactory = new (nothrow) CClassFactory(pfnCreateObject);
331     if (!pClassFactory)
332         return (E_OUTOFMEMORY);
333
334     // Pick the v-table based on the caller's request.
335     hr = pClassFactory->QueryInterface(riid, ppv);
336
337     // Always release the local reference, if QI failed it will be
338     // the only one and the object gets freed.
339     pClassFactory->Release();
340
341     return hr;
342 }
343
344 #if defined(FEATURE_DBGIPC_TRANSPORT_DI)
345 // In V2 we started hiding DllGetClassObject because activation was no longer performed through COM directly
346 // (we went through the shim). CoreCLR doesn't have a shim and we go back to the COM model so we re-expose
347 // DllGetClassObject to make that work.
348
349 STDAPI DllGetClassObject(               // Return code.
350     REFCLSID    rclsid,                 // The class to desired.
351     REFIID      riid,                   // Interface wanted on class factory.
352     LPVOID FAR  *ppv)                   // Return interface pointer here.
353 {
354     return DllGetClassObjectInternal(rclsid, riid, ppv);
355 }
356 #endif // FEATURE_DBGIPC_TRANSPORT_DI
357
358
359 //*****************************************************************************
360 //
361 //********** Class factory code.
362 //
363 //*****************************************************************************
364
365
366 //*****************************************************************************
367 // QueryInterface is called to pick a v-table on the co-class.
368 //*****************************************************************************
369 HRESULT STDMETHODCALLTYPE CClassFactory::QueryInterface(
370     REFIID      riid,
371     void        **ppvObject)
372 {
373     HRESULT     hr;
374
375     // Avoid confusion.
376     *ppvObject = NULL;
377
378     // Pick the right v-table based on the IID passed in.
379     if (riid == IID_IUnknown)
380         *ppvObject = (IUnknown *) this;
381     else if (riid == IID_IClassFactory)
382         *ppvObject = (IClassFactory *) this;
383
384     // If successful, add a reference for out pointer and return.
385     if (*ppvObject)
386     {
387         hr = S_OK;
388         AddRef();
389     }
390     else
391         hr = E_NOINTERFACE;
392     return (hr);
393 }
394
395
396 //*****************************************************************************
397 // CreateInstance is called to create a new instance of the coclass for which
398 // this class was created in the first place.  The returned pointer is the
399 // v-table matching the IID if there.
400 //*****************************************************************************
401 HRESULT STDMETHODCALLTYPE CClassFactory::CreateInstance(
402     IUnknown    *pUnkOuter,
403     REFIID      riid,
404     void        **ppvObject)
405 {
406     HRESULT     hr;
407
408     // Avoid confusion.
409     *ppvObject = NULL;
410     _ASSERTE(m_pfnCreateObject);
411
412     // Aggregation is not supported by these objects.
413     if (pUnkOuter)
414         return (CLASS_E_NOAGGREGATION);
415
416     // Ask the object to create an instance of itself, and check the iid.
417     hr = (*m_pfnCreateObject)(riid, ppvObject);
418     return (hr);
419 }
420
421
422 HRESULT STDMETHODCALLTYPE CClassFactory::LockServer(
423     BOOL        fLock)
424 {
425 //<TODO>@todo: hook up lock server logic.</TODO>
426     return (S_OK);
427 }
428
429
430 //*****************************************************************************
431 // This helper provides access to the instance handle of the loaded image.
432 //*****************************************************************************
433 #ifndef FEATURE_PAL
434 HINSTANCE GetModuleInst()
435 {
436     return g_hInst;
437 }
438 #endif
439
440
441 //-----------------------------------------------------------------------------
442 // Substitute for mscoree
443 // 
444 // Notes:
445 //    Mscordbi does not link with mscoree, provide a stub implementation. 
446 //    Callers are in dead-code paths, but we still need to provide a stub. Ideally, we'd factor
447 //    out the callers too and then we wouldn't need an E_NOTIMPL stub.
448 STDAPI GetRequestedRuntimeInfo(LPCWSTR pExe, 
449                                LPCWSTR pwszVersion, 
450                                LPCWSTR pConfigurationFile, 
451                                DWORD startupFlags, 
452                                DWORD runtimeInfoFlags, 
453                                __out_ecount_opt(dwDirectory) LPWSTR pDirectory, 
454                                DWORD dwDirectory, 
455                                DWORD *dwDirectoryLength, 
456                                __out_ecount_opt(cchBuffer)   LPWSTR pVersion, 
457                                DWORD cchBuffer, 
458                                DWORD* dwlength)
459 {
460     _ASSERTE(!"GetRequestedRuntimeInfo not impl");
461     return E_NOTIMPL;
462 }
463
464 //-----------------------------------------------------------------------------
465 // Replacement for legacy shim API GetCORRequiredVersion(...) used in linked libraries.
466 // Used in code:TiggerStorage::GetDefaultVersion#CallTo_CLRRuntimeHostInternal_GetImageVersionString.
467 // 
468 // Notes:
469 //   Mscordbi does not statically link to mscoree.dll.
470 //   This is used in EnC for IMetadataEmit2::GetSaveSize to computer size of header.
471 //   see code:TiggerStorage::GetDefaultVersion.
472 //   
473 //   Implemented by returning the version we're built for.  Mscordbi.dll has a tight coupling with
474 //   the CLR version, so this will match exactly the build version we're debugging.  
475 //   One potential caveat is that the build version doesn't necessarily match the install string
476 //   (eg. we may install as "v4.0.x86chk" but that's not captured in the build version).  But this should
477 //   be internal scenarios only, and shouldn't actually matter here.  If it did, we could instead get
478 //   the last components of the directory name the current mscordbi.dll is located in.
479 //     
480 HRESULT 
481 CLRRuntimeHostInternal_GetImageVersionString(
482     __out_ecount_part(*pcchBuffer, *pcchBuffer) LPWSTR wszBuffer, 
483     DWORD *pcchBuffer)
484 {
485     // Construct the cannoncial version string we're built as - eg. "v4.0.1234"
486     const WCHAR k_wszBuiltFor[] = W("v") VER_PRODUCTVERSION_NO_QFE_STR_L;
487
488     // Copy our buffer in
489     HRESULT hr = HRESULT_FROM_WIN32(wcscpy_s(wszBuffer, *pcchBuffer, k_wszBuiltFor));
490
491     // Hand out length regardless of success - like GetCORRequiredVersion
492     *pcchBuffer = _countof(k_wszBuiltFor);
493
494     return hr;
495 } // CLRRuntimeHostInternal_GetImageVersionString
496
497
498 #ifdef _TARGET_ARM_
499 BOOL
500 DbiGetThreadContext(HANDLE hThread,
501     DT_CONTEXT *lpContext)
502 {
503     // if we aren't local debugging this isn't going to work
504 #if !defined(_ARM_) || defined(FEATURE_DBGIPC_TRANSPORT_DI)
505     _ASSERTE(!"Can't use local GetThreadContext remotely, this needed to go to datatarget");
506     return FALSE;
507 #else
508     BOOL res = FALSE;
509     if (((ULONG)lpContext) & ~0x10)
510     {
511         CONTEXT *ctx = (CONTEXT*)_aligned_malloc(sizeof(CONTEXT), 16);
512         if (ctx)
513         {
514             ctx->ContextFlags = lpContext->ContextFlags;
515             if (::GetThreadContext(hThread, ctx))
516             {
517                 *lpContext = *(DT_CONTEXT*)ctx;
518                 res = TRUE;
519             }
520
521             _aligned_free(ctx);
522         }
523         else
524         {
525             // malloc does not set the last error, but the caller of GetThreadContext
526             // will expect it to be set on failure.
527             SetLastError(ERROR_OUTOFMEMORY);
528         }
529     }
530     else
531     {
532         res = ::GetThreadContext(hThread, (CONTEXT*)lpContext);
533     }
534     
535     return res;
536 #endif
537 }
538
539 BOOL
540 DbiSetThreadContext(HANDLE hThread,
541     const DT_CONTEXT *lpContext)
542 {
543 #if !defined(_ARM_) || defined(FEATURE_DBGIPC_TRANSPORT_DI)
544     _ASSERTE(!"Can't use local GetThreadContext remotely, this needed to go to datatarget");
545     return FALSE;
546 #else
547     BOOL res = FALSE;
548     if (((ULONG)lpContext) & ~0x10)
549     {
550         CONTEXT *ctx = (CONTEXT*)_aligned_malloc(sizeof(CONTEXT), 16);
551         if (ctx)
552         {
553             *ctx = *(CONTEXT*)lpContext;
554             res = ::SetThreadContext(hThread, ctx);
555             _aligned_free(ctx);
556         }   
557         else
558         {
559             // malloc does not set the last error, but the caller of SetThreadContext
560             // will expect it to be set on failure.
561             SetLastError(ERROR_OUTOFMEMORY);
562         }
563     }
564     else
565     {
566         res = ::SetThreadContext(hThread, (CONTEXT*)lpContext);
567     }
568     
569     return res;
570 #endif
571 }
572 #endif