1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4//*****************************************************************************
5
6//
7// File: rsthread.cpp
8//
9//*****************************************************************************
10#include "stdafx.h"
11#include "primitives.h"
12#include <float.h>
13#include <tls.h>
14
15// Stack-based holder for RSPTRs that we allocated to give to the LS.
16// If LS successfully takes ownership of them, then call SuppressRelease().
17// Else, dtor will free them up.
18// This is using a table protected by the ProcessLock().
19template <class T>
20class RsPtrHolder
21{
22 T * m_pObject;
23 RsPointer<T> m_ptr;
24public:
25 RsPtrHolder(T* pObject)
26 {
27 _ASSERTE(pObject != NULL);
28 m_ptr.AllocHandle(pObject->GetProcess(), pObject);
29 m_pObject = pObject;
30 }
31
32 // If owner didn't call SuppressRelease() to take ownership, then have dtor free it.
33 ~RsPtrHolder()
34 {
35 if (!m_ptr.IsNull())
36 {
37 // @dbgtodo synchronization - push this up. Note that since this is in a dtor;
38 // need to order it well against RSLockHolder.
39 RSLockHolder lockHolder(m_pObject->GetProcess()->GetProcessLock());
40 T* pObjTest = m_ptr.UnWrapAndRemove(m_pObject->GetProcess());
41 (void)pObjTest; //prevent "unused variable" error from GCC
42 _ASSERTE(pObjTest == m_pObject);
43 }
44 }
45
46 RsPointer<T> Ptr()
47 {
48 return m_ptr;
49 }
50 void SuppressRelease()
51 {
52 m_ptr = RsPointer<T>::NullPtr();
53 }
54
55};
56
57/* ------------------------------------------------------------------------- *
58 * Managed Thread classes
59 * ------------------------------------------------------------------------- */
60
61
62//---------------------------------------------------------------------------------------
63//
64// Instantiate a CordbThread object, which represents a managed thread.
65//
66// Arguments:
67// process - non-null process object that this thread lives in.
68// id - OS thread id of this thread.
69// handle - OS Handle to the native thread in the debuggee.
70//
71//---------------------------------------------------------------------------------------
72
73CordbThread::CordbThread(CordbProcess * pProcess, VMPTR_Thread vmThread) :
74 CordbBase(pProcess,
75 VmPtrToCookie(vmThread),
76 enumCordbThread),
77 m_pContext(NULL),
78 m_fContextFresh(false),
79 m_pAppDomain(NULL),
80 m_debugState(THREAD_RUN),
81 m_fFramesFresh(false),
82 m_fFloatStateValid(false),
83 m_floatStackTop(0),
84 m_fException(false),
85 m_fCreationEventQueued(false),
86 m_EnCRemapFunctionIP(NULL),
87 m_userState(kInvalidUserState),
88 m_hCachedThread(INVALID_HANDLE_VALUE),
89 m_hCachedOutOfProcThread(INVALID_HANDLE_VALUE)
90{
91 m_fHasUnhandledException = FALSE;
92 m_pExceptionRecord = NULL;
93
94 // Thread id may be a "fake" OS id for a CLRHosted thread.
95 m_vmThreadToken = vmThread;
96
97 // This id must be unique for the thread. V2 uses the current OS thread id.
98 // If we ever support fibers, then we need to use something more unique than that.
99 m_dwUniqueID = pProcess->GetDAC()->GetUniqueThreadID(vmThread); // may throw
100
101 LOG((LF_CORDB, LL_INFO1000, "CT::CT new thread 0x%p vmptr=0x%p id=0x%x\n",
102 this, m_vmThreadToken, m_dwUniqueID));
103
104 // Unique ID should never be 0.
105 _ASSERTE(m_dwUniqueID != 0);
106
107 m_vmLeftSideContext = VMPTR_CONTEXT::NullPtr();
108 m_vmExcepObjHandle = VMPTR_OBJECTHANDLE::NullPtr();
109
110#if defined(_DEBUG)
111 for (unsigned int i = 0;
112 i < (sizeof(m_floatValues) / sizeof(m_floatValues[0]));
113 i++)
114 {
115 m_floatValues[i] = 0;
116 }
117#endif
118
119 // Set AppDomain
120 VMPTR_AppDomain vmAppDomain = pProcess->GetDAC()->GetCurrentAppDomain(vmThread);
121 m_pAppDomain = pProcess->LookupOrCreateAppDomain(vmAppDomain);
122 _ASSERTE(m_pAppDomain != NULL);
123}
124
125
126CordbThread::~CordbThread()
127{
128 // We've already been neutered, thus we don't need to call CleanupStack().
129 // That will have neutered + cleared frames + chains.
130 _ASSERTE(IsNeutered());
131
132 // Cleared in neuter
133 _ASSERTE(m_pContext == NULL);
134 _ASSERTE(m_hCachedThread == INVALID_HANDLE_VALUE);
135 _ASSERTE(m_pExceptionRecord == NULL);
136}
137
138// Neutered by the CordbProcess
139void CordbThread::Neuter()
140{
141 if (IsNeutered())
142 {
143 return;
144 }
145
146 _ASSERTE(GetProcess()->ThreadHoldsProcessLock());
147
148 delete m_pExceptionRecord;
149 m_pExceptionRecord = NULL;
150
151 // Neuter frames & Chains.
152 CleanupStack();
153
154
155 if (m_hCachedThread != INVALID_HANDLE_VALUE)
156 {
157 CloseHandle(m_hCachedThread);
158 m_hCachedThread = INVALID_HANDLE_VALUE;
159 }
160
161 if( m_pContext != NULL )
162 {
163 delete [] m_pContext;
164 m_pContext = NULL;
165 }
166
167 ClearStackFrameCache();
168
169 CordbBase::Neuter();
170}
171
172HRESULT CordbThread::QueryInterface(REFIID id, void ** ppInterface)
173{
174 if (id == IID_ICorDebugThread)
175 {
176 *ppInterface = static_cast<ICorDebugThread *>(this);
177 }
178 else if (id == IID_ICorDebugThread2)
179 {
180 *ppInterface = static_cast<ICorDebugThread2 *>(this);
181 }
182 else if (id == IID_ICorDebugThread3)
183 {
184 *ppInterface = static_cast<ICorDebugThread3*>(this);
185 }
186 else if (id == IID_ICorDebugThread4)
187 {
188 *ppInterface = static_cast<ICorDebugThread4*>(this);
189 }
190 else if (id == IID_IUnknown)
191 {
192 *ppInterface = static_cast<IUnknown *>(static_cast<ICorDebugThread *>(this));
193 }
194 else
195 {
196 *ppInterface = NULL;
197 return E_NOINTERFACE;
198 }
199
200 ExternalAddRef();
201 return S_OK;
202}
203
204
205#ifdef _DEBUG
206// Callback helper for code:CordbThread::DbgAssertThreadDeleted
207//
208// Arguments:
209// vmThread - thread from enumeration of threads in the target.
210// pUserData - the CordbThread for the thread that's deleted
211//
212// static
213void CordbThread::DbgAssertThreadDeletedCallback(VMPTR_Thread vmThread, void * pUserData)
214{
215 CordbThread * pThis = reinterpret_cast<CordbThread *>(pUserData);
216 INTERNAL_DAC_CALLBACK(pThis->GetProcess());
217
218 VMPTR_Thread vmThreadDelete = pThis->m_vmThreadToken;
219
220 CONSISTENCY_CHECK_MSGF((vmThread != vmThreadDelete),
221 ("A Thread Exit event was sent, but it still shows up in the enumeration.\n vmThreadDelete=%p\n",
222 VmPtrToCookie(vmThreadDelete)));
223}
224
225// Debug-only helper to Assert that this thread is no longer discoverable in DacDbi enumerations
226// This is designed to enforce the code:IDacDbiInterface#Enumeration rules for enumerations.
227void CordbThread::DbgAssertThreadDeleted()
228{
229 // Enumerate through all threads and ensure the deleted threads don't show up.
230 GetProcess()->GetDAC()->EnumerateThreads(
231 DbgAssertThreadDeletedCallback,
232 this);
233}
234#endif // _DEBUG
235
236
237//---------------------------------------------------------------------------------------
238// Mark that this thread has an unhandled native exception on it.
239//
240// Arguments
241// pRecord - exception record of 2nd-chance exception that we're hijacking at. This will
242// get deep copied into the CordbThread object in case it's needed for hijacking later.
243//
244// Notes:
245// This bit is cleared in code:CordbThread::HijackForUnhandledException
246void CordbThread::SetUnhandledNativeException(const EXCEPTION_RECORD * pExceptionRecord)
247{
248 m_fHasUnhandledException = true;
249
250 if (m_pExceptionRecord == NULL)
251 {
252 m_pExceptionRecord = new EXCEPTION_RECORD(); // throws
253 }
254 memcpy(m_pExceptionRecord, pExceptionRecord, sizeof(EXCEPTION_RECORD));
255}
256
257//-----------------------------------------------------------------------------
258// Returns true if the thread has an unhandled exception
259// This is during the window after code:CordbThread::SetUnhandledNativeException is called,
260// but before code:CordbThread::HijackForUnhandledException
261bool CordbThread::HasUnhandledNativeException()
262{
263 return m_fHasUnhandledException;
264}
265
266
267//---------------------------------------------------------------------------------------
268// Determine if the thread's latest exception is a managed exception
269//
270// Notes:
271// The CLR's UnhandledExceptionFilter has to make this same determination.
272//
273BOOL CordbThread::IsThreadExceptionManaged()
274{
275 CONTRACTL
276 {
277 THROWS;
278 }
279 CONTRACTL_END;
280
281 // A Thread's latest exception is managed if the VM Thread object has a managed object
282 // for the thread's Current Exception property. The CLR's Exception system is very diligent
283 // about tracking and clearing the thread's managed exception property. The runtime will clear
284 // the object if the exception is caught by unmanaged code (it can do this in the 2nd-pass).
285
286 // It's the presence of a throwable that makes the difference between a managed
287 // exception event and an unmanaged exception event.
288
289 VMPTR_OBJECTHANDLE vmObject = GetProcess()->GetDAC()->GetCurrentException(m_vmThreadToken);
290
291 bool fHasThrowable = !vmObject.IsNull();
292
293 return fHasThrowable;
294
295}
296
297// ----------------------------------------------------------------------------
298// CordbThread::CreateCordbRegisterSet
299//
300// Description:
301// This is a private hook for the shim to create a CordbRegisterSet for a ShimChain.
302//
303// Arguments:
304// * pContext - the CONTEXT to be converted; this must be the leaf CONTEXT of a chain
305// * fLeaf - whether the chain is the leaf chain or not
306// * reason - the chain reason; this is needed for legacy reasons (see below)
307// * ppRegSet - out parameter; return the newly created ICDRegisterSet
308//
309// Notes:
310// * Note that the fQuickUnwind argument of the ctor of CordbRegisterSet is only true
311// for an enter-managed chain. We need to keep the same behaviour here. That's why we need the
312// chain reason.
313//
314
315void CordbThread::CreateCordbRegisterSet(DT_CONTEXT * pContext,
316 BOOL fLeaf,
317 CorDebugChainReason reason,
318 ICorDebugRegisterSet ** ppRegSet)
319{
320 CONTRACTL
321 {
322 THROWS;
323 }
324 CONTRACTL_END;
325
326 PUBLIC_REENTRANT_API_ENTRY_FOR_SHIM(GetProcess());
327
328 IfFailThrow(EnsureThreadIsAlive());
329
330 // The CordbRegisterSet is responsible for freeing this memory.
331 NewHolder<DebuggerREGDISPLAY> pDRD(new DebuggerREGDISPLAY());
332
333 // convert the CONTEXT to a DebuggerREGDISPLAY
334 IDacDbiInterface * pDAC = GetProcess()->GetDAC();
335 pDAC->ConvertContextToDebuggerRegDisplay(pContext, pDRD, fLeaf);
336
337 // create the CordbRegisterSet
338 RSInitHolder<CordbRegisterSet> pRS(new CordbRegisterSet(pDRD,
339 this,
340 (fLeaf == TRUE),
341 (reason == CHAIN_ENTER_MANAGED),
342 true));
343 pDRD.SuppressRelease();
344
345 pRS.TransferOwnershipExternal(ppRegSet);
346}
347
348// ----------------------------------------------------------------------------
349// CordbThread::ConvertFrameForILMethodWithoutMetadata
350//
351// Description:
352// This is a private hook for the shim to convert an ICDFrame into an ICDInternalFrame for a dynamic
353// method. There are two cases where we need this:
354// 1) In Arrowhead, dynamic methods are exposed as first-class stack frames, not internal frames. Thus,
355// the shim needs a way to convert an ICDNativeFrame for a dynamic method in Arrowhead to an
356// ICDInternalFrame of type STUBFRAME_LIGHTWEIGHT_FUNCTION in V2. Furthermore, IL stubs,
357// which are also considered as a type of dynamic methods, are not exposed in V2 at all.
358//
359// 2) In V2, PrestubMethodFrames (PMFs) can be exposed as one of two things: a chain of type
360// CHAIN_CLASS_INIT in most cases, or an internal frame of type STUBFRAME_LIGHTWEIGHT_FUNCTION if
361// the method being jitted is a dynamic method. There is no way to make this distinction at the
362// public ICD level.
363//
364// Arguments:
365// * pNativeFrame - the native frame to be converted
366// * ppInternalFrame - out parameter; the converted internal frame; could be NULL (see Notes below)
367//
368// Returns:
369// Return TRUE if conversion has occurred. Note that even if the return value is TRUE, ppInternalFrame
370// could be NULL. See Notes below.
371//
372// Notes:
373// * There are two main types of dynamic methods: ones which are generated by the runtime itself for
374// internal purposes (i.e. IL stubs), and ones which are generated by the user. ppInternalFrame
375// is NULL for IL stubs. We need this functionality because IL stubs are not exposed at all in V2.
376//
377
378BOOL CordbThread::ConvertFrameForILMethodWithoutMetadata(ICorDebugFrame * pFrame,
379 ICorDebugInternalFrame2 ** ppInternalFrame2)
380{
381 PUBLIC_REENTRANT_API_ENTRY_FOR_SHIM(GetProcess());
382
383 _ASSERTE(ppInternalFrame2 != NULL);
384 *ppInternalFrame2 = NULL;
385
386 HRESULT hr = E_FAIL;
387
388 CordbFrame * pRealFrame = CordbFrame::GetCordbFrameFromInterface(pFrame);
389
390 CordbInternalFrame * pInternalFrame = pRealFrame->GetAsInternalFrame();
391 if (pInternalFrame != NULL)
392 {
393 // The input is an internal frame.
394
395 // Check its frame type.
396 CorDebugInternalFrameType type;
397 hr = pInternalFrame->GetFrameType(&type);
398 IfFailThrow(hr);
399
400 if (type != STUBFRAME_JIT_COMPILATION)
401 {
402 // No conversion is necessary.
403 return FALSE;
404 }
405 else
406 {
407 // We are indeed dealing with a PrestubMethodFrame.
408 return pInternalFrame->ConvertInternalFrameForILMethodWithoutMetadata(ppInternalFrame2);
409 }
410 }
411 else
412 {
413 // The input is a native frame.
414 CordbNativeFrame * pNativeFrame = pRealFrame->GetAsNativeFrame();
415 _ASSERTE(pNativeFrame != NULL);
416
417 return pNativeFrame->ConvertNativeFrameForILMethodWithoutMetadata(ppInternalFrame2);
418 }
419}
420
421//-----------------------------------------------------------------------------
422// Hijack a thread at an unhandled exception. This lets it execute the
423// CLR's Unhandled Exception Filter (which will send the managed 2nd-chance exception event)
424//
425// Notes:
426// OS will not execute Unhandled Exception Filter (UEF) when debugger is attached.
427// The CLR's UEF does useful work, like dispatching 2nd-chance managed exception event
428// and allowing Func-eval and Continuable Exceptions for unhandled exceptions.
429// So hijack the thread, and the hijack will then execute the CLR's UEF just
430// like the OS would.
431void CordbThread::HijackForUnhandledException()
432{
433 CONTRACTL
434 {
435 THROWS;
436 }
437 CONTRACTL_END;
438
439 _ASSERTE(m_pExceptionRecord != NULL);
440
441 _ASSERTE(m_fHasUnhandledException);
442 m_fHasUnhandledException = false;
443
444
445 ULONG32 dwThreadId = GetVolatileOSThreadID();
446
447 // Note that the data-target is not atomic, and we have no rollback mechanism.
448 // We have to do several writes. If the data-target fails the writes half-way through the
449 // target will be inconsistent.
450
451 // We don't bother remembering the original context. LS hijack will have the
452 // context on its stack and will pass it to RS just like it does for filter-context.
453 GetProcess()->GetDAC()->Hijack(
454 m_vmThreadToken,
455 dwThreadId,
456 m_pExceptionRecord,
457 NULL, // LS will have the context.
458 0, // size of context
459 EHijackReason::kUnhandledException,
460 NULL,
461 NULL);
462
463 // Notify debugger to clear the exception.
464 // This will invoke the data-target.
465 GetProcess()->ContinueStatusChanged(dwThreadId, DBG_CONTINUE);
466}
467
468
469HRESULT CordbThread::GetProcess(ICorDebugProcess ** ppProcess)
470{
471 PUBLIC_API_ENTRY(this);
472 VALIDATE_POINTER_TO_OBJECT(ppProcess, ICorDebugProcess **);
473 FAIL_IF_NEUTERED(this);
474
475 *ppProcess = GetProcess();
476 GetProcess()->ExternalAddRef();
477
478 return S_OK;
479}
480
481// Public implementation of ICorDebugThread::GetID
482// Back in V1.0, GetID originally meant the OS thread ID that this managed thread was running on.
483// In theory, that can change (fibers, logical thread scheduling, etc). However, in practice, in V1.0, it would
484// not. Thus debuggers took a depedency on GetID being constant.
485// In V2, this returns an opaque handle that is unique to this thread and stable for this thread's lifetime.
486//
487// Compare to code:CordbThread::GetVolatileOSThreadID, which returns the actual OS thread Id (which may change).
488HRESULT CordbThread::GetID(DWORD * pdwThreadId)
489{
490 PUBLIC_API_ENTRY(this);
491 VALIDATE_POINTER_TO_OBJECT(pdwThreadId, DWORD *);
492 FAIL_IF_NEUTERED(this);
493
494 *pdwThreadId = GetUniqueId();
495
496 return S_OK;
497}
498
499// Returns a unique ID that's stable for the life of this thread.
500// In a non-hosted scenarios, this can be the OS thread id.
501DWORD CordbThread::GetUniqueId()
502{
503 return m_dwUniqueID;
504}
505
506// Implementation of public API, ICorDebugThread::GetHandle
507// @dbgtodo ICDThread - deprecate in V3, offload to Shim
508HRESULT CordbThread::GetHandle(HANDLE * phThreadHandle)
509{
510 PUBLIC_API_ENTRY(this);
511 VALIDATE_POINTER_TO_OBJECT(phThreadHandle, HANDLE *);
512 FAIL_IF_NEUTERED(this);
513 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
514
515 if (GetProcess()->GetShim() == NULL)
516 {
517 _ASSERTE(!"CordbThread::GetHandle() should be not be called on the new architecture");
518 *phThreadHandle = NULL;
519 return E_NOTIMPL;
520 }
521
522#if !defined(FEATURE_DBGIPC_TRANSPORT_DI)
523 HRESULT hr = S_OK;
524 EX_TRY
525 {
526 HANDLE hThread;
527 InternalGetHandle(&hThread); // throws on error
528 *phThreadHandle = hThread;
529 }
530 EX_CATCH_HRESULT(hr);
531#else // FEATURE_DBGIPC_TRANSPORT_DI
532 // In the old SL implementation of Mac debugging, we return a thread handle faked up by the PAL on the Mac.
533 // The returned handle is meaningless. Here we explicitly return E_NOTIMPL. We plan to deprecate this
534 // function in Dev10 anyway.
535 //
536 // @dbgtodo Mac - Check with VS to see if they need the thread handle, e.g. for waiting on thread
537 // termination.
538 HRESULT hr = E_NOTIMPL;
539#endif // !FEATURE_DBGIPC_TRANSPORT_DI
540
541 return hr;
542}
543
544// Note that we can return invalid handle
545void CordbThread::InternalGetHandle(HANDLE * phThread)
546{
547 INTERNAL_SYNC_API_ENTRY(GetProcess());
548
549 RefreshHandle(phThread);
550}
551
552//---------------------------------------------------------------------------------------
553//
554// This is a simple helper to check if a frame lives on the stack of the current thread.
555//
556// Arguments:
557// pFrame - the stack frame to check
558//
559// Return Value:
560// whether the frame lives on the stack of the current thread
561//
562// Assumption:
563// This function assumes that the stack frames are valid, i.e. the stack frames have not been
564// made dirty since the last stackwalk.
565//
566
567bool CordbThread::OwnsFrame(CordbFrame * pFrame)
568{
569 // preliminary checking
570 if ( (pFrame != NULL) &&
571 (!pFrame->IsNeutered()) &&
572 (pFrame->m_pThread == this)
573 )
574 {
575 //
576 // Note that this is one of the two remaining places where we need to use the cached stack frames.
577 // Theoretically, since this is not an exact check anyway, we could just use the thread's stack
578 // range instead of looping through all the individual frames. However, since we need to maintain
579 // the stack frame cache for code:CordbThread::GetActiveFunctions, we might as well use the cache here.
580 //
581
582 // make sure this thread actually have frames to check
583 if (m_stackFrames.Count() != 0)
584 {
585 // get the stack range of this thread
586 FramePointer fpLeaf = (*(m_stackFrames.Get(0)))->GetFramePointer();
587 FramePointer fpRoot = (*(m_stackFrames.Get(m_stackFrames.Count() - 1)))->GetFramePointer();
588
589 FramePointer fpCurrent = pFrame->GetFramePointer();
590
591 // compare the stack range against the frame pointer of the specified frame
592 if (IsEqualOrCloserToLeaf(fpLeaf, fpCurrent) && IsEqualOrCloserToRoot(fpRoot, fpCurrent))
593 {
594 return true;
595 }
596 }
597 }
598
599 return false;
600}
601
602//---------------------------------------------------------------------------------------
603//
604// This routine is a internal helper function for ICorDebugThread2::GetTaskId.
605//
606// Arguments:
607// pHandle - return thread handle here after fetching from the left side. Can return SWITCHOUT_HANDLE_VALUE.
608//
609// Return Value:
610// hr - It can fail with CORDBG_E_THREAD_NOT_SCHEDULED.
611//
612// Notes:
613// This method will most likely be deprecated in V3.0. We can't always return the thread handle.
614// For example, what does it mean to return a thread handle in remote debugging scenarios?
615//
616void CordbThread::RefreshHandle(HANDLE * phThread)
617{
618 // here is where we will put code in to fetch the thread handle from the left side.
619 // This should only happen when CLRTask is hosted.
620 // Make sure that we are setting the right HR when thread is being switched out.
621 THROW_IF_NEUTERED(this);
622 INTERNAL_SYNC_API_ENTRY(GetProcess());
623
624 if (phThread == NULL)
625 {
626 ThrowHR(E_INVALIDARG);
627 }
628 *phThread = INVALID_HANDLE_VALUE;
629
630 IDacDbiInterface * pDAC = GetProcess()->GetDAC();
631 HANDLE hThread = pDAC->GetThreadHandle(m_vmThreadToken);
632
633 if (hThread == SWITCHOUT_HANDLE_VALUE)
634 {
635 *phThread = SWITCHOUT_HANDLE_VALUE;
636 ThrowHR(CORDBG_E_THREAD_NOT_SCHEDULED);
637 }
638
639 _ASSERTE(hThread != INVALID_HANDLE_VALUE);
640 PREFAST_ASSUME(hThread != NULL);
641
642 // need to dup handle here
643 if (hThread == m_hCachedOutOfProcThread)
644 {
645 *phThread = m_hCachedThread;
646 }
647 else
648 {
649 BOOL fSuccess = TRUE;
650 if (m_hCachedThread != INVALID_HANDLE_VALUE)
651 {
652 // clear the previous cache
653 CloseHandle(m_hCachedThread);
654 m_hCachedOutOfProcThread = INVALID_HANDLE_VALUE;
655 m_hCachedThread = INVALID_HANDLE_VALUE;
656 }
657
658 // now duplicate the out-of-proc handle
659 fSuccess = DuplicateHandle(GetProcess()->UnsafeGetProcessHandle(),
660 hThread,
661 GetCurrentProcess(),
662 &m_hCachedThread,
663 NULL,
664 FALSE,
665 DUPLICATE_SAME_ACCESS);
666 *phThread = m_hCachedThread;
667
668 if (fSuccess)
669 {
670 m_hCachedOutOfProcThread = hThread;
671 }
672 else
673 {
674 ThrowLastError();
675 }
676 }
677} // CordbThread::RefreshHandle
678
679
680//---------------------------------------------------------------------------------------
681//
682// This routine sets the debug state of a thread.
683//
684// Arguments:
685// state - The debug state to set to.
686//
687// Return Value:
688// Normal HRESULT semantics.
689//
690HRESULT CordbThread::SetDebugState(CorDebugThreadState state)
691{
692 PUBLIC_API_ENTRY(this);
693 FAIL_IF_NEUTERED(this);
694 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
695
696 LOG((LF_CORDB, LL_INFO1000, "CT::SDS: thread=0x%08x 0x%x, state=%d\n", this, m_id, state));
697
698 // @dbgtodo- , sync - decide on how to suspend a thread. V2 leverages synchronization
699 // (see below). For V3, do we just hard suspend the thread?
700 if (GetProcess()->GetShim() == NULL)
701 {
702 return E_NOTIMPL;
703 }
704
705 HRESULT hr = S_OK;
706 EX_TRY
707 {
708 hr = EnsureThreadIsAlive();
709
710 if (SUCCEEDED(hr))
711 {
712 // This lets the debugger suspend / resume threads. This is only called when when the
713 // target is already synchronized. That means all the threads are already suspended. So
714 // setting the suspend bit here just means that the debugger's continue logic won't resume
715 // this thread when we do a Continue.
716 if ((state != THREAD_SUSPEND) && (state != THREAD_RUN))
717 {
718 ThrowHR(E_INVALIDARG);
719 }
720
721 IDacDbiInterface * pDAC = GetProcess()->GetDAC();
722 pDAC->SetDebugState(m_vmThreadToken, state);
723
724 m_debugState = state;
725 }
726 }
727 EX_CATCH_HRESULT(hr);
728
729 return hr;
730}
731
732HRESULT CordbThread::GetDebugState(CorDebugThreadState * pState)
733{
734 PUBLIC_API_ENTRY(this);
735 FAIL_IF_NEUTERED(this);
736 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
737 VALIDATE_POINTER_TO_OBJECT(pState, CorDebugThreadState *);
738
739 *pState = m_debugState;
740
741 return S_OK;
742}
743
744
745// Public implementation of ICorDebugThread::GetUserState
746// Arguments:
747// pState - out parameter; return the user state
748//
749// Return Value:
750// Return S_OK if the operation is successful.
751// Return E_INVALIDARG if the out parameter is NULL.
752// Return other failure HRs returned by the call to the DDI.
753HRESULT CordbThread::GetUserState(CorDebugUserState * pState)
754{
755 PUBLIC_REENTRANT_API_ENTRY(this);
756 FAIL_IF_NEUTERED(this);
757 VALIDATE_POINTER_TO_OBJECT(pState, CorDebugUserState *);
758
759 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
760
761 HRESULT hr = S_OK;
762 EX_TRY
763 {
764 if (pState == NULL)
765 {
766 ThrowHR(E_INVALIDARG);
767 }
768 *pState = GetUserState();
769 }
770 EX_CATCH_HRESULT(hr);
771 return hr;
772}
773
774//---------------------------------------------------------------------------------------
775//
776// Retrieve the user state of the current thread.
777//
778// Notes:
779// This caches results between continues. The cache is cleared when the target continues or is flushed.
780// See code:CordbThread::CleanupStack, code:CordbThread::MarkStackFramesDirty
781//
782CorDebugUserState CordbThread::GetUserState()
783{
784 if (m_userState == kInvalidUserState)
785 {
786 IDacDbiInterface * pDAC = GetProcess()->GetDAC();
787 m_userState = pDAC->GetUserState(m_vmThreadToken);
788 }
789
790 return m_userState;
791}
792
793
794//---------------------------------------------------------------------------------------
795//
796// This routine finds and returns the current exception off of a thread.
797//
798// Arguments:
799// ppExceptionObject - OUT: Space for storing the exception found on the thread as a value.
800//
801// Return Value:
802// Normal HRESULT semantics.
803//
804HRESULT CordbThread::GetCurrentException(ICorDebugValue ** ppExceptionObject)
805{
806 PUBLIC_API_ENTRY(this);
807 FAIL_IF_NEUTERED(this);
808
809 HRESULT hr = S_OK;
810
811 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
812
813 VALIDATE_POINTER_TO_OBJECT(ppExceptionObject, ICorDebugValue **);
814 *ppExceptionObject = NULL;
815
816 EX_TRY
817 {
818 if (!HasException())
819 {
820 //
821 // Go to the LS and retrieve any exception object.
822 //
823 IDacDbiInterface * pDAC = GetProcess()->GetDAC();
824 VMPTR_OBJECTHANDLE vmObjHandle = pDAC->GetCurrentException(m_vmThreadToken);
825
826 if (vmObjHandle.IsNull())
827 {
828 hr = S_FALSE;
829 }
830 else
831 {
832#if defined(_DEBUG)
833 // Since we know an exception is in progress on this thread, our assumption about the
834 // thread's current AppDomain should be correct
835 VMPTR_AppDomain vmAppDomain = pDAC->GetCurrentAppDomain(m_vmThreadToken);
836 _ASSERTE(GetAppDomain()->GetADToken() == vmAppDomain);
837#endif // _DEBUG
838
839 m_vmExcepObjHandle = vmObjHandle;
840 }
841 }
842
843 if (hr == S_OK)
844 {
845 // We've believe this assert may fire in the wild.
846 // We've seen m_vmExcepObjHandle null in retail builds after stack overflow.
847 _ASSERTE(!m_vmExcepObjHandle.IsNull());
848
849 ICorDebugReferenceValue * pRefValue = NULL;
850 hr = CordbReferenceValue::BuildFromGCHandle(GetAppDomain(), m_vmExcepObjHandle, &pRefValue);
851 *ppExceptionObject = pRefValue;
852 }
853 }
854 EX_CATCH_HRESULT(hr);
855
856 return hr;
857}
858
859HRESULT CordbThread::ClearCurrentException()
860{
861 PUBLIC_API_ENTRY(this);
862 FAIL_IF_NEUTERED(this);
863 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
864
865 // This API is not implemented. For Continuable Exceptions, see InterceptCurrentException.
866 // @todo - should it return E_NOTIMPL?
867 return S_OK;
868}
869
870HRESULT CordbThread::CreateStepper(ICorDebugStepper ** ppStepper)
871{
872 PUBLIC_API_ENTRY(this);
873 FAIL_IF_NEUTERED(this);
874 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
875
876 VALIDATE_POINTER_TO_OBJECT(ppStepper, ICorDebugStepper **);
877
878 CordbStepper * pStepper = new (nothrow) CordbStepper(this, NULL);
879
880 if (pStepper == NULL)
881 {
882 return E_OUTOFMEMORY;
883 }
884
885 pStepper->ExternalAddRef();
886 *ppStepper = pStepper;
887
888 return S_OK;
889}
890
891//Returns true if current user state of a thread is USER_WAIT_SLEEP_JOIN
892bool CordbThread::IsThreadWaitingOrSleeping()
893{
894 CorDebugUserState userState = m_userState;
895 if (userState == kInvalidUserState)
896 {
897 //If m_userState is not ready, we'll read from DAC only part of it which
898 //is important for us now, bacuase we don't want possible side effects
899 //of reading USER_UNSAFE_POINT flag.
900 //We don't cache the value, because it's potentially incomplete.
901 IDacDbiInterface *pDAC = GetProcess()->GetDAC();
902 userState = pDAC->GetPartialUserState(m_vmThreadToken);
903 }
904
905 return (userState & USER_WAIT_SLEEP_JOIN) != 0;
906}
907
908//----------------------------------------------------------------------------
909// check if the thread is dead
910//
911// Returns: true if the thread is dead.
912//
913bool CordbThread::IsThreadDead()
914{
915 return GetProcess()->GetDAC()->IsThreadMarkedDead(m_vmThreadToken);
916}
917
918// Helper to return CORDBG_E_BAD_THREAD_STATE if IsThreadDead
919//
920// Notes:
921// IsThreadDead queries the VM Thread's actual state, regardless of what ExitThread
922// callbacks have or have not been sent / queued / dispatched.
923HRESULT CordbThread::EnsureThreadIsAlive()
924{
925 if (IsThreadDead())
926 {
927 return CORDBG_E_BAD_THREAD_STATE;
928 }
929 else
930 {
931 return S_OK;
932 }
933}
934
935// ----------------------------------------------------------------------------
936// CordbThread::EnumerateChains
937//
938// Description:
939// Create and return an ICDChainEnum for enumerating chains on the stack. Since chains have been
940// deprecated in Arrowhead, this function returns E_NOTIMPL unless there is a shim.
941//
942// Arguments:
943// * ppChains - out parameter; return the ICDChainEnum
944//
945// Return Value:
946// Return S_OK on success.
947// Return E_INVALIDARG if ppChains is NULL.
948// Return CORDBG_E_OBJECT_NEUTERED if the CordbThread is neutered.
949// Return E_NOTIMPL if there is no shim.
950//
951
952HRESULT CordbThread::EnumerateChains(ICorDebugChainEnum ** ppChains)
953{
954 PUBLIC_API_ENTRY(this);
955 FAIL_IF_NEUTERED(this);
956
957 VALIDATE_POINTER_TO_OBJECT(ppChains, ICorDebugChainEnum **);
958
959 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
960
961 HRESULT hr = S_OK;
962 EX_TRY
963 {
964 *ppChains = NULL;
965
966 if (GetProcess()->GetShim() != NULL)
967 {
968 hr = EnsureThreadIsAlive();
969
970 if (SUCCEEDED(hr))
971 {
972 // use the shim to create an ICDChainEnum
973 PRIVATE_SHIM_CALLBACK_IN_THIS_SCOPE0(GetProcess());
974 ShimStackWalk * pSW = GetProcess()->GetShim()->LookupOrCreateShimStackWalk(this);
975 pSW->EnumerateChains(ppChains);
976 }
977 }
978 else
979 {
980 // This is the Arrowhead case, where ICDChain has been deprecated.
981 hr = E_NOTIMPL;
982 }
983 }
984 EX_CATCH_HRESULT(hr);
985
986 return hr;
987}
988
989// ----------------------------------------------------------------------------
990// CordbThread::GetActiveChain
991//
992// Description:
993// Retrieve the leaf chain on this thread. Since chains have been deprecated in Arrowhead,
994// this function returns E_NOTIMPL unless there is a shim.
995//
996// Arguments:
997// * ppChain - out parameter; return the leaf chain
998//
999// Return Value:
1000// Return S_OK on success.
1001// Return E_INVALIDARG if ppChain is NULL.
1002// Return CORDBG_E_OBJECT_NEUTERED if the CordbThread is neutered.
1003// Return E_NOTIMPL if there is no shim.
1004//
1005
1006HRESULT CordbThread::GetActiveChain(ICorDebugChain ** ppChain)
1007{
1008 PUBLIC_REENTRANT_API_ENTRY(this);
1009 FAIL_IF_NEUTERED(this);
1010
1011 VALIDATE_POINTER_TO_OBJECT(ppChain, ICorDebugChain **);
1012
1013 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
1014
1015 HRESULT hr = S_OK;
1016 EX_TRY
1017 {
1018 *ppChain = NULL;
1019 hr = EnsureThreadIsAlive();
1020
1021 if (SUCCEEDED(hr))
1022 {
1023 if (GetProcess()->GetShim() != NULL)
1024 {
1025 // use the shim to retrieve the leaf chain
1026 PRIVATE_SHIM_CALLBACK_IN_THIS_SCOPE0(GetProcess());
1027 ShimStackWalk * pSSW = GetProcess()->GetShim()->LookupOrCreateShimStackWalk(this);
1028 pSSW->GetActiveChain(ppChain);
1029 }
1030 else
1031 {
1032 // This is the Arrowhead case, where ICDChain has been deprecated.
1033 hr = E_NOTIMPL;
1034 }
1035 }
1036 }
1037 EX_CATCH_HRESULT(hr);
1038 return hr;
1039}
1040
1041// ----------------------------------------------------------------------------
1042// CordbThread::GetActiveFrame
1043//
1044// Description:
1045// Retrieve the leaf frame on this thread. Unfortunately, this is one of the cases where we need to
1046// do different things depending on whether there is a shim. See the Notes below.
1047//
1048// Arguments:
1049// * ppFrame - out parameter; return the leaf frame
1050//
1051// Return Value:
1052// Return S_OK on success.
1053// Return E_INVALIDARG if ppFrame is NULL.
1054// Return CORDBG_E_OBJECT_NEUTERED if the CordbThread is neutered.
1055// Also return whatever CreateStackWalk() and GetFrame() return if they fail.
1056//
1057// Notes:
1058// In V2, we return NULL if the leaf frame is not in the leaf chain, i.e. if the leaf chain is
1059// empty. Note that managed chains are never empty. Also, in V2 it is possible that this API
1060// will return an internal frame as the active frame on a thread.
1061//
1062// The Arrowhead implementation two breaking changes:
1063// 1) It never returns an internal frame.
1064// 2) We return a frame if the leaf frame is managed. Otherwise, we return NULL.
1065//
1066
1067HRESULT CordbThread::GetActiveFrame(ICorDebugFrame ** ppFrame)
1068{
1069 PUBLIC_REENTRANT_API_ENTRY(this);
1070 FAIL_IF_NEUTERED(this);
1071
1072 VALIDATE_POINTER_TO_OBJECT(ppFrame, ICorDebugFrame **);
1073
1074 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
1075
1076 HRESULT hr = S_OK;
1077 EX_TRY
1078 {
1079 *ppFrame = NULL;
1080 hr = EnsureThreadIsAlive();
1081
1082 if (SUCCEEDED(hr))
1083 {
1084 if (GetProcess()->GetShim() != NULL)
1085 {
1086 PRIVATE_SHIM_CALLBACK_IN_THIS_SCOPE0(GetProcess());
1087 ShimStackWalk * pSSW = GetProcess()->GetShim()->LookupOrCreateShimStackWalk(this);
1088 pSSW->GetActiveFrame(ppFrame);
1089 }
1090 else
1091 {
1092 // This is the Arrowhead case. We could call RefreshStack() here, but since we only need the
1093 // leaf frame, there is no point in walking the entire stack.
1094 RSExtSmartPtr<ICorDebugStackWalk> pSW;
1095 hr = CreateStackWalk(&pSW);
1096 IfFailThrow(hr);
1097
1098 hr = pSW->GetFrame(ppFrame);
1099 IfFailThrow(hr);
1100 }
1101 }
1102 }
1103 EX_CATCH_HRESULT(hr);
1104 return hr;
1105}
1106
1107// ----------------------------------------------------------------------------
1108// CordbThread::GetActiveRegister
1109//
1110// Description:
1111// In V2, retrieve the ICDRegisterSet for the leaf chain. In Arrowhead, retrieve the ICDRegisterSet
1112// for the leaf CONTEXT.
1113//
1114// Arguments:
1115// * ppRegisters - out parameter; return the ICDRegister
1116//
1117// Return Value:
1118// Return S_OK on success.
1119// Return E_INVALIDARG if ppFrame is NULL.
1120// Return CORDBG_E_OBJECT_NEUTERED if the CordbThread is neutered.
1121// Also return whatever CreateStackWalk() and GetContext() return if they fail.
1122//
1123
1124HRESULT CordbThread::GetRegisterSet(ICorDebugRegisterSet ** ppRegisters)
1125{
1126 PUBLIC_API_ENTRY(this);
1127 FAIL_IF_NEUTERED(this);
1128
1129 VALIDATE_POINTER_TO_OBJECT(ppRegisters, ICorDebugRegisterSet **);
1130
1131 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
1132
1133 HRESULT hr = S_OK;
1134 EX_TRY
1135 {
1136 *ppRegisters = NULL;
1137 hr = EnsureThreadIsAlive();
1138
1139 if (SUCCEEDED(hr))
1140 {
1141 if (GetProcess()->GetShim() != NULL)
1142 {
1143 // use the shim to retrieve the active ICDRegisterSet
1144 PRIVATE_SHIM_CALLBACK_IN_THIS_SCOPE0(GetProcess());
1145 ShimStackWalk * pSSW = GetProcess()->GetShim()->LookupOrCreateShimStackWalk(this);
1146 pSSW->GetActiveRegisterSet(ppRegisters);
1147 }
1148 else
1149 {
1150 // This is the Arrowhead case. We could call RefreshStack() here, but since we only need the
1151 // leaf frame, there is no point in walking the entire stack.
1152 RSExtSmartPtr<ICorDebugStackWalk> pSW;
1153 hr = CreateStackWalk(&pSW);
1154 IfFailThrow(hr);
1155
1156 // retrieve the leaf CONTEXT
1157 DT_CONTEXT ctx;
1158 hr = pSW->GetContext(CONTEXT_FULL, sizeof(ctx), NULL, reinterpret_cast<BYTE *>(&ctx));
1159 IfFailThrow(hr);
1160
1161 // the CordbRegisterSet is responsible for freeing this memory
1162 NewHolder<DebuggerREGDISPLAY> pDRD(new DebuggerREGDISPLAY());
1163
1164 // convert the CONTEXT to a DebuggerREGDISPLAY
1165 IDacDbiInterface * pDAC = GetProcess()->GetDAC();
1166 pDAC->ConvertContextToDebuggerRegDisplay(&ctx, pDRD, true);
1167
1168 // create the CordbRegisterSet
1169 RSInitHolder<CordbRegisterSet> pRS(new CordbRegisterSet(pDRD,
1170 this,
1171 true, // active
1172 false, // !fQuickUnwind
1173 true)); // own DRD memory
1174 pDRD.SuppressRelease();
1175
1176 pRS.TransferOwnershipExternal(ppRegisters);
1177 }
1178 }
1179 }
1180 EX_CATCH_HRESULT(hr);
1181 return hr;
1182}
1183
1184HRESULT CordbThread::CreateEval(ICorDebugEval ** ppEval)
1185{
1186 PUBLIC_API_ENTRY(this);
1187 FAIL_IF_NEUTERED(this);
1188 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
1189
1190 VALIDATE_POINTER_TO_OBJECT(ppEval, ICorDebugEval **);
1191
1192 CordbEval * pEval = new (nothrow) CordbEval(this);
1193 if (pEval == NULL)
1194 {
1195 return E_OUTOFMEMORY;
1196 }
1197
1198 pEval->ExternalAddRef();
1199 *ppEval = static_cast<ICorDebugEval *>(pEval);
1200
1201 return S_OK;
1202}
1203
1204// DAC check
1205
1206// Double check our results w/ DAC.
1207// This gives DAC some great coverage.
1208// Given an IP and the md token (that the RS obtained), use DAC to lookup the md token. Then
1209// we can compare DAC & the RS and make sure DACs working.
1210void CheckAgainstDAC(CordbFunction * pFunc, void * pIP, mdMethodDef mdExpected)
1211{
1212 // This is a hook to add DAC checks against a {function, ip}
1213}
1214
1215
1216//---------------------------------------------------------------------------------------
1217//
1218// Internal function to build up a stack trace.
1219//
1220//
1221// Return Value:
1222// S_OK on success.
1223//
1224// Assumptions:
1225// Process is stopped.
1226//
1227// Notes:
1228// Send a IPC events to the LS to build up the stack.
1229//
1230//---------------------------------------------------------------------------------------
1231void CordbThread::RefreshStack()
1232{
1233 THROW_IF_NEUTERED(this);
1234
1235 // We must have the Stop-Go lock to change our thread's stack-state.
1236 // Also, our caller should have guaranteed that we're synced. And b/c we hold the stop-go lock,
1237 // that shouldn't have changed.
1238 // INTERNAL_SYNC_API_ENTRY() checks that we have the lock and that we are synced.
1239 INTERNAL_SYNC_API_ENTRY(GetProcess());
1240
1241 // bail out early if the stack hasn't changed
1242 if (m_fFramesFresh)
1243 {
1244 return;
1245 }
1246
1247 HRESULT hr = S_OK;
1248
1249 //
1250 // Clean up old snapshot.
1251 //
1252
1253 RSLockHolder lockHolder(GetProcess()->GetProcessLock());
1254
1255 // clear the stack frame cache
1256 ClearStackFrameCache();
1257
1258 //
1259 // If we don't have a debugger thread token, then this thread has never
1260 // executed managed code and we have no frame information for it.
1261 //
1262 if (m_vmThreadToken.IsNull())
1263 {
1264 ThrowHR(E_FAIL);
1265 }
1266
1267 // walk the stack using the V3 API and populate the stack frame cache
1268 RSInitHolder<CordbStackWalk> pSW(new CordbStackWalk(this));
1269 pSW->Init();
1270 do
1271 {
1272 RSExtSmartPtr<ICorDebugFrame> pIFrame;
1273 hr = pSW->GetFrame(&pIFrame);
1274 IfFailThrow(hr);
1275
1276 if (pIFrame != NULL)
1277 {
1278 // add the stack frame to the cache
1279 CordbFrame ** ppCFrame = m_stackFrames.AppendThrowing();
1280 *ppCFrame = CordbFrame::GetCordbFrameFromInterface(pIFrame);
1281
1282 // Now that we have saved the pointer, increment the ref count.
1283 // This has to match the InternalRelease() in code:CordbThread::ClearStackFrameCache.
1284 (*ppCFrame)->InternalAddRef();
1285 }
1286
1287 // advance to the next frame
1288 hr = pSW->Next();
1289 IfFailThrow(hr);
1290 }
1291 while (hr != CORDBG_S_AT_END_OF_STACK);
1292
1293 m_fFramesFresh = true;
1294}
1295
1296
1297//---------------------------------------------------------------------------------------
1298//
1299// This function is used to invalidate and clean up the cached stack trace.
1300//
1301
1302void CordbThread::CleanupStack()
1303{
1304 _ASSERTE(GetProcess()->GetProcessLock()->HasLock());
1305
1306 // Neuter outstanding CordbChainEnums, CordbFrameEnums, some CordbTypeEnums, and some CordbValueEnums.
1307 m_RefreshStackNeuterList.NeuterAndClear(GetProcess());
1308
1309 m_fContextFresh = false; // invalidate the cached active CONTEXT
1310 m_vmLeftSideContext = VMPTR_CONTEXT::NullPtr(); // set the LS pointer to the active CONTEXT to NULL
1311 m_fFramesFresh = false; // invalidate the cached stack trace (frames & chains)
1312 m_userState = kInvalidUserState; // clear the cached user state
1313
1314 // tell the shim to flush its caches as well
1315 if (GetProcess()->GetShim() != NULL)
1316 {
1317 GetProcess()->GetShim()->NotifyOnStackInvalidate();
1318 }
1319}
1320
1321// Notifying the thread that the process is being continued.
1322// This will cause our caches to get invalidated without actually cleaning the caches.
1323void CordbThread::MarkStackFramesDirty()
1324{
1325 LIMITED_METHOD_CONTRACT;
1326
1327 _ASSERTE(GetProcess()->ThreadHoldsProcessLock());
1328
1329 // invalidate the cached floating point state
1330 m_fFloatStateValid = false;
1331
1332 // This flag is only true between the window when we get an exception callback and
1333 // when we call continue. Since this function is only called when we continue, we
1334 // need to reset this flag here. Note that in the case of an outstanding funceval,
1335 // we'll set this flag again when the funceval is completed.
1336 m_fException = false;
1337
1338 // Clear the stashed EnC remap IP address if any
1339 // This is important to ensure we don't try to write into LS memory which is no longer
1340 // being used to hold the remap IP.
1341 m_EnCRemapFunctionIP = NULL;
1342
1343 m_fContextFresh = false; // invalidate the cached active CONTEXT
1344 m_vmLeftSideContext = VMPTR_CONTEXT::NullPtr(); // set the LS pointer to the active CONTEXT to NULL
1345 m_fFramesFresh = false; // invalidate the cached stack trace (frames & chains)
1346 m_userState = kInvalidUserState; // clear the cached user state
1347
1348 m_RefreshStackNeuterList.NeuterAndClear(GetProcess());
1349
1350 // tell the shim to flush its caches as well
1351 if (GetProcess()->GetShim() != NULL)
1352 {
1353 GetProcess()->GetShim()->NotifyOnStackInvalidate();
1354 }
1355}
1356
1357// Set that there's an outstanding exception on this thread.
1358// This can be called when the process object receives an exception notification.
1359// This is cleared in code:CordbThread::MarkStackFramesDirty.
1360void CordbThread::SetExInfo(VMPTR_OBJECTHANDLE vmExcepObjHandle)
1361{
1362 m_fException = true;
1363 m_vmExcepObjHandle = vmExcepObjHandle;
1364
1365 // CordbThread::GetCurrentException assumes that we always have a m_vmExcepObjHandle when at an exception.
1366 // Push that assert up here.
1367 _ASSERTE(!m_vmExcepObjHandle.IsNull());
1368}
1369
1370
1371// ----------------------------------------------------------------------------
1372// CordbThread::FindFrame
1373//
1374// Description:
1375// Given a FramePointer, find the matching CordbFrame.
1376//
1377// Arguments:
1378// * ppFrame - out parameter; the CordbFrame to be returned
1379// * fp - the input FramePointer
1380//
1381// Return Value:
1382// Return S_OK on success.
1383// Return E_FAIL on failure.
1384//
1385// Assumptions:
1386// * This function is only called from the shim.
1387//
1388// Notes:
1389// * Currently this function is only used by the shim to map the FramePointer it gets via the
1390// DB_IPCE_EXCEPTION_CALLBACK2 callback. When we figure out what to do with the
1391// DB_IPCE_EXCEPTION_CALLBACK2, we should remove this function.
1392//
1393
1394HRESULT CordbThread::FindFrame(ICorDebugFrame ** ppFrame, FramePointer fp)
1395{
1396 FAIL_IF_NEUTERED(this);
1397
1398 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
1399
1400 _ASSERTE(ppFrame != NULL);
1401 *ppFrame = NULL;
1402
1403 _ASSERTE(GetProcess()->GetShim() != NULL);
1404
1405 PRIVATE_SHIM_CALLBACK_IN_THIS_SCOPE0(GetProcess());
1406 ShimStackWalk * pSSW = GetProcess()->GetShim()->LookupOrCreateShimStackWalk(this);
1407
1408 for (UINT32 i = 0; i < pSSW->GetFrameCount(); i++)
1409 {
1410 ICorDebugFrame * pIFrame = pSSW->GetFrame(i);
1411 CordbFrame * pCFrame = CordbFrame::GetCordbFrameFromInterface(pIFrame);
1412
1413#if defined(_WIN64)
1414 // On 64-bit we can simply compare the FramePointer.
1415 if (pCFrame->GetFramePointer() == fp)
1416#else // !_WIN64
1417 // On other platforms, we need to do a more elaborate check.
1418 if (pCFrame->IsContainedInFrame(fp))
1419#endif // _WIN64
1420 {
1421 *ppFrame = pIFrame;
1422 (*ppFrame)->AddRef();
1423 return S_OK;
1424 }
1425 }
1426
1427 // Cannot find the frame.
1428 return E_FAIL;
1429}
1430
1431
1432
1433#if defined(CROSS_COMPILE) && (defined(_TARGET_ARM64_) || defined(_TARGET_ARM_))
1434extern "C" double FPFillR8(void* pFillSlot)
1435{
1436 _ASSERTE(!"nyi for platform");
1437 return 0;
1438}
1439#elif defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_) || defined(_TARGET_ARM_)
1440extern "C" double FPFillR8(void* pFillSlot);
1441#endif
1442
1443
1444#if defined(_TARGET_X86_)
1445
1446// CordbThread::Get32bitFPRegisters
1447// Converts the values in the floating point register area of the context to real number values. See
1448// code:CordbThread::LoadFloatState for more details.
1449// Arguments:
1450// input: pContext
1451// output: none (initializes m_floatValues)
1452
1453void CordbThread::Get32bitFPRegisters(CONTEXT * pContext)
1454{
1455 // On X86, we get the values by saving our current FPU state, loading
1456 // the other thread's FPU state into our own, saving out each
1457 // value off the FPU stack, and then restoring our FPU state.
1458 //
1459 FLOATING_SAVE_AREA floatarea = pContext->FloatSave; // copy FloatSave
1460
1461 //
1462 // Take the TOP out of the FPU status word. Note, our version of the
1463 // stack runs from 0->7, not 7->0...
1464 //
1465 unsigned int floatStackTop = 7 - ((floatarea.StatusWord & 0x3800) >> 11);
1466
1467 FLOATING_SAVE_AREA currentFPUState;
1468
1469#ifdef _MSC_VER
1470 __asm fnsave currentFPUState // save the current FPU state.
1471#else
1472 __asm__ __volatile__
1473 (
1474 " fnsave %0\n" \
1475 : "=m"(currentFPUState)
1476 );
1477#endif
1478
1479 floatarea.StatusWord &= 0xFF00; // remove any error codes.
1480 floatarea.ControlWord |= 0x3F; // mask all exceptions.
1481
1482 // the x86 FPU stores real numbers as 10 byte values in IEEE format. Here we use
1483 // the hardware to convert these to doubles.
1484
1485 // @dbgtodo Microsoft crossplat: the conversion from a series of bytes to a floating
1486 // point value will need to be done with an explicit conversion routine to unpack
1487 // the IEEE format and compute the real number value represented.
1488
1489#ifdef _MSC_VER
1490 __asm
1491 {
1492 fninit
1493 frstor floatarea ;; reload the threads FPU state.
1494 }
1495#else
1496 __asm__
1497 (
1498 " fninit\n" \
1499 " frstor %0\n" \
1500 : /* no outputs */
1501 : "m"(floatarea)
1502 );
1503#endif
1504
1505 unsigned int i;
1506
1507 for (i = 0; i <= floatStackTop; i++)
1508 {
1509 double td = 0.0;
1510 __asm fstp td // copy out the double
1511 m_floatValues[i] = td;
1512 }
1513
1514#ifdef _MSC_VER
1515 __asm
1516 {
1517 fninit
1518 frstor currentFPUState ;; restore our saved FPU state.
1519 }
1520#else
1521 __asm__
1522 (
1523 " fninit\n" \
1524 " frstor %0\n" \
1525 : /* no outputs */
1526 : "m"(currentFPUState)
1527 );
1528#endif
1529
1530 m_fFloatStateValid = true;
1531 m_floatStackTop = floatStackTop;
1532} // CordbThread::Get32bitFPRegisters
1533
1534#elif defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_) || defined(_TARGET_ARM_)
1535
1536// CordbThread::Get64bitFPRegisters
1537// Converts the values in the floating point register area of the context to real number values. See
1538// code:CordbThread::LoadFloatState for more details.
1539// Arguments:
1540// input: pFPRegisterBase - starting address of the floating point register storage of the CONTEXT
1541// registerSize - the size of a floating point register
1542// start - the index into m_floatValues where we start initializing. For amd64, we start
1543// at the beginning, but for ia64, the first two registers have fixed values,
1544// so we start at two.
1545// nRegisters - the number of registers to be initialized
1546// output: none (initializes m_floatValues)
1547
1548void CordbThread::Get64bitFPRegisters(FPRegister64 * rgContextFPRegisters, int start, int nRegisters)
1549{
1550 // make sure no one has changed the type definition for 64-bit FP registers
1551 _ASSERTE(sizeof(FPRegister64) == 16);
1552 // We convert and copy all the fp registers.
1553 for (int reg = start; reg < nRegisters; reg++)
1554 {
1555 // @dbgtodo Microsoft crossplat: the conversion from a FLOAT128 or M128A struct to a floating
1556 // point value will need to be done with an explicit conversion routine instead
1557 // of the call to FPFillR8
1558 m_floatValues[reg] = FPFillR8(&rgContextFPRegisters[reg - start]);
1559 }
1560} // CordbThread::Get64bitFPRegisters
1561
1562#endif // _TARGET_X86_
1563
1564// CordbThread::LoadFloatState
1565// Initializes the float state members of this instance of CordbThread. This function gets the context and
1566// converts the floating point values from their context representation to a real number value. Floating
1567// point numbers are represented in IEEE format on all current platforms. We store them in the context as a
1568// pair of 64-bit integers (IA64 and AMD64) or a series of bytes (x86). Rather than unpack them explicitly
1569// and do the appropriate mathematical operations to produce the corresponding floating point value, we let
1570// the hardware do it instead. We load a floating point register with the representation from the context
1571// and then store it in m_floatValues. Using the hardware is obviously a huge perf win. If/when we make
1572// cross-plat work, we should at least code necessary conversion routines in assembly. Even with cross-plat,
1573// we can probably still use the hardware in most cases, as long as the size is appropriate.
1574//
1575// Arguments: none
1576// Return Value: none (initializes data members)
1577// Note: Throws
1578
1579void CordbThread::LoadFloatState()
1580{
1581 THROW_IF_NEUTERED(this);
1582 INTERNAL_SYNC_API_ENTRY(GetProcess());
1583
1584 DT_CONTEXT tempContext;
1585 GetProcess()->GetDAC()->GetContext(m_vmThreadToken, &tempContext);
1586
1587#if defined(_TARGET_X86_)
1588 Get32bitFPRegisters((CONTEXT*) &tempContext);
1589#elif defined(_TARGET_AMD64_)
1590 // we have no fixed-value registers, so we begin with the first one and initialize all 16
1591 Get64bitFPRegisters((FPRegister64*) &(tempContext.Xmm0), 0, 16);
1592#elif defined(_TARGET_ARM64_)
1593 Get64bitFPRegisters((FPRegister64*) &(tempContext.V), 0, 32);
1594#elif defined (_TARGET_ARM_)
1595 Get64bitFPRegisters((FPRegister64*) &(tempContext.D), 0, 32);
1596#else
1597 _ASSERTE(!"nyi for platform");
1598#endif // !_TARGET_X86_
1599
1600 m_fFloatStateValid = true;
1601} // CordbThread::LoadFloatState
1602
1603
1604const bool SetIP_fCanSetIPOnly = TRUE;
1605const bool SetIP_fSetIP = FALSE;
1606
1607const bool SetIP_fIL = TRUE;
1608const bool SetIP_fNative = FALSE;
1609
1610//---------------------------------------------------------------------------------------
1611//
1612// Issues a SetIP command to the left-side and returns the result
1613//
1614// Arguments:
1615// fCanSetIPOnly - TRUE if only to do the setip command and not refresh stacks as well.
1616// debuggerModule - LS token to the debugger module.
1617// mdMethod - Metadata token for the method.
1618// nativeCodeJITInfoToken - LS token to the DebuggerJitInfo for the method.
1619// offset - Offset within the method to set the IP to.
1620// fIsIl - Is this an IL offset?
1621//
1622// Return Value:
1623// S_OK on success.
1624//
1625HRESULT CordbThread::SetIP(bool fCanSetIPOnly,
1626 CordbNativeCode * pNativeCode,
1627 SIZE_T offset,
1628 bool fIsIL)
1629{
1630 PUBLIC_REENTRANT_API_ENTRY(this);
1631 FAIL_IF_NEUTERED(this);
1632
1633
1634 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
1635
1636 VMPTR_DomainFile vmDomainFile = pNativeCode->GetModule()->m_vmDomainFile;
1637 _ASSERTE(!vmDomainFile.IsNull());
1638
1639 // If this thread is stopped due to an exception, never allow SetIP
1640 if (HasException())
1641 {
1642 return (CORDBG_E_SET_IP_NOT_ALLOWED_ON_EXCEPTION);
1643 }
1644
1645 DebuggerIPCEvent event;
1646 GetProcess()->InitIPCEvent(&event, DB_IPCE_SET_IP, true, GetAppDomain()->GetADToken());
1647 event.SetIP.fCanSetIPOnly = fCanSetIPOnly;
1648 event.SetIP.vmThreadToken = m_vmThreadToken;
1649 event.SetIP.vmDomainFile = vmDomainFile;
1650 event.SetIP.mdMethod = pNativeCode->GetMetadataToken();
1651 event.SetIP.vmMethodDesc = pNativeCode->GetVMNativeCodeMethodDescToken();
1652 event.SetIP.startAddress = pNativeCode->GetAddress();
1653 event.SetIP.offset = offset;
1654 event.SetIP.fIsIL = fIsIL;
1655
1656
1657 LOG((LF_CORDB, LL_INFO10000, "[%x] CT::SIP: Info:thread:0x%x"
1658 "mod:0x%x MethodDef:0x%x offset:0x%x il?:0x%x\n",
1659 GetCurrentThreadId(),
1660 VmPtrToCookie(m_vmThreadToken),
1661 VmPtrToCookie(vmDomainFile),
1662 pNativeCode->GetMetadataToken(),
1663 offset,
1664 fIsIL));
1665
1666 LOG((LF_CORDB, LL_INFO10000, "[%x] CT::SIP: sizeof(DebuggerIPCEvent):0x%x **********\n",
1667 sizeof(DebuggerIPCEvent)));
1668
1669 HRESULT hr = GetProcess()->m_cordb->SendIPCEvent(GetProcess(), &event, sizeof(DebuggerIPCEvent));
1670
1671 if (FAILED(hr))
1672 {
1673 return hr;
1674 }
1675
1676 _ASSERTE(event.type == DB_IPCE_SET_IP);
1677
1678 if (!fCanSetIPOnly && SUCCEEDED(event.hr))
1679 {
1680 RSLockHolder lockHolder(GetProcess()->GetProcessLock());
1681 CleanupStack();
1682 }
1683
1684 return ErrWrapper(event.hr);
1685}
1686
1687// Get the context from a thread in managed code.
1688// This thread should be stopped gracefully by the LS in managed code.
1689HRESULT CordbThread::GetManagedContext(DT_CONTEXT ** ppContext)
1690{
1691 FAIL_IF_NEUTERED(this);
1692 INTERNAL_SYNC_API_ENTRY(GetProcess());
1693
1694 if (ppContext == NULL)
1695 {
1696 ThrowHR(E_INVALIDARG);
1697 }
1698
1699 *ppContext = NULL;
1700 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
1701
1702 // Each CordbThread object allocates the m_pContext's DT_CONTEXT structure only once, the first time GetContext is
1703 // invoked.
1704 if(m_pContext == NULL)
1705 {
1706 // Throw if the allocation fails.
1707 m_pContext = reinterpret_cast<DT_CONTEXT *>(new BYTE[sizeof(DT_CONTEXT)]);
1708 }
1709
1710 HRESULT hr = S_OK;
1711
1712 if (m_fContextFresh == false)
1713 {
1714 IDacDbiInterface * pDAC = GetProcess()->GetDAC();
1715 m_vmLeftSideContext = pDAC->GetManagedStoppedContext(m_vmThreadToken);
1716
1717 if (m_vmLeftSideContext.IsNull())
1718 {
1719 // We don't have a context in managed code.
1720 ThrowHR(CORDBG_E_CONTEXT_UNVAILABLE);
1721 }
1722 else
1723 {
1724 LOG((LF_CORDB, LL_INFO1000, "CT::GC: getting context from left side pointer.\n"));
1725
1726 // The thread we're examining IS handling an exception, So grab the CONTEXT of the exception, NOT the
1727 // currently executing thread's CONTEXT (which would be the context of the exception handler.)
1728 hr = GetProcess()->SafeReadThreadContext(m_vmLeftSideContext.ToLsPtr(), m_pContext);
1729 IfFailThrow(hr);
1730 }
1731
1732 // m_fContextFresh should be marked false when CleanupStack, MarkAllFramesAsDirty, etc get called.
1733 m_fContextFresh = true;
1734 }
1735
1736 _ASSERTE(SUCCEEDED(hr));
1737 (*ppContext) = m_pContext;
1738
1739 return hr;
1740}
1741
1742HRESULT CordbThread::SetManagedContext(DT_CONTEXT * pContext)
1743{
1744 INTERNAL_API_ENTRY(this);
1745 FAIL_IF_NEUTERED(this);
1746
1747 if(pContext == NULL)
1748 {
1749 ThrowHR(E_INVALIDARG);
1750 }
1751
1752 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
1753
1754 HRESULT hr = S_OK;
1755
1756 IDacDbiInterface * pDAC = GetProcess()->GetDAC();
1757 m_vmLeftSideContext = pDAC->GetManagedStoppedContext(m_vmThreadToken);
1758
1759 if (m_vmLeftSideContext.IsNull())
1760 {
1761 ThrowHR(CORDBG_E_CONTEXT_UNVAILABLE);
1762 }
1763 else
1764 {
1765 // The thread we're examining IS handling an exception, So set the CONTEXT of the exception, NOT the currently
1766 // executing thread's CONTEXT (which would be the context of the exception handler.)
1767 //
1768 // Note: we read the remote context and merge the new one in, then write it back. This ensures that we don't
1769 // write too much information into the remote process.
1770 DT_CONTEXT tempContext = { 0 };
1771 hr = GetProcess()->SafeReadThreadContext(m_vmLeftSideContext.ToLsPtr(), &tempContext);
1772 IfFailThrow(hr);
1773
1774 CORDbgCopyThreadContext(&tempContext, pContext);
1775
1776 hr = GetProcess()->SafeWriteThreadContext(m_vmLeftSideContext.ToLsPtr(), &tempContext);
1777 IfFailThrow(hr);
1778
1779 // @todo - who's updating the regdisplay to guarantee that's in sync w/ our new context?
1780 }
1781
1782 _ASSERTE(SUCCEEDED(hr));
1783 if (m_fContextFresh && (m_pContext != NULL))
1784 {
1785 *m_pContext = *pContext;
1786 }
1787
1788 return hr;
1789}
1790
1791
1792HRESULT CordbThread::GetAppDomain(ICorDebugAppDomain ** ppAppDomain)
1793{
1794 // We don't use the cached m_pAppDomain pointer here because it might be incorrect
1795 // if the thread has transitioned to another domain but we haven't received any events
1796 // from it yet. So we need to ask the left-side for the current domain.
1797 HRESULT hr = S_OK;
1798 PUBLIC_API_BEGIN(this);
1799 {
1800 ValidateOrThrow(ppAppDomain);
1801 *ppAppDomain = NULL;
1802 hr = EnsureThreadIsAlive();
1803
1804 if (SUCCEEDED(hr))
1805 {
1806 CordbAppDomain * pAppDomain = NULL;
1807 hr = GetCurrentAppDomain(&pAppDomain);
1808 IfFailThrow(hr);
1809 _ASSERTE( pAppDomain != NULL );
1810
1811 *ppAppDomain = static_cast<ICorDebugAppDomain *> (pAppDomain);
1812 pAppDomain->ExternalAddRef();
1813 }
1814 }
1815 PUBLIC_API_END(hr);
1816 return hr;
1817}
1818
1819//---------------------------------------------------------------------------------------
1820//
1821// Issues a get appdomain command and returns it.
1822//
1823// Arguments:
1824// ppAppDomain - OUT: Space for storing the app domain of this thread.
1825//
1826// Return Value:
1827// S_OK on success.
1828//
1829HRESULT CordbThread::GetCurrentAppDomain(CordbAppDomain ** ppAppDomain)
1830{
1831 FAIL_IF_NEUTERED(this);
1832 INTERNAL_API_ENTRY(GetProcess());
1833
1834 *ppAppDomain = NULL;
1835
1836 HRESULT hr = S_OK;
1837 EX_TRY
1838 {
1839 // @dbgtodo ICDThread - push this up
1840 RSLockHolder lockHolder(GetProcess()->GetProcessLock());
1841
1842 hr = EnsureThreadIsAlive();
1843
1844 if (SUCCEEDED(hr))
1845 {
1846 IDacDbiInterface * pDAC = GetProcess()->GetDAC();
1847 VMPTR_AppDomain vmAppDomain = pDAC->GetCurrentAppDomain(m_vmThreadToken);
1848
1849 CordbAppDomain * pAppDomain = GetProcess()->LookupOrCreateAppDomain(vmAppDomain);
1850 _ASSERTE(pAppDomain != NULL); // we should be aware of all AppDomains
1851
1852 *ppAppDomain = pAppDomain;
1853 }
1854 }
1855 EX_CATCH_HRESULT(hr);
1856
1857 return S_OK;
1858}
1859
1860//---------------------------------------------------------------------------------------
1861//
1862// Issues a get_object command and returns the thread object as a value.
1863//
1864// Arguments:
1865// ppThreadObject - OUT: Space for storing the thread object of this thread as a value
1866//
1867// Return Value:
1868// S_OK on success.
1869//
1870HRESULT CordbThread::GetObject(ICorDebugValue ** ppThreadObject)
1871{
1872 PUBLIC_API_ENTRY(this);
1873 FAIL_IF_NEUTERED(this);
1874
1875 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
1876
1877 VALIDATE_POINTER_TO_OBJECT(ppThreadObject, ICorDebugObjectValue **);
1878
1879 // Default to NULL
1880 *ppThreadObject = NULL;
1881
1882 HRESULT hr = S_OK;
1883 EX_TRY
1884 {
1885 // @dbgtodo ICDThread - push this up
1886 RSLockHolder lockHolder(GetProcess()->GetProcessLock());
1887
1888 hr = EnsureThreadIsAlive();
1889
1890 if (SUCCEEDED(hr))
1891 {
1892 IDacDbiInterface * pDAC = GetProcess()->GetDAC();
1893 VMPTR_OBJECTHANDLE vmObjHandle = pDAC->GetThreadObject(m_vmThreadToken);
1894 if (vmObjHandle.IsNull())
1895 {
1896 ThrowHR(E_FAIL);
1897 }
1898
1899 // We create the object relative to the current AppDomain of the thread
1900 // Thread objects aren't really agile (eg. their m_Context field is domain-bound and
1901 // fixed up manually during transitions). This means that a thread object can only
1902 // be used in the domain the thread was in when the object was created.
1903 VMPTR_AppDomain vmAppDomain = pDAC->GetCurrentAppDomain(m_vmThreadToken);
1904
1905 CordbAppDomain * pThreadCurrentDomain = NULL;
1906 pThreadCurrentDomain = GetProcess()->m_appDomains.GetBaseOrThrow(VmPtrToCookie(vmAppDomain));
1907 _ASSERTE(pThreadCurrentDomain != NULL); // we should be aware of all AppDomains
1908
1909 if (pThreadCurrentDomain == NULL)
1910 {
1911 // fall back to some domain to avoid crashes in retail -
1912 // safe enough for getting the name of the thread etc.
1913 pThreadCurrentDomain = GetProcess()->GetDefaultAppDomain();
1914 }
1915
1916 lockHolder.Release();
1917
1918 ICorDebugReferenceValue * pRefValue = NULL;
1919 hr = CordbReferenceValue::BuildFromGCHandle(pThreadCurrentDomain, vmObjHandle, &pRefValue);
1920 *ppThreadObject = pRefValue;
1921 }
1922 }
1923 EX_CATCH_HRESULT(hr);
1924
1925 // Don't return a null pointer with S_OK.
1926 _ASSERTE((hr != S_OK) || (*ppThreadObject != NULL));
1927 return hr;
1928}
1929
1930/*
1931 *
1932 * GetActiveFunctions
1933 *
1934 * This routine is the interface function for ICorDebugThread2::GetActiveFunctions.
1935 *
1936 * Parameters:
1937 * cFunctions - the count of the number of COR_ACTIVE_FUNCTION in pFunctions. Zero
1938 * indicates no pFunctions buffer.
1939 * pcFunctions - pointer to storage for the count of elements filled in to pFunctions, or
1940 * count that would be needed to fill pFunctions, if cFunctions is 0.
1941 * pFunctions - buffer to store results. May be NULL.
1942 *
1943 * Return Value:
1944 * HRESULT from the helper routine.
1945 *
1946 */
1947
1948HRESULT CordbThread::GetActiveFunctions(
1949 ULONG32 cFunctions,
1950 ULONG32 * pcFunctions,
1951 COR_ACTIVE_FUNCTION pFunctions[])
1952{
1953 PUBLIC_API_ENTRY(this);
1954 FAIL_IF_NEUTERED(this);
1955
1956 ULONG32 index;
1957 ULONG32 iRealIndex;
1958 ULONG32 last;
1959
1960 if (((cFunctions != 0) && (pFunctions == NULL)) || (pcFunctions == NULL))
1961 {
1962 return E_INVALIDARG;
1963 }
1964
1965 //
1966 // Default to 0
1967 //
1968 *pcFunctions = 0;
1969
1970 // @dbgtodo synchronization - The ATT macro may slip the thread to a sychronized state. The
1971 // synchronization feature crew needs to figure out what to do here. Then we can use the
1972 // PUBLIC_API_BEGIN macro in this function.
1973 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
1974
1975 HRESULT hr = S_OK;
1976 EX_TRY
1977 {
1978 RSLockHolder lockHolder(GetProcess()->GetProcessLock());
1979
1980 if (IsThreadDead())
1981 {
1982 //
1983 // Return zero active functions on this thread.
1984 //
1985 hr = S_OK;
1986 }
1987 else
1988 {
1989 ULONG32 cAllFrames = 0; // the total number of frames (stack frames and internal frames)
1990 ULONG32 cStackFrames = 0; // the number of stack frames
1991 ShimStackWalk * pSSW = NULL;
1992
1993 if (GetProcess()->GetShim() != NULL)
1994 {
1995 PRIVATE_SHIM_CALLBACK_IN_THIS_SCOPE0(GetProcess());
1996 pSSW = GetProcess()->GetShim()->LookupOrCreateShimStackWalk(this);
1997
1998 // initialize the frame counts
1999 cAllFrames = pSSW->GetFrameCount();
2000 for (ULONG32 i = 0; i < cAllFrames; i++)
2001 {
2002 // filter out internal frames
2003 if (CordbFrame::GetCordbFrameFromInterface(pSSW->GetFrame(i))->GetAsNativeFrame() != NULL)
2004 {
2005 cStackFrames += 1;
2006 }
2007 }
2008
2009 _ASSERTE(cStackFrames <= cAllFrames);
2010 }
2011 else
2012 {
2013 RefreshStack();
2014
2015 cAllFrames = m_stackFrames.Count();
2016 cStackFrames = cAllFrames;
2017
2018 // In Arrowhead, the stackwalking API doesn't return internal frames,
2019 // so the frame counts should be equal.
2020 _ASSERTE(cStackFrames == cAllFrames);
2021 }
2022
2023 *pcFunctions = cStackFrames;
2024
2025 //
2026 // If all we want is the count, then return that.
2027 //
2028 if ((pFunctions == NULL) || (cFunctions == 0))
2029 {
2030 hr = S_OK;
2031 }
2032 else
2033 {
2034 //
2035 // Now go down list of frames, storing information
2036 //
2037 last = (cFunctions < cStackFrames) ? cFunctions : cStackFrames;
2038 iRealIndex = 0;
2039 index =0;
2040
2041 while((index < last) && (iRealIndex < cAllFrames))
2042 {
2043 CordbFrame * pThisFrame = NULL;
2044 if (GetProcess()->GetShim())
2045 {
2046 _ASSERTE(pSSW != NULL);
2047 pThisFrame = CordbFrame::GetCordbFrameFromInterface(pSSW->GetFrame(iRealIndex));
2048 }
2049 else
2050 {
2051 pThisFrame = *(m_stackFrames.Get(iRealIndex));
2052 _ASSERTE(pThisFrame->GetAsNativeFrame() != NULL);
2053 }
2054
2055 iRealIndex++;
2056
2057 CordbNativeFrame * pNativeFrame = pThisFrame->GetAsNativeFrame();
2058 if (pNativeFrame == NULL)
2059 {
2060 // filter out internal frames
2061 _ASSERTE(pThisFrame->GetAsInternalFrame() != NULL);
2062 continue;
2063 }
2064
2065 //
2066 // Fill in the easy stuff.
2067 //
2068 CordbFunction * pFunction;
2069
2070 pFunction = (static_cast<CordbFrame *>(pNativeFrame))->GetFunction();
2071 ASSERT(pFunction != NULL);
2072
2073 hr = pFunction->QueryInterface(IID_ICorDebugFunction2,
2074 reinterpret_cast<void **>(&(pFunctions[index].pFunction)));
2075 ASSERT(!FAILED(hr));
2076
2077 CordbModule * pModule = pFunction->GetModule();
2078 pFunctions[index].pModule = pModule;
2079 pModule->ExternalAddRef();
2080
2081 CordbAppDomain * pAppDomain = pNativeFrame->GetCurrentAppDomain();
2082 pFunctions[index].pAppDomain = pAppDomain;
2083 pAppDomain->ExternalAddRef();
2084
2085 pFunctions[index].flags = 0;
2086
2087 //
2088 // Now go to the IL frame (if one exists) to the get the offset.
2089 //
2090 CordbJITILFrame * pJITILFrame;
2091
2092 pJITILFrame = pNativeFrame->m_JITILFrame;
2093
2094 if (pJITILFrame != NULL)
2095 {
2096 hr = pJITILFrame->GetIP(&(pFunctions[index].ilOffset), NULL);
2097 ASSERT(!FAILED(hr));
2098 }
2099 else
2100 {
2101 pFunctions[index].ilOffset = (DWORD) NO_MAPPING;
2102 }
2103
2104 // Update to the next count.
2105 index++;
2106 }
2107
2108 // @todo - The spec says that pcFunctions == # of elements in pFunctions,
2109 // but the behavior here is that it's always the total.
2110 // If we want to fix that, we should uncomment the assignment here:
2111 //*pcFunctions = index;
2112 }
2113 }
2114 }
2115 EX_CATCH_HRESULT(hr);
2116 return hr;
2117}
2118
2119
2120//---------------------------------------------------------------------------------------
2121//
2122// This is the entry point for continuable exceptions.
2123// It implements ICorDebugThread2::InterceptCurrentException.
2124//
2125// Arguments:
2126// pFrame - the stack frame to intercept at
2127//
2128// Return Value:
2129// HRESULT indicating success or failure
2130//
2131// Notes:
2132// Since we cannot intercept an exception at an internal frame,
2133// pFrame should not be an ICorDebugInternalFrame.
2134//
2135
2136HRESULT CordbThread::InterceptCurrentException(ICorDebugFrame * pFrame)
2137{
2138 PUBLIC_API_ENTRY(this);
2139 FAIL_IF_NEUTERED(this);
2140 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
2141
2142#if defined(FEATURE_DBGIPC_TRANSPORT_DI)
2143 // Continuable exceptions are not implemented on Unix-like platforms.
2144 return E_NOTIMPL;
2145
2146#else // !FEATURE_DBGIPC_TRANSPORT_DI
2147 HRESULT hr = S_OK;
2148 EX_TRY
2149 {
2150 DebuggerIPCEvent event;
2151
2152 if (pFrame == NULL)
2153 {
2154 ThrowHR(E_INVALIDARG);
2155 }
2156
2157 //
2158 // Verify we were passed a real stack frame, and not an internal
2159 // CLR mocked up one.
2160 //
2161 {
2162 RSExtSmartPtr<ICorDebugInternalFrame> pInternalFrame;
2163 hr = pFrame->QueryInterface(IID_ICorDebugInternalFrame, (void **)&pInternalFrame);
2164
2165 if (!FAILED(hr))
2166 {
2167 ThrowHR(E_INVALIDARG);
2168 }
2169 }
2170
2171
2172 //
2173 // If the thread is detached, then there should be no frames on its stack.
2174 //
2175 hr = EnsureThreadIsAlive();
2176
2177 if (SUCCEEDED(hr))
2178 {
2179 //
2180 // Refresh the stack frames for this thread and verify pFrame is on it.
2181 //
2182
2183 RefreshStack();
2184
2185 //
2186 // Now check if the frame actually lives on the stack of the current thread.
2187 //
2188
2189 // "Cast" the ICDFrame pointer to a CordbFrame pointer.
2190 CordbFrame * pRealFrame = CordbFrame::GetCordbFrameFromInterface(pFrame);
2191 if (!OwnsFrame(pRealFrame))
2192 {
2193 ThrowHR(E_INVALIDARG);
2194 }
2195
2196 //
2197 // pFrame is on the stack - good. Now tell the LS to intercept at that frame.
2198 //
2199
2200 GetProcess()->InitIPCEvent(&event, DB_IPCE_INTERCEPT_EXCEPTION, true, VMPTR_AppDomain::NullPtr());
2201
2202 event.InterceptException.vmThreadToken = m_vmThreadToken;
2203 event.InterceptException.frameToken = pRealFrame->GetFramePointer();
2204
2205 hr = GetProcess()->m_cordb->SendIPCEvent(GetProcess(), &event, sizeof(DebuggerIPCEvent));
2206
2207 //
2208 // Stop now if we can't even send the event.
2209 //
2210 if (!SUCCEEDED(hr))
2211 {
2212 ThrowHR(hr);
2213 }
2214
2215 _ASSERTE(event.type == DB_IPCE_INTERCEPT_EXCEPTION_RESULT);
2216
2217 hr = event.hr;
2218 // Since we are going to exit anyway, we don't need to throw here.
2219 }
2220 }
2221 EX_CATCH_HRESULT(hr);
2222 return hr;
2223#endif // FEATURE_DBGIPC_TRANSPORT_DI
2224}
2225
2226//---------------------------------------------------------------------------------------
2227//
2228// Return S_OK if there is a current exception and it is unhandled, otherwise
2229// return S_FALSE
2230//
2231HRESULT CordbThread::HasUnhandledException()
2232{
2233 FAIL_IF_NEUTERED(this);
2234
2235 HRESULT hr = S_FALSE;
2236 PUBLIC_REENTRANT_API_BEGIN(this)
2237 {
2238 IDacDbiInterface * pDAC = GetProcess()->GetDAC();
2239 if(pDAC->HasUnhandledException(m_vmThreadToken))
2240 {
2241 hr = S_OK;
2242 }
2243 }
2244 PUBLIC_REENTRANT_API_END(hr);
2245
2246 return hr;
2247}
2248
2249//---------------------------------------------------------------------------------------
2250//
2251// Create a stackwalker on the current thread. Initially, the stackwalker is stopped at the
2252// managed filter CONTEXT if there is one. Otherwise it is stopped at the leaf CONTEXT.
2253//
2254// Arguments:
2255// ppStackWalk - out parameter; return the new stackwalker
2256//
2257// Return Value:
2258// Return S_OK on succcess.
2259// Return E_FAIL on error.
2260//
2261// Notes:
2262// The filter CONTEXT will be removed in V3.0.
2263//
2264
2265HRESULT CordbThread::CreateStackWalk(ICorDebugStackWalk ** ppStackWalk)
2266{
2267 PUBLIC_REENTRANT_API_ENTRY(this);
2268 FAIL_IF_NEUTERED(this);
2269 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
2270
2271 VALIDATE_POINTER_TO_OBJECT(ppStackWalk, ICorDebugStackWalk **);
2272
2273 HRESULT hr = S_OK;
2274
2275 EX_TRY
2276 {
2277 RSLockHolder lockHolder(GetProcess()->GetProcessLock());
2278 hr = EnsureThreadIsAlive();
2279
2280 if (SUCCEEDED(hr))
2281 {
2282 RSInitHolder<CordbStackWalk> pSW(new CordbStackWalk(this));
2283 pSW->Init();
2284 pSW.TransferOwnershipExternal(ppStackWalk);
2285 }
2286 }
2287 EX_CATCH_HRESULT(hr);
2288
2289 return hr;
2290}
2291
2292
2293//---------------------------------------------------------------------------------------
2294//
2295// This is a callback function used to enumerate the internal frames on a thread.
2296// Each time this callback is invoked, we'll create a new CordbInternalFrame and store it
2297// in an array. See code:DacDbiInterfaceImpl::EnumerateInternalFrames for more information.
2298//
2299// Arguments:
2300// pFrameData - contains information about the current internal frame in the enumeration
2301// pUserData - This is a GetActiveInternalFramesData.
2302// It contains an array of internl frames to be filled.
2303//
2304
2305// static
2306void CordbThread::GetActiveInternalFramesCallback(const DebuggerIPCE_STRData * pFrameData,
2307 void * pUserData)
2308{
2309 // Retrieve the CordbThread.
2310 GetActiveInternalFramesData * pCallbackData = reinterpret_cast<GetActiveInternalFramesData *>(pUserData);
2311 CordbThread * pThis = pCallbackData->pThis;
2312 INTERNAL_DAC_CALLBACK(pThis->GetProcess());
2313
2314 // Make sure we are getting invoked for internal frames.
2315 _ASSERTE(pFrameData->eType == DebuggerIPCE_STRData::cStubFrame);
2316
2317 // Look up the CordbAppDomain.
2318 CordbAppDomain * pAppDomain = NULL;
2319 VMPTR_AppDomain vmCurrentAppDomain = pFrameData->vmCurrentAppDomainToken;
2320 if (!vmCurrentAppDomain.IsNull())
2321 {
2322 pAppDomain = pThis->GetProcess()->LookupOrCreateAppDomain(vmCurrentAppDomain);
2323 }
2324
2325 // Create a CordbInternalFrame.
2326 CordbInternalFrame * pInternalFrame = new CordbInternalFrame(pThis,
2327 pFrameData->fp,
2328 pAppDomain,
2329 pFrameData);
2330
2331 // Store the internal frame in the array and update the index to prepare for the next one.
2332 pCallbackData->pInternalFrames.Assign(pCallbackData->uIndex, pInternalFrame);
2333 pCallbackData->uIndex++;
2334}
2335
2336//---------------------------------------------------------------------------------------
2337//
2338// This function returns an array of ICDInternalFrame2. Each element represents an internal frame
2339// on the thread. If ppInternalFrames is NULL or cInternalFrames is 0, then we just return
2340// the number of internal frames on the thread.
2341//
2342// Arguments:
2343// cInternalFrames - the number of elements in ppInternalFrames
2344// pcInternalFrames - out parameter; return the number of internal frames on the thread
2345// ppInternalFrames - a buffer to store the array of internal frames
2346//
2347// Return Value:
2348// S_OK on success.
2349// E_INVALIDARG if
2350// - ppInternalFrames is NULL but cInternalFrames is not 0
2351// - pcInternalFrames is NULL
2352// - cInternalFrames is smaller than the number of internal frames actually on the thread
2353//
2354
2355HRESULT CordbThread::GetActiveInternalFrames(ULONG32 cInternalFrames,
2356 ULONG32 * pcInternalFrames,
2357 ICorDebugInternalFrame2 * ppInternalFrames[])
2358{
2359 HRESULT hr = S_OK;
2360 PUBLIC_REENTRANT_API_BEGIN(this);
2361 {
2362 if ( ((cInternalFrames != 0) && (ppInternalFrames == NULL)) ||
2363 (pcInternalFrames == NULL) )
2364 {
2365 ThrowHR(E_INVALIDARG);
2366 }
2367
2368 *pcInternalFrames = 0;
2369
2370 IDacDbiInterface * pDAC = GetProcess()->GetDAC();
2371 ULONG32 cActiveInternalFrames = pDAC->GetCountOfInternalFrames(m_vmThreadToken);
2372
2373 // Set the count.
2374 *pcInternalFrames = cActiveInternalFrames;
2375
2376 // Don't need to do anything else if the user is only asking for the count.
2377 if ((cInternalFrames != 0) && (ppInternalFrames != NULL))
2378 {
2379 if (cInternalFrames < cActiveInternalFrames)
2380 {
2381 ThrowWin32(ERROR_INSUFFICIENT_BUFFER);
2382 }
2383 else
2384 {
2385 // initialize the callback data
2386 GetActiveInternalFramesData data;
2387 data.pThis = this;
2388 data.uIndex = 0;
2389 data.pInternalFrames.AllocOrThrow(cActiveInternalFrames);
2390 // We want to ensure it's automatically cleaned up in all cases
2391 // e.g. if we're debugging a MiniDumpNormal and we fail to
2392 // retrieve memory from the target. The exception will be
2393 // caught above this frame.
2394 data.pInternalFrames.EnableAutoClear();
2395
2396 pDAC->EnumerateInternalFrames(m_vmThreadToken,
2397 &CordbThread::GetActiveInternalFramesCallback,
2398 &data);
2399 _ASSERTE(cActiveInternalFrames == data.pInternalFrames.Length());
2400
2401 // Copy the internal frames we have accumulated in GetActiveInternalFramesData to the out
2402 // argument.
2403 for (unsigned int i = 0; i < data.pInternalFrames.Length(); i++)
2404 {
2405 RSInitHolder<CordbInternalFrame> pInternalFrame(data.pInternalFrames[i]);
2406 pInternalFrame.TransferOwnershipExternal(&(ppInternalFrames[i]));
2407 }
2408 }
2409 }
2410 }
2411 PUBLIC_REENTRANT_API_END(hr);
2412 return hr;
2413}
2414
2415
2416// ICorDebugThread4
2417
2418// -------------------------------------------------------------------------------
2419// Gets the current custom notification on this thread or NULL if no such object exists
2420// Arguments:
2421// output: ppNotificationObject - current CustomNotification object.
2422// if we aren't currently inside a CustomNotification callback, this will
2423// always return NULL.
2424// return value:
2425// S_OK on success
2426// S_FALSE if no object exists
2427// CORDBG_E_BAD_REFERENCE_VALUE if the reference is bad
2428HRESULT CordbThread::GetCurrentCustomDebuggerNotification(ICorDebugValue ** ppNotificationObject)
2429{
2430 HRESULT hr = S_OK;
2431 PUBLIC_API_NO_LOCK_BEGIN(this);
2432 {
2433 ATT_REQUIRE_STOPPED_MAY_FAIL_OR_THROW(GetProcess(), ThrowHR);
2434
2435 if (ppNotificationObject == NULL)
2436 {
2437 ThrowHR(E_INVALIDARG);
2438 }
2439
2440 *ppNotificationObject = NULL;
2441
2442 //
2443 // Go to the LS and retrieve any notification object.
2444 //
2445 IDacDbiInterface * pDAC = GetProcess()->GetDAC();
2446 VMPTR_OBJECTHANDLE vmObjHandle = pDAC->GetCurrentCustomDebuggerNotification(m_vmThreadToken);
2447
2448#if defined(_DEBUG)
2449 // Since we know a notification has occurred on this thread, our assumption about the
2450 // thread's current AppDomain should be correct
2451 VMPTR_AppDomain vmAppDomain = pDAC->GetCurrentAppDomain(m_vmThreadToken);
2452
2453 _ASSERTE(GetAppDomain()->GetADToken() == vmAppDomain);
2454#endif // _DEBUG
2455
2456 if (!vmObjHandle.IsNull())
2457 {
2458 ICorDebugReferenceValue * pRefValue = NULL;
2459 IfFailThrow(CordbReferenceValue::BuildFromGCHandle(GetAppDomain(), vmObjHandle, &pRefValue));
2460 *ppNotificationObject = pRefValue;
2461 }
2462 }
2463 PUBLIC_API_END(hr);
2464 return hr;
2465}
2466
2467/*
2468 *
2469 * SetRemapIP
2470 *
2471 * This routine communicate the EnC remap IP to the LS by writing it to process memory using
2472 * the pointer that was set in the thread. If the address is null, then we haven't seen
2473 * a RemapOpportunity call for this frame/function combo yet, so invalid to Remap the function.
2474 *
2475 * Parameters:
2476 * offset - the IL offset to set the IP to
2477 *
2478 * Return Value:
2479 * S_OK or CORDBG_E_NO_REMAP_BREAKPIONT.
2480 *
2481 */
2482HRESULT CordbThread::SetRemapIP(SIZE_T offset)
2483{
2484 _ASSERTE(GetProcess()->ThreadHoldsProcessLock());
2485
2486 // This is only set when we're prepared to do a remap
2487 if (! m_EnCRemapFunctionIP)
2488 {
2489 return CORDBG_E_NO_REMAP_BREAKPIONT;
2490 }
2491
2492 // Write the value of the remap offset into the left side
2493 HRESULT hr = GetProcess()->SafeWriteStruct(PTR_TO_CORDB_ADDRESS(m_EnCRemapFunctionIP), &offset);
2494
2495 // Prevent SetRemapIP from being called twice for the same RemapOpportunity
2496 // If we don't get any calls to RemapFunction, this member will be cleared in
2497 // code:CordbThread::MarkStackFramesDirty when Continue is called
2498 m_EnCRemapFunctionIP = NULL;
2499
2500 return hr;
2501}
2502
2503
2504//---------------------------------------------------------------------------------------
2505//
2506// This routine is the interface function for ICorDebugThread2::GetConnectionID.
2507//
2508// Arguments:
2509// pdwConnectionId - return connection id set on the thread. Can return INVALID_CONNECTION_ID
2510//
2511// Return Value:
2512// HRESULT indicating success or failure
2513//
2514HRESULT CordbThread::GetConnectionID(CONNID * pConnectionID)
2515{
2516 PUBLIC_API_ENTRY(this);
2517 FAIL_IF_NEUTERED(this);
2518 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
2519
2520 // now retrieve the connection id
2521 HRESULT hr = S_OK;
2522 EX_TRY
2523 {
2524 if (pConnectionID == NULL)
2525 {
2526 ThrowHR(E_INVALIDARG);
2527 }
2528
2529 IDacDbiInterface * pDAC = GetProcess()->GetDAC();
2530 *pConnectionID = pDAC->GetConnectionID(m_vmThreadToken);
2531
2532 if (*pConnectionID == INVALID_CONNECTION_ID)
2533 {
2534 hr = S_FALSE;
2535 }
2536 }
2537 EX_CATCH_HRESULT(hr);
2538
2539 return hr;
2540} // CordbThread::GetConnectionID
2541
2542//---------------------------------------------------------------------------------------
2543//
2544// This routine is the interface function for ICorDebugThread2::GetTaskID.
2545//
2546// Arguments:
2547// pTaskId - return task id set on the thread. Can return INVALID_TASK_ID
2548//
2549// Return Value:
2550// HRESULT indicating success or failure
2551//
2552HRESULT CordbThread::GetTaskID(TASKID * pTaskID)
2553{
2554 PUBLIC_API_ENTRY(this);
2555 FAIL_IF_NEUTERED(this);
2556 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
2557
2558 // now retrieve the task id
2559 HRESULT hr = S_OK;
2560 EX_TRY
2561 {
2562 if (pTaskID == NULL)
2563 {
2564 ThrowHR(E_INVALIDARG);
2565 }
2566
2567 *pTaskID = this->GetTaskID();
2568
2569 if (*pTaskID == INVALID_TASK_ID)
2570 {
2571 hr = S_FALSE;
2572 }
2573 }
2574 EX_CATCH_HRESULT(hr);
2575
2576 return hr;
2577} // CordbThread::GetTaskID
2578
2579//---------------------------------------------------------------------------------------
2580// Get the task ID for this thread
2581//
2582// return:
2583// task id set on the thread. Can return INVALID_TASK_ID
2584//
2585TASKID CordbThread::GetTaskID()
2586{
2587 IDacDbiInterface * pDAC = GetProcess()->GetDAC();
2588 return pDAC->GetTaskID(m_vmThreadToken);
2589}
2590
2591
2592
2593//---------------------------------------------------------------------------------------
2594//
2595// This routine is the interface function for ICorDebugThread2::GetVolatileOSThreadID.
2596//
2597// Arguments:
2598// pdwTid - return os thread id
2599//
2600// Return Value:
2601// HRESULT indicating success or failure
2602//
2603// Notes:
2604// Compare with code:CordbThread::GetID
2605HRESULT CordbThread::GetVolatileOSThreadID(DWORD * pdwTID)
2606{
2607 PUBLIC_API_ENTRY(this);
2608 FAIL_IF_NEUTERED(this);
2609 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
2610
2611 // now retrieve the OS thread ID
2612 HRESULT hr = S_OK;
2613 EX_TRY
2614 {
2615 if (pdwTID == NULL)
2616 {
2617 ThrowHR(E_INVALIDARG);
2618 }
2619
2620 IDacDbiInterface * pDAC = GetProcess()->GetDAC();
2621 *pdwTID = pDAC->TryGetVolatileOSThreadID(m_vmThreadToken);
2622
2623 if (*pdwTID == 0)
2624 {
2625 hr = S_FALSE; // Switched out
2626 }
2627 }
2628 EX_CATCH_HRESULT(hr);
2629
2630 return hr;
2631} // CordbThread::GetOSThreadID
2632
2633//---------------------------------------------------------------------------------------
2634// Get the thread's volatile OS ID. (this is fiber aware)
2635//
2636// Returns:
2637// Thread's current OS id. For fibers / "logical threads", This may change as a thread executes.
2638// Throws if the managed thread currently is not mapped to an OS thread (ie, not scheduled)
2639//
2640DWORD CordbThread::GetVolatileOSThreadID()
2641{
2642 IDacDbiInterface * pDAC = GetProcess()->GetDAC();
2643 DWORD dwThreadID = pDAC->TryGetVolatileOSThreadID(m_vmThreadToken);
2644
2645 if (dwThreadID == 0)
2646 {
2647 ThrowHR(CORDBG_E_THREAD_NOT_SCHEDULED);
2648 }
2649 return dwThreadID;
2650}
2651
2652// ----------------------------------------------------------------------------
2653// CordbThread::ClearStackFrameCache
2654//
2655// Description:
2656// Clear the cache of stack frames maintained by the CordbThread.
2657//
2658// Notes:
2659// We are doing an InternalRelease() here to match the InternalAddRef() in code:CordbThread::RefreshStack.
2660//
2661
2662void CordbThread::ClearStackFrameCache()
2663{
2664 _ASSERTE(GetProcess()->ThreadHoldsProcessLock());
2665
2666 for (int i = 0; i < m_stackFrames.Count(); i++)
2667 {
2668 (*m_stackFrames.Get(i))->Neuter();
2669 (*m_stackFrames.Get(i))->InternalRelease();
2670 }
2671 m_stackFrames.Clear();
2672}
2673
2674// ----------------------------------------------------------------------------
2675// EnumerateBlockingObjectsCallback
2676//
2677// Description:
2678// A small helper used by CordbThread::GetBlockingObjects. This callback adds the enumerated items
2679// to a list
2680//
2681// Arguments:
2682// blockingObject - the object to add to the list
2683// pUserData - the list to add it to
2684
2685VOID EnumerateBlockingObjectsCallback(DacBlockingObject blockingObject, CALLBACK_DATA pUserData)
2686{
2687 CQuickArrayList<DacBlockingObject>* pDacBlockingObjs = (CQuickArrayList<DacBlockingObject>*)pUserData;
2688 pDacBlockingObjs->Push(blockingObject);
2689}
2690
2691// ----------------------------------------------------------------------------
2692// CordbThread::GetBlockingObjects
2693//
2694// Description:
2695// Returns a list of objects that a thread is blocking on by using Monitor.Enter and
2696// Monitor.Wait
2697//
2698// Arguments:
2699// ppBlockingObjectEnum - on return this is an enumerator for the list of blocking objects
2700//
2701// Return:
2702// S_OK on success or an appropriate failing HRESULT
2703
2704HRESULT CordbThread::GetBlockingObjects(ICorDebugBlockingObjectEnum **ppBlockingObjectEnum)
2705{
2706 PUBLIC_API_ENTRY(this);
2707 FAIL_IF_NEUTERED(this);
2708 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
2709 VALIDATE_POINTER_TO_OBJECT(ppBlockingObjectEnum, ICorDebugBlockingObjectEnum **);
2710
2711 HRESULT hr = S_OK;
2712 CorDebugBlockingObject* blockingObjs = NULL;
2713 EX_TRY
2714 {
2715 CQuickArrayList<DacBlockingObject> dacBlockingObjects;
2716 IDacDbiInterface* pDac = GetProcess()->GetDAC();
2717 pDac->EnumerateBlockingObjects(m_vmThreadToken,
2718 (IDacDbiInterface::FP_BLOCKINGOBJECT_ENUMERATION_CALLBACK) EnumerateBlockingObjectsCallback,
2719 (CALLBACK_DATA) &dacBlockingObjects);
2720 blockingObjs = new CorDebugBlockingObject[dacBlockingObjects.Size()];
2721 for(SIZE_T i = 0 ; i < dacBlockingObjects.Size(); i++)
2722 {
2723 // ICorDebug API needs to flip the direction of the list from the way DAC stores it
2724 SIZE_T dacObjIndex = dacBlockingObjects.Size()-i-1;
2725 switch(dacBlockingObjects[dacObjIndex].blockingReason)
2726 {
2727 case DacBlockReason_MonitorCriticalSection:
2728 blockingObjs[i].blockingReason = BLOCKING_MONITOR_CRITICAL_SECTION;
2729 break;
2730 case DacBlockReason_MonitorEvent:
2731 blockingObjs[i].blockingReason = BLOCKING_MONITOR_EVENT;
2732 break;
2733 default:
2734 _ASSERTE(!"Should not get here");
2735 ThrowHR(E_FAIL);
2736 break;
2737 }
2738 blockingObjs[i].dwTimeout = dacBlockingObjects[dacObjIndex].dwTimeout;
2739 CordbAppDomain* pAppDomain;
2740 {
2741 RSLockHolder holder(GetProcess()->GetProcessLock());
2742 pAppDomain = GetProcess()->LookupOrCreateAppDomain(dacBlockingObjects[dacObjIndex].vmAppDomain);
2743 }
2744 blockingObjs[i].pBlockingObject = CordbValue::CreateHeapValue(pAppDomain,
2745 dacBlockingObjects[dacObjIndex].vmBlockingObject);
2746 }
2747
2748 CordbBlockingObjectEnumerator* objEnum = new CordbBlockingObjectEnumerator(GetProcess(),
2749 blockingObjs,
2750 (DWORD)dacBlockingObjects.Size());
2751 GetProcess()->GetContinueNeuterList()->Add(GetProcess(), objEnum);
2752 hr = objEnum->QueryInterface(__uuidof(ICorDebugBlockingObjectEnum), (void**)ppBlockingObjectEnum);
2753 _ASSERTE(SUCCEEDED(hr));
2754 }
2755 EX_CATCH_HRESULT(hr);
2756 delete [] blockingObjs;
2757 return hr;
2758}
2759
2760// ----------------------------------------------------------------------------
2761// CordbThread::SetCreateEventQueued
2762void CordbThread::SetCreateEventQueued()
2763{
2764 m_fCreationEventQueued = true;
2765}
2766
2767// ----------------------------------------------------------------------------
2768// CordbThread::CreateEventWasQueued
2769bool CordbThread::CreateEventWasQueued()
2770{
2771 return m_fCreationEventQueued;
2772}
2773
2774
2775#ifdef FEATURE_INTEROP_DEBUGGING
2776/* ------------------------------------------------------------------------- *
2777 * Unmanaged Thread classes
2778 * ------------------------------------------------------------------------- */
2779
2780CordbUnmanagedThread::CordbUnmanagedThread(CordbProcess *pProcess, DWORD dwThreadId, HANDLE hThread, void *lpThreadLocalBase)
2781 : CordbBase(pProcess, dwThreadId, enumCordbUnmanagedThread),
2782 m_handle(hThread),
2783 m_threadLocalBase(lpThreadLocalBase),
2784 m_pTLSArray(NULL),
2785 m_pTLSExtendedArray(NULL),
2786 m_state(CUTS_None),
2787 m_originalHandler(NULL),
2788#ifdef DBG_TARGET_X86
2789 m_pSavedLeafSeh(NULL),
2790#endif
2791 m_stackBase(0),
2792 m_stackLimit(0),
2793 m_continueCountCached(0)
2794{
2795 m_pLeftSideContext.Set(NULL);
2796
2797 IBEvent()->m_state = CUES_None;
2798 IBEvent()->m_next = NULL;
2799 IBEvent()->m_owner = this;
2800
2801 IBEvent2()->m_state = CUES_None;
2802 IBEvent2()->m_next = NULL;
2803 IBEvent2()->m_owner = this;
2804
2805 OOBEvent()->m_state = CUES_None;
2806 OOBEvent()->m_next = NULL;
2807 OOBEvent()->m_owner = this;
2808
2809 m_pPatchSkipAddress = NULL;
2810
2811 this->GetStackRange(NULL, NULL);
2812}
2813
2814CordbUnmanagedThread::~CordbUnmanagedThread()
2815{
2816 // CordbUnmanagedThread objects will:
2817 // - never send IPC events.
2818 // - never be exposed to the public. (we assert external-ref is always == 0)
2819 // - always manipulated on W32ET (where we can't do IPC stuff)
2820
2821 UnsafeNeuterDeadObject();
2822
2823 _ASSERTE(this->IsNeutered());
2824
2825 // by the time the thread is deleted, it shouldn't have any outstanding debug events.
2826
2827 // Actually, the thread could get deleted while we have an outstanding IB debug event. We could get the IB event, hijack that thread,
2828 // and then since the process is continued, something could go off and kill the hijacked thread.
2829 // If the event is still in the process's queued list, and it still refers back to a thread, then we'll AV when we try to access the event
2830 // (or continue it).
2831 CONSISTENCY_CHECK_MSGF(!HasIBEvent(), ("Deleting thread w/ outstanding IB event:this=%p,event-code=%d\n", this, IBEvent()->m_currentDebugEvent.dwDebugEventCode));
2832
2833 CONSISTENCY_CHECK_MSGF(!HasOOBEvent(), ("Deleting thread w/ outstanding OOB event:this=%p,event-code=%d\n", this, OOBEvent()->m_currentDebugEvent.dwDebugEventCode));
2834}
2835
2836#define WINNT_TLS_OFFSET_X86 0xe10 // TLS[0] at fs:[WINNT_TLS_OFFSET]
2837#define WINNT_TLS_OFFSET_AMD64 0x1480
2838#define WINNT_TLS_OFFSET_ARM 0xe10
2839#define WINNT_TLS_OFFSET_ARM64 0x1480
2840#define WINNT5_TLSEXPANSIONPTR_OFFSET_X86 0xf94 // TLS[64] at [fs:[WINNT5_TLSEXPANSIONPTR_OFFSET]]
2841#define WINNT5_TLSEXPANSIONPTR_OFFSET_AMD64 0x1780
2842#define WINNT5_TLSEXPANSIONPTR_OFFSET_ARM 0xf94
2843#define WINNT5_TLSEXPANSIONPTR_OFFSET_ARM64 0x1780
2844
2845HRESULT CordbUnmanagedThread::LoadTLSArrayPtr(void)
2846{
2847 FAIL_IF_NEUTERED(this);
2848
2849 HRESULT hr = S_OK;
2850 _ASSERTE(GetProcess()->ThreadHoldsProcessLock());
2851
2852
2853 // Just simple math on NT with a small tls index.
2854 // The TLS slots for 0-63 are embedded in the TIB.
2855#if defined(DBG_TARGET_X86)
2856 m_pTLSArray = (BYTE*) m_threadLocalBase + WINNT_TLS_OFFSET_X86;
2857#elif defined(DBG_TARGET_AMD64)
2858 m_pTLSArray = (BYTE*) m_threadLocalBase + WINNT_TLS_OFFSET_AMD64;
2859#elif defined(DBG_TARGET_ARM)
2860 m_pTLSArray = (BYTE*) m_threadLocalBase + WINNT_TLS_OFFSET_ARM;
2861#elif defined(DBG_TARGET_ARM64)
2862 m_pTLSArray = (BYTE*) m_threadLocalBase + WINNT_TLS_OFFSET_ARM64;
2863#else
2864 PORTABILITY_ASSERT("Implement OOP TLS on your platform");
2865#endif
2866
2867 // Extended slot is lazily initialized, so check every time.
2868 if (m_pTLSExtendedArray == NULL)
2869 {
2870 // On NT 5 you can have TLS index's greater than 63, so we
2871 // have to grab the ptr to the TLS expansion array first,
2872 // then use that as the base to index off of. This will
2873 // never move once we find it for a given thread, so we
2874 // cache it here so we don't always have to perform two
2875 // ReadProcessMemory's.
2876#if defined(DBG_TARGET_X86)
2877 void *ppTLSArray = (BYTE*) m_threadLocalBase + WINNT5_TLSEXPANSIONPTR_OFFSET_X86;
2878#elif defined(DBG_TARGET_AMD64)
2879 void *ppTLSArray = (BYTE*) m_threadLocalBase + WINNT5_TLSEXPANSIONPTR_OFFSET_AMD64;
2880#elif defined(DBG_TARGET_ARM)
2881 void *ppTLSArray = (BYTE*) m_threadLocalBase + WINNT5_TLSEXPANSIONPTR_OFFSET_ARM;
2882#elif defined(DBG_TARGET_ARM64)
2883 void *ppTLSArray = (BYTE*) m_threadLocalBase + WINNT5_TLSEXPANSIONPTR_OFFSET_ARM64;
2884#else
2885 PORTABILITY_ASSERT("Implement OOP TLS on your platform");
2886#endif
2887
2888 hr = GetProcess()->SafeReadStruct(PTR_TO_CORDB_ADDRESS(ppTLSArray), &m_pTLSExtendedArray);
2889 }
2890
2891
2892 return hr;
2893}
2894
2895/*
2896VOID CordbUnmanagedThread::VerifyFSChain()
2897{
2898#if defined(DBG_TARGET_X86)
2899 DT_CONTEXT temp;
2900 temp.ContextFlags = DT_CONTEXT_FULL;
2901 DbiGetThreadContext(m_handle, &temp);
2902 LOG((LF_CORDB, LL_INFO1000, "CUT::VFSC: 0x%x fs=0x%x TIB=0x%x\n",
2903 m_id, temp.SegFs, m_threadLocalBase));
2904 REMOTE_PTR pExceptionRegRecordPtr;
2905 HRESULT hr = GetProcess()->SafeReadStruct(PTR_TO_CORDB_ADDRESS(m_threadLocalBase), &pExceptionRegRecordPtr);
2906 if(FAILED(hr))
2907 {
2908 LOG((LF_CORDB, LL_INFO1000, "CUT::VFSC: ERROR 0x%x failed to read fs:0 value: computed addr=0x%p err=%x\n",
2909 m_id, m_threadLocalBase, hr));
2910 _ASSERTE(FALSE);
2911 return;
2912 }
2913 while(pExceptionRegRecordPtr != EXCEPTION_CHAIN_END && pExceptionRegRecordPtr != NULL)
2914 {
2915 REMOTE_PTR prev;
2916 REMOTE_PTR handler;
2917 hr = GetProcess()->SafeReadStruct(PTR_TO_CORDB_ADDRESS(pExceptionRegRecordPtr), &prev);
2918 if(FAILED(hr))
2919 {
2920 LOG((LF_CORDB, LL_INFO1000, "CUT::VFSC: ERROR 0x%x failed to read prev value: computed addr=0x%p err=%x\n",
2921 m_id, pExceptionRegRecordPtr, hr));
2922 return;
2923 }
2924 hr = GetProcess()->SafeReadStruct(PTR_TO_CORDB_ADDRESS( (VOID*)((DWORD)pExceptionRegRecordPtr+4) ), &handler);
2925 if(FAILED(hr))
2926 {
2927 LOG((LF_CORDB, LL_INFO1000, "CUT::VFSC: ERROR 0x%x failed to read handler value: computed addr=0x%p err=%x\n",
2928 m_id, (DWORD)pExceptionRegRecordPtr+4, hr));
2929 return;
2930 }
2931 LOG((LF_CORDB, LL_INFO1000, "CUT::VFSC: OK 0x%x record=0x%x prev=0x%x handler=0x%x\n",
2932 m_id, pExceptionRegRecordPtr, prev, handler));
2933 if(handler == NULL)
2934 {
2935 LOG((LF_CORDB, LL_INFO1000, "CUT::VFSC: ERROR 0x%x NULL handler found\n", m_id));
2936 _ASSERTE(FALSE);
2937 return;
2938 }
2939 if(prev == NULL)
2940 {
2941 LOG((LF_CORDB, LL_INFO1000, "CUT::VFSC: ERROR 0x%x NULL prev found\n", m_id));
2942 _ASSERTE(FALSE);
2943 return;
2944 }
2945 if(prev == pExceptionRegRecordPtr)
2946 {
2947 LOG((LF_CORDB, LL_INFO1000, "CUT::VFSC: ERROR 0x%x cyclic prev found\n", m_id));
2948 _ASSERTE(FALSE);
2949 return;
2950 }
2951 pExceptionRegRecordPtr = prev;
2952 }
2953
2954 LOG((LF_CORDB, LL_INFO1000, "CUT::VFSC: OK 0x%x\n", m_id));
2955#endif
2956 return;
2957}*/
2958
2959#ifdef DBG_TARGET_X86
2960HRESULT CordbUnmanagedThread::SaveCurrentLeafSeh()
2961{
2962 _ASSERTE(m_pSavedLeafSeh == NULL);
2963 REMOTE_PTR pExceptionRegRecordPtr;
2964 HRESULT hr = GetProcess()->SafeReadStruct(PTR_TO_CORDB_ADDRESS(m_threadLocalBase), &pExceptionRegRecordPtr);
2965 if(FAILED(hr))
2966 {
2967 LOG((LF_CORDB, LL_INFO1000, "CUT::SCLS: failed to read fs:0 value: computed addr=0x%p err=%x\n", m_threadLocalBase, hr));
2968 return hr;
2969 }
2970 m_pSavedLeafSeh = pExceptionRegRecordPtr;
2971 return S_OK;
2972}
2973
2974HRESULT CordbUnmanagedThread::RestoreLeafSeh()
2975{
2976 _ASSERTE(m_pSavedLeafSeh != NULL);
2977 HRESULT hr = GetProcess()->SafeWriteStruct(PTR_TO_CORDB_ADDRESS(m_threadLocalBase), &m_pSavedLeafSeh);
2978 if(FAILED(hr))
2979 {
2980 LOG((LF_CORDB, LL_INFO1000, "CUT::RLS: failed to write fs:0 value: computed addr=0x%p err=%x\n", m_threadLocalBase, hr));
2981 return hr;
2982 }
2983 m_pSavedLeafSeh = NULL;
2984 return S_OK;
2985}
2986#endif
2987
2988// Read the contents from the LS's Predefined TLS block.
2989// This is an auxillary TLS storage array-of-void*, indexed off the TLS.
2990// pRead is optional. This makes sense when '0' is a valid default value.
2991// 1) On success (block exists in LS, we can read it),
2992// return value of data in the slot, *pRead = true
2993// 2) On failure to read block (block doens't exist yet, any other failure)
2994// return value == 0 (assumed default, *pRead = false
2995REMOTE_PTR CordbUnmanagedThread::GetPreDefTlsSlot(SIZE_T slot, bool * pRead)
2996{
2997 REMOTE_PTR pBlock = (REMOTE_PTR) GetEETlsDataBlock();
2998
2999 REMOTE_PTR data = 0;
3000
3001 // We don't have a maximum size, but we know it's less than ~200. This assert
3002 // will catch if we're just passsing Garbage.
3003 _ASSERTE(slot < 200);
3004
3005 bool dummy;
3006 if (pRead == NULL)
3007 {
3008 pRead = &dummy;
3009 }
3010
3011 if (pBlock != NULL)
3012 {
3013 REMOTE_PTR p = ((BYTE*) pBlock) + slot * sizeof(data);
3014
3015 // Now read the "special" status out of the PreDef block.
3016 HRESULT hr = GetProcess()->SafeReadStruct(PTR_TO_CORDB_ADDRESS(p), &data);
3017
3018 // The predef block should be valid at this point, so the ReadProcessMemory ought to work.
3019 SIMPLIFYING_ASSUMPTION_SUCCEEDED(hr);
3020
3021 if (SUCCEEDED(hr))
3022 {
3023 *pRead = true;
3024 return data;
3025 }
3026 }
3027
3028 *pRead = false;
3029 return 0;
3030}
3031
3032// Read the contents from a LS threads's TLS slot.
3033HRESULT CordbUnmanagedThread::GetTlsSlot(DWORD slot, REMOTE_PTR * pValue)
3034{
3035 // Compute the address of the necessary TLS value.
3036 HRESULT hr = LoadTLSArrayPtr();
3037 if (FAILED(hr))
3038 {
3039 return hr;
3040 }
3041
3042 void * pBase = NULL;
3043 SIZE_T slotAdjusted = slot;
3044
3045 if (slot < TLS_MINIMUM_AVAILABLE)
3046 {
3047 pBase = m_pTLSArray;
3048 }
3049 else if (slot < TLS_MINIMUM_AVAILABLE + TLS_EXPANSION_SLOTS)
3050 {
3051 pBase = m_pTLSExtendedArray;
3052 slotAdjusted -= TLS_MINIMUM_AVAILABLE;
3053
3054 // Expansion slot is lazily allocated. If we're trying to read from it, but hasn't been allocated,
3055 // then the TLS slot is still the default value, which is 0 (NULL).
3056 if (pBase == NULL)
3057 {
3058 *pValue = NULL;
3059 return S_OK;
3060 }
3061 }
3062 else
3063 {
3064 // Slot is out of range. Shouldn't happen unless debuggee is corrupted.
3065 _ASSERTE(!"Invalid TLS slot");
3066 return E_UNEXPECTED;
3067 }
3068
3069 void *pEEThreadTLS = (BYTE*)pBase + (slotAdjusted * sizeof(void*));
3070
3071 // Read the thread's TLS value.
3072 hr = GetProcess()->SafeReadStruct(PTR_TO_CORDB_ADDRESS(pEEThreadTLS), pValue);
3073 if (FAILED(hr))
3074 {
3075 LOG((LF_CORDB, LL_INFO1000, "CUT::GTS: failed to read TLS value: computed addr=0x%p index=%d, err=%x\n",
3076 pEEThreadTLS, slot, hr));
3077 return hr;
3078 }
3079
3080 LOG((LF_CORDB, LL_INFO1000000, "CUT::GTS: EE Thread TLS value is 0x%p for thread 0x%x, slot 0x%x\n", *pValue, m_id, slot));
3081 return S_OK;
3082}
3083
3084// This does a WriteProcessMemory to write to the debuggee's TLS slot
3085//
3086// Notes:
3087// This is very brittle because the OS can lazily allocates storage for TLS slots.
3088// In order to gaurantee the storage is available, it must have been written to by the debuggee.
3089// For managed threads, that's easy because the Thread* is already written to the slot.
3090// But for pure native threads where GetThread() == NULL, the storage may not yet be allocated.
3091//
3092// The saving grace is that the debuggee's hijack filters will force the TLS to be allocated before it
3093// sends a flare.
3094//
3095// Therefore, this function can only be called:
3096// 1) on a managed thread
3097// 2) on a native thread after that thread has been hijacked and sent a flare.
3098//
3099// This is brittle reasoning, but so is the rest of interop-debugging.
3100//
3101HRESULT CordbUnmanagedThread::SetTlsSlot(DWORD slot, REMOTE_PTR value)
3102{
3103 FAIL_IF_NEUTERED(this);
3104
3105 // Compute the address of the necessary TLS value.
3106 HRESULT hr = LoadTLSArrayPtr();
3107 if (FAILED(hr))
3108 {
3109 return hr;
3110 }
3111
3112 void * pBase = NULL;
3113 SIZE_T slotAdjusted = slot;
3114 if (slot < TLS_MINIMUM_AVAILABLE)
3115 {
3116 pBase = m_pTLSArray;
3117 }
3118 else if (slot < TLS_MINIMUM_AVAILABLE + TLS_EXPANSION_SLOTS)
3119 {
3120 pBase = m_pTLSExtendedArray;
3121 slotAdjusted -= TLS_MINIMUM_AVAILABLE;
3122
3123 // Expansion slot is lazily allocated. If we're trying to read from it, but hasn't been allocated,
3124 // then the TLS slot is still the default value, which is 0.
3125 if (pBase == NULL)
3126 {
3127 // See reasoning in header for why this should succeed.
3128 _ASSERTE(!"Can't set to expansion slots because they haven't been allocated");
3129 return E_FAIL;
3130 }
3131 }
3132 else
3133 {
3134 // Slot is out of range. Shouldn't happen unless debuggee is corrupted.
3135 _ASSERTE(!"Invalid TLS slot");
3136 return E_INVALIDARG;
3137 }
3138
3139 void *pEEThreadTLS = (BYTE*)pBase + (slotAdjusted * sizeof(void*));
3140
3141 // Write the thread's TLS value.
3142 hr = GetProcess()->SafeWriteStruct(PTR_TO_CORDB_ADDRESS(pEEThreadTLS), &value);
3143
3144 if (FAILED(hr))
3145 {
3146 LOG((LF_CORDB, LL_INFO1000, "CUT::SEETV: failed to set TLS value: computed addr=0x%p slot=%d, err=%x\n", pEEThreadTLS, slot, hr));
3147 return hr;
3148 }
3149
3150 LOG((LF_CORDB, LL_INFO1000000, "CUT::SEETV: EE Thread TLS value is now 0x%p for 0x%x\n", value, m_id));
3151 return S_OK;
3152}
3153
3154// gets the value of gCurrentThreadInfo.m_pThread
3155DWORD_PTR CordbUnmanagedThread::GetEEThreadValue()
3156{
3157 DWORD_PTR ret = NULL;
3158
3159 REMOTE_PTR tlsDataAddress;
3160 HRESULT hr = GetClrModuleTlsDataAddress(&tlsDataAddress);
3161 if (FAILED(hr))
3162 {
3163 LOG((LF_CORDB, LL_INFO1000, "CUT::GEETV: GetClrModuleTlsDataAddress FAILED %x for 0x%x\n", hr, m_id));
3164 return NULL;
3165 }
3166
3167 // Read the thread's TLS value.
3168 REMOTE_PTR EEThreadAddr = (BYTE*)tlsDataAddress + OFFSETOF__TLS__tls_CurrentThread;
3169 hr = GetProcess()->SafeReadStruct(PTR_TO_CORDB_ADDRESS(EEThreadAddr), &ret);
3170 if (FAILED(hr))
3171 {
3172 LOG((LF_CORDB, LL_INFO1000, "CUT::GEETV: failed to get TLS value: computed addr=0x%p index=%d, err=%x\n",
3173 EEThreadAddr, GetProcess()->m_runtimeOffsets.m_TLSIndex, hr));
3174 return NULL;
3175 }
3176
3177 LOG((LF_CORDB, LL_INFO1000000, "CUT::GEETV: EE Thread TLS value is 0x%p for 0x%x\n", ret, m_id));
3178 return ret;
3179}
3180
3181// returns the remote address of gCurrentThreadInfo
3182HRESULT CordbUnmanagedThread::GetClrModuleTlsDataAddress(REMOTE_PTR* pAddress)
3183{
3184 *pAddress = NULL;
3185
3186 REMOTE_PTR tlsArrayAddr;
3187 HRESULT hr = GetProcess()->SafeReadStruct(PTR_TO_CORDB_ADDRESS((BYTE*)m_threadLocalBase + WINNT_OFFSETOF__TEB__ThreadLocalStoragePointer), &tlsArrayAddr);
3188 if (FAILED(hr))
3189 {
3190 return hr;
3191 }
3192
3193 // This is the special break-in thread case: TEB.ThreadLocalStoragePointer == NULL
3194 if (tlsArrayAddr == NULL)
3195 {
3196 return E_FAIL;
3197 }
3198
3199 DWORD slot = (DWORD)(GetProcess()->m_runtimeOffsets.m_TLSIndex);
3200
3201 REMOTE_PTR clrModuleTlsDataAddr;
3202 hr = GetProcess()->SafeReadStruct(PTR_TO_CORDB_ADDRESS((BYTE*)tlsArrayAddr + (slot & 0xFFFF) * sizeof(void*)), &clrModuleTlsDataAddr);
3203 if (FAILED(hr))
3204 {
3205 return hr;
3206 }
3207
3208 if (clrModuleTlsDataAddr == NULL)
3209 {
3210 _ASSERTE(!"No clr module data present at _tls_index for this thread");
3211 return E_FAIL;
3212 }
3213
3214 *pAddress = (BYTE*) clrModuleTlsDataAddr + ((slot & 0x7FFF0000) >> 16);
3215 return S_OK;
3216}
3217
3218// Gets the value of gCurrentThreadInfo.m_EETlsData
3219REMOTE_PTR CordbUnmanagedThread::GetEETlsDataBlock()
3220{
3221 REMOTE_PTR ret;
3222
3223 REMOTE_PTR tlsDataAddress;
3224 HRESULT hr = GetClrModuleTlsDataAddress(&tlsDataAddress);
3225 if (FAILED(hr))
3226 {
3227 LOG((LF_CORDB, LL_INFO1000, "CUT::GEETDB: GetClrModuleTlsDataAddress FAILED %x for 0x%x\n", hr, m_id));
3228 return NULL;
3229 }
3230
3231 REMOTE_PTR blockAddr = (BYTE*)tlsDataAddress + OFFSETOF__TLS__tls_EETlsData;
3232 hr = GetProcess()->SafeReadStruct(PTR_TO_CORDB_ADDRESS(blockAddr), &ret);
3233 if (FAILED(hr))
3234 {
3235 LOG((LF_CORDB, LL_INFO1000, "CUT::GEETDB: failed to read EETlsData address: computed addr=0x%p offset=%d, err=%x\n",
3236 blockAddr, OFFSETOF__TLS__tls_EETlsData, hr));
3237 return NULL;
3238 }
3239
3240 LOG((LF_CORDB, LL_INFO1000000, "CUT::GEETDB: EETlsData address value is 0x%p for 0x%x\n", ret, m_id));
3241 return ret;
3242}
3243
3244/*
3245 * GetEEDebuggerWord
3246 *
3247 * This routine returns the value read from the thread
3248 *
3249 * Parameters:
3250 * pValue - Location to store value.
3251 *
3252 * Returns:
3253 * E_INVALIDARG, E_FAIL, S_OK
3254 */
3255HRESULT CordbUnmanagedThread::GetEEDebuggerWord(REMOTE_PTR *pValue)
3256{
3257 LOG((LF_CORDB, LL_INFO1000, "CUT::GEEDW: Entered\n"));
3258 if (pValue == NULL)
3259 {
3260 return E_INVALIDARG;
3261 }
3262 return GetTlsSlot(GetProcess()->m_runtimeOffsets.m_debuggerWordTLSIndex, pValue);
3263}
3264
3265// SetEEDebuggerWord
3266//
3267// This routine writes the value to the thread
3268//
3269// Parameters:
3270// pValue - Value to write.
3271//
3272// Returns:
3273// HRESULT failure code or S_OK
3274//
3275// Notes:
3276// This function is very dangerous. See code:CordbUnmanagedThread::SetEETlsValue for why.
3277HRESULT CordbUnmanagedThread::SetEEDebuggerWord(REMOTE_PTR value)
3278{
3279 LOG((LF_CORDB, LL_INFO1000, "CUT::SEEDW: Entered - value is 0x%p\n", value));
3280 return SetTlsSlot(GetProcess()->m_runtimeOffsets.m_debuggerWordTLSIndex, value);
3281}
3282
3283/*
3284 * GetEEThreadPtr
3285 *
3286 * This routine returns the value read from the thread
3287 *
3288 * Parameters:
3289 * ppEEThread - Location to store value.
3290 *
3291 * Returns:
3292 * E_INVALIDARG, E_FAIL, S_OK
3293 */
3294HRESULT CordbUnmanagedThread::GetEEThreadPtr(REMOTE_PTR *ppEEThread)
3295{
3296 _ASSERTE(GetProcess()->ThreadHoldsProcessLock());
3297
3298 if (ppEEThread == NULL)
3299 {
3300 return E_INVALIDARG;
3301 }
3302
3303 *ppEEThread = (REMOTE_PTR)GetEEThreadValue();
3304
3305 return S_OK;
3306}
3307
3308
3309void CordbUnmanagedThread::GetEEState(bool *threadStepping, bool *specialManagedException)
3310{
3311 REMOTE_PTR pEEThread;
3312
3313 HRESULT hr = GetEEThreadPtr(&pEEThread);
3314
3315 _ASSERTE(SUCCEEDED(hr));
3316 _ASSERTE(pEEThread != NULL);
3317
3318 *threadStepping = false;
3319 *specialManagedException = false;
3320
3321 // Compute the address of the thread's state
3322 DebuggerIPCRuntimeOffsets *pRO = &(GetProcess()->m_runtimeOffsets);
3323 void *pEEThreadStateNC = (BYTE*) pEEThread + pRO->m_EEThreadStateNCOffset;
3324
3325 // Grab the thread state out of the EE Thread.
3326 DWORD EEThreadStateNC;
3327 hr = GetProcess()->SafeReadStruct(PTR_TO_CORDB_ADDRESS(pEEThreadStateNC), &EEThreadStateNC);
3328 if (FAILED(hr))
3329 {
3330 LOG((LF_CORDB, LL_INFO1000, "CUT::GEETS: failed to read thread state NC: 0x%p + 0x%x = 0x%p, err=%d\n",
3331 pEEThread, pRO->m_EEThreadStateNCOffset, pEEThreadStateNC, GetLastError()));
3332 return;
3333 }
3334
3335 LOG((LF_CORDB, LL_INFO1000000, "CUT::GEETS: EE Thread state NC is 0x%08x\n", EEThreadStateNC));
3336
3337 // Looks like we've got the state of the thread.
3338 *threadStepping = ((EEThreadStateNC & pRO->m_EEThreadSteppingStateMask) != 0);
3339 *specialManagedException = ((EEThreadStateNC & pRO->m_EEIsManagedExceptionStateMask) != 0);
3340
3341 return;
3342}
3343
3344// Currently, the EE manually tracks its "can't-stop" regions. This retrieves that manual tracking value.
3345// @todo - This should eventually become deprecated since the Entire EE will be a can't-stop region.
3346bool CordbUnmanagedThread::GetEEThreadCantStopHelper()
3347{
3348 // Note: any failure to read memory is okay for this method. We simply say that the thread is not is a can't stop
3349 // state, and that's okay.
3350
3351 REMOTE_PTR pEEThread;
3352
3353 HRESULT hr = GetEEThreadPtr(&pEEThread);
3354
3355 _ASSERTE(SUCCEEDED(hr));
3356 _ASSERTE(pEEThread != NULL);
3357
3358 // Compute the address of the thread's debugger word #1
3359 DebuggerIPCRuntimeOffsets *pRO = &(GetProcess()->m_runtimeOffsets);
3360 void *pEEThreadCantStop = (BYTE*) pEEThread + pRO->m_EEThreadCantStopOffset;
3361
3362 // Grab the debugger word #1 out of the EE Thread.
3363 DWORD EEThreadCantStop;
3364 hr = GetProcess()->SafeReadStruct(PTR_TO_CORDB_ADDRESS(pEEThreadCantStop), &EEThreadCantStop);
3365
3366 if (FAILED(hr))
3367 {
3368 LOG((LF_CORDB, LL_INFO1000, "CUT::GEETS: failed to read thread cant stop: 0x%08x + 0x%x = 0x%08x, err=%d\n",
3369 pEEThread, pRO->m_EEThreadCantStopOffset, pEEThreadCantStop, GetLastError()));
3370
3371 return false;
3372 }
3373
3374 LOG((LF_CORDB, LL_INFO1000000, "CUT::GEETS: EE Thread cant stop is 0x%08x\n", EEThreadCantStop));
3375
3376 // Looks like we've got it.
3377 if (EEThreadCantStop != 0)
3378 return true;
3379 else
3380 return false;
3381}
3382
3383
3384// Is the thread in a "can't stop" region?
3385// "Can't-Stop" regions include anything that's "inside" the runtime; ie, the runtime has some
3386// synchronization mechanism that will halt this thread, and so we don't need to suspend it.
3387// The interop debugger should leave anything in a can't-stop region alone and just let the runtime
3388// handle it.
3389bool CordbUnmanagedThread::IsCantStop()
3390{
3391 CONTRACTL
3392 {
3393 NOTHROW;
3394 }
3395 CONTRACTL_END;
3396
3397 // Definition of a can't stop region:
3398 // - Any "Special" thread that doesn't have an EE Thread (includes the real Helper Thread,
3399 // Concurrent GC thread, ThreadPool thread, etc).
3400 // - Any thread in Cooperative code.
3401 // - Any thread w/ a can't-stop count > 0.
3402 // - Any thread holding a "Debugger" Crst. (This is actually a subset of the
3403 // can't-stop count b/c Enter/Leave adjust that count).
3404 // - Any generic, first chance or RaiseException hijacked thread
3405
3406 // If the runtime isn't init yet, not a can't-stop.
3407 // We don't even have the DCB yet.
3408 if (!GetProcess()->m_initialized)
3409 {
3410 return false;
3411 }
3412 _ASSERTE(GetProcess()->ThreadHoldsProcessLock());
3413
3414 if (IsRaiseExceptionHijacked())
3415 {
3416 return true;
3417 }
3418
3419 REMOTE_PTR pEEThread;
3420 HRESULT hr = this->GetEEThreadPtr(&pEEThread);
3421 if (FAILED(hr))
3422 {
3423 _ASSERTE(!"Failed to EEThreadPtr in IsCantStop");
3424 return true;
3425 }
3426
3427 DebuggerIPCRuntimeOffsets *pRO = &(GetProcess()->m_runtimeOffsets);
3428
3429 // @todo- remove this and use the CantStop index below.
3430 // Is this a "special" thread?
3431 // Any thread that can take CLR locks w/o having an EE Thread object should
3432 // be marked as special. These threads are in "can't-stop" regions b/c if we suspend
3433 // them, they may be holding a lock that blocks the helper thread.
3434 // The helper thread is marked as "special".
3435 {
3436 SIZE_T idx = pRO->m_TLSIsSpecialIndex;
3437 REMOTE_PTR special = GetPreDefTlsSlot(idx, NULL);
3438
3439 // If it's a special thread
3440 if ((special != 0) && (pEEThread == NULL))
3441 {
3442 return true;
3443 }
3444 }
3445
3446 // Check for CantStop regions off the FLS.
3447 // This is the biggest way to describe can't-stop regions when we're in preemptive mode
3448 // (or when we don't have a thread object).
3449 // If a LS thread takes a debugger lock, it will increment the Can't-Stop count.
3450 {
3451 SIZE_T idx = pRO->m_TLSCantStopIndex;
3452 REMOTE_PTR count = (REMOTE_PTR) GetPreDefTlsSlot(idx, NULL);
3453
3454 // Just a sanity check here. There's nothing special about 1000, but if the
3455 // stop-count gets this big, 99% chance it's:
3456 // - we're accessing the wrong memory (an issue)
3457 // - someone on the LS is leaking stop-counts. (an issue).
3458 _ASSERTE(count < (REMOTE_PTR)1000);
3459
3460 if (count > 0)
3461 {
3462 LOG((LF_CORDB, LL_INFO1000000, "Thread 0x%x is can't-stop b/c count=%d\n", m_id, count));
3463 return true;
3464 }
3465 }
3466
3467 EX_TRY
3468 {
3469 GetProcess()->UpdateRightSideDCB();
3470 }
3471 EX_CATCH
3472 {
3473 _ASSERTE(!"IsCantStop: Failed updating debugger control block");
3474 }
3475 EX_END_CATCH(SwallowAllExceptions);
3476
3477 // Helper's canary thread is always can't-stop.
3478 if (this->m_id == GetProcess()->GetDCB()->m_CanaryThreadId)
3479 {
3480 return true;
3481 }
3482
3483 // Check helper thread / or anyone pretending to be the helper thread.
3484 if ((this->m_id == GetProcess()->GetDCB()->m_helperThreadId) ||
3485 (this->m_id == GetProcess()->GetDCB()->m_temporaryHelperThreadId) ||
3486 (this->m_id == GetProcess()->m_helperThreadId))
3487 {
3488 return true;
3489 }
3490
3491 if (IsGenericHijacked() || IsFirstChanceHijacked())
3492 return true;
3493
3494 // If this isn't a EE thread (and not the helper thread, and not hijacked), then it's ok to stop.
3495 if (pEEThread == NULL)
3496 return false;
3497
3498 // This checks for an explicit "can't" stop region.
3499 // Eventually, these explicit regions should become a complete subset of the other checks.
3500 if (GetEEThreadCantStopHelper())
3501 return true;
3502
3503
3504 // If we're in cooperative mode (either managed code or parts inside the runtime), then don't stop.
3505 // Note we could remove this since the check is made in side of the DAC request below,
3506 // but it's faster to look here.
3507 if (GetEEPGCDisabled())
3508 return true;
3509
3510 return false;
3511}
3512
3513bool CordbUnmanagedThread::GetEEPGCDisabled()
3514{
3515 // Note: any failure to read memory is okay for this method. We simply say that the thread has PGC disabled, which
3516 // is always the worst case scenario.
3517
3518 REMOTE_PTR pEEThread;
3519
3520 HRESULT hr = GetEEThreadPtr(&pEEThread);
3521
3522 _ASSERTE(SUCCEEDED(hr));
3523
3524 // Compute the address of the thread's PGC disabled word
3525 DebuggerIPCRuntimeOffsets *pRO = &(GetProcess()->m_runtimeOffsets);
3526 void *pEEThreadPGCDisabled = (BYTE*) pEEThread + pRO->m_EEThreadPGCDisabledOffset;
3527
3528 // Grab the PGC disabled word out of the EE Thread.
3529 DWORD EEThreadPGCDisabled;
3530 hr = GetProcess()->SafeReadStruct(PTR_TO_CORDB_ADDRESS(pEEThreadPGCDisabled), &EEThreadPGCDisabled);
3531
3532 if (FAILED(hr))
3533 {
3534 LOG((LF_CORDB, LL_INFO1000, "CUT::GEETS: failed to read thread PGC Disabled: 0x%p + 0x%x = 0x%p, err=%d\n",
3535 pEEThread, pRO->m_EEThreadPGCDisabledOffset, pEEThreadPGCDisabled, GetLastError()));
3536
3537 return true;
3538 }
3539
3540 LOG((LF_CORDB, LL_INFO1000000, "CUT::GEETS: EE Thread PGC Disabled is 0x%08x\n", EEThreadPGCDisabled));
3541
3542 // Looks like we've got it.
3543 if (EEThreadPGCDisabled == pRO->m_EEThreadPGCDisabledValue)
3544 return true;
3545 else
3546 return false;
3547}
3548
3549bool CordbUnmanagedThread::GetEEFrame()
3550{
3551 REMOTE_PTR pEEThread;
3552
3553 HRESULT hr = GetEEThreadPtr(&pEEThread);
3554
3555 _ASSERTE(SUCCEEDED(hr));
3556 _ASSERTE(pEEThread != NULL);
3557
3558 // Compute the address of the thread's frame ptr
3559 DebuggerIPCRuntimeOffsets *pRO = &(GetProcess()->m_runtimeOffsets);
3560 void *pEEThreadFrame = (BYTE*) pEEThread + pRO->m_EEThreadFrameOffset;
3561
3562 // Grab the thread's frame out of the EE Thread.
3563 DWORD EEThreadFrame;
3564 hr = GetProcess()->SafeReadStruct(PTR_TO_CORDB_ADDRESS(pEEThreadFrame), &EEThreadFrame);
3565
3566 if (FAILED(hr))
3567 {
3568 LOG((LF_CORDB, LL_INFO1000, "CUT::GEETF: failed to read thread frame: 0x%p + 0x%x = 0x%p, err=%d\n",
3569 pEEThread, pRO->m_EEThreadFrameOffset, pEEThreadFrame, GetLastError()));
3570
3571 return false;
3572 }
3573
3574 LOG((LF_CORDB, LL_INFO1000000, "CUT::GEETF: EE Thread's frame is 0x%08x\n", EEThreadFrame));
3575
3576 // Looks like we've got the frame of the thread.
3577 if (EEThreadFrame != pRO->m_EEMaxFrameValue)
3578 return true;
3579 else
3580 return false;
3581}
3582
3583// Gets the thread context as if the thread were unhijacked, regardless
3584// of whether it really is
3585HRESULT CordbUnmanagedThread::GetThreadContext(DT_CONTEXT* pContext)
3586{
3587 // While hijacked there are 3 potential contexts we could be resuming back to
3588 // 1) A context provided in SetThreadContext that we defered applying
3589 // 2) The LS copy of the context on the stack being modified in the handler
3590 // 3) The original context present when the hijack was started
3591 //
3592 // Both #1 and #3 are stored in the GetHijackCtx() space so of course you can't
3593 // have them both. You have have #1 if IsContextSet() is true, otherwise it holds #3
3594 //
3595 // GenericHijack, FirstChanceHijackForSync, and RaiseExceptionHijack use #1 if available
3596 // and fallback to #3 if not. In other words they use GetHijackCtx() regardless of which thing it holds
3597 // M2UHandoff uses #1 if available and then falls back to #2.
3598 //
3599 // The reasoning here is that the first three hijacks are intended to be transparent. Since
3600 // the debugger shouldn't know they are occuring then it shouldn't see changes potentially
3601 // made on the LS. The M2UHandoff is not transparent, it has to update the context in order
3602 // to get clear of a bp.
3603 //
3604 // If not hijacked call the normal Win32 function.
3605
3606 HRESULT hr = S_OK;
3607
3608 LOG((LF_CORDB, LL_INFO10000, "CUT::GTC: thread=0x%p, flags=0x%x.\n", this, pContext->ContextFlags));
3609
3610 if(IsContextSet() || IsGenericHijacked() || (IsFirstChanceHijacked() && IsBlockingForSync())
3611 || IsRaiseExceptionHijacked())
3612 {
3613 _ASSERTE(IsFirstChanceHijacked() || IsGenericHijacked() || IsRaiseExceptionHijacked());
3614 LOG((LF_CORDB, LL_INFO10000, "CUT::GTC: hijackCtx case IsContextSet=%d IsGenericHijacked=%d"
3615 "HijackedForSync=%d RaiseExceptionHijacked=%d.\n",
3616 IsContextSet(), IsGenericHijacked(), IsBlockingForSync(), IsRaiseExceptionHijacked()));
3617 LOG((LF_CORDB, LL_INFO10000, "CUT::GTC: hijackCtx is:\n"));
3618 LogContext(GetHijackCtx());
3619 CORDbgCopyThreadContext(pContext, GetHijackCtx());
3620 }
3621 // use the LS for M2UHandoff
3622 else if (IsFirstChanceHijacked() && !IsBlockingForSync())
3623 {
3624 LOG((LF_CORDB, LL_INFO10000, "CUT::GTC: getting LS context for first chance hijack, addr=0x%08x.\n",
3625 m_pLeftSideContext.UnsafeGet()));
3626
3627 // Read the context into a temp context then copy to the out param.
3628 DT_CONTEXT tempContext = { 0 };
3629
3630 hr = GetProcess()->SafeReadThreadContext(m_pLeftSideContext, &tempContext);
3631
3632 if (SUCCEEDED(hr))
3633 CORDbgCopyThreadContext(pContext, &tempContext);
3634 }
3635 // no hijack in place so just call straight through
3636 else
3637 {
3638 LOG((LF_CORDB, LL_INFO10000, "CUT::GTC: getting context from win32.\n"));
3639
3640 BOOL succ = DbiGetThreadContext(m_handle, pContext);
3641
3642 if (!succ)
3643 hr = HRESULT_FROM_GetLastError();
3644 }
3645
3646 if(IsSSFlagHidden())
3647 {
3648 UnsetSSFlag(pContext);
3649 }
3650 LogContext(pContext);
3651
3652 return hr;
3653}
3654
3655// Sets the thread context as if the thread were unhijacked, regardless
3656// of whether it really is. See GetThreadContext above for more details
3657// on this abstraction
3658HRESULT CordbUnmanagedThread::SetThreadContext(DT_CONTEXT* pContext)
3659{
3660 HRESULT hr = S_OK;
3661
3662 LOG((LF_CORDB, LL_INFO10000,
3663 "CUT::STC: thread=0x%p, flags=0x%x.\n", this, pContext->ContextFlags));
3664
3665 LogContext(pContext);
3666
3667 // If the thread is first chance hijacked, then write the context into the remote process. If the thread is generic
3668 // hijacked, then update the copy of the context that we already have. Otherwise call the normal Win32 function.
3669
3670 if (IsGenericHijacked() || IsFirstChanceHijacked() || IsRaiseExceptionHijacked())
3671 {
3672 if(IsGenericHijacked())
3673 {
3674 LOG((LF_CORDB, LL_INFO10000, "CUT::STC: setting context from generic/2nd chance hijack.\n"));
3675 }
3676 else if(IsFirstChanceHijacked())
3677 {
3678 LOG((LF_CORDB, LL_INFO10000, "CUT::STC: setting context from 1st chance hijack.\n"));
3679 }
3680 else
3681 {
3682 LOG((LF_CORDB, LL_INFO10000, "CUT::STC: setting context from RaiseException hijack.\n"));
3683 }
3684 SetState(CUTS_HasContextSet);
3685 CORDbgCopyThreadContext(GetHijackCtx(), pContext);
3686 }
3687 else
3688 {
3689 LOG((LF_CORDB, LL_INFO10000, "CUT::STC: setting context from win32.\n"));
3690
3691 // If the user is also setting the SS flag then we no longer have to hide it
3692 if(IsSSFlagEnabled(pContext))
3693 {
3694 ClearState(CUTS_IsSSFlagHidden);
3695 }
3696 // if the user is turning off the SS flag but we still want it on then leave it on
3697 // but hidden
3698 if(!IsSSFlagEnabled(pContext) && IsSSFlagNeeded())
3699 {
3700 SetState(CUTS_IsSSFlagHidden);
3701 SetSSFlag(pContext);
3702 }
3703
3704 BOOL succ = DbiSetThreadContext(m_handle, pContext);
3705
3706 if (!succ)
3707 {
3708 hr = HRESULT_FROM_GetLastError();
3709 }
3710 }
3711
3712 return hr;
3713}
3714
3715// Turns on the stepping flag internally and tracks whether or not the flag
3716// should also be seen by the user
3717VOID CordbUnmanagedThread::BeginStepping()
3718{
3719 _ASSERTE(!IsGenericHijacked() && !IsFirstChanceHijacked());
3720 _ASSERTE(!IsSSFlagNeeded());
3721 _ASSERTE(!IsSSFlagHidden());
3722
3723 DT_CONTEXT tempContext;
3724 tempContext.ContextFlags = DT_CONTEXT_FULL;
3725 BOOL succ = DbiGetThreadContext(m_handle, &tempContext);
3726 _ASSERTE(succ);
3727
3728 if(!IsSSFlagEnabled(&tempContext))
3729 {
3730 SetSSFlag(&tempContext);
3731 SetState(CUTS_IsSSFlagHidden);
3732 }
3733 SetState(CUTS_IsSSFlagNeeded);
3734
3735 succ = DbiSetThreadContext(m_handle, &tempContext);
3736 _ASSERTE(succ);
3737}
3738
3739// Turns off the stepping flag internally. If the user was also not using it then
3740// the flag is turned off on the context
3741VOID CordbUnmanagedThread::EndStepping()
3742{
3743 _ASSERTE(!IsGenericHijacked() && !IsFirstChanceHijacked());
3744 _ASSERTE(IsSSFlagNeeded());
3745
3746 DT_CONTEXT tempContext;
3747 tempContext.ContextFlags = DT_CONTEXT_FULL;
3748 BOOL succ = DbiGetThreadContext(m_handle, &tempContext);
3749 _ASSERTE(succ);
3750
3751 if(IsSSFlagHidden())
3752 {
3753 UnsetSSFlag(&tempContext);
3754 ClearState(CUTS_IsSSFlagHidden);
3755 }
3756 ClearState(CUTS_IsSSFlagNeeded);
3757
3758 succ = DbiSetThreadContext(m_handle, &tempContext);
3759 _ASSERTE(succ);
3760}
3761
3762
3763// Writes some details of the given context into the debugger log
3764VOID CordbUnmanagedThread::LogContext(DT_CONTEXT* pContext)
3765{
3766#if defined(DBG_TARGET_X86)
3767 LOG((LF_CORDB, LL_INFO10000,
3768 "CUT::LC: Eip=0x%08x, Esp=0x%08x, Eflags=0x%08x\n", pContext->Eip, pContext->Esp,
3769 pContext->EFlags));
3770#elif defined(DBG_TARGET_AMD64)
3771 LOG((LF_CORDB, LL_INFO10000,
3772 "CUT::LC: Rip=" FMT_ADDR ", Rsp=" FMT_ADDR ", Eflags=0x%08x\n",
3773 DBG_ADDR(pContext->Rip),
3774 DBG_ADDR(pContext->Rsp),
3775 pContext->EFlags)); // EFlags is still 32bits on AMD64
3776#elif defined(DBG_TARGET_ARM64)
3777 LOG((LF_CORDB, LL_INFO10000,
3778 "CUT::LC: Pc=" FMT_ADDR ", Sp=" FMT_ADDR ", Lr=" FMT_ADDR ", Cpsr=" FMT_ADDR "\n",
3779 DBG_ADDR(pContext->Pc),
3780 DBG_ADDR(pContext->Sp),
3781 DBG_ADDR(pContext->Lr),
3782 DBG_ADDR(pContext->Cpsr)));
3783#else // DBG_TARGET_X86
3784 PORTABILITY_ASSERT("LogContext needs a PC and stack pointer.");
3785#endif // DBG_TARGET_X86
3786}
3787
3788// Hijacks this thread using the FirstChanceSuspend hijack
3789HRESULT CordbUnmanagedThread::SetupFirstChanceHijackForSync()
3790{
3791 HRESULT hr = S_OK;
3792
3793 CONSISTENCY_CHECK(!IsBlockingForSync()); // Shouldn't double hijack
3794 CONSISTENCY_CHECK(!IsCantStop()); // must be in stoppable-region.
3795 _ASSERTE(HasIBEvent());
3796
3797 // We used to hijack for real here but now we have a vectored exception handler that will always be
3798 // triggered. So we don't have hijack in the sense that we overwrite the thread's IP. However we still
3799 // set the flag so that when we receive the HijackStartedSignal from the LS we know that this thread
3800 // should block in there rather than continuing.
3801 //hr = SetupFirstChanceHijack(EHijackReason::kFirstChanceSuspend, &(IBEvent()->m_currentDebugEvent.u.Exception.ExceptionRecord));
3802
3803 _ASSERTE(!IsFirstChanceHijacked());
3804 _ASSERTE(!IsGenericHijacked());
3805 _ASSERTE(GetProcess()->ThreadHoldsProcessLock());
3806
3807 // We'd better not be hijacking in a can't stop region!
3808 // This also means we can't hijack in coopeative (since that's a can't-stop)
3809 _ASSERTE(!IsCantStop());
3810
3811 // we should not be stepping into hijacks
3812 _ASSERTE(!IsSSFlagHidden());
3813 _ASSERTE(!IsSSFlagNeeded());
3814 _ASSERTE(!IsContextSet());
3815
3816 // snapshot the current context so we can start spoofing it
3817 LOG((LF_CORDB, LL_INFO10000, "CUT::SFCHFS: hijackCtx started as:\n"));
3818 LogContext(GetHijackCtx());
3819
3820 // Save the thread's full context.
3821 DT_CONTEXT context;
3822 context.ContextFlags = DT_CONTEXT_FULL;
3823 BOOL succ = DbiGetThreadContext(m_handle, &context);
3824 _ASSERTE(succ);
3825 // for debugging when GetThreadContext fails
3826 if(!succ)
3827 {
3828 DWORD error = GetLastError();
3829 LOG((LF_CORDB, LL_ERROR, "CUT::SFCHFS: DbiGetThreadContext error=0x%x\n", error));
3830 }
3831
3832 GetHijackCtx()->ContextFlags = DT_CONTEXT_FULL;
3833 CORDbgCopyThreadContext(GetHijackCtx(), &context);
3834 LOG((LF_CORDB, LL_INFO10000, "CUT::SFCHFS: thread=0x%x Hijacking for sync. Original context is:\n", this));
3835 LogContext(GetHijackCtx());
3836
3837 // We're hijacking now...
3838 SetState(CUTS_FirstChanceHijacked);
3839 GetProcess()->m_state |= CordbProcess::PS_HIJACKS_IN_PLACE;
3840
3841 // We'll decrement this once the hijack returns
3842 GetProcess()->m_cFirstChanceHijackedThreads++;
3843 this->SetState(CUTS_BlockingForSync);
3844
3845 // we don't want to single step into the vectored exception handler
3846 // we will restore the SS flag after returning from the hijack
3847 if(IsSSFlagEnabled(&context))
3848 {
3849 LOG((LF_CORDB, LL_INFO10000, "CUT::SFCHFS: thread=0x%x Clearing SS flag\n", this));
3850 UnsetSSFlag(&context);
3851 succ = DbiSetThreadContext(m_handle, &context);
3852 _ASSERTE(succ);
3853 }
3854
3855
3856
3857 // There's a bizarre race where the thread was suspended right as the thread was about to dispatch a
3858 // debug event. We still get the debug event, and then may try to hijack. Resume the thread so that
3859 // it can run to the hijack.
3860 if (this->IsSuspended())
3861 {
3862 LOG((LF_CORDB, LL_ERROR, "CUT::SFCHFS: thread was suspended... resuming\n"));
3863 DWORD success = ResumeThread(this->m_handle);
3864
3865 if (success == 0xFFFFFFFF)
3866 {
3867 // Since we suspended it, we should be able to resume it in this window.
3868 CONSISTENCY_CHECK_MSGF(false, ("Failed to resume thread: tid=0x%x!", this->m_id));
3869 }
3870 else
3871 {
3872 this->ClearState(CUTS_Suspended);
3873 }
3874 }
3875
3876 return hr;
3877
3878}
3879
3880HRESULT CordbUnmanagedThread::SetupFirstChanceHijack(EHijackReason::EHijackReason reason, const EXCEPTION_RECORD * pExceptionRecord)
3881{
3882 _ASSERTE(!IsFirstChanceHijacked());
3883 _ASSERTE(!IsGenericHijacked());
3884 _ASSERTE(GetProcess()->ThreadHoldsProcessLock());
3885
3886 // We'd better not be hijacking in a can't stop region!
3887 // This also means we can't hijack in coopeative (since that's a can't-stop)
3888 _ASSERTE(!IsCantStop());
3889
3890 // we should not be stepping into hijacks
3891 _ASSERTE(!IsSSFlagHidden());
3892 _ASSERTE(!IsSSFlagNeeded());
3893
3894 // There's a bizarre race where the thread was suspended right as the thread was about to dispatch a
3895 // debug event. We still get the debug event, and then may try to hijack. Resume the thread so that
3896 // it can run to the hijack.
3897 if (this->IsSuspended())
3898 {
3899 DWORD succ = ResumeThread(this->m_handle);
3900
3901 if (succ == 0xFFFFFFFF)
3902 {
3903 // Since we suspended it, we should be able to resume it in this window.
3904 CONSISTENCY_CHECK_MSGF(false, ("Failed to resume thread: tid=0x%x!", this->m_id));
3905 }
3906 else
3907 {
3908 this->ClearState(CUTS_Suspended);
3909 }
3910 }
3911
3912 HRESULT hr = S_OK;
3913 EX_TRY
3914 {
3915// We save off the SEH handler on X86 to make sure we restore it properly after the hijack is complete
3916// The hijacks don't return normally and the SEH chain might have handlers added that don't get removed by default
3917#ifdef DBG_TARGET_X86
3918 hr = SaveCurrentLeafSeh();
3919 if(FAILED(hr))
3920 ThrowHR(hr);
3921#endif
3922 CORDB_ADDRESS LSContextAddr;
3923 GetProcess()->GetDAC()->Hijack(VMPTR_Thread::NullPtr(),
3924 GetOSTid(),
3925 pExceptionRecord,
3926 (T_CONTEXT*) GetHijackCtx(),
3927 sizeof(T_CONTEXT),
3928 reason,
3929 NULL,
3930 &LSContextAddr);
3931 LOG((LF_CORDB, LL_INFO10000, "CUT::SFCH: pLeftSideContext=0x%p\n", LSContextAddr));
3932 m_pLeftSideContext.Set(CORDB_ADDRESS_TO_PTR(LSContextAddr));
3933 }
3934 EX_CATCH_HRESULT(hr);
3935 if(FAILED(hr))
3936 {
3937 LOG((LF_CORDB, LL_INFO10000, "CUT::SFCH: Error setting up hijack context hr=0x%x\n", hr));
3938 return hr;
3939 }
3940
3941
3942 // We're hijacked now...
3943 SetState(CUTS_FirstChanceHijacked);
3944 GetProcess()->m_state |= CordbProcess::PS_HIJACKS_IN_PLACE;
3945
3946 // We'll decrement this once the hijack returns
3947 GetProcess()->m_cFirstChanceHijackedThreads++;
3948
3949 return S_OK;
3950}
3951
3952HRESULT CordbUnmanagedThread::SetupGenericHijack(DWORD eventCode, const EXCEPTION_RECORD * pRecord)
3953{
3954 _ASSERTE(GetProcess()->ThreadHoldsProcessLock());
3955
3956 _ASSERTE(eventCode == EXCEPTION_DEBUG_EVENT);
3957
3958 _ASSERTE(!IsFirstChanceHijacked());
3959 _ASSERTE(!IsGenericHijacked());
3960 _ASSERTE(!IsContextSet());
3961
3962 // Save the thread's full context.
3963 GetHijackCtx()->ContextFlags = DT_CONTEXT_FULL;
3964
3965 BOOL succ = DbiGetThreadContext(m_handle, GetHijackCtx());
3966
3967 if (!succ)
3968 {
3969 LOG((LF_CORDB, LL_INFO1000, "CUT::SGH: couldn't get thread context: %d\n", GetLastError()));
3970 return HRESULT_FROM_WIN32(GetLastError());
3971 }
3972
3973#if defined(DBG_TARGET_AMD64) || defined(DBG_TARGET_ARM64)
3974
3975 // On X86 Debugger::GenericHijackFunc() ensures the stack is walkable
3976 // by simply using the EBP chain, therefore we can execute the hijack
3977 // by setting the thread's context EIP to point to this function.
3978 // On X64, however, we first attempt to set up a "proper" hijack, with
3979 // a function that allows the OS to unwind the stack (ExceptionHijack).
3980 // If this fails we'll use the same method as on X86, even though the
3981 // stack will become un-walkable
3982
3983 ULONG32 dwThreadId = GetOSTid();
3984 CordbThread * pThread = GetProcess()->TryLookupOrCreateThreadByVolatileOSId(dwThreadId);
3985
3986 // For threads in the thread store we set up the full size
3987 // hijack, otherwise we fallback to hijacking by SetIP.
3988 if (pThread != NULL)
3989 {
3990 HRESULT hr = S_OK;
3991 EX_TRY
3992 {
3993 // Note that the data-target is not atomic, and we have no rollback mechanism.
3994 // We have to do several writes. If the data-target fails the writes half-way through the
3995 // target will be inconsistent.
3996 GetProcess()->GetDAC()->Hijack(
3997 pThread->m_vmThreadToken,
3998 dwThreadId,
3999 pRecord,
4000 (T_CONTEXT*) GetHijackCtx(),
4001 sizeof(T_CONTEXT),
4002 EHijackReason::kGenericHijack,
4003 NULL,
4004 NULL);
4005 }
4006 EX_CATCH_HRESULT(hr);
4007 if (SUCCEEDED(hr))
4008 {
4009 // Remember that we've hijacked the thread.
4010 SetState(CUTS_GenericHijacked);
4011
4012 return S_OK;
4013 }
4014
4015 STRESS_LOG1(LF_CORDB, LL_INFO1000, "CUT::SGH: Error setting up hijack context hr=0x%x\n", hr);
4016 // fallthrough (above hijack might have failed due to stack overflow, for example)
4017
4018 }
4019 // else (non-threadstore threads) fallthrough
4020
4021#endif // DBG_TARGET_AMD64 || defined(DBG_TARGET_ARM64)
4022
4023 // Remember that we've hijacked the guy.
4024 SetState(CUTS_GenericHijacked);
4025
4026 LOG((LF_CORDB, LL_INFO1000000, "CUT::SGH: Current IP is 0x%08x\n", CORDbgGetIP(GetHijackCtx())));
4027
4028 DebuggerIPCRuntimeOffsets *pRO = &(GetProcess()->m_runtimeOffsets);
4029
4030 // Wack the IP over to our generic hijack function.
4031 LPVOID holdIP = CORDbgGetIP(GetHijackCtx());
4032 CORDbgSetIP(GetHijackCtx(), pRO->m_genericHijackFuncAddr);
4033
4034 LOG((LF_CORDB, LL_INFO1000000, "CUT::SGH: New IP is 0x%08x\n", CORDbgGetIP(GetHijackCtx())));
4035
4036 // We should never single step into the hijack
4037 BOOL isSSFlagOn = IsSSFlagEnabled(GetHijackCtx());
4038 if(isSSFlagOn)
4039 {
4040 UnsetSSFlag(GetHijackCtx());
4041 }
4042
4043 succ = DbiSetThreadContext(m_handle, GetHijackCtx());
4044
4045 if (!succ)
4046 {
4047 LOG((LF_CORDB, LL_INFO1000, "CUT::SGH: couldn't set thread context: %d\n", GetLastError()));
4048
4049 return HRESULT_FROM_WIN32(GetLastError());
4050 }
4051
4052 // Put the original IP back into the local context copy for later.
4053 CORDbgSetIP(GetHijackCtx(), holdIP);
4054 // Set the original SS flag into the local context copy for later
4055 if(isSSFlagOn)
4056 {
4057 SetSSFlag(GetHijackCtx());
4058 }
4059 return S_OK;
4060}
4061
4062HRESULT CordbUnmanagedThread::FixupFromGenericHijack()
4063{
4064 LOG((LF_CORDB, LL_INFO1000, "CUT::FFGH: fixing up from generic hijack. Eip=0x%p, Esp=0x%p\n",
4065 CORDbgGetIP(GetHijackCtx()), CORDbgGetSP(GetHijackCtx())));
4066
4067 // We're no longer hijacked
4068 _ASSERTE(IsGenericHijacked());
4069 ClearState(CUTS_GenericHijacked);
4070
4071 // Clear the exception so we do a DBG_CONTINUE with the original context. Note: we only do generic hijacks on
4072 // in-band events.
4073 IBEvent()->SetState(CUES_ExceptionCleared);
4074
4075 // Using the context we saved when the event came in originally or the new context if set by user,
4076 // reset the thread as if it were never hijacked.
4077 BOOL succ = DbiSetThreadContext(m_handle, GetHijackCtx());
4078 // if the user set the context it has been applied now
4079 ClearState(CUTS_HasContextSet);
4080
4081 if (!succ)
4082 {
4083 LOG((LF_CORDB, LL_INFO1000, "CUT::FFGH: couldn't set thread context: %d\n", GetLastError()));
4084
4085 return HRESULT_FROM_WIN32(GetLastError());
4086 }
4087
4088 return S_OK;
4089}
4090
4091DT_CONTEXT * CordbUnmanagedThread::GetHijackCtx()
4092{
4093 return &m_context;
4094}
4095
4096
4097// Enable Single-Step (and bump the eip back one)
4098// This can only be called after a bp. (because we assume that we executed a bp when we adjust the eip).
4099HRESULT CordbUnmanagedThread::EnableSSAfterBP()
4100{
4101 DT_CONTEXT c;
4102 c.ContextFlags = DT_CONTEXT_FULL;
4103
4104 BOOL succ = DbiGetThreadContext(m_handle, &c);
4105
4106 if (!succ)
4107 return HRESULT_FROM_WIN32(GetLastError());
4108
4109 SetSSFlag(&c);
4110
4111 // Backup IP to point to the instruction we need to execute. Continuing from a breakpoint exception
4112 // continues execution at the instruction after the breakpoint, but we need to continue where the
4113 // breakpoint was.
4114 CORDbgAdjustPCForBreakInstruction(&c);
4115
4116 succ = DbiSetThreadContext(m_handle, &c);
4117
4118 if (!succ)
4119 {
4120 return HRESULT_FROM_WIN32(GetLastError());
4121 }
4122
4123 return S_OK;
4124}
4125
4126//
4127// FixupAfterOOBException automatically gets the debuggee past an OOB exception event. These are only BP or SS
4128// events. For SS, we just clear it, assuming that the only reason the thread was stepped in such place was to get it
4129// off of a BP. For a BP, we clear and backup the IP by one, and turn the trace flag on under the assumption that the
4130// only thing a debugger is allowed to do with an OOB BP exception is to get us off of it.
4131//
4132HRESULT CordbUnmanagedThread::FixupAfterOOBException(CordbUnmanagedEvent *ue)
4133{
4134 // We really should only be doing things to single steps and breakpoint exceptions.
4135 if (ue->m_currentDebugEvent.dwDebugEventCode == EXCEPTION_DEBUG_EVENT)
4136 {
4137 DWORD ec = ue->m_currentDebugEvent.u.Exception.ExceptionRecord.ExceptionCode;
4138
4139 if ((ec == STATUS_BREAKPOINT) || (ec == STATUS_SINGLE_STEP))
4140 {
4141 // Automatically clear the exception.
4142 ue->SetState(CUES_ExceptionCleared);
4143
4144 // Don't bother about toggling the single-step flag. OOB BPs should only be called
4145 // for raw int3 instructions, so no need to rewind and reexecute.
4146 }
4147 }
4148
4149 return S_OK;
4150}
4151
4152
4153//-----------------------------------------------------------------------------
4154// Setup to skip an native breakpoint
4155//-----------------------------------------------------------------------------
4156void CordbUnmanagedThread::SetupForSkipBreakpoint(NativePatch * pNativePatch)
4157{
4158 _ASSERTE(pNativePatch != NULL);
4159 _ASSERTE(!IsSkippingNativePatch());
4160 _ASSERTE(m_pPatchSkipAddress == NULL);
4161 _ASSERTE(GetProcess()->ThreadHoldsProcessLock());
4162
4163 SetState(CUTS_SkippingNativePatch);
4164
4165#ifdef _DEBUG
4166 // For debugging, provide a way that Cordbg devs can see if we're silently skipping BPs.
4167 static DWORD fTrapOnSkip = -1;
4168 if (fTrapOnSkip == -1)
4169 fTrapOnSkip = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_DbgTrapOnSkip);
4170
4171 if (fTrapOnSkip)
4172 {
4173 CONSISTENCY_CHECK_MSGF(false, ("The CLR is skipping a native BP at %p on thread 0x%x (%d)."
4174 "\nYou're getting this notification in debug builds b/c you have com+ var 'DbgTrapOnSkip' enabled.",
4175 pNativePatch->pAddress, this->m_id, this->m_id));
4176
4177 // We skipped this BP b/c IsCantStop was true. For debugging convenience, call IsCantStop here
4178 // (in case we break at the assert above and want to trace why we're in a CS region)
4179 bool fCantStop = this->IsCantStop();
4180 LOG((LF_CORDB, LL_INFO1000, "In Can'tStopRegion = %d\n", fCantStop));
4181
4182 // Refresh the reg key
4183 fTrapOnSkip = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_DbgTrapOnSkip);
4184 }
4185#endif
4186#if defined(DBG_TARGET_X86)
4187 STRESS_LOG2(LF_CORDB, LL_INFO100, "CUT::SetupSkip. addr=%p. Opcode=%x\n", pNativePatch->pAddress, (DWORD) pNativePatch->opcode);
4188#endif
4189
4190 // Replace the BP w/ the opcode.
4191 RemoveRemotePatch(GetProcess(), pNativePatch->pAddress, pNativePatch->opcode);
4192
4193 // Enable the SS flag & Adjust IP.
4194 HRESULT hr = this->EnableSSAfterBP();
4195 SIMPLIFYING_ASSUMPTION(SUCCEEDED(hr));
4196
4197
4198 // Now we return,
4199 // Process continues, LS will single step past BP, and fire a SS exception.
4200 // When we get the SS, we res
4201
4202
4203 // We need to remember this so we can make sure we fixup at the proper address.
4204 // The address of a ss exception is the instruction we finish on, not where
4205 // we originally placed the BP. Since instructions can be variable length,
4206 // we can't work backwards.
4207 m_pPatchSkipAddress = pNativePatch->pAddress;
4208}
4209
4210//-----------------------------------------------------------------------------
4211// Second half of skipping a native bp.
4212// Note we pass the address in b/c our caller has (from the debug_evet), and
4213// we don't want to waste storage to remember it ourselves.
4214//-----------------------------------------------------------------------------
4215void CordbUnmanagedThread::FixupForSkipBreakpoint()
4216{
4217 _ASSERTE(m_pPatchSkipAddress != NULL);
4218 _ASSERTE(IsSkippingNativePatch());
4219 _ASSERTE(GetProcess()->ThreadHoldsProcessLock());
4220
4221 ClearState(CUTS_SkippingNativePatch);
4222
4223 // Only reapply the int3 if it hasn't been removed yet.
4224 if (GetProcess()->GetNativePatch(m_pPatchSkipAddress) != NULL)
4225 {
4226 ApplyRemotePatch(GetProcess(), m_pPatchSkipAddress);
4227 STRESS_LOG1(LF_CORDB, LL_INFO100, "CUT::FixupSetupSkip. addr=%p\n", m_pPatchSkipAddress);
4228 }
4229 else
4230 {
4231 STRESS_LOG1(LF_CORDB, LL_INFO100, "CUT::FixupSetupSkip. Patch removed. Not-reading. addr=%p\n", m_pPatchSkipAddress);
4232 }
4233
4234 m_pPatchSkipAddress = NULL;
4235}
4236
4237inline TADDR GetSP(DT_CONTEXT* context)
4238{
4239#if defined(DBG_TARGET_X86)
4240 return (TADDR)context->Esp;
4241#elif defined(DBG_TARGET_AMD64)
4242 return (TADDR)context->Rsp;
4243#elif defined(DBG_TARGET_ARM) || defined(DBG_TARGET_ARM64)
4244 return (TADDR)context->Sp;
4245#else
4246 _ASSERTE(!"nyi for platform");
4247#endif
4248}
4249
4250BOOL CordbUnmanagedThread::GetStackRange(CORDB_ADDRESS *pBase, CORDB_ADDRESS *pLimit)
4251{
4252#if !defined(FEATURE_DBGIPC_TRANSPORT)
4253
4254 if (m_stackBase == 0 && m_stackLimit == 0)
4255 {
4256 HANDLE hProc;
4257 DT_CONTEXT tempContext;
4258 MEMORY_BASIC_INFORMATION mbi;
4259
4260 tempContext.ContextFlags = DT_CONTEXT_FULL;
4261 if (SUCCEEDED(GetProcess()->GetHandle(&hProc)) &&
4262 SUCCEEDED(GetThreadContext(&tempContext)) &&
4263 ::VirtualQueryEx(hProc, (LPCVOID)GetSP(&tempContext), &mbi, sizeof(mbi)) != 0)
4264 {
4265 // the lowest stack address is the AllocationBase
4266 TADDR limit = PTR_TO_TADDR(mbi.AllocationBase);
4267
4268 // Now, on to find the stack base:
4269 // Closest to the AllocationBase we might have a MEM_RESERVED block
4270 // for all the as yet unallocated pages...
4271 TADDR regionBase = limit;
4272 if (::VirtualQueryEx(hProc, (LPCVOID) regionBase, &mbi, sizeof(mbi)) == 0
4273 || mbi.Type != MEM_PRIVATE)
4274 goto Exit;
4275
4276 if (mbi.State == MEM_RESERVE)
4277 regionBase += mbi.RegionSize;
4278
4279 // Next we might have a few guard pages
4280 if (::VirtualQueryEx(hProc, (LPCVOID) regionBase, &mbi, sizeof(mbi)) == 0
4281 || mbi.Type != MEM_PRIVATE)
4282 goto Exit;
4283
4284 if (mbi.State == MEM_COMMIT && (mbi.Protect & PAGE_GUARD) != 0)
4285 regionBase += mbi.RegionSize;
4286
4287 // And finally the "regular" stack region
4288 if (::VirtualQueryEx(hProc, (LPCVOID) regionBase, &mbi, sizeof(mbi)) == 0
4289 || mbi.Type != MEM_PRIVATE)
4290 goto Exit;
4291
4292 if (mbi.State == MEM_COMMIT && (mbi.Protect & PAGE_READWRITE) != 0)
4293 regionBase += mbi.RegionSize;
4294
4295 if (limit == regionBase)
4296 goto Exit;
4297
4298 m_stackLimit = limit;
4299 m_stackBase = regionBase;
4300 }
4301 }
4302
4303Exit:
4304 if (pBase != NULL)
4305 *pBase = m_stackBase;
4306 if (pLimit != NULL)
4307 *pLimit = m_stackLimit;
4308
4309 return (m_stackBase != 0 || m_stackLimit != 0);
4310
4311#else
4312
4313 if (pBase != NULL)
4314 *pBase = 0;
4315 if (pLimit != NULL)
4316 *pLimit = 0;
4317
4318 return FALSE;
4319
4320#endif // FEATURE_DBGIPC_TRANSPORT
4321}
4322
4323//-----------------------------------------------------------------------------
4324// Returns the thread context to the state it was in when it last entered RaiseException
4325// This allows the thread to retrigger an exception caused by RaiseException
4326//-----------------------------------------------------------------------------
4327void CordbUnmanagedThread::HijackToRaiseException()
4328{
4329 LOG((LF_CORDB, LL_INFO1000, "CP::HTRE: hijacking to RaiseException\n"));
4330 _ASSERTE(HasRaiseExceptionEntryCtx());
4331 _ASSERTE(!IsRaiseExceptionHijacked());
4332 _ASSERTE(!IsGenericHijacked());
4333 _ASSERTE(!IsFirstChanceHijacked());
4334 _ASSERTE(!IsContextSet());
4335
4336 BOOL succ = DbiGetThreadContext(m_handle, GetHijackCtx());
4337 _ASSERTE(succ);
4338 succ = DbiSetThreadContext(m_handle, &m_raiseExceptionEntryContext);
4339 _ASSERTE(succ);
4340 SetState(CUTS_IsRaiseExceptionHijacked);
4341}
4342
4343//----------------------------------------------------------------------------
4344// Returns the context to its unhijacked state.
4345//----------------------------------------------------------------------------
4346void CordbUnmanagedThread::RestoreFromRaiseExceptionHijack()
4347{
4348 LOG((LF_CORDB, LL_INFO1000, "CP::RFREH: ending RaiseException hijack\n"));
4349 _ASSERTE(IsRaiseExceptionHijacked());
4350
4351 DT_CONTEXT restoreContext;
4352 restoreContext.ContextFlags = DT_CONTEXT_FULL;
4353 HRESULT hr = GetThreadContext(&restoreContext);
4354 _ASSERTE(SUCCEEDED(hr));
4355
4356 ClearState(CUTS_IsRaiseExceptionHijacked);
4357 hr = SetThreadContext(&restoreContext);
4358 _ASSERTE(SUCCEEDED(hr));
4359}
4360
4361//-----------------------------------------------------------------------------
4362// Attempts to store the state of a thread currently entering RaiseException
4363// This grabs both a full context and enough state to determine what exception
4364// RaiseException should be raising. If any of the state can not be retrieved
4365// then this entrance to RaiseException is silently ignored
4366//-----------------------------------------------------------------------------
4367void CordbUnmanagedThread::SaveRaiseExceptionEntryContext()
4368{
4369 _ASSERTE(FALSE); // should be unused now
4370 LOG((LF_CORDB, LL_INFO1000, "CP::SREEC: saving raise exception context.\n"));
4371 _ASSERTE(!HasRaiseExceptionEntryCtx());
4372 _ASSERTE(!IsRaiseExceptionHijacked());
4373 HRESULT hr = S_OK;
4374 DT_CONTEXT context;
4375 context.ContextFlags = DT_CONTEXT_FULL;
4376 DbiGetThreadContext(m_handle, &context);
4377 // if the flag is set, unset it
4378 // we don't want to be single stepping through RaiseException the second time
4379 // sending out OOB SS events. Ultimately we will rethrow the exception which would
4380 // cleared the SS flag anyways.
4381 UnsetSSFlag(&context);
4382 memcpy(&m_raiseExceptionEntryContext, &context, sizeof(DT_CONTEXT));
4383
4384 // calculate the exception that we would expect to come from this invocation of RaiseException
4385 REMOTE_PTR pExceptionInformation = NULL;
4386#if defined(DBG_TARGET_AMD64)
4387 m_raiseExceptionExceptionCode = (DWORD)m_raiseExceptionEntryContext.Rcx;
4388 m_raiseExceptionExceptionFlags = (DWORD)m_raiseExceptionEntryContext.Rdx;
4389 m_raiseExceptionNumberParameters = (DWORD)m_raiseExceptionEntryContext.R8;
4390 pExceptionInformation = (REMOTE_PTR)m_raiseExceptionEntryContext.R9;
4391#elif defined(DBG_TARGET_ARM64)
4392 m_raiseExceptionExceptionCode = (DWORD)m_raiseExceptionEntryContext.X0;
4393 m_raiseExceptionExceptionFlags = (DWORD)m_raiseExceptionEntryContext.X1;
4394 m_raiseExceptionNumberParameters = (DWORD)m_raiseExceptionEntryContext.X2;
4395 pExceptionInformation = (REMOTE_PTR)m_raiseExceptionEntryContext.X3;
4396#elif defined(DBG_TARGET_X86)
4397 hr = m_pProcess->SafeReadStruct(PTR_TO_CORDB_ADDRESS((BYTE*)m_raiseExceptionEntryContext.Esp+4), &m_raiseExceptionExceptionCode);
4398 if(FAILED(hr))
4399 {
4400 LOG((LF_CORDB, LL_INFO1000, "CP::SREEC: failed to read exception code.\n"));
4401 return;
4402 }
4403 hr = m_pProcess->SafeReadStruct(PTR_TO_CORDB_ADDRESS((BYTE*)m_raiseExceptionEntryContext.Esp+8), &m_raiseExceptionExceptionFlags);
4404 if(FAILED(hr))
4405 {
4406 LOG((LF_CORDB, LL_INFO1000, "CP::SREEC: failed to read exception flags.\n"));
4407 return;
4408 }
4409 hr = m_pProcess->SafeReadStruct(PTR_TO_CORDB_ADDRESS((BYTE*)m_raiseExceptionEntryContext.Esp+12), &m_raiseExceptionNumberParameters);
4410 if(FAILED(hr))
4411 {
4412 LOG((LF_CORDB, LL_INFO1000, "CP::SREEC: failed to read number of parameters.\n"));
4413 return;
4414 }
4415 hr = m_pProcess->SafeReadStruct(PTR_TO_CORDB_ADDRESS((BYTE*)m_raiseExceptionEntryContext.Esp+16), &pExceptionInformation);
4416 if(FAILED(hr))
4417 {
4418 LOG((LF_CORDB, LL_INFO1000, "CP::SREEC: failed to read exception information pointer.\n"));
4419 return;
4420 }
4421#else
4422 _ASSERTE(!"Implement this for your platform");
4423 return;
4424#endif
4425 LOG((LF_CORDB, LL_INFO1000, "CP::SREEC: RaiseException parameters are 0x%x 0x%x 0x%x 0x%p.\n",
4426 m_raiseExceptionExceptionCode, m_raiseExceptionExceptionFlags,
4427 m_raiseExceptionNumberParameters, pExceptionInformation));
4428 TargetBuffer exceptionInfoTargetBuffer(pExceptionInformation, sizeof(REMOTE_PTR)*m_raiseExceptionNumberParameters);
4429 EX_TRY
4430 {
4431 m_pProcess->SafeReadBuffer(exceptionInfoTargetBuffer, (BYTE*)m_raiseExceptionExceptionInformation);
4432 }
4433 EX_CATCH_HRESULT(hr);
4434 if(FAILED(hr))
4435 {
4436 LOG((LF_CORDB, LL_INFO1000, "CP::SREEC: failed to read exception information.\n"));
4437 return;
4438 }
4439
4440 // If everything was succesful then set this flag, otherwise none of the above data is considered valid
4441 SetState(CUTS_HasRaiseExceptionEntryCtx);
4442 return;
4443}
4444
4445//-----------------------------------------------------------------------------
4446// Clears all the state saved in SaveRaiseExceptionContext and returns the thread
4447// to the state as if RaiseException has yet to be called. This is typically called
4448// after an exception retriggers or after determining that the exception never will
4449// retrigger.
4450//-----------------------------------------------------------------------------
4451void CordbUnmanagedThread::ClearRaiseExceptionEntryContext()
4452{
4453 _ASSERTE(FALSE); // should be unused now
4454 LOG((LF_CORDB, LL_INFO1000, "CP::CREEC: clearing raise exception context.\n"));
4455 _ASSERTE(HasRaiseExceptionEntryCtx());
4456 ClearState(CUTS_HasRaiseExceptionEntryCtx);
4457}
4458
4459//-----------------------------------------------------------------------------
4460// Uses a heuristic to determine if the given exception record is likely to be the exception
4461// raised by the last invocation of RaiseException on this thread. The current heuristic compares
4462// ExceptionCode, ExceptionFlags, and all ExceptionInformation.
4463//-----------------------------------------------------------------------------
4464BOOL CordbUnmanagedThread::IsExceptionFromLastRaiseException(const EXCEPTION_RECORD* pExceptionRecord)
4465{
4466 _ASSERTE(FALSE); // should be unused now
4467 if(!HasRaiseExceptionEntryCtx())
4468 {
4469 LOG((LF_CORDB, LL_INFO1000, "CP::IEFLRE: not a match - no previous raise context\n"));
4470 return FALSE;
4471 }
4472
4473 if (pExceptionRecord->ExceptionCode != m_raiseExceptionExceptionCode)
4474 {
4475 LOG((LF_CORDB, LL_INFO1000, "CP::IEFLRE: not a match - exception codes differ 0x%x 0x%x\n",
4476 pExceptionRecord->ExceptionCode, m_raiseExceptionExceptionCode));
4477 return FALSE;
4478 }
4479
4480 if (pExceptionRecord->ExceptionFlags != m_raiseExceptionExceptionFlags)
4481 {
4482 LOG((LF_CORDB, LL_INFO1000, "CP::IEFLRE: not a match - exception flags differ 0x%x 0x%x\n",
4483 pExceptionRecord->ExceptionFlags, m_raiseExceptionExceptionFlags));
4484 return FALSE;
4485 }
4486
4487 if (pExceptionRecord->NumberParameters != m_raiseExceptionNumberParameters)
4488 {
4489 LOG((LF_CORDB, LL_INFO1000, "CP::IEFLRE: not a match - number parameters differ 0x%x 0x%x\n",
4490 pExceptionRecord->NumberParameters, m_raiseExceptionNumberParameters));
4491 return FALSE;
4492 }
4493
4494 for(DWORD i = 0; i < pExceptionRecord->NumberParameters; i++)
4495 {
4496 if(m_raiseExceptionExceptionInformation[i] != pExceptionRecord->ExceptionInformation[i])
4497 {
4498 LOG((LF_CORDB, LL_INFO1000, "CP::IEFLRE: not a match - param %d differs 0x%x 0x%x\n",
4499 i, pExceptionRecord->ExceptionInformation[i], m_raiseExceptionExceptionInformation[i]));
4500 return FALSE;
4501 }
4502 }
4503
4504 LOG((LF_CORDB, LL_INFO1000, "CP::IEFLRE: match\n"));
4505 return TRUE;
4506}
4507
4508
4509//-----------------------------------------------------------------------------
4510// Inject an int3 at the given remote address
4511//-----------------------------------------------------------------------------
4512
4513// This flavor is assuming our caller already knows the opcode.
4514HRESULT ApplyRemotePatch(CordbProcess * pProcess, const void * pRemoteAddress)
4515{
4516#if defined(DBG_TARGET_X86) || defined(DBG_TARGET_AMD64)
4517 const BYTE patch = CORDbg_BREAK_INSTRUCTION;
4518#elif defined(DBG_TARGET_ARM64)
4519 const PRD_TYPE patch = CORDbg_BREAK_INSTRUCTION;
4520#else
4521 const BYTE patch = 0;
4522 PORTABILITY_ASSERT("NYI: ApplyRemotePatch for this platform");
4523#endif
4524 HRESULT hr = pProcess->SafeWriteStruct(PTR_TO_CORDB_ADDRESS(pRemoteAddress), &patch);
4525 SIMPLIFYING_ASSUMPTION_SUCCEEDED(hr);
4526 return S_OK;
4527}
4528
4529
4530// Get the opcode that we're replacing.
4531HRESULT ApplyRemotePatch(CordbProcess * pProcess, const void * pRemoteAddress, PRD_TYPE * pOpcode)
4532{
4533#if defined(DBG_TARGET_X86) || defined(DBG_TARGET_AMD64)
4534 // Read out opcode. 1 byte on x86
4535 BYTE opcode;
4536#elif defined(DBG_TARGET_ARM64)
4537 // Read out opcode. 4 bytes on arm64
4538 PRD_TYPE opcode;
4539#else
4540 BYTE opcode;
4541 PORTABILITY_ASSERT("NYI: ApplyRemotePatch for this platform");
4542#endif
4543
4544 HRESULT hr = pProcess->SafeReadStruct(PTR_TO_CORDB_ADDRESS(pRemoteAddress), &opcode);
4545 if (FAILED(hr))
4546 {
4547 return hr;
4548 }
4549
4550 *pOpcode = (PRD_TYPE) opcode;
4551 ApplyRemotePatch(pProcess, pRemoteAddress);
4552 return S_OK;
4553}
4554
4555//-----------------------------------------------------------------------------
4556// Remove the int3 from the remote address
4557//-----------------------------------------------------------------------------
4558HRESULT RemoveRemotePatch(CordbProcess * pProcess, const void * pRemoteAddress, PRD_TYPE opcode)
4559{
4560#if defined(DBG_TARGET_X86) || defined(DBG_TARGET_AMD64)
4561 // Replace the BP w/ the opcode.
4562 BYTE opcode2 = (BYTE) opcode;
4563#elif defined(DBG_TARGET_ARM64)
4564 // 4 bytes on arm64
4565 PRD_TYPE opcode2 = opcode;
4566#else
4567 PRD_TYPE opcode2 = opcode;
4568 PORTABILITY_ASSERT("NYI: RemoveRemotePatch for this platform");
4569#endif
4570
4571 pProcess->SafeWriteStruct(PTR_TO_CORDB_ADDRESS(pRemoteAddress), &opcode2);
4572
4573 // This may fail because the module has been unloaded. In which case, the patch is also
4574 // gone so it makes sense to return success.
4575 return S_OK;
4576}
4577#endif // FEATURE_INTEROP_DEBUGGING
4578
4579//---------------------------------------------------------------------------------------
4580//
4581// Simple helper to return the SP value stored in a DebuggerREGDISPLAY.
4582//
4583// Arguments:
4584// pDRD - the DebuggerREGDISPLAY in question
4585//
4586// Return Value:
4587// the SP value
4588//
4589
4590inline CORDB_ADDRESS GetSPFromDebuggerREGDISPLAY(DebuggerREGDISPLAY* pDRD)
4591{
4592 return pDRD->SP;
4593}
4594
4595
4596HRESULT CordbContext::QueryInterface(REFIID id, void **pInterface)
4597{
4598 if (id == IID_ICorDebugContext)
4599 *pInterface = static_cast<ICorDebugContext*>(this);
4600 else if (id == IID_IUnknown)
4601 *pInterface = static_cast<IUnknown*>(static_cast<ICorDebugContext*>(this));
4602 else
4603 {
4604 *pInterface = NULL;
4605 return E_NOINTERFACE;
4606 }
4607
4608 AddRef();
4609 return S_OK;
4610}
4611
4612
4613/* ------------------------------------------------------------------------- *
4614 * Frame class
4615 * ------------------------------------------------------------------------- */
4616
4617
4618// This is just used as a proxy object to pass a FramePointer around.
4619CordbFrame::CordbFrame(CordbProcess * pProcess, FramePointer fp)
4620 : CordbBase(pProcess, 0, enumCordbFrame),
4621 m_fp(fp)
4622{
4623 UnsafeNeuterDeadObject(); // mark as neutered.
4624}
4625
4626
4627CordbFrame::CordbFrame(CordbThread * pThread,
4628 FramePointer fp,
4629 SIZE_T ip,
4630 CordbAppDomain * pCurrentAppDomain)
4631 : CordbBase(pThread->GetProcess(), 0, enumCordbFrame),
4632 m_ip(ip),
4633 m_pThread(pThread),
4634 m_currentAppDomain(pCurrentAppDomain),
4635 m_fp(fp)
4636{
4637#ifdef _DEBUG
4638 // For debugging purposes, track what Continue session these frames were created in.
4639 m_DbgContinueCounter = GetProcess()->m_continueCounter;
4640#endif
4641
4642 HRESULT hr = S_OK;
4643 EX_TRY
4644 {
4645 m_pThread->GetRefreshStackNeuterList()->Add(GetProcess(), this);
4646 }
4647 EX_CATCH_HRESULT(hr);
4648 SetUnrecoverableIfFailed(GetProcess(), hr);
4649}
4650
4651
4652CordbFrame::~CordbFrame()
4653{
4654 _ASSERTE(IsNeutered());
4655}
4656
4657// Neutered by DerivedClasses
4658void CordbFrame::Neuter()
4659{
4660 CordbBase::Neuter();
4661}
4662
4663
4664HRESULT CordbFrame::QueryInterface(REFIID id, void **pInterface)
4665{
4666 if (id == IID_ICorDebugFrame)
4667 *pInterface = static_cast<ICorDebugFrame*>(this);
4668 else if (id == IID_IUnknown)
4669 *pInterface = static_cast<IUnknown*>(static_cast<ICorDebugFrame*>(this));
4670 else
4671 {
4672 *pInterface = NULL;
4673 return E_NOINTERFACE;
4674 }
4675
4676 ExternalAddRef();
4677 return S_OK;
4678}
4679
4680// ----------------------------------------------------------------------------
4681// CordbFrame::GetChain
4682//
4683// Description:
4684// Return the owning chain. Since chains have been deprecated in Arrowhead,
4685// this function returns E_NOTIMPL unless there is a shim.
4686//
4687// Arguments:
4688// * ppChain - out parameter; return the owning chain
4689//
4690// Return Value:
4691// Return S_OK on success.
4692// Return E_INVALIDARG if ppChain is NULL.
4693// Return CORDBG_E_OBJECT_NEUTERED if the CordbFrame is neutered.
4694// Return E_NOTIMPL if there is no shim.
4695// Return E_FAIL if failed to find the chain
4696//
4697
4698HRESULT CordbFrame::GetChain(ICorDebugChain **ppChain)
4699{
4700 HRESULT hr = S_OK;
4701 PUBLIC_REENTRANT_API_BEGIN(this)
4702 {
4703 ValidateOrThrow(ppChain);
4704 *ppChain = NULL;
4705
4706 if (GetProcess()->GetShim() != NULL)
4707 {
4708 PUBLIC_CALLBACK_IN_THIS_SCOPE0(GetProcess(), GET_PUBLIC_LOCK_HOLDER());
4709 ShimStackWalk * pSSW = GetProcess()->GetShim()->LookupOrCreateShimStackWalk(m_pThread);
4710 pSSW->GetChainForFrame(static_cast<ICorDebugFrame *>(this), ppChain);
4711
4712 if (*ppChain == NULL)
4713 hr = E_FAIL;
4714 }
4715 else
4716 {
4717 // This is the Arrowhead case, where ICDChain has been deprecated.
4718 hr = E_NOTIMPL;
4719 }
4720 }
4721 PUBLIC_REENTRANT_API_END(hr);
4722 return hr;
4723}
4724
4725
4726// Return the stack range taken up by this frame.
4727// Note that this is not implemented in the base CordbFrame class.
4728// Instead, this is implemented by the derived classes.
4729// The start of the stack range is the leafmost boundary, and the end is the rootmost boundary.
4730//
4731// Notes: see code:#GetStackRange
4732HRESULT CordbFrame::GetStackRange(CORDB_ADDRESS *pStart, CORDB_ADDRESS *pEnd)
4733{
4734 HRESULT hr = S_OK;
4735 PUBLIC_REENTRANT_API_BEGIN(this)
4736 {
4737 ValidateOrThrow(pStart);
4738 ValidateOrThrow(pEnd);
4739
4740 hr = E_NOTIMPL;
4741 }
4742 PUBLIC_REENTRANT_API_END(hr);
4743 return hr;
4744}
4745
4746// Return the ICorDebugFunction associated with this frame.
4747// There is one ICorDebugFunction for each EnC version of a method.
4748HRESULT CordbFrame::GetFunction(ICorDebugFunction **ppFunction)
4749{
4750 HRESULT hr = S_OK;
4751 PUBLIC_REENTRANT_API_BEGIN(this)
4752 {
4753 ValidateOrThrow(ppFunction);
4754
4755 CordbFunction * pFunc = this->GetFunction();
4756
4757 if (pFunc == NULL)
4758 {
4759 ThrowHR(CORDBG_E_CODE_NOT_AVAILABLE);
4760 }
4761
4762 // @dbgtodo LCG methods, IL stubs, dynamic language debugging
4763 // Don't return an ICDFunction if we are dealing with a dynamic method.
4764 // The dynamic debugging feature crew needs to decide exactly what to hand out for dynamic methods.
4765 if (pFunc->GetMetadataToken() == mdMethodDefNil)
4766 {
4767 ThrowHR(CORDBG_E_CODE_NOT_AVAILABLE);
4768 }
4769
4770 *ppFunction = static_cast<ICorDebugFunction *>(pFunc);
4771 pFunc->ExternalAddRef();
4772 }
4773 PUBLIC_REENTRANT_API_END(hr);
4774 return hr;
4775}
4776
4777// Return the token of the ICorDebugFunction associated with this frame.
4778// There is one ICorDebugFunction for each EnC version of a method.
4779HRESULT CordbFrame::GetFunctionToken(mdMethodDef *pToken)
4780{
4781 HRESULT hr = S_OK;
4782 PUBLIC_REENTRANT_API_BEGIN(this)
4783 {
4784 ValidateOrThrow(pToken);
4785
4786 CordbFunction * pFunc = GetFunction();
4787 if (pFunc == NULL)
4788 {
4789 hr = CORDBG_E_CODE_NOT_AVAILABLE;
4790 }
4791 else
4792 {
4793 *pToken = pFunc->GetMetadataToken();
4794 }
4795 }
4796 PUBLIC_REENTRANT_API_END(hr);
4797 return hr;
4798}
4799
4800// ----------------------------------------------------------------------------
4801// CordbFrame::GetCaller
4802//
4803// Description:
4804// Return the caller of this frame. The caller is closer to the root.
4805// This function has been deprecated in Arrowhead, and so it returns E_NOTIMPL unless there is a shim.
4806//
4807// Arguments:
4808// * ppFrame - out parameter; return the caller frame
4809//
4810// Return Value:
4811// Return S_OK on success.
4812// Return E_INVALIDARG if ppFrame is NULL.
4813// Return CORDBG_E_OBJECT_NEUTERED if the CordbFrame is neutered.
4814// Return E_NOTIMPL if there is no shim.
4815//
4816
4817HRESULT CordbFrame::GetCaller(ICorDebugFrame **ppFrame)
4818{
4819 HRESULT hr = S_OK;
4820 PUBLIC_REENTRANT_API_BEGIN(this)
4821 {
4822 ValidateOrThrow(ppFrame);
4823
4824 *ppFrame = NULL;
4825
4826 if (GetProcess()->GetShim() != NULL)
4827 {
4828 PUBLIC_CALLBACK_IN_THIS_SCOPE0(GetProcess(), GET_PUBLIC_LOCK_HOLDER());
4829 ShimStackWalk * pSSW = GetProcess()->GetShim()->LookupOrCreateShimStackWalk(m_pThread);
4830 pSSW->GetCallerForFrame(this, ppFrame);
4831 }
4832 else
4833 {
4834 *ppFrame = NULL;
4835 hr = E_NOTIMPL;
4836 }
4837 }
4838 PUBLIC_REENTRANT_API_END(hr);
4839 return hr;
4840}
4841
4842// ----------------------------------------------------------------------------
4843// CordbFrame::GetCallee
4844//
4845// Description:
4846// Return the callee of this frame. The callee is closer to the leaf.
4847// This function has been deprecated in Arrowhead, and so it returns E_NOTIMPL unless there is a shim.
4848//
4849// Arguments:
4850// * ppFrame - out parameter; return the callee frame
4851//
4852// Return Value:
4853// Return S_OK on success.
4854// Return E_INVALIDARG if ppFrame is NULL.
4855// Return CORDBG_E_OBJECT_NEUTERED if the CordbFrame is neutered.
4856// Return E_NOTIMPL if there is no shim.
4857//
4858
4859HRESULT CordbFrame::GetCallee(ICorDebugFrame **ppFrame)
4860{
4861 HRESULT hr = S_OK;
4862 PUBLIC_REENTRANT_API_BEGIN(this)
4863 {
4864 ValidateOrThrow(ppFrame);
4865
4866 *ppFrame = NULL;
4867
4868 if (GetProcess()->GetShim() != NULL)
4869 {
4870 PUBLIC_CALLBACK_IN_THIS_SCOPE0(GetProcess(), GET_PUBLIC_LOCK_HOLDER());
4871 ShimStackWalk * pSSW = GetProcess()->GetShim()->LookupOrCreateShimStackWalk(m_pThread);
4872 pSSW->GetCalleeForFrame(static_cast<ICorDebugFrame *>(this), ppFrame);
4873 }
4874 else
4875 {
4876 *ppFrame = NULL;
4877 hr = E_NOTIMPL;
4878 }
4879 }
4880 PUBLIC_REENTRANT_API_END(hr);
4881 return hr;
4882}
4883
4884// Create a stepper on the frame.
4885HRESULT CordbFrame::CreateStepper(ICorDebugStepper **ppStepper)
4886{
4887 PUBLIC_REENTRANT_API_ENTRY(this);
4888 FAIL_IF_NEUTERED(this);
4889 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
4890 VALIDATE_POINTER_TO_OBJECT(ppStepper, ICorDebugStepper **);
4891
4892 HRESULT hr = S_OK;
4893 EX_TRY
4894 {
4895 RSInitHolder<CordbStepper> pStepper(new CordbStepper(m_pThread, this));
4896 pStepper.TransferOwnershipExternal(ppStepper);
4897 }
4898 EX_CATCH_HRESULT(hr);
4899
4900 return hr;
4901}
4902
4903//---------------------------------------------------------------------------------------
4904//
4905// Given a frame pointer, determine if it is in the stack range owned by the frame.
4906//
4907// Arguments:
4908// fp - frame pointer to check
4909//
4910// Return Value:
4911// whether the specified frame pointer is in the stack range or not
4912//
4913
4914bool CordbFrame::IsContainedInFrame(FramePointer fp)
4915{
4916 CORDB_ADDRESS stackStart;
4917 CORDB_ADDRESS stackEnd;
4918
4919 // get the stack range
4920 HRESULT hr;
4921 hr = GetStackRange(&stackStart, &stackEnd);
4922 _ASSERTE(SUCCEEDED(hr));
4923
4924 CORDB_ADDRESS sp = PTR_TO_CORDB_ADDRESS(fp.GetSPValue());
4925
4926 if ((stackStart <= sp) && (sp <= stackEnd))
4927 {
4928 return true;
4929 }
4930 else
4931 {
4932 return false;
4933 }
4934}
4935
4936//---------------------------------------------------------------------------------------
4937//
4938// Given an ICorDebugFrame interface pointer, return a pointer to the base class CordbFrame.
4939//
4940// Arguments:
4941// pFrame - the ICorDebugFrame interface pointer
4942//
4943// Return Value:
4944// the CordbFrame pointer corresponding to the specified interface pointer
4945//
4946// Note:
4947// This is currently only used for continuable exceptions.
4948//
4949
4950// static
4951CordbFrame* CordbFrame::GetCordbFrameFromInterface(ICorDebugFrame *pFrame)
4952{
4953 CordbFrame* pTargetFrame = NULL;
4954
4955 if (pFrame != NULL)
4956 {
4957 // test for CordbNativeFrame
4958 RSExtSmartPtr<ICorDebugNativeFrame> pNativeFrame;
4959 pFrame->QueryInterface(IID_ICorDebugNativeFrame, (void**)&pNativeFrame);
4960 if (pNativeFrame != NULL)
4961 {
4962 pTargetFrame = static_cast<CordbFrame*>(static_cast<CordbNativeFrame*>(pNativeFrame.GetValue()));
4963 }
4964 else
4965 {
4966 // test for CordbJITILFrame
4967 RSExtSmartPtr<ICorDebugILFrame> pILFrame;
4968 pFrame->QueryInterface(IID_ICorDebugILFrame, (void**)&pILFrame);
4969 if (pILFrame != NULL)
4970 {
4971 pTargetFrame = (static_cast<CordbJITILFrame*>(pILFrame.GetValue()))->m_nativeFrame;
4972 }
4973 else
4974 {
4975 // test for CordbInternalFrame
4976 RSExtSmartPtr<ICorDebugInternalFrame> pInternalFrame;
4977 pFrame->QueryInterface(IID_ICorDebugInternalFrame, (void**)&pInternalFrame);
4978 if (pInternalFrame != NULL)
4979 {
4980 pTargetFrame = static_cast<CordbFrame*>(static_cast<CordbInternalFrame*>(pInternalFrame.GetValue()));
4981 }
4982 else
4983 {
4984 // when all else fails, this is just a CordbFrame
4985 pTargetFrame = static_cast<CordbFrame*>(pFrame);
4986 }
4987 }
4988 }
4989 }
4990 return pTargetFrame;
4991}
4992
4993
4994/* ------------------------------------------------------------------------- *
4995
4996 * Value Enumerator class
4997 *
4998 * Used by CordbJITILFrame for EnumLocalVars & EnumArgs.
4999 * NOTE NOTE NOTE WE ASSUME that the 'frame' argument is actually the
5000 * CordbJITILFrame's native frame member variable.
5001 * ------------------------------------------------------------------------- */
5002
5003CordbValueEnum::CordbValueEnum(CordbNativeFrame *frame, ValueEnumMode mode) :
5004 CordbBase(frame->GetProcess(), 0)
5005{
5006 _ASSERTE( frame != NULL );
5007 _ASSERTE( mode == LOCAL_VARS_ORIGINAL_IL || mode == LOCAL_VARS_REJIT_IL || mode == ARGS);
5008
5009 m_frame = frame;
5010 m_mode = mode;
5011 m_iCurrent = 0;
5012 m_iMax = 0;
5013}
5014
5015/*
5016 * CordbValueEnum::Init
5017 *
5018 * Initialize a CordbValueEnum object. Must be called after allocating the object and before using it. If Init
5019 * fails, then destroy the object and release the memory.
5020 *
5021 * Parameters:
5022 * none.
5023 *
5024 * Returns:
5025 * HRESULT for success or failure.
5026 *
5027 */
5028HRESULT CordbValueEnum::Init()
5029{
5030 HRESULT hr = S_OK;
5031 CordbNativeFrame *nil = m_frame;
5032 CordbJITILFrame *jil = nil->m_JITILFrame;
5033
5034 switch (m_mode)
5035 {
5036 case ARGS:
5037 {
5038 // Get the function signature
5039 CordbFunction *func = m_frame->GetFunction();
5040 ULONG methodArgCount;
5041
5042 IfFailRet(func->GetSig(NULL, &methodArgCount, NULL));
5043
5044 // Grab the argument count for the size of the enumeration.
5045 m_iMax = methodArgCount;
5046 if (jil->m_fVarArgFnx && !jil->m_sigParserCached.IsNull())
5047 {
5048 m_iMax = jil->m_allArgsCount;
5049 }
5050 break;
5051 }
5052 case LOCAL_VARS_ORIGINAL_IL:
5053 {
5054 // Get the locals signature.
5055 ULONG localsCount;
5056 IfFailRet(jil->GetOriginalILCode()->GetLocalVarSig(NULL, &localsCount));
5057
5058 // Grab the number of locals for the size of the enumeration.
5059 m_iMax = localsCount;
5060 break;
5061 }
5062 case LOCAL_VARS_REJIT_IL:
5063 {
5064 // Get the locals signature.
5065 ULONG localsCount;
5066 CordbReJitILCode* pCode = jil->GetReJitILCode();
5067 if (pCode == NULL)
5068 {
5069 m_iMax = 0;
5070 }
5071 else
5072 {
5073 IfFailRet(pCode->GetLocalVarSig(NULL, &localsCount));
5074
5075 // Grab the number of locals for the size of the enumeration.
5076 m_iMax = localsCount;
5077 }
5078 break;
5079 }
5080 }
5081 // Everything worked okay, so add this object to the neuter list for objects that are tied to the stack trace.
5082 EX_TRY
5083 {
5084 m_frame->m_pThread->GetRefreshStackNeuterList()->Add(GetProcess(), this);
5085 }
5086 EX_CATCH_HRESULT(hr);
5087 SetUnrecoverableIfFailed(GetProcess(), hr);
5088
5089 return hr;
5090}
5091
5092CordbValueEnum::~CordbValueEnum()
5093{
5094 _ASSERTE(this->IsNeutered());
5095 _ASSERTE(m_frame == NULL);
5096}
5097
5098void CordbValueEnum::Neuter()
5099{
5100 m_frame = NULL;
5101 CordbBase::Neuter();
5102}
5103
5104
5105
5106HRESULT CordbValueEnum::QueryInterface(REFIID id, void **pInterface)
5107{
5108 if (id == IID_ICorDebugEnum)
5109 *pInterface = static_cast<ICorDebugEnum*>(this);
5110 else if (id == IID_ICorDebugValueEnum)
5111 *pInterface = static_cast<ICorDebugValueEnum*>(this);
5112 else if (id == IID_IUnknown)
5113 *pInterface = static_cast<IUnknown*>(static_cast<ICorDebugValueEnum*>(this));
5114 else
5115 {
5116 *pInterface = NULL;
5117 return E_NOINTERFACE;
5118 }
5119
5120 ExternalAddRef();
5121 return S_OK;
5122}
5123
5124HRESULT CordbValueEnum::Skip(ULONG celt)
5125{
5126 PUBLIC_REENTRANT_API_ENTRY(this);
5127 FAIL_IF_NEUTERED(this);
5128 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
5129
5130 HRESULT hr = E_FAIL;
5131 if ( (m_iCurrent+celt) < m_iMax ||
5132 celt == 0)
5133 {
5134 m_iCurrent += celt;
5135 hr = S_OK;
5136 }
5137
5138 return hr;
5139}
5140
5141HRESULT CordbValueEnum::Reset()
5142{
5143 PUBLIC_REENTRANT_API_ENTRY(this);
5144 FAIL_IF_NEUTERED(this);
5145 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
5146
5147 m_iCurrent = 0;
5148 return S_OK;
5149}
5150
5151HRESULT CordbValueEnum::Clone(ICorDebugEnum **ppEnum)
5152{
5153 PUBLIC_REENTRANT_API_ENTRY(this);
5154 FAIL_IF_NEUTERED(this);
5155 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
5156
5157 VALIDATE_POINTER_TO_OBJECT(ppEnum, ICorDebugEnum **);
5158
5159 HRESULT hr = S_OK;
5160 EX_TRY
5161 {
5162 *ppEnum = NULL;
5163 RSInitHolder<CordbValueEnum> pCVE(new CordbValueEnum(m_frame, m_mode));
5164
5165 // Initialize the new enum
5166 hr = pCVE->Init();
5167 IfFailThrow(hr);
5168
5169 pCVE.TransferOwnershipExternal(ppEnum);
5170 }
5171 EX_CATCH_HRESULT(hr);
5172
5173 return hr;
5174}
5175
5176HRESULT CordbValueEnum::GetCount(ULONG *pcelt)
5177{
5178 PUBLIC_REENTRANT_API_ENTRY(this);
5179 FAIL_IF_NEUTERED(this);
5180 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
5181
5182 VALIDATE_POINTER_TO_OBJECT(pcelt, ULONG *);
5183
5184 if( pcelt == NULL)
5185 {
5186 return E_INVALIDARG;
5187 }
5188
5189 (*pcelt) = m_iMax;
5190 return S_OK;
5191}
5192
5193//
5194// In the event of failure, the current pointer will be left at
5195// one element past the troublesome element. Thus, if one were
5196// to repeatedly ask for one element to iterate through the
5197// array, you would iterate exactly m_iMax times, regardless
5198// of individual failures.
5199HRESULT CordbValueEnum::Next(ULONG celt, ICorDebugValue *values[], ULONG *pceltFetched)
5200{
5201 PUBLIC_API_ENTRY(this);
5202 FAIL_IF_NEUTERED(this);
5203 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
5204
5205 VALIDATE_POINTER_TO_OBJECT_ARRAY(values, ICorDebugValue *,
5206 celt, true, true);
5207 VALIDATE_POINTER_TO_OBJECT_OR_NULL(pceltFetched, ULONG *);
5208
5209 if ((pceltFetched == NULL) && (celt != 1))
5210 {
5211 return E_INVALIDARG;
5212 }
5213
5214 if (celt == 0)
5215 {
5216 if (pceltFetched != NULL)
5217 {
5218 *pceltFetched = 0;
5219 }
5220 return S_OK;
5221 }
5222
5223 HRESULT hr = S_OK;
5224
5225 int iMax = min( m_iMax, m_iCurrent+celt);
5226 int i;
5227 for (i = m_iCurrent; i< iMax;i++)
5228 {
5229 switch ( m_mode )
5230 {
5231 case ARGS:
5232 {
5233 hr = m_frame->m_JITILFrame->GetArgument( i, &(values[i-m_iCurrent]) );
5234 break;
5235 }
5236 case LOCAL_VARS_ORIGINAL_IL:
5237 {
5238 hr = m_frame->m_JITILFrame->GetLocalVariableEx(ILCODE_ORIGINAL_IL, i, &(values[i-m_iCurrent]) );
5239 break;
5240 }
5241 case LOCAL_VARS_REJIT_IL:
5242 {
5243 hr = m_frame->m_JITILFrame->GetLocalVariableEx(ILCODE_REJIT_IL, i, &(values[i - m_iCurrent]));
5244 break;
5245 }
5246 }
5247 if ( FAILED( hr ) )
5248 {
5249 break;
5250 }
5251 }
5252
5253 int count = (i - m_iCurrent);
5254
5255 if ( FAILED( hr ) )
5256 {
5257 //
5258 // we failed: +1 pushes us past troublesome element
5259 //
5260 m_iCurrent += 1 + count;
5261 }
5262 else
5263 {
5264 m_iCurrent += count;
5265 }
5266
5267 if (pceltFetched != NULL)
5268 {
5269 *pceltFetched = count;
5270 }
5271
5272 if (FAILED(hr))
5273 {
5274 return hr;
5275 }
5276
5277
5278 //
5279 // If we reached the end of the enumeration, but not the end
5280 // of the number of requested items, we return S_FALSE.
5281 //
5282 if (((ULONG)count) < celt)
5283 {
5284 return S_FALSE;
5285 }
5286
5287 return hr;
5288}
5289
5290
5291//-----------------------------------------------------------------------------
5292// CordbInternalFrame
5293//-----------------------------------------------------------------------------
5294CordbInternalFrame::CordbInternalFrame(CordbThread * pThread,
5295 FramePointer fp,
5296 CordbAppDomain * pCurrentAppDomain,
5297 const DebuggerIPCE_STRData * pData)
5298 : CordbFrame(pThread, fp, 0, pCurrentAppDomain)
5299{
5300 CONTRACTL
5301 {
5302 THROWS;
5303 }
5304 CONTRACTL_END;
5305
5306 m_eFrameType = pData->stubFrame.frameType;
5307 m_funcMetadataToken = pData->stubFrame.funcMetadataToken;
5308 m_vmMethodDesc = pData->stubFrame.vmMethodDesc;
5309
5310 // Some internal frames may not have a Function associated w/ them.
5311 if (!IsNilToken(m_funcMetadataToken))
5312 {
5313 // Find the module of the function. Note that this module isn't necessarily in the same domain as our frame.
5314 // FuncEval frames can point to methods they are going to invoke in another domain.
5315 CordbModule * pModule = NULL;
5316 pModule = GetProcess()->LookupOrCreateModule(pData->stubFrame.vmDomainFile);
5317 _ASSERTE(pModule != NULL);
5318
5319 //
5320 if( pModule != NULL )
5321 {
5322 _ASSERTE( (pModule->GetAppDomain() == pCurrentAppDomain) || (m_eFrameType == STUBFRAME_FUNC_EVAL) );
5323
5324
5325
5326 mdMethodDef token = pData->stubFrame.funcMetadataToken;
5327
5328 // @dbgtodo synchronization - push this up.
5329 RSLockHolder lockHolder(GetProcess()->GetProcessLock());
5330
5331 // CordbInternalFrame could handle a null function.
5332 // But if we fail to lookup, things are not in a good state anyways.
5333 CordbFunction * pFunction = pModule->LookupOrCreateFunctionLatestVersion(token);
5334 m_function.Assign(pFunction);
5335
5336 }
5337 }
5338}
5339
5340CordbInternalFrame::CordbInternalFrame(CordbThread * pThread,
5341 FramePointer fp,
5342 CordbAppDomain * pCurrentAppDomain,
5343 CorDebugInternalFrameType frameType,
5344 mdMethodDef funcMetadataToken,
5345 CordbFunction * pFunction,
5346 VMPTR_MethodDesc vmMethodDesc)
5347 : CordbFrame(pThread, fp, 0, pCurrentAppDomain)
5348{
5349 m_eFrameType = frameType;
5350 m_funcMetadataToken = funcMetadataToken;
5351 m_function.Assign(pFunction);
5352 m_vmMethodDesc = vmMethodDesc;
5353}
5354
5355HRESULT CordbInternalFrame::QueryInterface(REFIID id, void **pInterface)
5356{
5357 if (id == IID_ICorDebugFrame)
5358 {
5359 *pInterface = static_cast<ICorDebugFrame*>(static_cast<ICorDebugInternalFrame*>(this));
5360 }
5361 else if (id == IID_ICorDebugInternalFrame)
5362 {
5363 *pInterface = static_cast<ICorDebugInternalFrame*>(this);
5364 }
5365 else if (id == IID_ICorDebugInternalFrame2)
5366 {
5367 *pInterface = static_cast<ICorDebugInternalFrame2*>(this);
5368 }
5369 else if (id == IID_IUnknown)
5370 {
5371 *pInterface = static_cast<IUnknown*>(static_cast<ICorDebugInternalFrame*>(this));
5372 }
5373 else
5374 {
5375 *pInterface = NULL;
5376 return E_NOINTERFACE;
5377 }
5378
5379 ExternalAddRef();
5380 return S_OK;
5381}
5382
5383void CordbInternalFrame::Neuter()
5384{
5385 m_function.Clear();
5386 CordbFrame::Neuter();
5387}
5388
5389
5390// ----------------------------------------------------------------------------
5391// CordbInternalFrame::GetStackRange
5392//
5393// Description:
5394// Return the stack range owned by this frame.
5395// The start of the stack range is the leafmost boundary, and the end is the rootmost boundary.
5396//
5397// Arguments:
5398// * pStart - out parameter; return the leaf end of the frame
5399// * pEnd - out parameter; return the root end of the frame
5400//
5401// Return Value:
5402// Return S_OK on success.
5403//
5404// Notes:
5405// #GetStackRange
5406// This is a virtual function and so there are multiple implementations for different types of frames.
5407// It's very important to note that GetStackRange() can work when even after the frame is neutered.
5408// Debuggers may rely on this to map old frames up to new frames across Continue() calls.
5409//
5410
5411HRESULT CordbInternalFrame::GetStackRange(CORDB_ADDRESS *pStart,
5412 CORDB_ADDRESS *pEnd)
5413{
5414 PUBLIC_REENTRANT_API_ENTRY(this);
5415
5416 // Callers explicit require GetStackRange() to be callable when neutered so that they
5417 // can line up ICorDebugFrame objects across continues. We only return stack ranges
5418 // here and don't access any special data.
5419 OK_IF_NEUTERED(this);
5420
5421 if (GetProcess()->GetShim() != NULL)
5422 {
5423 CORDB_ADDRESS pFramePointer = PTR_TO_CORDB_ADDRESS(GetFramePointer().GetSPValue());
5424 if (pStart)
5425 {
5426 *pStart = pFramePointer;
5427 }
5428 if (pEnd)
5429 {
5430 *pEnd = pFramePointer;
5431 }
5432 return S_OK;
5433 }
5434 else
5435 {
5436 if (pStart != NULL)
5437 {
5438 *pStart = NULL;
5439 }
5440 if (pEnd != NULL)
5441 {
5442 *pEnd = NULL;
5443 }
5444 return E_NOTIMPL;
5445 }
5446}
5447
5448
5449// This may return NULL if there's no Method associated w/ this Frame.
5450// For FuncEval frames, the function returned might also be in a different AppDomain
5451// than the frame itself.
5452CordbFunction * CordbInternalFrame::GetFunction()
5453{
5454 return m_function;
5455}
5456
5457// Accessor for the shim private hook code:CordbThread::ConvertFrameForILMethodWithoutMetadata.
5458// Refer to that function for comments on the return value, the argument, etc.
5459BOOL CordbInternalFrame::ConvertInternalFrameForILMethodWithoutMetadata(
5460 ICorDebugInternalFrame2 ** ppInternalFrame2)
5461{
5462 _ASSERTE(ppInternalFrame2 != NULL);
5463 *ppInternalFrame2 = NULL;
5464
5465 // The only internal frame conversion we need to perform is from STUBFRAME_JIT_COMPILATION to
5466 // STUBFRAME_LIGTHWEIGHT_FUNCTION.
5467 if (m_eFrameType != STUBFRAME_JIT_COMPILATION)
5468 {
5469 return FALSE;
5470 }
5471
5472 // Check whether the internal frame has an associated MethodDesc.
5473 // Currently, the only STUBFRAME_JIT_COMPILATION frame with a NULL MethodDesc is ComPrestubMethodFrame,
5474 // which is not exposed in Whidbey. So convert it according to rule #2 below.
5475 if (m_vmMethodDesc.IsNull())
5476 {
5477 return TRUE;
5478 }
5479
5480 // Retrieve the type of the method associated with the STUBFRAME_JIT_COMPILATION.
5481 IDacDbiInterface::DynamicMethodType type = GetProcess()->GetDAC()->IsILStubOrLCGMethod(m_vmMethodDesc);
5482
5483 // Here are the conversion rules:
5484 // 1) For a normal managed method, we don't convert, and we return FALSE.
5485 // 2) For an IL stub, we convert to NULL, and we return TRUE.
5486 // 3) For a dynamic method, we convert to a STUBFRAME_LIGHTWEIGHT_FUNCTION, and we return TRUE.
5487 if (type == IDacDbiInterface::kNone)
5488 {
5489 return FALSE;
5490 }
5491 else if (type == IDacDbiInterface::kILStub)
5492 {
5493 return TRUE;
5494 }
5495 else if (type == IDacDbiInterface::kLCGMethod)
5496 {
5497 // Here we are basically cloning another CordbInternalFrame.
5498 RSInitHolder<CordbInternalFrame> pInternalFrame(new CordbInternalFrame(m_pThread,
5499 m_fp,
5500 m_currentAppDomain,
5501 STUBFRAME_LIGHTWEIGHT_FUNCTION,
5502 m_funcMetadataToken,
5503 m_function.GetValue(),
5504 m_vmMethodDesc));
5505 pInternalFrame.TransferOwnershipExternal(ppInternalFrame2);
5506 return TRUE;
5507 }
5508
5509 UNREACHABLE();
5510}
5511
5512
5513//---------------------------------------------------------------------------------------
5514//
5515// Returns the address of an internal frame. The address is a stack pointer, even on IA64.
5516//
5517// Arguments:
5518// pAddress - out parameter; return the frame marker address
5519//
5520// Return Value:
5521// S_OK on success.
5522// E_INVALIDARG if pAddress is NULL.
5523//
5524
5525HRESULT CordbInternalFrame::GetAddress(CORDB_ADDRESS * pAddress)
5526{
5527 PUBLIC_REENTRANT_API_ENTRY(this);
5528 FAIL_IF_NEUTERED(this);
5529
5530 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
5531
5532 if (pAddress == NULL)
5533 {
5534 return E_INVALIDARG;
5535 }
5536
5537 *pAddress = PTR_TO_CORDB_ADDRESS(GetFramePointer().GetSPValue());
5538 return S_OK;
5539}
5540
5541//---------------------------------------------------------------------------------------
5542//
5543// Refer to the comment for code:CordbInternalFrame::IsCloserToLeaf
5544//
5545
5546BOOL CordbInternalFrame::IsCloserToLeafWorker(ICorDebugFrame * pFrameToCompare)
5547{
5548 // Get the address of the "this" internal frame.
5549 CORDB_ADDRESS thisFrameAddr = PTR_TO_CORDB_ADDRESS(this->GetFramePointer().GetSPValue());
5550
5551 // Note that a QI on ICorDebugJITILFrame for ICorDebugNativeFrame will work.
5552 RSExtSmartPtr<ICorDebugNativeFrame> pNativeFrame;
5553 pFrameToCompare->QueryInterface(IID_ICorDebugNativeFrame, (void **)&pNativeFrame);
5554 if (pNativeFrame != NULL)
5555 {
5556 // The frame to compare is a CordbNativeFrame.
5557 CordbNativeFrame * pCNativeFrame = static_cast<CordbNativeFrame *>(pNativeFrame.GetValue());
5558
5559 // Compare the address of the "this" internal frame to the SP of the stack frame.
5560 // We can't compare frame pointers because the frame pointer means different things on
5561 // different platforms.
5562 CORDB_ADDRESS stackFrameSP = GetSPFromDebuggerREGDISPLAY(&(pCNativeFrame->m_rd));
5563 return (thisFrameAddr < stackFrameSP);
5564 }
5565
5566 RSExtSmartPtr<ICorDebugRuntimeUnwindableFrame> pRUFrame;
5567 pFrameToCompare->QueryInterface(IID_ICorDebugRuntimeUnwindableFrame, (void **)&pRUFrame);
5568 if (pRUFrame != NULL)
5569 {
5570 // The frame to compare is a CordbRuntimeUnwindableFrame.
5571 CordbRuntimeUnwindableFrame * pCRUFrame =
5572 static_cast<CordbRuntimeUnwindableFrame *>(pRUFrame.GetValue());
5573
5574 DT_CONTEXT * pResumeContext = const_cast<DT_CONTEXT *>(pCRUFrame->GetContext());
5575 CORDB_ADDRESS stackFrameSP = PTR_TO_CORDB_ADDRESS(CORDbgGetSP(pResumeContext));
5576 return (thisFrameAddr < stackFrameSP);
5577 }
5578
5579 RSExtSmartPtr<ICorDebugInternalFrame> pInternalFrame;
5580 pFrameToCompare->QueryInterface(IID_ICorDebugInternalFrame, (void **)&pInternalFrame);
5581 if (pInternalFrame != NULL)
5582 {
5583 // The frame to compare is a CordbInternalFrame.
5584 CordbInternalFrame * pCInternalFrame =
5585 static_cast<CordbInternalFrame *>(pInternalFrame.GetValue());
5586
5587 CORDB_ADDRESS frameAddr = PTR_TO_CORDB_ADDRESS(pCInternalFrame->GetFramePointer().GetSPValue());
5588 return (thisFrameAddr < frameAddr);
5589 }
5590
5591 // What does this mean? This is unexpected.
5592 _ASSERTE(!"CIF::ICTLW - Unexpected frame type.\n");
5593 ThrowHR(E_FAIL);
5594}
5595
5596//---------------------------------------------------------------------------------------
5597//
5598// Checks whether the "this" internal frame is closer to the leaf than the specified ICDFrame.
5599// If the specified ICDFrame represents a stack frame, then we compare the address of the "this"
5600// internal frame against the SP of the stack frame.
5601//
5602// Arguments:
5603// pFrameToCompare - the ICDFrame to compare against
5604// pIsCloser - out parameter; returns TRUE if the "this" internal frame is closer to the leaf
5605//
5606// Return Value:
5607// S_OK on success.
5608// E_INVALIDARG if pFrameToCompare or pIsCloser is NULL.
5609// E_FAIL if pFrameToCompare is bogus.
5610//
5611// Notes:
5612// This function doesn't deal with the backing store at all.
5613//
5614
5615HRESULT CordbInternalFrame::IsCloserToLeaf(ICorDebugFrame * pFrameToCompare,
5616 BOOL * pIsCloser)
5617{
5618 HRESULT hr = S_OK;
5619 PUBLIC_REENTRANT_API_BEGIN(this);
5620 {
5621 ValidateOrThrow(pFrameToCompare);
5622 ValidateOrThrow(pIsCloser);
5623
5624 *pIsCloser = IsCloserToLeafWorker(pFrameToCompare);
5625 }
5626 PUBLIC_REENTRANT_API_END(hr);
5627 return hr;
5628}
5629
5630
5631CordbRuntimeUnwindableFrame::CordbRuntimeUnwindableFrame(CordbThread * pThread,
5632 FramePointer fp,
5633 CordbAppDomain * pCurrentAppDomain,
5634 DT_CONTEXT * pContext)
5635 : CordbFrame(pThread, fp, 0, pCurrentAppDomain),
5636 m_context(*pContext)
5637{
5638}
5639
5640void CordbRuntimeUnwindableFrame::Neuter()
5641{
5642 CordbFrame::Neuter();
5643}
5644
5645HRESULT CordbRuntimeUnwindableFrame::QueryInterface(REFIID id, void ** ppInterface)
5646{
5647 if (id == IID_ICorDebugFrame)
5648 {
5649 *ppInterface = static_cast<ICorDebugFrame *>(static_cast<ICorDebugRuntimeUnwindableFrame *>(this));
5650 }
5651 else if (id == IID_ICorDebugRuntimeUnwindableFrame)
5652 {
5653 *ppInterface = static_cast<ICorDebugRuntimeUnwindableFrame *>(this);
5654 }
5655 else if (id == IID_IUnknown)
5656 {
5657 *ppInterface = static_cast<IUnknown *>(static_cast<ICorDebugRuntimeUnwindableFrame *>(this));
5658 }
5659 else
5660 {
5661 *ppInterface = NULL;
5662 return E_NOINTERFACE;
5663 }
5664
5665 ExternalAddRef();
5666 return S_OK;
5667}
5668
5669//---------------------------------------------------------------------------------------
5670//
5671// Returns the CONTEXT corresponding to this CordbRuntimeUnwindableFrame.
5672//
5673// Return Value:
5674// Return a pointer to the CONTEXT.
5675//
5676
5677const DT_CONTEXT * CordbRuntimeUnwindableFrame::GetContext() const
5678{
5679 return &m_context;
5680}
5681
5682
5683// default constructor to make the compiler happy
5684CordbMiscFrame::CordbMiscFrame()
5685{
5686#ifdef WIN64EXCEPTIONS
5687 this->parentIP = 0;
5688 this->fpParentOrSelf = LEAF_MOST_FRAME;
5689 this->fIsFilterFunclet = false;
5690#endif // WIN64EXCEPTIONS
5691}
5692
5693// the real constructor which stores the funclet-related information in the CordbMiscFrame
5694CordbMiscFrame::CordbMiscFrame(DebuggerIPCE_JITFuncData * pJITFuncData)
5695{
5696#ifdef WIN64EXCEPTIONS
5697 this->parentIP = pJITFuncData->parentNativeOffset;
5698 this->fpParentOrSelf = pJITFuncData->fpParentOrSelf;
5699 this->fIsFilterFunclet = (pJITFuncData->fIsFilterFrame == TRUE);
5700#endif // WIN64EXCEPTIONS
5701}
5702
5703/* ------------------------------------------------------------------------- *
5704 * Native Frame class
5705 * ------------------------------------------------------------------------- */
5706
5707
5708CordbNativeFrame::CordbNativeFrame(CordbThread * pThread,
5709 FramePointer fp,
5710 CordbNativeCode * pNativeCode,
5711 SIZE_T ip,
5712 DebuggerREGDISPLAY * pDRD,
5713 TADDR taAmbientESP,
5714 bool fQuicklyUnwound,
5715 CordbAppDomain * pCurrentAppDomain,
5716 CordbMiscFrame * pMisc /*= NULL*/,
5717 DT_CONTEXT * pContext /*= NULL*/)
5718 : CordbFrame(pThread, fp, ip, pCurrentAppDomain),
5719 m_rd(*pDRD),
5720 m_quicklyUnwound(fQuicklyUnwound),
5721 m_JITILFrame(NULL),
5722 m_nativeCode(pNativeCode), // implicit InternalAddRef
5723 m_taAmbientESP(taAmbientESP)
5724{
5725 m_misc = *pMisc;
5726
5727 // Only new CordbNativeFrames created by the new stackwalk contain a CONTEXT.
5728 _ASSERTE(pContext != NULL);
5729 m_context = *pContext;
5730}
5731
5732/*
5733 A list of which resources owned by this object are accounted for.
5734
5735 RESOLVED:
5736 CordbJITILFrame* m_JITILFrame; // Neutered
5737*/
5738
5739CordbNativeFrame::~CordbNativeFrame()
5740{
5741 _ASSERTE(IsNeutered());
5742}
5743
5744// Neutered by CordbThread::CleanupStack
5745void CordbNativeFrame::Neuter()
5746{
5747 // Neuter may be called multiple times so be sure to set ptrs to NULL so that we don't
5748 // double release them.
5749 if (IsNeutered())
5750 {
5751 return;
5752 }
5753
5754 m_nativeCode.Clear();
5755
5756 if (m_JITILFrame != NULL)
5757 {
5758 m_JITILFrame->Neuter();
5759 m_JITILFrame.Clear();
5760 }
5761
5762 CordbFrame::Neuter();
5763}
5764
5765// CordbNativeFrame::QueryInterface
5766//
5767// Description
5768// interface query for this COM object
5769//
5770// NOTE: the COM object associated with this CordbNativeFrame may consist of
5771// two C++ objects (the CordbNativeFrame and the CordbJITILFrame).
5772//
5773// Parameters
5774// id the GUID associated with the requested interface
5775// pInterface [out] the interface pointer
5776//
5777// Returns
5778// HRESULT
5779// S_OK If this CordbJITILFrame supports the interface
5780// E_NOINTERFACE If this object does not support the interface
5781//
5782// Exceptions
5783// None
5784//
5785//
5786HRESULT CordbNativeFrame::QueryInterface(REFIID id, void **pInterface)
5787{
5788 if (id == IID_ICorDebugFrame)
5789 {
5790 *pInterface = static_cast<ICorDebugFrame*>(static_cast<ICorDebugNativeFrame*>(this));
5791 }
5792 else if (id == IID_ICorDebugNativeFrame)
5793 {
5794 *pInterface = static_cast<ICorDebugNativeFrame*>(this);
5795 }
5796 else if (id == IID_ICorDebugNativeFrame2)
5797 {
5798 *pInterface = static_cast<ICorDebugNativeFrame2*>(this);
5799 }
5800 else if (id == IID_IUnknown)
5801 {
5802 *pInterface = static_cast<IUnknown*>(static_cast<ICorDebugNativeFrame*>(this));
5803 }
5804 else
5805 {
5806 // might be searching for an IL Frame. delegate that search to the
5807 // JITILFrame
5808 if (m_JITILFrame != NULL)
5809 {
5810 return m_JITILFrame->QueryInterfaceInternal(id, pInterface);
5811 }
5812 else
5813 {
5814 *pInterface = NULL;
5815 return E_NOINTERFACE;
5816 }
5817 }
5818
5819 ExternalAddRef();
5820 return S_OK;
5821}
5822
5823// Return the CordbNativeCode object associated with this native frame.
5824// This is just a wrapper around the real helper.
5825HRESULT CordbNativeFrame::GetCode(ICorDebugCode **ppCode)
5826{
5827 PUBLIC_API_ENTRY(this);
5828 VALIDATE_POINTER_TO_OBJECT(ppCode, ICorDebugCode **);
5829 FAIL_IF_NEUTERED(this);
5830
5831 CordbNativeCode * pCode = GetNativeCode();
5832 *ppCode = static_cast<ICorDebugCode*> (pCode);
5833 pCode->ExternalAddRef();
5834
5835 return S_OK;;
5836}
5837
5838//---------------------------------------------------------------------------------------
5839//
5840// Returns the CONTEXT corresponding to this CordbNativeFrame.
5841//
5842// Return Value:
5843// Return a pointer to the CONTEXT.
5844//
5845
5846const DT_CONTEXT * CordbNativeFrame::GetContext() const
5847{
5848 return &m_context;
5849}
5850
5851//---------------------------------------------------------------------------------------
5852//
5853// This is an internal helper to get the CordbNativeCode object associated with this native frame.
5854//
5855// Return Value:
5856// the associated CordbNativeCode object
5857//
5858
5859CordbNativeCode * CordbNativeFrame::GetNativeCode()
5860{
5861 return this->m_nativeCode;
5862}
5863
5864//---------------------------------------------------------------------------------------
5865//
5866// This is an internal helper to get the CordbFunction object associated with this native frame.
5867//
5868// Return Value:
5869// the associated CordbFunction object
5870//
5871
5872CordbFunction *CordbNativeFrame::GetFunction()
5873{
5874 return this->m_nativeCode->GetFunction();
5875}
5876
5877
5878
5879// Return the native offset.
5880HRESULT CordbNativeFrame::GetIP(ULONG32 *pnOffset)
5881{
5882 PUBLIC_REENTRANT_API_ENTRY(this);
5883 FAIL_IF_NEUTERED(this);
5884 VALIDATE_POINTER_TO_OBJECT(pnOffset, ULONG32 *);
5885
5886 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
5887
5888 *pnOffset = (ULONG32)m_ip;
5889
5890 return S_OK;
5891}
5892
5893ULONG32 CordbNativeFrame::GetIPOffset()
5894{
5895 return (ULONG32)m_ip;
5896}
5897
5898TADDR CordbNativeFrame::GetReturnRegisterValue()
5899{
5900#if defined(DBG_TARGET_X86)
5901 return (TADDR)m_context.Eax;
5902#elif defined(DBG_TARGET_AMD64)
5903 return (TADDR)m_context.Rax;
5904#elif defined(DBG_TARGET_ARM)
5905 return (TADDR)m_context.R0;
5906#elif defined(DBG_TARGET_ARM64)
5907 return (TADDR)m_context.X0;
5908#else
5909 _ASSERTE(!"nyi for platform");
5910 return 0;
5911#endif
5912}
5913
5914// Determine if we can set IP at this point. The specified offset is the native offset.
5915HRESULT CordbNativeFrame::CanSetIP(ULONG32 nOffset)
5916{
5917 PUBLIC_API_ENTRY(this);
5918 FAIL_IF_NEUTERED(this);
5919
5920 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
5921
5922 HRESULT hr = S_OK;
5923 EX_TRY
5924 {
5925 if (!IsLeafFrame())
5926 {
5927 ThrowHR(CORDBG_E_SET_IP_NOT_ALLOWED_ON_NONLEAF_FRAME);
5928 }
5929
5930 hr = m_pThread->SetIP(SetIP_fCanSetIPOnly,
5931 m_nativeCode,
5932 nOffset,
5933 SetIP_fNative );
5934 }
5935 EX_CATCH_HRESULT(hr);
5936
5937 return hr;
5938}
5939
5940// Try to set the IP to the specified offset. The specified offset is the native offset.
5941HRESULT CordbNativeFrame::SetIP(ULONG32 nOffset)
5942{
5943 PUBLIC_API_ENTRY(this);
5944 FAIL_IF_NEUTERED(this);
5945
5946 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
5947
5948 HRESULT hr = S_OK;
5949 EX_TRY
5950 {
5951 if (!IsLeafFrame())
5952 {
5953 ThrowHR(CORDBG_E_SET_IP_NOT_ALLOWED_ON_NONLEAF_FRAME);
5954 }
5955
5956 hr = m_pThread->SetIP(SetIP_fSetIP,
5957 m_nativeCode,
5958 nOffset,
5959 SetIP_fNative );
5960 }
5961 EX_CATCH_HRESULT(hr);
5962
5963 return hr;
5964}
5965
5966
5967// Given a (register,offset) description of a stack location, compute
5968// the real memory address for it.
5969// This will also handle ambient SP values (which are encoded with regNum == REGNUM_AMBIENT_SP).
5970CORDB_ADDRESS CordbNativeFrame::GetLSStackAddress(
5971 ICorDebugInfo::RegNum regNum,
5972 signed offset)
5973{
5974 UINT_PTR *pRegAddr;
5975
5976 CORDB_ADDRESS pRemoteValue;
5977
5978 if (regNum != DBG_TARGET_REGNUM_AMBIENT_SP)
5979 {
5980 // Even if we're inside a funclet, variables (in both x64 and ARM) are still
5981 // relative to the frame pointer or stack pointer, which are accurate in the
5982 // funclet, after the funclet prolog; the frame pointer is re-established in the
5983 // funclet prolog using the PSP. Thus, we just look up the frame pointer in the
5984 // current native frame.
5985
5986 pRegAddr = this->GetAddressOfRegister(
5987 ConvertRegNumToCorDebugRegister(regNum));
5988
5989 // This should never be null as long as regNum is a member of the RegNum enum.
5990 // If it is, an AV dereferencing a null-pointer in retail builds, or an assert in debug
5991 // builds is exactly the behavior we want.
5992 PREFIX_ASSUME(pRegAddr != NULL);
5993
5994 pRemoteValue = PTR_TO_CORDB_ADDRESS(*pRegAddr + offset);
5995 }
5996 else
5997 {
5998 // Use the ambient ESP. At this point we're decoding an ambient-sp var, so
5999 // we should definitely have an ambient-sp. If this is null, then the jit
6000 // likely gave us an inconsistent data.
6001 TADDR taAmbient = this->GetAmbientESP();
6002 _ASSERTE(taAmbient != NULL);
6003
6004 pRemoteValue = PTR_TO_CORDB_ADDRESS(taAmbient + offset);
6005 }
6006
6007 return pRemoteValue;
6008}
6009
6010
6011// ----------------------------------------------------------------------------
6012// CordbNativeFrame::GetStackRange
6013//
6014// Description:
6015// Return the stack range owned by this native frame.
6016// The start of the stack range is the leafmost boundary, and the end is the rootmost boundary.
6017//
6018// Arguments:
6019// * pStart - out parameter; return the leaf end of the frame
6020// * pEnd - out parameter; return the root end of the frame
6021//
6022// Return Value:
6023// Return S_OK on success.
6024//
6025// Notes: see code:#GetStackRange
6026
6027HRESULT CordbNativeFrame::GetStackRange(CORDB_ADDRESS *pStart,
6028 CORDB_ADDRESS *pEnd)
6029{
6030 PUBLIC_REENTRANT_API_ENTRY(this);
6031
6032 // Callers explicit require GetStackRange() to be callable when neutered so that they
6033 // can line up ICorDebugFrame objects across continues. We only return stack ranges
6034 // here and don't access any special data.
6035 OK_IF_NEUTERED(this);
6036
6037 if (GetProcess()->GetShim() != NULL)
6038 {
6039 if (pStart)
6040 {
6041 // From register set.
6042 *pStart = GetSPFromDebuggerREGDISPLAY(&m_rd);
6043 }
6044
6045 if (pEnd)
6046 {
6047 // The rootmost boundary is the frame pointer.
6048 // <NOTE>
6049 // This is not true on AMD64, on which we use the stack pointer as the frame pointer.
6050 // </NOTE>
6051 *pEnd = PTR_TO_CORDB_ADDRESS(GetFramePointer().GetSPValue());
6052 }
6053 return S_OK;
6054 }
6055 else
6056 {
6057 if (pStart != NULL)
6058 {
6059 *pStart = NULL;
6060 }
6061 if (pEnd != NULL)
6062 {
6063 *pEnd = NULL;
6064 }
6065 return E_NOTIMPL;
6066 }
6067}
6068
6069// Return the register set of the native frame.
6070HRESULT CordbNativeFrame::GetRegisterSet(ICorDebugRegisterSet **ppRegisters)
6071{
6072 PUBLIC_REENTRANT_API_ENTRY(this);
6073 FAIL_IF_NEUTERED(this);
6074 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
6075
6076 VALIDATE_POINTER_TO_OBJECT(ppRegisters, ICorDebugRegisterSet **);
6077
6078 HRESULT hr = S_OK;
6079 EX_TRY
6080 {
6081 // allocate a new CordbRegisterSet object
6082 RSInitHolder<CordbRegisterSet> pRegisterSet(new CordbRegisterSet(&m_rd,
6083 m_pThread,
6084 IsLeafFrame(),
6085 m_quicklyUnwound));
6086
6087 pRegisterSet.TransferOwnershipExternal(ppRegisters);
6088 }
6089 EX_CATCH_HRESULT(hr);
6090 return hr;
6091}
6092
6093//---------------------------------------------------------------------------------------
6094//
6095// Checks whether the frame is a child frame or not.
6096//
6097// Arguments:
6098// pIsChild - out parameter; returns whether the frame is a child frame
6099//
6100// Return Value:
6101// S_OK on success.
6102// E_INVALIDARG if the out parmater is NULL.
6103//
6104
6105HRESULT CordbNativeFrame::IsChild(BOOL * pIsChild)
6106{
6107 HRESULT hr = S_OK;
6108 PUBLIC_REENTRANT_API_BEGIN(this)
6109 {
6110 if (pIsChild == NULL)
6111 {
6112 ThrowHR(E_INVALIDARG);
6113 }
6114 else
6115 {
6116 *pIsChild = ((this->IsFunclet() && !this->IsFilterFunclet()) ? TRUE : FALSE);
6117 }
6118 }
6119 PUBLIC_REENTRANT_API_END(hr);
6120 return hr;
6121}
6122
6123//---------------------------------------------------------------------------------------
6124//
6125// Given an ICDNativeFrame2, check whether it is the parent frame of the current frame.
6126//
6127// Arguments:
6128// pPotentialParentFrame - the ICDNativeFrame2 to check
6129// pIsParent - out paramter; returns whether the specified frame is indeed the parent frame
6130//
6131// Return Value:
6132// S_OK on success.
6133// CORDBG_E_NOT_CHILD_FRAME if the current frame is not a child frame.
6134// E_INVALIDARG if either of the incoming argument is NULL.
6135// E_FAIL on other failures.
6136//
6137
6138HRESULT CordbNativeFrame::IsMatchingParentFrame(ICorDebugNativeFrame2 * pPotentialParentFrame,
6139 BOOL * pIsParent)
6140{
6141 PUBLIC_REENTRANT_API_ENTRY(this);
6142 FAIL_IF_NEUTERED(this);
6143 VALIDATE_POINTER_TO_OBJECT(pPotentialParentFrame, ICorDebugNativeFrame2 *);
6144
6145 HRESULT hr = S_OK;
6146 EX_TRY
6147 {
6148 if ((pPotentialParentFrame == NULL) || (pIsParent == NULL))
6149 {
6150 ThrowHR(E_INVALIDARG);
6151 }
6152
6153 *pIsParent = FALSE;
6154
6155 if (!this->IsFunclet())
6156 {
6157 ThrowHR(CORDBG_E_NOT_CHILD_FRAME);
6158 }
6159
6160#ifdef WIN64EXCEPTIONS
6161 CordbNativeFrame * pFrameToCheck = static_cast<CordbNativeFrame *>(pPotentialParentFrame);
6162 if (pFrameToCheck->IsFunclet())
6163 {
6164 *pIsParent = FALSE;
6165 }
6166 else
6167 {
6168 FramePointer fpParent = this->m_misc.fpParentOrSelf;
6169 FramePointer fpToCheck = pFrameToCheck->m_misc.fpParentOrSelf;
6170
6171 IDacDbiInterface * pDAC = GetProcess()->GetDAC();
6172 *pIsParent = pDAC->IsMatchingParentFrame(fpToCheck, fpParent);
6173 }
6174#endif // WIN64EXCEPTIONS
6175 }
6176 EX_CATCH_HRESULT(hr);
6177
6178 return hr;
6179}
6180
6181//---------------------------------------------------------------------------------------
6182//
6183// Return the stack parameter size of the current frame. Since this information is only used on x86,
6184// we return S_FALSE and a size of 0 on WIN64 platforms.
6185//
6186// Arguments:
6187// pSize - out parameter; return the size of the stack parameter
6188//
6189// Return Value:
6190// S_OK on success.
6191// S_FALSE on WIN64 platforms.
6192// E_INVALIDARG if pSize is NULL.
6193//
6194// Notes:
6195// Always return S_FALSE on WIN64.
6196//
6197
6198HRESULT CordbNativeFrame::GetStackParameterSize(ULONG32 * pSize)
6199{
6200 PUBLIC_API_ENTRY(this);
6201 FAIL_IF_NEUTERED(this);
6202
6203 HRESULT hr = S_OK;
6204 EX_TRY
6205 {
6206 if (pSize == NULL)
6207 {
6208 ThrowHR(E_INVALIDARG);
6209 }
6210
6211#if defined(_TARGET_X86_)
6212 IDacDbiInterface * pDAC = GetProcess()->GetDAC();
6213 *pSize = pDAC->GetStackParameterSize(PTR_TO_CORDB_ADDRESS(CORDbgGetIP(&m_context)));
6214#else // !_TARGET_X86_
6215 hr = S_FALSE;
6216 *pSize = 0;
6217#endif // _TARGET_X86_
6218 }
6219 EX_CATCH_HRESULT(hr);
6220
6221 return hr;
6222}
6223
6224//
6225// GetAddressOfRegister returns the address of the given register in the
6226// frame's current register display (eg, a local address). This is usually used to build a
6227// ICorDebugValue from.
6228//
6229UINT_PTR * CordbNativeFrame::GetAddressOfRegister(CorDebugRegister regNum) const
6230{
6231 UINT_PTR* ret = NULL;
6232
6233 switch (regNum)
6234 {
6235 case REGISTER_STACK_POINTER:
6236 ret = (UINT_PTR*)GetSPAddress(&m_rd);
6237 break;
6238
6239#if !defined(DBG_TARGET_AMD64) && !defined(DBG_TARGET_ARM) // @ARMTODO
6240 case REGISTER_FRAME_POINTER:
6241 ret = (UINT_PTR*)GetFPAddress(&m_rd);
6242 break;
6243#endif
6244
6245#if defined(DBG_TARGET_X86)
6246 case REGISTER_X86_EAX:
6247 ret = (UINT_PTR*)&m_rd.Eax;
6248 break;
6249
6250 case REGISTER_X86_ECX:
6251 ret = (UINT_PTR*)&m_rd.Ecx;
6252 break;
6253
6254 case REGISTER_X86_EDX:
6255 ret = (UINT_PTR*)&m_rd.Edx;
6256 break;
6257
6258 case REGISTER_X86_EBX:
6259 ret = (UINT_PTR*)&m_rd.Ebx;
6260 break;
6261
6262 case REGISTER_X86_ESI:
6263 ret = (UINT_PTR*)&m_rd.Esi;
6264 break;
6265
6266 case REGISTER_X86_EDI:
6267 ret = (UINT_PTR*)&m_rd.Edi;
6268 break;
6269
6270#elif defined(DBG_TARGET_AMD64)
6271 case REGISTER_AMD64_RBP:
6272 ret = (UINT_PTR*)&m_rd.Rbp;
6273 break;
6274
6275 case REGISTER_AMD64_RAX:
6276 ret = (UINT_PTR*)&m_rd.Rax;
6277 break;
6278
6279 case REGISTER_AMD64_RCX:
6280 ret = (UINT_PTR*)&m_rd.Rcx;
6281 break;
6282
6283 case REGISTER_AMD64_RDX:
6284 ret = (UINT_PTR*)&m_rd.Rdx;
6285 break;
6286
6287 case REGISTER_AMD64_RBX:
6288 ret = (UINT_PTR*)&m_rd.Rbx;
6289 break;
6290
6291 case REGISTER_AMD64_RSI:
6292 ret = (UINT_PTR*)&m_rd.Rsi;
6293 break;
6294
6295 case REGISTER_AMD64_RDI:
6296 ret = (UINT_PTR*)&m_rd.Rdi;
6297 break;
6298
6299 case REGISTER_AMD64_R8:
6300 ret = (UINT_PTR*)&m_rd.R8;
6301 break;
6302
6303 case REGISTER_AMD64_R9:
6304 ret = (UINT_PTR*)&m_rd.R9;
6305 break;
6306
6307 case REGISTER_AMD64_R10:
6308 ret = (UINT_PTR*)&m_rd.R10;
6309 break;
6310
6311 case REGISTER_AMD64_R11:
6312 ret = (UINT_PTR*)&m_rd.R11;
6313 break;
6314
6315 case REGISTER_AMD64_R12:
6316 ret = (UINT_PTR*)&m_rd.R12;
6317 break;
6318
6319 case REGISTER_AMD64_R13:
6320 ret = (UINT_PTR*)&m_rd.R13;
6321 break;
6322
6323 case REGISTER_AMD64_R14:
6324 ret = (UINT_PTR*)&m_rd.R14;
6325 break;
6326
6327 case REGISTER_AMD64_R15:
6328 ret = (UINT_PTR*)&m_rd.R15;
6329 break;
6330#elif defined(DBG_TARGET_ARM)
6331 case REGISTER_ARM_R0:
6332 ret = (UINT_PTR*)&m_rd.R0;
6333 break;
6334
6335 case REGISTER_ARM_R1:
6336 ret = (UINT_PTR*)&m_rd.R1;
6337 break;
6338
6339 case REGISTER_ARM_R2:
6340 ret = (UINT_PTR*)&m_rd.R2;
6341 break;
6342
6343 case REGISTER_ARM_R3:
6344 ret = (UINT_PTR*)&m_rd.R3;
6345 break;
6346
6347 case REGISTER_ARM_R4:
6348 ret = (UINT_PTR*)&m_rd.R4;
6349 break;
6350
6351 case REGISTER_ARM_R5:
6352 ret = (UINT_PTR*)&m_rd.R5;
6353 break;
6354
6355 case REGISTER_ARM_R6:
6356 ret = (UINT_PTR*)&m_rd.R6;
6357 break;
6358
6359 case REGISTER_ARM_R7:
6360 ret = (UINT_PTR*)&m_rd.R7;
6361 break;
6362
6363 case REGISTER_ARM_R8:
6364 ret = (UINT_PTR*)&m_rd.R8;
6365 break;
6366
6367 case REGISTER_ARM_R9:
6368 ret = (UINT_PTR*)&m_rd.R9;
6369 break;
6370
6371 case REGISTER_ARM_R10:
6372 ret = (UINT_PTR*)&m_rd.R10;
6373 break;
6374
6375 case REGISTER_ARM_R11:
6376 ret = (UINT_PTR*)&m_rd.R11;
6377 break;
6378
6379 case REGISTER_ARM_R12:
6380 ret = (UINT_PTR*)&m_rd.R12;
6381 break;
6382
6383 case REGISTER_ARM_LR:
6384 ret = (UINT_PTR*)&m_rd.LR;
6385 break;
6386
6387 case REGISTER_ARM_PC:
6388 ret = (UINT_PTR*)&m_rd.PC;
6389 break;
6390#elif defined(DBG_TARGET_ARM64)
6391 case REGISTER_ARM64_X0:
6392 case REGISTER_ARM64_X1:
6393 case REGISTER_ARM64_X2:
6394 case REGISTER_ARM64_X3:
6395 case REGISTER_ARM64_X4:
6396 case REGISTER_ARM64_X5:
6397 case REGISTER_ARM64_X6:
6398 case REGISTER_ARM64_X7:
6399 case REGISTER_ARM64_X8:
6400 case REGISTER_ARM64_X9:
6401 case REGISTER_ARM64_X10:
6402 case REGISTER_ARM64_X11:
6403 case REGISTER_ARM64_X12:
6404 case REGISTER_ARM64_X13:
6405 case REGISTER_ARM64_X14:
6406 case REGISTER_ARM64_X15:
6407 case REGISTER_ARM64_X16:
6408 case REGISTER_ARM64_X17:
6409 case REGISTER_ARM64_X18:
6410 case REGISTER_ARM64_X19:
6411 case REGISTER_ARM64_X20:
6412 case REGISTER_ARM64_X21:
6413 case REGISTER_ARM64_X22:
6414 case REGISTER_ARM64_X23:
6415 case REGISTER_ARM64_X24:
6416 case REGISTER_ARM64_X25:
6417 case REGISTER_ARM64_X26:
6418 case REGISTER_ARM64_X27:
6419 case REGISTER_ARM64_X28:
6420 ret = (UINT_PTR*)&m_rd.X[regNum - REGISTER_ARM64_X0];
6421 break;
6422
6423 case REGISTER_ARM64_LR:
6424 ret = (UINT_PTR*)&m_rd.LR;
6425 break;
6426
6427 case REGISTER_ARM64_PC:
6428 ret = (UINT_PTR*)&m_rd.PC;
6429 break;
6430#endif
6431
6432 default:
6433 _ASSERT(!"Invalid register number!");
6434 }
6435
6436 return ret;
6437}
6438
6439//
6440// GetLeftSideAddressOfRegister returns the Left Side address of the given register in the frames current register
6441// display.
6442//
6443CORDB_ADDRESS CordbNativeFrame::GetLeftSideAddressOfRegister(CorDebugRegister regNum) const
6444{
6445#if !defined(USE_REMOTE_REGISTER_ADDRESS)
6446 // Use marker values as the register address. This is to implement the funceval breaking change.
6447 //
6448 if (IsLeafFrame())
6449 {
6450 return kLeafFrameRegAddr;
6451 }
6452 else
6453 {
6454 return kNonLeafFrameRegAddr;
6455 }
6456
6457#else // USE_REMOTE_REGISTER_ADDRESS
6458 void* ret = 0;
6459
6460 switch (regNum)
6461 {
6462
6463#if !defined(DBG_TARGET_AMD64)
6464 case REGISTER_FRAME_POINTER:
6465 ret = m_rd.pFP;
6466 break;
6467#endif
6468
6469#if defined(DBG_TARGET_X86)
6470 case REGISTER_X86_EAX:
6471 ret = m_rd.pEax;
6472 break;
6473
6474 case REGISTER_X86_ECX:
6475 ret = m_rd.pEcx;
6476 break;
6477
6478 case REGISTER_X86_EDX:
6479 ret = m_rd.pEdx;
6480 break;
6481
6482 case REGISTER_X86_EBX:
6483 ret = m_rd.pEbx;
6484 break;
6485
6486 case REGISTER_X86_ESI:
6487 ret = m_rd.pEsi;
6488 break;
6489
6490 case REGISTER_X86_EDI:
6491 ret = m_rd.pEdi;
6492 break;
6493
6494#elif defined(DBG_TARGET_AMD64)
6495 case REGISTER_AMD64_RBP:
6496 ret = m_rd.pRbp;
6497 break;
6498
6499 case REGISTER_AMD64_RAX:
6500 ret = m_rd.pRax;
6501 break;
6502
6503 case REGISTER_AMD64_RCX:
6504 ret = m_rd.pRcx;
6505 break;
6506
6507 case REGISTER_AMD64_RDX:
6508 ret = m_rd.pRdx;
6509 break;
6510
6511 case REGISTER_AMD64_RBX:
6512 ret = m_rd.pRbx;
6513 break;
6514
6515 case REGISTER_AMD64_RSI:
6516 ret = m_rd.pRsi;
6517 break;
6518
6519 case REGISTER_AMD64_RDI:
6520 ret = m_rd.pRdi;
6521 break;
6522
6523 case REGISTER_AMD64_R8:
6524 ret = m_rd.pR8;
6525 break;
6526
6527 case REGISTER_AMD64_R9:
6528 ret = m_rd.pR9;
6529 break;
6530
6531 case REGISTER_AMD64_R10:
6532 ret = m_rd.pR10;
6533 break;
6534
6535 case REGISTER_AMD64_R11:
6536 ret = m_rd.pR11;
6537 break;
6538
6539 case REGISTER_AMD64_R12:
6540 ret = m_rd.pR12;
6541 break;
6542
6543 case REGISTER_AMD64_R13:
6544 ret = m_rd.pR13;
6545 break;
6546
6547 case REGISTER_AMD64_R14:
6548 ret = m_rd.pR14;
6549 break;
6550
6551 case REGISTER_AMD64_R15:
6552 ret = m_rd.pR15;
6553 break;
6554#endif
6555 default:
6556 _ASSERT(!"Invalid register number!");
6557 }
6558
6559 return PTR_TO_CORDB_ADDRESS(ret);
6560#endif // !USE_REMOTE_REGISTER_ADDRESS
6561}
6562
6563
6564//---------------------------------------------------------------------------------------
6565//
6566// Given the native variable information of a variable, return its value.
6567//
6568// Arguments:
6569// pNativeVarInfo - the variable information of the variable to be retrieved
6570//
6571// Returns:
6572// Return the specified value.
6573// Throw on error.
6574//
6575// Assumption:
6576// This function assumes that the value is either in a register or on the stack
6577// (i.e. VLT_REG or VLT_STK).
6578//
6579// Notes:
6580// Eventually we should make this more general-purpose.
6581//
6582
6583SIZE_T CordbNativeFrame::GetRegisterOrStackValue(const ICorDebugInfo::NativeVarInfo * pNativeVarInfo)
6584{
6585 SIZE_T uResult;
6586
6587 if (pNativeVarInfo->loc.vlType == ICorDebugInfo::VLT_REG)
6588 {
6589 CorDebugRegister reg = ConvertRegNumToCorDebugRegister(pNativeVarInfo->loc.vlReg.vlrReg);
6590 uResult = *(reinterpret_cast<SIZE_T *>(GetAddressOfRegister(reg)));
6591 }
6592 else if (pNativeVarInfo->loc.vlType == ICorDebugInfo::VLT_STK)
6593 {
6594 CORDB_ADDRESS remoteAddr = GetLSStackAddress(pNativeVarInfo->loc.vlStk.vlsBaseReg,
6595 pNativeVarInfo->loc.vlStk.vlsOffset);
6596
6597 HRESULT hr = GetProcess()->SafeReadStruct(remoteAddr, &uResult);
6598 IfFailThrow(hr);
6599 }
6600 else
6601 {
6602 ThrowHR(E_FAIL);
6603 }
6604
6605 return uResult;
6606}
6607
6608
6609//---------------------------------------------------------------------------------------
6610//
6611// Looks in a register and retrieves the value as a specific type, returning it
6612// as an ICorDebugValue.
6613//
6614// Arguments:
6615// reg - The register to use.
6616// cbSigBlob - The number of bytes in the signature given.
6617// pvSigBlob - A signature stream that describes the type of the value in the register.
6618// ppValue - OUT: Space to store the resulting ICorDebugValue
6619//
6620// Returns:
6621// S_OK on success, else an error code.
6622//
6623HRESULT CordbNativeFrame::GetLocalRegisterValue(CorDebugRegister reg,
6624 ULONG cbSigBlob,
6625 PCCOR_SIGNATURE pvSigBlob,
6626 ICorDebugValue ** ppValue)
6627{
6628 PUBLIC_REENTRANT_API_ENTRY(this);
6629 FAIL_IF_NEUTERED(this);
6630 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
6631
6632 VALIDATE_POINTER_TO_OBJECT_ARRAY(pvSigBlob, BYTE, cbSigBlob, true, false);
6633
6634 CordbType * pType;
6635
6636 SigParser sigParser(pvSigBlob, cbSigBlob);
6637
6638 Instantiation emptyInst;
6639
6640 HRESULT hr = CordbType::SigToType(m_JITILFrame->GetModule(), &sigParser, &emptyInst, &pType);
6641
6642 if (FAILED(hr))
6643 {
6644 return hr;
6645 }
6646
6647 return GetLocalRegisterValue(reg, pType, ppValue);
6648}
6649
6650//---------------------------------------------------------------------------------------
6651//
6652// Looks in two registers and retrieves the value as a specific type, returning it
6653// as an ICorDebugValue.
6654//
6655// Arguments:
6656// highWordReg - The register to use for the high word.
6657// lowWordReg - The register to use for the low word.
6658// cbSigBlob - The number of bytes in the signature given.
6659// pvSigBlob - A signature stream that describes the type of the value in the register.
6660// ppValue - OUT: Space to store the resulting ICorDebugValue
6661//
6662// Returns:
6663// S_OK on success, else an error code.
6664//
6665HRESULT CordbNativeFrame::GetLocalDoubleRegisterValue(CorDebugRegister highWordReg,
6666 CorDebugRegister lowWordReg,
6667 ULONG cbSigBlob,
6668 PCCOR_SIGNATURE pvSigBlob,
6669 ICorDebugValue ** ppValue)
6670{
6671 PUBLIC_REENTRANT_API_ENTRY(this);
6672 FAIL_IF_NEUTERED(this);
6673 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
6674
6675 if (cbSigBlob == 0)
6676 {
6677 return E_INVALIDARG;
6678 }
6679
6680 CordbType * pType;
6681
6682 SigParser sigParser(pvSigBlob, cbSigBlob);
6683
6684 Instantiation emptyInst;
6685
6686 HRESULT hr = CordbType::SigToType(m_JITILFrame->GetModule(), &sigParser, &emptyInst, &pType);
6687
6688 if (FAILED(hr))
6689 {
6690 return hr;
6691 }
6692
6693 return GetLocalDoubleRegisterValue(highWordReg, lowWordReg, pType, ppValue);
6694}
6695
6696
6697//---------------------------------------------------------------------------------------
6698//
6699// Uses an address and retrieves the value as a specific type, returning it
6700// as an ICorDebugValue.
6701//
6702// Arguments:
6703// address - A local memory address.
6704// cbSigBlob - The number of bytes in the signature given.
6705// pvSigBlob - A signature stream that describes the type of the value in the register.
6706// ppValue - OUT: Space to store the resulting ICorDebugValue
6707//
6708// Returns:
6709// S_OK on success, else an error code.
6710//
6711HRESULT CordbNativeFrame::GetLocalMemoryValue(CORDB_ADDRESS address,
6712 ULONG cbSigBlob,
6713 PCCOR_SIGNATURE pvSigBlob,
6714 ICorDebugValue ** ppValue)
6715{
6716 PUBLIC_REENTRANT_API_ENTRY(this);
6717 FAIL_IF_NEUTERED(this);
6718 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
6719
6720 VALIDATE_POINTER_TO_OBJECT_ARRAY(pvSigBlob, BYTE, cbSigBlob, true, false);
6721
6722 CordbType * pType;
6723
6724 SigParser sigParser(pvSigBlob, cbSigBlob);
6725
6726 Instantiation emptyInst;
6727
6728 HRESULT hr = CordbType::SigToType(m_JITILFrame->GetModule(), &sigParser, &emptyInst, &pType);
6729
6730 if (FAILED(hr))
6731 {
6732 return hr;
6733 }
6734
6735 return GetLocalMemoryValue(address, pType, ppValue);
6736}
6737
6738
6739//---------------------------------------------------------------------------------------
6740//
6741// Uses a register and an address, retrieving the value as a specific type, returning it
6742// as an ICorDebugValue.
6743//
6744// Arguments:
6745// highWordReg - Register to use as the high word.
6746// lowWordAddress - A local memory address containing the low word.
6747// cbSigBlob - The number of bytes in the signature given.
6748// pvSigBlob - A signature stream that describes the type of the value in the register.
6749// ppValue - OUT: Space to store the resulting ICorDebugValue
6750//
6751// Returns:
6752// S_OK on success, else an error code.
6753//
6754HRESULT CordbNativeFrame::GetLocalRegisterMemoryValue(CorDebugRegister highWordReg,
6755 CORDB_ADDRESS lowWordAddress,
6756 ULONG cbSigBlob,
6757 PCCOR_SIGNATURE pvSigBlob,
6758 ICorDebugValue ** ppValue)
6759{
6760 PUBLIC_REENTRANT_API_ENTRY(this);
6761 FAIL_IF_NEUTERED(this);
6762 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
6763
6764 if (cbSigBlob == 0)
6765 {
6766 return E_INVALIDARG;
6767 }
6768
6769 VALIDATE_POINTER_TO_OBJECT_ARRAY(pvSigBlob, BYTE, cbSigBlob, true, true);
6770
6771 CordbType * pType;
6772
6773 SigParser sigParser(pvSigBlob, cbSigBlob);
6774
6775 Instantiation emptyInst;
6776
6777 HRESULT hr = CordbType::SigToType(m_JITILFrame->GetModule(), &sigParser, &emptyInst, &pType);
6778
6779 if (FAILED(hr))
6780 {
6781 return hr;
6782 }
6783
6784 return GetLocalRegisterMemoryValue(highWordReg, lowWordAddress, pType, ppValue);
6785}
6786
6787
6788//---------------------------------------------------------------------------------------
6789//
6790// Uses a register and an address, retrieving the value as a specific type, returning it
6791// as an ICorDebugValue.
6792//
6793// Arguments:
6794// highWordReg - A local memory address to use as the high word.
6795// lowWordAddress - Register containing the low word.
6796// cbSigBlob - The number of bytes in the signature given.
6797// pvSigBlob - A signature stream that describes the type of the value in the register.
6798// ppValue - OUT: Space to store the resulting ICorDebugValue
6799//
6800// Returns:
6801// S_OK on success, else an error code.
6802//
6803HRESULT CordbNativeFrame::GetLocalMemoryRegisterValue(CORDB_ADDRESS highWordAddress,
6804 CorDebugRegister lowWordRegister,
6805 ULONG cbSigBlob,
6806 PCCOR_SIGNATURE pvSigBlob,
6807 ICorDebugValue ** ppValue)
6808{
6809 PUBLIC_REENTRANT_API_ENTRY(this);
6810 FAIL_IF_NEUTERED(this);
6811 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
6812
6813 if (cbSigBlob == 0)
6814 {
6815 return E_INVALIDARG;
6816 }
6817
6818 VALIDATE_POINTER_TO_OBJECT_ARRAY(pvSigBlob, BYTE, cbSigBlob, true, true);
6819
6820 CordbType * pType;
6821
6822 SigParser sigParser(pvSigBlob, cbSigBlob);
6823
6824 Instantiation emptyInst;
6825
6826 HRESULT hr = CordbType::SigToType(m_JITILFrame->GetModule(), &sigParser, &emptyInst, &pType);
6827
6828 if (FAILED(hr))
6829 {
6830 return hr;
6831 }
6832
6833 return GetLocalMemoryRegisterValue(highWordAddress, lowWordRegister, pType, ppValue);
6834}
6835
6836
6837
6838HRESULT CordbNativeFrame::GetLocalRegisterValue(CorDebugRegister reg,
6839 CordbType * pType,
6840 ICorDebugValue **ppValue)
6841{
6842 PUBLIC_REENTRANT_API_ENTRY(this);
6843 FAIL_IF_NEUTERED(this);
6844 VALIDATE_POINTER_TO_OBJECT(ppValue, ICorDebugValue **);
6845 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
6846
6847#if defined(DBG_TARGET_X86) || defined(DBG_TARGET_WIN64)
6848#if defined(DBG_TARGET_X86)
6849 if ((reg >= REGISTER_X86_FPSTACK_0) && (reg <= REGISTER_X86_FPSTACK_7))
6850#elif defined(DBG_TARGET_AMD64)
6851 if ((reg >= REGISTER_AMD64_XMM0) && (reg <= REGISTER_AMD64_XMM15))
6852#elif defined(DBG_TARGET_ARM64)
6853 if ((reg >= REGISTER_ARM64_V0) && (reg <= REGISTER_ARM64_V31))
6854#endif
6855 {
6856 return GetLocalFloatingPointValue(reg, pType, ppValue);
6857 }
6858#endif
6859
6860 // The address of the given register is the address of the value
6861 // in this process. We have no remote address here.
6862 void *pLocalValue = (void*)GetAddressOfRegister(reg);
6863 HRESULT hr = S_OK;
6864
6865 EX_TRY
6866 {
6867 // Provide the register info as we create the value. CreateValueByType will transfer ownership of this to
6868 // the new instance of CordbValue.
6869 EnregisteredValueHomeHolder pRemoteReg(new RegValueHome(this, reg));
6870 EnregisteredValueHomeHolder * pRegHolder = pRemoteReg.GetAddr();
6871
6872 ICorDebugValue *pValue;
6873 CordbValue::CreateValueByType(GetCurrentAppDomain(),
6874 pType,
6875 false,
6876 EMPTY_BUFFER,
6877 MemoryRange(pLocalValue, REG_SIZE),
6878 pRegHolder,
6879 &pValue); // throws
6880
6881 *ppValue = pValue;
6882 }
6883 EX_CATCH_HRESULT(hr);
6884 return hr;
6885}
6886
6887HRESULT CordbNativeFrame::GetLocalDoubleRegisterValue(
6888 CorDebugRegister highWordReg,
6889 CorDebugRegister lowWordReg,
6890 CordbType * pType,
6891 ICorDebugValue **ppValue)
6892{
6893 PUBLIC_REENTRANT_API_ENTRY(this);
6894 FAIL_IF_NEUTERED(this);
6895 VALIDATE_POINTER_TO_OBJECT(ppValue, ICorDebugValue **);
6896 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
6897
6898 HRESULT hr = S_OK;
6899 EX_TRY
6900 {
6901 // Provide the register info as we create the value. CreateValueByType will transfer ownership of this to
6902 // the new instance of CordbValue.
6903 EnregisteredValueHomeHolder pRemoteReg(new RegRegValueHome(this, highWordReg, lowWordReg));
6904 EnregisteredValueHomeHolder * pRegHolder = pRemoteReg.GetAddr();
6905
6906 CordbValue::CreateValueByType(GetCurrentAppDomain(),
6907 pType,
6908 false,
6909 EMPTY_BUFFER,
6910 MemoryRange(NULL, 0),
6911 pRegHolder,
6912 ppValue); // throws
6913 }
6914 EX_CATCH_HRESULT(hr);
6915
6916#ifdef _DEBUG
6917 {
6918 // sanity check object size
6919 if (SUCCEEDED(hr))
6920 {
6921 ULONG32 objectSize;
6922 hr = (*ppValue)->GetSize(&objectSize);
6923 _ASSERTE(SUCCEEDED(hr));
6924 //
6925 // nickbe
6926 // 10/31/2002 11:09:42
6927 //
6928 // This assert assumes that the JIT will only partially enregister
6929 // objects that have a size equal to twice the size of a register.
6930 //
6931 _ASSERTE(objectSize == 2 * sizeof(void*));
6932 }
6933 }
6934#endif
6935 return hr;
6936}
6937
6938HRESULT
6939CordbNativeFrame::GetLocalMemoryValue(CORDB_ADDRESS address,
6940 CordbType * pType,
6941 ICorDebugValue **ppValue)
6942{
6943 PUBLIC_REENTRANT_API_ENTRY(this);
6944 FAIL_IF_NEUTERED(this);
6945 VALIDATE_POINTER_TO_OBJECT(ppValue, ICorDebugValue **);
6946 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
6947
6948 _ASSERTE(m_nativeCode->GetFunction() != NULL);
6949 HRESULT hr = S_OK;
6950
6951 ICorDebugValue *pValue;
6952 EX_TRY
6953 {
6954 CordbValue::CreateValueByType(GetCurrentAppDomain(),
6955 pType,
6956 false,
6957 TargetBuffer(address, CordbValue::GetSizeForType(pType, kUnboxed)),
6958 MemoryRange(NULL, 0),
6959 NULL,
6960 &pValue); // throws
6961 }
6962 EX_CATCH_HRESULT(hr);
6963
6964 if (SUCCEEDED(hr))
6965 *ppValue = pValue;
6966
6967 return hr;
6968}
6969
6970HRESULT
6971CordbNativeFrame::GetLocalByRefMemoryValue(CORDB_ADDRESS address,
6972 CordbType * pType,
6973 ICorDebugValue **ppValue)
6974{
6975 INTERNAL_API_ENTRY(this);
6976 FAIL_IF_NEUTERED(this);
6977
6978 LPVOID actualAddress = NULL;
6979 HRESULT hr = GetProcess()->SafeReadStruct(address, &actualAddress);
6980 if (FAILED(hr))
6981 {
6982 return hr;
6983 }
6984
6985 return GetLocalMemoryValue(PTR_TO_CORDB_ADDRESS(actualAddress), pType, ppValue);
6986}
6987
6988HRESULT
6989CordbNativeFrame::GetLocalRegisterMemoryValue(CorDebugRegister highWordReg,
6990 CORDB_ADDRESS lowWordAddress,
6991 CordbType * pType,
6992 ICorDebugValue **ppValue)
6993{
6994 PUBLIC_REENTRANT_API_ENTRY(this);
6995 FAIL_IF_NEUTERED(this);
6996 VALIDATE_POINTER_TO_OBJECT(ppValue, ICorDebugValue **);
6997 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
6998
6999 HRESULT hr = S_OK;
7000 EX_TRY
7001 {
7002 // Provide the register info as we create the value. CreateValueByType will transfer ownership of this to
7003 // the new instance of CordbValue.
7004 EnregisteredValueHomeHolder pRemoteReg(new RegMemValueHome(this,
7005 highWordReg,
7006 lowWordAddress));
7007 EnregisteredValueHomeHolder * pRegHolder = pRemoteReg.GetAddr();
7008
7009 CordbValue::CreateValueByType(GetCurrentAppDomain(),
7010 pType,
7011 false,
7012 EMPTY_BUFFER,
7013 MemoryRange(NULL, 0),
7014 pRegHolder,
7015 ppValue); // throws
7016 }
7017 EX_CATCH_HRESULT(hr);
7018
7019#ifdef _DEBUG
7020 {
7021 if (SUCCEEDED(hr))
7022 {
7023 ULONG32 objectSize;
7024 hr = (*ppValue)->GetSize(&objectSize);
7025 _ASSERTE(SUCCEEDED(hr));
7026 // See the comment in CordbNativeFrame::GetLocalDoubleRegisterValue
7027 // for more information on this assertion
7028 _ASSERTE(objectSize == 2 * sizeof(void*));
7029 }
7030 }
7031#endif
7032 return hr;
7033}
7034
7035HRESULT
7036CordbNativeFrame::GetLocalMemoryRegisterValue(CORDB_ADDRESS highWordAddress,
7037 CorDebugRegister lowWordRegister,
7038 CordbType * pType,
7039 ICorDebugValue **ppValue)
7040{
7041 PUBLIC_REENTRANT_API_ENTRY(this);
7042 FAIL_IF_NEUTERED(this);
7043 VALIDATE_POINTER_TO_OBJECT(ppValue, ICorDebugValue **);
7044 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
7045
7046 HRESULT hr = S_OK;
7047 EX_TRY
7048 {
7049 // Provide the register info as we create the value. CreateValueByType will transfer ownership of this to
7050 // the new instance of CordbValue.
7051 EnregisteredValueHomeHolder pRemoteReg(new MemRegValueHome(this,
7052 lowWordRegister,
7053 highWordAddress));
7054 EnregisteredValueHomeHolder * pRegHolder = pRemoteReg.GetAddr();
7055
7056 CordbValue::CreateValueByType(GetCurrentAppDomain(),
7057 pType,
7058 false,
7059 EMPTY_BUFFER,
7060 MemoryRange(NULL, 0),
7061 pRegHolder,
7062 ppValue); // throws
7063 }
7064 EX_CATCH_HRESULT(hr);
7065
7066#ifdef _DEBUG
7067 {
7068 if (SUCCEEDED(hr))
7069 {
7070 ULONG32 objectSize;
7071 hr = (*ppValue)->GetSize(&objectSize);
7072 _ASSERTE(SUCCEEDED(hr));
7073 // See the comment in CordbNativeFrame::GetLocalDoubleRegisterValue
7074 // for more information on this assertion
7075 _ASSERTE(objectSize == 2 * sizeof(void*));
7076 }
7077 }
7078#endif
7079 return hr;
7080}
7081
7082HRESULT CordbNativeFrame::GetLocalFloatingPointValue(DWORD index,
7083 CordbType * pType,
7084 ICorDebugValue **ppValue)
7085{
7086 PUBLIC_REENTRANT_API_ENTRY(this);
7087 FAIL_IF_NEUTERED(this);
7088 HRESULT hr = S_OK;
7089
7090 CorElementType et = pType->m_elementType;
7091
7092 if ((et != ELEMENT_TYPE_R4) &&
7093 (et != ELEMENT_TYPE_R8))
7094 return E_INVALIDARG;
7095
7096#if defined(DBG_TARGET_AMD64)
7097 if (!((index >= REGISTER_AMD64_XMM0) &&
7098 (index <= REGISTER_AMD64_XMM15)))
7099 return E_INVALIDARG;
7100 index -= REGISTER_AMD64_XMM0;
7101#elif defined(DBG_TARGET_ARM64)
7102 if (!((index >= REGISTER_ARM64_V0) &&
7103 (index <= REGISTER_ARM64_V31)))
7104 return E_INVALIDARG;
7105 index -= REGISTER_ARM64_V0;
7106#elif defined(DBG_TARGET_ARM)
7107 if (!((index >= REGISTER_ARM_D0) &&
7108 (index <= REGISTER_ARM_D31)))
7109 return E_INVALIDARG;
7110 index -= REGISTER_ARM_D0;
7111#else
7112 if (!((index >= REGISTER_X86_FPSTACK_0) &&
7113 (index <= REGISTER_X86_FPSTACK_7)))
7114 return E_INVALIDARG;
7115 index -= REGISTER_X86_FPSTACK_0;
7116#endif
7117
7118 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
7119
7120
7121 // Make sure the thread's floating point stack state is loaded
7122 // over from the left side.
7123 //
7124 CordbThread *pThread = m_pThread;
7125
7126 EX_TRY
7127 {
7128 if (!pThread->m_fFloatStateValid)
7129 {
7130 pThread->LoadFloatState();
7131 }
7132 }
7133 EX_CATCH_HRESULT(hr);
7134 if (SUCCEEDED(hr))
7135 {
7136#if !defined(DBG_TARGET_WIN64)
7137 // This is needed on x86 because we are dealing with a stack.
7138 index = pThread->m_floatStackTop - index;
7139#endif
7140
7141 if (index >= (sizeof(pThread->m_floatValues) /
7142 sizeof(pThread->m_floatValues[0])))
7143 return E_INVALIDARG;
7144
7145#ifdef DBG_TARGET_X86
7146 // A workaround (sort of) to get around the difference in format between
7147 // a float value and a double value. We can't simply cast a double pointer to
7148 // a float pointer. Instead, we have to cast the double itself to a float.
7149 if (pType->m_elementType == ELEMENT_TYPE_R4)
7150 *(float *)&(pThread->m_floatValues[index]) = (float)pThread->m_floatValues[index];
7151#endif
7152
7153 ICorDebugValue* pValue;
7154
7155 EX_TRY
7156 {
7157 // Provide the register info as we create the value. CreateValueByType will transfer ownership of this to
7158 // the new instance of CordbValue.
7159 EnregisteredValueHomeHolder pRemoteReg(new FloatRegValueHome(this, index));
7160 EnregisteredValueHomeHolder * pRegHolder = pRemoteReg.GetAddr();
7161
7162 CordbValue::CreateValueByType(GetCurrentAppDomain(),
7163 pType,
7164 false,
7165 EMPTY_BUFFER,
7166 MemoryRange(&(pThread->m_floatValues[index]), sizeof(double)),
7167 pRegHolder,
7168 &pValue); // throws
7169
7170 *ppValue = pValue;
7171 }
7172 EX_CATCH_HRESULT(hr);
7173
7174 }
7175
7176 return hr;
7177}
7178
7179//---------------------------------------------------------------------------------------
7180//
7181// Quick accessor to tell if we're the leaf frame.
7182//
7183// Return Value:
7184// whether we are the leaf frame or not
7185//
7186
7187bool CordbNativeFrame::IsLeafFrame() const
7188{
7189 CONTRACTL
7190 {
7191 THROWS;
7192 }
7193 CONTRACTL_END;
7194
7195 // Should only be called by non-neutered stuff.
7196 // Also, since we're not neutered, we know we have a Thread object, and we know it's state is current.
7197 _ASSERTE(!this->IsNeutered());
7198
7199 // If the thread's state is sleeping, then there's no frame below us, but we're actually
7200 // not the leaf frame.
7201 // @todo- consider having Sleep / Wait / Join be an ICDInternalFrame.
7202 _ASSERTE(m_pThread != NULL); // not neutered, so should have a thread
7203 if (m_pThread->IsThreadWaitingOrSleeping())
7204 {
7205 return false;
7206 }
7207
7208 if (!m_optfIsLeafFrame.HasValue())
7209 {
7210 if (GetProcess()->GetShim() != NULL)
7211 {
7212 // In V2, the definition of "leaf frame" is the leaf frame in the leaf chain in the stackwalk.
7213 PRIVATE_SHIM_CALLBACK_IN_THIS_SCOPE0(GetProcess());
7214 ShimStackWalk * pSW = GetProcess()->GetShim()->LookupOrCreateShimStackWalk(m_pThread);
7215
7216 // check if there is any chain
7217 if (pSW->GetChainCount() > 0)
7218 {
7219 // check if the leaf chain has any frame
7220 if (pSW->GetChain(0)->GetLastFrameIndex() > 0)
7221 {
7222 CordbFrame * pCFrame = GetCordbFrameFromInterface(pSW->GetFrame(0));
7223 CordbNativeFrame * pNFrame = pCFrame->GetAsNativeFrame();
7224 if (pNFrame != NULL)
7225 {
7226 // check if the leaf frame in the leaf chain is "this"
7227 if (CompareControlRegisters(GetContext(), pNFrame->GetContext()))
7228 {
7229 m_optfIsLeafFrame = TRUE;
7230 }
7231 }
7232 }
7233 }
7234
7235 if (!m_optfIsLeafFrame.HasValue())
7236 {
7237 m_optfIsLeafFrame = FALSE;
7238 }
7239 }
7240 else
7241 {
7242 IDacDbiInterface * pDAC = GetProcess()->GetDAC();
7243 m_optfIsLeafFrame = (pDAC->IsLeafFrame(m_pThread->m_vmThreadToken, &m_context) == TRUE);
7244 }
7245 }
7246 return m_optfIsLeafFrame.GetValue();
7247}
7248
7249//---------------------------------------------------------------------------------------
7250//
7251// Get the offset used to determine if a variable is live in a particular method frame.
7252//
7253// Return Value:
7254// the offset used for inspection purposes
7255//
7256// Notes:
7257// On WIN64, variables used in funclets are always homed on the stack. Morever, the variable lifetime
7258// information only covers the parent method. The idea is that the variables which are live in a funclet
7259// will be the variables which are live in the parent method at the offset at which the exception occurs.
7260// Thus, to determine if a variable is live in a funclet frame, we need to use the offset of the parent
7261// method frame at which the exception occurs.
7262//
7263
7264SIZE_T CordbNativeFrame::GetInspectionIP()
7265{
7266#ifdef WIN64EXCEPTIONS
7267 // On 64-bit, if this is a funclet, then return the offset of the parent method frame at which
7268 // the exception occurs. Otherwise just return the normal offset.
7269 return (IsFunclet() ? GetParentIP() : m_ip);
7270#else
7271 // Always return the normal offset on all other platforms.
7272 return m_ip;
7273#endif // WIN64EXCEPTIONS
7274}
7275
7276//---------------------------------------------------------------------------------------
7277//
7278// Return whether this is a funclet method frame.
7279//
7280// Return Value:
7281// whether this is a funclet method frame.
7282//
7283
7284bool CordbNativeFrame::IsFunclet()
7285{
7286#ifdef WIN64EXCEPTIONS
7287 return (m_misc.parentIP != NULL);
7288#else
7289 return false;
7290#endif // WIN64EXCEPTIONS
7291}
7292
7293//---------------------------------------------------------------------------------------
7294//
7295// Return whether this is a filter funclet method frame.
7296//
7297// Return Value:
7298// whether this is a filter funclet method frame.
7299//
7300
7301bool CordbNativeFrame::IsFilterFunclet()
7302{
7303#ifdef WIN64EXCEPTIONS
7304 return (IsFunclet() && m_misc.fIsFilterFunclet);
7305#else
7306 return false;
7307#endif // WIN64EXCEPTIONS
7308}
7309
7310
7311#ifdef WIN64EXCEPTIONS
7312//---------------------------------------------------------------------------------------
7313//
7314// Return the offset of the parent method frame at which the exception occurs.
7315//
7316// Return Value:
7317// the offset of the parent method frame at which the exception occurs
7318//
7319
7320SIZE_T CordbNativeFrame::GetParentIP()
7321{
7322 return m_misc.parentIP;
7323}
7324#endif // WIN64EXCEPTIONS
7325
7326// Accessor for the shim private hook code:CordbThread::ConvertFrameForILMethodWithoutMetadata.
7327// Refer to that function for comments on the return value, the argument, etc.
7328BOOL CordbNativeFrame::ConvertNativeFrameForILMethodWithoutMetadata(
7329 ICorDebugInternalFrame2 ** ppInternalFrame2)
7330{
7331 _ASSERTE(ppInternalFrame2 != NULL);
7332 *ppInternalFrame2 = NULL;
7333
7334 IDacDbiInterface * pDAC = GetProcess()->GetDAC();
7335 IDacDbiInterface::DynamicMethodType type =
7336 pDAC->IsILStubOrLCGMethod(GetNativeCode()->GetVMNativeCodeMethodDescToken());
7337
7338 // Here are the conversion rules:
7339 // 1) For a normal managed method, we don't convert, and we return FALSE.
7340 // 2) For an IL stub, we convert to NULL, and we return TRUE.
7341 // 3) For a dynamic method, we convert to a STUBFRAME_LIGHTWEIGHT_FUNCTION, and we return TRUE.
7342 if (type == IDacDbiInterface::kNone)
7343 {
7344 return FALSE;
7345 }
7346 else if (type == IDacDbiInterface::kILStub)
7347 {
7348 return TRUE;
7349 }
7350 else if (type == IDacDbiInterface::kLCGMethod)
7351 {
7352 RSInitHolder<CordbInternalFrame> pInternalFrame(
7353 new CordbInternalFrame(m_pThread,
7354 m_fp,
7355 m_currentAppDomain,
7356 STUBFRAME_LIGHTWEIGHT_FUNCTION,
7357 GetNativeCode()->GetMetadataToken(),
7358 GetNativeCode()->GetFunction(),
7359 GetNativeCode()->GetVMNativeCodeMethodDescToken()));
7360
7361 pInternalFrame.TransferOwnershipExternal(ppInternalFrame2);
7362 return TRUE;
7363 }
7364
7365 UNREACHABLE();
7366}
7367
7368/* ------------------------------------------------------------------------- *
7369 * JIT-IL Frame class
7370 * ------------------------------------------------------------------------- */
7371
7372CordbJITILFrame::CordbJITILFrame(CordbNativeFrame * pNativeFrame,
7373 CordbILCode * pCode,
7374 UINT_PTR ip,
7375 CorDebugMappingResult mapping,
7376 GENERICS_TYPE_TOKEN exactGenericArgsToken,
7377 DWORD dwExactGenericArgsTokenIndex,
7378 bool fVarArgFnx,
7379 CordbReJitILCode * pRejitCode)
7380 : CordbBase(pNativeFrame->GetProcess(), 0, enumCordbJITILFrame),
7381 m_nativeFrame(pNativeFrame),
7382 m_ilCode(pCode),
7383 m_ip(ip),
7384 m_mapping(mapping),
7385 m_fVarArgFnx(fVarArgFnx),
7386 m_allArgsCount(0),
7387 m_rgbSigParserBuf(NULL),
7388 m_FirstArgAddr(NULL),
7389 m_rgNVI(NULL),
7390 m_genericArgs(),
7391 m_genericArgsLoaded(false),
7392 m_frameParamsToken(exactGenericArgsToken),
7393 m_dwFrameParamsTokenIndex(dwExactGenericArgsTokenIndex),
7394 m_pReJitCode(pRejitCode)
7395{
7396 // We'll initialize the SigParser in CordbJITILFrame::Init().
7397 m_sigParserCached = SigParser(NULL, 0);
7398 _ASSERTE(m_sigParserCached.IsNull());
7399
7400 HRESULT hr = S_OK;
7401 EX_TRY
7402 {
7403 m_nativeFrame->m_pThread->GetRefreshStackNeuterList()->Add(GetProcess(), this);
7404 }
7405 EX_CATCH_HRESULT(hr);
7406 SetUnrecoverableIfFailed(GetProcess(), hr);
7407}
7408
7409//---------------------------------------------------------------------------------------
7410//
7411// Initialize a CordbJITILFrame object. Must be called after allocating the object and before using it.
7412// If Init fails, then destroy the object and release the memory.
7413//
7414// Return Value:
7415// HRESULT for the operation
7416//
7417// Notes:
7418// This is a nop if the function is not a vararg function.
7419//
7420
7421HRESULT CordbJITILFrame::Init()
7422{
7423 // ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
7424 HRESULT hr = S_OK;
7425
7426
7427 EX_TRY
7428 {
7429 _ASSERTE(m_ilCode != NULL);
7430
7431 if (m_fVarArgFnx)
7432 {
7433 // First, we need to find the VASigCookie. Use the native var info to do so.
7434 const ICorDebugInfo::NativeVarInfo * pNativeVarInfo = NULL;
7435 CordbNativeFrame * pNativeFrame = this->m_nativeFrame;
7436
7437 pNativeFrame->m_nativeCode->LoadNativeInfo();
7438 hr = pNativeFrame->m_nativeCode->ILVariableToNative((DWORD)ICorDebugInfo::VARARGS_HND_ILNUM,
7439 pNativeFrame->GetInspectionIP(),
7440 &pNativeVarInfo);
7441 IfFailThrow(hr);
7442
7443 // Check for the case where the VASigCookie isn't pushed on the stack yet.
7444 // This should only be a problem with optimized code.
7445 if (pNativeVarInfo->loc.vlType != ICorDebugInfo::VLT_STK)
7446 {
7447 ThrowHR(E_FAIL);
7448 }
7449
7450 // Retrieve the target address.
7451 CORDB_ADDRESS pRemoteValue = pNativeFrame->GetLSStackAddress(
7452 pNativeVarInfo->loc.vlStk.vlsBaseReg,
7453 pNativeVarInfo->loc.vlStk.vlsOffset);
7454
7455 CORDB_ADDRESS argBase;
7456 // Now is the time to ask DacDbi to retrieve the information based on the VASigCookie.
7457 IDacDbiInterface * pDAC = GetProcess()->GetDAC();
7458 TargetBuffer sigTargetBuf = pDAC->GetVarArgSig(pRemoteValue, &argBase);
7459
7460 // make sure we are not leaking any memory
7461 _ASSERTE(m_rgbSigParserBuf == NULL);
7462
7463 m_rgbSigParserBuf = new BYTE[sigTargetBuf.cbSize];
7464 GetProcess()->SafeReadBuffer(sigTargetBuf, m_rgbSigParserBuf);
7465 m_sigParserCached = SigParser(m_rgbSigParserBuf, sigTargetBuf.cbSize);
7466
7467 // Note that we should never mutate the SigParser.
7468 // Instead, make a copy and work with the copy instead.
7469 if (!m_sigParserCached.IsNull())
7470 {
7471 SigParser sigParser = m_sigParserCached;
7472
7473 // get the actual count of arguments, including the var args
7474 IfFailThrow(sigParser.SkipMethodHeaderSignature(&m_allArgsCount));
7475
7476 BOOL methodIsStatic;
7477
7478 m_ilCode->GetSig(NULL, NULL, &methodIsStatic); // throws
7479
7480 if (!methodIsStatic)
7481 {
7482 m_allArgsCount++; // skip the "this" object
7483 }
7484
7485 // initialize the variable lifetime information
7486 m_rgNVI = new ICorDebugInfo::NativeVarInfo[m_allArgsCount]; // throws
7487
7488 _ASSERTE(ICorDebugInfo::VLT_COUNT <= ICorDebugInfo::VLT_INVALID);
7489
7490 for (ULONG i = 0; i < m_allArgsCount; i++)
7491 {
7492 m_rgNVI[i].loc.vlType = ICorDebugInfo::VLT_INVALID;
7493 }
7494 }
7495
7496 // GetVarArgSig gets the address of the beginning of the arguments pushed for this frame.
7497 // We'll need the address of the first argument, which will depend on its size and the
7498 // calling convention, so we'll commpute that now that we have the SigParser.
7499 CordbType * pArgType;
7500 IfFailThrow(GetArgumentType(0, &pArgType));
7501 ULONG32 argSize = 0;
7502 IfFailThrow(pArgType->GetUnboxedObjectSize(&argSize));
7503#if defined(_TARGET_X86_) // (STACK_GROWS_DOWN_ON_ARGS_WALK)
7504 m_FirstArgAddr = argBase - argSize;
7505#else // !_TARGET_X86_ (STACK_GROWS_UP_ON_ARGS_WALK)
7506 AlignAddressForType(pArgType, argBase);
7507 m_FirstArgAddr = argBase;
7508#endif // !_TARGET_X86_ (STACK_GROWS_UP_ON_ARGS_WALK)
7509 }
7510
7511 // The stackwalking code can't always successfully retrieve the generics type token.
7512 // For example, on 64-bit, the JIT only encodes the generics type token location if
7513 // a method has catch clause for a generic exception (e.g. "catch(MyException<string> e)").
7514 if ((m_dwFrameParamsTokenIndex != (DWORD)ICorDebugInfo::MAX_ILNUM) && (m_frameParamsToken == NULL))
7515 {
7516 // All variables are unavailable in the prolog and the epilog.
7517 // This includes the generics type token. Failing to get the token just means that
7518 // we won't have full generics information. This should not be a disastrous failure.
7519 //
7520 // Currently, on X64, the JIT is reporting that the variables are live even in the epilog.
7521 // That's why we need this check here. I need to follow up on this.
7522 if ((m_mapping != MAPPING_PROLOG) && (m_mapping != MAPPING_EPILOG))
7523 {
7524 // Find the generics type token using the variable lifetime information.
7525 const ICorDebugInfo::NativeVarInfo * pNativeVarInfo = NULL;
7526 CordbNativeFrame * pNativeFrame = this->m_nativeFrame;
7527
7528 pNativeFrame->m_nativeCode->LoadNativeInfo();
7529 HRESULT hrTmp = pNativeFrame->m_nativeCode->ILVariableToNative(m_dwFrameParamsTokenIndex,
7530 pNativeFrame->GetInspectionIP(),
7531 &pNativeVarInfo);
7532
7533 // It's not a disaster if we can't find the generics token, so don't throw an exception here.
7534 // In fact, it's fairly common in retail code. Even if we can't find the generics token,
7535 // we may still be able to look up the generics type information later by using the MethodDesc,
7536 // the "this" object, etc. If not, we'll at least get the representative type information
7537 // (e.g. Foo<T> instead of Foo<string>).
7538 if (SUCCEEDED(hrTmp))
7539 {
7540 _ASSERTE(pNativeVarInfo != NULL);
7541
7542 // The generics type token should be stored either in a register or on the stack.
7543 SIZE_T uRawToken = pNativeFrame->GetRegisterOrStackValue(pNativeVarInfo);
7544
7545 // Ask DAC to resolve the token for us. We really don't want to deal with all the logic here.
7546 IDacDbiInterface * pDAC = GetProcess()->GetDAC();
7547 // On a minidump, we'll throw if we're missing the memory.
7548 ALLOW_DATATARGET_MISSING_MEMORY(
7549 m_frameParamsToken = pDAC->ResolveExactGenericArgsToken(m_dwFrameParamsTokenIndex, uRawToken);
7550 );
7551 }
7552 }
7553 }
7554 }
7555 EX_CATCH_HRESULT(hr);
7556
7557 return hr;
7558}
7559
7560/*
7561 A list of which resources owned by this object are accounted for.
7562
7563 UNKNOWN:
7564 CordbNativeFrame* m_nativeFrame;
7565 CordbILCode * m_ilCode;
7566 CorDebugMappingResult m_mapping;
7567 CORDB_ADDRESS m_FirstArgAddr;
7568 ICorDebugInfo::NativeVarInfo * m_rgNVI; // Deleted in neuter
7569 CordbClass **m_genericArgs;
7570*/
7571
7572CordbJITILFrame::~CordbJITILFrame()
7573{
7574 _ASSERTE(IsNeutered());
7575}
7576
7577// Neutered by CordbNativeFrame
7578void CordbJITILFrame::Neuter()
7579{
7580 // Since neutering here calls Release directly, we don't want to double-release
7581 // if neuter is called multiple times.
7582 if (IsNeutered())
7583 {
7584 return;
7585 }
7586
7587 // Frames include pointers across to other types that specify the
7588 // representation instantiation - reduce the reference counts on these....
7589 for (unsigned int i = 0; i < m_genericArgs.m_cInst; i++)
7590 {
7591 m_genericArgs.m_ppInst[i]->Release();
7592 }
7593
7594 if (m_rgNVI != NULL)
7595 {
7596 delete [] m_rgNVI;
7597 m_rgNVI = NULL;
7598 }
7599
7600 if (m_rgbSigParserBuf != NULL)
7601 {
7602 delete [] m_rgbSigParserBuf;
7603 m_rgbSigParserBuf = NULL;
7604 }
7605
7606 m_pReJitCode.Clear();
7607
7608 // If this class ever inherits from the CordbFrame we'll need a call
7609 // to CordbFrame::Neuter() here instead of to CordbBase::Neuter();
7610 CordbBase::Neuter();
7611}
7612
7613//---------------------------------------------------------------------------------------
7614//
7615// Load the generic type and method arguments and store them into the frame if possible.
7616//
7617// Return Value:
7618// HRESULT for the operation
7619//
7620
7621void CordbJITILFrame::LoadGenericArgs()
7622{
7623 THROW_IF_NEUTERED(this);
7624 INTERNAL_SYNC_API_ENTRY(GetProcess()); //
7625
7626 // The case where there are no type parameters, or the case where we've
7627 // already feched the realInst, is easy.
7628 if (m_genericArgsLoaded)
7629 {
7630 return;
7631 }
7632
7633 _ASSERTE(m_nativeFrame->m_nativeCode != NULL);
7634
7635 if (!m_nativeFrame->m_nativeCode->IsInstantiatedGeneric())
7636 {
7637 m_genericArgs = Instantiation(0, NULL,0);
7638 m_genericArgsLoaded = true;
7639 return;
7640 }
7641
7642 // Find the exact generic arguments for a frame that is executing
7643 // a generic method. The left-side will fetch these from arguments
7644 // given on the stack and/or from the IP.
7645
7646
7647 IDacDbiInterface * pDAC = GetProcess()->GetDAC();
7648
7649 UINT32 cGenericClassTypeParams = 0;
7650 DacDbiArrayList<DebuggerIPCE_ExpandedTypeData> rgGenericTypeParams;
7651
7652 pDAC->GetMethodDescParams(GetCurrentAppDomain()->GetADToken(),
7653 m_nativeFrame->GetNativeCode()->GetVMNativeCodeMethodDescToken(),
7654 m_frameParamsToken,
7655 &cGenericClassTypeParams,
7656 &rgGenericTypeParams);
7657
7658 UINT32 cTotalGenericTypeParams = rgGenericTypeParams.Count();
7659
7660 // @dbgtodo reliability - This holder doesn't actually work in this case because it just deletes
7661 // each element on error. The RS classes are all expected to be neutered before the destructor is called.
7662 NewArrayHolder<CordbType *> ppGenericArgs(new CordbType *[cTotalGenericTypeParams]);
7663
7664 for (UINT32 i = 0; i < cTotalGenericTypeParams;i++)
7665 {
7666 // creates a CordbType object for the generic argument
7667 HRESULT hr = CordbType::TypeDataToType(GetCurrentAppDomain(),
7668 &(rgGenericTypeParams[i]),
7669 &ppGenericArgs[i]);
7670 IfFailThrow(hr);
7671
7672 // We add a ref as the instantiation will be stored away in the
7673 // ref-counted data structure associated with the JITILFrame
7674 ppGenericArgs[i]->AddRef();
7675 }
7676
7677 // initialize the generics information
7678 m_genericArgs = Instantiation(cTotalGenericTypeParams, ppGenericArgs, cGenericClassTypeParams);
7679 m_genericArgsLoaded = true;
7680
7681 ppGenericArgs.SuppressRelease();
7682}
7683
7684
7685//
7686// CordbJITILFrame::QueryInterface
7687//
7688// Description
7689// Interface query for this COM object
7690//
7691// NOTE: the COM object associated with this CordbJITILFrame may consist of two
7692// C++ objects (a CordbJITILFrame and its associated CordbNativeFrame)
7693//
7694// Parameters
7695// id the GUID associated with the requested interface
7696// pInterface [out] the interface pointer
7697//
7698// Returns
7699// HRESULT
7700// S_OK If this CordbJITILFrame supports the interface
7701// E_NOINTERFACE If this object does not support the interface
7702//
7703// Exceptions
7704// None
7705//
7706HRESULT CordbJITILFrame::QueryInterface(REFIID id, void **pInterface)
7707{
7708 if (NULL != m_nativeFrame)
7709 {
7710 // If the native frame does not support the requested interface, then
7711 // the native fram is responsible for delegating the query back to this
7712 // object through QueryInterfaceInternal(...)
7713 return m_nativeFrame->QueryInterface(id, pInterface);
7714 }
7715
7716 // no native frame. Check for interfaces common to CordbNativeFrame and
7717 // CordbJITILFrame
7718 if (id == IID_IUnknown)
7719 {
7720 *pInterface = static_cast<IUnknown*>(static_cast<ICorDebugILFrame*>(this));
7721 }
7722 else if (id == IID_ICorDebugFrame)
7723 {
7724 *pInterface = static_cast<ICorDebugFrame*>(this);
7725 }
7726 else
7727 {
7728 // didn't find an interface yet. Since there's no native frame
7729 // associated with this IL frame, go ahead and check for the IL frame
7730 return this->QueryInterfaceInternal(id, pInterface);
7731 }
7732
7733 ExternalAddRef();
7734 return S_OK;
7735}
7736
7737//
7738// CordbJITILFrame::QueryInterfaceInternal
7739//
7740// Description
7741// Interface query for interfaces implemented ONLY by CordbJITILFrame (as
7742// opposed to interfaces implemented by both CordbNativeFrame and
7743// CordbJITILFrame)
7744//
7745// Parameters
7746// id the GUID associated with the requested interface
7747// pInterface [out] the interface pointer
7748// NOTE: id must not be IUnknown or ICorDebugFrame
7749// NOTE: if this object is in "forward compatibility mode", passing in
7750// IID_ICorDebugILFrame2 for the id will result in a failure (returns
7751// E_NOINTERFACE)
7752//
7753// Returns
7754// HRESULT
7755// S_OK If this CordbJITILFrame supports the interface
7756// E_NOINTERFACE If this object does not support the interface
7757//
7758// Exceptions
7759// None
7760//
7761HRESULT
7762CordbJITILFrame::QueryInterfaceInternal(REFIID id, void** pInterface)
7763{
7764 _ASSERTE(IID_ICorDebugFrame != id);
7765 _ASSERTE(IID_IUnknown != id);
7766
7767 // don't query for IUnknown or ICorDebugFrame! Someone else should have
7768 // already taken care of that.
7769 if (id == IID_ICorDebugILFrame)
7770 {
7771 *pInterface = static_cast<ICorDebugILFrame*>(this);
7772 }
7773 else if (id == IID_ICorDebugILFrame2)
7774 {
7775 *pInterface = static_cast<ICorDebugILFrame2*>(this);
7776 }
7777 else if (id == IID_ICorDebugILFrame3)
7778 {
7779 *pInterface = static_cast<ICorDebugILFrame3*>(this);
7780 }
7781 else if (id == IID_ICorDebugILFrame4)
7782 {
7783 *pInterface = static_cast<ICorDebugILFrame4*>(this);
7784 }
7785 else
7786 {
7787 *pInterface = NULL;
7788 return E_NOINTERFACE;
7789 }
7790
7791 ExternalAddRef();
7792 return S_OK;
7793}
7794
7795//---------------------------------------------------------------------------------------
7796//
7797// Get an enumerator for the generic type and method arguments on this frame.
7798//
7799// Arguments:
7800// ppTypeParameterEnum - out parameter; return the enumerator
7801//
7802// Return Value:
7803// HRESULT for the operation
7804//
7805HRESULT CordbJITILFrame::EnumerateTypeParameters(ICorDebugTypeEnum **ppTypeParameterEnum)
7806{
7807 PUBLIC_API_ENTRY(this);
7808 FAIL_IF_NEUTERED(this);
7809 VALIDATE_POINTER_TO_OBJECT(ppTypeParameterEnum, ICorDebugTypeEnum **);
7810 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
7811
7812 (*ppTypeParameterEnum) = NULL;
7813
7814 HRESULT hr = S_OK;
7815 EX_TRY
7816 {
7817
7818 // load the generic arguments, which may be cached
7819 LoadGenericArgs();
7820
7821 // create the enumerator
7822 RSInitHolder<CordbTypeEnum> pEnum(
7823 CordbTypeEnum::Build(GetCurrentAppDomain(), m_nativeFrame->m_pThread->GetRefreshStackNeuterList(), m_genericArgs.m_cInst, m_genericArgs.m_ppInst));
7824 if ( pEnum == NULL )
7825 {
7826 ThrowOutOfMemory();
7827 }
7828
7829 pEnum.TransferOwnershipExternal(ppTypeParameterEnum);
7830 }
7831 EX_CATCH_HRESULT(hr);
7832 return hr;
7833}
7834
7835
7836// ----------------------------------------------------------------------------
7837// CordbJITILFrame::GetChain
7838//
7839// Description:
7840// Return the owning chain. Since chains have been deprecated in Arrowhead,
7841// this function returns E_NOTIMPL unless there is a shim.
7842//
7843// Arguments:
7844// * ppChain - out parameter; return the owning chain
7845//
7846// Return Value:
7847// Return S_OK on success.
7848// Return E_INVALIDARG if ppChain is NULL.
7849// Return CORDBG_E_OBJECT_NEUTERED if the CordbJITILFrame is neutered.
7850// Return E_NOTIMPL if there is no shim.
7851//
7852
7853HRESULT CordbJITILFrame::GetChain(ICorDebugChain **ppChain)
7854{
7855 PUBLIC_REENTRANT_API_ENTRY(this);
7856 FAIL_IF_NEUTERED(this);
7857 VALIDATE_POINTER_TO_OBJECT(ppChain, ICorDebugChain **);
7858
7859 HRESULT hr = S_OK;
7860 EX_TRY
7861 {
7862 hr = m_nativeFrame->GetChain(ppChain);
7863 // Since we are returning anyway, let's not throw even if the call fails.
7864 }
7865 EX_CATCH_HRESULT(hr);
7866 return hr;
7867}
7868
7869// Return the IL code blob associated with this IL frame.
7870// Each IL frame corresponds to exactly one IL code blob.
7871HRESULT CordbJITILFrame::GetCode(ICorDebugCode **ppCode)
7872{
7873 FAIL_IF_NEUTERED(this);
7874 VALIDATE_POINTER_TO_OBJECT(ppCode, ICorDebugCode **);
7875
7876 *ppCode = static_cast<ICorDebugCode*> (m_ilCode);
7877 m_ilCode->ExternalAddRef();
7878
7879 return S_OK;;
7880}
7881
7882// Return the function associated with this IL frame.
7883// Each IL frame corresponds to exactly one function.
7884HRESULT CordbJITILFrame::GetFunction(ICorDebugFunction **ppFunction)
7885{
7886 HRESULT hr = S_OK;
7887 PUBLIC_API_BEGIN(this)
7888 {
7889 ValidateOrThrow(ppFunction);
7890
7891 CordbFunction * pFunc = m_nativeFrame->GetFunction();
7892 *ppFunction = static_cast<ICorDebugFunction *>(pFunc);
7893 pFunc->ExternalAddRef();
7894 }
7895 PUBLIC_API_END(hr);
7896 return hr;
7897}
7898
7899// Return the token of the function associated with this IL frame.
7900// Each IL frame corresponds to exactly one function.
7901HRESULT CordbJITILFrame::GetFunctionToken(mdMethodDef *pToken)
7902{
7903 FAIL_IF_NEUTERED(this);
7904 VALIDATE_POINTER_TO_OBJECT(pToken, mdMethodDef *);
7905
7906 *pToken = m_nativeFrame->m_nativeCode->GetMetadataToken();
7907
7908 return S_OK;
7909}
7910
7911// ----------------------------------------------------------------------------
7912// CordJITILFrame::GetStackRange
7913//
7914// Description:
7915// Get the stack range owned by the associated native frame.
7916// IL frames and native frames are 1:1 for normal jitted managed methods.
7917// Dynamic methods are an exception.
7918//
7919// Arguments:
7920// * pStart - out parameter; return the leaf end of the frame
7921// * pEnd - out parameter; return the root end of the frame
7922//
7923// Return Value:
7924// Return S_OK on success.
7925//
7926// Notes: see code:#GetStackRange
7927
7928HRESULT CordbJITILFrame::GetStackRange(CORDB_ADDRESS *pStart, CORDB_ADDRESS *pEnd)
7929{
7930 PUBLIC_REENTRANT_API_ENTRY(this);
7931
7932 // The access of m_nativeFrame is not safe here. It's a weak reference.
7933 OK_IF_NEUTERED(this);
7934
7935 HRESULT hr = S_OK;
7936 EX_TRY
7937 {
7938 hr = m_nativeFrame->GetStackRange(pStart, pEnd);
7939 // Since we are returning anyway, let's not throw even if the call fails.
7940 }
7941 EX_CATCH_HRESULT(hr);
7942 return hr;
7943}
7944
7945// ----------------------------------------------------------------------------
7946// CordbJITILFrame::GetCaller
7947//
7948// Description:
7949// Delegate to the associated native frame to return the caller, which is closer to the root.
7950// This function has been deprecated in Arrowhead, and so it returns E_NOTIMPL unless there is a shim.
7951//
7952// Arguments:
7953// * ppFrame - out parameter; return the caller frame
7954//
7955// Return Value:
7956// Return S_OK on success.
7957// Return E_INVALIDARG if ppFrame is NULL.
7958// Return CORDBG_E_OBJECT_NEUTERED if the CordbJITILFrame is neutered.
7959// Return E_NOTIMPL if there is no shim.
7960//
7961
7962HRESULT CordbJITILFrame::GetCaller(ICorDebugFrame **ppFrame)
7963{
7964 PUBLIC_REENTRANT_API_ENTRY(this);
7965 FAIL_IF_NEUTERED(this);
7966 VALIDATE_POINTER_TO_OBJECT(ppFrame, ICorDebugFrame **);
7967
7968 HRESULT hr = S_OK;
7969 EX_TRY
7970 {
7971 hr = m_nativeFrame->GetCaller(ppFrame);
7972 // Since we are returning anyway, let's not throw even if the call fails.
7973 }
7974 EX_CATCH_HRESULT(hr);
7975 return hr;
7976}
7977
7978// ----------------------------------------------------------------------------
7979// CordbJITILFrame::GetCallee
7980//
7981// Description:
7982// Delegate to the associated native frame to return the callee, which is closer to the leaf.
7983// This function has been deprecated in Arrowhead, and so it returns E_NOTIMPL unless there is a shim.
7984//
7985// Arguments:
7986// * ppFrame - out parameter; return the callee frame
7987//
7988// Return Value:
7989// Return S_OK on success.
7990// Return E_INVALIDARG if ppFrame is NULL.
7991// Return CORDBG_E_OBJECT_NEUTERED if the CordbJITILFrame is neutered.
7992// Return E_NOTIMPL if there is no shim.
7993//
7994
7995HRESULT CordbJITILFrame::GetCallee(ICorDebugFrame **ppFrame)
7996{
7997 PUBLIC_REENTRANT_API_ENTRY(this);
7998 FAIL_IF_NEUTERED(this);
7999 VALIDATE_POINTER_TO_OBJECT(ppFrame, ICorDebugFrame **);
8000
8001 HRESULT hr = S_OK;
8002 EX_TRY
8003 {
8004 hr = m_nativeFrame->GetCallee(ppFrame);
8005 // Since we are returning anyway, let's not throw even if the call fails.
8006 }
8007 EX_CATCH_HRESULT(hr);
8008 return hr;
8009}
8010
8011// Create a stepper on the frame.
8012HRESULT CordbJITILFrame::CreateStepper(ICorDebugStepper **ppStepper)
8013{
8014 PUBLIC_API_ENTRY(this);
8015 FAIL_IF_NEUTERED(this);
8016 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
8017
8018 // by default, a stepper operates on the IL level, using IL offsets
8019 return m_nativeFrame->CreateStepper(ppStepper);
8020}
8021
8022// Return the IL offset and the mapping result.
8023HRESULT CordbJITILFrame::GetIP(ULONG32 *pnOffset,
8024 CorDebugMappingResult *pMappingResult)
8025{
8026 PUBLIC_REENTRANT_API_ENTRY(this);
8027 FAIL_IF_NEUTERED(this);
8028 VALIDATE_POINTER_TO_OBJECT(pnOffset, ULONG32 *);
8029 VALIDATE_POINTER_TO_OBJECT_OR_NULL(pMappingResult, CorDebugMappingResult *);
8030
8031 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
8032
8033 *pnOffset = (ULONG32)m_ip;
8034 if (pMappingResult)
8035 *pMappingResult = m_mapping;
8036
8037 return S_OK;
8038}
8039
8040// Determine if we can set IP at this point. The specified offset is the IL offset.
8041HRESULT CordbJITILFrame::CanSetIP(ULONG32 nOffset)
8042{
8043 PUBLIC_API_ENTRY(this);
8044 FAIL_IF_NEUTERED(this);
8045
8046 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
8047
8048 HRESULT hr = S_OK;
8049 EX_TRY
8050 {
8051 // Check to see that this is a leaf frame
8052 if (!m_nativeFrame->IsLeafFrame())
8053 {
8054 ThrowHR(CORDBG_E_SET_IP_NOT_ALLOWED_ON_NONLEAF_FRAME);
8055 }
8056
8057 // delegate to the associated native frame
8058 CordbNativeCode * pNativeCode = m_nativeFrame->m_nativeCode;
8059 hr = m_nativeFrame->m_pThread->SetIP(SetIP_fCanSetIPOnly, // specify that this is for checking only
8060 pNativeCode,
8061 nOffset,
8062 SetIP_fIL );
8063 }
8064 EX_CATCH_HRESULT(hr);
8065
8066 return hr;
8067}
8068
8069// Try to set the IP to the specified offset. The specified offset is the IL offset.
8070HRESULT CordbJITILFrame::SetIP(ULONG32 nOffset)
8071{
8072 PUBLIC_API_ENTRY(this);
8073 FAIL_IF_NEUTERED(this);
8074
8075 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
8076
8077 HRESULT hr = S_OK;
8078 EX_TRY
8079 {
8080 // Check to see that this is a leaf frame
8081 if (!m_nativeFrame->IsLeafFrame())
8082 {
8083 ThrowHR(CORDBG_E_SET_IP_NOT_ALLOWED_ON_NONLEAF_FRAME);
8084 }
8085
8086 // delegate to the native frame
8087 CordbNativeCode * pNativeCode = m_nativeFrame->m_nativeCode;
8088 hr = m_nativeFrame->m_pThread->SetIP(SetIP_fSetIP, // specify that this is a real SetIP operation
8089 pNativeCode,
8090 nOffset,
8091 SetIP_fIL );
8092 }
8093 EX_CATCH_HRESULT(hr);
8094
8095 return hr;
8096}
8097
8098//---------------------------------------------------------------------------------------
8099//
8100// This routine creates backing native info for a local variable, returning an ICorDebugInfo
8101// object for the local variable when successful.
8102//
8103// Arguments:
8104// dwIndex - Index of the local variable to create native info for.
8105// ppNativeInfo - OUT: Space for storing the resulting pointer to native variable info.
8106//
8107// Return Value:
8108// HRESULT for the operation
8109//
8110HRESULT CordbJITILFrame::FabricateNativeInfo(DWORD dwIndex,
8111 const ICorDebugInfo::NativeVarInfo ** ppNativeInfo)
8112{
8113 HRESULT hr = S_OK;
8114 EX_TRY
8115 {
8116 THROW_IF_NEUTERED(this);
8117 INTERNAL_SYNC_API_ENTRY(this->GetProcess());
8118 _ASSERTE(m_fVarArgFnx);
8119
8120 // This array should have been populated in CordbJITILFrame::Init().
8121 _ASSERTE(m_rgNVI != NULL);
8122
8123 // check if we have already fabricated all the information
8124 if (m_rgNVI[dwIndex].loc.vlType != ICorDebugInfo::VLT_INVALID)
8125 {
8126 (*ppNativeInfo) = &m_rgNVI[dwIndex];
8127 }
8128 else
8129 {
8130 // We'll initialize everything at once
8131 ULONG cbArchitectureMin;
8132
8133 // m_FirstArgAddr will already be aligned on platforms that require alignment
8134 CORDB_ADDRESS rpCur = m_FirstArgAddr;
8135
8136#if defined(DBG_TARGET_X86) || defined(DBG_TARGET_ARM)
8137 cbArchitectureMin = 4;
8138#elif defined(DBG_TARGET_WIN64)
8139 cbArchitectureMin = 8;
8140#else
8141 cbArchitectureMin = 8; //REVISIT_TODO not sure if this is correct
8142 PORTABILITY_ASSERT("What is the architecture-dependent minimum word size?");
8143#endif // DBG_TARGET_X86
8144
8145 // make a copy of the cached SigParser
8146 SigParser sigParser = m_sigParserCached;
8147
8148 IfFailThrow(sigParser.SkipMethodHeaderSignature(NULL));
8149
8150 ULONG32 cbType;
8151
8152 CordbType * pArgType;
8153
8154 // make sure all the generic type and method arguments are loaded
8155 LoadGenericArgs();
8156
8157 // get a CordbType object for the generic argument
8158 IfFailThrow(CordbType::SigToType(GetModule(), &sigParser, &(this->m_genericArgs), &pArgType));
8159
8160 IfFailThrow(pArgType->GetUnboxedObjectSize(&cbType));
8161
8162#if defined(DBG_TARGET_X86) // STACK_GROWS_DOWN_ON_ARGS_WALK
8163 // The the rpCur pointer starts off in the right spot for the
8164 // first argument, but thereafter we have to decrement it
8165 // before getting the variable's location from it. So increment
8166 // it here to be consistent later.
8167 rpCur += max(cbType, cbArchitectureMin);
8168#endif
8169
8170 // Grab the IL code's function's method signature so we can see if it's static.
8171 BOOL fMethodIsStatic;
8172
8173 m_ilCode->GetSig(NULL, NULL, &fMethodIsStatic); // throws
8174
8175 ULONG i;
8176
8177 if (fMethodIsStatic)
8178 {
8179 i = 0;
8180 }
8181 else
8182 {
8183 i = 1;
8184 }
8185
8186 for ( ; i < m_allArgsCount; i++)
8187 {
8188 m_rgNVI[i].startOffset = 0;
8189 m_rgNVI[i].endOffset = 0xFFffFFff;
8190 m_rgNVI[i].varNumber = i;
8191 m_rgNVI[i].loc.vlType = ICorDebugInfo::VLT_FIXED_VA;
8192
8193 LoadGenericArgs();
8194
8195 IfFailThrow(CordbType::SigToType(GetModule(), &sigParser, &(this->m_genericArgs), &pArgType));
8196
8197 IfFailThrow(pArgType->GetUnboxedObjectSize(&cbType));
8198
8199#if defined(DBG_TARGET_X86) // STACK_GROWS_DOWN_ON_ARGS_WALK
8200 rpCur -= max(cbType, cbArchitectureMin);
8201 m_rgNVI[i].loc.vlFixedVarArg.vlfvOffset =
8202 (unsigned)(m_FirstArgAddr - rpCur);
8203
8204 // Since the JIT adds in the size of this field, we do too to
8205 // be consistent.
8206 m_rgNVI[i].loc.vlFixedVarArg.vlfvOffset += sizeof(((CORINFO_VarArgInfo*)0)->argBytes);
8207#else // STACK_GROWS_UP_ON_ARGS_WALK
8208 m_rgNVI[i].loc.vlFixedVarArg.vlfvOffset =
8209 (unsigned)(rpCur - m_FirstArgAddr);
8210 rpCur += max(cbType, cbArchitectureMin);
8211 AlignAddressForType(pArgType, rpCur);
8212#endif
8213
8214 IfFailThrow(sigParser.SkipExactlyOne());
8215 } // for ( ; i M m_allArgsCount; i++)
8216
8217 (*ppNativeInfo) = &m_rgNVI[dwIndex];
8218 } // else (m_rgNVI[dwIndex].loc.vlType == ICorDebugInfo::VLT_INVALID)
8219 }
8220 EX_CATCH_HRESULT(hr);
8221
8222 return hr;
8223}
8224
8225HRESULT CordbJITILFrame::ILVariableToNative(DWORD dwVarNumber,
8226 const ICorDebugInfo::NativeVarInfo **ppNativeInfo)
8227{
8228 FAIL_IF_NEUTERED(this);
8229 INTERNAL_SYNC_API_ENTRY(GetProcess()); //
8230
8231 _ASSERTE(m_nativeFrame->m_nativeCode->IsNativeCodeValid());
8232 // We keep the fixed argument native var infos in the
8233 // CordbFunction, which only is an issue for var args info:
8234 if (!m_fVarArgFnx || //not a var args function
8235 (dwVarNumber < m_nativeFrame->m_nativeCode->GetFixedArgCount()) || // var args,fixed arg
8236 // note that this include the implicit 'this' for nonstatic fnxs
8237 (dwVarNumber >= m_allArgsCount) ||// var args, local variable
8238 (m_sigParserCached.IsNull())) //we don't have any VA info
8239 {
8240 // If we're in a var args fnx, but we're actually looking
8241 // for a local variable, then we want to use the variable
8242 // index as the function sees it - fixed (but not var)
8243 // args are added to local var number to get native info
8244 // We are really trying to find a variable by it's number,
8245 // but "special" variables have a negative number which we
8246 // don't use. We "number" them conceptually between the
8247 // arguments and locals:
8248 //
8249 // arguments special locals
8250 // -----------------------------------------
8251 // Actual numbers: 1 2 3 . . . 4 5 6 7
8252 // Logical numbers: 0 1 2 3 4 5 6 7 8
8253 //
8254 // We have two different counts for the number of arguments: the fixedArgCount
8255 // gives the actual number of arguments and the allArgsCount is the number of
8256 // of fixed arguments plus the number of var args.
8257 //
8258 // Thus, to get the correct actual number for locals we have to compute it as
8259 // logicalNumber - allArgsCount + fixedArgCount
8260
8261 if (m_fVarArgFnx && (dwVarNumber >= m_allArgsCount) && !m_sigParserCached.IsNull())
8262 {
8263 dwVarNumber -= m_allArgsCount;
8264 dwVarNumber += m_nativeFrame->m_nativeCode->GetFixedArgCount();
8265 }
8266
8267 return m_nativeFrame->m_nativeCode->ILVariableToNative(dwVarNumber,
8268 m_nativeFrame->GetInspectionIP(),
8269 ppNativeInfo);
8270 }
8271
8272 return FabricateNativeInfo(dwVarNumber,ppNativeInfo);
8273}
8274
8275//---------------------------------------------------------------------------------------
8276//
8277// This routine get the type of a particular argument.
8278//
8279// Arguments:
8280// dwIndex - Index of the argument.
8281// ppResultType - OUT: Space for storing the type of the argument.
8282//
8283// Return Value:
8284// HRESULT for the operation
8285//
8286HRESULT CordbJITILFrame::GetArgumentType(DWORD dwIndex,
8287 CordbType ** ppResultType)
8288{
8289 HRESULT hr = S_OK;
8290 THROW_IF_NEUTERED(this);
8291 INTERNAL_SYNC_API_ENTRY(GetProcess());
8292
8293 LoadGenericArgs();
8294
8295 if (m_fVarArgFnx && !m_sigParserCached.IsNull())
8296 {
8297 SigParser sigParser = m_sigParserCached;
8298
8299 IfFailThrow(sigParser.SkipMethodHeaderSignature(NULL));
8300
8301 // Grab the IL code's function's method signature so we can see if it's static.
8302 BOOL fMethodIsStatic;
8303
8304 m_ilCode->GetSig(NULL, NULL, &fMethodIsStatic); // throws
8305 if (!fMethodIsStatic)
8306 {
8307 if (dwIndex == 0)
8308 {
8309 // Return the signature for the 'this' pointer for the
8310 // class this method is in.
8311
8312 IfFailThrow(m_ilCode->GetClass()->GetThisType(&(this->m_genericArgs), ppResultType));
8313 return hr;
8314 }
8315 else
8316 {
8317 dwIndex--;
8318 }
8319 }
8320 for (ULONG i = 0; i < dwIndex; i++)
8321 {
8322 IfFailThrow(sigParser.SkipExactlyOne());
8323 }
8324
8325 IfFailThrow(sigParser.SkipFunkyAndCustomModifiers());
8326
8327 IfFailThrow(sigParser.SkipAnyVASentinel());
8328
8329 IfFailThrow(CordbType::SigToType(GetModule(), &sigParser, &(this->m_genericArgs), ppResultType));
8330 }
8331 else // (!m_fVarArgFnx || m_sigParserCached.IsNull())
8332 {
8333 m_nativeFrame->m_nativeCode->GetArgumentType(dwIndex, &(this->m_genericArgs), ppResultType);
8334 }
8335
8336 return hr;
8337}
8338
8339//
8340// GetNativeVariable uses the JIT variable information to delegate to
8341// the native frame when the value is really created.
8342//
8343HRESULT CordbJITILFrame::GetNativeVariable(CordbType *type,
8344 const ICorDebugInfo::NativeVarInfo *pNativeVarInfo,
8345 ICorDebugValue **ppValue)
8346{
8347 INTERNAL_API_ENTRY(this);
8348 FAIL_IF_NEUTERED(this);
8349
8350 HRESULT hr = S_OK;
8351
8352#ifdef WIN64EXCEPTIONS
8353 if (m_nativeFrame->IsFunclet())
8354 {
8355 if ( (pNativeVarInfo->loc.vlType != ICorDebugInfo::VLT_STK) &&
8356 (pNativeVarInfo->loc.vlType != ICorDebugInfo::VLT_STK2) &&
8357 (pNativeVarInfo->loc.vlType != ICorDebugInfo::VLT_STK_BYREF) )
8358 {
8359 _ASSERTE(!"CordbJITILFrame::GetNativeVariable()"
8360 " - Variables used in funclets should always be homed on the stack.\n");
8361 return E_FAIL;
8362 }
8363 }
8364#endif // WIN64EXCEPTIONS
8365
8366 switch (pNativeVarInfo->loc.vlType)
8367 {
8368 case ICorDebugInfo::VLT_REG:
8369 hr = m_nativeFrame->GetLocalRegisterValue(
8370 ConvertRegNumToCorDebugRegister(pNativeVarInfo->loc.vlReg.vlrReg),
8371 type, ppValue);
8372 break;
8373
8374 case ICorDebugInfo::VLT_REG_BYREF:
8375 {
8376 CORDB_ADDRESS pRemoteByRefAddr = PTR_TO_CORDB_ADDRESS(
8377 *( m_nativeFrame->GetAddressOfRegister(ConvertRegNumToCorDebugRegister(pNativeVarInfo->loc.vlReg.vlrReg))) );
8378
8379 hr = m_nativeFrame->GetLocalMemoryValue(pRemoteByRefAddr,
8380 type,
8381 ppValue);
8382 }
8383 break;
8384
8385#if defined(DBG_TARGET_WIN64) || defined(DBG_TARGET_ARM)
8386 case ICorDebugInfo::VLT_REG_FP:
8387#if defined(DBG_TARGET_ARM) // @ARMTODO
8388 hr = E_NOTIMPL;
8389#else // DBG_TARGET_ARM @ARMTODO
8390 hr = m_nativeFrame->GetLocalFloatingPointValue(pNativeVarInfo->loc.vlReg.vlrReg + REGISTER_AMD64_XMM0,
8391 type, ppValue);
8392
8393#endif // DBG_TARGET_ARM @ARMTODO
8394 break;
8395#endif // DBG_TARGET_WIN64 || DBG_TARGET_ARM
8396
8397 case ICorDebugInfo::VLT_STK_BYREF:
8398 {
8399 CORDB_ADDRESS pRemoteByRefAddr = m_nativeFrame->GetLSStackAddress(
8400 pNativeVarInfo->loc.vlStk.vlsBaseReg, pNativeVarInfo->loc.vlStk.vlsOffset) ;
8401
8402 hr = m_nativeFrame->GetLocalByRefMemoryValue(pRemoteByRefAddr,
8403 type,
8404 ppValue);
8405 }
8406 break;
8407
8408 case ICorDebugInfo::VLT_STK:
8409 {
8410 CORDB_ADDRESS pRemoteValue = m_nativeFrame->GetLSStackAddress(
8411 pNativeVarInfo->loc.vlStk.vlsBaseReg, pNativeVarInfo->loc.vlStk.vlsOffset) ;
8412
8413 hr = m_nativeFrame->GetLocalMemoryValue(pRemoteValue,
8414 type,
8415 ppValue);
8416 }
8417 break;
8418
8419 case ICorDebugInfo::VLT_REG_REG:
8420 hr = m_nativeFrame->GetLocalDoubleRegisterValue(
8421 ConvertRegNumToCorDebugRegister(pNativeVarInfo->loc.vlRegReg.vlrrReg2),
8422 ConvertRegNumToCorDebugRegister(pNativeVarInfo->loc.vlRegReg.vlrrReg1),
8423 type, ppValue);
8424 break;
8425
8426 case ICorDebugInfo::VLT_REG_STK:
8427 {
8428 CORDB_ADDRESS pRemoteValue = m_nativeFrame->GetLSStackAddress(
8429 pNativeVarInfo->loc.vlRegStk.vlrsStk.vlrssBaseReg, pNativeVarInfo->loc.vlRegStk.vlrsStk.vlrssOffset);
8430
8431 hr = m_nativeFrame->GetLocalMemoryRegisterValue(
8432 pRemoteValue,
8433 ConvertRegNumToCorDebugRegister(pNativeVarInfo->loc.vlRegStk.vlrsReg),
8434 type, ppValue);
8435 }
8436 break;
8437
8438 case ICorDebugInfo::VLT_STK_REG:
8439 {
8440 CORDB_ADDRESS pRemoteValue = m_nativeFrame->GetLSStackAddress(
8441 pNativeVarInfo->loc.vlStkReg.vlsrStk.vlsrsBaseReg, pNativeVarInfo->loc.vlStkReg.vlsrStk.vlsrsOffset);
8442
8443 hr = m_nativeFrame->GetLocalRegisterMemoryValue(
8444 ConvertRegNumToCorDebugRegister(pNativeVarInfo->loc.vlStkReg.vlsrReg),
8445 pRemoteValue, type, ppValue);
8446 }
8447 break;
8448
8449 case ICorDebugInfo::VLT_STK2:
8450 {
8451 CORDB_ADDRESS pRemoteValue = m_nativeFrame->GetLSStackAddress(
8452 pNativeVarInfo->loc.vlStk2.vls2BaseReg, pNativeVarInfo->loc.vlStk2.vls2Offset);
8453
8454 hr = m_nativeFrame->GetLocalMemoryValue(pRemoteValue,
8455 type,
8456 ppValue);
8457 }
8458 break;
8459
8460 case ICorDebugInfo::VLT_FPSTK:
8461#if defined(DBG_TARGET_ARM) // @ARMTODO
8462 hr = E_NOTIMPL;
8463#else
8464 /*
8465 @TODO [Microsoft] We have to make this work!!!!!!!!!!!!!
8466 hr = m_nativeFrame->GetLocalFloatingPointValue(
8467 pNativeVarInfo->loc.vlFPstk.vlfReg + REGISTER_X86_FPSTACK_0,
8468 type, ppValue);
8469 */
8470 hr = CORDBG_E_IL_VAR_NOT_AVAILABLE;
8471#endif
8472 break;
8473
8474 case ICorDebugInfo::VLT_FIXED_VA:
8475 if (m_sigParserCached.IsNull()) //no var args info
8476 return CORDBG_E_IL_VAR_NOT_AVAILABLE;
8477
8478 CORDB_ADDRESS pRemoteValue;
8479
8480
8481#if defined(DBG_TARGET_X86) // STACK_GROWS_DOWN_ON_ARGS_WALK
8482 pRemoteValue = m_FirstArgAddr - pNativeVarInfo->loc.vlFixedVarArg.vlfvOffset;
8483 // Remember to subtract out this amount
8484 pRemoteValue += sizeof(((CORINFO_VarArgInfo*)0)->argBytes);
8485#else // STACK_GROWS_UP_ON_ARGS_WALK
8486 pRemoteValue = m_FirstArgAddr + pNativeVarInfo->loc.vlFixedVarArg.vlfvOffset;
8487#endif
8488
8489 hr = m_nativeFrame->GetLocalMemoryValue(pRemoteValue,
8490 type,
8491 ppValue);
8492
8493 break;
8494
8495
8496 default:
8497 _ASSERTE(!"Invalid locVarType");
8498 hr = E_FAIL;
8499 break;
8500 }
8501
8502 return hr;
8503}
8504
8505HRESULT CordbJITILFrame::EnumerateLocalVariables(ICorDebugValueEnum **ppValueEnum)
8506{
8507 PUBLIC_REENTRANT_API_ENTRY(this);
8508 FAIL_IF_NEUTERED(this);
8509 VALIDATE_POINTER_TO_OBJECT(ppValueEnum, ICorDebugValueEnum **);
8510 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
8511
8512 return EnumerateLocalVariablesEx(ILCODE_ORIGINAL_IL, ppValueEnum);
8513}
8514
8515HRESULT CordbJITILFrame::GetLocalVariable(DWORD dwIndex,
8516 ICorDebugValue **ppValue)
8517{
8518 PUBLIC_REENTRANT_API_ENTRY(this);
8519 VALIDATE_POINTER_TO_OBJECT(ppValue, ICorDebugValue **);
8520 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
8521
8522 return GetLocalVariableEx(ILCODE_ORIGINAL_IL, dwIndex, ppValue);
8523}
8524
8525
8526HRESULT CordbJITILFrame::EnumerateArguments(ICorDebugValueEnum **ppValueEnum)
8527{
8528 PUBLIC_API_ENTRY(this);
8529 FAIL_IF_NEUTERED(this);
8530 VALIDATE_POINTER_TO_OBJECT(ppValueEnum, ICorDebugValueEnum **);
8531 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
8532
8533 HRESULT hr = S_OK;
8534
8535 EX_TRY
8536 {
8537 RSInitHolder<CordbValueEnum> cdVE(new CordbValueEnum(m_nativeFrame, CordbValueEnum::ARGS));
8538
8539 // Initialize the new enum
8540 hr = cdVE->Init();
8541 IfFailThrow(hr);
8542
8543 cdVE.TransferOwnershipExternal(ppValueEnum);
8544
8545 }
8546 EX_CATCH_HRESULT(hr);
8547 return hr;
8548}
8549
8550//---------------------------------------------------------------------------------------
8551//
8552// This routine gets the value of a particular argument
8553//
8554// Arguments:
8555// dwIndex - Index of the argument.
8556// ppValue - OUT: Space for storing the value of the argument
8557//
8558// Return Value:
8559// HRESULT for the operation
8560//
8561HRESULT CordbJITILFrame::GetArgument(DWORD dwIndex, ICorDebugValue ** ppValue)
8562{
8563 PUBLIC_REENTRANT_API_ENTRY(this);
8564 FAIL_IF_NEUTERED(this);
8565 VALIDATE_POINTER_TO_OBJECT(ppValue, ICorDebugValue **);
8566
8567 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
8568
8569 const ICorDebugInfo::NativeVarInfo * pNativeInfo;
8570
8571 //
8572 // First, make sure that we've got the jitted variable location data
8573 // loaded from the left side.
8574 //
8575 HRESULT hr = S_OK;
8576 EX_TRY
8577 {
8578 m_nativeFrame->m_nativeCode->LoadNativeInfo(); //throws
8579
8580 hr = ILVariableToNative(dwIndex, &pNativeInfo);
8581 IfFailThrow(hr);
8582
8583 // Get the type of this argument from the function
8584 CordbType * pType;
8585
8586 hr = GetArgumentType(dwIndex, &pType);
8587 IfFailThrow(hr);
8588
8589 hr = GetNativeVariable(pType, pNativeInfo, ppValue);
8590 IfFailThrow(hr);
8591 }
8592 EX_CATCH_HRESULT(hr);
8593
8594 return hr;
8595}
8596
8597
8598HRESULT CordbJITILFrame::GetStackDepth(ULONG32 *pDepth)
8599{
8600 PUBLIC_API_ENTRY(this);
8601 FAIL_IF_NEUTERED(this);
8602 VALIDATE_POINTER_TO_OBJECT(pDepth, ULONG32 *);
8603 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
8604
8605
8606 /* !!! */
8607
8608 return E_NOTIMPL;
8609}
8610
8611HRESULT CordbJITILFrame::GetStackValue(DWORD dwIndex, ICorDebugValue **ppValue)
8612{
8613 PUBLIC_API_ENTRY(this);
8614 FAIL_IF_NEUTERED(this);
8615 VALIDATE_POINTER_TO_OBJECT(ppValue, ICorDebugValue **);
8616 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
8617
8618 /* !!! */
8619
8620 return E_NOTIMPL;
8621}
8622
8623//---------------------------------------------------------------------------------------
8624//
8625// Remaps the active frame to the latest EnC version of the function, preserving the
8626// execution state of the method such as the values of locals.
8627// Can only be called when the leaf frame is at a remap opportunity.
8628//
8629// Arguments:
8630// nOffset - the IL offset in the new version of the function to remap to
8631//
8632
8633HRESULT CordbJITILFrame::RemapFunction(ULONG32 nOffset)
8634{
8635 HRESULT hr = S_OK;
8636 PUBLIC_API_BEGIN(this)
8637 {
8638#if !defined(EnC_SUPPORTED)
8639 ThrowHR(E_NOTIMPL);
8640
8641#else // EnC_SUPPORTED
8642 // Can only be called on leaf frame.
8643 if (!m_nativeFrame->IsLeafFrame())
8644 {
8645 ThrowHR(E_INVALIDARG);
8646 }
8647
8648 // mark frames as not fresh, because this frame has been updated.
8649 m_nativeFrame->m_pThread->CleanupStack();
8650
8651 // Since we may have overwritten anything (objects, code, etc), we should mark
8652 // everything as needing to be re-cached.
8653 m_nativeFrame->m_pThread->GetProcess()->m_continueCounter++;
8654
8655 // Tell the left-side to do the remap
8656 hr = m_nativeFrame->m_pThread->SetRemapIP(nOffset);
8657
8658#endif // EnC_SUPPORTED
8659 }
8660 PUBLIC_API_END(hr);
8661
8662 return hr;
8663}
8664HRESULT CordbJITILFrame::GetReturnValueForILOffset(ULONG32 ILoffset, ICorDebugValue** ppReturnValue)
8665{
8666 HRESULT hr = S_OK;
8667 PUBLIC_API_ENTRY(this);
8668 FAIL_IF_NEUTERED(this);
8669
8670 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
8671 EX_TRY
8672 {
8673 hr = GetReturnValueForILOffsetImpl(ILoffset, ppReturnValue);
8674 }
8675 EX_CATCH_HRESULT(hr);
8676
8677 return hr;
8678}
8679
8680
8681HRESULT CordbJITILFrame::BuildInstantiationForCallsite(CordbModule * pModule, NewArrayHolder<CordbType*> &types, Instantiation &inst, Instantiation *currentInstantiation, mdToken targetClass, SigParser genericSig)
8682{
8683 // This function builds an Instantiation object (and backing "types" array) for a given
8684 // class and method signature.
8685 HRESULT hr = S_OK;
8686 RSExtSmartPtr<IMetaDataImport2> pImport2;
8687 IfFailRet(pModule->GetMetaDataImporter()->QueryInterface(IID_IMetaDataImport2, (void**)&pImport2));
8688
8689 // If the targetClass is a TypeSpec that means its first element is GENERICINST.
8690 // We only need to build types for the Instantiation if targetClass is a TypeSpec.
8691 ULONG classGenerics = 0;
8692 SigParser typeSig;
8693 if (TypeFromToken(targetClass) == mdtTypeSpec)
8694 {
8695 // Our goal with this is to full "classGenerics" with the number of
8696 // generics, and move "typeSig" to the start of the first generic type.
8697 PCCOR_SIGNATURE sig = 0;
8698 ULONG sigCount = 0;
8699
8700 IfFailRet(pImport2->GetTypeSpecFromToken(targetClass, &sig, &sigCount));
8701
8702 typeSig = SigParser(sig, sigCount);
8703 CorElementType elemType;
8704 IfFailRet(typeSig.GetElemType(&elemType));
8705
8706 if (elemType != ELEMENT_TYPE_GENERICINST)
8707 return META_E_BAD_SIGNATURE;
8708
8709 IfFailRet(typeSig.GetElemType(&elemType));
8710 if (elemType != ELEMENT_TYPE_VALUETYPE && elemType != ELEMENT_TYPE_CLASS)
8711 return META_E_BAD_SIGNATURE;
8712
8713 IfFailRet(typeSig.GetToken(NULL));
8714 IfFailRet(typeSig.GetData(&classGenerics));
8715 }
8716
8717 // Similarly for method generics. Simply fill "methodGenerics" with the number
8718 // of generics, and move "genericSig" to the start of the first generic param.
8719 ULONG methodGenerics = 0;
8720 if (!genericSig.IsNull())
8721 {
8722 ULONG callingConv = 0;
8723 IfFailRet(genericSig.GetCallingConvInfo(&callingConv));
8724 if (callingConv == IMAGE_CEE_CS_CALLCONV_GENERICINST)
8725 IfFailRet(genericSig.GetData(&methodGenerics));
8726 }
8727
8728
8729 // Now build "types" and "inst".
8730 CordbType *pType = 0;
8731 types = new CordbType*[methodGenerics+classGenerics];
8732 ULONG i = 0;
8733 for (;i < classGenerics; ++i)
8734 {
8735 CorElementType et;
8736 IfFailRet(typeSig.PeekElemType(&et));
8737 if ((et == ELEMENT_TYPE_VAR || et == ELEMENT_TYPE_MVAR) && currentInstantiation->m_cInst == 0)
8738 return E_FAIL;
8739
8740 CordbType::SigToType(pModule, &typeSig, currentInstantiation, &pType);
8741 types[i] = pType;
8742 typeSig.SkipExactlyOne();
8743 }
8744
8745 for (; i < methodGenerics+classGenerics; ++i)
8746 {
8747 CorElementType et;
8748 IfFailRet(genericSig.PeekElemType(&et));
8749 if ((et == ELEMENT_TYPE_VAR || et == ELEMENT_TYPE_MVAR) && currentInstantiation->m_cInst == 0)
8750 return E_FAIL;
8751
8752 CordbType::SigToType(pModule, &genericSig, currentInstantiation, &pType);
8753 types[i] = pType;
8754 genericSig.SkipExactlyOne();
8755 }
8756
8757 inst = Instantiation(methodGenerics+classGenerics, types, classGenerics);
8758 return S_OK;
8759}
8760
8761HRESULT CordbJITILFrame::GetReturnValueForILOffsetImpl(ULONG32 ILoffset, ICorDebugValue** ppReturnValue)
8762{
8763 if (ppReturnValue == NULL)
8764 return E_INVALIDARG;
8765
8766 if (!m_genericArgsLoaded)
8767 LoadGenericArgs();
8768
8769 // First verify that we're stopped at the correct native offset
8770 // by calling ICorDebugCode3::GetReturnValueLiveOffset and
8771 // compare the returned native offset to our current location.
8772 HRESULT hr = S_OK;
8773 CordbNativeCode *pCode = m_nativeFrame->m_nativeCode;
8774 pCode->LoadNativeInfo();
8775
8776 ULONG32 count = 0;
8777 IfFailRet(pCode->GetReturnValueLiveOffsetImpl(&m_genericArgs, ILoffset, 0, &count, NULL));
8778
8779 NewArrayHolder<ULONG32> offsets(new ULONG32[count]);
8780 IfFailRet(pCode->GetReturnValueLiveOffsetImpl(&m_genericArgs, ILoffset, count, &count, offsets));
8781
8782 bool found = false;
8783 ULONG32 currentOffset = m_nativeFrame->GetIPOffset();
8784 for (ULONG32 i = 0; i < count; ++i)
8785 {
8786 if (currentOffset == offsets[i])
8787 {
8788 found = true;
8789 break;
8790 }
8791 }
8792
8793 if (!found)
8794 return E_UNEXPECTED;
8795
8796 // Get the signatures and mdToken for the callee.
8797 SigParser methodSig, genericSig;
8798 mdToken mdFunction = 0, targetClass = 0;
8799 IfFailRet(pCode->GetCallSignature(ILoffset, &targetClass, &mdFunction, methodSig, genericSig));
8800 IfFailRet(CordbNativeCode::SkipToReturn(methodSig));
8801
8802
8803
8804
8805 // Create the Instantiation, type and then return value
8806 NewArrayHolder<CordbType*> types;
8807 Instantiation inst;
8808 CordbType *pType = 0;
8809 IfFailRet(BuildInstantiationForCallsite(GetModule(), types, inst, &m_genericArgs, targetClass, genericSig));
8810 IfFailRet(CordbType::SigToType(GetModule(), &methodSig, &inst, &pType));
8811 return GetReturnValueForType(pType, ppReturnValue);
8812}
8813
8814
8815HRESULT CordbJITILFrame::GetReturnValueForType(CordbType *pType, ICorDebugValue **ppReturnValue)
8816{
8817
8818
8819#if defined(DBG_TARGET_X86)
8820 const CorDebugRegister floatRegister = REGISTER_X86_FPSTACK_0;
8821#elif defined(DBG_TARGET_AMD64)
8822 const CorDebugRegister floatRegister = REGISTER_AMD64_XMM0;
8823#elif defined(DBG_TARGET_ARM64)
8824 const CorDebugRegister floatRegister = REGISTER_ARM64_V0;
8825#elif defined(DBG_TARGET_ARM)
8826 const CorDebugRegister floatRegister = REGISTER_ARM_D0;
8827#endif
8828
8829#if defined(DBG_TARGET_X86)
8830 const CorDebugRegister ptrRegister = REGISTER_X86_EAX;
8831 const CorDebugRegister ptrHighWordRegister = REGISTER_X86_EDX;
8832#elif defined(DBG_TARGET_AMD64)
8833 const CorDebugRegister ptrRegister = REGISTER_AMD64_RAX;
8834#elif defined(DBG_TARGET_ARM64)
8835 const CorDebugRegister ptrRegister = REGISTER_ARM64_X0;
8836#elif defined(DBG_TARGET_ARM)
8837 const CorDebugRegister ptrRegister = REGISTER_ARM_R0;
8838 const CorDebugRegister ptrHighWordRegister = REGISTER_ARM_R1;
8839
8840#endif
8841
8842 CorElementType corReturnType = pType->GetElementType();
8843 switch (corReturnType)
8844 {
8845 default:
8846 return m_nativeFrame->GetLocalRegisterValue(ptrRegister, pType, ppReturnValue);
8847
8848 case ELEMENT_TYPE_R4:
8849 case ELEMENT_TYPE_R8:
8850 return m_nativeFrame->GetLocalFloatingPointValue(floatRegister, pType, ppReturnValue);
8851
8852#if defined(DBG_TARGET_X86) || defined(DBG_TARGET_ARM)
8853 case ELEMENT_TYPE_I8:
8854 case ELEMENT_TYPE_U8:
8855 return m_nativeFrame->GetLocalDoubleRegisterValue(ptrHighWordRegister, ptrRegister, pType, ppReturnValue);
8856#endif
8857 }
8858}
8859
8860HRESULT CordbJITILFrame::EnumerateLocalVariablesEx(ILCodeKind flags, ICorDebugValueEnum **ppValueEnum)
8861{
8862 PUBLIC_REENTRANT_API_ENTRY(this);
8863 FAIL_IF_NEUTERED(this);
8864 VALIDATE_POINTER_TO_OBJECT(ppValueEnum, ICorDebugValueEnum **);
8865 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
8866
8867 HRESULT hr = S_OK;
8868 if (flags != ILCODE_ORIGINAL_IL && flags != ILCODE_REJIT_IL)
8869 return E_INVALIDARG;
8870
8871 EX_TRY
8872 {
8873 RSInitHolder<CordbValueEnum> cdVE(new CordbValueEnum(m_nativeFrame,
8874 flags == ILCODE_ORIGINAL_IL ? CordbValueEnum::LOCAL_VARS_ORIGINAL_IL : CordbValueEnum::LOCAL_VARS_REJIT_IL));
8875
8876 // Initialize the new enum
8877 hr = cdVE->Init();
8878 IfFailThrow(hr);
8879
8880 cdVE.TransferOwnershipExternal(ppValueEnum);
8881 }
8882 EX_CATCH_HRESULT(hr);
8883
8884 return hr;
8885}
8886HRESULT CordbJITILFrame::GetLocalVariableEx(ILCodeKind flags, DWORD dwIndex, ICorDebugValue **ppValue)
8887{
8888 PUBLIC_REENTRANT_API_ENTRY(this);
8889 VALIDATE_POINTER_TO_OBJECT(ppValue, ICorDebugValue **);
8890 FAIL_IF_NEUTERED(this);
8891 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
8892
8893 if (flags != ILCODE_ORIGINAL_IL && flags != ILCODE_REJIT_IL)
8894 return E_INVALIDARG;
8895 if (flags == ILCODE_REJIT_IL && m_pReJitCode == NULL)
8896 return E_INVALIDARG;
8897
8898 const ICorDebugInfo::NativeVarInfo *pNativeInfo;
8899
8900 //
8901 // First, make sure that we've got the jitted variable location data
8902 // loaded from the left side.
8903 //
8904
8905 HRESULT hr = S_OK;
8906 EX_TRY
8907 {
8908 m_nativeFrame->m_nativeCode->LoadNativeInfo(); //throws
8909
8910 ULONG cArgs;
8911 if (m_fVarArgFnx && (!m_sigParserCached.IsNull()))
8912 {
8913 cArgs = m_allArgsCount;
8914 }
8915 else
8916 {
8917 cArgs = m_nativeFrame->m_nativeCode->GetFixedArgCount();
8918 }
8919
8920 hr = ILVariableToNative(dwIndex + cArgs, &pNativeInfo);
8921 IfFailThrow(hr);
8922
8923 LoadGenericArgs();
8924
8925 // Get the type of this argument from the function
8926 CordbType *type;
8927 CordbILCode* pActiveCode = m_pReJitCode != NULL ? m_pReJitCode : m_ilCode;
8928 hr = pActiveCode->GetLocalVariableType(dwIndex, &(this->m_genericArgs), &type);
8929 IfFailThrow(hr);
8930
8931 // if the caller wants the original IL local, it should implicitly map to the same index
8932 // variable in the profiler instrumented code. We can't determine whether the instrumented code
8933 // really adhered to this, but we can check two things:
8934 // a) the requested index was valid in the original signature
8935 // (GetLocalVariableType will return E_INVALIDARG if not)
8936 // b) the type of local in the original signature matches the type of local in the instrumented signature
8937 // (the code below will return CORDBG_E_IL_VAR_NOT_AVAILABLE)
8938 if (flags == ILCODE_ORIGINAL_IL && m_pReJitCode != NULL)
8939 {
8940 CordbType* pOriginalType;
8941 hr = m_ilCode->GetLocalVariableType(dwIndex, &(this->m_genericArgs), &pOriginalType);
8942 IfFailThrow(hr);
8943 if (pOriginalType != type)
8944 {
8945 IfFailThrow(CORDBG_E_IL_VAR_NOT_AVAILABLE); // bad profiler, it shouldn't have changed types
8946 }
8947 }
8948
8949
8950 hr = GetNativeVariable(type, pNativeInfo, ppValue);
8951 IfFailThrow(hr);
8952 }
8953 EX_CATCH_HRESULT(hr);
8954
8955 return hr;
8956}
8957
8958HRESULT CordbJITILFrame::GetCodeEx(ILCodeKind flags, ICorDebugCode **ppCode)
8959{
8960 HRESULT hr = S_OK;
8961 PUBLIC_API_ENTRY(this);
8962 FAIL_IF_NEUTERED(this);
8963 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
8964
8965 if (flags != ILCODE_ORIGINAL_IL && flags != ILCODE_REJIT_IL)
8966 return E_INVALIDARG;
8967
8968 if (flags == ILCODE_ORIGINAL_IL)
8969 {
8970 return GetCode(ppCode);
8971 }
8972 else
8973 {
8974 *ppCode = m_pReJitCode;
8975 if (m_pReJitCode != NULL)
8976 {
8977 m_pReJitCode->ExternalAddRef();
8978 }
8979 }
8980 return S_OK;
8981}
8982
8983CordbILCode* CordbJITILFrame::GetOriginalILCode()
8984{
8985 return m_ilCode;
8986}
8987
8988CordbReJitILCode* CordbJITILFrame::GetReJitILCode()
8989{
8990 return m_pReJitCode;
8991}
8992
8993/* ------------------------------------------------------------------------- *
8994 * Eval class
8995 * ------------------------------------------------------------------------- */
8996
8997CordbEval::CordbEval(CordbThread *pThread)
8998 : CordbBase(pThread->GetProcess(), 0, enumCordbEval),
8999 m_thread(pThread), // implicit InternalAddRef
9000 m_function(NULL),
9001 m_complete(false),
9002 m_successful(false),
9003 m_aborted(false),
9004 m_resultAddr(NULL),
9005 m_evalDuringException(false)
9006{
9007 m_vmObjectHandle = VMPTR_OBJECTHANDLE::NullPtr();
9008 m_debuggerEvalKey = LSPTR_DEBUGGEREVAL::NullPtr();
9009
9010 m_resultType.elementType = ELEMENT_TYPE_VOID;
9011 m_resultAppDomainToken = VMPTR_AppDomain::NullPtr();
9012
9013 CordbAppDomain * pDomain = m_thread->GetAppDomain();
9014 (void)pDomain; //prevent "unused variable" error from GCC
9015#ifdef _DEBUG
9016 // Remember what AD we started in so that we can check that we finish there too.
9017 m_DbgAppDomainStarted = pDomain;
9018#endif
9019
9020 // Place ourselves on the processes neuter-list.
9021 HRESULT hr = S_OK;
9022 EX_TRY
9023 {
9024 GetProcess()->AddToLeftSideResourceCleanupList(this);
9025 }
9026 EX_CATCH_HRESULT(hr);
9027 SetUnrecoverableIfFailed(GetProcess(), hr);
9028}
9029
9030CordbEval::~CordbEval()
9031{
9032 _ASSERTE(IsNeutered());
9033}
9034
9035// Free the left-side resources for the eval.
9036void CordbEval::NeuterLeftSideResources()
9037{
9038 SendCleanup();
9039
9040 RSLockHolder lockHolder(GetProcess()->GetProcessLock());
9041 Neuter();
9042}
9043
9044// Neuter the CordbEval
9045//
9046// Assumptions:
9047// By the time we neuter the eval, it's associated left-side resources
9048// are already cleaned up (either explicitly from calling code:CordbEval::SendCleanup
9049// or implicitly from the left-side exiting).
9050//
9051// Notes:
9052// We place ourselves on a neuter list. This gets called when the neuterlist sweeps.
9053void CordbEval::Neuter()
9054{
9055 // By now, we should have freed our target-resources (code:CordbEval::NeuterLeftSideResources
9056 // or code:CordbEval::SendCleanup), unless the target is dead (terminated or about to exit).
9057 BOOL fTargetIsDead = !GetProcess()->IsSafeToSendEvents() || GetProcess()->m_exiting;
9058 (void)fTargetIsDead; //prevent "unused variable" error from GCC
9059 _ASSERTE(fTargetIsDead || (m_debuggerEvalKey == NULL));
9060
9061 m_thread.Clear();
9062
9063 CordbBase::Neuter();
9064}
9065
9066HRESULT CordbEval::SendCleanup()
9067{
9068 FAIL_IF_NEUTERED(this);
9069 INTERNAL_SYNC_API_ENTRY(GetProcess()); //
9070
9071 HRESULT hr = S_OK;
9072
9073 // Send a message to the left side to release the eval object over
9074 // there if one exists.
9075 if ((m_debuggerEvalKey != NULL) &&
9076 GetProcess()->IsSafeToSendEvents())
9077 {
9078 // Call Abort() before doing new CallFunction()
9079 if (!m_complete)
9080 return CORDBG_E_FUNC_EVAL_NOT_COMPLETE;
9081
9082 // Release the left side handle to the object
9083 DebuggerIPCEvent event;
9084
9085 GetProcess()->InitIPCEvent(
9086 &event,
9087 DB_IPCE_FUNC_EVAL_CLEANUP,
9088 true,
9089 m_thread->GetAppDomain()->GetADToken());
9090
9091 event.FuncEvalCleanup.debuggerEvalKey = m_debuggerEvalKey;
9092
9093 hr = GetProcess()->SendIPCEvent(&event, sizeof(DebuggerIPCEvent));
9094 IfFailRet(hr);
9095
9096#if _DEBUG
9097 if (SUCCEEDED(hr))
9098 _ASSERTE(event.type == DB_IPCE_FUNC_EVAL_CLEANUP_RESULT);
9099#endif
9100
9101 // Null out the key so we don't try to do this again.
9102 m_debuggerEvalKey = LSPTR_DEBUGGEREVAL::NullPtr();
9103
9104 hr = event.hr;
9105 }
9106
9107 // Release the cached HandleValue for the result. This may cleanup resources,
9108 // like our object handle to the func-eval result.
9109 m_pHandleValue.Clear();
9110
9111
9112 return hr;
9113}
9114
9115HRESULT CordbEval::QueryInterface(REFIID id, void **pInterface)
9116{
9117 if (id == IID_ICorDebugEval)
9118 {
9119 *pInterface = static_cast<ICorDebugEval*>(this);
9120 }
9121 else if (id == IID_ICorDebugEval2)
9122 {
9123 *pInterface = static_cast<ICorDebugEval2*>(this);
9124 }
9125 else if (id == IID_IUnknown)
9126 {
9127 *pInterface = static_cast<IUnknown*>(static_cast<ICorDebugEval*>(this));
9128 }
9129 else
9130 {
9131 *pInterface = NULL;
9132 return E_NOINTERFACE;
9133 }
9134
9135 ExternalAddRef();
9136 return S_OK;
9137}
9138
9139//
9140// Gather data about an argument to either CallFunction or NewObject
9141// and place it into a DebuggerIPCE_FuncEvalArgData struct for passing
9142// to the Left Side.
9143//
9144HRESULT CordbEval::GatherArgInfo(ICorDebugValue *pValue,
9145 DebuggerIPCE_FuncEvalArgData *argData)
9146{
9147 FAIL_IF_NEUTERED(this);
9148 INTERNAL_SYNC_API_ENTRY(GetProcess()); //
9149
9150 HRESULT hr;
9151 CORDB_ADDRESS addr;
9152 CorElementType ty;
9153 bool needRelease = false;
9154
9155 pValue->GetType(&ty);
9156
9157 // Note: if the value passed in is in fact a byref, then we need to dereference it to get to the real thing. Passing
9158 // a byref as a byref to a func eval is never right.
9159 if ((ty == ELEMENT_TYPE_BYREF) || (ty == ELEMENT_TYPE_TYPEDBYREF))
9160 {
9161 ICorDebugReferenceValue *prv = NULL;
9162
9163 // The value had better implement ICorDebugReference value.
9164 IfFailRet(pValue->QueryInterface(IID_ICorDebugReferenceValue, (void**)&prv));
9165
9166 // This really should always work for a byref, unless we're out of memory.
9167 hr = prv->Dereference(&pValue);
9168 prv->Release();
9169
9170 IfFailRet(hr);
9171
9172 // Make sure to get the type we were referencing for use below.
9173 pValue->GetType(&ty);
9174 needRelease = true;
9175 }
9176
9177 // We should never have a byref by this point.
9178 _ASSERTE((ty != ELEMENT_TYPE_BYREF) && (ty != ELEMENT_TYPE_TYPEDBYREF));
9179
9180 pValue->GetAddress(&addr);
9181
9182 argData->argAddr = CORDB_ADDRESS_TO_PTR(addr);
9183 argData->argElementType = ty;
9184
9185 argData->argIsHandleValue = false;
9186 argData->argIsLiteral = false;
9187 argData->fullArgType = NULL;
9188 argData->fullArgTypeNodeCount = 0;
9189
9190 // We have to have knowledge of our value implementation here,
9191 // which it would nice if we didn't have to know.
9192 CordbValue *cv = NULL;
9193
9194 switch(ty)
9195 {
9196
9197 case ELEMENT_TYPE_CLASS:
9198 case ELEMENT_TYPE_OBJECT:
9199 case ELEMENT_TYPE_STRING:
9200 case ELEMENT_TYPE_PTR:
9201 case ELEMENT_TYPE_ARRAY:
9202 case ELEMENT_TYPE_SZARRAY:
9203 {
9204 ICorDebugHandleValue *pHandle = NULL;
9205 pValue->QueryInterface(IID_ICorDebugHandleValue, (void **) &pHandle);
9206 if (pHandle == NULL)
9207 {
9208 // A reference value
9209 cv = static_cast<CordbValue*> (static_cast<CordbReferenceValue*> (pValue));
9210 argData->argIsHandleValue = !(((CordbReferenceValue *)pValue)->m_valueHome.ObjHandleIsNull());
9211
9212 // Is this a literal value? If, we'll copy the data to the
9213 // buffer area so the left side can get it.
9214 CordbReferenceValue *rv;
9215 rv = static_cast<CordbReferenceValue*>(pValue);
9216 argData->argIsLiteral = rv->CopyLiteralData(argData->argLiteralData);
9217 if (rv->GetValueHome())
9218 {
9219 rv->GetValueHome()->CopyToIPCEType(&(argData->argHome));
9220 }
9221 }
9222 else
9223 {
9224 argData->argIsHandleValue = true;
9225 argData->argIsLiteral = false;
9226 pHandle->Release();
9227 argData->argHome.kind = RAK_NONE;
9228 }
9229 }
9230 break;
9231
9232 case ELEMENT_TYPE_VALUETYPE: // OK: this E_T_VALUETYPE comes ICorDebugValue::GetType
9233
9234 // A value class object
9235 cv = static_cast<CordbValue*> (static_cast<CordbVCObjectValue*>(static_cast<ICorDebugObjectValue*> (pValue)));
9236
9237 // The EE does not guarantee to have exact type information
9238 // available for all struct types, so we indicate the type by using a
9239 // DebuggerIPCE_TypeArgData serialization of a type.
9240 //
9241 // At the moment the LHS only cares about this data
9242 // when boxing the "this" pointer.
9243 {
9244 CordbVCObjectValue * pVCObjVal =
9245 static_cast<CordbVCObjectValue *>(static_cast<ICorDebugObjectValue*> (pValue));
9246
9247 unsigned int fullArgTypeNodeCount = 0;
9248 cv->m_type->CountTypeDataNodes(&fullArgTypeNodeCount);
9249
9250 _ASSERTE(fullArgTypeNodeCount > 0);
9251 unsigned int bufferSize = sizeof(DebuggerIPCE_TypeArgData) * fullArgTypeNodeCount;
9252 DebuggerIPCE_TypeArgData *bufferFrom = (DebuggerIPCE_TypeArgData *) _alloca(bufferSize);
9253
9254 DebuggerIPCE_TypeArgData *curr = bufferFrom;
9255 CordbType::GatherTypeData(cv->m_type, &curr);
9256
9257 void *buffer = NULL;
9258 IfFailRet(m_thread->GetProcess()->GetAndWriteRemoteBuffer(m_thread->GetAppDomain(), bufferSize, bufferFrom, &buffer));
9259
9260 argData->fullArgType = buffer;
9261 argData->fullArgTypeNodeCount = fullArgTypeNodeCount;
9262 // Is it enregistered?
9263 if ((addr == NULL) && (pVCObjVal->GetValueHome() != NULL))
9264 {
9265 pVCObjVal->GetValueHome()->CopyToIPCEType(&(argData->argHome));
9266 }
9267
9268 }
9269 break;
9270
9271 default:
9272
9273 // A generic value
9274 cv = static_cast<CordbValue*> (static_cast<CordbGenericValue*> (pValue));
9275
9276 // Is this a literal value? If, we'll copy the data to the
9277 // buffer area so the left side can get it.
9278 CordbGenericValue *gv = (CordbGenericValue*)pValue;
9279 argData->argIsLiteral = gv->CopyLiteralData(argData->argLiteralData);
9280 // Is it enregistered?
9281 if ((addr == NULL) && (gv->GetValueHome() != NULL))
9282 {
9283 gv->GetValueHome()->CopyToIPCEType(&(argData->argHome));
9284 }
9285 break;
9286 }
9287
9288
9289 // Release pValue if we got it via a dereference from above.
9290 if (needRelease)
9291 pValue->Release();
9292
9293 return S_OK;
9294}
9295
9296
9297HRESULT CordbEval::SendFuncEval(unsigned int genericArgsCount,
9298 ICorDebugType *genericArgs[],
9299 void *argData1, unsigned int argData1Size,
9300 void *argData2, unsigned int argData2Size,
9301 DebuggerIPCEvent * event)
9302{
9303 FAIL_IF_NEUTERED(this);
9304 INTERNAL_SYNC_API_ENTRY(GetProcess()); //
9305 unsigned int genericArgsNodeCount = 0;
9306
9307 DebuggerIPCE_TypeArgData *tyargData = NULL;
9308 CordbType::CountTypeDataNodesForInstantiation(genericArgsCount,genericArgs,&genericArgsNodeCount);
9309
9310 unsigned int tyargDataSize = sizeof(DebuggerIPCE_TypeArgData) * genericArgsNodeCount;
9311
9312 if (genericArgsNodeCount > 0)
9313 {
9314 tyargData = new (nothrow) DebuggerIPCE_TypeArgData[genericArgsNodeCount];
9315 if (tyargData == NULL)
9316 {
9317 return E_OUTOFMEMORY;
9318 }
9319
9320 DebuggerIPCE_TypeArgData *curr_tyargData = tyargData;
9321 CordbType::GatherTypeDataForInstantiation(genericArgsCount, genericArgs, &curr_tyargData);
9322
9323 }
9324 event->FuncEval.genericArgsNodeCount = genericArgsNodeCount;
9325
9326
9327 // Are we doing an eval during an exception? If so, we need to remember
9328 // that over here and also tell the Left Side.
9329 event->FuncEval.evalDuringException = m_thread->HasException();
9330 m_evalDuringException = !!event->FuncEval.evalDuringException;
9331 m_vmThreadOldExceptionHandle = m_thread->GetThreadExceptionRawObjectHandle();
9332
9333 // Corresponding Release() on DB_IPCE_FUNC_EVAL_COMPLETE.
9334 // If a func eval is aborted, the LHS may not complete the abort
9335 // immediately and hence we cant do a SendCleanup(). Hence, we maintain
9336 // an extra ref-count to determine when this can be done.
9337 AddRef();
9338
9339 HRESULT hr = m_thread->GetProcess()->SendIPCEvent(event, sizeof(DebuggerIPCEvent));
9340
9341 // If the send failed, return that failure.
9342 if (FAILED(hr))
9343 goto LExit;
9344
9345 _ASSERTE(event->type == DB_IPCE_FUNC_EVAL_SETUP_RESULT);
9346
9347 hr = event->hr;
9348
9349 // Memory has been allocated to hold info about each argument on
9350 // the left side now, so copy the argument data over to the left
9351 // side. No need to send another event, since the left side won't
9352 // take any more action on this evaluation until the process is
9353 // continued anyway.
9354 //
9355 // The type arguments come first, followed by up to two blobs of data
9356 // for other arguments.
9357 if (SUCCEEDED(hr))
9358 {
9359 EX_TRY
9360 {
9361 CORDB_ADDRESS argdata = event->FuncEvalSetupComplete.argDataArea;
9362
9363 if ((tyargData != NULL) && (tyargDataSize != 0))
9364 {
9365
9366 TargetBuffer tb(argdata, tyargDataSize);
9367 m_thread->GetProcess()->SafeWriteBuffer(tb, (const BYTE*) tyargData); // throws
9368
9369 argdata += tyargDataSize;
9370 }
9371
9372 if ((argData1 != NULL) && (argData1Size != 0))
9373 {
9374 TargetBuffer tb(argdata, argData1Size);
9375 m_thread->GetProcess()->SafeWriteBuffer(tb, (const BYTE*) argData1); // throws
9376
9377 argdata += argData1Size;
9378 }
9379
9380 if ((argData2 != NULL) && (argData2Size != 0))
9381 {
9382 TargetBuffer tb(argdata, argData2Size);
9383 m_thread->GetProcess()->SafeWriteBuffer(tb, (const BYTE*) argData2); // throws
9384
9385 argdata += argData2Size;
9386 }
9387 }
9388 EX_CATCH_HRESULT(hr);
9389 }
9390
9391LExit:
9392 if (tyargData)
9393 {
9394 delete [] tyargData;
9395 }
9396
9397 // Save the key to the eval on the left side for future reference.
9398 if (SUCCEEDED(hr))
9399 {
9400 m_debuggerEvalKey = event->FuncEvalSetupComplete.debuggerEvalKey;
9401 m_thread->GetProcess()->IncrementOutstandingEvalCount();
9402 }
9403 else
9404 {
9405 // We dont expect to receive a DB_IPCE_FUNC_EVAL_COMPLETE, so just release here
9406 Release();
9407 }
9408
9409 return hr;
9410}
9411
9412
9413// Get the AppDomain that an object lives in.
9414// This does not adjust any reference counts.
9415// Returns NULL if we can't determine the appdomain, or if the value is known to be agile.
9416CordbAppDomain * GetAppDomainFromValue(ICorDebugValue * pValue)
9417{
9418 // Unfortunately, there's no direct way to cast from an ICDValue to a CordbValue.
9419 // So we need to QI for the culprit interfaces and check specifically.
9420
9421 {
9422 RSExtSmartPtr<ICorDebugHandleValue> handleP;
9423 pValue->QueryInterface(IID_ICorDebugHandleValue, (void**)&handleP);
9424 if (handleP != NULL)
9425 {
9426 CordbHandleValue * chp = static_cast<CordbHandleValue *> (handleP.GetValue());
9427 return chp->GetAppDomain();
9428 }
9429 }
9430
9431 {
9432 RSExtSmartPtr<ICorDebugReferenceValue> refP;
9433 pValue->QueryInterface(IID_ICorDebugReferenceValue, (void**)&refP);
9434 if (refP != NULL)
9435 {
9436 CordbReferenceValue * crp = static_cast<CordbReferenceValue *> (refP.GetValue());
9437 return crp->GetAppDomain();
9438 }
9439 }
9440
9441 {
9442 RSExtSmartPtr<ICorDebugObjectValue> objP;
9443 pValue->QueryInterface(IID_ICorDebugObjectValue, (void**)&objP);
9444 if (objP != NULL)
9445 {
9446 CordbVCObjectValue * crp = static_cast<CordbVCObjectValue*> (objP.GetValue());
9447 return crp->GetAppDomain();
9448 }
9449 }
9450
9451 // Assume nothing else has AD affinity.
9452 return NULL;
9453}
9454
9455HRESULT CordbEval::CallFunction(ICorDebugFunction *pFunction,
9456 ULONG32 nArgs,
9457 ICorDebugValue *pArgs[])
9458{
9459 PUBLIC_API_ENTRY(this);
9460 FAIL_IF_NEUTERED(this);
9461 if (GetProcess()->GetShim() == NULL)
9462 {
9463 return E_NOTIMPL;
9464 }
9465 return CallParameterizedFunction(pFunction,0,NULL,nArgs,pArgs);
9466}
9467
9468//-----------------------------------------------------------------------------
9469// See if we can convert general Func-eval failure HRs (which are usually based on EE-invariants that
9470// may be meaningless to the user) into a more specific user-friendly hr.
9471// Doing the conversions here in the RS (instead of in the LS) makes it more clear that these
9472// HRs definitely map to concepts described by the ICorDebugAPI instead of EE-invariants.
9473// It also lets us clearly prioritize the HRs in case of ambiguity.
9474//-----------------------------------------------------------------------------
9475HRESULT CordbEval::FilterHR(HRESULT hr)
9476{
9477 // Currently, we only make CORDBG_E_ILLEGAL_AT_GC_UNSAFE_POINT more specific.
9478 // If it's not that HR, then shortcut our work.
9479 if (hr != CORDBG_E_ILLEGAL_AT_GC_UNSAFE_POINT)
9480 {
9481 return hr;
9482 }
9483
9484 // In the case of conflicting HRs (if the func-eval fails for multiple reasons),
9485 // we'll try to give priority to the more general HR.
9486 // This communicates the quickest action for the user to be able to get to a
9487 // func-eval friendly spot. It also means less churn in the hrs we return
9488 // because specific hrs are more likely to change than general ones.
9489
9490 // If we got CORDBG_E_ILLEGAL_AT_GC_UNSAFE_POINT, check the common reasons.
9491 // We'll use the Right-Side's intimate knowledge of the Left-Side to guess _why_
9492 // it's a GC-unsafe spot, and then we'll communicate that back w/ a more meaningful HR.
9493 // If GC safe-spots change, then these errors should be updated.
9494
9495
9496 //
9497 // Most likely is if we're in native code. Check that first.
9498 //
9499 // In V2, we do this check by checking if the leaf chain is native. Since we have no chain in Arrowhead,
9500 // we can't do this check. Instead, we check whether the active frame is NULL or not. If it's NULL,
9501 // then we are stopped in native code.
9502 //
9503 HRESULT hrTemp = S_OK;
9504 if (GetProcess()->GetShim() != NULL)
9505 {
9506 // the V2 case
9507 RSExtSmartPtr<ICorDebugChain> pChain;
9508 hrTemp = m_thread->GetActiveChain(&pChain);
9509 if (FAILED(hrTemp))
9510 {
9511 // just return the original HR if this call fails
9512 return hr;
9513 }
9514
9515 // pChain should never be NULL here, since we should have at least one thread start chain even if
9516 // there is no managed code on the stack, but let's just be extra careful here.
9517 if (pChain == NULL)
9518 {
9519 return hr;
9520 }
9521
9522 BOOL fManagedChain;
9523 hrTemp = pChain->IsManaged(&fManagedChain);
9524 if (FAILED(hrTemp))
9525 {
9526 // just return the original HR if this call fails
9527 return hr;
9528 }
9529
9530 if (fManagedChain == FALSE)
9531 {
9532 return CORDBG_E_ILLEGAL_IN_NATIVE_CODE;
9533 }
9534 }
9535
9536 RSExtSmartPtr<ICorDebugFrame> pIFrame;
9537 hrTemp = m_thread->GetActiveFrame(&pIFrame);
9538 if (FAILED(hrTemp))
9539 {
9540 // just return the original HR if this call fails
9541 return hr;
9542 }
9543
9544 CordbFrame * pFrame = NULL;
9545 pFrame = CordbFrame::GetCordbFrameFromInterface(pIFrame);
9546
9547 if (GetProcess()->GetShim() == NULL)
9548 {
9549 // the Arrowhead case
9550 if (pFrame == NULL)
9551 {
9552 return CORDBG_E_ILLEGAL_IN_NATIVE_CODE;
9553 }
9554 }
9555
9556 // Next, check if we're in optimized code.
9557 // Optimized code doesn't directly mean that func-evals are illegal; but it greatly
9558 // increases the odds of being at a GC-unsafe point.
9559 // We give this failure higher precedence than the "Is in prolog" failure.
9560
9561 if (pFrame != NULL)
9562 {
9563 CordbNativeFrame * pNativeFrame = pFrame->GetAsNativeFrame();
9564 if (pNativeFrame != NULL)
9565 {
9566 CordbNativeCode * pCode = pNativeFrame->GetNativeCode();
9567 if (pCode != NULL)
9568 {
9569 DWORD flags;
9570 hrTemp = pCode->GetModule()->GetJITCompilerFlags(&flags);
9571
9572 if (SUCCEEDED(hrTemp))
9573 {
9574 if ((flags & CORDEBUG_JIT_DISABLE_OPTIMIZATION) != CORDEBUG_JIT_DISABLE_OPTIMIZATION)
9575 {
9576 return CORDBG_E_ILLEGAL_IN_OPTIMIZED_CODE;
9577 }
9578
9579 } // GetCompilerFlags
9580 } // Code
9581
9582 CordbJITILFrame * pILFrame = pNativeFrame->m_JITILFrame;
9583 if (pILFrame != NULL)
9584 {
9585 if (pILFrame->m_mapping == MAPPING_PROLOG)
9586 {
9587 return CORDBG_E_ILLEGAL_IN_PROLOG;
9588 }
9589 }
9590 } // Native Frame
9591 }
9592
9593 // No filtering.
9594 return hr;
9595
9596}
9597
9598//---------------------------------------------------------------------------------------
9599//
9600// This routine calls a function with the given set of type arguments and actual arguments.
9601// This is the jumping off point for func-eval.
9602//
9603// Arguments:
9604// pFunction - The function to call.
9605// nTypeArgs - The number of type-arguments for the method in rgpTypeArgs
9606// rgpTypeArgs - An array of pointers to types.
9607// nArgs - The number of arguments for the method in rgpArgs
9608// rgpArgs - An array of pointers to values for the arguments to the method.
9609//
9610// Return Value:
9611// HRESULT for the operation
9612//
9613HRESULT CordbEval::CallParameterizedFunction(ICorDebugFunction *pFunction,
9614 ULONG32 nTypeArgs,
9615 ICorDebugType * rgpTypeArgs[],
9616 ULONG32 nArgs,
9617 ICorDebugValue * rgpArgs[])
9618{
9619 PUBLIC_REENTRANT_API_ENTRY(this);
9620 FAIL_IF_NEUTERED(this);
9621
9622 VALIDATE_POINTER_TO_OBJECT(pFunction, ICorDebugFunction *);
9623
9624 if (nArgs > 0)
9625 {
9626 VALIDATE_POINTER_TO_OBJECT_ARRAY(rgpArgs, ICorDebugValue *, nArgs, true, true);
9627 }
9628
9629 HRESULT hr = E_FAIL;
9630
9631 {
9632 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
9633
9634 // The LS will assume that all of the ICorDebugValues and ICorDebugTypes are in
9635 // the same appdomain as the function. Verify this.
9636 CordbAppDomain * pMethodAppDomain = (static_cast<CordbFunction *> (pFunction))->GetAppDomain();
9637
9638 if (!DoAppDomainsMatch(pMethodAppDomain, nTypeArgs, rgpTypeArgs, nArgs, rgpArgs))
9639 {
9640 return ErrWrapper(CORDBG_E_APPDOMAIN_MISMATCH);
9641 }
9642
9643 // Callers are free to reuse an ICorDebugEval object for multiple
9644 // evals. Since we create a Left Side eval representation each
9645 // time, we need to be sure to clean it up now that we know we're
9646 // done with it.
9647 hr = SendCleanup();
9648
9649 if (FAILED(hr))
9650 {
9651 return hr;
9652 }
9653
9654 RSLockHolder lockHolder(GetProcess()->GetProcessLock());
9655
9656 // Must be locked to get a cookie
9657 RsPtrHolder<CordbEval> hFuncEval(this);
9658
9659 if (hFuncEval.Ptr().IsNull())
9660 {
9661 return E_OUTOFMEMORY;
9662 }
9663 lockHolder.Release(); // release to send an IPC event.
9664
9665 // Remember the function that we're evaluating.
9666 m_function = static_cast<CordbFunction *>(pFunction);
9667 m_evalType = DB_IPCE_FET_NORMAL;
9668
9669
9670 // Arrange the arguments into a form that the left side can deal
9671 // with. We do this before starting the func eval setup to ensure
9672 // that we can complete this step before mutating the left
9673 // side.
9674 DebuggerIPCE_FuncEvalArgData * pArgData = NULL;
9675
9676 if (nArgs > 0)
9677 {
9678 // We need to make the same type of array that the left side
9679 // holds.
9680 pArgData = new (nothrow) DebuggerIPCE_FuncEvalArgData[nArgs];
9681
9682 if (pArgData == NULL)
9683 {
9684 return E_OUTOFMEMORY;
9685 }
9686
9687 // For each argument, convert its home into something the left
9688 // side can understand.
9689 for (unsigned int i = 0; i < nArgs; i++)
9690 {
9691 hr = GatherArgInfo(rgpArgs[i], &(pArgData[i]));
9692
9693 if (FAILED(hr))
9694 {
9695 delete [] pArgData;
9696 return hr;
9697 }
9698 }
9699 }
9700
9701 // Send over to the left side and get it to setup this eval.
9702 DebuggerIPCEvent event;
9703 m_thread->GetProcess()->InitIPCEvent(&event, DB_IPCE_FUNC_EVAL, true, m_thread->GetAppDomain()->GetADToken());
9704
9705 event.FuncEval.vmThreadToken = m_thread->m_vmThreadToken;
9706 event.FuncEval.funcEvalType = m_evalType;
9707 event.FuncEval.funcMetadataToken = m_function->GetMetadataToken();
9708 event.FuncEval.vmDomainFile = m_function->GetModule()->GetRuntimeDomainFile();
9709 event.FuncEval.funcEvalKey = hFuncEval.Ptr();
9710 event.FuncEval.argCount = nArgs;
9711 event.FuncEval.genericArgsCount = nTypeArgs;
9712
9713
9714
9715 hr = SendFuncEval(nTypeArgs,
9716 rgpTypeArgs,
9717 reinterpret_cast<void *>(pArgData),
9718 sizeof(DebuggerIPCE_FuncEvalArgData) * nArgs,
9719 NULL,
9720 0,
9721 &event);
9722
9723 // Cleanup
9724
9725 if (pArgData)
9726 {
9727 delete [] pArgData;
9728 }
9729
9730 if (SUCCEEDED(hr))
9731 {
9732 hFuncEval.SuppressRelease(); // Now LS owns.
9733 }
9734 }
9735
9736 // Convert from LS EE-centric failure code to something more friendly to end-users.
9737 // Success HRs will not be converted.
9738 hr = FilterHR(hr);
9739
9740 // Return any failure the Left Side may have told us about.
9741 return hr;
9742}
9743
9744BOOL CordbEval::DoAppDomainsMatch( CordbAppDomain * pAppDomain,
9745 ULONG32 nTypes,
9746 ICorDebugType *pTypes[],
9747 ULONG32 nValues,
9748 ICorDebugValue *pValues[] )
9749{
9750 _ASSERTE( !(pTypes == NULL && nTypes != 0) );
9751 _ASSERTE( !(pValues == NULL && nValues != 0) );
9752
9753 // Make sure each value is in the appdomain.
9754 for(unsigned int i = 0; i < nValues; i++)
9755 {
9756 // Assuming that only Ref Values have AD affinity
9757 CordbAppDomain * pValueAppDomain = GetAppDomainFromValue( pValues[i] );
9758
9759 if ((pValueAppDomain != NULL) && (pValueAppDomain != pAppDomain))
9760 {
9761 LOG((LF_CORDB,LL_INFO1000, "CordbEval::DADM - AD mismatch. appDomain=0x%08x, param #%d=0x%08x, must fail.\n",
9762 pAppDomain, i, pValueAppDomain));
9763 return FALSE;
9764 }
9765 }
9766
9767 for(unsigned int i = 0; i < nTypes; i++ )
9768 {
9769 CordbType* t = static_cast<CordbType*>( pTypes[i] );
9770 CordbAppDomain * pTypeAppDomain = t->GetAppDomain();
9771
9772 if( pTypeAppDomain != NULL && pTypeAppDomain != pAppDomain )
9773 {
9774 LOG((LF_CORDB,LL_INFO1000, "CordbEval::DADM - AD mismatch. appDomain=0x%08x, type param #%d=0x%08x, must fail.\n",
9775 pAppDomain, i, pTypeAppDomain));
9776 return FALSE;
9777 }
9778 }
9779
9780 return TRUE;
9781}
9782
9783HRESULT CordbEval::NewObject(ICorDebugFunction *pConstructor,
9784 ULONG32 nArgs,
9785 ICorDebugValue *pArgs[])
9786{
9787 PUBLIC_API_ENTRY(this);
9788 FAIL_IF_NEUTERED(this);
9789 return NewParameterizedObject(pConstructor,0,NULL,nArgs,pArgs);
9790}
9791
9792//---------------------------------------------------------------------------------------
9793//
9794// This routine calls a constructor with the given set of type arguments and actual arguments.
9795// This is the jumping off point for func-evaling "new".
9796//
9797// Arguments:
9798// pConstructor - The function to call.
9799// nTypeArgs - The number of type-arguments for the method in rgpTypeArgs
9800// rgpTypeArgs - An array of pointers to types.
9801// nArgs - The number of arguments for the method in rgpArgs
9802// rgpArgs - An array of pointers to values for the arguments to the method.
9803//
9804// Return Value:
9805// HRESULT for the operation
9806//
9807HRESULT CordbEval::NewParameterizedObject(ICorDebugFunction * pConstructor,
9808 ULONG32 nTypeArgs,
9809 ICorDebugType * rgpTypeArgs[],
9810 ULONG32 nArgs,
9811 ICorDebugValue * rgpArgs[])
9812{
9813 PUBLIC_REENTRANT_API_ENTRY(this);
9814 FAIL_IF_NEUTERED(this);
9815 VALIDATE_POINTER_TO_OBJECT(pConstructor, ICorDebugFunction *);
9816 VALIDATE_POINTER_TO_OBJECT_ARRAY(rgpArgs, ICorDebugValue *, nArgs, true, true);
9817 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
9818
9819 // The LS will assume that all of the ICorDebugValues and ICorDebugTypes are in
9820 // the same appdomain as the constructor. Verify this.
9821 CordbAppDomain * pConstructorAppDomain = (static_cast<CordbFunction *> (pConstructor))->GetAppDomain();
9822
9823 if (!DoAppDomainsMatch(pConstructorAppDomain, nTypeArgs, rgpTypeArgs, nArgs, rgpArgs))
9824 {
9825 return ErrWrapper(CORDBG_E_APPDOMAIN_MISMATCH);
9826 }
9827
9828 // Callers are free to reuse an ICorDebugEval object for multiple
9829 // evals. Since we create a Left Side eval representation each
9830 // time, we need to be sure to clean it up now that we know we're
9831 // done with it.
9832 HRESULT hr = SendCleanup();
9833
9834 if (FAILED(hr))
9835 {
9836 return hr;
9837 }
9838
9839 RSLockHolder lockHolder(GetProcess()->GetProcessLock());
9840 RsPtrHolder<CordbEval> hFuncEval(this);
9841
9842 if (hFuncEval.Ptr().IsNull())
9843 {
9844 return E_OUTOFMEMORY;
9845 }
9846 lockHolder.Release();
9847
9848 // Remember the function that we're evaluating.
9849 m_function = static_cast<CordbFunction *>(pConstructor);
9850 m_evalType = DB_IPCE_FET_NEW_OBJECT;
9851
9852 // Arrange the arguments into a form that the left side can deal
9853 // with. We do this before starting the func eval setup to ensure
9854 // that we can complete this step before mutating up the left
9855 // side.
9856 DebuggerIPCE_FuncEvalArgData * pArgData = NULL;
9857
9858 if (nArgs > 0)
9859 {
9860 // We need to make the same type of array that the left side
9861 // holds.
9862 pArgData = new (nothrow) DebuggerIPCE_FuncEvalArgData[nArgs];
9863
9864 if (pArgData == NULL)
9865 {
9866 return E_OUTOFMEMORY;
9867 }
9868
9869 // For each argument, convert its home into something the left
9870 // side can understand.
9871 for (unsigned int i = 0; i < nArgs; i++)
9872 {
9873 hr = GatherArgInfo(rgpArgs[i], &(pArgData[i]));
9874
9875 if (FAILED(hr))
9876 {
9877 return hr;
9878 }
9879 }
9880 }
9881
9882 // Send over to the left side and get it to setup this eval.
9883 DebuggerIPCEvent event;
9884
9885 m_thread->GetProcess()->InitIPCEvent(&event, DB_IPCE_FUNC_EVAL, true, m_thread->GetAppDomain()->GetADToken());
9886
9887 event.FuncEval.vmThreadToken = m_thread->m_vmThreadToken;
9888 event.FuncEval.funcEvalType = m_evalType;
9889 event.FuncEval.funcMetadataToken = m_function->GetMetadataToken();
9890 event.FuncEval.vmDomainFile = m_function->GetModule()->GetRuntimeDomainFile();
9891 event.FuncEval.funcEvalKey = hFuncEval.Ptr();
9892 event.FuncEval.argCount = nArgs;
9893 event.FuncEval.genericArgsCount = nTypeArgs;
9894
9895 hr = SendFuncEval(nTypeArgs,
9896 rgpTypeArgs,
9897 reinterpret_cast<void *>(pArgData),
9898 sizeof(DebuggerIPCE_FuncEvalArgData) * nArgs,
9899 NULL,
9900 0,
9901 &event);
9902
9903 // Cleanup
9904
9905 if (pArgData)
9906 {
9907 delete [] pArgData;
9908 }
9909
9910 if (SUCCEEDED(hr))
9911 {
9912 hFuncEval.SuppressRelease(); // Now LS owns.
9913 }
9914
9915
9916 // Return any failure the Left Side may have told us about.
9917 return hr;
9918}
9919
9920HRESULT CordbEval::NewObjectNoConstructor(ICorDebugClass *pClass)
9921{
9922 PUBLIC_API_ENTRY(this);
9923 FAIL_IF_NEUTERED(this);
9924 return NewParameterizedObjectNoConstructor(pClass,0,NULL);
9925}
9926
9927//---------------------------------------------------------------------------------------
9928//
9929// This routine creates an object of a certain type, but does not call the constructor
9930// for the type on the object.
9931//
9932// Arguments:
9933// pClass - the type of the object to create.
9934// nTypeArgs - The number of type-arguments for the method in rgpTypeArgs
9935// rgpTypeArgs - An array of pointers to types.
9936//
9937// Return Value:
9938// HRESULT for the operation
9939//
9940HRESULT CordbEval::NewParameterizedObjectNoConstructor(ICorDebugClass * pClass,
9941 ULONG32 nTypeArgs,
9942 ICorDebugType * rgpTypeArgs[])
9943{
9944 PUBLIC_REENTRANT_API_ENTRY(this);
9945 FAIL_IF_NEUTERED(this);
9946 VALIDATE_POINTER_TO_OBJECT(pClass, ICorDebugClass *);
9947 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
9948
9949 // The LS will assume that all of the ICorDebugTypes are in
9950 // the same appdomain as the class. Verify this.
9951 CordbAppDomain * pClassAppDomain = (static_cast<CordbClass *> (pClass))->GetAppDomain();
9952
9953 if (!DoAppDomainsMatch(pClassAppDomain, nTypeArgs, rgpTypeArgs, 0, NULL))
9954 {
9955 return ErrWrapper(CORDBG_E_APPDOMAIN_MISMATCH);
9956 }
9957
9958 // Callers are free to reuse an ICorDebugEval object for multiple
9959 // evals. Since we create a Left Side eval representation each
9960 // time, we need to be sure to clean it up now that we know we're
9961 // done with it.
9962 HRESULT hr = SendCleanup();
9963
9964 if (FAILED(hr))
9965 {
9966 return hr;
9967 }
9968
9969 RSLockHolder lockHolder(GetProcess()->GetProcessLock());
9970 RsPtrHolder<CordbEval> hFuncEval(this);
9971 lockHolder.Release(); // release to send an IPC event.
9972
9973 if (hFuncEval.Ptr().IsNull())
9974 {
9975 return E_OUTOFMEMORY;
9976 }
9977
9978 // Remember the function that we're evaluating.
9979 m_class = (CordbClass*)pClass;
9980 m_evalType = DB_IPCE_FET_NEW_OBJECT_NC;
9981
9982 // Send over to the left side and get it to setup this eval.
9983 DebuggerIPCEvent event;
9984
9985 m_thread->GetProcess()->InitIPCEvent(&event, DB_IPCE_FUNC_EVAL, true, m_thread->GetAppDomain()->GetADToken());
9986
9987 event.FuncEval.vmThreadToken = m_thread->m_vmThreadToken;
9988 event.FuncEval.funcEvalType = m_evalType;
9989 event.FuncEval.funcMetadataToken = mdMethodDefNil;
9990 event.FuncEval.funcClassMetadataToken = (mdTypeDef)m_class->m_id;
9991 event.FuncEval.vmDomainFile = m_class->GetModule()->GetRuntimeDomainFile();
9992 event.FuncEval.funcEvalKey = hFuncEval.Ptr();
9993 event.FuncEval.argCount = 0;
9994 event.FuncEval.genericArgsCount = nTypeArgs;
9995
9996 hr = SendFuncEval(nTypeArgs, rgpTypeArgs, NULL, 0, NULL, 0, &event);
9997
9998 if (SUCCEEDED(hr))
9999 {
10000 hFuncEval.SuppressRelease(); // Now LS owns.
10001 }
10002
10003 // Return any failure the Left Side may have told us about.
10004 return hr;
10005}
10006
10007/*
10008 *
10009 * NewString
10010 *
10011 * This routine is the interface function for ICorDebugEval::NewString
10012 *
10013 * Parameters:
10014 * string - the string to create - must be null-terminated
10015 *
10016 * Return Value:
10017 * HRESULT from the helper routines on RS and LS.
10018 *
10019 */
10020HRESULT CordbEval::NewString(LPCWSTR string)
10021{
10022 PUBLIC_API_ENTRY(this);
10023 FAIL_IF_NEUTERED(this);
10024 return NewStringWithLength(string, (UINT)wcslen(string));
10025}
10026
10027//---------------------------------------------------------------------------------------
10028//
10029// This routine is the interface function for ICorDebugEval::NewStringWithLength.
10030//
10031// Arguments:
10032// wszString - the string to create
10033// iLength - the number of characters that you want to create. Can include embedded nulls.
10034//
10035// Return Value:
10036// HRESULT for the operation
10037//
10038HRESULT CordbEval::NewStringWithLength(LPCWSTR wszString, UINT iLength)
10039{
10040 PUBLIC_REENTRANT_API_ENTRY(this);
10041 FAIL_IF_NEUTERED(this);
10042 VALIDATE_POINTER_TO_OBJECT(wszString, LPCWSTR); // Gotta have a string...
10043 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
10044
10045 // Callers are free to reuse an ICorDebugEval object for multiple
10046 // evals. Since we create a Left Side eval representation each
10047 // time, we need to be sure to clean it up now that we know we're
10048 // done with it.
10049 HRESULT hr = SendCleanup();
10050
10051 if (FAILED(hr))
10052 {
10053 return hr;
10054 }
10055
10056 RSLockHolder lockHolder(GetProcess()->GetProcessLock());
10057 RsPtrHolder<CordbEval> hFuncEval(this);
10058 lockHolder.Release(); // release to send an IPC event.
10059
10060 if (hFuncEval.Ptr().IsNull())
10061 {
10062 return E_OUTOFMEMORY;
10063 }
10064
10065
10066 // Length of the string? Don't account for null as COMString::NewString is length-based
10067 SIZE_T cbString = iLength * sizeof(WCHAR);
10068
10069 // Remember that we're doing a func eval for a new string.
10070 m_function = NULL;
10071 m_evalType = DB_IPCE_FET_NEW_STRING;
10072
10073 // Send over to the left side and get it to setup this eval.
10074 DebuggerIPCEvent event;
10075
10076 m_thread->GetProcess()->InitIPCEvent(&event, DB_IPCE_FUNC_EVAL, true, m_thread->GetAppDomain()->GetADToken());
10077
10078 event.FuncEval.vmThreadToken = m_thread->m_vmThreadToken;
10079 event.FuncEval.funcEvalType = m_evalType;
10080 event.FuncEval.funcEvalKey = hFuncEval.Ptr();
10081 event.FuncEval.stringSize = cbString;
10082
10083 // Note: no function or module here...
10084 event.FuncEval.funcMetadataToken = mdMethodDefNil;
10085 event.FuncEval.funcClassMetadataToken = mdTypeDefNil;
10086 event.FuncEval.vmDomainFile = VMPTR_DomainFile::NullPtr();
10087 event.FuncEval.argCount = 0;
10088 event.FuncEval.genericArgsCount = 0;
10089 event.FuncEval.genericArgsNodeCount = 0;
10090
10091 hr = SendFuncEval(0, NULL, (void *)wszString, (unsigned int)cbString, NULL, 0, &event);
10092
10093 if (SUCCEEDED(hr))
10094 {
10095 hFuncEval.SuppressRelease(); // Now LS owns.
10096 }
10097
10098 // Return any failure the Left Side may have told us about.
10099 return hr;
10100}
10101
10102HRESULT CordbEval::NewArray(CorElementType elementType,
10103 ICorDebugClass *pElementClass,
10104 ULONG32 rank,
10105 ULONG32 dims[],
10106 ULONG32 lowBounds[])
10107{
10108 PUBLIC_API_ENTRY(this);
10109 FAIL_IF_NEUTERED(this);
10110 VALIDATE_POINTER_TO_OBJECT_OR_NULL(pElementClass, ICorDebugClass *);
10111
10112 // If you want a class, you gotta pass a class.
10113 if ((elementType == ELEMENT_TYPE_CLASS) && (pElementClass == NULL))
10114 return E_INVALIDARG;
10115
10116 // If you want an array of objects, then why pass a class?
10117 if ((elementType == ELEMENT_TYPE_OBJECT) && (pElementClass != NULL))
10118 return E_INVALIDARG;
10119
10120 // Arg check...
10121 if (elementType == ELEMENT_TYPE_VOID)
10122 return E_INVALIDARG;
10123
10124 CordbType *typ;
10125 HRESULT hr = S_OK;
10126 hr = CordbType::MkUnparameterizedType(m_thread->GetAppDomain(), elementType, (CordbClass *) pElementClass, &typ);
10127
10128 if (FAILED(hr))
10129 return hr;
10130
10131 return NewParameterizedArray(typ, rank,dims,lowBounds);
10132
10133}
10134
10135
10136//---------------------------------------------------------------------------------------
10137//
10138// This routine sets up a func-eval to create a new array of the given type.
10139//
10140// Arguments:
10141// pElementType - The type of each element of the array.
10142// rank - Rank of the array.
10143// rgDimensions - Array of dimensions for the array.
10144// rmLowBounds - Array of lower bounds on the array.
10145//
10146// Return Value:
10147// HRESULT for the operation
10148//
10149HRESULT CordbEval::NewParameterizedArray(ICorDebugType * pElementType,
10150 ULONG32 rank,
10151 ULONG32 rgDimensions[],
10152 ULONG32 rgLowBounds[])
10153{
10154 PUBLIC_REENTRANT_API_ENTRY(this);
10155 FAIL_IF_NEUTERED(this);
10156 VALIDATE_POINTER_TO_OBJECT_OR_NULL(pElementType, ICorDebugType *);
10157 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
10158
10159
10160 // Callers are free to reuse an ICorDebugEval object for multiple evals. Since we create a Left Side eval
10161 // representation each time, we need to be sure to clean it up now that we know we're done with it.
10162 HRESULT hr = SendCleanup();
10163
10164 if (FAILED(hr))
10165 {
10166 return hr;
10167 }
10168
10169 // Arg check...
10170 if ((rank == 0) || (rgDimensions == NULL))
10171 {
10172 return E_INVALIDARG;
10173 }
10174
10175 RSLockHolder lockHolder(GetProcess()->GetProcessLock());
10176 RsPtrHolder<CordbEval> hFuncEval(this);
10177 lockHolder.Release(); // release to send an IPC event.
10178
10179 if (hFuncEval.Ptr().IsNull())
10180 {
10181 return E_OUTOFMEMORY;
10182 }
10183
10184
10185 // Remember that we're doing a func eval for a new string.
10186 m_function = NULL;
10187 m_evalType = DB_IPCE_FET_NEW_ARRAY;
10188
10189 // Send over to the left side and get it to setup this eval.
10190 DebuggerIPCEvent event;
10191
10192 m_thread->GetProcess()->InitIPCEvent(&event, DB_IPCE_FUNC_EVAL, true, m_thread->GetAppDomain()->GetADToken());
10193
10194 event.FuncEval.vmThreadToken = m_thread->m_vmThreadToken;
10195 event.FuncEval.funcEvalType = m_evalType;
10196 event.FuncEval.funcEvalKey = hFuncEval.Ptr();
10197
10198 event.FuncEval.arrayRank = rank;
10199
10200 // Note: no function or module here...
10201 event.FuncEval.funcMetadataToken = mdMethodDefNil;
10202 event.FuncEval.funcClassMetadataToken = mdTypeDefNil;
10203 event.FuncEval.vmDomainFile = VMPTR_DomainFile::NullPtr();
10204 event.FuncEval.argCount = 0;
10205 event.FuncEval.genericArgsCount = 1;
10206
10207 // Prefast overflow sanity check.
10208 S_UINT32 allocSize = S_UINT32(rank) * S_UINT32(sizeof(SIZE_T));
10209
10210 if (allocSize.IsOverflow())
10211 {
10212 return E_INVALIDARG;
10213 }
10214
10215 // Just in case sizeof(SIZE_T) != sizeof(ULONG32)
10216 SIZE_T * rgDimensionsSizeT = reinterpret_cast<SIZE_T *>(_alloca(allocSize.Value()));
10217
10218 for (unsigned int i = 0; i < rank; i++)
10219 {
10220 rgDimensionsSizeT[i] = rgDimensions[i];
10221 }
10222
10223 ICorDebugType * rgpGenericArgs[1];
10224
10225 rgpGenericArgs[0] = pElementType;
10226
10227 // @dbgtodo funceval : lower bounds were ignored in V1 - fix this.
10228 hr = SendFuncEval(1,
10229 rgpGenericArgs,
10230 reinterpret_cast<void *>(rgDimensionsSizeT),
10231 rank * sizeof(SIZE_T),
10232 NULL, // (void*)lowBounds,
10233 0, // ((lowBounds == NULL) ? 0 : rank * sizeof(SIZE_T)),
10234 &event);
10235
10236 if (SUCCEEDED(hr))
10237 {
10238 hFuncEval.SuppressRelease(); // Now LS owns.
10239 }
10240
10241 // Return any failure the Left Side may have told us about.
10242 return hr;
10243}
10244
10245HRESULT CordbEval::IsActive(BOOL *pbActive)
10246{
10247 PUBLIC_API_ENTRY(this);
10248 FAIL_IF_NEUTERED(this);
10249 VALIDATE_POINTER_TO_OBJECT(pbActive, BOOL *);
10250
10251 *pbActive = (m_complete == true);
10252 return S_OK;
10253}
10254
10255/*
10256 * This routine submits an abort request to the LS.
10257 *
10258 * Parameters:
10259 * None.
10260 *
10261 * Returns:
10262 * The HRESULT as returned by the LS.
10263 *
10264 */
10265
10266HRESULT
10267CordbEval::Abort(
10268 void
10269 )
10270{
10271 PUBLIC_API_ENTRY(this);
10272 FAIL_IF_NEUTERED(this);
10273
10274 ATT_ALLOW_LIVE_DO_STOPGO(GetProcess());
10275
10276
10277 //
10278 // No need to abort if its already completed.
10279 //
10280 if (m_complete)
10281 {
10282 return S_OK;
10283 }
10284
10285
10286 //
10287 // Can't abort if its never even been started.
10288 //
10289 if (m_debuggerEvalKey == NULL)
10290 {
10291 return E_INVALIDARG;
10292 }
10293
10294 CORDBRequireProcessStateOK(m_thread->GetProcess());
10295
10296 //
10297 // Send over to the left side to get the eval aborted.
10298 //
10299 DebuggerIPCEvent event;
10300
10301 m_thread->GetProcess()->InitIPCEvent(&event,
10302 DB_IPCE_FUNC_EVAL_ABORT,
10303 true,
10304 m_thread->GetAppDomain()->GetADToken()
10305 );
10306
10307 event.FuncEvalAbort.debuggerEvalKey = m_debuggerEvalKey;
10308
10309 HRESULT hr = m_thread->GetProcess()->SendIPCEvent(&event,
10310 sizeof(DebuggerIPCEvent)
10311 );
10312
10313
10314 //
10315 // If the send failed, return that failure.
10316 //
10317 if (FAILED(hr))
10318 {
10319 return hr;
10320 }
10321
10322 _ASSERTE(event.type == DB_IPCE_FUNC_EVAL_ABORT_RESULT);
10323
10324 //
10325 // Since we may have
10326 // overwritten anything (objects, code, etc), we should mark
10327 // everything as needing to be re-cached.
10328 //
10329 m_thread->GetProcess()->m_continueCounter++;
10330
10331 hr = event.hr;
10332
10333 return hr;
10334}
10335
10336HRESULT CordbEval::GetResult(ICorDebugValue **ppResult)
10337{
10338 PUBLIC_API_ENTRY(this);
10339 FAIL_IF_NEUTERED(this);
10340 VALIDATE_POINTER_TO_OBJECT(ppResult, ICorDebugValue **);
10341 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
10342
10343 *ppResult = NULL;
10344
10345 // Is the evaluation complete?
10346 if (!m_complete)
10347 {
10348 return CORDBG_E_FUNC_EVAL_NOT_COMPLETE;
10349 }
10350
10351 if (m_aborted)
10352 {
10353 return CORDBG_S_FUNC_EVAL_ABORTED;
10354 }
10355
10356 // Does the evaluation have a result?
10357 if (m_resultType.elementType == ELEMENT_TYPE_VOID)
10358 {
10359 return CORDBG_S_FUNC_EVAL_HAS_NO_RESULT;
10360 }
10361
10362 HRESULT hr = S_OK;
10363 EX_TRY
10364 {
10365 // Make a ICorDebugValue out of the result.
10366 CordbAppDomain * pAppDomain;
10367
10368 if (!m_resultAppDomainToken.IsNull())
10369 {
10370 // @dbgtodo funceval - push this up
10371 RSLockHolder lockHolder(GetProcess()->GetProcessLock());
10372
10373 pAppDomain = m_thread->GetProcess()->LookupOrCreateAppDomain(m_resultAppDomainToken);
10374 }
10375 else
10376 {
10377 pAppDomain = m_thread->GetAppDomain();
10378 }
10379 PREFIX_ASSUME(pAppDomain != NULL);
10380
10381 CordbType * pType = NULL;
10382 hr = CordbType::TypeDataToType(pAppDomain, &m_resultType, &pType);
10383 IfFailThrow(hr);
10384
10385 bool resultInHandle =
10386 ((m_resultType.elementType == ELEMENT_TYPE_CLASS) ||
10387 (m_resultType.elementType == ELEMENT_TYPE_SZARRAY) ||
10388 (m_resultType.elementType == ELEMENT_TYPE_OBJECT) ||
10389 (m_resultType.elementType == ELEMENT_TYPE_ARRAY) ||
10390 (m_resultType.elementType == ELEMENT_TYPE_STRING));
10391
10392 if (resultInHandle)
10393 {
10394 // if object handle is null here, something has gone wrong!!!
10395 _ASSERTE(!m_vmObjectHandle.IsNull());
10396
10397 if (m_pHandleValue == NULL)
10398 {
10399 // Create CordbHandleValue for result
10400 RSInitHolder<CordbHandleValue> pHandleValue(new CordbHandleValue(pAppDomain, pType, HANDLE_STRONG));
10401
10402 // Initialize the handle value object. The HandleValue will now
10403 // own the m_objectHandle.
10404 hr = pHandleValue->Init(m_vmObjectHandle);
10405
10406 if (!SUCCEEDED(hr))
10407 {
10408 // Neuter the new object we've been working on. This will
10409 // call Dispose(), and that will go back to the left side
10410 // and free the handle that we got above.
10411 pHandleValue->NeuterLeftSideResources();
10412
10413 //
10414
10415 // Do not delete chv here. The neuter list still has a reference to it, and it will be cleaned up automatically.
10416 ThrowHR(hr);
10417 }
10418 m_pHandleValue.Assign(pHandleValue);
10419 pHandleValue.ClearAndMarkDontNeuter();
10420 }
10421
10422 // This AddRef is for caller to release
10423 //
10424 *ppResult = m_pHandleValue;
10425 m_pHandleValue->ExternalAddRef();
10426 }
10427 else if (CorIsPrimitiveType(m_resultType.elementType) && (m_resultType.elementType != ELEMENT_TYPE_STRING))
10428 {
10429 // create a CordbGenericValue flagged as a literal
10430 hr = CordbEval::CreatePrimitiveLiteral(pType, ppResult);
10431 }
10432 else
10433 {
10434 TargetBuffer remoteValue(m_resultAddr, CordbValue::GetSizeForType(pType, kBoxed));
10435 // Now that we have the module, go ahead and create the result.
10436
10437 CordbValue::CreateValueByType(pAppDomain,
10438 pType,
10439 true,
10440 remoteValue,
10441 MemoryRange(NULL, 0),
10442 NULL,
10443 ppResult); // throws
10444 }
10445
10446 }
10447 EX_CATCH_HRESULT(hr);
10448 return hr;
10449}
10450
10451HRESULT CordbEval::GetThread(ICorDebugThread **ppThread)
10452{
10453 PUBLIC_API_ENTRY(this);
10454 FAIL_IF_NEUTERED(this);
10455 VALIDATE_POINTER_TO_OBJECT(ppThread, ICorDebugThread **);
10456
10457 *ppThread = static_cast<ICorDebugThread*> (m_thread);
10458 m_thread->ExternalAddRef();
10459
10460 return S_OK;
10461}
10462
10463// Create a RS literal for primitive type funceval result. In case the result is used as an argument for
10464// another funceval, we need to make sure that we're not relying on the LS value, which will be freed and
10465// thus unavailable.
10466// Arguments:
10467// input: pType - CordbType instance representing the type of the primitive value
10468// output: ppValue - ICorDebugValue representing the result as a literal CordbGenericValue
10469// Return Value:
10470// hr: may fail for OOM, ReadProcessMemory failures
10471HRESULT CordbEval::CreatePrimitiveLiteral(CordbType * pType,
10472 ICorDebugValue ** ppValue)
10473{
10474 CordbGenericValue * gv = NULL;
10475 HRESULT hr = S_OK;
10476 EX_TRY
10477 {
10478 // Create a generic value.
10479 gv = new CordbGenericValue(pType);
10480
10481 // initialize the local value
10482 int size = CordbValue::GetSizeForType(pType, kBoxed);
10483 if (size > 8)
10484 {
10485 ThrowHR(HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER));
10486 }
10487 TargetBuffer remoteValue(m_resultAddr, size);
10488 BYTE localBuffer[8] = {0};
10489
10490 GetProcess()->SafeReadBuffer (remoteValue, localBuffer);
10491 gv->SetValue(localBuffer);
10492
10493 // Do not delete gv here even if the initialization fails.
10494 // The neuter list still has a reference to it, and it will be cleaned up automatically.
10495 gv->ExternalAddRef();
10496 *ppValue = (ICorDebugValue*)(ICorDebugGenericValue*)gv;
10497 }
10498 EX_CATCH_HRESULT(hr);
10499 return hr;
10500}
10501
10502HRESULT CordbEval::CreateValue(CorElementType elementType,
10503 ICorDebugClass *pElementClass,
10504 ICorDebugValue **ppValue)
10505{
10506 PUBLIC_API_ENTRY(this);
10507 FAIL_IF_NEUTERED(this);
10508 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
10509
10510 CordbType *typ;
10511
10512 // @todo: only primitive values right now.
10513 if (((elementType < ELEMENT_TYPE_BOOLEAN) ||
10514 (elementType > ELEMENT_TYPE_R8)) &&
10515 !(elementType == ELEMENT_TYPE_CLASS))
10516 return E_INVALIDARG;
10517
10518 HRESULT hr = S_OK;
10519
10520 // MkUnparameterizedType now works if you give it ELEMENT_TYPE_CLASS and
10521 // a null pElementClass - it returns the type for ELEMENT_TYPE_OBJECT.
10522
10523 hr = CordbType::MkUnparameterizedType(m_thread->GetAppDomain(), elementType, (CordbClass *) pElementClass, &typ);
10524
10525 if (FAILED(hr))
10526 return hr;
10527
10528 return CreateValueForType(typ, ppValue);
10529}
10530
10531// create an ICDValue to represent a value for a funceval
10532// Arguments:
10533// input: pIType - the type for the new value
10534// output: ppValue - the new ICDValue. If there is a failure of some sort, this will be NULL
10535// ReturnValue: S_OK on success (ppValue should contain a non-NULL address)
10536// E_OUTOFMEMORY, if we can't allocate space for the new ICDValue
10537// Notes: We can also get read process memory errors or E_INVALIDARG if errors occur during initialization,
10538// but in that case, we don't return the hresult. Instead, we just never update ppValue, so it will still be
10539// NULL on exit.
10540HRESULT CordbEval::CreateValueForType(ICorDebugType * pIType,
10541 ICorDebugValue ** ppValue)
10542{
10543 HRESULT hr = S_OK;
10544
10545 PUBLIC_REENTRANT_API_ENTRY(this);
10546 FAIL_IF_NEUTERED(this);
10547 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
10548
10549 VALIDATE_POINTER_TO_OBJECT(ppValue, ICorDebugValue **);
10550 VALIDATE_POINTER_TO_OBJECT(pIType, ICorDebugType*);
10551
10552 *ppValue = NULL;
10553 CordbType *pType = static_cast<CordbType *> (pIType);
10554
10555 CorElementType elementType = pType->m_elementType;
10556 // We don't support IntPtr and UIntPtr types as arguments here, but we do support these types as results
10557 // (see code:CordbEval::CreatePrimitiveLiteral) and we have changed the LS to support them as well
10558 if (((elementType < ELEMENT_TYPE_BOOLEAN) ||
10559 (elementType > ELEMENT_TYPE_R8)) &&
10560 !((elementType == ELEMENT_TYPE_CLASS) || (elementType == ELEMENT_TYPE_OBJECT)))
10561 return E_INVALIDARG;
10562
10563 // Note: ELEMENT_TYPE_OBJECT is what we'll get for the null reference case, so allow that.
10564 if ((elementType == ELEMENT_TYPE_CLASS) || (elementType == ELEMENT_TYPE_OBJECT))
10565 {
10566 EX_TRY
10567 {
10568 // create a reference value
10569 CordbReferenceValue *rv = new CordbReferenceValue(pType);
10570
10571 if (SUCCEEDED(rv->InitRef(MemoryRange(NULL,0))))
10572 {
10573 // Do not delete rv here even if the initialization fails.
10574 // The neuter list still has a reference to it, and it will be cleaned up automatically.
10575 rv->ExternalAddRef();
10576 *ppValue = (ICorDebugValue*)(ICorDebugReferenceValue*)rv;
10577 }
10578 }
10579 EX_CATCH_HRESULT(hr);
10580 }
10581 else
10582 {
10583 CordbGenericValue * gv = NULL;
10584 EX_TRY
10585 {
10586 // Create a generic value.
10587 gv = new CordbGenericValue(pType);
10588
10589 gv->Init(MemoryRange(NULL,0));
10590 // Do not delete gv here even if the initialization fails.
10591 // The neuter list still has a reference to it, and it will be cleaned up automatically.
10592 gv->ExternalAddRef();
10593 *ppValue = (ICorDebugValue*)(ICorDebugGenericValue*)gv;
10594 }
10595 EX_CATCH_HRESULT(hr);
10596 }
10597
10598 return hr;
10599} // CordbEval::CreateValueForType
10600
10601
10602/* ------------------------------------------------------------------------- *
10603 * CordbEval2
10604 *
10605 * Extentions to the CordbEval class for Whidbey
10606 *
10607 * ------------------------------------------------------------------------- */
10608
10609
10610/*
10611 * This routine submits a rude abort request to the LS.
10612 *
10613 * Parameters:
10614 * None.
10615 *
10616 * Returns:
10617 * The HRESULT as returned by the LS.
10618 *
10619 */
10620
10621HRESULT
10622CordbEval::RudeAbort(
10623 void
10624 )
10625{
10626 PUBLIC_API_ENTRY(this);
10627 FAIL_IF_NEUTERED(this);
10628
10629
10630 ATT_ALLOW_LIVE_DO_STOPGO(GetProcess());
10631
10632 //
10633 // No need to abort if its already completed.
10634 //
10635 if (m_complete)
10636 {
10637 return S_OK;
10638 }
10639
10640 //
10641 // Can't abort if its never even been started.
10642 //
10643 if (m_debuggerEvalKey == NULL)
10644 {
10645 return E_INVALIDARG;
10646 }
10647
10648 CORDBRequireProcessStateOK(m_thread->GetProcess());
10649
10650 //
10651 // Send over to the left side to get the eval aborted.
10652 //
10653 DebuggerIPCEvent event;
10654
10655 m_thread->GetProcess()->InitIPCEvent(&event,
10656 DB_IPCE_FUNC_EVAL_RUDE_ABORT,
10657 true,
10658 m_thread->GetAppDomain()->GetADToken()
10659 );
10660
10661 event.FuncEvalRudeAbort.debuggerEvalKey = m_debuggerEvalKey;
10662
10663 HRESULT hr = m_thread->GetProcess()->SendIPCEvent(&event,
10664 sizeof(DebuggerIPCEvent)
10665 );
10666
10667 //
10668 // If the send failed, return that failure.
10669 //
10670 if (FAILED(hr))
10671 {
10672 return hr;
10673 }
10674
10675 _ASSERTE(event.type == DB_IPCE_FUNC_EVAL_RUDE_ABORT_RESULT);
10676
10677 //
10678 // Since we may have
10679 // overwritten anything (objects, code, etc), we should mark
10680 // everything as needing to be re-cached.
10681 //
10682 m_thread->GetProcess()->m_continueCounter++;
10683
10684 hr = event.hr;
10685
10686 return hr;
10687}
10688
10689
10690
10691
10692/* ------------------------------------------------------------------------- *
10693 * CodeParameter Enumerator class
10694 * ------------------------------------------------------------------------- */
10695
10696CordbCodeEnum::CordbCodeEnum(unsigned int cCodes, RSSmartPtr<CordbCode> * ppCodes) :
10697 CordbBase(NULL, 0)
10698{
10699 // Because the array is of smart-ptrs, the elements are already reffed
10700 // We now take ownership of the array itself too.
10701 m_ppCodes = ppCodes;
10702
10703 m_iCurrent = 0;
10704 m_iMax = cCodes;
10705}
10706
10707
10708CordbCodeEnum::~CordbCodeEnum()
10709{
10710 // This will invoke the SmartPtr dtors on each element and call release.
10711 delete [] m_ppCodes;
10712}
10713
10714HRESULT CordbCodeEnum::QueryInterface(REFIID id, void **pInterface)
10715{
10716 if (id == IID_ICorDebugEnum)
10717 *pInterface = static_cast<ICorDebugEnum*>(this);
10718 else if (id == IID_ICorDebugCodeEnum)
10719 *pInterface = static_cast<ICorDebugCodeEnum*>(this);
10720 else if (id == IID_IUnknown)
10721 *pInterface = static_cast<IUnknown*>(static_cast<ICorDebugCodeEnum*>(this));
10722 else
10723 {
10724 *pInterface = NULL;
10725 return E_NOINTERFACE;
10726 }
10727
10728 ExternalAddRef();
10729 return S_OK;
10730}
10731
10732HRESULT CordbCodeEnum::Skip(ULONG celt)
10733{
10734 HRESULT hr = E_FAIL;
10735 if ( (m_iCurrent+celt) < m_iMax ||
10736 celt == 0)
10737 {
10738 m_iCurrent += celt;
10739 hr = S_OK;
10740 }
10741
10742 return hr;
10743}
10744
10745HRESULT CordbCodeEnum::Reset()
10746{
10747 m_iCurrent = 0;
10748 return S_OK;
10749}
10750
10751HRESULT CordbCodeEnum::Clone(ICorDebugEnum **ppEnum)
10752{
10753 VALIDATE_POINTER_TO_OBJECT(ppEnum, ICorDebugEnum **);
10754 (*ppEnum) = NULL;
10755
10756 HRESULT hr = S_OK;
10757
10758 // Create a new copy of the array because the CordbCodeEnum will
10759 // take ownership of it.
10760 RSSmartPtr<CordbCode> * ppCodes = new (nothrow) RSSmartPtr<CordbCode> [m_iMax];
10761 if (ppCodes == NULL)
10762 {
10763 return E_OUTOFMEMORY;
10764 }
10765 for(UINT i = 0; i < m_iMax; i++)
10766 {
10767 ppCodes[i].Assign(m_ppCodes[i]);
10768 }
10769
10770
10771 CordbCodeEnum *pCVE = new (nothrow) CordbCodeEnum( m_iMax, ppCodes);
10772 if ( pCVE == NULL )
10773 {
10774 delete [] ppCodes;
10775 hr = E_OUTOFMEMORY;
10776 goto LExit;
10777 }
10778
10779 pCVE->ExternalAddRef();
10780 (*ppEnum) = (ICorDebugEnum*)pCVE;
10781
10782LExit:
10783 return hr;
10784}
10785
10786HRESULT CordbCodeEnum::GetCount(ULONG *pcelt)
10787{
10788 VALIDATE_POINTER_TO_OBJECT(pcelt, ULONG *);
10789
10790 if( pcelt == NULL)
10791 return E_INVALIDARG;
10792
10793 (*pcelt) = m_iMax;
10794 return S_OK;
10795}
10796
10797//
10798// In the event of failure, the current pointer will be left at
10799// one element past the troublesome element. Thus, if one were
10800// to repeatedly ask for one element to iterate through the
10801// array, you would iterate exactly m_iMax times, regardless
10802// of individual failures.
10803HRESULT CordbCodeEnum::Next(ULONG celt, ICorDebugCode *values[], ULONG *pceltFetched)
10804{
10805 VALIDATE_POINTER_TO_OBJECT_ARRAY(values, ICorDebugClass *,
10806 celt, true, true);
10807 VALIDATE_POINTER_TO_OBJECT_OR_NULL(pceltFetched, ULONG *);
10808
10809 if ((pceltFetched == NULL) && (celt != 1))
10810 {
10811 return E_INVALIDARG;
10812 }
10813
10814 if (celt == 0)
10815 {
10816 if (pceltFetched != NULL)
10817 {
10818 *pceltFetched = 0;
10819 }
10820 return S_OK;
10821 }
10822
10823 HRESULT hr = S_OK;
10824
10825 int iMax = min( m_iMax, m_iCurrent+celt);
10826 int i;
10827
10828 for (i = m_iCurrent; i < iMax; i++)
10829 {
10830 values[i-m_iCurrent] = m_ppCodes[i];
10831 values[i-m_iCurrent]->AddRef();
10832 }
10833
10834 int count = (i - m_iCurrent);
10835
10836 if ( FAILED( hr ) )
10837 { //we failed: +1 pushes us past troublesome element
10838 m_iCurrent += 1 + count;
10839 }
10840 else
10841 {
10842 m_iCurrent += count;
10843 }
10844
10845 if (pceltFetched != NULL)
10846 {
10847 *pceltFetched = count;
10848 }
10849
10850 //
10851 // If we reached the end of the enumeration, but not the end
10852 // of the number of requested items, we return S_FALSE.
10853 //
10854 if (((ULONG)count) < celt)
10855 {
10856 return S_FALSE;
10857 }
10858
10859 return hr;
10860}
10861
10862