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// File: funceval.cpp
6//
7
8//
9// funceval.cpp - Debugger func-eval routines.
10//
11// ****************************************************************************
12// Putting code & #includes, #defines, etc, before the stdafx.h will
13// cause the code,etc, to be silently ignored
14
15
16#include "stdafx.h"
17#include "debugdebugger.h"
18#include "../inc/common.h"
19#include "perflog.h"
20#include "eeconfig.h" // This is here even for retail & free builds...
21#include "../../dlls/mscorrc/resource.h"
22
23#include "vars.hpp"
24#include "threads.h"
25#include "appdomain.inl"
26#include <limits.h>
27#include "ilformatter.h"
28
29#ifndef DACCESS_COMPILE
30
31//
32// This is the main file for processing func-evals. Nestle in
33// with a cup o' tea and read on.
34//
35// The most common case is handled in GCProtectArgsAndDoNormalFuncEval(), which follows
36// all the comments below. The two other corner cases are handled in
37// FuncEvalHijackWorker(), and are extremely straight-forward.
38//
39// There are several steps to successfully processing a func-eval. At a
40// very high level, the first step is to gather all the information necessary
41// to make the call (specifically, gather arg info and method info); the second
42// step is to actually make the call to managed code; finally, the third step
43// is to take all results and unpackage them.
44//
45// The first step (gathering arg and method info) has several critical passes that
46// must be made.
47// a) Protect all passed in args from a GC.
48// b) Transition into the appropriate AppDomain if necessary
49// c) Pre-allocate object for 'new' calls and, if necessary, box the 'this' argument. (May cause a GC)
50// d) Gather method info (May cause GC)
51// e) Gather info from runtime about args. (May cause a GC)
52// f) Box args that need to be, GC-protecting the newly boxed items. (May cause a GC)
53// g) Pre-allocate object for return values. (May cause a GC)
54// h) Copy to pBufferForArgsArray all the args. This array is used to hold values that
55// may need writable memory for ByRef args.
56// i) Create and load pArgumentArray to be passed as the stack for the managed call.
57// NOTE: From the time we load the first argument into the stack we cannot cause a GC
58// as the argument array cannot be GC-protected.
59//
60// The second step (Making the managed call), is relatively easy, and is a single call.
61//
62// The third step (unpacking all results), has a couple of passes as well.
63// a) Copy back all resulting values.
64// b) Free all temporary work memory.
65//
66//
67// The most difficult part of doing a func-eval is the first step, since once you
68// have everything set up, unpacking and calling are reverse, gc-safe, operations. Thus,
69// elaboration is needed on the first step.
70//
71// a) Protect all passed in args from a GC. This must be done in a gc-forbid region,
72// and the code path to this function must not trigger a gc either. In this function five
73// parallel arrays are used: pObjectRefArray, pMaybeInteriorPtrArray, pByRefMaybeInteriorPtrArray,
74// pBufferForArgsArray, and pArguments.
75// pObjectRefArray is used to gc-protect all arguments and results that are objects.
76// pMaybeInteriorPtrArray is used to gc-protect all arguments that might be pointers
77// to an interior of a managed object.
78// pByRefMaybeInteriorPtrArray is similar to pMaybeInteriorPtrArray, except that it protects the
79// address of the arguments instead of the arguments themselves. This is needed because we may have
80// by ref arguments whose address is an interior pointer into the GC heap.
81// pBufferForArgsArray is used strictly as a buffer for copying primitives
82// that need to be passed as ByRef, or may be enregistered. This array also holds
83// handles.
84// These first two arrays are mutually exclusive, that is, if there is an entry
85// in one array at index i, there should be no entry in either of the other arrays at
86// the same index.
87// pArguments is used as the complete array of arguments to pass to the managed function.
88//
89// Unfortunately the necessary information to complete pass (a) perfectly may cause a gc, so
90// instead, pass (a) is over-aggressive and protects the following: All object refs into
91// pObjectRefArray, and puts all values that could be raw pointers into pMaybeInteriorPtrArray.
92//
93// b) Discovers the method to be called, and if it is a 'new' allocate an object for the result.
94//
95// c) Gather information about the method that will be called.
96//
97// d) Here we gather information from the method signature which tells which args are
98// ByRef and various other flags. We will use this information in later passes.
99//
100// e) Using the information in pass (c), for each argument: box arguments, placing newly
101// boxed items into pObjectRefArray immediately after creating them.
102//
103// f) Pre-allocate any object for a returned value.
104//
105// g) Using the information is pass (c), all arguments are copied into a scratch buffer before
106// invoking the managed function.
107//
108// h) pArguments is loaded from the pre-allocated return object, the individual elements
109// of the other 3 arrays, and from any non-ByRef literals. This is the complete stack
110// to be passed to the managed function. For performance increase, it can remove any
111// overly aggressive items that were placed in pMaybeInteriorPtrArray.
112//
113
114//
115// IsElementTypeSpecial()
116//
117// This is a simple function used to check if a CorElementType needs special handling for func eval.
118//
119// parameters: type - the CorElementType which we need to check
120//
121// return value: true if the specified type needs special handling
122//
123inline static bool IsElementTypeSpecial(CorElementType type)
124{
125 LIMITED_METHOD_CONTRACT;
126
127 return ((type == ELEMENT_TYPE_CLASS) ||
128 (type == ELEMENT_TYPE_OBJECT) ||
129 (type == ELEMENT_TYPE_ARRAY) ||
130 (type == ELEMENT_TYPE_SZARRAY) ||
131 (type == ELEMENT_TYPE_STRING));
132}
133
134//
135// GetAndSetLiteralValue()
136//
137// This helper function extracts the value out of the source pointer while taking into account alignment and size.
138// Then it stores the value into the destination pointer, again taking into account alignment and size.
139//
140// parameters: pDst - destination pointer
141// dstType - the CorElementType of the destination value
142// pSrc - source pointer
143// srcType - the CorElementType of the source value
144//
145// return value: none
146//
147inline static void GetAndSetLiteralValue(LPVOID pDst, CorElementType dstType, LPVOID pSrc, CorElementType srcType)
148{
149 LIMITED_METHOD_CONTRACT;
150
151 UINT64 srcValue;
152
153 // Retrieve the value using the source CorElementType.
154 switch (g_pEEInterface->GetSizeForCorElementType(srcType))
155 {
156 case 1:
157 srcValue = (UINT64)*((BYTE*)pSrc);
158 break;
159 case 2:
160 srcValue = (UINT64)*((USHORT*)pSrc);
161 break;
162 case 4:
163 srcValue = (UINT64)*((UINT32*)pSrc);
164 break;
165 case 8:
166 srcValue = (UINT64)*((UINT64*)pSrc);
167 break;
168
169 default:
170 UNREACHABLE();
171 }
172
173 // Cast to the appropriate type using the destination CorElementType.
174 switch (dstType)
175 {
176 case ELEMENT_TYPE_BOOLEAN:
177 *(BYTE*)pDst = (BYTE)!!srcValue;
178 break;
179 case ELEMENT_TYPE_I1:
180 *(INT8*)pDst = (INT8)srcValue;
181 break;
182 case ELEMENT_TYPE_U1:
183 *(UINT8*)pDst = (UINT8)srcValue;
184 break;
185 case ELEMENT_TYPE_I2:
186 *(INT16*)pDst = (INT16)srcValue;
187 break;
188 case ELEMENT_TYPE_U2:
189 case ELEMENT_TYPE_CHAR:
190 *(UINT16*)pDst = (UINT16)srcValue;
191 break;
192#if !defined(_WIN64)
193 case ELEMENT_TYPE_I:
194#endif
195 case ELEMENT_TYPE_I4:
196 *(int*)pDst = (int)srcValue;
197 break;
198#if !defined(_WIN64)
199 case ELEMENT_TYPE_U:
200#endif
201 case ELEMENT_TYPE_U4:
202 case ELEMENT_TYPE_R4:
203 *(unsigned*)pDst = (unsigned)srcValue;
204 break;
205#if defined(_WIN64)
206 case ELEMENT_TYPE_I:
207#endif
208 case ELEMENT_TYPE_I8:
209 case ELEMENT_TYPE_R8:
210 *(INT64*)pDst = (INT64)srcValue;
211 break;
212
213#if defined(_WIN64)
214 case ELEMENT_TYPE_U:
215#endif
216 case ELEMENT_TYPE_U8:
217 *(UINT64*)pDst = (UINT64)srcValue;
218 break;
219 case ELEMENT_TYPE_FNPTR:
220 case ELEMENT_TYPE_PTR:
221 *(void **)pDst = (void *)(SIZE_T)srcValue;
222 break;
223
224 default:
225 UNREACHABLE();
226 }
227
228}
229
230
231//
232// Throw on not supported func evals
233//
234static void ValidateFuncEvalReturnType(DebuggerIPCE_FuncEvalType evalType, MethodTable * pMT)
235{
236 CONTRACTL
237 {
238 THROWS;
239 GC_TRIGGERS;
240 }
241 CONTRACTL_END;
242
243 if (pMT == g_pStringClass)
244 {
245 if (evalType == DB_IPCE_FET_NEW_OBJECT || evalType == DB_IPCE_FET_NEW_OBJECT_NC)
246 {
247 // Cannot call New object on String constructor.
248 COMPlusThrow(kArgumentException,W("Argument_CannotCreateString"));
249 }
250 }
251 else if (g_pEEInterface->IsTypedReference(pMT))
252 {
253 // Cannot create typed references through funceval.
254 if (evalType == DB_IPCE_FET_NEW_OBJECT || evalType == DB_IPCE_FET_NEW_OBJECT_NC || evalType == DB_IPCE_FET_NORMAL)
255 {
256 COMPlusThrow(kArgumentException, W("Argument_CannotCreateTypedReference"));
257 }
258 }
259}
260
261//
262// Given a register, return the value.
263//
264static SIZE_T GetRegisterValue(DebuggerEval *pDE, CorDebugRegister reg, void *regAddr, SIZE_T regValue)
265{
266 LIMITED_METHOD_CONTRACT;
267
268 SIZE_T ret = 0;
269
270 // Check whether the register address is the marker value for a register in a non-leaf frame.
271 // This is related to the funceval breaking change.
272 //
273 if (regAddr == CORDB_ADDRESS_TO_PTR(kNonLeafFrameRegAddr))
274 {
275 ret = regValue;
276 }
277 else
278 {
279 switch (reg)
280 {
281 case REGISTER_STACK_POINTER:
282 ret = (SIZE_T)GetSP(&pDE->m_context);
283 break;
284
285 case REGISTER_FRAME_POINTER:
286 ret = (SIZE_T)GetFP(&pDE->m_context);
287 break;
288
289#if defined(_TARGET_X86_)
290 case REGISTER_X86_EAX:
291 ret = pDE->m_context.Eax;
292 break;
293
294 case REGISTER_X86_ECX:
295 ret = pDE->m_context.Ecx;
296 break;
297
298 case REGISTER_X86_EDX:
299 ret = pDE->m_context.Edx;
300 break;
301
302 case REGISTER_X86_EBX:
303 ret = pDE->m_context.Ebx;
304 break;
305
306 case REGISTER_X86_ESI:
307 ret = pDE->m_context.Esi;
308 break;
309
310 case REGISTER_X86_EDI:
311 ret = pDE->m_context.Edi;
312 break;
313
314#elif defined(_TARGET_AMD64_)
315 case REGISTER_AMD64_RAX:
316 ret = pDE->m_context.Rax;
317 break;
318
319 case REGISTER_AMD64_RCX:
320 ret = pDE->m_context.Rcx;
321 break;
322
323 case REGISTER_AMD64_RDX:
324 ret = pDE->m_context.Rdx;
325 break;
326
327 case REGISTER_AMD64_RBX:
328 ret = pDE->m_context.Rbx;
329 break;
330
331 case REGISTER_AMD64_RSI:
332 ret = pDE->m_context.Rsi;
333 break;
334
335 case REGISTER_AMD64_RDI:
336 ret = pDE->m_context.Rdi;
337 break;
338
339 case REGISTER_AMD64_R8:
340 ret = pDE->m_context.R8;
341 break;
342
343 case REGISTER_AMD64_R9:
344 ret = pDE->m_context.R9;
345 break;
346
347 case REGISTER_AMD64_R10:
348 ret = pDE->m_context.R10;
349 break;
350
351 case REGISTER_AMD64_R11:
352 ret = pDE->m_context.R11;
353 break;
354
355 case REGISTER_AMD64_R12:
356 ret = pDE->m_context.R12;
357 break;
358
359 case REGISTER_AMD64_R13:
360 ret = pDE->m_context.R13;
361 break;
362
363 case REGISTER_AMD64_R14:
364 ret = pDE->m_context.R14;
365 break;
366
367 case REGISTER_AMD64_R15:
368 ret = pDE->m_context.R15;
369 break;
370
371 // fall through
372 case REGISTER_AMD64_XMM0:
373 case REGISTER_AMD64_XMM1:
374 case REGISTER_AMD64_XMM2:
375 case REGISTER_AMD64_XMM3:
376 case REGISTER_AMD64_XMM4:
377 case REGISTER_AMD64_XMM5:
378 case REGISTER_AMD64_XMM6:
379 case REGISTER_AMD64_XMM7:
380 case REGISTER_AMD64_XMM8:
381 case REGISTER_AMD64_XMM9:
382 case REGISTER_AMD64_XMM10:
383 case REGISTER_AMD64_XMM11:
384 case REGISTER_AMD64_XMM12:
385 case REGISTER_AMD64_XMM13:
386 case REGISTER_AMD64_XMM14:
387 case REGISTER_AMD64_XMM15:
388 ret = FPSpillToR8(&(pDE->m_context.Xmm0) + (reg - REGISTER_AMD64_XMM0));
389 break;
390
391#endif // !_TARGET_X86_ && !_TARGET_AMD64_
392 default:
393 _ASSERT(!"Invalid register number!");
394
395 }
396 }
397
398 return ret;
399}
400
401//
402// Given a register, set its value.
403//
404static void SetRegisterValue(DebuggerEval *pDE, CorDebugRegister reg, void *regAddr, SIZE_T newValue)
405{
406 CONTRACTL
407 {
408 THROWS;
409 }
410 CONTRACTL_END;
411
412 // Check whether the register address is the marker value for a register in a non-leaf frame.
413 // If so, then we can't update the register. Throw an exception to communicate this error.
414 if (regAddr == CORDB_ADDRESS_TO_PTR(kNonLeafFrameRegAddr))
415 {
416 COMPlusThrowHR(CORDBG_E_FUNC_EVAL_CANNOT_UPDATE_REGISTER_IN_NONLEAF_FRAME);
417 return;
418 }
419 else
420 {
421 switch (reg)
422 {
423 case REGISTER_STACK_POINTER:
424 SetSP(&pDE->m_context, newValue);
425 break;
426
427 case REGISTER_FRAME_POINTER:
428 SetFP(&pDE->m_context, newValue);
429 break;
430
431#ifdef _TARGET_X86_
432 case REGISTER_X86_EAX:
433 pDE->m_context.Eax = newValue;
434 break;
435
436 case REGISTER_X86_ECX:
437 pDE->m_context.Ecx = newValue;
438 break;
439
440 case REGISTER_X86_EDX:
441 pDE->m_context.Edx = newValue;
442 break;
443
444 case REGISTER_X86_EBX:
445 pDE->m_context.Ebx = newValue;
446 break;
447
448 case REGISTER_X86_ESI:
449 pDE->m_context.Esi = newValue;
450 break;
451
452 case REGISTER_X86_EDI:
453 pDE->m_context.Edi = newValue;
454 break;
455
456#elif defined(_TARGET_AMD64_)
457 case REGISTER_AMD64_RAX:
458 pDE->m_context.Rax = newValue;
459 break;
460
461 case REGISTER_AMD64_RCX:
462 pDE->m_context.Rcx = newValue;
463 break;
464
465 case REGISTER_AMD64_RDX:
466 pDE->m_context.Rdx = newValue;
467 break;
468
469 case REGISTER_AMD64_RBX:
470 pDE->m_context.Rbx = newValue;
471 break;
472
473 case REGISTER_AMD64_RSI:
474 pDE->m_context.Rsi = newValue;
475 break;
476
477 case REGISTER_AMD64_RDI:
478 pDE->m_context.Rdi = newValue;
479 break;
480
481 case REGISTER_AMD64_R8:
482 pDE->m_context.R8= newValue;
483 break;
484
485 case REGISTER_AMD64_R9:
486 pDE->m_context.R9= newValue;
487 break;
488
489 case REGISTER_AMD64_R10:
490 pDE->m_context.R10= newValue;
491 break;
492
493 case REGISTER_AMD64_R11:
494 pDE->m_context.R11 = newValue;
495 break;
496
497 case REGISTER_AMD64_R12:
498 pDE->m_context.R12 = newValue;
499 break;
500
501 case REGISTER_AMD64_R13:
502 pDE->m_context.R13 = newValue;
503 break;
504
505 case REGISTER_AMD64_R14:
506 pDE->m_context.R14 = newValue;
507 break;
508
509 case REGISTER_AMD64_R15:
510 pDE->m_context.R15 = newValue;
511 break;
512
513 // fall through
514 case REGISTER_AMD64_XMM0:
515 case REGISTER_AMD64_XMM1:
516 case REGISTER_AMD64_XMM2:
517 case REGISTER_AMD64_XMM3:
518 case REGISTER_AMD64_XMM4:
519 case REGISTER_AMD64_XMM5:
520 case REGISTER_AMD64_XMM6:
521 case REGISTER_AMD64_XMM7:
522 case REGISTER_AMD64_XMM8:
523 case REGISTER_AMD64_XMM9:
524 case REGISTER_AMD64_XMM10:
525 case REGISTER_AMD64_XMM11:
526 case REGISTER_AMD64_XMM12:
527 case REGISTER_AMD64_XMM13:
528 case REGISTER_AMD64_XMM14:
529 case REGISTER_AMD64_XMM15:
530 R8ToFPSpill(&(pDE->m_context.Xmm0) + (reg - REGISTER_AMD64_XMM0), newValue);
531 break;
532
533#endif // !_TARGET_X86_ && !_TARGET_AMD64_
534 default:
535 _ASSERT(!"Invalid register number!");
536
537 }
538 }
539}
540
541
542/*
543 * GetRegsiterValueAndReturnAddress
544 *
545 * This routine takes out a value from a register, or set of registers, into one of
546 * the given buffers (depending on size), and returns a pointer to the filled in
547 * buffer, or NULL on error.
548 *
549 * Parameters:
550 * pDE - pointer to the DebuggerEval object being processed.
551 * pFEAD - Information about this particular argument.
552 * pInt64Buf - pointer to a buffer of type INT64
553 * pSizeTBuf - pointer to a buffer of native size type.
554 *
555 * Returns:
556 * pointer to the filled in buffer, else NULL on error.
557 *
558 */
559static PVOID GetRegisterValueAndReturnAddress(DebuggerEval *pDE,
560 DebuggerIPCE_FuncEvalArgData *pFEAD,
561 INT64 *pInt64Buf,
562 SIZE_T *pSizeTBuf
563 )
564{
565 LIMITED_METHOD_CONTRACT;
566
567 PVOID pAddr;
568
569#if !defined(_WIN64)
570 pAddr = pInt64Buf;
571 DWORD *pLow = (DWORD*)(pInt64Buf);
572 DWORD *pHigh = pLow + 1;
573#endif // _WIN64
574
575 switch (pFEAD->argHome.kind)
576 {
577#if !defined(_WIN64)
578 case RAK_REGREG:
579 *pLow = GetRegisterValue(pDE, pFEAD->argHome.u.reg2, pFEAD->argHome.u.reg2Addr, pFEAD->argHome.u.reg2Value);
580 *pHigh = GetRegisterValue(pDE, pFEAD->argHome.reg1, pFEAD->argHome.reg1Addr, pFEAD->argHome.reg1Value);
581 break;
582
583 case RAK_MEMREG:
584 *pLow = GetRegisterValue(pDE, pFEAD->argHome.reg1, pFEAD->argHome.reg1Addr, pFEAD->argHome.reg1Value);
585 *pHigh = *((DWORD*)CORDB_ADDRESS_TO_PTR(pFEAD->argHome.addr));
586 break;
587
588 case RAK_REGMEM:
589 *pLow = *((DWORD*)CORDB_ADDRESS_TO_PTR(pFEAD->argHome.addr));
590 *pHigh = GetRegisterValue(pDE, pFEAD->argHome.reg1, pFEAD->argHome.reg1Addr, pFEAD->argHome.reg1Value);
591 break;
592#endif // _WIN64
593
594 case RAK_REG:
595 // Simply grab the value out of the proper register.
596 *pSizeTBuf = GetRegisterValue(pDE, pFEAD->argHome.reg1, pFEAD->argHome.reg1Addr, pFEAD->argHome.reg1Value);
597 pAddr = pSizeTBuf;
598 break;
599
600 default:
601 pAddr = NULL;
602 break;
603 }
604
605 return pAddr;
606}
607
608//---------------------------------------------------------------------------------------
609//
610// Clean up any temporary value class variables we have allocated for the funceval.
611//
612// Arguments:
613// pStackStructArray - array whose elements track the location and type of the temporary variables
614//
615
616void CleanUpTemporaryVariables(ValueClassInfo ** ppProtectedValueClasses)
617{
618 while (*ppProtectedValueClasses != NULL)
619 {
620 ValueClassInfo * pValueClassInfo = *ppProtectedValueClasses;
621 *ppProtectedValueClasses = pValueClassInfo->pNext;
622
623 DeleteInteropSafe(reinterpret_cast<BYTE *>(pValueClassInfo));
624 }
625}
626
627
628#ifdef _DEBUG
629
630//
631// Create a parallel array that tracks that we have initialized information in
632// each array.
633//
634#define MAX_DATA_LOCATIONS_TRACKED 100
635
636typedef DWORD DataLocation;
637
638#define DL_NonExistent 0x00
639#define DL_ObjectRefArray 0x01
640#define DL_MaybeInteriorPtrArray 0x02
641#define DL_BufferForArgsArray 0x04
642#define DL_All 0xFF
643
644#endif // _DEBUG
645
646
647/*
648 * GetFuncEvalArgValue
649 *
650 * This routine is used to fill the pArgument array with the appropriate value. This function
651 * uses the three parallel array entries given, and places the correct value, or reference to
652 * the value in pArgument.
653 *
654 * Parameters:
655 * pDE - pointer to the DebuggerEval object being processed.
656 * pFEAD - Information about this particular argument.
657 * isByRef - Is the argument being passed ByRef.
658 * fNeedBoxOrUnbox - Did the argument need boxing or unboxing.
659 * argTH - The type handle for the argument.
660 * byrefArgSigType - The signature type of a parameter that isByRef == true.
661 * pArgument - Location to place the reference or value.
662 * pMaybeInteriorPtrArg - A pointer that contains a value that may be pointers to
663 * the interior of a managed object.
664 * pObjectRefArg - A pointer that contains an object ref. It was built previously.
665 * pBufferArg - A pointer for holding stuff that did not need to be protected.
666 *
667 * Returns:
668 * None.
669 *
670 */
671static void GetFuncEvalArgValue(DebuggerEval *pDE,
672 DebuggerIPCE_FuncEvalArgData *pFEAD,
673 bool isByRef,
674 bool fNeedBoxOrUnbox,
675 TypeHandle argTH,
676 CorElementType byrefArgSigType,
677 TypeHandle byrefArgTH,
678 ARG_SLOT *pArgument,
679 void *pMaybeInteriorPtrArg,
680 OBJECTREF *pObjectRefArg,
681 INT64 *pBufferArg,
682 ValueClassInfo ** ppProtectedValueClasses,
683 CorElementType argSigType
684 DEBUG_ARG(DataLocation dataLocation)
685 )
686{
687 CONTRACTL
688 {
689 THROWS;
690 GC_NOTRIGGER;
691 }
692 CONTRACTL_END;
693
694 _ASSERTE((dataLocation != DL_NonExistent) ||
695 (pFEAD->argElementType == ELEMENT_TYPE_VALUETYPE));
696
697 switch (pFEAD->argElementType)
698 {
699 case ELEMENT_TYPE_I8:
700 case ELEMENT_TYPE_U8:
701 case ELEMENT_TYPE_R8:
702 {
703 INT64 *pSource;
704
705#if defined(_WIN64)
706 _ASSERTE(dataLocation & DL_MaybeInteriorPtrArray);
707
708 pSource = (INT64 *)pMaybeInteriorPtrArg;
709#else // !_WIN64
710 _ASSERTE(dataLocation & DL_BufferForArgsArray);
711
712 pSource = pBufferArg;
713#endif // !_WIN64
714
715 if (!isByRef)
716 {
717 *((INT64*)pArgument) = *pSource;
718 }
719 else
720 {
721 *pArgument = PtrToArgSlot(pSource);
722 }
723 }
724 break;
725
726 case ELEMENT_TYPE_VALUETYPE:
727 {
728 SIZE_T v = 0;
729 LPVOID pAddr = NULL;
730 INT64 bigVal = 0;
731
732 if (pFEAD->argAddr != NULL)
733 {
734 pAddr = *((void **)pMaybeInteriorPtrArg);
735 }
736 else
737 {
738 pAddr = GetRegisterValueAndReturnAddress(pDE, pFEAD, &bigVal, &v);
739
740 if (pAddr == NULL)
741 {
742 COMPlusThrow(kArgumentNullException);
743 }
744 }
745
746
747 _ASSERTE(pAddr);
748
749 if (!fNeedBoxOrUnbox && !isByRef)
750 {
751 _ASSERTE(argTH.GetMethodTable());
752
753 unsigned size = argTH.GetMethodTable()->GetNumInstanceFieldBytes();
754 if (size <= sizeof(ARG_SLOT)
755#if defined(_TARGET_AMD64_)
756 // On AMD64 we pass value types of size which are not powers of 2 by ref.
757 && ((size & (size-1)) == 0)
758#endif // _TARGET_AMD64_
759 )
760 {
761 memcpyNoGCRefs(ArgSlotEndianessFixup(pArgument, sizeof(LPVOID)), pAddr, size);
762 }
763 else
764 {
765 _ASSERTE(pFEAD->argAddr != NULL);
766#if defined(ENREGISTERED_PARAMTYPE_MAXSIZE)
767 if (ArgIterator::IsArgPassedByRef(argTH))
768 {
769 // On X64, by-value value class arguments which are bigger than 8 bytes are passed by reference
770 // according to the native calling convention. The same goes for value class arguments whose size
771 // is smaller than 8 bytes but not a power of 2. To avoid side effets, we need to allocate a
772 // temporary variable and pass that by reference instead. On ARM64, by-value value class
773 // arguments which are bigger than 16 bytes are passed by reference.
774 _ASSERTE(ppProtectedValueClasses != NULL);
775
776 BYTE * pTemp = new (interopsafe) BYTE[ALIGN_UP(sizeof(ValueClassInfo), 8) + size];
777
778 ValueClassInfo * pValueClassInfo = (ValueClassInfo *)pTemp;
779 LPVOID pData = pTemp + ALIGN_UP(sizeof(ValueClassInfo), 8);
780
781 memcpyNoGCRefs(pData, pAddr, size);
782 *pArgument = PtrToArgSlot(pData);
783
784 pValueClassInfo->pData = pData;
785 pValueClassInfo->pMT = argTH.GetMethodTable();
786
787 pValueClassInfo->pNext = *ppProtectedValueClasses;
788 *ppProtectedValueClasses = pValueClassInfo;
789 }
790 else
791#endif // ENREGISTERED_PARAMTYPE_MAXSIZE
792 *pArgument = PtrToArgSlot(pAddr);
793
794 }
795 }
796 else
797 {
798 if (fNeedBoxOrUnbox)
799 {
800 *pArgument = ObjToArgSlot(*pObjectRefArg);
801 }
802 else
803 {
804 if (pFEAD->argAddr)
805 {
806 *pArgument = PtrToArgSlot(pAddr);
807 }
808 else
809 {
810 // The argument is the address of where we're holding the primitive in the PrimitiveArg array. We
811 // stick the real value from the register into the PrimitiveArg array. It should be in a single
812 // register since it is pointer-sized.
813 _ASSERTE( pFEAD->argHome.kind == RAK_REG );
814 *pArgument = PtrToArgSlot(pBufferArg);
815 *pBufferArg = (INT64)v;
816 }
817 }
818 }
819 }
820 break;
821
822 default:
823 // literal values smaller than 8 bytes and "special types" (e.g. object, string, etc.)
824
825 {
826 INT64 *pSource;
827
828 INDEBUG(DataLocation expectedLocation);
829
830#ifdef _TARGET_X86_
831 if ((pFEAD->argElementType == ELEMENT_TYPE_I4) ||
832 (pFEAD->argElementType == ELEMENT_TYPE_U4) ||
833 (pFEAD->argElementType == ELEMENT_TYPE_R4))
834 {
835 INDEBUG(expectedLocation = DL_MaybeInteriorPtrArray);
836
837 pSource = (INT64 *)pMaybeInteriorPtrArg;
838 }
839 else
840#endif
841 if (IsElementTypeSpecial(pFEAD->argElementType))
842 {
843 INDEBUG(expectedLocation = DL_ObjectRefArray);
844
845 pSource = (INT64 *)pObjectRefArg;
846 }
847 else
848 {
849 INDEBUG(expectedLocation = DL_BufferForArgsArray);
850
851 pSource = pBufferArg;
852 }
853
854 if (pFEAD->argAddr != NULL)
855 {
856 if (!isByRef)
857 {
858 if (pFEAD->argIsHandleValue)
859 {
860 _ASSERTE(dataLocation & DL_BufferForArgsArray);
861
862 OBJECTHANDLE oh = *((OBJECTHANDLE*)(pBufferArg)); // Always comes from buffer
863 *pArgument = PtrToArgSlot(g_pEEInterface->GetObjectFromHandle(oh));
864 }
865 else
866 {
867 _ASSERTE(dataLocation & expectedLocation);
868
869 if (pSource != NULL)
870 {
871 *pArgument = *pSource; // may come from either array.
872 }
873 else
874 {
875 *pArgument = NULL;
876 }
877 }
878 }
879 else
880 {
881 if (pFEAD->argIsHandleValue)
882 {
883 _ASSERTE(dataLocation & DL_BufferForArgsArray);
884
885 *pArgument = *pBufferArg; // Buffer contains the object handle, in this case, so
886 // just copy that across.
887 }
888 else
889 {
890 _ASSERTE(dataLocation & expectedLocation);
891
892 *pArgument = PtrToArgSlot(pSource); // Load the argument with the address of our buffer.
893 }
894 }
895 }
896 else if (pFEAD->argIsLiteral)
897 {
898 _ASSERTE(dataLocation & expectedLocation);
899
900 if (!isByRef)
901 {
902 if (pSource != NULL)
903 {
904 *pArgument = *pSource; // may come from either array.
905 }
906 else
907 {
908 *pArgument = NULL;
909 }
910 }
911 else
912 {
913 *pArgument = PtrToArgSlot(pSource); // Load the argument with the address of our buffer.
914 }
915 }
916 else
917 {
918 if (!isByRef)
919 {
920 if (pSource != NULL)
921 {
922 *pArgument = *pSource; // may come from either array.
923 }
924 else
925 {
926 *pArgument = NULL;
927 }
928 }
929 else
930 {
931 *pArgument = PtrToArgSlot(pSource); // Load the argument with the address of our buffer.
932 }
933 }
934
935 // If we need to unbox, then unbox the arg now.
936 if (fNeedBoxOrUnbox)
937 {
938 if (!isByRef)
939 {
940 // function expects valuetype, argument received is class or object
941
942 // Take the ObjectRef off the stack.
943 ARG_SLOT oi1 = *pArgument;
944 OBJECTREF o1 = ArgSlotToObj(oi1);
945
946 // For Nullable types, we need a 'true' nullable to pass to the function, and we do this
947 // by passing a boxed nullable that we unbox. We allocated this space earlier however we
948 // did not know the data location until just now. Fill it in with the data and use that
949 // to pass to the function.
950
951 if (Nullable::IsNullableType(argTH))
952 {
953 _ASSERTE(*pObjectRefArg != 0);
954 _ASSERTE((*pObjectRefArg)->GetMethodTable() == argTH.GetMethodTable());
955 if (o1 != *pObjectRefArg)
956 {
957 Nullable::UnBoxNoCheck((*pObjectRefArg)->GetData(), o1, (*pObjectRefArg)->GetMethodTable());
958 o1 = *pObjectRefArg;
959 }
960 }
961
962 if (o1 == NULL)
963 {
964 COMPlusThrow(kArgumentNullException);
965 }
966
967
968 if (!o1->GetMethodTable()->IsValueType())
969 {
970 COMPlusThrow(kArgumentException, W("Argument_BadObjRef"));
971 }
972
973
974 // Unbox the little fella to get a pointer to the raw data.
975 void *pData = o1->GetData();
976
977 // Get its size to make sure it fits in an ARG_SLOT
978 unsigned size = o1->GetMethodTable()->GetNumInstanceFieldBytes();
979
980 if (size <= sizeof(ARG_SLOT))
981 {
982 // Its not ByRef, so we need to copy the value class onto the ARG_SLOT.
983 CopyValueClassUnchecked(ArgSlotEndianessFixup(pArgument, sizeof(LPVOID)), pData, o1->GetMethodTable());
984 }
985 else
986 {
987 // Store pointer to the space in the ARG_SLOT
988 *pArgument = PtrToArgSlot(pData);
989 }
990 }
991 else
992 {
993 // Function expects byref valuetype, argument received is byref class.
994
995 // Grab the ObjectRef off the stack via the pointer on the stack. Note: the stack has a pointer to the
996 // ObjectRef since the arg was specified as byref.
997 OBJECTREF* op1 = (OBJECTREF*)ArgSlotToPtr(*pArgument);
998 if (op1 == NULL)
999 {
1000 COMPlusThrow(kArgumentNullException);
1001 }
1002 OBJECTREF o1 = *op1;
1003
1004 // For Nullable types, we need a 'true' nullable to pass to the function, and we do this
1005 // by passing a boxed nullable that we unbox. We allocated this space earlier however we
1006 // did not know the data location until just now. Fill it in with the data and use that
1007 // to pass to the function.
1008
1009 if (Nullable::IsNullableType(byrefArgTH))
1010 {
1011 _ASSERTE(*pObjectRefArg != 0 && (*pObjectRefArg)->GetMethodTable() == byrefArgTH.GetMethodTable());
1012 if (o1 != *pObjectRefArg)
1013 {
1014 Nullable::UnBoxNoCheck((*pObjectRefArg)->GetData(), o1, (*pObjectRefArg)->GetMethodTable());
1015 o1 = *pObjectRefArg;
1016 }
1017 }
1018
1019 if (o1 == NULL)
1020 {
1021 COMPlusThrow(kArgumentNullException);
1022 }
1023
1024 _ASSERTE(o1->GetMethodTable()->IsValueType());
1025
1026 // Unbox the little fella to get a pointer to the raw data.
1027 void *pData = o1->GetData();
1028
1029 // If it is ByRef, then we just replace the ObjectRef with a pointer to the data.
1030 *pArgument = PtrToArgSlot(pData);
1031 }
1032 }
1033
1034 // Validate any objectrefs that are supposed to be on the stack.
1035 // <TODO>@TODO: Move this to before the boxing/unboxing above</TODO>
1036 if (!fNeedBoxOrUnbox)
1037 {
1038 Object *objPtr;
1039 if (!isByRef)
1040 {
1041 if (IsElementTypeSpecial(argSigType))
1042 {
1043 // validate the integrity of the object
1044 objPtr = (Object*)ArgSlotToPtr(*pArgument);
1045 if (FAILED(ValidateObject(objPtr)))
1046 {
1047 COMPlusThrow(kArgumentException, W("Argument_BadObjRef"));
1048 }
1049 }
1050 }
1051 else
1052 {
1053 _ASSERTE(argSigType == ELEMENT_TYPE_BYREF);
1054 if (IsElementTypeSpecial(byrefArgSigType))
1055 {
1056 objPtr = *(Object**)(ArgSlotToPtr(*pArgument));
1057 if (FAILED(ValidateObject(objPtr)))
1058 {
1059 COMPlusThrow(kArgumentException, W("Argument_BadObjRef"));
1060 }
1061 }
1062 }
1063 }
1064 }
1065 }
1066}
1067
1068static CorDebugRegister GetArgAddrFromReg( DebuggerIPCE_FuncEvalArgData *pFEAD)
1069{
1070 CorDebugRegister retval = REGISTER_INSTRUCTION_POINTER; // good as default as any
1071#if defined(_WIN64)
1072 retval = (pFEAD->argHome.kind == RAK_REG ?
1073 pFEAD->argHome.reg1 :
1074 (CorDebugRegister)((int)REGISTER_IA64_F0 + pFEAD->argHome.floatIndex));
1075#else // !_WIN64
1076 retval = pFEAD->argHome.reg1;
1077#endif // !_WIN64
1078 return retval;
1079}
1080
1081//
1082// Given info about a byref argument, retrieve the current value from the pBufferForArgsArray,
1083// the pMaybeInteriorPtrArray, the pByRefMaybeInteriorPtrArray, or the pObjectRefArray. Then
1084// place it back into the proper register or address.
1085//
1086// Note that we should never use the argAddr of the DebuggerIPCE_FuncEvalArgData in this function
1087// since the address may be an interior GC pointer and may have been moved by the GC. Instead,
1088// use the pByRefMaybeInteriorPtrArray.
1089//
1090static void SetFuncEvalByRefArgValue(DebuggerEval *pDE,
1091 DebuggerIPCE_FuncEvalArgData *pFEAD,
1092 CorElementType byrefArgSigType,
1093 INT64 bufferByRefArg,
1094 void *maybeInteriorPtrArg,
1095 void *byRefMaybeInteriorPtrArg,
1096 OBJECTREF objectRefByRefArg)
1097{
1098 WRAPPER_NO_CONTRACT;
1099
1100 switch (pFEAD->argElementType)
1101 {
1102 case ELEMENT_TYPE_I8:
1103 case ELEMENT_TYPE_U8:
1104 case ELEMENT_TYPE_R8:
1105 // 64bit values
1106 {
1107 INT64 source;
1108
1109#if defined(_WIN64)
1110 source = (INT64)maybeInteriorPtrArg;
1111#else // !_WIN64
1112 source = bufferByRefArg;
1113#endif // !_WIN64
1114
1115 if (pFEAD->argIsLiteral)
1116 {
1117 // If this was a literal arg, then copy the updated primitive back into the literal.
1118 memcpy(pFEAD->argLiteralData, &source, sizeof(pFEAD->argLiteralData));
1119 }
1120 else if (pFEAD->argAddr != NULL)
1121 {
1122 *((INT64 *)byRefMaybeInteriorPtrArg) = source;
1123 return;
1124 }
1125 else
1126 {
1127#if !defined(_WIN64)
1128 // RAK_REG is the only 4 byte type, all others are 8 byte types.
1129 _ASSERTE(pFEAD->argHome.kind != RAK_REG);
1130
1131 SIZE_T *pLow = (SIZE_T*)(&source);
1132 SIZE_T *pHigh = pLow + 1;
1133
1134 switch (pFEAD->argHome.kind)
1135 {
1136 case RAK_REGREG:
1137 SetRegisterValue(pDE, pFEAD->argHome.u.reg2, pFEAD->argHome.u.reg2Addr, *pLow);
1138 SetRegisterValue(pDE, pFEAD->argHome.reg1, pFEAD->argHome.reg1Addr, *pHigh);
1139 break;
1140
1141 case RAK_MEMREG:
1142 SetRegisterValue(pDE, pFEAD->argHome.reg1, pFEAD->argHome.reg1Addr, *pLow);
1143 *((SIZE_T*)CORDB_ADDRESS_TO_PTR(pFEAD->argHome.addr)) = *pHigh;
1144 break;
1145
1146 case RAK_REGMEM:
1147 *((SIZE_T*)CORDB_ADDRESS_TO_PTR(pFEAD->argHome.addr)) = *pLow;
1148 SetRegisterValue(pDE, pFEAD->argHome.reg1, pFEAD->argHome.reg1Addr, *pHigh);
1149 break;
1150
1151 default:
1152 break;
1153 }
1154#else // _WIN64
1155 // The only types we use are RAK_REG and RAK_FLOAT, and both of them can be 4 or 8 bytes.
1156 _ASSERTE((pFEAD->argHome.kind == RAK_REG) || (pFEAD->argHome.kind == RAK_FLOAT));
1157
1158 SetRegisterValue(pDE, pFEAD->argHome.reg1, pFEAD->argHome.reg1Addr, source);
1159#endif // _WIN64
1160 }
1161 }
1162 break;
1163
1164 default:
1165 // literal values smaller than 8 bytes and "special types" (e.g. object, array, string, etc.)
1166 {
1167 SIZE_T source;
1168
1169#ifdef _TARGET_X86_
1170 if ((pFEAD->argElementType == ELEMENT_TYPE_I4) ||
1171 (pFEAD->argElementType == ELEMENT_TYPE_U4) ||
1172 (pFEAD->argElementType == ELEMENT_TYPE_R4))
1173 {
1174 source = (SIZE_T)maybeInteriorPtrArg;
1175 }
1176 else
1177 {
1178#endif
1179 source = (SIZE_T)bufferByRefArg;
1180#ifdef _TARGET_X86_
1181 }
1182#endif
1183
1184 if (pFEAD->argIsLiteral)
1185 {
1186 // If this was a literal arg, then copy the updated primitive back into the literal.
1187 // The literall buffer is a fixed size (8 bytes), but our source may be 4 or 8 bytes
1188 // depending on the platform. To prevent reading past the end of the source, we
1189 // zero the destination buffer and copy only as many bytes as available.
1190 memset( pFEAD->argLiteralData, 0, sizeof(pFEAD->argLiteralData) );
1191 if (IsElementTypeSpecial(pFEAD->argElementType))
1192 {
1193 _ASSERTE( sizeof(pFEAD->argLiteralData) >= sizeof(objectRefByRefArg) );
1194 memcpy(pFEAD->argLiteralData, &objectRefByRefArg, sizeof(objectRefByRefArg));
1195 }
1196 else
1197 {
1198 _ASSERTE( sizeof(pFEAD->argLiteralData) >= sizeof(source) );
1199 memcpy(pFEAD->argLiteralData, &source, sizeof(source));
1200 }
1201 }
1202 else if (pFEAD->argAddr == NULL)
1203 {
1204 // If the 32bit value is enregistered, copy it back to the proper regs.
1205
1206 // RAK_REG is the only valid 4 byte type on WIN32. On WIN64, both RAK_REG and RAK_FLOAT can be
1207 // 4 bytes or 8 bytes.
1208 _ASSERTE((pFEAD->argHome.kind == RAK_REG)
1209 WIN64_ONLY(|| (pFEAD->argHome.kind == RAK_FLOAT)));
1210
1211 CorDebugRegister regNum = GetArgAddrFromReg(pFEAD);
1212
1213 // Shove the result back into the proper register.
1214 if (IsElementTypeSpecial(pFEAD->argElementType))
1215 {
1216 SetRegisterValue(pDE, regNum, pFEAD->argHome.reg1Addr, (SIZE_T)ObjToArgSlot(objectRefByRefArg));
1217 }
1218 else
1219 {
1220 SetRegisterValue(pDE, regNum, pFEAD->argHome.reg1Addr, (SIZE_T)source);
1221 }
1222 }
1223 else
1224 {
1225 // If the result was an object by ref, then copy back the new location of the object (in GC case).
1226 if (pFEAD->argIsHandleValue)
1227 {
1228 // do nothing. The Handle was passed in the pArgument array directly
1229 }
1230 else if (IsElementTypeSpecial(pFEAD->argElementType))
1231 {
1232 *((SIZE_T*)byRefMaybeInteriorPtrArg) = (SIZE_T)ObjToArgSlot(objectRefByRefArg);
1233 }
1234 else if (pFEAD->argElementType == ELEMENT_TYPE_VALUETYPE)
1235 {
1236 // Do nothing, we passed in the pointer to the valuetype in the pArgument array directly.
1237 }
1238 else
1239 {
1240 GetAndSetLiteralValue(byRefMaybeInteriorPtrArg, pFEAD->argElementType, &source, ELEMENT_TYPE_PTR);
1241 }
1242 }
1243 } // end default
1244 } // end switch
1245}
1246
1247
1248/*
1249 * GCProtectAllPassedArgs
1250 *
1251 * This routine is the first step in doing a func-eval. For a complete overview, see
1252 * the comments at the top of this file.
1253 *
1254 * This routine over-aggressively protects all arguments that may be references to
1255 * managed objects. This function cannot crawl the function signature, since doing
1256 * so may trigger a GC, and thus, we must assume everything is ByRef.
1257 *
1258 * Parameters:
1259 * pDE - pointer to the DebuggerEval object being processed.
1260 * pObjectRefArray - An array that contains any object refs. It was built previously.
1261 * pMaybeInteriorPtrArray - An array that contains values that may be pointers to
1262 * the interior of a managed object.
1263 * pBufferForArgsArray - An array for holding stuff that does not need to be protected.
1264 * Any handle for the 'this' pointer is put in here for pulling it out later.
1265 *
1266 * Returns:
1267 * None.
1268 *
1269 */
1270static void GCProtectAllPassedArgs(DebuggerEval *pDE,
1271 OBJECTREF *pObjectRefArray,
1272 void **pMaybeInteriorPtrArray,
1273 void **pByRefMaybeInteriorPtrArray,
1274 INT64 *pBufferForArgsArray
1275 DEBUG_ARG(DataLocation pDataLocationArray[])
1276 )
1277{
1278 CONTRACTL
1279 {
1280 NOTHROW;
1281 GC_NOTRIGGER;
1282 MODE_COOPERATIVE;
1283 }
1284 CONTRACTL_END;
1285
1286
1287 DebuggerIPCE_FuncEvalArgData *argData = pDE->GetArgData();
1288
1289 unsigned currArgIndex = 0;
1290
1291 //
1292 // Gather all the information for the parameters.
1293 //
1294 for ( ; currArgIndex < pDE->m_argCount; currArgIndex++)
1295 {
1296 DebuggerIPCE_FuncEvalArgData *pFEAD = &argData[currArgIndex];
1297
1298 // In case any of the arguments is a by ref argument and points into the GC heap,
1299 // we need to GC protect their addresses as well.
1300 if (pFEAD->argAddr != NULL)
1301 {
1302 pByRefMaybeInteriorPtrArray[currArgIndex] = pFEAD->argAddr;
1303 }
1304
1305 switch (pFEAD->argElementType)
1306 {
1307 case ELEMENT_TYPE_I8:
1308 case ELEMENT_TYPE_U8:
1309 case ELEMENT_TYPE_R8:
1310 // 64bit values
1311
1312#if defined(_WIN64)
1313 //
1314 // Only need to worry about protecting if a pointer is a 64 bit quantity.
1315 //
1316 _ASSERTE(sizeof(void *) == sizeof(INT64));
1317
1318 if (pFEAD->argAddr != NULL)
1319 {
1320 pMaybeInteriorPtrArray[currArgIndex] = *((void **)(pFEAD->argAddr));
1321#ifdef _DEBUG
1322 if (currArgIndex < MAX_DATA_LOCATIONS_TRACKED)
1323 {
1324 pDataLocationArray[currArgIndex] |= DL_MaybeInteriorPtrArray;
1325 }
1326#endif
1327 }
1328 else if (pFEAD->argIsLiteral)
1329 {
1330 _ASSERTE(sizeof(pFEAD->argLiteralData) >= sizeof(void *));
1331
1332 //
1333 // If this is a byref literal arg, then it maybe an interior ptr.
1334 //
1335 void *v = NULL;
1336 memcpy(&v, pFEAD->argLiteralData, sizeof(v));
1337 pMaybeInteriorPtrArray[currArgIndex] = v;
1338#ifdef _DEBUG
1339 if (currArgIndex < MAX_DATA_LOCATIONS_TRACKED)
1340 {
1341 pDataLocationArray[currArgIndex] |= DL_MaybeInteriorPtrArray;
1342 }
1343#endif
1344 }
1345 else
1346 {
1347 _ASSERTE((pFEAD->argHome.kind == RAK_REG) || (pFEAD->argHome.kind == RAK_FLOAT));
1348
1349
1350 CorDebugRegister regNum = GetArgAddrFromReg(pFEAD);
1351 SIZE_T v = GetRegisterValue(pDE, regNum, pFEAD->argHome.reg1Addr, pFEAD->argHome.reg1Value);
1352 pMaybeInteriorPtrArray[currArgIndex] = (void *)(v);
1353
1354#ifdef _DEBUG
1355 if (currArgIndex < MAX_DATA_LOCATIONS_TRACKED)
1356 {
1357 pDataLocationArray[currArgIndex] |= DL_MaybeInteriorPtrArray;
1358 }
1359#endif
1360 }
1361#endif // _WIN64
1362 break;
1363
1364 case ELEMENT_TYPE_VALUETYPE:
1365 //
1366 // If the value type address could be an interior pointer.
1367 //
1368 if (pFEAD->argAddr != NULL)
1369 {
1370 pMaybeInteriorPtrArray[currArgIndex] = ((void **)(pFEAD->argAddr));
1371 }
1372
1373 INDEBUG(pDataLocationArray[currArgIndex] |= DL_MaybeInteriorPtrArray);
1374 break;
1375
1376 case ELEMENT_TYPE_CLASS:
1377 case ELEMENT_TYPE_OBJECT:
1378 case ELEMENT_TYPE_STRING:
1379 case ELEMENT_TYPE_ARRAY:
1380 case ELEMENT_TYPE_SZARRAY:
1381
1382 if (pFEAD->argAddr != NULL)
1383 {
1384 if (pFEAD->argIsHandleValue)
1385 {
1386 OBJECTHANDLE oh = (OBJECTHANDLE)(pFEAD->argAddr);
1387 pBufferForArgsArray[currArgIndex] = (INT64)(size_t)oh;
1388
1389 INDEBUG(pDataLocationArray[currArgIndex] |= DL_BufferForArgsArray);
1390 }
1391 else
1392 {
1393 pObjectRefArray[currArgIndex] = *((OBJECTREF *)(pFEAD->argAddr));
1394
1395 INDEBUG(pDataLocationArray[currArgIndex] |= DL_ObjectRefArray);
1396 }
1397 }
1398 else if (pFEAD->argIsLiteral)
1399 {
1400 _ASSERTE(sizeof(pFEAD->argLiteralData) >= sizeof(OBJECTREF));
1401 OBJECTREF v = NULL;
1402 memcpy(&v, pFEAD->argLiteralData, sizeof(v));
1403 pObjectRefArray[currArgIndex] = v;
1404#ifdef _DEBUG
1405 if (currArgIndex < MAX_DATA_LOCATIONS_TRACKED)
1406 {
1407 pDataLocationArray[currArgIndex] |= DL_ObjectRefArray;
1408 }
1409#endif
1410 }
1411 else
1412 {
1413 // RAK_REG is the only valid pointer-sized type.
1414 _ASSERTE(pFEAD->argHome.kind == RAK_REG);
1415
1416 // Simply grab the value out of the proper register.
1417 SIZE_T v = GetRegisterValue(pDE, pFEAD->argHome.reg1, pFEAD->argHome.reg1Addr, pFEAD->argHome.reg1Value);
1418
1419 // The argument is the address.
1420 pObjectRefArray[currArgIndex] = (OBJECTREF)v;
1421#ifdef _DEBUG
1422 if (currArgIndex < MAX_DATA_LOCATIONS_TRACKED)
1423 {
1424 pDataLocationArray[currArgIndex] |= DL_ObjectRefArray;
1425 }
1426#endif
1427 }
1428 break;
1429
1430 case ELEMENT_TYPE_I4:
1431 case ELEMENT_TYPE_U4:
1432 case ELEMENT_TYPE_R4:
1433 // 32bit values
1434
1435#ifdef _TARGET_X86_
1436 _ASSERTE(sizeof(void *) == sizeof(INT32));
1437
1438 if (pFEAD->argAddr != NULL)
1439 {
1440 if (pFEAD->argIsHandleValue)
1441 {
1442 //
1443 // Ignorable - no need to protect
1444 //
1445 }
1446 else
1447 {
1448 pMaybeInteriorPtrArray[currArgIndex] = *((void **)(pFEAD->argAddr));
1449#ifdef _DEBUG
1450 if (currArgIndex < MAX_DATA_LOCATIONS_TRACKED)
1451 {
1452 pDataLocationArray[currArgIndex] |= DL_MaybeInteriorPtrArray;
1453 }
1454#endif
1455 }
1456 }
1457 else if (pFEAD->argIsLiteral)
1458 {
1459 _ASSERTE(sizeof(pFEAD->argLiteralData) >= sizeof(INT32));
1460
1461 //
1462 // If this is a byref literal arg, then it maybe an interior ptr.
1463 //
1464 void *v = NULL;
1465 memcpy(&v, pFEAD->argLiteralData, sizeof(v));
1466 pMaybeInteriorPtrArray[currArgIndex] = v;
1467#ifdef _DEBUG
1468 if (currArgIndex < MAX_DATA_LOCATIONS_TRACKED)
1469 {
1470 pDataLocationArray[currArgIndex] |= DL_MaybeInteriorPtrArray;
1471 }
1472#endif
1473 }
1474 else
1475 {
1476 // RAK_REG is the only valid 4 byte type on WIN32.
1477 _ASSERTE(pFEAD->argHome.kind == RAK_REG);
1478
1479 // Simply grab the value out of the proper register.
1480 SIZE_T v = GetRegisterValue(pDE, pFEAD->argHome.reg1, pFEAD->argHome.reg1Addr, pFEAD->argHome.reg1Value);
1481
1482 // The argument is the address.
1483 pMaybeInteriorPtrArray[currArgIndex] = (void *)v;
1484#ifdef _DEBUG
1485 if (currArgIndex < MAX_DATA_LOCATIONS_TRACKED)
1486 {
1487 pDataLocationArray[currArgIndex] |= DL_MaybeInteriorPtrArray;
1488 }
1489#endif
1490 }
1491#endif // _TARGET_X86_
1492
1493 default:
1494 //
1495 // Ignorable - no need to protect
1496 //
1497 break;
1498 }
1499 }
1500}
1501
1502/*
1503 * ResolveFuncEvalGenericArgInfo
1504 *
1505 * This function pulls out any generic args and makes sure the method is loaded for it.
1506 *
1507 * Parameters:
1508 * pDE - pointer to the DebuggerEval object being processed.
1509 *
1510 * Returns:
1511 * None.
1512 *
1513 */
1514void ResolveFuncEvalGenericArgInfo(DebuggerEval *pDE)
1515{
1516 CONTRACTL
1517 {
1518 THROWS;
1519 GC_TRIGGERS;
1520 }
1521 CONTRACTL_END;
1522
1523 DebuggerIPCE_TypeArgData *firstdata = pDE->GetTypeArgData();
1524 unsigned int nGenericArgs = pDE->m_genericArgsCount;
1525 SIZE_T cbAllocSize;
1526 if ((!ClrSafeInt<SIZE_T>::multiply(nGenericArgs, sizeof(TypeHandle *), cbAllocSize)) ||
1527 (cbAllocSize != (size_t)(cbAllocSize)))
1528 {
1529 ThrowHR(COR_E_OVERFLOW);
1530 }
1531 TypeHandle * pGenericArgs = (nGenericArgs == 0) ? NULL : (TypeHandle *) _alloca(cbAllocSize);
1532
1533 //
1534 // Snag the type arguments from the input and get the
1535 // method desc that corresponds to the instantiated desc.
1536 //
1537 Debugger::TypeDataWalk walk(firstdata, pDE->m_genericArgsNodeCount);
1538 walk.ReadTypeHandles(nGenericArgs, pGenericArgs);
1539
1540 // <TODO>better error message</TODO>
1541 if (!walk.Finished())
1542 {
1543 COMPlusThrow(kArgumentException, W("Argument_InvalidGenericArg"));
1544 }
1545
1546 // Find the proper MethodDesc that we need to call.
1547 // Since we're already in the target domain, it can't be unloaded so it's safe to
1548 // use domain specific structures like the Module*.
1549 _ASSERTE( GetAppDomain() == pDE->m_debuggerModule->GetAppDomain() );
1550 pDE->m_md = g_pEEInterface->LoadMethodDef(pDE->m_debuggerModule->GetRuntimeModule(),
1551 pDE->m_methodToken,
1552 nGenericArgs,
1553 pGenericArgs,
1554 &(pDE->m_ownerTypeHandle));
1555
1556
1557 // We better have a MethodDesc at this point.
1558 _ASSERTE(pDE->m_md != NULL);
1559
1560 ValidateFuncEvalReturnType(pDE->m_evalType , pDE->m_md->GetMethodTable());
1561
1562 // If this is a new object operation, then we should have a .ctor.
1563 if ((pDE->m_evalType == DB_IPCE_FET_NEW_OBJECT) && !pDE->m_md->IsCtor())
1564 {
1565 COMPlusThrow(kArgumentException, W("Argument_MissingDefaultConstructor"));
1566 }
1567
1568 pDE->m_md->EnsureActive();
1569
1570 // Run the Class Init for this class, if necessary.
1571 MethodTable * pOwningMT = pDE->m_ownerTypeHandle.GetMethodTable();
1572 pOwningMT->EnsureInstanceActive();
1573 pOwningMT->CheckRunClassInitThrowing();
1574
1575 if (pDE->m_evalType == DB_IPCE_FET_NEW_OBJECT)
1576 {
1577 // Work out the exact type of the allocated object
1578 pDE->m_resultType = (nGenericArgs == 0)
1579 ? TypeHandle(pDE->m_md->GetMethodTable())
1580 : g_pEEInterface->LoadInstantiation(pDE->m_md->GetModule(), pDE->m_md->GetMethodTable()->GetCl(), nGenericArgs, pGenericArgs);
1581 }
1582}
1583
1584
1585/*
1586 * BoxFuncEvalThisParameter
1587 *
1588 * This function is a helper for DoNormalFuncEval. It boxes the 'this' parameter if necessary.
1589 * For example, when a method Object.ToString is called on a value class like System.DateTime
1590 *
1591 * Parameters:
1592 * pDE - pointer to the DebuggerEval object being processed.
1593 * argData - Array of information about the arguments.
1594 * pMaybeInteriorPtrArray - An array that contains values that may be pointers to
1595 * the interior of a managed object.
1596 * pObjectRef - A GC protected place to put a boxed value, if necessary.
1597 *
1598 * Returns:
1599 * None
1600 *
1601 */
1602void BoxFuncEvalThisParameter(DebuggerEval *pDE,
1603 DebuggerIPCE_FuncEvalArgData *argData,
1604 void **pMaybeInteriorPtrArray,
1605 OBJECTREF *pObjectRefArg // out
1606 DEBUG_ARG(DataLocation pDataLocationArray[])
1607 )
1608{
1609 WRAPPER_NO_CONTRACT;
1610
1611 //
1612 // See if we have a value type that is going to be passed as a 'this' pointer.
1613 //
1614 if ((pDE->m_evalType != DB_IPCE_FET_NEW_OBJECT) &&
1615 !pDE->m_md->IsStatic() &&
1616 (pDE->m_argCount > 0))
1617 {
1618 // Allocate the space for box nullables. Nullable parameters need a unboxed
1619 // nullable value to point at, where our current representation does not have
1620 // an unboxed value inside them. Thus we need another buffer to hold it (and
1621 // gcprotects it. We used boxed values for this by converting them to 'true'
1622 // nullable form, calling the function, and in the case of byrefs, converting
1623 // them back afterward.
1624
1625 MethodTable* pMT = pDE->m_md->GetMethodTable();
1626 if (Nullable::IsNullableType(pMT))
1627 {
1628 OBJECTREF obj = AllocateObject(pMT);
1629 if (*pObjectRefArg != NULL)
1630 {
1631 BOOL typesMatch = Nullable::UnBox(obj->GetData(), *pObjectRefArg, pMT);
1632 (void)typesMatch; //prevent "unused variable" error from GCC
1633 _ASSERTE(typesMatch);
1634 }
1635 *pObjectRefArg = obj;
1636 }
1637
1638 if (argData[0].argElementType == ELEMENT_TYPE_VALUETYPE)
1639 {
1640 //
1641 // See if we need to box up the 'this' parameter.
1642 //
1643 if (!pDE->m_md->GetMethodTable()->IsValueType())
1644 {
1645 DebuggerIPCE_FuncEvalArgData *pFEAD = &argData[0];
1646 SIZE_T v;
1647 LPVOID pAddr = NULL;
1648 INT64 bigVal;
1649
1650 {
1651 GCX_FORBID(); //pAddr is unprotected from the time we initialize it
1652
1653 if (pFEAD->argAddr != NULL)
1654 {
1655 _ASSERTE(pDataLocationArray[0] & DL_MaybeInteriorPtrArray);
1656 pAddr = pMaybeInteriorPtrArray[0];
1657 INDEBUG(pDataLocationArray[0] &= ~DL_MaybeInteriorPtrArray);
1658 }
1659 else
1660 {
1661
1662 pAddr = GetRegisterValueAndReturnAddress(pDE, pFEAD, &bigVal, &v);
1663
1664 if (pAddr == NULL)
1665 {
1666 COMPlusThrow(kArgumentNullException);
1667 }
1668 }
1669
1670 _ASSERTE(pAddr != NULL);
1671 } //GCX_FORBID
1672
1673 GCPROTECT_BEGININTERIOR(pAddr); //ReadTypeHandle may trigger a GC and move the object that has the value type at pAddr as a field
1674
1675 //
1676 // Grab the class of this value type. If the type is a parameterized
1677 // struct type then it may not have yet been loaded by the EE (generics
1678 // code sharing may have meant we have never bothered to create the exact
1679 // type yet).
1680 //
1681 // A buffer should have been allocated for the full struct type
1682 _ASSERTE(argData[0].fullArgType != NULL);
1683 Debugger::TypeDataWalk walk((DebuggerIPCE_TypeArgData *) argData[0].fullArgType, argData[0].fullArgTypeNodeCount);
1684
1685 TypeHandle typeHandle = walk.ReadTypeHandle();
1686
1687 if (typeHandle.IsNull())
1688 {
1689 COMPlusThrow(kArgumentException, W("Argument_BadObjRef"));
1690 }
1691 //
1692 // Box up this value type
1693 //
1694 *pObjectRefArg = typeHandle.GetMethodTable()->Box(pAddr);
1695 if (Nullable::IsNullableType(typeHandle.GetMethodTable()) && (*pObjectRefArg == NULL))
1696 {
1697 COMPlusThrow(kArgumentNullException);
1698 }
1699 GCPROTECT_END();
1700
1701 INDEBUG(pDataLocationArray[0] |= DL_ObjectRefArray);
1702 }
1703 }
1704 }
1705}
1706
1707
1708//
1709// This is used to store (temporarily) information about the arguments that func-eval
1710// will pass. It is used only for the args of the function, not the return buffer nor
1711// the 'this' pointer, if there is any of either.
1712//
1713struct FuncEvalArgInfo
1714{
1715 CorElementType argSigType;
1716 CorElementType byrefArgSigType;
1717 TypeHandle byrefArgTypeHandle;
1718 bool fNeedBoxOrUnbox;
1719 TypeHandle sigTypeHandle;
1720};
1721
1722
1723
1724/*
1725 * GatherFuncEvalArgInfo
1726 *
1727 * This function is a helper for DoNormalFuncEval. It gathers together all the information
1728 * necessary to process the arguments.
1729 *
1730 * Parameters:
1731 * pDE - pointer to the DebuggerEval object being processed.
1732 * mSig - The metadata signature of the fuction to call.
1733 * argData - Array of information about the arguments.
1734 * pFEArgInfo - An array of structs to hold the argument information.
1735 *
1736 * Returns:
1737 * None.
1738 *
1739 */
1740void GatherFuncEvalArgInfo(DebuggerEval *pDE,
1741 MetaSig mSig,
1742 DebuggerIPCE_FuncEvalArgData *argData,
1743 FuncEvalArgInfo *pFEArgInfo // out
1744 )
1745{
1746 WRAPPER_NO_CONTRACT;
1747
1748 unsigned currArgIndex = 0;
1749
1750 if ((pDE->m_evalType == DB_IPCE_FET_NORMAL) && !pDE->m_md->IsStatic())
1751 {
1752 //
1753 // Skip over the 'this' arg, since this function is not supposed to mess with it.
1754 //
1755 currArgIndex++;
1756 }
1757
1758 //
1759 // Gather all the information for the parameters.
1760 //
1761 for ( ; currArgIndex < pDE->m_argCount; currArgIndex++)
1762 {
1763 DebuggerIPCE_FuncEvalArgData *pFEAD = &argData[currArgIndex];
1764
1765 //
1766 // Move to the next arg in the signature.
1767 //
1768 CorElementType argSigType = mSig.NextArgNormalized();
1769 _ASSERTE(argSigType != ELEMENT_TYPE_END);
1770
1771 //
1772 // If this arg is a byref arg, then we'll need to know what type we're referencing for later...
1773 //
1774 TypeHandle byrefTypeHandle = TypeHandle();
1775 CorElementType byrefArgSigType = ELEMENT_TYPE_END;
1776 if (argSigType == ELEMENT_TYPE_BYREF)
1777 {
1778 byrefArgSigType = mSig.GetByRefType(&byrefTypeHandle);
1779 }
1780
1781 //
1782 // If the sig says class but we've got a value class parameter, then remember that we need to box it. If
1783 // the sig says value class, but we've got a boxed value class, then remember that we need to unbox it.
1784 //
1785 bool fNeedBoxOrUnbox = ((argSigType == ELEMENT_TYPE_CLASS) && (pFEAD->argElementType == ELEMENT_TYPE_VALUETYPE)) ||
1786 (((argSigType == ELEMENT_TYPE_VALUETYPE) && ((pFEAD->argElementType == ELEMENT_TYPE_CLASS) || (pFEAD->argElementType == ELEMENT_TYPE_OBJECT))) ||
1787 // This is when method signature is expecting a BYREF ValueType, yet we receive the boxed valuetype's handle.
1788 (pFEAD->argElementType == ELEMENT_TYPE_CLASS && argSigType == ELEMENT_TYPE_BYREF && byrefArgSigType == ELEMENT_TYPE_VALUETYPE));
1789
1790 pFEArgInfo[currArgIndex].argSigType = argSigType;
1791 pFEArgInfo[currArgIndex].byrefArgSigType = byrefArgSigType;
1792 pFEArgInfo[currArgIndex].byrefArgTypeHandle = byrefTypeHandle;
1793 pFEArgInfo[currArgIndex].fNeedBoxOrUnbox = fNeedBoxOrUnbox;
1794 pFEArgInfo[currArgIndex].sigTypeHandle = mSig.GetLastTypeHandleThrowing();
1795 }
1796}
1797
1798
1799/*
1800 * BoxFuncEvalArguments
1801 *
1802 * This function is a helper for DoNormalFuncEval. It boxes all the arguments that
1803 * need to be.
1804 *
1805 * Parameters:
1806 * pDE - pointer to the DebuggerEval object being processed.
1807 * argData - Array of information about the arguments.
1808 * pFEArgInfo - An array of structs to hold the argument information.
1809 * pMaybeInteriorPtrArray - An array that contains values that may be pointers to
1810 * the interior of a managed object.
1811 * pObjectRef - A GC protected place to put a boxed value, if necessary.
1812 *
1813 * Returns:
1814 * None
1815 *
1816 */
1817void BoxFuncEvalArguments(DebuggerEval *pDE,
1818 DebuggerIPCE_FuncEvalArgData *argData,
1819 FuncEvalArgInfo *pFEArgInfo,
1820 void **pMaybeInteriorPtrArray,
1821 OBJECTREF *pObjectRef // out
1822 DEBUG_ARG(DataLocation pDataLocationArray[])
1823 )
1824{
1825 WRAPPER_NO_CONTRACT;
1826
1827 unsigned currArgIndex = 0;
1828
1829
1830 if ((pDE->m_evalType == DB_IPCE_FET_NORMAL) && !pDE->m_md->IsStatic())
1831 {
1832 //
1833 // Skip over the 'this' arg, since this function is not supposed to mess with it.
1834 //
1835 currArgIndex++;
1836 }
1837
1838 //
1839 // Gather all the information for the parameters.
1840 //
1841 for ( ; currArgIndex < pDE->m_argCount; currArgIndex++)
1842 {
1843 DebuggerIPCE_FuncEvalArgData *pFEAD = &argData[currArgIndex];
1844
1845 // Allocate the space for box nullables. Nullable parameters need a unboxed
1846 // nullable value to point at, where our current representation does not have
1847 // an unboxed value inside them. Thus we need another buffer to hold it (and
1848 // gcprotects it. We used boxed values for this by converting them to 'true'
1849 // nullable form, calling the function, and in the case of byrefs, converting
1850 // them back afterward.
1851
1852 TypeHandle th = pFEArgInfo[currArgIndex].sigTypeHandle;
1853 if (pFEArgInfo[currArgIndex].argSigType == ELEMENT_TYPE_BYREF)
1854 th = pFEArgInfo[currArgIndex].byrefArgTypeHandle;
1855
1856 if (!th.IsNull() && Nullable::IsNullableType(th))
1857 {
1858
1859 OBJECTREF obj = AllocateObject(th.AsMethodTable());
1860 if (pObjectRef[currArgIndex] != NULL)
1861 {
1862 BOOL typesMatch = Nullable::UnBox(obj->GetData(), pObjectRef[currArgIndex], th.AsMethodTable());
1863 (void)typesMatch; //prevent "unused variable" error from GCC
1864 _ASSERTE(typesMatch);
1865 }
1866 pObjectRef[currArgIndex] = obj;
1867 }
1868
1869 //
1870 // Check if we should box this value now
1871 //
1872 if ((pFEAD->argElementType == ELEMENT_TYPE_VALUETYPE) &&
1873 (pFEArgInfo[currArgIndex].argSigType == ELEMENT_TYPE_BYREF) &&
1874 pFEArgInfo[currArgIndex].fNeedBoxOrUnbox)
1875 {
1876 SIZE_T v;
1877 INT64 bigVal;
1878 LPVOID pAddr = NULL;
1879
1880 if (pFEAD->argAddr != NULL)
1881 {
1882 _ASSERTE(pDataLocationArray[currArgIndex] & DL_MaybeInteriorPtrArray);
1883 pAddr = pMaybeInteriorPtrArray[currArgIndex];
1884 INDEBUG(pDataLocationArray[currArgIndex] &= ~DL_MaybeInteriorPtrArray);
1885 }
1886 else
1887 {
1888
1889 pAddr = GetRegisterValueAndReturnAddress(pDE, pFEAD, &bigVal, &v);
1890
1891 if (pAddr == NULL)
1892 {
1893 COMPlusThrow(kArgumentNullException);
1894 }
1895 }
1896
1897 _ASSERTE(pAddr != NULL);
1898
1899 MethodTable * pMT = pFEArgInfo[currArgIndex].sigTypeHandle.GetMethodTable();
1900
1901 //
1902 // Stuff the newly boxed item into our GC-protected array.
1903 //
1904 pObjectRef[currArgIndex] = pMT->Box(pAddr);
1905
1906#ifdef _DEBUG
1907 if (currArgIndex < MAX_DATA_LOCATIONS_TRACKED)
1908 {
1909 pDataLocationArray[currArgIndex] |= DL_ObjectRefArray;
1910 }
1911#endif
1912 }
1913 }
1914}
1915
1916
1917/*
1918 * GatherFuncEvalMethodInfo
1919 *
1920 * This function is a helper for DoNormalFuncEval. It gathers together all the information
1921 * necessary to process the method
1922 *
1923 * Parameters:
1924 * pDE - pointer to the DebuggerEval object being processed.
1925 * mSig - The metadata signature of the fuction to call.
1926 * argData - Array of information about the arguments.
1927 * ppUnboxedMD - Returns a resolve method desc if the original is an unboxing stub.
1928 * pObjectRefArray - GC protected array of objects passed to this func-eval call.
1929 * used to resolve down to the method target for generics.
1930 * pBufferForArgsArray - Array of values not needing gc-protection. May hold the
1931 * handle for the method targer for generics.
1932 * pfHasRetBuffArg - TRUE if the function has a return buffer.
1933 * pRetValueType - The TypeHandle of the return value.
1934 *
1935 *
1936 * Returns:
1937 * None.
1938 *
1939 */
1940void GatherFuncEvalMethodInfo(DebuggerEval *pDE,
1941 MetaSig mSig,
1942 DebuggerIPCE_FuncEvalArgData *argData,
1943 MethodDesc **ppUnboxedMD,
1944 OBJECTREF *pObjectRefArray,
1945 INT64 *pBufferForArgsArray,
1946 BOOL *pfHasRetBuffArg, // out
1947 BOOL *pfHasNonStdByValReturn, // out
1948 TypeHandle *pRetValueType // out, only if fHasRetBuffArg == true
1949 DEBUG_ARG(DataLocation pDataLocationArray[])
1950 )
1951{
1952 WRAPPER_NO_CONTRACT;
1953
1954 //
1955 // If 'this' is a non-static function that points to an unboxing stub, we need to return the
1956 // unboxed method desc to really call.
1957 //
1958 if ((pDE->m_evalType != DB_IPCE_FET_NEW_OBJECT) && !pDE->m_md->IsStatic() && pDE->m_md->IsUnboxingStub())
1959 {
1960 *ppUnboxedMD = pDE->m_md->GetMethodTable()->GetUnboxedEntryPointMD(pDE->m_md);
1961 }
1962
1963 //
1964 // Resolve down to the method on the class of the 'this' parameter.
1965 //
1966 if ((pDE->m_evalType != DB_IPCE_FET_NEW_OBJECT) && pDE->m_md->IsVtableMethod())
1967 {
1968 //
1969 // Assuming that a constructor can't be an interface method...
1970 //
1971 _ASSERTE(pDE->m_evalType == DB_IPCE_FET_NORMAL);
1972
1973 //
1974 // We need to go grab the 'this' argument to figure out what class we're headed for...
1975 //
1976 if (pDE->m_argCount == 0)
1977 {
1978 COMPlusThrow(kArgumentException, W("Argument_BadObjRef"));
1979 }
1980
1981 //
1982 // We should have a valid this pointer.
1983 // <TODO>@todo: But the check should cover the register kind as well!</TODO>
1984 //
1985 if ((argData[0].argHome.kind == RAK_NONE) && (argData[0].argAddr == NULL))
1986 {
1987 COMPlusThrow(kArgumentNullException);
1988 }
1989
1990 //
1991 // Assume we can only have this for real objects or boxed value types, not value classes...
1992 //
1993 _ASSERTE((argData[0].argElementType == ELEMENT_TYPE_OBJECT) ||
1994 (argData[0].argElementType == ELEMENT_TYPE_STRING) ||
1995 (argData[0].argElementType == ELEMENT_TYPE_CLASS) ||
1996 (argData[0].argElementType == ELEMENT_TYPE_ARRAY) ||
1997 (argData[0].argElementType == ELEMENT_TYPE_SZARRAY) ||
1998 ((argData[0].argElementType == ELEMENT_TYPE_VALUETYPE) &&
1999 (pObjectRefArray[0] != NULL)));
2000
2001 //
2002 // Now get the object pointer to our first arg.
2003 //
2004 OBJECTREF objRef = NULL;
2005 GCPROTECT_BEGIN(objRef);
2006
2007 if (argData[0].argElementType == ELEMENT_TYPE_VALUETYPE)
2008 {
2009 //
2010 // In this case, we know where it is.
2011 //
2012 objRef = pObjectRefArray[0];
2013 _ASSERTE(pDataLocationArray[0] & DL_ObjectRefArray);
2014 }
2015 else
2016 {
2017 TypeHandle dummyTH;
2018 ARG_SLOT objSlot;
2019
2020 //
2021 // Take out the first arg. We're gonna trick GetFuncEvalArgValue by passing in just our
2022 // object ref as the stack.
2023 //
2024 // Note that we are passing ELEMENT_TYPE_END in the last parameter because we want to
2025 // supress the the valid object ref check.
2026 //
2027 GetFuncEvalArgValue(pDE,
2028 &(argData[0]),
2029 false,
2030 false,
2031 dummyTH,
2032 ELEMENT_TYPE_CLASS,
2033 dummyTH,
2034 &objSlot,
2035 NULL,
2036 pObjectRefArray,
2037 pBufferForArgsArray,
2038 NULL,
2039 ELEMENT_TYPE_END
2040 DEBUG_ARG(pDataLocationArray[0])
2041 );
2042
2043 objRef = ArgSlotToObj(objSlot);
2044 }
2045
2046 //
2047 // Validate the object
2048 //
2049 if (FAILED(ValidateObject(OBJECTREFToObject(objRef))))
2050 {
2051 COMPlusThrow(kArgumentException, W("Argument_BadObjRef"));
2052 }
2053
2054 //
2055 // Null isn't valid in this case!
2056 //
2057 if (objRef == NULL)
2058 {
2059 COMPlusThrow(kArgumentNullException);
2060 }
2061
2062 //
2063 // Make sure that the object supplied is of a type that can call the method supplied.
2064 //
2065 if (!g_pEEInterface->ObjIsInstanceOf(OBJECTREFToObject(objRef), pDE->m_ownerTypeHandle))
2066 {
2067 COMPlusThrow(kArgumentException, W("Argument_CORDBBadMethod"));
2068 }
2069
2070 //
2071 // Now, find the proper MethodDesc for this interface method based on the object we're invoking the
2072 // method on.
2073 //
2074 pDE->m_targetCodeAddr = pDE->m_md->GetCallTarget(&objRef, pDE->m_ownerTypeHandle);
2075
2076 GCPROTECT_END();
2077 }
2078 else
2079 {
2080 pDE->m_targetCodeAddr = pDE->m_md->GetCallTarget(NULL, pDE->m_ownerTypeHandle);
2081 }
2082
2083 //
2084 // Get the resulting type now. Doing this may trigger a GC or throw.
2085 //
2086 if (pDE->m_evalType != DB_IPCE_FET_NEW_OBJECT)
2087 {
2088 pDE->m_resultType = mSig.GetRetTypeHandleThrowing();
2089 }
2090
2091 //
2092 // Check if there is an explicit return argument, or if the return type is really a VALUETYPE but our
2093 // calling convention is passing it in registers. We just need to remember the pretValueClass so
2094 // that we will box it properly on our way out.
2095 //
2096 {
2097 ArgIterator argit(&mSig);
2098 *pfHasRetBuffArg = argit.HasRetBuffArg();
2099 *pfHasNonStdByValReturn = argit.HasNonStandardByvalReturn();
2100 }
2101
2102 CorElementType retType = mSig.GetReturnType();
2103 CorElementType retTypeNormalized = mSig.GetReturnTypeNormalized();
2104
2105
2106 if (*pfHasRetBuffArg || *pfHasNonStdByValReturn
2107 || ((retType == ELEMENT_TYPE_VALUETYPE) && (retType != retTypeNormalized)))
2108 {
2109 *pRetValueType = mSig.GetRetTypeHandleThrowing();
2110 }
2111 else
2112 {
2113 //
2114 // Make sure the caller initialized this value
2115 //
2116 _ASSERTE((*pRetValueType).IsNull());
2117 }
2118}
2119
2120/*
2121 * CopyArgsToBuffer
2122 *
2123 * This routine copies all the arguments to a local buffer, so that any one that needs to be
2124 * passed can be. Note that this local buffer is NOT GC-protected, and so all the values
2125 * in the buffer may not be relied on. You *must* use GetFuncEvalArgValue() to load up the
2126 * Arguments for the call, because it has the logic to decide which of the parallel arrays to pull
2127 * from.
2128 *
2129 * Parameters:
2130 * pDE - pointer to the DebuggerEval object being processed.
2131 * argData - Array of information about the arguments.
2132 * pFEArgInfo - An array of structs to hold the argument information. Must have be previously filled in.
2133 * pBufferArray - An array to store values.
2134 *
2135 * Returns:
2136 * None.
2137 *
2138 */
2139void CopyArgsToBuffer(DebuggerEval *pDE,
2140 DebuggerIPCE_FuncEvalArgData *argData,
2141 FuncEvalArgInfo *pFEArgInfo,
2142 INT64 *pBufferArray
2143 DEBUG_ARG(DataLocation pDataLocationArray[])
2144 )
2145{
2146 CONTRACTL
2147 {
2148 THROWS;
2149 GC_NOTRIGGER;
2150 }
2151 CONTRACTL_END;
2152
2153 unsigned currArgIndex = 0;
2154
2155
2156 if ((pDE->m_evalType == DB_IPCE_FET_NORMAL) && !pDE->m_md->IsStatic())
2157 {
2158 //
2159 // Skip over the 'this' arg, since this function is not supposed to mess with it.
2160 //
2161 currArgIndex++;
2162 }
2163
2164 //
2165 // Spin thru each argument now
2166 //
2167 for ( ; currArgIndex < pDE->m_argCount; currArgIndex++)
2168 {
2169 DebuggerIPCE_FuncEvalArgData *pFEAD = &argData[currArgIndex];
2170 BOOL isByRef = (pFEArgInfo[currArgIndex].argSigType == ELEMENT_TYPE_BYREF);
2171 BOOL fNeedBoxOrUnbox;
2172 fNeedBoxOrUnbox = pFEArgInfo[currArgIndex].fNeedBoxOrUnbox;
2173
2174
2175 LOG((LF_CORDB, LL_EVERYTHING, "CATB: currArgIndex=%d\n",
2176 currArgIndex));
2177 LOG((LF_CORDB, LL_EVERYTHING,
2178 "\t: argSigType=0x%x, byrefArgSigType=0x%0x, inType=0x%0x\n",
2179 pFEArgInfo[currArgIndex].argSigType,
2180 pFEArgInfo[currArgIndex].byrefArgSigType,
2181 pFEAD->argElementType));
2182
2183 INT64 *pDest = &(pBufferArray[currArgIndex]);
2184
2185 switch (pFEAD->argElementType)
2186 {
2187 case ELEMENT_TYPE_I8:
2188 case ELEMENT_TYPE_U8:
2189 case ELEMENT_TYPE_R8:
2190
2191 if (pFEAD->argAddr != NULL)
2192 {
2193 *pDest = *(INT64*)(pFEAD->argAddr);
2194#ifdef _DEBUG
2195 if (currArgIndex < MAX_DATA_LOCATIONS_TRACKED)
2196 {
2197 pDataLocationArray[currArgIndex] |= DL_BufferForArgsArray;
2198 }
2199#endif
2200 }
2201 else if (pFEAD->argIsLiteral)
2202 {
2203 _ASSERTE(sizeof(pFEAD->argLiteralData) >= sizeof(void *));
2204
2205 // If this is a literal arg, then we just copy the data.
2206 memcpy(pDest, pFEAD->argLiteralData, sizeof(INT64));
2207#ifdef _DEBUG
2208 if (currArgIndex < MAX_DATA_LOCATIONS_TRACKED)
2209 {
2210 pDataLocationArray[currArgIndex] |= DL_BufferForArgsArray;
2211 }
2212#endif
2213 }
2214 else
2215 {
2216
2217#if !defined(_WIN64)
2218 // RAK_REG is the only 4 byte type, all others are 8 byte types.
2219 _ASSERTE(pFEAD->argHome.kind != RAK_REG);
2220
2221 INT64 bigVal = 0;
2222 SIZE_T v;
2223 INT64 *pAddr;
2224
2225 pAddr = (INT64*)GetRegisterValueAndReturnAddress(pDE, pFEAD, &bigVal, &v);
2226
2227 if (pAddr == NULL)
2228 {
2229 COMPlusThrow(kArgumentNullException);
2230 }
2231
2232 *pDest = *pAddr;
2233
2234#else // _WIN64
2235 // Both RAK_REG and RAK_FLOAT can be either 4 bytes or 8 bytes.
2236 _ASSERTE((pFEAD->argHome.kind == RAK_REG) || (pFEAD->argHome.kind == RAK_FLOAT));
2237
2238 CorDebugRegister regNum = GetArgAddrFromReg(pFEAD);
2239 *pDest = GetRegisterValue(pDE, regNum, pFEAD->argHome.reg1Addr, pFEAD->argHome.reg1Value);
2240#endif // _WIN64
2241
2242
2243
2244#ifdef _DEBUG
2245 if (currArgIndex < MAX_DATA_LOCATIONS_TRACKED)
2246 {
2247 pDataLocationArray[currArgIndex] |= DL_BufferForArgsArray;
2248 }
2249#endif
2250 }
2251 break;
2252
2253 case ELEMENT_TYPE_VALUETYPE:
2254
2255 //
2256 // For value types, we dont do anything here, instead delay until GetFuncEvalArgInfo
2257 //
2258 break;
2259
2260 case ELEMENT_TYPE_CLASS:
2261 case ELEMENT_TYPE_OBJECT:
2262 case ELEMENT_TYPE_STRING:
2263 case ELEMENT_TYPE_ARRAY:
2264 case ELEMENT_TYPE_SZARRAY:
2265
2266 if (pFEAD->argAddr != NULL)
2267 {
2268 if (!isByRef)
2269 {
2270 if (pFEAD->argIsHandleValue)
2271 {
2272 OBJECTHANDLE oh = (OBJECTHANDLE)(pFEAD->argAddr);
2273 *pDest = (INT64)(size_t)oh;
2274 }
2275 else
2276 {
2277 *pDest = *((SIZE_T*)(pFEAD->argAddr));
2278 }
2279#ifdef _DEBUG
2280 if (currArgIndex < MAX_DATA_LOCATIONS_TRACKED)
2281 {
2282 pDataLocationArray[currArgIndex] |= DL_BufferForArgsArray;
2283 }
2284#endif
2285 }
2286 else
2287 {
2288 if (pFEAD->argIsHandleValue)
2289 {
2290 *pDest = (INT64)(size_t)(pFEAD->argAddr);
2291 }
2292 else
2293 {
2294 *pDest = *(SIZE_T*)(pFEAD->argAddr);
2295 }
2296#ifdef _DEBUG
2297 if (currArgIndex < MAX_DATA_LOCATIONS_TRACKED)
2298 {
2299 pDataLocationArray[currArgIndex] |= DL_BufferForArgsArray;
2300 }
2301#endif
2302 }
2303 }
2304 else if (pFEAD->argIsLiteral)
2305 {
2306 _ASSERTE(sizeof(pFEAD->argLiteralData) >= sizeof(INT64));
2307
2308 // The called function may expect a larger/smaller value than the literal value.
2309 // So we convert the value to the right type.
2310
2311 CONSISTENCY_CHECK_MSGF(((pFEArgInfo[currArgIndex].argSigType == ELEMENT_TYPE_CLASS) ||
2312 (pFEArgInfo[currArgIndex].argSigType == ELEMENT_TYPE_SZARRAY) ||
2313 (pFEArgInfo[currArgIndex].argSigType == ELEMENT_TYPE_ARRAY)) ||
2314 (isByRef && ((pFEArgInfo[currArgIndex].byrefArgSigType == ELEMENT_TYPE_CLASS) ||
2315 (pFEArgInfo[currArgIndex].byrefArgSigType == ELEMENT_TYPE_SZARRAY) ||
2316 (pFEArgInfo[currArgIndex].byrefArgSigType == ELEMENT_TYPE_ARRAY))),
2317 ("argSigType=0x%0x, byrefArgSigType=0x%0x, isByRef=%d",
2318 pFEArgInfo[currArgIndex].argSigType,
2319 pFEArgInfo[currArgIndex].byrefArgSigType,
2320 isByRef));
2321
2322 LOG((LF_CORDB, LL_EVERYTHING,
2323 "argSigType=0x%0x, byrefArgSigType=0x%0x, isByRef=%d\n",
2324 pFEArgInfo[currArgIndex].argSigType, pFEArgInfo[currArgIndex].byrefArgSigType, isByRef));
2325
2326 *(SIZE_T*)pDest = *(SIZE_T*)pFEAD->argLiteralData;
2327#ifdef _DEBUG
2328 if (currArgIndex < MAX_DATA_LOCATIONS_TRACKED)
2329 {
2330 pDataLocationArray[currArgIndex] |= DL_BufferForArgsArray;
2331 }
2332#endif
2333 }
2334 else
2335 {
2336 // RAK_REG is the only valid 4 byte type on WIN32. On WIN64, RAK_REG and RAK_FLOAT
2337 // can both be either 4 bytes or 8 bytes;
2338 _ASSERTE((pFEAD->argHome.kind == RAK_REG)
2339 WIN64_ONLY(|| (pFEAD->argHome.kind == RAK_FLOAT)));
2340
2341 CorDebugRegister regNum = GetArgAddrFromReg(pFEAD);
2342
2343 // Simply grab the value out of the proper register.
2344 SIZE_T v = GetRegisterValue(pDE, regNum, pFEAD->argHome.reg1Addr, pFEAD->argHome.reg1Value);
2345 *pDest = v;
2346#ifdef _DEBUG
2347 if (currArgIndex < MAX_DATA_LOCATIONS_TRACKED)
2348 {
2349 pDataLocationArray[currArgIndex] |= DL_BufferForArgsArray;
2350 }
2351#endif
2352 }
2353 break;
2354
2355 default:
2356 // 4-byte, 2-byte, or 1-byte values
2357
2358 if (pFEAD->argAddr != NULL)
2359 {
2360 if (!isByRef)
2361 {
2362 if (pFEAD->argIsHandleValue)
2363 {
2364 OBJECTHANDLE oh = (OBJECTHANDLE)(pFEAD->argAddr);
2365 *pDest = (INT64)(size_t)oh;
2366 }
2367 else
2368 {
2369 GetAndSetLiteralValue(pDest, pFEArgInfo[currArgIndex].argSigType,
2370 pFEAD->argAddr, pFEAD->argElementType);
2371 }
2372#ifdef _DEBUG
2373 if (currArgIndex < MAX_DATA_LOCATIONS_TRACKED)
2374 {
2375 pDataLocationArray[currArgIndex] |= DL_BufferForArgsArray;
2376 }
2377#endif
2378 }
2379 else
2380 {
2381 if (pFEAD->argIsHandleValue)
2382 {
2383 *pDest = (INT64)(size_t)(pFEAD->argAddr);
2384 }
2385 else
2386 {
2387 // We have to make sure we only grab the correct size of memory from the source. On IA64, we
2388 // have to make sure we don't cause misaligned data exceptions as well. Then we put the value
2389 // into the pBufferArray. The reason is that we may be passing in some values by ref to a
2390 // function that's expecting something of a bigger size. Thus, if we don't do this, then we'll
2391 // be bashing memory right next to the source value as the function being called acts upon some
2392 // bigger value.
2393 GetAndSetLiteralValue(pDest, pFEArgInfo[currArgIndex].byrefArgSigType,
2394 pFEAD->argAddr, pFEAD->argElementType);
2395 }
2396#ifdef _DEBUG
2397 if (currArgIndex < MAX_DATA_LOCATIONS_TRACKED)
2398 {
2399 pDataLocationArray[currArgIndex] |= DL_BufferForArgsArray;
2400 }
2401#endif
2402 }
2403 }
2404 else if (pFEAD->argIsLiteral)
2405 {
2406 _ASSERTE(sizeof(pFEAD->argLiteralData) >= sizeof(INT32));
2407
2408 // The called function may expect a larger/smaller value than the literal value,
2409 // so we convert the value to the right type.
2410
2411 CONSISTENCY_CHECK_MSGF(
2412 ((pFEArgInfo[currArgIndex].argSigType>=ELEMENT_TYPE_BOOLEAN) && (pFEArgInfo[currArgIndex].argSigType<=ELEMENT_TYPE_R8)) ||
2413 (pFEArgInfo[currArgIndex].argSigType == ELEMENT_TYPE_PTR) ||
2414 (pFEArgInfo[currArgIndex].argSigType == ELEMENT_TYPE_I) ||
2415 (pFEArgInfo[currArgIndex].argSigType == ELEMENT_TYPE_U) ||
2416 (isByRef && ((pFEArgInfo[currArgIndex].byrefArgSigType>=ELEMENT_TYPE_BOOLEAN) && (pFEArgInfo[currArgIndex].byrefArgSigType<=ELEMENT_TYPE_R8))),
2417 ("argSigType=0x%0x, byrefArgSigType=0x%0x, isByRef=%d", pFEArgInfo[currArgIndex].argSigType, pFEArgInfo[currArgIndex].byrefArgSigType, isByRef));
2418
2419 LOG((LF_CORDB, LL_EVERYTHING,
2420 "argSigType=0x%0x, byrefArgSigType=0x%0x, isByRef=%d\n",
2421 pFEArgInfo[currArgIndex].argSigType,
2422 pFEArgInfo[currArgIndex].byrefArgSigType,
2423 isByRef));
2424
2425 CorElementType relevantType = (isByRef ? pFEArgInfo[currArgIndex].byrefArgSigType : pFEArgInfo[currArgIndex].argSigType);
2426
2427 GetAndSetLiteralValue(pDest, relevantType, pFEAD->argLiteralData, pFEAD->argElementType);
2428#ifdef _DEBUG
2429 if (currArgIndex < MAX_DATA_LOCATIONS_TRACKED)
2430 {
2431 pDataLocationArray[currArgIndex] |= DL_BufferForArgsArray;
2432 }
2433#endif
2434 }
2435 else
2436 {
2437 // RAK_REG is the only valid 4 byte type on WIN32. On WIN64, RAK_REG and RAK_FLOAT
2438 // can both be either 4 bytes or 8 bytes;
2439 _ASSERTE((pFEAD->argHome.kind == RAK_REG)
2440 WIN64_ONLY(|| (pFEAD->argHome.kind == RAK_FLOAT)));
2441
2442 CorDebugRegister regNum = GetArgAddrFromReg(pFEAD);
2443
2444 // Simply grab the value out of the proper register.
2445 SIZE_T v = GetRegisterValue(pDE, regNum, pFEAD->argHome.reg1Addr, pFEAD->argHome.reg1Value);
2446 *pDest = v;
2447#ifdef _DEBUG
2448 if (currArgIndex < MAX_DATA_LOCATIONS_TRACKED)
2449 {
2450 pDataLocationArray[currArgIndex] |= DL_BufferForArgsArray;
2451 }
2452#endif
2453 }
2454 }
2455 }
2456}
2457
2458
2459/*
2460 * PackArgumentArray
2461 *
2462 * This routine fills a given array with the correct values for passing to a managed function.
2463 * It uses various component arrays that contain information to correctly create the argument array.
2464 *
2465 * Parameters:
2466 * pDE - pointer to the DebuggerEval object being processed.
2467 * argData - Array of information about the arguments.
2468 * pUnboxedMD - MethodDesc of the function to call, after unboxing.
2469 * RetValueType - Type Handle of the return value of the managed function we will call.
2470 * pFEArgInfo - An array of structs to hold the argument information. Must have be previously filled in.
2471 * pObjectRefArray - An array that contains any object refs. It was built previously.
2472 * pMaybeInteriorPtrArray - An array that contains values that may be pointers to
2473 * the interior of a managed object.
2474 * pBufferForArgsArray - An array that contains values that need writable memory space
2475 * for passing ByRef.
2476 * newObj - Pre-allocated object for a 'new' call.
2477 * pArguments - This array is packed from the above arrays.
2478 * ppRetValue - Return value buffer if fRetValueArg is TRUE
2479 *
2480 * Returns:
2481 * None.
2482 *
2483 */
2484void PackArgumentArray(DebuggerEval *pDE,
2485 DebuggerIPCE_FuncEvalArgData *argData,
2486 FuncEvalArgInfo *pFEArgInfo,
2487 MethodDesc *pUnboxedMD,
2488 TypeHandle RetValueType,
2489 OBJECTREF *pObjectRefArray,
2490 void **pMaybeInteriorPtrArray,
2491 INT64 *pBufferForArgsArray,
2492 ValueClassInfo ** ppProtectedValueClasses,
2493 OBJECTREF newObj,
2494 BOOL fRetValueArg,
2495 ARG_SLOT *pArguments,
2496 PVOID * ppRetValue
2497 DEBUG_ARG(DataLocation pDataLocationArray[])
2498 )
2499{
2500 WRAPPER_NO_CONTRACT;
2501
2502 GCX_FORBID();
2503
2504 unsigned currArgIndex = 0;
2505 unsigned currArgSlot = 0;
2506
2507
2508 //
2509 // THIS POINTER (if any)
2510 // For non-static methods, or when returning a new object,
2511 // the first arg in the array is 'this' or the new object.
2512 //
2513 if (pDE->m_evalType == DB_IPCE_FET_NEW_OBJECT)
2514 {
2515 //
2516 // If this is a new object op, then we need to fill in the 0'th
2517 // arg slot with the 'this' ptr.
2518 //
2519 pArguments[0] = ObjToArgSlot(newObj);
2520
2521 //
2522 // If we are invoking a function on a value class, but we have a boxed value class for 'this',
2523 // then go ahead and unbox it and leave a ref to the value class on the stack as 'this'.
2524 //
2525 if (pDE->m_md->GetMethodTable()->IsValueType())
2526 {
2527 _ASSERTE(newObj->GetMethodTable()->IsValueType());
2528
2529 // This is one of those places we use true boxed nullables
2530 _ASSERTE(!Nullable::IsNullableType(pDE->m_md->GetMethodTable()) ||
2531 newObj->GetMethodTable() == pDE->m_md->GetMethodTable());
2532 void *pData = newObj->GetData();
2533 pArguments[0] = PtrToArgSlot(pData);
2534 }
2535
2536 //
2537 // Bump up the arg slot
2538 //
2539 currArgSlot++;
2540 }
2541 else if (!pDE->m_md->IsStatic())
2542 {
2543 //
2544 // Place 'this' first in the array for non-static methods.
2545 //
2546 TypeHandle dummyTH;
2547 bool isByRef = false;
2548 bool fNeedBoxOrUnbox = false;
2549
2550 // We had better have an object for a 'this' argument!
2551 CorElementType et = argData[0].argElementType;
2552
2553 if (!(IsElementTypeSpecial(et) ||
2554 et == ELEMENT_TYPE_VALUETYPE))
2555 {
2556 COMPlusThrow(kArgumentOutOfRangeException, W("ArgumentOutOfRange_Enum"));
2557 }
2558
2559 LOG((LF_CORDB, LL_EVERYTHING, "this: currArgSlot=%d, currArgIndex=%d et=0x%x\n", currArgSlot, currArgIndex, et));
2560
2561 if (pDE->m_md->GetMethodTable()->IsValueType())
2562 {
2563 // For value classes, the 'this' parameter is always passed by reference.
2564 // However do not unbox if we are calling an unboxing stub.
2565 if (pDE->m_md == pUnboxedMD)
2566 {
2567 // pDE->m_md is expecting an unboxed this pointer. Then we will unbox it.
2568 isByRef = true;
2569
2570 // Remember if we need to unbox this parameter, though.
2571 if ((et == ELEMENT_TYPE_CLASS) || (et == ELEMENT_TYPE_OBJECT))
2572 {
2573 fNeedBoxOrUnbox = true;
2574 }
2575 }
2576 }
2577 else if (et == ELEMENT_TYPE_VALUETYPE)
2578 {
2579 // When the method that we invoking is defined on non value type and we receive the ValueType as input,
2580 // we are calling methods on System.Object. In this case, we need to box the input ValueType.
2581 fNeedBoxOrUnbox = true;
2582 }
2583
2584 GetFuncEvalArgValue(pDE,
2585 &argData[currArgIndex],
2586 isByRef,
2587 fNeedBoxOrUnbox,
2588 dummyTH,
2589 ELEMENT_TYPE_CLASS,
2590 pDE->m_md->GetMethodTable(),
2591 &(pArguments[currArgSlot]),
2592 &(pMaybeInteriorPtrArray[currArgIndex]),
2593 &(pObjectRefArray[currArgIndex]),
2594 &(pBufferForArgsArray[currArgIndex]),
2595 NULL,
2596 ELEMENT_TYPE_OBJECT
2597 DEBUG_ARG((currArgIndex < MAX_DATA_LOCATIONS_TRACKED) ? pDataLocationArray[currArgIndex]
2598 : DL_All)
2599 );
2600
2601 LOG((LF_CORDB, LL_EVERYTHING, "this = 0x%08x\n", ArgSlotToPtr(pArguments[currArgSlot])));
2602
2603 // We need to check 'this' for a null ref ourselves... NOTE: only do this if we put an object reference on
2604 // the stack. If we put a byref for a value type, then we don't need to do this!
2605 if (!isByRef)
2606 {
2607 // The this pointer is not a unboxed value type.
2608
2609 ARG_SLOT oi1 = pArguments[currArgSlot];
2610 OBJECTREF o1 = ArgSlotToObj(oi1);
2611
2612 if (FAILED(ValidateObject(OBJECTREFToObject(o1))))
2613 {
2614 COMPlusThrow(kArgumentException, W("Argument_BadObjRef"));
2615 }
2616
2617 if (OBJECTREFToObject(o1) == NULL)
2618 {
2619 COMPlusThrow(kNullReferenceException, W("NullReference_This"));
2620 }
2621
2622 // For interface method, we have already done the check early on.
2623 if (!pDE->m_md->IsInterface())
2624 {
2625 // We also need to make sure that the method that we are invoking is either defined on this object or the direct/indirect
2626 // base objects.
2627 Object *objPtr = OBJECTREFToObject(o1);
2628 MethodTable *pMT = objPtr->GetMethodTable();
2629 // <TODO> Do this check in the following cases as well... </TODO>
2630 if (!pMT->IsArray()
2631 && !pDE->m_md->IsSharedByGenericInstantiations())
2632 {
2633 TypeHandle thFrom = TypeHandle(pMT);
2634 TypeHandle thTarget = TypeHandle(pDE->m_md->GetMethodTable());
2635 //<TODO> What about MaybeCast?</TODO>
2636 if (thFrom.CanCastToNoGC(thTarget) == TypeHandle::CannotCast)
2637 {
2638 COMPlusThrow(kArgumentException, W("Argument_CORDBBadMethod"));
2639 }
2640 }
2641 }
2642 }
2643
2644 //
2645 // Increment up both arrays.
2646 //
2647 currArgSlot++;
2648 currArgIndex++;
2649 }
2650
2651 // Special handling for functions that return value classes.
2652 if (fRetValueArg)
2653 {
2654 LOG((LF_CORDB, LL_EVERYTHING, "retBuff: currArgSlot=%d, currArgIndex=%d\n", currArgSlot, currArgIndex));
2655
2656 //
2657 // Allocate buffer for return value and GC protect it in case it contains object references
2658 //
2659 unsigned size = RetValueType.GetMethodTable()->GetNumInstanceFieldBytes();
2660
2661#ifdef FEATURE_HFA
2662 // The buffer for HFAs has to be always ENREGISTERED_RETURNTYPE_MAXSIZE
2663 size = max(size, ENREGISTERED_RETURNTYPE_MAXSIZE);
2664#endif
2665
2666 BYTE * pTemp = new (interopsafe) BYTE[ALIGN_UP(sizeof(ValueClassInfo), 8) + size];
2667
2668 ValueClassInfo * pValueClassInfo = (ValueClassInfo *)pTemp;
2669 LPVOID pData = pTemp + ALIGN_UP(sizeof(ValueClassInfo), 8);
2670
2671 memset(pData, 0, size);
2672
2673 pValueClassInfo->pData = pData;
2674 pValueClassInfo->pMT = RetValueType.GetMethodTable();
2675
2676 pValueClassInfo->pNext = *ppProtectedValueClasses;
2677 *ppProtectedValueClasses = pValueClassInfo;
2678
2679 pArguments[currArgSlot++] = PtrToArgSlot(pData);
2680 *ppRetValue = pData;
2681 }
2682
2683 // REAL ARGUMENTS (if any)
2684 // Now do the remaining args
2685 for ( ; currArgIndex < pDE->m_argCount; currArgSlot++, currArgIndex++)
2686 {
2687 DebuggerIPCE_FuncEvalArgData *pFEAD = &argData[currArgIndex];
2688
2689 LOG((LF_CORDB, LL_EVERYTHING, "currArgSlot=%d, currArgIndex=%d\n",
2690 currArgSlot,
2691 currArgIndex));
2692 LOG((LF_CORDB, LL_EVERYTHING,
2693 "\t: argSigType=0x%x, byrefArgSigType=0x%0x, inType=0x%0x\n",
2694 pFEArgInfo[currArgIndex].argSigType,
2695 pFEArgInfo[currArgIndex].byrefArgSigType,
2696 pFEAD->argElementType));
2697
2698
2699 GetFuncEvalArgValue(pDE,
2700 pFEAD,
2701 pFEArgInfo[currArgIndex].argSigType == ELEMENT_TYPE_BYREF,
2702 pFEArgInfo[currArgIndex].fNeedBoxOrUnbox,
2703 pFEArgInfo[currArgIndex].sigTypeHandle,
2704 pFEArgInfo[currArgIndex].byrefArgSigType,
2705 pFEArgInfo[currArgIndex].byrefArgTypeHandle,
2706 &(pArguments[currArgSlot]),
2707 &(pMaybeInteriorPtrArray[currArgIndex]),
2708 &(pObjectRefArray[currArgIndex]),
2709 &(pBufferForArgsArray[currArgIndex]),
2710 ppProtectedValueClasses,
2711 pFEArgInfo[currArgIndex].argSigType
2712 DEBUG_ARG((currArgIndex < MAX_DATA_LOCATIONS_TRACKED) ? pDataLocationArray[currArgIndex]
2713 : DL_All)
2714 );
2715 }
2716}
2717
2718/*
2719 * UnpackFuncEvalResult
2720 *
2721 * This routine takes the resulting object of a func-eval, and does any copying, boxing, unboxing, necessary.
2722 *
2723 * Parameters:
2724 * pDE - pointer to the DebuggerEval object being processed.
2725 * newObj - Pre-allocated object for NEW_OBJ func-evals.
2726 * retObject - Pre-allocated object to be filled in with the info in pRetBuff.
2727 * RetValueType - The return type of the function called.
2728 * pRetBuff - The raw bytes returned by the func-eval call when there is a return buffer parameter.
2729 *
2730 *
2731 * Returns:
2732 * None.
2733 *
2734 */
2735void UnpackFuncEvalResult(DebuggerEval *pDE,
2736 OBJECTREF newObj,
2737 OBJECTREF retObject,
2738 TypeHandle RetValueType,
2739 void *pRetBuff
2740 )
2741{
2742 CONTRACTL
2743 {
2744 WRAPPER(THROWS);
2745 GC_NOTRIGGER;
2746 }
2747 CONTRACTL_END;
2748
2749
2750 // Ah, but if this was a new object op, then the result is really
2751 // the object we allocated above...
2752 if (pDE->m_evalType == DB_IPCE_FET_NEW_OBJECT)
2753 {
2754 // We purposely do not morph nullables to be boxed Ts here because debugger EE's otherwise
2755 // have no way of creating true nullables that they need for their own purposes.
2756 pDE->m_result[0] = ObjToArgSlot(newObj);
2757 pDE->m_retValueBoxing = Debugger::AllBoxed;
2758 }
2759 else if (!RetValueType.IsNull())
2760 {
2761 LOG((LF_CORDB, LL_EVERYTHING, "FuncEval call is saving a boxed VC return value.\n"));
2762
2763 //
2764 // We pre-created it above
2765 //
2766 _ASSERTE(retObject != NULL);
2767
2768 // This is one of those places we use true boxed nullables
2769 _ASSERTE(!Nullable::IsNullableType(RetValueType)||
2770 retObject->GetMethodTable() == RetValueType.GetMethodTable());
2771
2772 if (pRetBuff != NULL)
2773 {
2774 // box the object
2775 CopyValueClass(retObject->GetData(),
2776 pRetBuff,
2777 RetValueType.GetMethodTable(),
2778 retObject->GetAppDomain());
2779 }
2780 else
2781 {
2782 // box the primitive returned, retObject is a true nullable for nullabes, It will be Normalized later
2783 CopyValueClass(retObject->GetData(),
2784 pDE->m_result,
2785 RetValueType.GetMethodTable(),
2786 retObject->GetAppDomain());
2787 }
2788
2789 pDE->m_result[0] = ObjToArgSlot(retObject);
2790 pDE->m_retValueBoxing = Debugger::AllBoxed;
2791 }
2792 else
2793 {
2794 //
2795 // Other FuncEvals return primitives as unboxed.
2796 //
2797 pDE->m_retValueBoxing = Debugger::OnlyPrimitivesUnboxed;
2798 }
2799
2800 LOG((LF_CORDB, LL_INFO10000, "FuncEval call has saved the return value.\n"));
2801 // No exception, so it worked as far as we're concerned.
2802 pDE->m_successful = true;
2803
2804 // If the result is an object, then place the object
2805 // reference into a strong handle and place the handle into the
2806 // pDE to protect the result from a collection.
2807 CorElementType retClassET = pDE->m_resultType.GetSignatureCorElementType();
2808
2809 if ((pDE->m_retValueBoxing == Debugger::AllBoxed) ||
2810 !RetValueType.IsNull() ||
2811 IsElementTypeSpecial(retClassET))
2812 {
2813 LOG((LF_CORDB, LL_EVERYTHING, "Creating strong handle for boxed DoNormalFuncEval result.\n"));
2814 OBJECTHANDLE oh = pDE->m_thread->GetDomain()->CreateStrongHandle(ArgSlotToObj(pDE->m_result[0]));
2815 pDE->m_result[0] = (INT64)(LONG_PTR)oh;
2816 pDE->m_vmObjectHandle = VMPTR_OBJECTHANDLE::MakePtr(oh);
2817 }
2818}
2819
2820/*
2821 * UnpackFuncEvalArguments
2822 *
2823 * This routine takes the resulting object of a func-eval, and does any copying, boxing, unboxing, necessary.
2824 *
2825 * Parameters:
2826 * pDE - pointer to the DebuggerEval object being processed.
2827 * newObj - Pre-allocated object for NEW_OBJ func-evals.
2828 * retObject - Pre-allocated object to be filled in with the info in pSource.
2829 * RetValueType - The return type of the function called.
2830 * pSource - The raw bytes returned by the func-eval call when there is a hidden parameter.
2831 *
2832 *
2833 * Returns:
2834 * None.
2835 *
2836 */
2837void UnpackFuncEvalArguments(DebuggerEval *pDE,
2838 DebuggerIPCE_FuncEvalArgData *argData,
2839 MetaSig mSig,
2840 BOOL staticMethod,
2841 OBJECTREF *pObjectRefArray,
2842 void **pMaybeInteriorPtrArray,
2843 void **pByRefMaybeInteriorPtrArray,
2844 INT64 *pBufferForArgsArray
2845 )
2846{
2847 WRAPPER_NO_CONTRACT;
2848
2849 // Update any enregistered byrefs with their new values from the
2850 // proper byref temporary array.
2851 if (pDE->m_argCount > 0)
2852 {
2853 mSig.Reset();
2854
2855 unsigned currArgIndex = 0;
2856
2857 if ((pDE->m_evalType == DB_IPCE_FET_NORMAL) && !pDE->m_md->IsStatic())
2858 {
2859 //
2860 // Skip over the 'this' arg, since this function is not supposed to mess with it.
2861 //
2862 currArgIndex++;
2863 }
2864
2865 for (; currArgIndex < pDE->m_argCount; currArgIndex++)
2866 {
2867 CorElementType argSigType = mSig.NextArgNormalized();
2868
2869 LOG((LF_CORDB, LL_EVERYTHING, "currArgIndex=%d argSigType=0x%x\n", currArgIndex, argSigType));
2870
2871 _ASSERTE(argSigType != ELEMENT_TYPE_END);
2872
2873 if (argSigType == ELEMENT_TYPE_BYREF)
2874 {
2875 TypeHandle byrefClass = TypeHandle();
2876 CorElementType byrefArgSigType = mSig.GetByRefType(&byrefClass);
2877
2878 // If these are the true boxed nullables we created in BoxFuncEvalArguments, convert them back
2879 pObjectRefArray[currArgIndex] = Nullable::NormalizeBox(pObjectRefArray[currArgIndex]);
2880
2881 LOG((LF_CORDB, LL_EVERYTHING, "DoNormalFuncEval: Updating enregistered byref...\n"));
2882 SetFuncEvalByRefArgValue(pDE,
2883 &argData[currArgIndex],
2884 byrefArgSigType,
2885 pBufferForArgsArray[currArgIndex],
2886 pMaybeInteriorPtrArray[currArgIndex],
2887 pByRefMaybeInteriorPtrArray[currArgIndex],
2888 pObjectRefArray[currArgIndex]
2889 );
2890 }
2891 }
2892 }
2893}
2894
2895
2896/*
2897 * FuncEvalWrapper
2898 *
2899 * Helper function for func-eval. We have to split it out so that we can put a __try / __finally in to
2900 * notify on a Catch-Handler found.
2901 *
2902 * Parameters:
2903 * pDE - pointer to the DebuggerEval object being processed.
2904 * pArguments - created stack to pass for the call.
2905 * pCatcherStackAddr - stack address to report as the Catch Handler Found location.
2906 *
2907 * Returns:
2908 * None.
2909 *
2910 */
2911void FuncEvalWrapper(MethodDescCallSite* pMDCS, DebuggerEval *pDE, const ARG_SLOT *pArguments, BYTE *pCatcherStackAddr)
2912{
2913 struct Param : NotifyOfCHFFilterWrapperParam
2914 {
2915 MethodDescCallSite* pMDCS;
2916 DebuggerEval *pDE;
2917 const ARG_SLOT *pArguments;
2918 };
2919
2920 Param param;
2921 param.pFrame = pCatcherStackAddr; // Inherited from NotifyOfCHFFilterWrapperParam
2922 param.pMDCS = pMDCS;
2923 param.pDE = pDE;
2924 param.pArguments = pArguments;
2925
2926 PAL_TRY(Param *, pParam, &param)
2927 {
2928 pParam->pMDCS->CallWithValueTypes_RetArgSlot(pParam->pArguments, pParam->pDE->m_result, sizeof(pParam->pDE->m_result));
2929 }
2930 PAL_EXCEPT_FILTER(NotifyOfCHFFilterWrapper)
2931 {
2932 // Should never reach here b/c handler should always continue search.
2933 _ASSERTE(false);
2934 }
2935 PAL_ENDTRY
2936}
2937
2938/*
2939 * RecordFuncEvalException
2940 *
2941 * Helper function records the details of an exception that occurred during a FuncEval
2942 * Note that this should be called from within the target domain of the FuncEval.
2943 *
2944 * Parameters:
2945 * pDE - pointer to the DebuggerEval object being processed
2946 * ppException - the Exception object that was thrown
2947 *
2948 * Returns:
2949 * None.
2950 */
2951static void RecordFuncEvalException(DebuggerEval *pDE,
2952 OBJECTREF ppException )
2953{
2954 CONTRACTL
2955 {
2956 THROWS; // CreateStrongHandle could throw OOM
2957 GC_NOTRIGGER;
2958 MODE_COOPERATIVE;
2959 }
2960 CONTRACTL_END;
2961
2962 // We got an exception. Make the exception into our result.
2963 pDE->m_successful = false;
2964 LOG((LF_CORDB, LL_EVERYTHING, "D::FEHW - Exception during funceval.\n"));
2965
2966 //
2967 // Special handling for thread abort exceptions. We need to explicitly reset the
2968 // abort request on the EE thread, then make sure to place this thread on a thunk
2969 // that will re-raise the exception when we continue the process. Note: we still
2970 // pass this thread abort exception up as the result of the eval.
2971 //
2972 if (IsExceptionOfType(kThreadAbortException, &ppException))
2973 {
2974 if (pDE->m_aborting != DebuggerEval::FE_ABORT_NONE)
2975 {
2976 //
2977 // Reset the abort request.
2978 //
2979 pDE->m_thread->UserResetAbort(Thread::TAR_FuncEval);
2980
2981 //
2982 // This is the abort we sent down.
2983 //
2984 memset(pDE->m_result, 0, sizeof(pDE->m_result));
2985 pDE->m_resultType = TypeHandle();
2986 pDE->m_aborted = true;
2987 pDE->m_retValueBoxing = Debugger::NoValueTypeBoxing;
2988
2989 LOG((LF_CORDB, LL_EVERYTHING, "D::FEHW - funceval abort exception.\n"));
2990 }
2991 else
2992 {
2993 //
2994 // This must have come from somewhere else, remember that we need to
2995 // rethrow this.
2996 //
2997 pDE->m_rethrowAbortException = true;
2998
2999 //
3000 // The result is the exception object.
3001 //
3002 pDE->m_result[0] = ObjToArgSlot(ppException);
3003
3004 pDE->m_resultType = ppException->GetTypeHandle();
3005 OBJECTHANDLE oh = pDE->m_thread->GetDomain()->CreateStrongHandle(ArgSlotToObj(pDE->m_result[0]));
3006 pDE->m_result[0] = (ARG_SLOT)PTR_TO_CORDB_ADDRESS(oh);
3007 pDE->m_vmObjectHandle = VMPTR_OBJECTHANDLE::MakePtr(oh);
3008 pDE->m_retValueBoxing = Debugger::NoValueTypeBoxing;
3009
3010 LOG((LF_CORDB, LL_EVERYTHING, "D::FEHW - Non-FE abort thread abort..\n"));
3011 }
3012 }
3013 else
3014 {
3015 //
3016 // The result is the exception object.
3017 //
3018 pDE->m_result[0] = ObjToArgSlot(ppException);
3019
3020 pDE->m_resultType = ppException->GetTypeHandle();
3021 OBJECTHANDLE oh = pDE->m_thread->GetDomain()->CreateStrongHandle(ArgSlotToObj(pDE->m_result[0]));
3022 pDE->m_result[0] = (ARG_SLOT)(LONG_PTR)oh;
3023 pDE->m_vmObjectHandle = VMPTR_OBJECTHANDLE::MakePtr(oh);
3024
3025 pDE->m_retValueBoxing = Debugger::NoValueTypeBoxing;
3026
3027 LOG((LF_CORDB, LL_EVERYTHING, "D::FEHW - Exception for the user.\n"));
3028 }
3029}
3030
3031
3032/*
3033 * DoNormalFuncEval
3034 *
3035 * Does the main body of work (steps 1c onward) for the normal func-eval algorithm detailed at the
3036 * top of this file. The args have already been GC protected and we've transitioned into the appropriate
3037 * domain (steps 1a & 1b). This has to be a seperate function from GCProtectArgsAndDoNormalFuncEval
3038 * because otherwise we can't reliably find the right GCFrames to pop when unwinding the stack due to
3039 * an exception on 64-bit platforms (we have some GCFrames outside of the TRY, and some inside,
3040 * and they won't necesarily be layed out sequentially on the stack if they are all in the same function).
3041 *
3042 * Parameters:
3043 * pDE - pointer to the DebuggerEval object being processed.
3044 * pCatcherStackAddr - stack address to report as the Catch Handler Found location.
3045 * pObjectRefArray - An array to hold object ref args. This array is protected from GC's.
3046 * pMaybeInteriorPtrArray - An array to hold values that may be pointers into a managed object.
3047 * This array is protected from GCs.
3048 * pByRefMaybeInteriorPtrArray - An array to hold values that may be pointers into a managed
3049 * object. This array is protected from GCs. This array protects the address of the arguments
3050 * while the pMaybeInteriorPtrArray protects the value of the arguments. We need to do this
3051 * because of by ref arguments.
3052 * pBufferForArgsArray - a buffer of temporary scratch space for things that do not need to be
3053 * protected, or are protected for free (e.g. Handles).
3054 * pDataLocationArray - an array of tracking data for debug sanity checks
3055 *
3056 * Returns:
3057 * None.
3058 */
3059static void DoNormalFuncEval( DebuggerEval *pDE,
3060 BYTE *pCatcherStackAddr,
3061 OBJECTREF *pObjectRefArray,
3062 void **pMaybeInteriorPtrArray,
3063 void **pByRefMaybeInteriorPtrArray,
3064 INT64 *pBufferForArgsArray,
3065 ValueClassInfo ** ppProtectedValueClasses
3066 DEBUG_ARG(DataLocation pDataLocationArray[])
3067 )
3068{
3069 CONTRACTL
3070 {
3071 THROWS;
3072 GC_TRIGGERS;
3073 MODE_COOPERATIVE;
3074 }
3075 CONTRACTL_END;
3076
3077 //
3078 // Now that all the args are protected, we can go back and deal with generic args and resolving
3079 // all their information.
3080 //
3081 ResolveFuncEvalGenericArgInfo(pDE);
3082
3083 //
3084 // Grab the signature of the method we're working on and do some error checking.
3085 // Note that if this instantiated generic code, then this will
3086 // correctly give as an instantiated view of the signature that we can iterate without
3087 // worrying about generic items in the signature.
3088 //
3089 MetaSig mSig(pDE->m_md);
3090
3091 BYTE callingconvention = mSig.GetCallingConvention();
3092 if (!isCallConv(callingconvention, IMAGE_CEE_CS_CALLCONV_DEFAULT))
3093 {
3094 // We don't support calling vararg!
3095 COMPlusThrow(kArgumentException, W("Argument_CORDBBadVarArgCallConv"));
3096 }
3097
3098 //
3099 // We'll need to know if this is a static method or not.
3100 //
3101 BOOL staticMethod = pDE->m_md->IsStatic();
3102
3103 _ASSERTE((pDE->m_evalType == DB_IPCE_FET_NORMAL) || !staticMethod);
3104
3105 //
3106 // Do Step 1c - Pre-allocate space for new objects.
3107 //
3108 OBJECTREF newObj = NULL;
3109 GCPROTECT_BEGIN(newObj);
3110
3111 SIZE_T allocArgCnt = 0;
3112
3113 if (pDE->m_evalType == DB_IPCE_FET_NEW_OBJECT)
3114 {
3115 ValidateFuncEvalReturnType(DB_IPCE_FET_NEW_OBJECT, pDE->m_resultType.GetMethodTable());
3116 pDE->m_resultType.GetMethodTable()->EnsureInstanceActive();
3117 newObj = AllocateObject(pDE->m_resultType.GetMethodTable());
3118
3119 //
3120 // Note: we account for an extra argument in the count passed
3121 // in. We use this to increase the space allocated for args,
3122 // and we use it to control the number of args copied into
3123 // those arrays below. Note: m_argCount already includes space
3124 // for this.
3125 //
3126 allocArgCnt = pDE->m_argCount + 1;
3127 }
3128 else
3129 {
3130 allocArgCnt = pDE->m_argCount;
3131 }
3132
3133 //
3134 // Validate the argument count with mSig.
3135 //
3136 if (allocArgCnt != (mSig.NumFixedArgs() + (staticMethod ? 0 : 1)))
3137 {
3138 COMPlusThrow(kTargetParameterCountException, W("Arg_ParmCnt"));
3139 }
3140
3141 //
3142 // Do Step 1d - Gather information about the method that will be called.
3143 //
3144 // An array to hold information about the parameters to be passed. This is
3145 // all the information we need to gather before entering the GCX_FORBID area.
3146 //
3147 DebuggerIPCE_FuncEvalArgData *argData = pDE->GetArgData();
3148
3149 MethodDesc *pUnboxedMD = pDE->m_md;
3150 BOOL fHasRetBuffArg;
3151 BOOL fHasNonStdByValReturn;
3152 TypeHandle RetValueType;
3153
3154 BoxFuncEvalThisParameter(pDE,
3155 argData,
3156 pMaybeInteriorPtrArray,
3157 pObjectRefArray
3158 DEBUG_ARG(pDataLocationArray)
3159 );
3160
3161 GatherFuncEvalMethodInfo(pDE,
3162 mSig,
3163 argData,
3164 &pUnboxedMD,
3165 pObjectRefArray,
3166 pBufferForArgsArray,
3167 &fHasRetBuffArg,
3168 &fHasNonStdByValReturn,
3169 &RetValueType
3170 DEBUG_ARG(pDataLocationArray)
3171 );
3172
3173 //
3174 // Do Step 1e - Gather info from runtime about args (may trigger a GC).
3175 //
3176 SIZE_T cbAllocSize;
3177 if (!(ClrSafeInt<SIZE_T>::multiply(pDE->m_argCount, sizeof(FuncEvalArgInfo), cbAllocSize)) ||
3178 (cbAllocSize != (size_t)(cbAllocSize)))
3179 {
3180 ThrowHR(COR_E_OVERFLOW);
3181 }
3182 FuncEvalArgInfo * pFEArgInfo = (FuncEvalArgInfo *)_alloca(cbAllocSize);
3183 memset(pFEArgInfo, 0, cbAllocSize);
3184
3185 GatherFuncEvalArgInfo(pDE, mSig, argData, pFEArgInfo);
3186
3187 //
3188 // Do Step 1f - Box or unbox arguments one at a time, placing newly boxed items into
3189 // pObjectRefArray immediately after creating them.
3190 //
3191 BoxFuncEvalArguments(pDE,
3192 argData,
3193 pFEArgInfo,
3194 pMaybeInteriorPtrArray,
3195 pObjectRefArray
3196 DEBUG_ARG(pDataLocationArray)
3197 );
3198
3199#ifdef _DEBUG
3200 if (!RetValueType.IsNull())
3201 {
3202 _ASSERTE(RetValueType.IsValueType());
3203 }
3204#endif
3205
3206 //
3207 // Do Step 1g - Pre-allocate any return value object.
3208 //
3209 OBJECTREF retObject = NULL;
3210 GCPROTECT_BEGIN(retObject);
3211
3212 if ((pDE->m_evalType != DB_IPCE_FET_NEW_OBJECT) && !RetValueType.IsNull())
3213 {
3214 ValidateFuncEvalReturnType(pDE->m_evalType, RetValueType.GetMethodTable());
3215 RetValueType.GetMethodTable()->EnsureInstanceActive();
3216 retObject = AllocateObject(RetValueType.GetMethodTable());
3217 }
3218
3219 //
3220 // Do Step 1h - Copy into scratch buffer all enregistered arguments, and
3221 // ByRef literals.
3222 //
3223 CopyArgsToBuffer(pDE,
3224 argData,
3225 pFEArgInfo,
3226 pBufferForArgsArray
3227 DEBUG_ARG(pDataLocationArray)
3228 );
3229
3230 //
3231 // We presume that the function has a return buffer. This assumption gets squeezed out
3232 // when we pack the argument array.
3233 //
3234 allocArgCnt++;
3235
3236 LOG((LF_CORDB, LL_EVERYTHING,
3237 "Func eval for %s::%s: allocArgCnt=%d\n",
3238 pDE->m_md->m_pszDebugClassName,
3239 pDE->m_md->m_pszDebugMethodName,
3240 allocArgCnt));
3241
3242 MethodDescCallSite funcToEval(pDE->m_md, pDE->m_targetCodeAddr);
3243
3244 //
3245 // Do Step 1i - Create and pack argument array for managed function call.
3246 //
3247 // Allocate space for argument stack
3248 //
3249 if ((!ClrSafeInt<SIZE_T>::multiply(allocArgCnt, sizeof(ARG_SLOT), cbAllocSize)) ||
3250 (cbAllocSize != (size_t)(cbAllocSize)))
3251 {
3252 ThrowHR(COR_E_OVERFLOW);
3253 }
3254 ARG_SLOT * pArguments = (ARG_SLOT *)_alloca(cbAllocSize);
3255 memset(pArguments, 0, cbAllocSize);
3256
3257 LPVOID pRetBuff = NULL;
3258
3259 PackArgumentArray(pDE,
3260 argData,
3261 pFEArgInfo,
3262 pUnboxedMD,
3263 RetValueType,
3264 pObjectRefArray,
3265 pMaybeInteriorPtrArray,
3266 pBufferForArgsArray,
3267 ppProtectedValueClasses,
3268 newObj,
3269#ifdef FEATURE_HFA
3270 fHasRetBuffArg || fHasNonStdByValReturn,
3271#else
3272 fHasRetBuffArg,
3273#endif
3274 pArguments,
3275 &pRetBuff
3276 DEBUG_ARG(pDataLocationArray)
3277 );
3278
3279 //
3280 //
3281 // Do Step 2 - Make the call!
3282 //
3283 //
3284 FuncEvalWrapper(&funcToEval, pDE, pArguments, pCatcherStackAddr);
3285 {
3286
3287 // We have now entered the zone where taking a GC is fatal until we get the
3288 // return value all fixed up.
3289 //
3290 GCX_FORBID();
3291
3292
3293 //
3294 //
3295 // Do Step 3 - Unpack results and update ByRef arguments.
3296 //
3297 //
3298 //
3299 LOG((LF_CORDB, LL_EVERYTHING, "FuncEval call has returned\n"));
3300
3301
3302 // GC still can't happen until we get our return value out half way through the unpack function
3303
3304 UnpackFuncEvalResult(pDE,
3305 newObj,
3306 retObject,
3307 RetValueType,
3308 pRetBuff
3309 );
3310 }
3311
3312 UnpackFuncEvalArguments(pDE,
3313 argData,
3314 mSig,
3315 staticMethod,
3316 pObjectRefArray,
3317 pMaybeInteriorPtrArray,
3318 pByRefMaybeInteriorPtrArray,
3319 pBufferForArgsArray
3320 );
3321
3322 GCPROTECT_END(); // retObject
3323 GCPROTECT_END(); // newObj
3324}
3325
3326/*
3327 * GCProtectArgsAndDoNormalFuncEval
3328 *
3329 * This routine is the primary entrypoint for normal func-evals. It implements the algorithm
3330 * described at the top of this file, doing steps 1a and 1b itself, then calling DoNormalFuncEval
3331 * to do the rest.
3332 *
3333 * Parameters:
3334 * pDE - pointer to the DebuggerEval object being processed.
3335 * pCatcherStackAddr - stack address to report as the Catch Handler Found location.
3336 *
3337 * Returns:
3338 * None.
3339 *
3340 */
3341static void GCProtectArgsAndDoNormalFuncEval(DebuggerEval *pDE,
3342 BYTE *pCatcherStackAddr )
3343{
3344 CONTRACTL
3345 {
3346 THROWS;
3347 GC_TRIGGERS;
3348 MODE_COOPERATIVE;
3349 }
3350 CONTRACTL_END;
3351
3352
3353 INDEBUG(DataLocation pDataLocationArray[MAX_DATA_LOCATIONS_TRACKED]);
3354
3355 //
3356 // An array to hold object ref args. This array is protected from GC's.
3357 //
3358 SIZE_T cbAllocSize;
3359 if ((!ClrSafeInt<SIZE_T>::multiply(pDE->m_argCount, sizeof(OBJECTREF), cbAllocSize)) ||
3360 (cbAllocSize != (size_t)(cbAllocSize)))
3361 {
3362 ThrowHR(COR_E_OVERFLOW);
3363 }
3364 OBJECTREF * pObjectRefArray = (OBJECTREF*)_alloca(cbAllocSize);
3365 memset(pObjectRefArray, 0, cbAllocSize);
3366 GCPROTECT_ARRAY_BEGIN(*pObjectRefArray, pDE->m_argCount);
3367
3368 //
3369 // An array to hold values that may be pointers into a managed object. This array
3370 // is protected from GCs.
3371 //
3372 if ((!ClrSafeInt<SIZE_T>::multiply(pDE->m_argCount, sizeof(void**), cbAllocSize)) ||
3373 (cbAllocSize != (size_t)(cbAllocSize)))
3374 {
3375 ThrowHR(COR_E_OVERFLOW);
3376 }
3377 void ** pMaybeInteriorPtrArray = (void **)_alloca(cbAllocSize);
3378 memset(pMaybeInteriorPtrArray, 0, cbAllocSize);
3379 GCPROTECT_BEGININTERIOR_ARRAY(*pMaybeInteriorPtrArray, (UINT)(cbAllocSize/sizeof(OBJECTREF)));
3380
3381 //
3382 // An array to hold values that may be pointers into a managed object. This array
3383 // is protected from GCs. This array protects the address of the arguments while the
3384 // pMaybeInteriorPtrArray protects the value of the arguments. We need to do this because
3385 // of by ref arguments.
3386 //
3387 if ((!ClrSafeInt<SIZE_T>::multiply(pDE->m_argCount, sizeof(void**), cbAllocSize)) ||
3388 (cbAllocSize != (size_t)(cbAllocSize)))
3389 {
3390 ThrowHR(COR_E_OVERFLOW);
3391 }
3392 void ** pByRefMaybeInteriorPtrArray = (void **)_alloca(cbAllocSize);
3393 memset(pByRefMaybeInteriorPtrArray, 0, cbAllocSize);
3394 GCPROTECT_BEGININTERIOR_ARRAY(*pByRefMaybeInteriorPtrArray, (UINT)(cbAllocSize/sizeof(OBJECTREF)));
3395
3396 //
3397 // A buffer of temporary scratch space for things that do not need to be protected, or
3398 // are protected for free (e.g. Handles).
3399 //
3400 if ((!ClrSafeInt<SIZE_T>::multiply(pDE->m_argCount, sizeof(INT64), cbAllocSize)) ||
3401 (cbAllocSize != (size_t)(cbAllocSize)))
3402 {
3403 ThrowHR(COR_E_OVERFLOW);
3404 }
3405 INT64 *pBufferForArgsArray = (INT64*)_alloca(cbAllocSize);
3406 memset(pBufferForArgsArray, 0, cbAllocSize);
3407
3408 FrameWithCookie<ProtectValueClassFrame> protectValueClassFrame;
3409
3410 //
3411 // Initialize our tracking array
3412 //
3413 INDEBUG(memset(pDataLocationArray, 0, sizeof(DataLocation) * (MAX_DATA_LOCATIONS_TRACKED)));
3414
3415 {
3416 GCX_FORBID();
3417
3418 //
3419 // Do step 1a
3420 //
3421 GCProtectAllPassedArgs(pDE,
3422 pObjectRefArray,
3423 pMaybeInteriorPtrArray,
3424 pByRefMaybeInteriorPtrArray,
3425 pBufferForArgsArray
3426 DEBUG_ARG(pDataLocationArray)
3427 );
3428
3429 }
3430
3431 //
3432 // Do step 1b: we can switch domains since everything is now protected.
3433 // Note that before this point, it's unsafe to rely on pDE->m_module since it may be
3434 // invalid due to an AD unload.
3435 // All normal func evals should have an AppDomain specified.
3436 //
3437 _ASSERTE( pDE->m_appDomainId.m_dwId != 0 );
3438 ENTER_DOMAIN_ID( pDE->m_appDomainId );
3439
3440 // Wrap everything in a EX_TRY so we catch any exceptions that could be thrown.
3441 // Note that we don't let any thrown exceptions cross the AppDomain boundary because we don't
3442 // want them to get marshalled.
3443 EX_TRY
3444 {
3445 DoNormalFuncEval(
3446 pDE,
3447 pCatcherStackAddr,
3448 pObjectRefArray,
3449 pMaybeInteriorPtrArray,
3450 pByRefMaybeInteriorPtrArray,
3451 pBufferForArgsArray,
3452 protectValueClassFrame.GetValueClassInfoList()
3453 DEBUG_ARG(pDataLocationArray)
3454 );
3455 }
3456 EX_CATCH
3457 {
3458 // We got an exception. Make the exception into our result.
3459 OBJECTREF ppException = GET_THROWABLE();
3460 GCX_FORBID();
3461 RecordFuncEvalException( pDE, ppException);
3462 }
3463 // Note: we need to catch all exceptioins here because they all get reported as the result of
3464 // the funceval. If a ThreadAbort occurred other than for a funcEval abort, we'll re-throw it manually.
3465 EX_END_CATCH(SwallowAllExceptions);
3466
3467 // Restore context
3468 END_DOMAIN_TRANSITION;
3469
3470 protectValueClassFrame.Pop();
3471
3472 CleanUpTemporaryVariables(protectValueClassFrame.GetValueClassInfoList());
3473
3474 GCPROTECT_END(); // pByRefMaybeInteriorPtrArray
3475 GCPROTECT_END(); // pMaybeInteriorPtrArray
3476 GCPROTECT_END(); // pObjectRefArray
3477 LOG((LF_CORDB, LL_EVERYTHING, "DoNormalFuncEval: returning...\n"));
3478}
3479
3480
3481void FuncEvalHijackRealWorker(DebuggerEval *pDE, Thread* pThread, FuncEvalFrame* pFEFrame)
3482{
3483 BYTE * pCatcherStackAddr = (BYTE*) pFEFrame;
3484
3485 // Handle normal func evals in DoNormalFuncEval
3486 if ((pDE->m_evalType == DB_IPCE_FET_NEW_OBJECT) || (pDE->m_evalType == DB_IPCE_FET_NORMAL))
3487 {
3488 GCProtectArgsAndDoNormalFuncEval(pDE, pCatcherStackAddr);
3489 LOG((LF_CORDB, LL_EVERYTHING, "DoNormalFuncEval has returned.\n"));
3490 return;
3491 }
3492
3493 // The method may be in a different AD than the thread.
3494 // The RS already verified that all of the arguments are in the same appdomain as the function
3495 // (because we can't verify it here).
3496 // Note that this is exception safe, so we are guarenteed to be in the correct AppDomain when
3497 // we leave this method.
3498 // Before this, we can't safely use the DebuggerModule* since the domain may have been unloaded.
3499 ENTER_DOMAIN_ID( pDE->m_appDomainId );
3500
3501 OBJECTREF newObj = NULL;
3502 GCPROTECT_BEGIN(newObj);
3503
3504 // Wrap everything in a EX_TRY so we catch any exceptions that could be thrown.
3505 // Note that we don't let any thrown exceptions cross the AppDomain boundary because we don't
3506 // want them to get marshalled.
3507 EX_TRY
3508 {
3509 DebuggerIPCE_TypeArgData *firstdata = pDE->GetTypeArgData();
3510 DWORD nGenericArgs = pDE->m_genericArgsCount;
3511
3512 SIZE_T cbAllocSize;
3513 if ((!ClrSafeInt<SIZE_T>::multiply(nGenericArgs, sizeof(TypeHandle *), cbAllocSize)) ||
3514 (cbAllocSize != (size_t)(cbAllocSize)))
3515 {
3516 ThrowHR(COR_E_OVERFLOW);
3517 }
3518 TypeHandle *pGenericArgs = (nGenericArgs == 0) ? NULL : (TypeHandle *) _alloca(cbAllocSize);
3519 //
3520 // Snag the type arguments from the input and get the
3521 // method desc that corresponds to the instantiated desc.
3522 //
3523 Debugger::TypeDataWalk walk(firstdata, pDE->m_genericArgsNodeCount);
3524 walk.ReadTypeHandles(nGenericArgs, pGenericArgs);
3525
3526 // <TODO>better error message</TODO>
3527 if (!walk.Finished())
3528 COMPlusThrow(kArgumentException, W("Argument_InvalidGenericArg"));
3529
3530 switch (pDE->m_evalType)
3531 {
3532 case DB_IPCE_FET_NEW_OBJECT_NC:
3533 {
3534
3535 // Find the class.
3536 TypeHandle thClass = g_pEEInterface->LoadClass(pDE->m_debuggerModule->GetRuntimeModule(),
3537 pDE->m_classToken);
3538
3539 if (thClass.IsNull())
3540 COMPlusThrow(kArgumentNullException, W("ArgumentNull_Type"));
3541
3542 // Apply any type arguments
3543 TypeHandle th =
3544 (nGenericArgs == 0)
3545 ? thClass
3546 : g_pEEInterface->LoadInstantiation(pDE->m_debuggerModule->GetRuntimeModule(),
3547 pDE->m_classToken, nGenericArgs, pGenericArgs);
3548
3549 if (th.IsNull() || th.ContainsGenericVariables())
3550 COMPlusThrow(kArgumentException, W("Argument_InvalidGenericArg"));
3551
3552 // Run the Class Init for this type, if necessary.
3553 MethodTable * pOwningMT = th.GetMethodTable();
3554 pOwningMT->EnsureInstanceActive();
3555 pOwningMT->CheckRunClassInitThrowing();
3556
3557 // Create a new instance of the class
3558
3559 ValidateFuncEvalReturnType(DB_IPCE_FET_NEW_OBJECT_NC, th.GetMethodTable());
3560
3561 newObj = AllocateObject(th.GetMethodTable());
3562
3563 // No exception, so it worked.
3564 pDE->m_successful = true;
3565
3566 // So is the result type.
3567 pDE->m_resultType = th;
3568
3569 //
3570 // Box up all returned objects
3571 //
3572 pDE->m_retValueBoxing = Debugger::AllBoxed;
3573
3574 // Make a strong handle for the result.
3575 OBJECTHANDLE oh = pDE->m_thread->GetDomain()->CreateStrongHandle(newObj);
3576 pDE->m_result[0] = (ARG_SLOT)(LONG_PTR)oh;
3577 pDE->m_vmObjectHandle = VMPTR_OBJECTHANDLE::MakePtr(oh);
3578
3579 break;
3580 }
3581
3582 case DB_IPCE_FET_NEW_STRING:
3583 {
3584 // Create the string. m_argData is not necessarily null terminated...
3585 // The numeration parameter represents the string length, not the buffer size, but
3586 // we have passed the buffer size across to copy our data properly, so must divide back out.
3587 // NewString will return NULL if pass null, but want an empty string in that case, so
3588 // just create an EmptyString explicitly.
3589 if ((pDE->m_argData == NULL) || (pDE->m_stringSize == 0))
3590 {
3591 newObj = StringObject::GetEmptyString();
3592 }
3593 else
3594 {
3595 newObj = StringObject::NewString(pDE->GetNewStringArgData(), (int)(pDE->m_stringSize/sizeof(WCHAR)));
3596 }
3597
3598 // No exception, so it worked.
3599 pDE->m_successful = true;
3600
3601 // Result type is, of course, a string.
3602 pDE->m_resultType = newObj->GetTypeHandle();
3603
3604 // Place the result in a strong handle to protect it from a collection.
3605 OBJECTHANDLE oh = pDE->m_thread->GetDomain()->CreateStrongHandle(newObj);
3606 pDE->m_result[0] = (ARG_SLOT)(LONG_PTR)oh;
3607 pDE->m_vmObjectHandle = VMPTR_OBJECTHANDLE::MakePtr(oh);
3608
3609 break;
3610 }
3611
3612 case DB_IPCE_FET_NEW_ARRAY:
3613 {
3614 // <TODO>@todo: We're only gonna handle SD arrays for right now.</TODO>
3615 if (pDE->m_arrayRank > 1)
3616 COMPlusThrow(kRankException, W("Rank_MultiDimNotSupported"));
3617
3618 // Grab the elementType from the arg/data area.
3619 _ASSERTE(nGenericArgs == 1);
3620 TypeHandle th = pGenericArgs[0];
3621
3622 CorElementType et = th.GetSignatureCorElementType();
3623 // Gotta be a primitive, class, or System.Object.
3624 if (((et < ELEMENT_TYPE_BOOLEAN) || (et > ELEMENT_TYPE_R8)) &&
3625 !IsElementTypeSpecial(et))
3626 {
3627 COMPlusThrow(kArgumentOutOfRangeException, W("ArgumentOutOfRange_Enum"));
3628 }
3629
3630 // Grab the dims from the arg/data area. These come after the type arguments.
3631 SIZE_T *dims;
3632 dims = (SIZE_T*) (firstdata + pDE->m_genericArgsNodeCount);
3633
3634 if (IsElementTypeSpecial(et))
3635 {
3636 newObj = AllocateObjectArray((DWORD)dims[0], th);
3637 }
3638 else
3639 {
3640 // Create a simple array. Note: we can only do this type of create here due to the checks above.
3641 newObj = AllocatePrimitiveArray(et, (DWORD)dims[0]);
3642 }
3643
3644 // No exception, so it worked.
3645 pDE->m_successful = true;
3646
3647 // Result type is, of course, the type of the array.
3648 pDE->m_resultType = newObj->GetTypeHandle();
3649
3650 // Place the result in a strong handle to protect it from a collection.
3651 OBJECTHANDLE oh = pDE->m_thread->GetDomain()->CreateStrongHandle(newObj);
3652 pDE->m_result[0] = (ARG_SLOT)(LONG_PTR)oh;
3653 pDE->m_vmObjectHandle = VMPTR_OBJECTHANDLE::MakePtr(oh);
3654
3655 break;
3656 }
3657
3658 default:
3659 _ASSERTE(!"Invalid eval type!");
3660 }
3661 }
3662 EX_CATCH
3663 {
3664 // We got an exception. Make the exception into our result.
3665 OBJECTREF ppException = GET_THROWABLE();
3666 GCX_FORBID();
3667 RecordFuncEvalException( pDE, ppException);
3668 }
3669 // Note: we need to catch all exceptioins here because they all get reported as the result of
3670 // the funceval. If a ThreadAbort occurred other than for a funcEval abort, we'll re-throw it manually.
3671 EX_END_CATCH(SwallowAllExceptions);
3672
3673 GCPROTECT_END();
3674
3675 //
3676 // Restore context
3677 //
3678 END_DOMAIN_TRANSITION;
3679
3680}
3681
3682//
3683// FuncEvalHijackWorker is the function that managed threads start executing in order to perform a function
3684// evaluation. Control is transfered here on the proper thread by hijacking that that's IP to this method in
3685// Debugger::FuncEvalSetup. This function can also be called directly by a Runtime thread that is stopped sending a
3686// first or second chance exception to the Right Side.
3687//
3688// The DebuggerEval object may get deleted by the helper thread doing a CleanupFuncEval while this thread is blocked
3689// sending the eval complete.
3690void * STDCALL FuncEvalHijackWorker(DebuggerEval *pDE)
3691{
3692 CONTRACTL
3693 {
3694 MODE_COOPERATIVE;
3695 GC_TRIGGERS;
3696 THROWS;
3697 SO_NOT_MAINLINE;
3698
3699 PRECONDITION(CheckPointer(pDE));
3700 }
3701 CONTRACTL_END;
3702
3703
3704
3705 Thread *pThread = NULL;
3706 CONTEXT *filterContext = NULL;
3707
3708 {
3709 GCX_FORBID();
3710
3711 LOG((LF_CORDB, LL_INFO100000, "D:FEHW for pDE:%08x evalType:%d\n", pDE, pDE->m_evalType));
3712
3713 pThread = GetThread();
3714
3715#ifndef DACCESS_COMPILE
3716#ifdef _DEBUG
3717 //
3718 // Flush all debug tracking information for this thread on object refs as it
3719 // only approximates proper tracking and may have stale data, resulting in false
3720 // positives. We dont want that as func-eval runs a lot, so flush them now.
3721 //
3722 g_pEEInterface->ObjectRefFlush(pThread);
3723#endif
3724#endif
3725
3726 if (!pDE->m_evalDuringException)
3727 {
3728 //
3729 // From this point forward we use FORBID regions to guard against GCs.
3730 // Refer to code:Debugger::FuncEvalSetup to see the increment was done.
3731 //
3732 g_pDebugger->DecThreadsAtUnsafePlaces();
3733 }
3734
3735 // Preemptive GC is disabled at the start of this method.
3736 _ASSERTE(g_pEEInterface->IsPreemptiveGCDisabled());
3737
3738 DebuggerController::DispatchFuncEvalEnter(pThread);
3739
3740
3741 // If we've got a filter context still installed, then remove it while we do the work...
3742 filterContext = g_pEEInterface->GetThreadFilterContext(pDE->m_thread);
3743
3744 if (filterContext)
3745 {
3746 _ASSERTE(pDE->m_evalDuringException);
3747 g_pEEInterface->SetThreadFilterContext(pDE->m_thread, NULL);
3748 }
3749
3750 }
3751
3752 //
3753 // Special handling for a re-abort eval. We don't setup a EX_TRY or try to lookup a function to call. All we do
3754 // is have this thread abort itself.
3755 //
3756 if (pDE->m_evalType == DB_IPCE_FET_RE_ABORT)
3757 {
3758 //
3759 // Push our FuncEvalFrame. The return address is equal to the IP in the saved context in the DebuggerEval. The
3760 // m_Datum becomes the ptr to the DebuggerEval. The frame address also serves as the address of the catch-handler-found.
3761 //
3762 FrameWithCookie<FuncEvalFrame> FEFrame(pDE, GetIP(&pDE->m_context), false);
3763 FEFrame.Push();
3764
3765 pDE->m_thread->UserAbort(pDE->m_requester, EEPolicy::TA_Safe, INFINITE, Thread::UAC_Normal);
3766 _ASSERTE(!"Should not return from UserAbort here!");
3767 return NULL;
3768 }
3769
3770 //
3771 // We cannot scope the following in a GCX_FORBID(), but we would like to. But we need the frames on the
3772 // stack here, so they must never go out of scope.
3773 //
3774
3775 //
3776 // Push our FuncEvalFrame. The return address is equal to the IP in the saved context in the DebuggerEval. The
3777 // m_Datum becomes the ptr to the DebuggerEval. The frame address also serves as the address of the catch-handler-found.
3778 //
3779 FrameWithCookie<FuncEvalFrame> FEFrame(pDE, GetIP(&pDE->m_context), true);
3780 FEFrame.Push();
3781
3782 // On ARM the single step flag is per-thread and not per context. We need to make sure that the SS flag is cleared
3783 // for the funceval, and that the state is back to what it should be after the funceval completes.
3784#ifdef _TARGET_ARM_
3785 bool ssEnabled = pDE->m_thread->IsSingleStepEnabled();
3786 if (ssEnabled)
3787 pDE->m_thread->DisableSingleStep();
3788#endif
3789
3790 FuncEvalHijackRealWorker(pDE, pThread, &FEFrame);
3791
3792#ifdef _TARGET_ARM_
3793 if (ssEnabled)
3794 pDE->m_thread->EnableSingleStep();
3795#endif
3796
3797
3798
3799 LOG((LF_CORDB, LL_EVERYTHING, "FuncEval has finished its primary work.\n"));
3800
3801 //
3802 // The func-eval is now completed, successfully or with failure, aborted or run-to-completion.
3803 //
3804 pDE->m_completed = true;
3805
3806 if (pDE->m_thread->IsAbortRequested())
3807 {
3808 //
3809 // Check if an unmanaged thread tried to also abort this thread while we
3810 // were doing the func-eval, then that kind we want to rethrow. The check
3811 // versus m_aborted is for the case where the FE was aborted, we caught that,
3812 // then cleared the FEAbort request, but there is still an outstanding abort
3813 // - then it must be a user abort.
3814 //
3815 if ((pDE->m_aborting == DebuggerEval::FE_ABORT_NONE) || pDE->m_aborted)
3816 {
3817 pDE->m_rethrowAbortException = true;
3818 }
3819
3820 //
3821 // Reset the abort request if a func-eval abort was submitted, but the func-eval completed
3822 // before the abort could take place, we want to make sure we do not throw an abort exception
3823 // in this case.
3824 //
3825 if (pDE->m_aborting != DebuggerEval::FE_ABORT_NONE)
3826 {
3827 pDE->m_thread->UserResetAbort(Thread::TAR_FuncEval);
3828 }
3829
3830 }
3831
3832 // Codepitching can hijack our frame's return address. That means that we'll need to update PC in our saved context
3833 // so that when its restored, its like we've returned to the codepitching hijack. At this point, the old value of
3834 // EIP is worthless anyway.
3835 if (!pDE->m_evalDuringException)
3836 {
3837 SetIP(&pDE->m_context, (SIZE_T)FEFrame.GetReturnAddress());
3838 }
3839
3840 //
3841 // Disable all steppers and breakpoints created during the func-eval
3842 //
3843 DebuggerController::DispatchFuncEvalExit(pThread);
3844
3845 void *dest = NULL;
3846
3847 if (!pDE->m_evalDuringException)
3848 {
3849 // Signal to the helper thread that we're done with our func eval. Start by creating a DebuggerFuncEvalComplete
3850 // object. Give it an address at which to create the patch, which is a chunk of memory specified by our
3851 // DebuggerEval big enough to hold a breakpoint instruction.
3852#ifdef _TARGET_ARM_
3853 dest = (BYTE*)((DWORD)&(pDE->m_bpInfoSegment->m_breakpointInstruction) | THUMB_CODE);
3854#else
3855 dest = &(pDE->m_bpInfoSegment->m_breakpointInstruction);
3856#endif
3857
3858 //
3859 // The created object below sets up itself as a hijack and will destroy itself when the hijack and work
3860 // is done.
3861 //
3862
3863 DebuggerFuncEvalComplete *comp;
3864 comp = new (interopsafe) DebuggerFuncEvalComplete(pThread, dest);
3865 _ASSERTE(comp != NULL); // would have thrown
3866
3867 // Pop the FuncEvalFrame now that we're pretty much done. Make sure we
3868 // don't pop the frame too early. Because GC can be triggered in our grabbing of
3869 // Debugger lock. If we pop the FE frame without setting back thread filter context,
3870 // the frames left uncrawlable.
3871 //
3872 FEFrame.Pop();
3873 }
3874 else
3875 {
3876 // We don't have to setup any special hijacks to return from here when we've been processing during an
3877 // exception. We just go ahead and send the FuncEvalComplete event over now. Don't forget to enable/disable PGC
3878 // around the call...
3879 _ASSERTE(g_pEEInterface->IsPreemptiveGCDisabled());
3880
3881 if (filterContext != NULL)
3882 {
3883 g_pEEInterface->SetThreadFilterContext(pDE->m_thread, filterContext);
3884 }
3885
3886 // Pop the FuncEvalFrame now that we're pretty much done.
3887 FEFrame.Pop();
3888
3889
3890 {
3891 //
3892 // This also grabs the debugger lock, so we can atomically check if a detach has
3893 // happened.
3894 //
3895 SENDIPCEVENT_BEGIN(g_pDebugger, pDE->m_thread);
3896
3897 if ((pDE->m_thread->GetDomain() != NULL) && pDE->m_thread->GetDomain()->IsDebuggerAttached())
3898 {
3899
3900 if (CORDebuggerAttached())
3901 {
3902 g_pDebugger->FuncEvalComplete(pDE->m_thread, pDE);
3903
3904 g_pDebugger->SyncAllThreads(SENDIPCEVENT_PtrDbgLockHolder);
3905 }
3906
3907 }
3908
3909 SENDIPCEVENT_END;
3910 }
3911 }
3912
3913
3914 // pDE may now point to deleted memory if the helper thread did a CleanupFuncEval while we
3915 // were blocked waiting for a continue after the func-eval complete.
3916
3917 // We return the address that we want to resume executing at.
3918 return dest;
3919
3920}
3921
3922
3923#if defined(WIN64EXCEPTIONS) && !defined(FEATURE_PAL)
3924
3925EXTERN_C EXCEPTION_DISPOSITION
3926FuncEvalHijackPersonalityRoutine(IN PEXCEPTION_RECORD pExceptionRecord
3927 WIN64_ARG(IN ULONG64 MemoryStackFp)
3928 NOT_WIN64_ARG(IN ULONG32 MemoryStackFp),
3929 IN OUT PCONTEXT pContextRecord,
3930 IN OUT PDISPATCHER_CONTEXT pDispatcherContext
3931 )
3932{
3933 DebuggerEval* pDE = NULL;
3934#if defined(_TARGET_AMD64_)
3935 pDE = *(DebuggerEval**)(pDispatcherContext->EstablisherFrame);
3936#elif defined(_TARGET_ARM_)
3937 // on ARM the establisher frame is the SP of the caller of FuncEvalHijack, on other platforms it's FuncEvalHijack's SP.
3938 // in FuncEvalHijack we allocate 8 bytes of stack space and then store R0 at the current SP, so if we subtract 8 from
3939 // the establisher frame we can get the stack location where R0 was stored.
3940 pDE = *(DebuggerEval**)(pDispatcherContext->EstablisherFrame - 8);
3941
3942#elif defined(_TARGET_ARM64_)
3943 // on ARM64 the establisher frame is the SP of the caller of FuncEvalHijack.
3944 // in FuncEvalHijack we allocate 32 bytes of stack space and then store R0 at the current SP + 16, so if we subtract 16 from
3945 // the establisher frame we can get the stack location where R0 was stored.
3946 pDE = *(DebuggerEval**)(pDispatcherContext->EstablisherFrame - 16);
3947#else
3948 _ASSERTE(!"NYI - FuncEvalHijackPersonalityRoutine()");
3949#endif
3950
3951 FixupDispatcherContext(pDispatcherContext, &(pDE->m_context), pContextRecord);
3952
3953 // Returning ExceptionCollidedUnwind will cause the OS to take our new context record and
3954 // dispatcher context and restart the exception dispatching on this call frame, which is
3955 // exactly the behavior we want.
3956 return ExceptionCollidedUnwind;
3957}
3958
3959
3960#endif // WIN64EXCEPTIONS && !FEATURE_PAL
3961
3962#endif // ifndef DACCESS_COMPILE
3963