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: DIValue.cpp
6//
7
8//
9//*****************************************************************************
10#include "stdafx.h"
11#include "primitives.h"
12
13// copy from a MemoryRange to dest
14// Arguments:
15// input: source - MemoryRange describing the start address and size of the source buffer
16// output: dest - address of the buffer to which the source buffer is copied
17// Note: the buffer for dest must be allocated by the caller and must be large enough to hold the
18// bytes from the source buffer.
19void localCopy(void * dest, MemoryRange source)
20{
21 _ASSERTE(dest != NULL);
22 _ASSERTE(source.StartAddress() != NULL);
23
24 memcpy(dest, source.StartAddress(), source.Size());
25}
26
27// for an inheritance graph of the ICDValue types, // See file:./ICorDebugValueTypes.vsd for a diagram of the types.
28
29/* ------------------------------------------------------------------------- *
30 * CordbValue class
31 * ------------------------------------------------------------------------- */
32
33CordbValue::CordbValue(CordbAppDomain * appdomain,
34 CordbType * type,
35 CORDB_ADDRESS id,
36 bool isLiteral,
37 NeuterList * pList)
38 : CordbBase(
39 ((appdomain != NULL) ? (appdomain->GetProcess()) : (type->GetProcess())),
40 (UINT_PTR)id, enumCordbValue),
41 m_appdomain(appdomain),
42 m_type(type), // implicit InternalAddRef
43 //m_sigCopied(false),
44 m_size(0),
45 m_isLiteral(isLiteral)
46{
47 HRESULT hr = S_OK;
48
49 _ASSERTE(GetProcess() != NULL);
50
51 // Add to a neuter list. If none is provided, use the ExitProcess list as a default.
52 // The main neuter lists of interest here are:
53 // - CordbProcess::GetContinueNeuterList() - Shortest. Neuter when the process continues.
54 // - CordbAppDomain::GetExitNeuterList() - Middle. Neuter when the AD exits. Since most Values (except globals) are in
55 // a specific AD, this almost catches all; and keeps us safe in AD-unload scenarios.
56 // - CordbProcess::GetExitNeuterList() - Worst. Doesn't neuter until the process exits (or we detach).
57 // This could be a long time.
58 if (pList == NULL)
59 {
60 pList = GetProcess()->GetExitNeuterList();
61 }
62
63
64 EX_TRY
65 {
66 pList->Add(GetProcess(), this);
67 }
68 EX_CATCH_HRESULT(hr);
69 SetUnrecoverableIfFailed(GetProcess(), hr);
70} // CordbValue::CordbValue
71
72CordbValue::~CordbValue()
73{
74 DTOR_ENTRY(this);
75
76 _ASSERTE(this->IsNeutered());
77
78 _ASSERTE(m_type == NULL);
79} // CordbValue::~CordbValue
80
81void CordbValue::Neuter()
82{
83 m_appdomain = NULL;
84 m_type.Clear();
85
86 ValueHome * pValueHome = GetValueHome();
87 if (pValueHome != NULL)
88 {
89 pValueHome->Clear();
90 }
91 CordbBase::Neuter();
92} // CordbValue::Neuter
93
94// Helper for code:CordbValue::CreateValueByType. Create a new instance of CordbGenericValue
95// Arguments:
96// input: pAppdomain - appdomain to which the value belongs
97// pType - type of the value
98// remoteValue - remote address and size of the value
99// localValue - local address and size of the value
100// ppRemoteRegAddr - register address of the value
101// output: ppValue - the newly created instance of an ICDValue
102// Notes:
103// - only one of the three locations will be non-NULL
104// - Throws
105/* static */
106void CordbValue::CreateGenericValue(CordbAppDomain * pAppdomain,
107 CordbType * pType,
108 TargetBuffer remoteValue,
109 MemoryRange localValue,
110 EnregisteredValueHomeHolder * ppRemoteRegAddr,
111 ICorDebugValue** ppValue)
112{
113 LOG((LF_CORDB,LL_INFO100000,"CV::CreateValueByType CreateGenericValue\n"));
114 RSSmartPtr<CordbGenericValue> pGenValue;
115 // A generic value
116 // By using a RSSmartPtr we ensure that in both success and failure cases,
117 // this object is cleaned up properly (deleted or not depending on ref counts).
118 // Specifically, the object has probably been placed on a neuter list so we
119 // can't delete it (but this is a detail we shouldn't rely on)
120 pGenValue.Assign(new CordbGenericValue(pAppdomain,
121 pType,
122 remoteValue,
123 ppRemoteRegAddr));
124
125 pGenValue->Init(localValue); // throws
126
127 pGenValue->AddRef();
128 *ppValue = (ICorDebugValue *)(ICorDebugGenericValue *)pGenValue;
129} // CordbValue::CreateGenericValue
130
131// create a new instance of CordbVCObjectValue or CordbReferenceValue
132// Arguments:
133// input: pAppdomain - appdomain to which the value belongs
134// pType - type of the value
135// boxed - indicates whether the value is boxed
136// remoteValue - remote address and size of the value
137// localValue - local address and size of the value
138// ppRemoteRegAddr - register address of the value
139// output: ppValue - the newly created instance of an ICDValue
140// Notes:
141// - only one of the three locations will be non-NULL
142// - Throws error codes from reading process memory
143/* static */
144void CordbValue::CreateVCObjOrRefValue(CordbAppDomain * pAppdomain,
145 CordbType * pType,
146 bool boxed,
147 TargetBuffer remoteValue,
148 MemoryRange localValue,
149 EnregisteredValueHomeHolder * ppRemoteRegAddr,
150 ICorDebugValue** ppValue)
151
152{
153 HRESULT hr = S_OK;
154 LOG((LF_CORDB,LL_INFO1000000,"CV::CreateValueByType Creating ReferenceValue\n"));
155
156 // We either have a boxed or unboxed value type, or we have a value that's not a value type.
157 // For an unboxed value type, we'll create an instance of CordbVCObjectValue. Otherwise, we'll
158 // create an instance of CordbReferenceValue.
159
160 // do we have a value type?
161 bool isVCObject = pType->IsValueType(); // throws
162
163 if (!boxed && isVCObject)
164 {
165 RSSmartPtr<CordbVCObjectValue> pVCValue(new CordbVCObjectValue(pAppdomain,
166 pType,
167 remoteValue,
168 ppRemoteRegAddr));
169
170 IfFailThrow(pVCValue->Init(localValue));
171
172 pVCValue->AddRef();
173 *ppValue = (ICorDebugValue*)(ICorDebugObjectValue*)pVCValue;
174 }
175 else
176 {
177 // either the value is boxed or it's not a value type
178 RSSmartPtr<CordbReferenceValue> pRef;
179 hr = CordbReferenceValue::Build(pAppdomain,
180 pType,
181 remoteValue,
182 localValue,
183 VMPTR_OBJECTHANDLE::NullPtr(),
184 ppRemoteRegAddr, // Home
185 &pRef);
186 IfFailThrow(hr);
187 hr = pRef->QueryInterface(__uuidof(ICorDebugValue), (void**)ppValue);
188 _ASSERTE(SUCCEEDED(hr));
189 }
190} // CordbValue::CreateVCObjOrRefValue
191
192//
193// Create the proper ICDValue instance based on the given element type.
194// Arguments:
195// input: pAppdomain - appdomain to which the value belongs
196// pType - type of the value
197// boxed - indicates whether the value is boxed
198// remoteValue - remote address and size of the value
199// localValue - local address and size of the value
200// ppRemoteRegAddr - register address of the value
201// output: ppValue - the newly created instance of an ICDValue
202// Notes:
203// - Only one of the three locations, remoteValue, localValue or ppRemoteRegAddr, will be non-NULL.
204// - Throws.
205/*static*/ void CordbValue::CreateValueByType(CordbAppDomain * pAppdomain,
206 CordbType * pType,
207 bool boxed,
208 TargetBuffer remoteValue,
209 MemoryRange localValue,
210 EnregisteredValueHomeHolder * ppRemoteRegAddr,
211 ICorDebugValue** ppValue)
212{
213 INTERNAL_SYNC_API_ENTRY(pAppdomain->GetProcess()); //
214
215 // We'd really hope that our callers give us a valid appdomain, but in case
216 // they don't, we'll fail gracefully.
217 if ((pAppdomain != NULL) && pAppdomain->IsNeutered())
218 {
219 STRESS_LOG1(LF_CORDB, LL_EVERYTHING, "CVBT using neutered AP, %p\n", pAppdomain);
220 ThrowHR(E_INVALIDARG);
221 }
222
223 LOG((LF_CORDB,LL_INFO100000,"CV::CreateValueByType\n"));
224
225 *ppValue = NULL;
226
227 switch(pType->m_elementType)
228 {
229 case ELEMENT_TYPE_BOOLEAN:
230 case ELEMENT_TYPE_CHAR:
231 case ELEMENT_TYPE_I1:
232 case ELEMENT_TYPE_U1:
233 case ELEMENT_TYPE_I2:
234 case ELEMENT_TYPE_U2:
235 case ELEMENT_TYPE_I4:
236 case ELEMENT_TYPE_U4:
237 case ELEMENT_TYPE_R4:
238 case ELEMENT_TYPE_I8:
239 case ELEMENT_TYPE_U8:
240 case ELEMENT_TYPE_R8:
241 case ELEMENT_TYPE_I:
242 case ELEMENT_TYPE_U:
243 {
244 CreateGenericValue(pAppdomain, pType, remoteValue, localValue, ppRemoteRegAddr, ppValue); // throws
245 break;
246 }
247
248 case ELEMENT_TYPE_CLASS:
249 case ELEMENT_TYPE_OBJECT:
250 case ELEMENT_TYPE_STRING:
251 case ELEMENT_TYPE_PTR:
252 case ELEMENT_TYPE_BYREF:
253 case ELEMENT_TYPE_TYPEDBYREF:
254 case ELEMENT_TYPE_ARRAY:
255 case ELEMENT_TYPE_SZARRAY:
256 case ELEMENT_TYPE_FNPTR:
257 {
258 CreateVCObjOrRefValue(pAppdomain, pType, boxed, remoteValue, localValue, ppRemoteRegAddr, ppValue); // throws
259 break;
260 }
261
262 default:
263 _ASSERTE(!"Bad value type!");
264 ThrowHR(E_FAIL);
265 }
266} // CordbValue::CreateValueByType
267
268// Create the proper ICDValue instance based on the given remote heap object
269// Arguments:
270// pAppDomain - the app domain the remote object is in
271// vmObj - the remote object to get an ICDValue for
272ICorDebugValue* CordbValue::CreateHeapValue(CordbAppDomain* pAppDomain, VMPTR_Object vmObj)
273{
274 IDacDbiInterface* pDac = pAppDomain->GetProcess()->GetDAC();
275
276 TargetBuffer objBuffer = pDac->GetObjectContents(vmObj);
277 VOID* pRemoteAddr = CORDB_ADDRESS_TO_PTR(objBuffer.pAddress);
278 // This creates a local reference that has a remote address in it. Ie &pRemoteAddr is an address
279 // in the host address space and pRemoteAddr is an address in the target.
280 MemoryRange localReferenceDescription(&pRemoteAddr, sizeof(pRemoteAddr));
281 RSSmartPtr<CordbReferenceValue> pRefValue;
282 IfFailThrow(CordbReferenceValue::Build(pAppDomain,
283 NULL,
284 EMPTY_BUFFER,
285 localReferenceDescription,
286 VMPTR_OBJECTHANDLE::NullPtr(),
287 NULL,
288 &pRefValue));
289
290 // Dereference our temporary reference value to construct the heap value we want
291 ICorDebugValue* pExtValue;
292 IfFailThrow(pRefValue->Dereference(&pExtValue));
293 return pExtValue;
294}
295
296// Gets the size om bytes of a value from its type. If the value is complex, we assume it is represented as
297// a reference, since this is called for values that have been found on the stack, as an element of an
298// array (represented as CordbArrayValue) or field of an object (CordbObjectValue) or the result of a
299// func eval. For unboxed value types, we get the size of the entire value (it is not represented as a
300// reference).
301// Examples:
302// - int on the stack
303// => sizeof(int)
304// - int as a field in an object on the heap
305// =>sizeof(int)
306// - Boxed int on the heap
307// => size of a pointer
308// - Class Point { int x; int y}; // class will have a method table / object header which may increase size.
309// => size of a pointer
310// - Struct Point {int x; int y; }; // unboxed struct may not necessarily have the object header.
311// => 2 * sizeof(int)
312// - List<int>
313// => size of a pointer
314// Arguments: pType - the type of the value
315// boxing - indicates whether the value is boxed or not
316// Return Value: the size of the value
317// Notes: Throws
318// In general, this returns the unboxed size of the value, but if we have a type
319// that represents a non-generic and it's not an unboxed value type, we know that
320// it will be represented as a reference, so we return the size of a pointer instead.
321/* static */
322ULONG32 CordbValue::GetSizeForType(CordbType * pType, BoxedValue boxing)
323{
324 ULONG32 size = 0;
325
326 switch(pType->m_elementType)
327 {
328 case ELEMENT_TYPE_BOOLEAN:
329 case ELEMENT_TYPE_CHAR:
330 case ELEMENT_TYPE_I1:
331 case ELEMENT_TYPE_U1:
332 case ELEMENT_TYPE_I2:
333 case ELEMENT_TYPE_U2:
334 case ELEMENT_TYPE_I4:
335 case ELEMENT_TYPE_U4:
336 case ELEMENT_TYPE_R4:
337 case ELEMENT_TYPE_I8:
338 case ELEMENT_TYPE_U8:
339 case ELEMENT_TYPE_R8:
340 case ELEMENT_TYPE_I:
341 case ELEMENT_TYPE_U: pType->GetUnboxedObjectSize(&size); break;
342
343 case ELEMENT_TYPE_CLASS:
344 case ELEMENT_TYPE_OBJECT:
345 case ELEMENT_TYPE_STRING:
346 case ELEMENT_TYPE_PTR:
347 case ELEMENT_TYPE_BYREF:
348 case ELEMENT_TYPE_TYPEDBYREF:
349 case ELEMENT_TYPE_ARRAY:
350 case ELEMENT_TYPE_SZARRAY:
351 case ELEMENT_TYPE_FNPTR: {
352 bool isUnboxedVCObject = false;
353
354 if (boxing == kUnboxed)
355 {
356 isUnboxedVCObject = pType->IsValueType(); // throws
357 }
358 if (!isUnboxedVCObject)
359 {
360 // if it's not an unboxed value type (we're in the case
361 // for compound types), then it's a reference
362 // and we just want to return the size of a pointer
363 size = sizeof(void *);
364 }
365 else
366 {
367 pType->GetUnboxedObjectSize(&size);
368 }
369 } break;
370
371 default:
372 _ASSERTE(!"Bad value type!");
373}
374 return size;
375} // CordbValue::GetSizeForType
376
377
378HRESULT CordbValue::CreateBreakpoint(ICorDebugValueBreakpoint **ppBreakpoint)
379{
380 VALIDATE_POINTER_TO_OBJECT(ppBreakpoint, ICorDebugValueBreakpoint **);
381
382 return E_NOTIMPL;
383} // CordbValue::CreateBreakpoint
384
385// gets the exact type of a value
386// Arguments:
387// input: none (uses m_type field)
388// output: ppType - an instance of ICDType representing the exact type of the value
389// Return Value:
390HRESULT CordbValue::GetExactType(ICorDebugType **ppType)
391{
392 PUBLIC_REENTRANT_API_ENTRY(this);
393 VALIDATE_POINTER_TO_OBJECT(ppType, ICorDebugType **);
394 FAIL_IF_NEUTERED(this);
395
396 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
397
398 *ppType = static_cast<ICorDebugType*> (m_type);
399
400 if (*ppType != NULL)
401 (*ppType)->AddRef();
402
403 return S_OK;
404} // CordbValue::GetExactType
405
406// CreateHandle for a heap object.
407// @todo: How to prevent this being called by non-heap object?
408// Arguments:
409// input: handleType - type of the handle to be created
410// output: ppHandle - on success, the newly created handle
411// Return Value: S_OK on success or E_INVALIDARG, E_OUTOFMEMORY, or CORDB_E_HELPER_MAY_DEADLOCK
412HRESULT CordbValue::InternalCreateHandle(CorDebugHandleType handleType,
413 ICorDebugHandleValue ** ppHandle)
414{
415 INTERNAL_SYNC_API_ENTRY(GetProcess());
416 LOG((LF_CORDB,LL_INFO1000,"CV::CreateHandle\n"));
417
418 DebuggerIPCEvent event;
419 CordbProcess *process;
420 BOOL fStrong = FALSE;
421
422 // @dbgtodo- , as part of inspection, convert this path to throwing.
423 if (ppHandle == NULL)
424 {
425 return E_INVALIDARG;
426 }
427
428 *ppHandle = NULL;
429
430 if (handleType == HANDLE_STRONG)
431 {
432 fStrong = TRUE;
433 }
434 else
435 {
436 _ASSERTE(handleType == HANDLE_WEAK_TRACK_RESURRECTION);
437 }
438
439
440 // Create the ICorDebugHandleValue object
441 RSInitHolder<CordbHandleValue> pHandle(new (nothrow) CordbHandleValue(m_appdomain, m_type, handleType) );
442
443 if (pHandle == NULL)
444 {
445 return E_OUTOFMEMORY;
446 }
447
448 // Send the event to create the handle.
449 process = m_appdomain->GetProcess();
450 _ASSERTE(process != NULL);
451
452 process->InitIPCEvent(&event,
453 DB_IPCE_CREATE_HANDLE,
454 true,
455 m_appdomain->GetADToken());
456
457 CORDB_ADDRESS addr = GetValueHome() != NULL ? GetValueHome()->GetAddress() : NULL;
458 event.CreateHandle.objectToken = CORDB_ADDRESS_TO_PTR(addr);
459 event.CreateHandle.fStrong = fStrong;
460
461 // Note: two-way event here...
462 HRESULT hr = process->SendIPCEvent(&event, sizeof(DebuggerIPCEvent));
463 hr = WORST_HR(hr, event.hr);
464
465 if (SUCCEEDED(hr))
466 {
467 _ASSERTE(event.type == DB_IPCE_CREATE_HANDLE_RESULT);
468
469 // Initialize the handle value object.
470 hr = pHandle->Init(event.CreateHandleResult.vmObjectHandle);
471 }
472
473 if (!SUCCEEDED(hr))
474 {
475 // Free the handle from the left-side.
476 pHandle->Dispose();
477
478 // The RSInitHolder will neuter and delete it.
479 return hr;
480 }
481
482 // Pass out the new handle value object.
483 pHandle.TransferOwnershipExternal(ppHandle);
484
485 return S_OK;
486} // CordbValue::InternalCreateHandle
487
488/* ------------------------------------------------------------------------- *
489 * Generic Value class
490 * ------------------------------------------------------------------------- */
491
492//
493// CordbGenericValue constructor that builds a generic value from
494// a remote address or register.
495// Arguments:
496// input: pAppdomain - the app domain to which the value belongs
497// pType - the type of the value
498// remoteValue - buffer (and size) of the remote location where
499// the value resides. This may be NULL if the value
500// is enregistered.
501// ppRemoteRegAddr - information describing the register in which the
502// value resides. This may be NULL--only one of
503// ppRemoteRegAddr and remoteValue will be non-NULL,
504// depending on whether the value is in a register or
505// memory.
506CordbGenericValue::CordbGenericValue(CordbAppDomain * pAppdomain,
507 CordbType * pType,
508 TargetBuffer remoteValue,
509 EnregisteredValueHomeHolder * ppRemoteRegAddr)
510 : CordbValue(pAppdomain, pType, remoteValue.pAddress, false),
511 m_pValueHome(NULL)
512{
513 _ASSERTE(pType->m_elementType != ELEMENT_TYPE_END);
514 _ASSERTE(pType->m_elementType != ELEMENT_TYPE_VOID);
515 _ASSERTE(pType->m_elementType < ELEMENT_TYPE_MAX);
516
517 // We can fill in the size now for generic values.
518 ULONG32 size;
519 HRESULT hr;
520 hr = pType->GetUnboxedObjectSize(&size);
521 _ASSERTE (!FAILED(hr));
522 m_size = size;
523
524 // now instantiate the value home
525 NewHolder<ValueHome> pHome(NULL);
526 if (remoteValue.IsEmpty())
527 {
528 pHome = (new RegisterValueHome(pAppdomain->GetProcess(), ppRemoteRegAddr));
529 }
530 else
531 {
532 pHome = (new RemoteValueHome(pAppdomain->GetProcess(), remoteValue));
533 }
534 m_pValueHome = pHome.GetValue(); // throws
535 pHome.SuppressRelease();
536} // CordbGenericValue::CordbGenericValue
537
538//
539// CordbGenericValue constructor that builds an empty generic value
540// from just an element type. Used for literal values for func evals
541// only.
542// Arguments:
543// input: pType - the type of the value
544CordbGenericValue::CordbGenericValue(CordbType * pType)
545 : CordbValue(NULL, pType, NULL, true),
546 m_pValueHome(NULL)
547{
548 // The only purpose of a literal value is to hold a RS literal value.
549 ULONG32 size;
550 HRESULT hr;
551 hr = pType->GetUnboxedObjectSize(&size);
552 _ASSERTE (!FAILED(hr));
553 m_size = size;
554
555 memset(m_pCopyOfData, 0, m_size);
556
557 // there is no value home for a literal so we leave it as NULL
558} // CordbGenericValue::CordbGenericValue
559
560// destructor
561CordbGenericValue::~CordbGenericValue()
562{
563 if (m_pValueHome != NULL)
564 {
565 delete m_pValueHome;
566 m_pValueHome = NULL;
567}
568} // CordbGenericValue::~CordbGenericValue
569
570HRESULT CordbGenericValue::QueryInterface(REFIID id, void **pInterface)
571{
572 if (id == IID_ICorDebugValue)
573 {
574 *pInterface = static_cast<ICorDebugValue*>(static_cast<ICorDebugGenericValue*>(this));
575 }
576 else if (id == IID_ICorDebugValue2)
577 {
578 *pInterface = static_cast<ICorDebugValue2*>(this);
579 }
580 else if (id == IID_ICorDebugValue3)
581 {
582 *pInterface = static_cast<ICorDebugValue3*>(this);
583 }
584 else if (id == IID_ICorDebugGenericValue)
585 {
586 *pInterface = static_cast<ICorDebugGenericValue*>(this);
587 }
588 else if (id == IID_IUnknown)
589 {
590 *pInterface = static_cast<IUnknown*>(static_cast<ICorDebugGenericValue*>(this));
591 }
592 else
593 {
594 *pInterface = NULL;
595 return E_NOINTERFACE;
596 }
597
598 ExternalAddRef();
599 return S_OK;
600} // CordbGenericValue::QueryInterface
601
602//
603// initialize a generic value by copying the necessary data, either
604// from the remote process or from another value in this process.
605// Argument:
606// input: localValue - RS location of value to be copied. This could be NULL or it
607// could be a field from the cached copy of a CordbVCObjectValue or CordbObjectValue
608// instance or an element from the cached copy of a CordbArrayValue instance
609// Note: Throws error codes from reading process memory
610void CordbGenericValue::Init(MemoryRange localValue)
611{
612 INTERNAL_SYNC_API_ENTRY(this->GetProcess());
613
614 if(!m_isLiteral)
615 {
616 // If neither localValue.StartAddress nor m_remoteValue.pAddress are set, then all that means
617 // is that we've got a pre-initialized 64-bit value.
618 if (localValue.StartAddress() != NULL)
619 {
620 // Copy the data out of the local address space.
621 localCopy(m_pCopyOfData, localValue);
622 }
623 else
624 {
625 m_pValueHome->GetValue(MemoryRange(m_pCopyOfData, m_size)); // throws
626 }
627 }
628} // CordbGenericValue::Init
629
630// gets the value (i.e., number, boolean or pointer value) for this instance of CordbGenericValue
631// Arguments:
632// output: pTo - the starting address of a buffer in which the value will be written. This buffer must
633// be guaranteed by the caller to be large enough to hold the value. There is no way for
634// us to check here if it is. This must be non-NULL.
635// Return Value: S_OK on success or E_INVALIDARG if the pTo is NULL
636HRESULT CordbGenericValue::GetValue(void *pTo)
637{
638 PUBLIC_REENTRANT_API_ENTRY(this);
639 FAIL_IF_NEUTERED(this);
640 VALIDATE_POINTER_TO_OBJECT_ARRAY(pTo, BYTE, m_size, false, true);
641
642 _ASSERTE(m_pCopyOfData != NULL);
643 // Copy out the value
644 memcpy(pTo, m_pCopyOfData, m_size);
645
646 return S_OK;
647} // CordbGenericValue::GetValue
648
649// Sets the value of this instance of CordbGenericValue
650// Arguments:
651// input: pFrom - pointer to a buffer holding the new value. We assume this is the same size as the
652// original value; we have no way to check. This must be non-NULL.
653// Return Value: S_OK on success or E_INVALIDARG if the pFrom is NULL
654HRESULT CordbGenericValue::SetValue(void *pFrom)
655{
656 HRESULT hr = S_OK;
657 PUBLIC_REENTRANT_API_ENTRY(this);
658 FAIL_IF_NEUTERED(this);
659 VALIDATE_POINTER_TO_OBJECT_ARRAY(pFrom, BYTE, m_size, true, false);
660 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
661
662 // We only need to send to the left side to update values that are
663 // object references. For generic values, we can simply do a write
664 // memory.
665
666 EX_TRY
667 {
668 if(!m_isLiteral)
669 {
670 m_pValueHome->SetValue(MemoryRange(pFrom, m_size), m_type); // throws
671 }
672 }
673 EX_CATCH_HRESULT(hr);
674 IfFailRet(hr);
675
676 // That worked, so update the copy of the value we have in
677 // m_copyOfData.
678 memcpy(m_pCopyOfData, pFrom, m_size);
679
680 return hr;
681} // CordbGenericValue::SetValue
682
683// copies the value from this instance of CordbGenericValue iff the value represents a literal
684// Arguments:
685// output: pBuffer - pointer to the beginning of a caller-allocated buffer.This buffer must
686// be guaranteed by the caller to be large enough to hol
687// d the value. There is no way for
688// us to check here if it is. This must be non-NULL.
689// Return Value: true iff this is a literal value and pBuffer is a valid writeable address
690bool CordbGenericValue::CopyLiteralData(BYTE *pBuffer)
691{
692 INTERNAL_SYNC_API_ENTRY(this->GetProcess());
693 _ASSERTE(pBuffer != NULL);
694
695 // If this is a RS fabrication, copy the literal data into the
696 // given buffer and return true.
697 if (m_isLiteral)
698 {
699 _ASSERTE(m_size <= 8);
700 memcpy(pBuffer, m_pCopyOfData, m_size);
701 return true;
702 }
703 else
704 return false;
705} // CordbGenericValue::CopyLiteralData
706
707/* ------------------------------------------------------------------------- *
708 * Reference Value class
709 * ------------------------------------------------------------------------- */
710
711// constructor
712// Arguments:
713// input: pAppdomain - appdomain to which the value belongs
714// pType - the type of the referent (the object pointed to)
715// localValue - the RS address and size of the buffer from which the reference
716// will be copied. This will be NULL if either remoteValue,
717// ppRemoteRegAddr or vmObjectHandle is non-NULL. Otherwise, it will
718// point into the local cached copy of another instance of ICDValue
719// remoteValue - the LS address and size of the buffer from which the reference
720// will be copied. This will be NULL if either localValue,
721// ppRemoteRegAddr, or vmObjectHandle is non-NULL.
722// ppRemoteRegAddr - information about the register location of the buffer from which
723// the reference will be copied. This will be NULL if either localValue,
724// remoteValue, or vmObjectHandle is non-NULL.
725// vmObjectHandle - a LS object handle holding the reference. This will be NULL if either
726// localValue, remoteValue, or ppRemoteRegAddr is non-NULL.
727// Note: this may throw OOM
728CordbReferenceValue::CordbReferenceValue(CordbAppDomain * pAppdomain,
729 CordbType * pType,
730 MemoryRange localValue,
731 TargetBuffer remoteValue,
732 EnregisteredValueHomeHolder * ppRemoteRegAddr,
733 VMPTR_OBJECTHANDLE vmObjectHandle)
734 : CordbValue(pAppdomain, pType, remoteValue.pAddress, false,
735 // We'd like to change this to be a ContinueList so it gets neutered earlier,
736 // but it may be a breaking change
737 pAppdomain->GetSweepableExitNeuterList()),
738
739 m_realTypeOfTypedByref(NULL)
740{
741 memset(&m_info, 0, sizeof(m_info));
742
743 LOG((LF_CORDB,LL_EVERYTHING,"CRV::CRV: this:0x%x\n",this));
744 m_size = sizeof(void *);
745
746 // now instantiate the value home
747 NewHolder<ValueHome> pHome(NULL);
748
749 if (!vmObjectHandle.IsNull())
750 {
751 pHome = (new HandleValueHome(pAppdomain->GetProcess(), vmObjectHandle));
752 m_valueHome.SetObjHandleFlag(false);
753 }
754
755 else if (remoteValue.IsEmpty())
756 {
757 pHome = (new RegisterValueHome(pAppdomain->GetProcess(), ppRemoteRegAddr));
758 m_valueHome.SetObjHandleFlag(true);
759
760 }
761 else
762 {
763 pHome = (new RefRemoteValueHome(pAppdomain->GetProcess(), remoteValue));
764}
765 m_valueHome.m_pHome = pHome.GetValue(); // throws
766 pHome.SuppressRelease();
767} // CordbReferenceValue::CordbReferenceValue
768
769// CordbReferenceValue constructor that builds an empty reference value
770// from just an element type. Used for literal values for func evals
771// only.
772// Arguments:
773// input: pType - the type of the value
774CordbReferenceValue::CordbReferenceValue(CordbType * pType)
775 : CordbValue(NULL, pType, NULL, true, pType->GetAppDomain()->GetSweepableExitNeuterList())
776{
777 memset(&m_info, 0, sizeof(m_info));
778
779 // The only purpose of a literal value is to hold a RS literal value.
780 m_size = sizeof(void*);
781
782 // there is no value home for a literal
783 m_valueHome.m_pHome = NULL;
784} // CordbReferenceValue::CordbReferenceValue
785
786// copies the value from this instance of CordbReferenceValue iff the value represents a literal
787// Arguments:
788// output: pBuffer - pointer to the beginning of a caller-allocated buffer.This buffer must
789// be guaranteed by the caller to be large enough to hold the value.
790// There is no way for us to check here if it is. This must be non-NULL.
791// Return Value: true iff this is a literal value and pBuffer is a valid writeable address
792bool CordbReferenceValue::CopyLiteralData(BYTE *pBuffer)
793{
794 _ASSERTE(pBuffer != NULL);
795
796 // If this is a RS fabrication, then its a null reference.
797 if (m_isLiteral)
798 {
799 void *n = NULL;
800 memcpy(pBuffer, &n, sizeof(n));
801 return true;
802 }
803 else
804 return false;
805} // CordbReferenceValue::CopyLiteralData
806
807// destructor
808CordbReferenceValue::~CordbReferenceValue()
809{
810 DTOR_ENTRY(this);
811
812 LOG((LF_CORDB,LL_EVERYTHING,"CRV::~CRV: this:0x%x\n",this));
813
814 _ASSERTE(IsNeutered());
815} // CordbReferenceValue::~CordbReferenceValue
816
817void CordbReferenceValue::Neuter()
818{
819 if (m_valueHome.m_pHome != NULL)
820 {
821 m_valueHome.m_pHome->Clear();
822 delete m_valueHome.m_pHome;
823 m_valueHome.m_pHome = NULL;
824 }
825
826 m_realTypeOfTypedByref = NULL;
827 CordbValue::Neuter();
828} // CordbReferenceValue::Neuter
829
830
831HRESULT CordbReferenceValue::QueryInterface(REFIID id, void **pInterface)
832{
833 if (id == IID_ICorDebugValue)
834 {
835 *pInterface = static_cast<ICorDebugValue*>(static_cast<ICorDebugReferenceValue*>(this));
836 }
837 else if (id == IID_ICorDebugValue2)
838 {
839 *pInterface = static_cast<ICorDebugValue2*>(this);
840 }
841 else if (id == IID_ICorDebugValue3)
842 {
843 *pInterface = static_cast<ICorDebugValue3*>(this);
844 }
845 else if (id == IID_ICorDebugReferenceValue)
846 {
847 *pInterface = static_cast<ICorDebugReferenceValue*>(this);
848 }
849 else if (id == IID_IUnknown)
850 {
851 *pInterface = static_cast<IUnknown*>(static_cast<ICorDebugReferenceValue*>(this));
852 }
853 else
854 {
855 *pInterface = NULL;
856 return E_NOINTERFACE;
857 }
858
859 ExternalAddRef();
860 return S_OK;
861} // CordbReferenceValue::QueryInterface
862
863// gets the type of the referent of the object ref
864// Arguments:
865// output: pType - the type of the value. The caller must guarantee that pType is non-null.
866// Return Value: S_OK on success, E_INVALIDARG on failure
867HRESULT CordbReferenceValue::GetType(CorElementType *pType)
868{
869 LIMITED_METHOD_CONTRACT;
870
871 FAIL_IF_NEUTERED(this);
872 VALIDATE_POINTER_TO_OBJECT(pType, CorElementType *);
873
874 if( m_type == NULL )
875 {
876 // We may not have a CordbType if we were created from a GC handle to NULL
877 _ASSERTE( m_info.objTypeData.elementType == ELEMENT_TYPE_CLASS );
878 _ASSERTE(!m_valueHome.ObjHandleIsNull());
879 _ASSERTE( m_info.objRef == NULL );
880 *pType = m_info.objTypeData.elementType;
881 }
882 else
883 {
884 // The element type stored in both places should match
885 _ASSERTE( m_info.objTypeData.elementType == m_type->m_elementType );
886 *pType = m_type->m_elementType;
887 }
888
889 return S_OK;
890} // CordbReferenceValue::GetType
891
892// gets the remote (LS) address of the reference. This may return NULL if the
893// reference is a literal or resides in a register.
894// Arguments:
895// output: pAddress - the LS location of the reference. The caller must guarantee pAddress is non-null,
896// but the contents may be null after the call if the reference is enregistered or is
897// the value of a field or element of some other Cordb*Value instance.
898// Return Value: S_OK on success or E_INVALIDARG if pAddress is null
899HRESULT CordbReferenceValue::GetAddress(CORDB_ADDRESS *pAddress)
900{
901 PUBLIC_REENTRANT_API_ENTRY(this);
902 VALIDATE_POINTER_TO_OBJECT(pAddress, CORDB_ADDRESS *);
903
904 *pAddress = m_valueHome.m_pHome ? m_valueHome.m_pHome->GetAddress() : NULL;
905 return (S_OK);
906}
907
908// Determines whether the reference is null
909// Arguments:
910// output - pfIsNull - pointer to a BOOL that will be set to true iff this represents a
911// null reference
912// Return Value: S_OK on success or E_INVALIDARG if pfIsNull is null
913HRESULT CordbReferenceValue::IsNull(BOOL * pfIsNull)
914{
915 PUBLIC_REENTRANT_API_ENTRY(this);
916 FAIL_IF_NEUTERED(this);
917 VALIDATE_POINTER_TO_OBJECT(pfIsNull, BOOL *);
918
919 if (m_isLiteral || (m_info.objRef == NULL))
920 *pfIsNull = TRUE;
921 else
922 *pfIsNull = FALSE;
923
924 return S_OK;
925}
926
927// gets the value (object address) of this CordbReferenceValue
928// Arguments:
929// output: pTo - reference value
930// Return Value: S_OK on success or E_INVALIDARG if pAddress is null
931HRESULT CordbReferenceValue::GetValue(CORDB_ADDRESS *pAddress)
932{
933 PUBLIC_REENTRANT_API_ENTRY(this);
934 VALIDATE_POINTER_TO_OBJECT(pAddress, CORDB_ADDRESS *);
935 FAIL_IF_NEUTERED(this);
936
937 // Copy out the value, which is simply the value the object reference.
938 if (m_isLiteral)
939 *pAddress = NULL;
940 else
941 *pAddress = PTR_TO_CORDB_ADDRESS(m_info.objRef);
942
943 return S_OK;
944}
945
946// sets the value of the reference
947// Arguments:
948// input: address - the new reference--this must be a LS address
949// Return Value: S_OK on success or E_INVALIDARG or write process memory errors
950// Note: We make no effort to ensure that the new reference is of the same type as the old one.
951// We simply assume it is. As long as this assumption is correct, we only need to update information about
952// the referent if it's a string (its length can change).
953
954// @dbgtodo Microsoft inspection: consider whether it's worthwhile to verify that the type of the new referent is
955// the same as the type of the existing one. We'd have to do most of the work for a call to InitRef to do
956// this, since we need to know the type of the new referent.
957HRESULT CordbReferenceValue::SetValue(CORDB_ADDRESS address)
958{
959 PUBLIC_API_ENTRY(this);
960 FAIL_IF_NEUTERED(this);
961 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
962 HRESULT hr = S_OK;
963
964 // If this is a heap object, ideally we'd prevent violations of AppDomain isolation
965 // here. However, we have no reliable way of determining what AppDomain the address is in.
966
967 // Can't change literal refs.
968 if (m_isLiteral)
969 {
970 return E_INVALIDARG;
971 }
972
973 // Either we know the type, or it's a handle to a null value
974 _ASSERTE((m_type != NULL) ||
975 (!m_valueHome.ObjHandleIsNull() && (m_info.objRef == NULL)));
976
977 EX_TRY
978 {
979 m_valueHome.m_pHome->SetValue(MemoryRange(&address, sizeof(void *)), m_type); // throws
980 }
981 EX_CATCH_HRESULT(hr);
982
983 if (SUCCEEDED(hr))
984 {
985 // That worked, so update the copy of the value we have in
986 // our local cache.
987 m_info.objRef = CORDB_ADDRESS_TO_PTR(address);
988
989
990 if (m_info.objTypeData.elementType == ELEMENT_TYPE_STRING)
991 {
992 // update information about the string
993 InitRef(MemoryRange(&m_info.objRef, sizeof (void *)));
994 }
995
996 // All other data in m_info is no longer valid, and we may have invalidated other
997 // ICDRVs at this address. We have to invalidate all cached debuggee data.
998 m_appdomain->GetProcess()->m_continueCounter++;
999 }
1000
1001 return hr;
1002} // CordbReferenceValue::SetValue
1003
1004HRESULT CordbReferenceValue::DereferenceStrong(ICorDebugValue **ppValue)
1005{
1006 return E_NOTIMPL;
1007}
1008
1009// Get a new ICDValue instance to represent the referent of this object ref.
1010// Arguments:
1011// output: ppValue - the new ICDValue instance
1012// Return Value: S_OK on success or E_INVALIDARG
1013HRESULT CordbReferenceValue::Dereference(ICorDebugValue **ppValue)
1014{
1015 PUBLIC_REENTRANT_API_ENTRY(this);
1016 FAIL_IF_NEUTERED(this);
1017
1018 // Can't dereference literal refs.
1019 if (m_isLiteral)
1020 return E_INVALIDARG;
1021
1022 VALIDATE_POINTER_TO_OBJECT(ppValue, ICorDebugValue **);
1023 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
1024
1025 HRESULT hr = S_OK;
1026
1027 if (m_continueCounterLastSync != m_appdomain->GetProcess()->m_continueCounter)
1028 {
1029 IfFailRet(InitRef(MemoryRange(NULL, 0)));
1030 }
1031
1032 EX_TRY
1033 {
1034 // We may know ahead of time (depending on the reference type) if
1035 // the reference is bad.
1036 if ((m_info.objRefBad) || (m_info.objRef == NULL))
1037 {
1038 ThrowHR(CORDBG_E_BAD_REFERENCE_VALUE);
1039 }
1040
1041 hr = DereferenceCommon(m_appdomain, m_type, m_realTypeOfTypedByref, &m_info, ppValue);
1042 }
1043 EX_CATCH_HRESULT(hr);
1044 return hr;
1045
1046}
1047
1048//-----------------------------------------------------------------------------
1049// Common helper to dereferefence.
1050// Parameters:
1051// pAppDomain, pType, pInfo - necessary paramters to create the value
1052// pRealTypeOfTypedByref - type for a potential TypedByRef. Can be NULL if we know
1053// that we're not a typed-byref (this is true if we're definitely an object handle)
1054// ppValue - outparameter for newly created value. This will get an Ext AddRef.
1055//-----------------------------------------------------------------------------
1056HRESULT CordbReferenceValue::DereferenceCommon(
1057 CordbAppDomain * pAppDomain,
1058 CordbType * pType,
1059 CordbType * pRealTypeOfTypedByref,
1060 DebuggerIPCE_ObjectData * pInfo,
1061 ICorDebugValue **ppValue
1062)
1063{
1064 INTERNAL_SYNC_API_ENTRY(pAppDomain->GetProcess());
1065
1066 // pCachedObject may be NULL if we're not caching.
1067 _ASSERTE(pType != NULL);
1068 _ASSERTE(pAppDomain != NULL);
1069 _ASSERTE(pInfo != NULL);
1070 _ASSERTE(ppValue != NULL);
1071
1072 HRESULT hr = S_OK;
1073 *ppValue = NULL; // just to be safe.
1074
1075 switch(pType->m_elementType)
1076 {
1077 case ELEMENT_TYPE_CLASS:
1078 case ELEMENT_TYPE_OBJECT:
1079 case ELEMENT_TYPE_STRING:
1080 {
1081 LOG((LF_CORDB, LL_INFO1000, "DereferenceInternal: type class/object/string\n"));
1082 // An object value (possibly a string value, too.) If the class of this object is a value class,
1083 // then we have a reference to a boxed object. So we create a box instead of an object value.
1084 bool isBoxedVCObject = false;
1085
1086 if ((pType->m_pClass != NULL) && (pType->m_elementType != ELEMENT_TYPE_STRING))
1087 {
1088 EX_TRY
1089 {
1090 isBoxedVCObject = pType->m_pClass->IsValueClass();
1091 }
1092 EX_CATCH_HRESULT(hr);
1093 if (FAILED(hr))
1094 {
1095 return hr;
1096 }
1097 }
1098
1099 if (isBoxedVCObject)
1100 {
1101 TargetBuffer remoteValue(PTR_TO_CORDB_ADDRESS(pInfo->objRef), (ULONG)pInfo->objSize);
1102 EX_TRY
1103 {
1104 RSSmartPtr<CordbBoxValue> pBoxValue(new CordbBoxValue(
1105 pAppDomain,
1106 pType,
1107 remoteValue,
1108 (ULONG32)pInfo->objSize,
1109 pInfo->objOffsetToVars));
1110 pBoxValue->ExternalAddRef();
1111 *ppValue = (ICorDebugValue*)(ICorDebugBoxValue*)pBoxValue;
1112 }
1113 EX_CATCH_HRESULT(hr);
1114 }
1115 else
1116 {
1117 RSSmartPtr<CordbObjectValue> pObj;
1118 TargetBuffer remoteValue(PTR_TO_CORDB_ADDRESS(pInfo->objRef), (ULONG)pInfo->objSize);
1119 // Note: we call Init() by default when we create (or refresh) a reference value, so we
1120 // never have to do it again.
1121 EX_TRY
1122 {
1123 pObj.Assign(new CordbObjectValue(pAppDomain, pType, remoteValue, pInfo));
1124 IfFailThrow(pObj->Init());
1125
1126 pObj->ExternalAddRef();
1127 *ppValue = static_cast<ICorDebugValue*>( static_cast<ICorDebugObjectValue*>(pObj) );
1128 }
1129 EX_CATCH_HRESULT(hr);
1130 } // boxed?
1131
1132 break;
1133 }
1134
1135 case ELEMENT_TYPE_ARRAY:
1136 case ELEMENT_TYPE_SZARRAY:
1137 {
1138 LOG((LF_CORDB, LL_INFO1000, "DereferenceInternal: type array/szarray\n"));
1139 TargetBuffer remoteValue(PTR_TO_CORDB_ADDRESS(pInfo->objRef), (ULONG)pInfo->objSize); // sizeof(void *)?
1140 EX_TRY
1141 {
1142 RSSmartPtr<CordbArrayValue> pArrayValue(new CordbArrayValue(
1143 pAppDomain,
1144 pType,
1145 pInfo,
1146 remoteValue));
1147
1148 IfFailThrow(pArrayValue->Init());
1149
1150 pArrayValue->ExternalAddRef();
1151 *ppValue = (ICorDebugValue*)(ICorDebugArrayValue*)pArrayValue;
1152 }
1153 EX_CATCH_HRESULT(hr);
1154
1155 break;
1156 }
1157
1158 case ELEMENT_TYPE_BYREF:
1159 case ELEMENT_TYPE_PTR:
1160 {
1161 //_ASSERTE(pInfo->objToken.IsNull()); // can't get this type w/ an object handle
1162
1163 LOG((LF_CORDB, LL_INFO1000, "DereferenceInternal: type byref/ptr\n"));
1164 CordbType *ptrType;
1165 pType->DestUnaryType(&ptrType);
1166
1167 CorElementType et = ptrType->m_elementType;
1168
1169 if (et == ELEMENT_TYPE_VOID)
1170 {
1171 *ppValue = NULL;
1172 return CORDBG_S_VALUE_POINTS_TO_VOID;
1173 }
1174
1175 TargetBuffer remoteValue(pInfo->objRef, GetSizeForType(ptrType, kUnboxed));
1176 // Create a value for what this reference points to. Note:
1177 // this could be almost any type of value.
1178 EX_TRY
1179 {
1180 CordbValue::CreateValueByType(
1181 pAppDomain,
1182 ptrType,
1183 false,
1184 remoteValue,
1185 MemoryRange(NULL, 0), // local value
1186 NULL,
1187 ppValue); // throws
1188 }
1189 EX_CATCH_HRESULT(hr);
1190
1191 break;
1192 }
1193
1194 case ELEMENT_TYPE_TYPEDBYREF:
1195 {
1196 //_ASSERTE(pInfo->objToken.IsNull()); // can't get this type w/ an object handle
1197 _ASSERTE(pRealTypeOfTypedByref != NULL);
1198
1199 LOG((LF_CORDB, LL_INFO1000, "DereferenceInternal: type typedbyref\n"));
1200
1201 TargetBuffer remoteValue(pInfo->objRef, sizeof(void *));
1202 // Create the value for what this reference points
1203 // to.
1204 EX_TRY
1205 {
1206 CordbValue::CreateValueByType(
1207 pAppDomain,
1208 pRealTypeOfTypedByref,
1209 false,
1210 remoteValue,
1211 MemoryRange(NULL, 0), // local value
1212 NULL,
1213 ppValue); // throws
1214 }
1215 EX_CATCH_HRESULT(hr);
1216
1217 break;
1218 }
1219
1220 case ELEMENT_TYPE_FNPTR:
1221 // Function pointers cannot be dereferenced; only the pointer value itself
1222 // may be inspected--not what it points to.
1223 *ppValue = NULL;
1224 return CORDBG_E_VALUE_POINTS_TO_FUNCTION;
1225
1226 default:
1227 LOG((LF_CORDB, LL_INFO1000, "DereferenceInternal: Fail!\n"));
1228 _ASSERTE(!"Bad reference type!");
1229 hr = E_FAIL;
1230 break;
1231 }
1232
1233 return hr;
1234}
1235
1236// static helper to build a CordbReferenceValue from a general variable home.
1237// We can find the CordbType from the object instance.
1238HRESULT CordbReferenceValue::Build(CordbAppDomain * appdomain,
1239 CordbType * type,
1240 TargetBuffer remoteValue,
1241 MemoryRange localValue,
1242 VMPTR_OBJECTHANDLE vmObjectHandle,
1243 EnregisteredValueHomeHolder * ppRemoteRegAddr,
1244 CordbReferenceValue** ppValue)
1245{
1246 HRESULT hr = S_OK;
1247
1248 // We can find the AD from an object handle (but not a normal object), so the AppDomain may
1249 // be NULL if if it's an OH.
1250 //_ASSERTE((appdomain != NULL) || objectRefsInHandles);
1251
1252 // A reference, possibly to an object or value class
1253 // Weak by default
1254 EX_TRY
1255 {
1256 RSSmartPtr<CordbReferenceValue> pRefValue(new CordbReferenceValue(appdomain,
1257 type,
1258 localValue,
1259 remoteValue,
1260 ppRemoteRegAddr,
1261 vmObjectHandle));
1262 IfFailThrow(pRefValue->InitRef(localValue));
1263
1264 pRefValue->InternalAddRef();
1265 *ppValue = pRefValue;
1266 }
1267 EX_CATCH_HRESULT(hr)
1268 return hr;
1269}
1270
1271//-----------------------------------------------------------------------------
1272// Static helper to build a CordbReferenceValue from a GCHandle
1273// The LS can actually determine an AppDomain from an OBJECTHandles, however, the RS
1274// should already have this infromation too, so we pass it in.
1275// We also supply the AppDomain here because it provides the CordbValue with
1276// process affinity.
1277// Note that the GC handle may point to a NULL reference, in which case we should still create
1278// an appropriate ICorDebugReferenceValue for which IsNull returns TRUE.
1279//-----------------------------------------------------------------------------
1280HRESULT CordbReferenceValue::BuildFromGCHandle(
1281 CordbAppDomain *pAppDomain,
1282 VMPTR_OBJECTHANDLE gcHandle,
1283 ICorDebugReferenceValue ** pOutRef
1284)
1285{
1286 _ASSERTE(pAppDomain != NULL);
1287 _ASSERTE(pOutRef != NULL);
1288
1289 CordbProcess * pProc;
1290 pProc = pAppDomain->GetProcess();
1291 INTERNAL_SYNC_API_ENTRY(pProc);
1292
1293 HRESULT hr = S_OK;
1294
1295 *pOutRef = NULL;
1296
1297 // Make sure we even have a GC handle.
1298 // Also, We may have a handle, but its contents may be null.
1299 if (gcHandle.IsNull())
1300 {
1301 // We've seen this assert fire in the wild, but have never gotten a repro.
1302 // so we'll include a runtime check to avoid the AV.
1303 _ASSERTE(false || !"We got a bad reference value.");
1304 return CORDBG_E_BAD_REFERENCE_VALUE;
1305 }
1306
1307 // Now that we've got an AppDomain, we can go ahead and create the reference value normally.
1308
1309 RSSmartPtr<CordbReferenceValue> pRefValue;
1310 TargetBuffer remoteValue;
1311 EX_TRY
1312 {
1313 remoteValue.Init(pProc->GetDAC()->GetHandleAddressFromVmHandle(gcHandle), sizeof(void *));
1314 }
1315 EX_CATCH_HRESULT(hr);
1316 IfFailRet(hr);
1317
1318 hr = CordbReferenceValue::Build(
1319 pAppDomain,
1320 NULL, // unknown type
1321 remoteValue, // CORDB_ADDRESS remoteAddress,
1322 MemoryRange(NULL, 0),
1323 gcHandle, // objectRefsInHandles,
1324 NULL, // EnregisteredValueHome * pRemoteRegAddr,
1325 &pRefValue);
1326
1327 if (SUCCEEDED(hr))
1328 {
1329 pRefValue->QueryInterface(__uuidof(ICorDebugReferenceValue), (void**)pOutRef);
1330 }
1331
1332 return hr;
1333}
1334
1335// Helper function for SanityCheckPointer. Make an attempt to read memory at the address which is the value
1336// of the reference.
1337// Arguments: none
1338// Notes:
1339// - Throws
1340// - m_info.objRefBad must be set to true before calling this function. If we throw, we'll
1341// never end up setting m_info.objRefBad, but throwing indicates that the reference is
1342// indeed bad. Only if we exit normally will we end up setting m_info.objRefBad to false.
1343void CordbReferenceValue::TryDereferencingTarget()
1344{
1345 _ASSERTE(!!m_info.objRefBad == true);
1346 // First get the referent type
1347 CordbType * pReferentType;
1348 m_type->DestUnaryType(&pReferentType);
1349
1350 // Next get the size
1351 ULONG32 dataSize, sizeToRead;
1352 IfFailThrow(pReferentType->GetUnboxedObjectSize(&dataSize));
1353 if (dataSize <= 0)
1354 sizeToRead = 1; // Read at least one byte.
1355 else if (dataSize >= 8)
1356 sizeToRead = 8; // Read at most eight bytes--this is just a perf improvement. Even if we read
1357 // all the bytes, we are only able to determine that we can read those bytes,
1358 // we can't really tell if the data we are reading is actually the data we
1359 // want.
1360 else sizeToRead = dataSize;
1361
1362 // Now see if we can read from the address where the object is supposed to be
1363 BYTE dummy[8];
1364
1365 // Get a target buffer with the remote address and size of the object--since we don't know if the
1366 // address if valid, this could throw or return a size that's complete garbage
1367 TargetBuffer object(m_info.objRef, sizeToRead);
1368
1369 // now read target memory. This may throw ...
1370 GetProcess()->SafeReadBuffer(object, dummy);
1371
1372} // CordbReferenceValue::TryDereferencingTarget
1373
1374// Do a sanity check on the pointer which is the value of the object reference. We can't efficiently ensure that
1375// the pointer is really good, so we settle for a quick check just to make sure the memory at the address is
1376// readable. We're actually just checking that we can dereference the pointer.
1377// Arguments:
1378// input: type - the type of the pointer to which the object reference points.
1379// output: none, but fills in m_info.objRefBad
1380// Note: Throws
1381void CordbReferenceValue::SanityCheckPointer (CorElementType type)
1382{
1383 m_info.objRefBad = TRUE;
1384 if (type != ELEMENT_TYPE_FNPTR)
1385 {
1386 // We should never dereference a function pointer, so all references
1387 // are considered "bad."
1388 if (m_info.objRef != NULL)
1389 {
1390 if (type == ELEMENT_TYPE_PTR)
1391 {
1392 // The only way to tell if the reference in PTR is bad or
1393 // not is to try to deref the thing.
1394 TryDereferencingTarget();
1395 }
1396 } // !m_info.m_basicData.m_vmObject.IsNull()
1397 // else Null refs are considered "bad".
1398 } // type != ELEMENT_TYPE_FNPTR
1399
1400 // we made it without throwing, so we'll assume (perhaps wrongly) that the ref is good
1401 m_info.objRefBad = FALSE;
1402
1403} // CordbReferenceValue::SanityCheckPointer
1404
1405// get information about the reference when it's not an object address but another kind of pointer type:
1406// ELEMENT_TYPE_BYREF, ELEMENT_TYPE_PTR or ELEMENT_TYPE_FNPTR
1407// Arguments:
1408// input: type - type of the referent
1409// localValue - starting address and length of a local buffer containing the object ref
1410// Notes:
1411// - fills in the m_info field of "this"
1412// - Throws (errors from reading process memory)
1413void CordbReferenceValue::GetPointerData(CorElementType type, MemoryRange localValue)
1414{
1415 HRESULT hr = S_OK;
1416 // Fill in the type since we will not be getting it from the DAC
1417 m_info.objTypeData.elementType = type;
1418
1419 // First get the objRef
1420 if (localValue.StartAddress() != NULL)
1421 {
1422 // localValue represents a buffer containing a copy of the objectRef that exists locally. It could be a
1423 // component of a container type residing within a local cached copy belonging to some other
1424 // Cordb*Value instance representing the container type. In this case it will be a field, array
1425 // element, or referent of a different object reference for that other Cordb*Value instance. It
1426 // could also be a pointer to the value of a local register display of the frame from which this object
1427 // ref comes.
1428
1429 // For example, if we have a value class (represented by a CordbVCObject instance) with a field
1430 // that is an object pointer, localValue will contain a pointer to that field in the local
1431 // cache of the CordbVCObjectValue instance (CordbVCObjectValue::m_pObjectCopy).
1432
1433 // Note, though, that pLocalValue holds the address of a target object. We will cache
1434 // the contents of pLocalValue (the object ref) here for efficiency of read access, but if we
1435 // want to set the reference later (e.g., we want the object ref to point to NULL instead of an
1436 // object), we'll have to set the object ref in the target, not our local copy.
1437 // Host memory Target memory
1438 // --------------- |
1439 // CordbVCObjectValue::m_copyOfObject ----> | |
1440 // | ... | |
1441 // | |
1442 // |---------------| | Object
1443 // localAddress ---> | object addr |-------------> --------------
1444 // |---------------| | ---> | |
1445 // | ... | | | |
1446 // --------------- | | --------------
1447 // |
1448 // CordbReferenceValue::m_info.objRef ---> --------------- | |
1449 // | object addr |---------
1450 // --------------- |
1451
1452 _ASSERTE(localValue.Size() == sizeof(void *));
1453 localCopy(&(m_info.objRef), localValue);
1454 }
1455 else
1456 {
1457 // we have a non-local location, so we'll get the value of the ref from its home
1458
1459 // do some preinitialization in case we get an exception
1460 EX_TRY
1461 {
1462 m_valueHome.m_pHome->GetValue(MemoryRange(&(m_info.objRef), sizeof(void*))); // throws
1463 }
1464 EX_CATCH_HRESULT(hr);
1465 if (FAILED(hr))
1466 {
1467 m_info.objRef = NULL;
1468 m_info.objRefBad = TRUE;
1469 ThrowHR(hr);
1470 }
1471 }
1472
1473 EX_TRY
1474 {
1475 // If we made it this far, we need to sanity check the pointer--we'll just see if we can
1476 // read at that address
1477 SanityCheckPointer(type);
1478 }
1479 EX_CATCH_HRESULT(hr); // we don't need to do anything here, m_info.objRefBad will have been set to true
1480
1481} // CordbReferenceValue::GetPointerData
1482
1483// Helper function for CordbReferenceValue::GetObjectData: Sets default values for the fields in pObjectData
1484// before processing begins. Not all will necessarily be initialized during processing.
1485// Arguments:
1486// input: objectType - type of the referent of the objRef being examined
1487// output: pObjectData - information about the reference to be initialized
1488void PreInitObjectData(DebuggerIPCE_ObjectData * pObjectData, void * objAddress, CorElementType objectType)
1489{
1490 _ASSERTE(pObjectData != NULL);
1491
1492 memset(pObjectData, 0, sizeof(DebuggerIPCE_ObjectData));
1493 pObjectData->objRef = objAddress;
1494 pObjectData->objTypeData.elementType = objectType;
1495
1496} // PreInitObjectData
1497
1498// get basic object specific data when a reference points to an object, plus extra data if the object is an
1499// array or string
1500// Arguments:
1501// input: pProcess - process to which the object belongs
1502// objectAddress - pointer to the TypedByRef object (this is the value of the object reference
1503// or handle.
1504// type - the type of the object referenced
1505// vmAppDomain - appdomain to which the object belongs
1506// output: pInfo - filled with information about the object to which the TypedByRef refers.
1507// Note: Throws
1508/* static */
1509void CordbReferenceValue::GetObjectData(CordbProcess * pProcess,
1510 void * objectAddress,
1511 CorElementType type,
1512 VMPTR_AppDomain vmAppdomain,
1513 DebuggerIPCE_ObjectData * pInfo)
1514{
1515 IDacDbiInterface *pInterface = pProcess->GetDAC();
1516 CORDB_ADDRESS objTargetAddr = PTR_TO_CORDB_ADDRESS(objectAddress);
1517
1518 // make sure we don't end up with old garbage values in case the reference is bad
1519 PreInitObjectData(pInfo, objectAddress, type);
1520
1521 pInterface->GetBasicObjectInfo(objTargetAddr, type, vmAppdomain, pInfo);
1522
1523 if (!pInfo->objRefBad)
1524 {
1525 // for certain referent types, we need a bit more information:
1526 if (pInfo->objTypeData.elementType == ELEMENT_TYPE_STRING)
1527 {
1528 pInterface->GetStringData(objTargetAddr, pInfo);
1529 }
1530 else if ((pInfo->objTypeData.elementType == ELEMENT_TYPE_ARRAY) ||
1531 (pInfo->objTypeData.elementType == ELEMENT_TYPE_SZARRAY))
1532 {
1533 pInterface->GetArrayData(objTargetAddr, pInfo);
1534 }
1535 }
1536
1537} // CordbReferenceValue::GetObjectData
1538
1539// get information about a TypedByRef object when the reference is the address of a TypedByRef structure.
1540// Arguments:
1541// input: pProcess - process to which the object belongs
1542// pTypedByRef - pointer to the TypedByRef object (this is the value of the object reference or
1543// handle.
1544// type - the type of the object referenced
1545// vmAppDomain - appdomain to which the object belongs
1546// output: pInfo - filled with information about the object to which the TypedByRef refers.
1547// Note: Throws
1548/* static */
1549void CordbReferenceValue::GetTypedByRefData(CordbProcess * pProcess,
1550 CORDB_ADDRESS pTypedByRef,
1551 CorElementType type,
1552 VMPTR_AppDomain vmAppDomain,
1553 DebuggerIPCE_ObjectData * pInfo)
1554{
1555
1556 // make sure we don't end up with old garbage values since we don't set all the values for TypedByRef objects
1557 PreInitObjectData(pInfo, CORDB_ADDRESS_TO_PTR(pTypedByRef), type);
1558
1559 // Though pTypedByRef is the value of the object ref represented by an instance of CordbReferenceValue,
1560 // it is not the address of an object, as we would ordinarily expect. Instead, in the special case of
1561 // TypedByref objects, it is actually the address of the TypedByRef struct which contains the
1562 // type and the object address.
1563
1564 pProcess->GetDAC()->GetTypedByRefInfo(pTypedByRef, vmAppDomain, pInfo);
1565} // CordbReferenceValue::GetTypedByRefData
1566
1567// get the address of the object referenced
1568// Arguments: none
1569// Return Value: the address of the object referenced (i.e., the value of the object ref)
1570// Note: Throws
1571void * CordbReferenceValue::GetObjectAddress(MemoryRange localValue)
1572{
1573 void * objectAddress;
1574 if (localValue.StartAddress() != NULL)
1575 {
1576 // the object ref comes from a local cached copy
1577 _ASSERTE(localValue.Size() == sizeof(void *));
1578 memcpy(&objectAddress, localValue.StartAddress(), localValue.Size());
1579 }
1580 else
1581 {
1582 _ASSERTE(m_valueHome.m_pHome != NULL);
1583 m_valueHome.m_pHome->GetValue(MemoryRange(&objectAddress, sizeof(void *))); // throws
1584 }
1585 return objectAddress;
1586} // CordbReferenceValue::GetObjectAddress
1587
1588// update type information after initializing -- when we initialize, we may get more exact type information
1589// than we previously had
1590// Arguments: none--uses and updates data members
1591// Note: Throws
1592void CordbReferenceValue::UpdateTypeInfo()
1593{
1594 // If the object type that we got back is different than the one we sent, then it means that we
1595 // originally had a CLASS and now have something more specific, like a SDARRAY, MDARRAY, or STRING or
1596 // a constructed type.
1597 // Update our signature accordingly, which is okay since we always have a copy of our sig. This
1598 // ensures that the reference's signature accurately reflects what the Runtime knows it's pointing
1599 // to.
1600 //
1601 // GENERICS: do this for all types: for example, an array might have been discovered to be a more
1602 // specific kind of array (String[] where an Object[] was expected).
1603 CordbType *newtype;
1604
1605 IfFailThrow(CordbType::TypeDataToType(m_appdomain, &m_info.objTypeData, &newtype));
1606
1607 _ASSERTE(newtype->m_elementType != ELEMENT_TYPE_VALUETYPE);
1608 m_type.Assign(newtype); // implicit Release + AddRef
1609
1610 // For typed-byref's the act of dereferencing the object also reveals to us
1611 // what the "real" type of the object is...
1612 if (m_info.objTypeData.elementType == ELEMENT_TYPE_TYPEDBYREF)
1613{
1614 IfFailThrow(CordbType::TypeDataToType(m_appdomain,
1615 &m_info.typedByrefInfo.typedByrefType,
1616 &m_realTypeOfTypedByref));
1617 }
1618} // CordbReferenceValue::UpdateTypeInfo
1619
1620// Initialize this CordbReferenceValue. This may involve inspecting the LS to get information about the
1621// referent.
1622// Arguments:
1623// input: localValue - buffer address and size of the RS location of the reference. (This may be NULL
1624// if the reference didn't come from a local cached copy. See
1625// code:CordbReferenceValue::GetPointerData for further explanation of local locations.)
1626// Return Value: S_OK on success or E_INVALIDARG or write process memory errors on failure
1627
1628HRESULT CordbReferenceValue::InitRef(MemoryRange localValue)
1629{
1630 INTERNAL_SYNC_API_ENTRY(this->GetProcess());
1631
1632 HRESULT hr = S_OK;
1633 CordbProcess * pProcess = GetProcess();
1634
1635 // Simple init needed for literal refs. Literals may have a null process / appdomain ptr.
1636 if (m_isLiteral)
1637 {
1638 _ASSERTE(m_type != NULL);
1639 m_info.objTypeData.elementType = m_type->m_elementType;
1640 return hr;
1641 }
1642
1643 _ASSERTE((pProcess->GetShim() == NULL) || pProcess->GetSynchronized());
1644
1645 // If the helper thread is dead, then pretend this is a bad reference.
1646 if (GetProcess()->m_helperThreadDead)
1647 {
1648 m_info.objRef = NULL;
1649 m_info.objRefBad = TRUE;
1650 return hr;
1651 }
1652
1653 m_continueCounterLastSync = pProcess->m_continueCounter;
1654
1655 // If no type provided, then it's b/c we're a class and we'll get the type when we get Created.
1656 CorElementType type = (m_type != NULL) ? (m_type->m_elementType) : ELEMENT_TYPE_CLASS;
1657 _ASSERTE (type != ELEMENT_TYPE_GENERICINST);
1658 _ASSERTE (type != ELEMENT_TYPE_VAR);
1659 _ASSERTE (type != ELEMENT_TYPE_MVAR);
1660
1661 EX_TRY
1662 {
1663 if ((type == ELEMENT_TYPE_BYREF) ||
1664 (type == ELEMENT_TYPE_PTR) ||
1665 (type == ELEMENT_TYPE_FNPTR))
1666 {
1667 // we know the size is just the size of a pointer, so we can just read process memory to get the
1668 // information we need
1669 GetPointerData(type, localValue);
1670 }
1671 else // we have to get more information about the object from the DAC
1672 {
1673 if (type == ELEMENT_TYPE_TYPEDBYREF)
1674 {
1675 _ASSERTE(m_valueHome.m_pHome != NULL);
1676 GetTypedByRefData(pProcess,
1677 m_valueHome.m_pHome->GetAddress(),
1678 type,
1679 m_appdomain->GetADToken(),
1680 &m_info);
1681 }
1682 else
1683 {
1684 GetObjectData(pProcess, GetObjectAddress(localValue), type, m_appdomain->GetADToken(), &m_info);
1685 }
1686
1687 // if we got (what we believe is probably) a good reference, we should update the type info
1688 if (!m_info.objRefBad)
1689 {
1690 // we may have gotten back a more specific type than we had previously
1691 UpdateTypeInfo();
1692 }
1693 }
1694 }
1695 EX_CATCH_HRESULT(hr);
1696 return hr;
1697} // CordbReferenceValue::InitRef
1698
1699/* ------------------------------------------------------------------------- *
1700 * Object Value class
1701 * ------------------------------------------------------------------------- */
1702
1703
1704// validate a CordbObjectValue to ensure it hasn't been neutered
1705#define COV_VALIDATE_OBJECT() do { \
1706 BOOL bValid; \
1707 HRESULT hr; \
1708 if (FAILED(hr = IsValid(&bValid))) \
1709 return hr; \
1710 \
1711 if (!bValid) \
1712 { \
1713 return CORDBG_E_INVALID_OBJECT; \
1714 } \
1715 }while(0)
1716
1717// constructor
1718// Arguments:
1719// input: pAppDomain - the appdomain to which the object belongs
1720// pType - the type of the object
1721// remoteValue - the LS address and size of the object
1722// pObjectData - other information about the object, most importantly, the offset to the
1723// fields of the object
1724CordbObjectValue::CordbObjectValue(CordbAppDomain * pAppdomain,
1725 CordbType * pType,
1726 TargetBuffer remoteValue,
1727 DebuggerIPCE_ObjectData *pObjectData )
1728 : CordbValue(pAppdomain, pType, remoteValue.pAddress,
1729 false, pAppdomain->GetProcess()->GetContinueNeuterList()),
1730 m_info(*pObjectData),
1731 m_pObjectCopy(NULL), m_objectLocalVars(NULL), m_stringBuffer(NULL),
1732 m_valueHome(pAppdomain->GetProcess(), remoteValue),
1733 m_fIsExceptionObject(FALSE), m_fIsRcw(FALSE)
1734{
1735 _ASSERTE(pAppdomain != NULL);
1736
1737 m_size = m_info.objSize;
1738
1739 HRESULT hr = S_FALSE;
1740
1741 ALLOW_DATATARGET_MISSING_MEMORY
1742 (
1743 hr = IsExceptionObject();
1744 );
1745
1746 if (hr == S_OK)
1747 m_fIsExceptionObject = TRUE;
1748
1749 hr = S_FALSE;
1750 ALLOW_DATATARGET_MISSING_MEMORY
1751 (
1752 hr = IsRcw();
1753 );
1754
1755 if (hr == S_OK)
1756 m_fIsRcw = TRUE;
1757} // CordbObjectValue::CordbObjectValue
1758
1759// destructor
1760CordbObjectValue::~CordbObjectValue()
1761{
1762 DTOR_ENTRY(this);
1763
1764 _ASSERTE(IsNeutered());
1765} // CordbObjectValue::~CordbObjectValue
1766
1767void CordbObjectValue::Neuter()
1768{
1769 // Destroy the copy of the object.
1770 if (m_pObjectCopy != NULL)
1771 {
1772 delete [] m_pObjectCopy;
1773 m_pObjectCopy = NULL;
1774 }
1775
1776 CordbValue::Neuter();
1777} // CordbObjectValue::Neuter
1778
1779HRESULT CordbObjectValue::QueryInterface(REFIID id, void **pInterface)
1780{
1781 if (id == IID_ICorDebugValue)
1782 {
1783 *pInterface = static_cast<ICorDebugValue*>(static_cast<ICorDebugObjectValue*>(this));
1784 }
1785 else if (id == IID_ICorDebugValue2)
1786 {
1787 *pInterface = static_cast<ICorDebugValue2*>(this);
1788 }
1789 else if (id == IID_ICorDebugValue3)
1790 {
1791 *pInterface = static_cast<ICorDebugValue3*>(this);
1792 }
1793 else if (id == IID_ICorDebugObjectValue)
1794 {
1795 *pInterface = static_cast<ICorDebugObjectValue*>(this);
1796 }
1797 else if (id == IID_ICorDebugObjectValue2)
1798 {
1799 *pInterface = static_cast<ICorDebugObjectValue2*>(this);
1800 }
1801 else if (id == IID_ICorDebugGenericValue)
1802 {
1803 *pInterface = static_cast<ICorDebugGenericValue*>(this);
1804 }
1805 else if (id == IID_ICorDebugHeapValue)
1806 {
1807 *pInterface = static_cast<ICorDebugHeapValue*>(this);
1808 }
1809 else if (id == IID_ICorDebugHeapValue2)
1810 {
1811 *pInterface = static_cast<ICorDebugHeapValue2*>(this);
1812 }
1813 else if (id == IID_ICorDebugHeapValue3)
1814 {
1815 *pInterface = static_cast<ICorDebugHeapValue3*>(this);
1816 }
1817 else if ((id == IID_ICorDebugStringValue) &&
1818 (m_info.objTypeData.elementType == ELEMENT_TYPE_STRING))
1819 {
1820 *pInterface = static_cast<ICorDebugStringValue*>(this);
1821 }
1822 else if (id == IID_ICorDebugExceptionObjectValue && m_fIsExceptionObject)
1823 {
1824 *pInterface = static_cast<IUnknown*>(static_cast<ICorDebugExceptionObjectValue*>(this));
1825 }
1826 else if (id == IID_ICorDebugComObjectValue && m_fIsRcw)
1827 {
1828 *pInterface = static_cast<ICorDebugComObjectValue*>(this);
1829 }
1830 else if (id == IID_IUnknown)
1831 {
1832 *pInterface = static_cast<IUnknown*>(static_cast<ICorDebugObjectValue*>(this));
1833 }
1834 else
1835 {
1836 *pInterface = NULL;
1837 return E_NOINTERFACE;
1838 }
1839
1840 ExternalAddRef();
1841 return S_OK;
1842} // CordbObjectValue::QueryInterface
1843
1844// gets the type of the object
1845// Arguments:
1846// output: pType - the type of the value. The caller must guarantee that pType is non-null.
1847// Return Value: S_OK on success, E_INVALIDARG on failure
1848HRESULT CordbObjectValue::GetType(CorElementType *pType)
1849{
1850 PUBLIC_REENTRANT_API_ENTRY(this);
1851 FAIL_IF_NEUTERED(this);
1852 return (CordbValue::GetType(pType));
1853} // CordbObjectValue::GetType
1854
1855// gets the size of the object
1856// Arguments:
1857// output: pSize - the size of the value. The caller must guarantee that pSize is non-null.
1858// Return Value: S_OK on success, E_INVALIDARG on failure
1859HRESULT CordbObjectValue::GetSize(ULONG32 *pSize)
1860{
1861 PUBLIC_REENTRANT_API_ENTRY(this);
1862 FAIL_IF_NEUTERED(this);
1863 return (CordbValue::GetSize(pSize));
1864} // CordbObjectValue::GetSize
1865
1866// gets the size of the object
1867// Arguments:
1868// output: pSize - the size of the value. The caller must guarantee that pSize is non-null.
1869// Return Value: S_OK on success, E_INVALIDARG on failure
1870HRESULT CordbObjectValue::GetSize64(ULONG64 *pSize)
1871{
1872 PUBLIC_REENTRANT_API_ENTRY(this);
1873 FAIL_IF_NEUTERED(this);
1874 return (CordbValue::GetSize64(pSize));
1875} // CordbObjectValue::GetSize64
1876
1877
1878// gets the remote (LS) address of the object. This may return NULL if the
1879// object is a literal or resides in a register.
1880// Arguments:
1881// output: pAddress - the LS address (the contents should not be null since objects
1882// aren't enregistered nor are they fields or elements of other
1883// types). The caller must ensure that pAddress is not null.
1884// Return Value: S_OK on success or E_INVALIDARG if pAddress is null
1885HRESULT CordbObjectValue::GetAddress(CORDB_ADDRESS *pAddress)
1886{
1887 PUBLIC_REENTRANT_API_ENTRY(this);
1888 FAIL_IF_NEUTERED(this);
1889 COV_VALIDATE_OBJECT();
1890 VALIDATE_POINTER_TO_OBJECT(pAddress, CORDB_ADDRESS *);
1891
1892 *pAddress = m_valueHome.GetAddress();
1893 return (S_OK);
1894} // CordbObjectValue::GetAddress
1895
1896HRESULT CordbObjectValue::CreateBreakpoint(ICorDebugValueBreakpoint ** ppBreakpoint)
1897{
1898 PUBLIC_REENTRANT_API_ENTRY(this);
1899 FAIL_IF_NEUTERED(this);
1900 COV_VALIDATE_OBJECT();
1901
1902 return (CordbValue::CreateBreakpoint(ppBreakpoint));
1903}
1904
1905// determine if "this" is still valid (i.e., not neutered)
1906// Arguments:
1907// output: pfIsValid - true iff "this" is still not neutered
1908// Return Value: S_OK or E_INVALIDARG
1909HRESULT CordbObjectValue::IsValid(BOOL * pfIsValid)
1910{
1911 PUBLIC_REENTRANT_API_ENTRY(this);
1912 VALIDATE_POINTER_TO_OBJECT(pfIsValid, BOOL *);
1913 FAIL_IF_NEUTERED(this);
1914 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
1915
1916 // We're neutered on continue, so we're valid up until the time we're neutered
1917 (*pfIsValid) = TRUE;
1918 return S_OK;
1919}
1920
1921HRESULT CordbObjectValue::CreateRelocBreakpoint(
1922 ICorDebugValueBreakpoint **ppBreakpoint)
1923{
1924 PUBLIC_REENTRANT_API_ENTRY(this);
1925 FAIL_IF_NEUTERED(this);
1926 VALIDATE_POINTER_TO_OBJECT(ppBreakpoint, ICorDebugValueBreakpoint **);
1927
1928 COV_VALIDATE_OBJECT();
1929
1930 return E_NOTIMPL;
1931}
1932
1933/*
1934* Creates a handle of the given type for this heap value.
1935*
1936* Not Implemented In-Proc.
1937*/
1938HRESULT CordbObjectValue::CreateHandle(
1939 CorDebugHandleType handleType,
1940 ICorDebugHandleValue ** ppHandle)
1941{
1942 PUBLIC_API_ENTRY(this);
1943 FAIL_IF_NEUTERED(this);
1944 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
1945
1946 return CordbValue::InternalCreateHandle(handleType, ppHandle);
1947} // CreateHandle
1948
1949// Get class information for this object
1950// Arguments:
1951// output: ppClass - ICDClass instance for this object
1952// Return Value: S_OK if success, CORDBG_E_CLASS_NOT_LOADED, E_INVALIDARG, OOM on failure
1953HRESULT CordbObjectValue::GetClass(ICorDebugClass **ppClass)
1954{
1955 PUBLIC_REENTRANT_API_ENTRY(this);
1956 VALIDATE_POINTER_TO_OBJECT(ppClass, ICorDebugClass **);
1957 FAIL_IF_NEUTERED(this);
1958 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
1959
1960 HRESULT hr = S_OK;
1961 if (m_type->m_pClass == NULL)
1962 {
1963 if (FAILED(hr = m_type->Init(FALSE)))
1964 return hr;
1965 }
1966
1967 _ASSERTE(m_type->m_pClass);
1968 *ppClass = (ICorDebugClass*) m_type->m_pClass;
1969
1970 if (*ppClass != NULL)
1971 (*ppClass)->AddRef();
1972
1973 return hr;
1974} // CordbObjectValue::GetClass
1975
1976
1977
1978
1979
1980//-----------------------------------------------------------------------------
1981//
1982// Public API to get instance field of the given type in the object and returns an ICDValue for it.
1983//
1984// Arguments:
1985// pType - The type containing the field token.
1986// fieldDef - The field's metadata def.
1987// ppValue - OUT: the ICDValue for the field.
1988//
1989// Returns:
1990// S_OK on success. E_INVALIDARG, CORDBG_E_ENC_HANGING_FIELD, CORDBG_E_FIELD_NOT_INSTANCE or OOM on
1991// failure
1992//
1993// Notes:
1994// This is for instance fields only.
1995// Lookup on code:CordbType::GetStaticFieldValue to get static fields.
1996// This is generics aware.
1997HRESULT CordbObjectValue::GetFieldValueForType(ICorDebugType * pType,
1998 mdFieldDef fieldDef,
1999 ICorDebugValue ** ppValue)
2000{
2001 PUBLIC_REENTRANT_API_ENTRY(this);
2002 VALIDATE_POINTER_TO_OBJECT(pType, ICorDebugType *);
2003 VALIDATE_POINTER_TO_OBJECT(ppValue, ICorDebugValue **);
2004
2005 FAIL_IF_NEUTERED(this);
2006 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
2007
2008 COV_VALIDATE_OBJECT();
2009
2010 CordbType * pCordbType = NULL;
2011 HRESULT hr = S_OK;
2012
2013 EX_TRY
2014 {
2015 BOOL fSyncBlockField = FALSE;
2016 SIZE_T fldOffset;
2017
2018 //
2019 // <TODO>@todo: need to ensure that pType is really on the class
2020 // hierarchy of m_class!!!</TODO>
2021 //
2022 if (pType == NULL)
2023 {
2024 pCordbType = m_type;
2025 }
2026 else
2027 {
2028 pCordbType = static_cast<CordbType *>(pType);
2029 }
2030
2031 // Validate the token.
2032 if (pCordbType->m_pClass == NULL)
2033 {
2034 ThrowHR(E_INVALIDARG);
2035 }
2036 IMetaDataImport * pImport = pCordbType->m_pClass->GetModule()->GetMetaDataImporter();
2037
2038 if (!pImport->IsValidToken(fieldDef))
2039 {
2040 ThrowHR(E_INVALIDARG);
2041 }
2042
2043 FieldData * pFieldData;
2044
2045 #ifdef _DEBUG
2046 pFieldData = NULL;
2047 #endif
2048
2049 hr = pCordbType->GetFieldInfo(fieldDef, &pFieldData);
2050
2051 // If we couldn't get field info because the field was added with EnC
2052 if (hr == CORDBG_E_ENC_HANGING_FIELD)
2053 {
2054 // The instance field hangs off the syncblock, get its address
2055 hr = pCordbType->m_pClass->GetEnCHangingField(fieldDef, &pFieldData, this);
2056
2057 if (SUCCEEDED(hr))
2058 {
2059 fSyncBlockField = TRUE;
2060 }
2061 }
2062
2063 if (SUCCEEDED(hr))
2064 {
2065 _ASSERTE(pFieldData != NULL);
2066
2067 if (pFieldData->m_fFldIsStatic)
2068 {
2069 ThrowHR(CORDBG_E_FIELD_NOT_INSTANCE);
2070 }
2071
2072 // Compute the remote address, too, so that SetValue will work.
2073 // Note that if pFieldData is a syncBlock field, fldOffset will have been cooked
2074 // to produce the correct result here.
2075 _ASSERTE(pFieldData->OkToGetOrSetInstanceOffset());
2076 fldOffset = pFieldData->GetInstanceOffset();
2077
2078 CordbModule * pModule = pCordbType->m_pClass->GetModule();
2079
2080 SigParser sigParser;
2081 IfFailThrow(pFieldData->GetFieldSignature(pModule, &sigParser));
2082
2083 CordbType * pFieldType;
2084 IfFailThrow(CordbType::SigToType(pModule, &sigParser, &(pCordbType->m_inst), &pFieldType));
2085
2086 ULONG32 size = GetSizeForType(pFieldType, kUnboxed);
2087
2088 void * localAddr = NULL;
2089 if (!fSyncBlockField)
2090 {
2091 // verify that the field starts and ends before the end of m_pObjectCopy
2092 _ASSERTE(m_info.objOffsetToVars + fldOffset < m_size);
2093 _ASSERTE(m_info.objOffsetToVars + fldOffset + size <= m_size);
2094 localAddr = m_objectLocalVars + fldOffset;
2095 }
2096
2097 // pass the computed local field address, but don't claim we have a local addr if the fldOffset
2098 // has been cooked to point us to a sync block field.
2099 m_valueHome.CreateInternalValue(pFieldType,
2100 m_info.objOffsetToVars + fldOffset,
2101 localAddr,
2102 size,
2103 ppValue); // throws
2104 }
2105
2106 // If we can't get it b/c it's a constant, then say so.
2107 hr = CordbClass::PostProcessUnavailableHRESULT(hr, pImport, fieldDef);
2108 }
2109 EX_CATCH_HRESULT(hr);
2110 return hr;
2111} // CordbObjectValue::GetFieldValueForType
2112
2113// Public implementation of ICorDebugObjectValue::GetFieldValue
2114// Arguments:
2115// input: pClass - class information for this object
2116// fieldDef - the field token for the requested field
2117// output: ppValue - instance of ICDValue created to represent the field
2118// Return Value: S_OK on success, E_INVALIDARG, CORDBG_E_ENC_HANGING_FIELD, CORDBG_E_FIELD_NOT_INSTANCE
2119// or OOM on failure
2120HRESULT CordbObjectValue::GetFieldValue(ICorDebugClass *pClass,
2121 mdFieldDef fieldDef,
2122 ICorDebugValue **ppValue)
2123{
2124 PUBLIC_REENTRANT_API_ENTRY(this);
2125 FAIL_IF_NEUTERED(this);
2126 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
2127 VALIDATE_POINTER_TO_OBJECT(pClass, ICorDebugClass *);
2128 VALIDATE_POINTER_TO_OBJECT(ppValue, ICorDebugValue **);
2129
2130 COV_VALIDATE_OBJECT();
2131
2132 HRESULT hr;
2133 _ASSERTE(m_type);
2134
2135 if (m_type->m_elementType != ELEMENT_TYPE_CLASS &&
2136 m_type->m_elementType != ELEMENT_TYPE_VALUETYPE)
2137 {
2138 return E_INVALIDARG;
2139 }
2140
2141 // mdFieldDef may specify a field within a base class. mdFieldDef tokens are unique throughout a module.
2142 // So we still need a metadata scope to resolve the mdFieldDef. We can infer the scope from pClass.
2143 // Beware that this Type may be derived from a type in another module, and so the incoming
2144 // fieldDef has to be resolved in the metadata scope of pClass.
2145
2146 RSExtSmartPtr<CordbType> relevantType;
2147
2148 // This object has an ICorDebugType which has the type-parameters for generics.
2149 // ICorDebugClass provided by the caller does not have type-parameters. So we resolve that
2150 // by using the provided ICDClass with the type parameters from this object's ICDType.
2151 if (FAILED (hr= m_type->GetParentType((CordbClass *) pClass, &relevantType)))
2152 {
2153 return hr;
2154 }
2155 // Upon exit relevantType will either be the appropriate type for the
2156 // class we're looking for.
2157
2158 hr = GetFieldValueForType(relevantType, fieldDef, ppValue);
2159 // GetParentType adds one reference to relevantType., Holder dtor releases
2160 return hr;
2161
2162} // CordbObjectValue::GetFieldValue
2163
2164HRESULT CordbObjectValue::GetVirtualMethod(mdMemberRef memberRef,
2165 ICorDebugFunction **ppFunction)
2166{
2167 VALIDATE_POINTER_TO_OBJECT(ppFunction, ICorDebugFunction **);
2168 FAIL_IF_NEUTERED(this);
2169 COV_VALIDATE_OBJECT();
2170
2171 return E_NOTIMPL;
2172} // CordbObjectValue::GetVirtualMethod
2173
2174HRESULT CordbObjectValue::GetVirtualMethodAndType(mdMemberRef memberRef,
2175 ICorDebugFunction **ppFunction,
2176 ICorDebugType **ppType)
2177{
2178 FAIL_IF_NEUTERED(this);
2179 VALIDATE_POINTER_TO_OBJECT(ppFunction, ICorDebugFunction **);
2180 VALIDATE_POINTER_TO_OBJECT(ppFunction, ICorDebugType **);
2181
2182 COV_VALIDATE_OBJECT();
2183
2184 return E_NOTIMPL;
2185} // CordbObjectValue::GetVirtualMethodAndType
2186
2187HRESULT CordbObjectValue::GetContext(ICorDebugContext **ppContext)
2188{
2189 FAIL_IF_NEUTERED(this);
2190 VALIDATE_POINTER_TO_OBJECT(ppContext, ICorDebugContext **);
2191
2192 COV_VALIDATE_OBJECT();
2193
2194 return E_NOTIMPL;
2195} // CordbObjectValue::GetContext
2196
2197// determines whether this represents a value class-- always returns false
2198// Arguments:
2199// output: pfIsValueClass - always false; CordbVCObjectValue is used to represent
2200// value classes, so by definition, a CordbObjectValue instance
2201// does not represent a value class
2202// Return Value: S_OK
2203//
2204HRESULT CordbObjectValue::IsValueClass(BOOL * pfIsValueClass)
2205{
2206 FAIL_IF_NEUTERED(this);
2207 COV_VALIDATE_OBJECT();
2208
2209 if (pfIsValueClass) // don't assign to a null pointer!
2210 *pfIsValueClass = FALSE;
2211
2212 return S_OK;
2213} // CordbObjectValue::IsValueClass
2214
2215HRESULT CordbObjectValue::GetManagedCopy(IUnknown **ppObject)
2216{
2217 // GetManagedCopy() is deprecated. In the case where the version of
2218 // the debugger doesn't match the version of the debuggee, the two processes
2219 // might have dangerously different notions of the layout of an object.
2220
2221 // This function is deprecated
2222 return E_NOTIMPL;
2223} // CordbObjectValue::GetManagedCopy
2224
2225HRESULT CordbObjectValue::SetFromManagedCopy(IUnknown *pObject)
2226{
2227 // Deprecated for the same reason as GetManagedCopy()
2228 return E_NOTIMPL;
2229} // CordbObjectValue::SetFromManagedCopy
2230
2231// gets a copy of the value
2232// Arguments:
2233// output: pTo - buffer to hold the object copy. The caller must guarantee that this
2234// is non-null and the buffer is large enough to hold the object
2235// Return Value: S_OK or CORDBG_E_INVALID_OBJECT, CORDBG_E_OBJECT_NEUTERED, or E_INVALIDARG on failure
2236//
2237HRESULT CordbObjectValue::GetValue(void *pTo)
2238{
2239 FAIL_IF_NEUTERED(this);
2240 COV_VALIDATE_OBJECT();
2241
2242 VALIDATE_POINTER_TO_OBJECT_ARRAY(pTo, BYTE, m_size, false, true);
2243
2244 // Copy out the value, which is the whole object.
2245 memcpy(pTo, m_pObjectCopy, m_size);
2246
2247 return S_OK;
2248} // CordbObjectValue::GetValue
2249
2250HRESULT CordbObjectValue::SetValue(void *pFrom)
2251{
2252 // You're not allowed to set a whole object at once.
2253 return E_INVALIDARG;
2254} // CordbObjectValue::SetValue
2255
2256// If this instance of CordbObjectValue is actually a string, get its length
2257// Arguments:
2258// output: pcchString - the count of characters in the string
2259// Return Value: S_OK or CORDBG_E_INVALID_OBJECT, CORDBG_E_OBJECT_NEUTERED, or E_INVALIDARG on failure
2260// Note: if the object is not really a string, the value in pcchString will be garbage on exit
2261HRESULT CordbObjectValue::GetLength(ULONG32 *pcchString)
2262{
2263 PUBLIC_REENTRANT_API_ENTRY(this);
2264 VALIDATE_POINTER_TO_OBJECT(pcchString, SIZE_T *);
2265 FAIL_IF_NEUTERED(this);
2266
2267 _ASSERTE(m_info.objTypeData.elementType == ELEMENT_TYPE_STRING);
2268
2269 COV_VALIDATE_OBJECT();
2270
2271 *pcchString = (ULONG32)m_info.stringInfo.length;
2272 return S_OK;
2273} // CordbObjectValue::GetLength
2274
2275// If this instance of CordbObjectValue represents a string, extract the string and its length.
2276// If cchString is less than the length of the string, we'll return only the first cchString characters
2277// but pcchString will still hold the full length. If cchString is more than the string length, we'll
2278// return only string length characters.
2279// Arguments:
2280// input: cchString - the maximum number of characters to return, including NULL terminator
2281// output: pcchString - the actual length of the string, excluding NULL terminator (this may be greater than cchString)
2282// szString - a buffer holding the string. The memory for this must be allocated and
2283// managed by the caller and must have space for at least cchString characters
2284// Return Value: S_OK or CORDBG_E_INVALID_OBJECT, CORDBG_E_OBJECT_NEUTERED, or E_INVALIDARG on failure
2285HRESULT CordbObjectValue::GetString(ULONG32 cchString,
2286 ULONG32 *pcchString,
2287 __out_ecount_opt(cchString) WCHAR szString[])
2288{
2289 PUBLIC_REENTRANT_API_ENTRY(this);
2290 FAIL_IF_NEUTERED(this);
2291 VALIDATE_POINTER_TO_OBJECT_ARRAY(szString, WCHAR, cchString, true, true);
2292 VALIDATE_POINTER_TO_OBJECT(pcchString, SIZE_T *);
2293
2294 _ASSERTE(m_info.objTypeData.elementType == ELEMENT_TYPE_STRING);
2295
2296 COV_VALIDATE_OBJECT();
2297
2298 if ((szString == NULL) || (cchString == 0))
2299 return E_INVALIDARG;
2300
2301 // Add 1 to include null terminator
2302 SIZE_T len = m_info.stringInfo.length + 1;
2303
2304 // adjust length to the size of the buffer
2305 if (cchString < len)
2306 len = cchString;
2307
2308 memcpy(szString, m_stringBuffer, len * 2);
2309 *pcchString = (ULONG32)m_info.stringInfo.length;
2310
2311 return S_OK;
2312} // CordbObjectValue::GetString
2313
2314// Initialize an instance of CordbObjectValue, filling in the m_pObjectCopy field and, if appropriate,
2315// string information.
2316// Arguments: none
2317// ReturnValue: S_OK on success or E_OUTOFMEMORY or read process memory errors on failure
2318HRESULT CordbObjectValue::Init()
2319{
2320 INTERNAL_SYNC_API_ENTRY(this->GetProcess()); //
2321 LOG((LF_CORDB,LL_INFO1000,"Invoking COV::Init\n"));
2322
2323 HRESULT hr = S_OK;
2324
2325 _ASSERTE (m_info.objTypeData.elementType != ELEMENT_TYPE_GENERICINST);
2326 _ASSERTE (m_info.objTypeData.elementType != ELEMENT_TYPE_VAR);
2327 _ASSERTE (m_info.objTypeData.elementType != ELEMENT_TYPE_MVAR);
2328
2329 // Copy the entire object over to this process.
2330 m_pObjectCopy = new (nothrow) BYTE[m_size];
2331
2332 if (m_pObjectCopy == NULL)
2333 return E_OUTOFMEMORY;
2334
2335 EX_TRY
2336 {
2337 m_valueHome.GetValue(MemoryRange(m_pObjectCopy, m_size)); // throws
2338 }
2339 EX_CATCH_HRESULT(hr);
2340 IfFailRet(hr);
2341
2342 // Compute offsets in bytes to the locals and to a string if this is a
2343 // string object.
2344 m_objectLocalVars = m_pObjectCopy + m_info.objOffsetToVars;
2345
2346 if (m_info.objTypeData.elementType == ELEMENT_TYPE_STRING)
2347 m_stringBuffer = m_pObjectCopy + m_info.stringInfo.offsetToStringBase;
2348
2349 return hr;
2350} // CordbObjectValue::Init
2351
2352// CordbObjectValue::GetThreadOwningMonitorLock
2353// If a managed thread owns the monitor lock on this object then *ppThread
2354// will point to that thread and S_OK will be returned. The thread object is valid
2355// until the thread exits. *pAcquisitionCount will indicate the number of times
2356// this thread would need to release the lock before it returns to being
2357// unowned.
2358// If no managed thread owns the monitor lock on this object then *ppThread
2359// and pAcquisitionCount will be unchanged and S_FALSE returned.
2360// If ppThread or pAcquisitionCount is not a valid pointer the result is
2361// undefined.
2362// If any error occurs such that it cannot be determined which, if any, thread
2363// owns the monitor lock on this object then a failing HRESULT will be returned
2364HRESULT CordbObjectValue::GetThreadOwningMonitorLock(ICorDebugThread **ppThread, DWORD *pAcquisitionCount)
2365{
2366 PUBLIC_API_ENTRY(this);
2367 FAIL_IF_NEUTERED(this);
2368 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
2369
2370 return CordbHeapValue3Impl::GetThreadOwningMonitorLock(GetProcess(),
2371 GetValueHome()->GetAddress(),
2372 ppThread,
2373 pAcquisitionCount);
2374}
2375
2376// CordbObjectValue::GetMonitorEventWaitList
2377// Provides an ordered list of threads which are queued on the event associated
2378// with a monitor lock. The first thread in the list is the first thread which
2379// will be released by the next call to Monitor.Pulse, the next thread in the list
2380// will be released on the following call, and so on.
2381// If this list is non-empty S_OK will be returned, if it is empty S_FALSE
2382// will be returned (the enumeration is still valid, just empty).
2383// In either case the enumeration interface is only usable for the duration
2384// of the current synchronized state, however the threads interfaces dispensed
2385// from it are valid until the thread exits.
2386// If ppThread is not a valid pointer the result is undefined.
2387// If any error occurs such that it cannot be determined which, if any, threads
2388// are waiting for the monitor then a failing HRESULT will be returned
2389HRESULT CordbObjectValue::GetMonitorEventWaitList(ICorDebugThreadEnum **ppThreadEnum)
2390{
2391 PUBLIC_API_ENTRY(this);
2392 FAIL_IF_NEUTERED(this);
2393 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
2394
2395 return CordbHeapValue3Impl::GetMonitorEventWaitList(GetProcess(),
2396 GetValueHome()->GetAddress(),
2397 ppThreadEnum);
2398}
2399
2400HRESULT CordbObjectValue::EnumerateExceptionCallStack(ICorDebugExceptionObjectCallStackEnum** ppCallStackEnum)
2401{
2402 if (!ppCallStackEnum)
2403 return E_INVALIDARG;
2404
2405 *ppCallStackEnum = NULL;
2406
2407 HRESULT hr = S_OK;
2408 CorDebugExceptionObjectStackFrame* pStackFrames = NULL;
2409
2410 PUBLIC_API_BEGIN(this);
2411
2412 CORDB_ADDRESS objAddr = m_valueHome.GetAddress();
2413
2414 IDacDbiInterface* pDAC = GetProcess()->GetDAC();
2415 VMPTR_Object vmObj = pDAC->GetObject(objAddr);
2416
2417 DacDbiArrayList<DacExceptionCallStackData> dacStackFrames;
2418
2419 pDAC->GetStackFramesFromException(vmObj, dacStackFrames);
2420 int stackFramesLength = dacStackFrames.Count();
2421
2422 if (stackFramesLength > 0)
2423 {
2424 pStackFrames = new CorDebugExceptionObjectStackFrame[stackFramesLength];
2425 for (int index = 0; index < stackFramesLength; ++index)
2426 {
2427 DacExceptionCallStackData& currentDacFrame = dacStackFrames[index];
2428 CorDebugExceptionObjectStackFrame& currentStackFrame = pStackFrames[index];
2429
2430 CordbAppDomain* pAppDomain = GetProcess()->LookupOrCreateAppDomain(currentDacFrame.vmAppDomain);
2431 CordbModule* pModule = pAppDomain->LookupOrCreateModule(currentDacFrame.vmDomainFile);
2432
2433 hr = pModule->QueryInterface(IID_ICorDebugModule, reinterpret_cast<void**>(&currentStackFrame.pModule));
2434 _ASSERTE(SUCCEEDED(hr));
2435
2436 currentStackFrame.ip = currentDacFrame.ip;
2437 currentStackFrame.methodDef = currentDacFrame.methodDef;
2438 currentStackFrame.isLastForeignExceptionFrame = currentDacFrame.isLastForeignExceptionFrame;
2439 }
2440 }
2441
2442 CordbExceptionObjectCallStackEnumerator* callStackEnum = new CordbExceptionObjectCallStackEnumerator(GetProcess(), pStackFrames, stackFramesLength);
2443 GetProcess()->GetContinueNeuterList()->Add(GetProcess(), callStackEnum);
2444
2445 hr = callStackEnum->QueryInterface(IID_ICorDebugExceptionObjectCallStackEnum, reinterpret_cast<void**>(ppCallStackEnum));
2446 _ASSERTE(SUCCEEDED(hr));
2447
2448 PUBLIC_API_END(hr);
2449
2450 if (pStackFrames)
2451 delete[] pStackFrames;
2452
2453 return hr;
2454}
2455
2456HRESULT CordbObjectValue::IsExceptionObject()
2457{
2458 HRESULT hr = S_OK;
2459
2460 if (m_info.objTypeData.elementType != ELEMENT_TYPE_CLASS)
2461 {
2462 hr = S_FALSE;
2463 }
2464 else
2465 {
2466 CORDB_ADDRESS objAddr = m_valueHome.GetAddress();
2467
2468 if (objAddr == NULL)
2469 {
2470 // object is a literal
2471 hr = S_FALSE;
2472 }
2473 else
2474 {
2475 IDacDbiInterface* pDAC = GetProcess()->GetDAC();
2476
2477 VMPTR_Object vmObj = pDAC->GetObject(objAddr);
2478 BOOL fIsException = pDAC->IsExceptionObject(vmObj);
2479
2480 if (!fIsException)
2481 hr = S_FALSE;
2482 }
2483 }
2484
2485 return hr;
2486}
2487
2488HRESULT CordbObjectValue::IsRcw()
2489{
2490 HRESULT hr = S_OK;
2491
2492 if (m_info.objTypeData.elementType != ELEMENT_TYPE_CLASS)
2493 {
2494 hr = S_FALSE;
2495 }
2496 else
2497 {
2498 CORDB_ADDRESS objAddr = m_valueHome.GetAddress();
2499
2500 if (objAddr == NULL)
2501 {
2502 // object is a literal
2503 hr = S_FALSE;
2504 }
2505 else
2506 {
2507 IDacDbiInterface* pDAC = GetProcess()->GetDAC();
2508
2509 VMPTR_Object vmObj = pDAC->GetObject(objAddr);
2510 BOOL fIsRcw = pDAC->IsRcw(vmObj);
2511
2512 if (!fIsRcw)
2513 hr = S_FALSE;
2514 }
2515 }
2516
2517 return hr;
2518}
2519
2520HRESULT CordbObjectValue::GetCachedInterfaceTypes(
2521 BOOL bIInspectableOnly,
2522 ICorDebugTypeEnum * * ppInterfacesEnum)
2523{
2524#if !defined(FEATURE_COMINTEROP)
2525
2526 return E_NOTIMPL;
2527
2528#else
2529
2530 HRESULT hr = S_OK;
2531
2532 PUBLIC_API_ENTRY(this);
2533 FAIL_IF_NEUTERED(this);
2534 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
2535 VALIDATE_POINTER_TO_OBJECT(ppInterfacesEnum, ICorDebugTypeEnum **);
2536
2537 _ASSERTE(m_fIsRcw);
2538
2539 EX_TRY
2540 {
2541 *ppInterfacesEnum = NULL;
2542
2543 NewArrayHolder<CordbType*> pItfs(NULL);
2544
2545 // retrieve interface types
2546 DacDbiArrayList<DebuggerIPCE_ExpandedTypeData> dacInterfaces;
2547
2548 IDacDbiInterface* pDAC = GetProcess()->GetDAC();
2549
2550 CORDB_ADDRESS objAddr = m_valueHome.GetAddress();
2551 VMPTR_Object vmObj = pDAC->GetObject(objAddr);
2552
2553 // retrieve type info from LS
2554 pDAC->GetRcwCachedInterfaceTypes(vmObj, m_appdomain->GetADToken(),
2555 bIInspectableOnly, &dacInterfaces);
2556
2557 // synthesize CordbType instances
2558 int cItfs = dacInterfaces.Count();
2559 if (cItfs > 0)
2560 {
2561 pItfs = new CordbType*[cItfs];
2562 for (int n = 0; n < cItfs; ++n)
2563 {
2564 hr = CordbType::TypeDataToType(m_appdomain,
2565 &(dacInterfaces[n]),
2566 &pItfs[n]);
2567 }
2568 }
2569
2570 // build a type enumerator
2571 CordbTypeEnum* pTypeEnum = CordbTypeEnum::Build(m_appdomain, GetProcess()->GetContinueNeuterList(), cItfs, pItfs);
2572 if ( pTypeEnum == NULL )
2573 {
2574 IfFailThrow(E_OUTOFMEMORY);
2575 }
2576
2577 (*ppInterfacesEnum) = static_cast<ICorDebugTypeEnum*> (pTypeEnum);
2578 pTypeEnum->ExternalAddRef();
2579
2580 }
2581 EX_CATCH_HRESULT(hr);
2582
2583 return hr;
2584
2585#endif
2586}
2587
2588HRESULT CordbObjectValue::GetCachedInterfacePointers(
2589 BOOL bIInspectableOnly,
2590 ULONG32 celt,
2591 ULONG32 *pcEltFetched,
2592 CORDB_ADDRESS * ptrs)
2593{
2594#if !defined(FEATURE_COMINTEROP)
2595
2596 return E_NOTIMPL;
2597
2598#else
2599
2600 PUBLIC_API_ENTRY(this);
2601 FAIL_IF_NEUTERED(this);
2602 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
2603 _ASSERTE(m_fIsRcw);
2604
2605 if (pcEltFetched == NULL && (ptrs == NULL || celt == 0))
2606 return E_INVALIDARG;
2607
2608 HRESULT hr = S_OK;
2609 ULONG32 cItfs = 0;
2610
2611 // retrieve interface types
2612
2613 CORDB_ADDRESS objAddr = m_valueHome.GetAddress();
2614
2615 DacDbiArrayList<CORDB_ADDRESS> dacItfPtrs;
2616 EX_TRY
2617 {
2618 IDacDbiInterface* pDAC = GetProcess()->GetDAC();
2619 VMPTR_Object vmObj = pDAC->GetObject(objAddr);
2620
2621 // retrieve type info from LS
2622 pDAC->GetRcwCachedInterfacePointers(vmObj, bIInspectableOnly, &dacItfPtrs);
2623 }
2624 EX_CATCH_HRESULT(hr);
2625 IfFailRet(hr);
2626
2627 // synthesize CordbType instances
2628 cItfs = (ULONG32)dacItfPtrs.Count();
2629
2630 if (pcEltFetched != NULL && ptrs == NULL)
2631 {
2632 *pcEltFetched = cItfs;
2633 return S_OK;
2634 }
2635
2636 if (pcEltFetched != NULL)
2637 {
2638 *pcEltFetched = (cItfs <= celt ? cItfs : celt);
2639 }
2640
2641 if (ptrs != NULL && *pcEltFetched > 0)
2642 {
2643 for (ULONG32 i = 0; i < *pcEltFetched; ++i)
2644 ptrs[i] = dacItfPtrs[i];
2645 }
2646
2647 return (*pcEltFetched == celt ? S_OK : S_FALSE);
2648
2649#endif
2650}
2651
2652
2653/* ------------------------------------------------------------------------- *
2654 * Value Class Object
2655 * ------------------------------------------------------------------------- */
2656
2657// constructor
2658// Arguments:
2659// input: pAppdomain - app domain to which the value belongs
2660// pType - type information for the value
2661// remoteValue - buffer describing the target location of the value
2662// ppRemoteRegAddr - describes the register information if the value resides in a register
2663// Note: May throw E_OUTOFMEMORY
2664CordbVCObjectValue::CordbVCObjectValue(CordbAppDomain * pAppdomain,
2665 CordbType * pType,
2666 TargetBuffer remoteValue,
2667 EnregisteredValueHomeHolder * ppRemoteRegAddr)
2668
2669 // We'd like to neuter this on Continue (not just exit), but it may be a breaking change,
2670 // especially for ValueTypes that don't have any GC refs in them.
2671 : CordbValue(pAppdomain,
2672 pType,
2673 remoteValue.pAddress,
2674 false,
2675 pAppdomain->GetSweepableExitNeuterList()),
2676 m_pObjectCopy(NULL),
2677 m_pValueHome(NULL)
2678{
2679 // instantiate the value home
2680 NewHolder<ValueHome> pHome(NULL);
2681
2682 if (remoteValue.IsEmpty())
2683 {
2684 pHome = (new RegisterValueHome(pAppdomain->GetProcess(), ppRemoteRegAddr));
2685 }
2686 else
2687 {
2688 pHome = (new VCRemoteValueHome(pAppdomain->GetProcess(), remoteValue));
2689 }
2690 m_pValueHome = pHome.GetValue(); // throws
2691 pHome.SuppressRelease();
2692} // CordbVCObjectValue::CordbVCObjectValue
2693
2694// destructor
2695CordbVCObjectValue::~CordbVCObjectValue()
2696{
2697 DTOR_ENTRY(this);
2698
2699 _ASSERTE(IsNeutered());
2700
2701 // Destroy the copy of the object.
2702 if (m_pObjectCopy != NULL)
2703 {
2704 delete [] m_pObjectCopy;
2705 m_pObjectCopy = NULL;
2706 }
2707
2708 // destroy the value home
2709 if (m_pValueHome != NULL)
2710 {
2711 delete m_pValueHome;
2712 m_pValueHome = NULL;
2713}
2714} // CordbVCObjectValue::~CordbVCObjectValue
2715
2716HRESULT CordbVCObjectValue::QueryInterface(REFIID id, void **pInterface)
2717{
2718 if (id == IID_ICorDebugValue)
2719 {
2720 *pInterface = static_cast<ICorDebugValue*>(static_cast<ICorDebugObjectValue*>(this));
2721 }
2722 else if (id == IID_ICorDebugValue2)
2723 {
2724 *pInterface = static_cast<ICorDebugValue2*>(this);
2725 }
2726 else if (id == IID_ICorDebugValue3)
2727 {
2728 *pInterface = static_cast<ICorDebugValue3*>(this);
2729 }
2730 else if (id == IID_ICorDebugObjectValue)
2731 {
2732 *pInterface = static_cast<ICorDebugObjectValue*>(this);
2733 }
2734 else if (id == IID_ICorDebugObjectValue2)
2735
2736 {
2737 *pInterface = static_cast<ICorDebugObjectValue2*>(this);
2738 }
2739 else if (id == IID_ICorDebugGenericValue)
2740 {
2741 *pInterface = static_cast<ICorDebugGenericValue*>(this);
2742 }
2743 else if (id == IID_IUnknown)
2744 {
2745 *pInterface = static_cast<IUnknown*>(static_cast<ICorDebugObjectValue*>(this));
2746 }
2747 else
2748 {
2749 *pInterface = NULL;
2750 return E_NOINTERFACE;
2751 }
2752
2753 ExternalAddRef();
2754 return S_OK;
2755} // CordbVCObjectValue::QueryInterface
2756
2757// returns the basic type of the ICDValue
2758// Arguments:
2759// output: pType - the type of the ICDValue (always E_T_VALUETYPE)
2760// ReturnValue: S_OK on success or E_INVALIDARG if pType is NULL
2761HRESULT CordbVCObjectValue::GetType(CorElementType *pType)
2762{
2763 PUBLIC_REENTRANT_API_ENTRY(this);
2764 VALIDATE_POINTER_TO_OBJECT(pType, CorElementType *);
2765
2766 *pType = ELEMENT_TYPE_VALUETYPE;
2767 return S_OK;
2768} // CordbVCObjectValue::GetType
2769
2770// public API to get the CordbClass field
2771// Arguments:
2772// output: ppClass - holds a pointer to the ICDClass instance belonging to this
2773// Return Value: S_OK on success, CORDBG_E_OBJECT_NEUTERED or synchronization errors on failure
2774HRESULT CordbVCObjectValue::GetClass(ICorDebugClass **ppClass)
2775{
2776 PUBLIC_REENTRANT_API_ENTRY(this);
2777 FAIL_IF_NEUTERED(this);
2778 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
2779 *ppClass = (ICorDebugClass*) GetClass();
2780
2781 if (*ppClass != NULL)
2782 (*ppClass)->AddRef();
2783
2784 return S_OK;
2785} // CordbVCObjectValue::GetClass
2786
2787// internal method to get the CordbClass field
2788// Arguments: none
2789// ReturnValue: the instance of CordbClass belonging to this VC object
2790CordbClass *CordbVCObjectValue::GetClass()
2791{
2792 CordbClass *tycon;
2793 Instantiation inst;
2794 m_type->DestConstructedType(&tycon, &inst);
2795 return tycon;
2796} // CordbVCObjectValue::GetClass
2797
2798//-----------------------------------------------------------------------------
2799//
2800// Finds the given field of the given type in the object and returns an ICDValue for it.
2801//
2802// Arguments:
2803// pType - The type of the field
2804// fieldDef - The field's metadata def.
2805// ppValue - OUT: the ICDValue for the field.
2806//
2807// Returns:
2808// S_OK on success, CORDBG_E_OBJECT_NEUTERED, E_INVALIDARG, CORDBG_E_ENC_HANGING_FIELD, or various other
2809// failure codes
2810HRESULT CordbVCObjectValue::GetFieldValueForType(ICorDebugType * pType,
2811 mdFieldDef fieldDef,
2812 ICorDebugValue ** ppValue)
2813{
2814 PUBLIC_REENTRANT_API_ENTRY(this);
2815 FAIL_IF_NEUTERED(this);
2816 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
2817
2818 HRESULT hr = S_OK;
2819 EX_TRY
2820 {
2821 // Validate the token.
2822 if ((m_type->m_pClass == NULL) || !m_type->m_pClass->GetModule()->GetMetaDataImporter()->IsValidToken(fieldDef))
2823 {
2824 ThrowHR(E_INVALIDARG);
2825 }
2826
2827
2828 CordbType * pCordbType;
2829
2830 //
2831 // <TODO>@todo: need to ensure that pClass is really on the class
2832 // hierarchy of m_class!!!</TODO>
2833 //
2834 if (pType == NULL)
2835 {
2836 pCordbType = m_type;
2837 }
2838 else
2839 {
2840 pCordbType = static_cast<CordbType *> (pType);
2841 }
2842
2843 FieldData * pFieldData;
2844
2845 #ifdef _DEBUG
2846 pFieldData = NULL;
2847 #endif
2848
2849 hr = pCordbType->GetFieldInfo(fieldDef, &pFieldData);
2850 _ASSERTE(hr != CORDBG_E_ENC_HANGING_FIELD);
2851
2852 // If we get back CORDBG_E_ENC_HANGING_FIELD we'll just fail -
2853 // value classes should not be able to add fields once they're loaded,
2854 // since the new fields _can't_ be contiguous with the old fields,
2855 // and having all the fields contiguous is kinda the point of a V.C.
2856 IfFailThrow(hr);
2857
2858 _ASSERTE(pFieldData != NULL);
2859
2860 CordbModule * pModule = pCordbType->m_pClass->GetModule();
2861
2862 SigParser sigParser;
2863 IfFailThrow(pFieldData->GetFieldSignature(pModule, &sigParser));
2864
2865 // <TODO>
2866 // How can I assert that I have exactly one field?
2867 // </TODO>
2868 CordbType * pFieldType;
2869
2870 IfFailThrow(CordbType::SigToType(pModule, &sigParser, &(pCordbType->m_inst), &pFieldType));
2871
2872 _ASSERTE(pFieldData->OkToGetOrSetInstanceOffset());
2873 // Compute the address of the field contents in our local object cache
2874 SIZE_T fieldOffset = pFieldData->GetInstanceOffset();
2875 ULONG32 size = GetSizeForType(pFieldType, kUnboxed);
2876
2877 // verify that the field starts before the end of m_pObjectCopy
2878 _ASSERTE(fieldOffset < m_size);
2879 _ASSERTE(fieldOffset + size <= m_size);
2880
2881 m_pValueHome->CreateInternalValue(pFieldType,
2882 fieldOffset,
2883 m_pObjectCopy + fieldOffset,
2884 size,
2885 ppValue); // throws
2886
2887 }
2888 EX_CATCH_HRESULT(hr);
2889 return hr;
2890} // CordbVCObjectValue::GetFieldValueForType
2891
2892// gets an ICDValue to represent a field of the VC object
2893// Arguments:
2894// input: pClass - the class information for this object (needed to get the parent class information)
2895// fieldDef - field token for the desired field
2896// output: ppValue - on success, the ICDValue representing the desired field
2897// Return Value: S_OK on success, CORDBG_E_OBJECT_NEUTERED, CORDBG_E_CLASS_NOT_LOADED, E_INVALIDARG, OOM,
2898// CORDBG_E_ENC_HANGING_FIELD, or various other failure codes
2899HRESULT CordbVCObjectValue::GetFieldValue(ICorDebugClass *pClass,
2900 mdFieldDef fieldDef,
2901 ICorDebugValue **ppValue)
2902{
2903 PUBLIC_REENTRANT_API_ENTRY(this);
2904 FAIL_IF_NEUTERED(this);
2905 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
2906 VALIDATE_POINTER_TO_OBJECT(pClass, ICorDebugClass *);
2907 VALIDATE_POINTER_TO_OBJECT(ppValue, ICorDebugValue **);
2908
2909 HRESULT hr;
2910 _ASSERTE(m_type);
2911
2912 if (m_type->m_elementType != ELEMENT_TYPE_CLASS &&
2913 m_type->m_elementType != ELEMENT_TYPE_VALUETYPE)
2914 {
2915 return E_INVALIDARG;
2916 }
2917
2918 RSExtSmartPtr<CordbType> relevantType;
2919
2920 if (FAILED (hr= m_type->GetParentType((CordbClass *) pClass, &relevantType)))
2921 {
2922 return hr;
2923 }
2924 // Upon exit relevantType will either be the appropriate type for the
2925 // class we're looking for.
2926
2927 hr = GetFieldValueForType(relevantType, fieldDef, ppValue);
2928 // GetParentType ands one reference to relevantType, holder dtor releases that.
2929 return hr;
2930
2931} // CordbVCObjectValue::GetFieldValue
2932
2933// get a copy of the VC object
2934// Arguments:
2935// output: pTo - a caller-allocated buffer to hold the copy
2936// Return Value: S_OK on success, CORDBG_E_OBJECT_NEUTERED on failure
2937// Note: The caller must ensure the buffer is large enough to hold the value (by a previous call to GetSize)
2938// and is responsible for allocation and deallocation.
2939HRESULT CordbVCObjectValue::GetValue(void *pTo)
2940{
2941 VALIDATE_POINTER_TO_OBJECT_ARRAY(pTo, BYTE, m_size, false, true);
2942 FAIL_IF_NEUTERED(this);
2943
2944 // Copy out the value, which is the whole object.
2945 memcpy(pTo, m_pObjectCopy, m_size);
2946
2947 return S_OK;
2948} // CordbVCObjectValue::GetValue
2949
2950// set the value of a VC object
2951// Arguments:
2952// input: pSrc - buffer containing the new value. Allocated and managed by the caller.
2953// Return Value: S_OK on success, CORDBG_E_OBJECT_NEUTERED, synchronization errors, E_INVALIDARG, write
2954// process memory errors, CORDBG_E_CLASS_NOT_LOADED or OOM on failure
2955HRESULT CordbVCObjectValue::SetValue(void * pSrc)
2956{
2957 PUBLIC_REENTRANT_API_ENTRY(this);
2958 FAIL_IF_NEUTERED(this);
2959 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
2960
2961 HRESULT hr = S_OK;
2962
2963 VALIDATE_POINTER_TO_OBJECT_ARRAY(pSrc, BYTE, m_size, true, false);
2964
2965 // Can't change literals...
2966 if (m_isLiteral)
2967 return E_INVALIDARG;
2968
2969 if (m_type)
2970 {
2971 IfFailRet(m_type->Init(FALSE));
2972 }
2973
2974 EX_TRY
2975 {
2976 m_pValueHome->SetValue(MemoryRange(pSrc, m_size), m_type); // throws
2977 }
2978 EX_CATCH_HRESULT(hr);
2979 if (SUCCEEDED(hr))
2980 {
2981 // That worked, so update the copy of the value we have over here.
2982 memcpy(m_pObjectCopy, pSrc, m_size);
2983 }
2984
2985 return hr;
2986} // CordbVCObjectValue::SetValue
2987
2988HRESULT CordbVCObjectValue::GetVirtualMethod(mdMemberRef memberRef,
2989 ICorDebugFunction **ppFunction)
2990{
2991 return E_NOTIMPL;
2992}
2993
2994HRESULT CordbVCObjectValue::GetVirtualMethodAndType(mdMemberRef memberRef,
2995 ICorDebugFunction **ppFunction,
2996 ICorDebugType **ppType)
2997{
2998 return E_NOTIMPL;
2999}
3000
3001HRESULT CordbVCObjectValue::GetContext(ICorDebugContext **ppContext)
3002{
3003 return E_NOTIMPL;
3004}
3005
3006// self-identifier--always returns true as long as pbIsValueClass is non-Null
3007HRESULT CordbVCObjectValue::IsValueClass(BOOL *pbIsValueClass)
3008{
3009 if (pbIsValueClass)
3010 *pbIsValueClass = TRUE;
3011
3012 return S_OK;
3013} // CordbVCObjectValue::IsValueClass
3014
3015HRESULT CordbVCObjectValue::GetManagedCopy(IUnknown **ppObject)
3016{
3017 // This function is deprecated
3018 return E_NOTIMPL;
3019}
3020
3021HRESULT CordbVCObjectValue::SetFromManagedCopy(IUnknown *pObject)
3022{
3023 // This function is deprecated
3024 return E_NOTIMPL;
3025}
3026
3027 //
3028// CordbVCObjectValue::Init
3029//
3030// Description
3031// Initializes the Right-Side's representation of a Value Class object.
3032// Parameters
3033// input: localValue - buffer containing the value if this instance of CordbObjectValue
3034// was a field or array element of an existing value, otherwise this
3035// will have a start address equal to NULL
3036// Returns
3037// HRESULT
3038// S_OK if the function completed normally
3039// failing HR otherwise
3040// Exceptions
3041// None
3042//
3043HRESULT CordbVCObjectValue::Init(MemoryRange localValue)
3044{
3045 HRESULT hr = S_OK;
3046
3047 INTERNAL_SYNC_API_ENTRY(this->GetProcess()); //
3048
3049 // Get the object size from the class
3050 ULONG32 size;
3051 IfFailRet( m_type->GetUnboxedObjectSize(&size) );
3052 m_size = size;
3053
3054 // Copy the entire object over to this process.
3055 m_pObjectCopy = new (nothrow) BYTE[m_size];
3056
3057 if (m_pObjectCopy == NULL)
3058 {
3059 return E_OUTOFMEMORY;
3060 }
3061
3062 if (localValue.StartAddress() != NULL)
3063 {
3064 // The data is already in the local address space. Go ahead and copy it
3065 // from there.
3066 // localValue.StartAddress points to:
3067 // 1. A field from the local cached copy belonging to an instance of CordbVCObjectValue (different
3068 // instance from "this") or CordbObjectValue
3069 // 2. An element in the locally cached subrange of an array belonging to an instance of CordbArrayValue
3070 // 3. The address of a particular register in the register display of an instance of CordbNativeFrame
3071 // for an enregistered value type. In this case, it's possible that the size of the value is
3072 // smaller than the size of a full register. For that reason, we can't just use localValue.Size()
3073 // as the number of bytes to copy, because only enough space for the value has been allocated.
3074 _ASSERTE(localValue.Size() >= m_size);
3075 localCopy(m_pObjectCopy, MemoryRange(localValue.StartAddress(), m_size));
3076 return S_OK;
3077 }
3078
3079 EX_TRY
3080 {
3081 m_pValueHome->GetValue(MemoryRange(m_pObjectCopy, m_size)); // throws
3082 }
3083 EX_CATCH_HRESULT(hr);
3084 return hr;
3085} // CordbVCObjectValue::Init
3086
3087/* ------------------------------------------------------------------------- *
3088 * Box Value class
3089 * ------------------------------------------------------------------------- */
3090
3091// constructor
3092// Arguments:
3093// input: appdomain - app domain to which the value belongs
3094// type - type information for the boxed value
3095// remoteValue - buffer describing the remote location of the value
3096// size - size of the value
3097// offsetToVars - offset from the beginning of the value to the first field of the value
3098CordbBoxValue::CordbBoxValue(CordbAppDomain *appdomain,
3099 CordbType *type,
3100 TargetBuffer remoteValue,
3101 ULONG32 size,
3102 SIZE_T offsetToVars)
3103 : CordbValue(appdomain, type, remoteValue.pAddress, false, appdomain->GetProcess()->GetContinueNeuterList()),
3104 m_offsetToVars(offsetToVars),
3105 m_valueHome(appdomain->GetProcess(), remoteValue)
3106{
3107 m_size = size;
3108} // CordbBoxValue::CordbBoxValue
3109
3110// destructor
3111CordbBoxValue::~CordbBoxValue()
3112{
3113 DTOR_ENTRY(this);
3114 _ASSERTE(IsNeutered());
3115} // CordbBoxValue::~CordbBoxValue
3116
3117HRESULT CordbBoxValue::QueryInterface(REFIID id, void **pInterface)
3118{
3119 if (id == IID_ICorDebugValue)
3120 {
3121 *pInterface = static_cast<ICorDebugValue*>(static_cast<ICorDebugBoxValue*>(this));
3122 }
3123 else if (id == IID_ICorDebugValue2)
3124 {
3125 *pInterface = static_cast<ICorDebugValue2*>(this);
3126 }
3127 else if (id == IID_ICorDebugValue3)
3128 {
3129 *pInterface = static_cast<ICorDebugValue3*>(this);
3130 }
3131 else if (id == IID_ICorDebugBoxValue)
3132 {
3133 *pInterface = static_cast<ICorDebugBoxValue*>(this);
3134 }
3135 else if (id == IID_ICorDebugGenericValue)
3136 {
3137 *pInterface = static_cast<ICorDebugGenericValue*>(this);
3138 }
3139 else if (id == IID_ICorDebugHeapValue)
3140 {
3141 *pInterface = static_cast<ICorDebugHeapValue*>(this);
3142 }
3143 else if (id == IID_ICorDebugHeapValue2)
3144 {
3145 *pInterface = static_cast<ICorDebugHeapValue2*>(this);
3146 }
3147 else if (id == IID_ICorDebugHeapValue3)
3148 {
3149 *pInterface = static_cast<ICorDebugHeapValue3*>(this);
3150 }
3151 else if (id == IID_IUnknown)
3152 {
3153 *pInterface = static_cast<IUnknown*>(static_cast<ICorDebugBoxValue*>(this));
3154 }
3155 else
3156 {
3157 *pInterface = NULL;
3158 return E_NOINTERFACE;
3159 }
3160
3161 ExternalAddRef();
3162 return S_OK;
3163} // CordbBoxValue::QueryInterface
3164
3165// returns the basic type of the ICDValue
3166// Arguments:
3167// output: pType - the type of the ICDValue (always E_T_CLASS)
3168// ReturnValue: S_OK on success or E_INVALIDARG if pType is NULL
3169HRESULT CordbBoxValue::GetType(CorElementType *pType)
3170{
3171 VALIDATE_POINTER_TO_OBJECT(pType, CorElementType *);
3172
3173 *pType = ELEMENT_TYPE_CLASS;
3174
3175 return (S_OK);
3176} // CordbBoxValue::GetType
3177
3178HRESULT CordbBoxValue::IsValid(BOOL *pbValid)
3179{
3180 VALIDATE_POINTER_TO_OBJECT(pbValid, BOOL *);
3181
3182 // <TODO>@todo: implement tracking of objects across collections.</TODO>
3183
3184 return E_NOTIMPL;
3185}
3186
3187HRESULT CordbBoxValue::CreateRelocBreakpoint(ICorDebugValueBreakpoint **ppBreakpoint)
3188{
3189 VALIDATE_POINTER_TO_OBJECT(ppBreakpoint, ICorDebugValueBreakpoint **);
3190
3191 return E_NOTIMPL;
3192}
3193
3194// Creates a handle of the given type for this heap value.
3195// Not Implemented In-Proc.
3196// Create a handle for a heap object.
3197// @todo: How to prevent this being called by non-heap object?
3198// Arguments:
3199// input: handleType - type of the handle to be created
3200// output: ppHandle - on success, the newly created handle
3201// Return Value: S_OK on success or E_INVALIDARG, E_OUTOFMEMORY, or CORDB_E_HELPER_MAY_DEADLOCK
3202HRESULT CordbBoxValue::CreateHandle(
3203 CorDebugHandleType handleType,
3204 ICorDebugHandleValue ** ppHandle)
3205{
3206 PUBLIC_API_ENTRY(this);
3207 FAIL_IF_NEUTERED(this);
3208 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
3209
3210 return CordbValue::InternalCreateHandle(handleType, ppHandle);
3211} // CordbBoxValue::CreateHandle
3212
3213HRESULT CordbBoxValue::GetValue(void *pTo)
3214{
3215 // Can't get a whole copy of a box.
3216 return E_INVALIDARG;
3217}
3218
3219HRESULT CordbBoxValue::SetValue(void *pFrom)
3220{
3221 // You're not allowed to set a box value.
3222 return E_INVALIDARG;
3223}
3224
3225// gets the unboxed value from this boxed value
3226// Arguments:
3227// output: ppObject - pointer to an instance of ICDValue representing the unboxed value, unless ppObject
3228// is NULL
3229// Return Value: S_OK on success or a variety of possible failures: OOM, E_FAIL, errors from
3230// ReadProcessMemory.
3231HRESULT CordbBoxValue::GetObject(ICorDebugObjectValue **ppObject)
3232{
3233 PUBLIC_REENTRANT_API_ENTRY(this);
3234 VALIDATE_POINTER_TO_OBJECT(ppObject, ICorDebugObjectValue **);
3235 FAIL_IF_NEUTERED(this);
3236 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
3237
3238 ULONG32 size;
3239 m_type->GetUnboxedObjectSize(&size);
3240
3241 HRESULT hr = S_OK;
3242 EX_TRY
3243 {
3244 m_valueHome.CreateInternalValue(m_type,
3245 m_offsetToVars,
3246 NULL,
3247 size,
3248 reinterpret_cast<ICorDebugValue **>(ppObject)); // throws
3249 }
3250 EX_CATCH_HRESULT(hr);
3251 return hr;
3252} // CordbBoxValue::GetObject
3253
3254// If a managed thread owns the monitor lock on this object then *ppThread
3255// will point to that thread and S_OK will be returned. The thread object is valid
3256// until the thread exits. *pAcquisitionCount will indicate the number of times
3257// this thread would need to release the lock before it returns to being
3258// unowned.
3259// If no managed thread owns the monitor lock on this object then *ppThread
3260// and pAcquisitionCount will be unchanged and S_FALSE returned.
3261// If ppThread or pAcquisitionCount is not a valid pointer the result is
3262// undefined.
3263// If any error occurs such that it cannot be determined which, if any, thread
3264// owns the monitor lock on this object then a failing HRESULT will be returned
3265HRESULT CordbBoxValue::GetThreadOwningMonitorLock(ICorDebugThread **ppThread, DWORD *pAcquisitionCount)
3266{
3267 PUBLIC_API_ENTRY(this);
3268 FAIL_IF_NEUTERED(this);
3269 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
3270
3271 return CordbHeapValue3Impl::GetThreadOwningMonitorLock(GetProcess(),
3272 GetValueHome()->GetAddress(),
3273 ppThread,
3274 pAcquisitionCount);
3275}
3276
3277// Provides an ordered list of threads which are queued on the event associated
3278// with a monitor lock. The first thread in the list is the first thread which
3279// will be released by the next call to Monitor.Pulse, the next thread in the list
3280// will be released on the following call, and so on.
3281// If this list is non-empty S_OK will be returned, if it is empty S_FALSE
3282// will be returned (the enumeration is still valid, just empty).
3283// In either case the enumeration interface is only usable for the duration
3284// of the current synchronized state, however the threads interfaces dispensed
3285// from it are valid until the thread exits.
3286// If ppThread is not a valid pointer the result is undefined.
3287// If any error occurs such that it cannot be determined which, if any, threads
3288// are waiting for the monitor then a failing HRESULT will be returned
3289HRESULT CordbBoxValue::GetMonitorEventWaitList(ICorDebugThreadEnum **ppThreadEnum)
3290{
3291 PUBLIC_API_ENTRY(this);
3292 FAIL_IF_NEUTERED(this);
3293 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
3294
3295 return CordbHeapValue3Impl::GetMonitorEventWaitList(GetProcess(),
3296 GetValueHome()->GetAddress(),
3297 ppThreadEnum);
3298}
3299
3300
3301/* ------------------------------------------------------------------------- *
3302 * Array Value class
3303 * ------------------------------------------------------------------------- */
3304
3305// The size of the buffer we allocate to hold array elements.
3306// Note that since we must be able to hold at least one element, we may
3307// allocate larger than the cache size here.
3308// Also, this cache doesn't include a small header used to store the rank vectors
3309#ifdef _DEBUG
3310// For debug, use a small size to cause more churn
3311 #define ARRAY_CACHE_SIZE (1000)
3312#else
3313// For release, guess 4 pages should be enough. Subtract some bytes to store
3314// the header so that that doesn't push us onto another page. (We guess a reasonable
3315// header size, but it's ok if it's larger).
3316 #define ARRAY_CACHE_SIZE (4 * 4096 - 24)
3317#endif
3318
3319// constructor
3320// Arguments:
3321// input:
3322// pAppDomain - app domain to which the value belongs
3323// pType - type information for the value
3324// pObjectInfo - array specific type information
3325// remoteValue - buffer describing the remote location of the value
3326CordbArrayValue::CordbArrayValue(CordbAppDomain * pAppdomain,
3327 CordbType * pType,
3328 DebuggerIPCE_ObjectData * pObjectInfo,
3329 TargetBuffer remoteValue)
3330 : CordbValue(pAppdomain,
3331 pType,
3332 remoteValue.pAddress,
3333 false,
3334 pAppdomain->GetProcess()->GetContinueNeuterList()),
3335 m_info(*pObjectInfo),
3336 m_pObjectCopy(NULL),
3337 m_valueHome(pAppdomain->GetProcess(), remoteValue)
3338{
3339 m_size = m_info.objSize;
3340 pType->DestUnaryType(&m_elemtype);
3341
3342// Set range to illegal values to force a load on first access
3343 m_idxLower = m_idxUpper = (SIZE_T) -1;
3344} // CordbArrayValue::CordbArrayValue
3345
3346// destructor
3347CordbArrayValue::~CordbArrayValue()
3348{
3349 DTOR_ENTRY(this);
3350 _ASSERTE(IsNeutered());
3351
3352 // Destroy the copy of the object.
3353 if (m_pObjectCopy != NULL)
3354 delete [] m_pObjectCopy;
3355} // CordbArrayValue::~CordbArrayValue
3356
3357HRESULT CordbArrayValue::QueryInterface(REFIID id, void **pInterface)
3358{
3359 if (id == IID_ICorDebugValue)
3360 {
3361 *pInterface = static_cast<ICorDebugValue*>(static_cast<ICorDebugArrayValue*>(this));
3362 }
3363 else if (id == IID_ICorDebugValue2)
3364 {
3365 *pInterface = static_cast<ICorDebugValue2*>(this);
3366 }
3367 else if (id == IID_ICorDebugValue3)
3368 {
3369 *pInterface = static_cast<ICorDebugValue3*>(this);
3370 }
3371 else if (id == IID_ICorDebugArrayValue)
3372 {
3373 *pInterface = static_cast<ICorDebugArrayValue*>(this);
3374 }
3375 else if (id == IID_ICorDebugGenericValue)
3376 {
3377 *pInterface = static_cast<ICorDebugGenericValue*>(this);
3378 }
3379 else if (id == IID_ICorDebugHeapValue)
3380 {
3381 *pInterface = static_cast<ICorDebugHeapValue*>(this);
3382 }
3383 else if (id == IID_ICorDebugHeapValue2)
3384 {
3385 *pInterface = static_cast<ICorDebugHeapValue2*>(this);
3386 }
3387 else if (id == IID_ICorDebugHeapValue3)
3388 {
3389 *pInterface = static_cast<ICorDebugHeapValue3*>(this);
3390 }
3391 else if (id == IID_IUnknown)
3392 {
3393 *pInterface = static_cast<IUnknown*>(static_cast<ICorDebugArrayValue*>(this));
3394 }
3395 else
3396 {
3397 *pInterface = NULL;
3398 return E_NOINTERFACE;
3399 }
3400
3401 ExternalAddRef();
3402 return S_OK;
3403} // CordbArrayValue::QueryInterface
3404
3405// gets the type of the array elements
3406// Arguments:
3407// output: pType - the element type unless pType is NULL
3408// Return Value: S_OK on success or E_INVALIDARG if pType is null
3409HRESULT CordbArrayValue::GetElementType(CorElementType *pType)
3410{
3411 PUBLIC_REENTRANT_API_ENTRY(this);
3412 FAIL_IF_NEUTERED(this);
3413 VALIDATE_POINTER_TO_OBJECT(pType, CorElementType *);
3414
3415 *pType = m_elemtype->m_elementType;
3416 return S_OK;
3417} // CordbArrayValue::GetElementType
3418
3419
3420// gets the rank of the array
3421// Arguments:
3422// output: pnRank - the rank of the array unless pnRank is null
3423// Return Value: S_OK on success or E_INVALIDARG if pnRank is null
3424HRESULT CordbArrayValue::GetRank(ULONG32 *pnRank)
3425{
3426 PUBLIC_REENTRANT_API_ENTRY(this);
3427 FAIL_IF_NEUTERED(this);
3428 VALIDATE_POINTER_TO_OBJECT(pnRank, SIZE_T *);
3429
3430 // Rank info is duplicated for sanity checking - double check it here.
3431 _ASSERTE(m_info.arrayInfo.rank == m_type->m_rank);
3432 *pnRank = m_type->m_rank;
3433 return S_OK;
3434} // CordbArrayValue::GetRank
3435
3436// gets the number of elements in the array
3437// Arguments:
3438// output: pnCount - the number of dimensions for the array unless pnCount is null
3439// Return Value: S_OK on success or E_INVALIDARG if pnCount is null
3440HRESULT CordbArrayValue::GetCount(ULONG32 *pnCount)
3441{
3442 PUBLIC_REENTRANT_API_ENTRY(this);
3443 FAIL_IF_NEUTERED(this);
3444 VALIDATE_POINTER_TO_OBJECT(pnCount, ULONG32 *);
3445
3446 *pnCount = (ULONG32)m_info.arrayInfo.componentCount;
3447 return S_OK;
3448} // CordbArrayValue::GetCount
3449
3450// get the size of each dimension of the array
3451// Arguments:
3452// input: cdim - the number of dimensions about which to get dimensions--this must be the same as the rank
3453// output: dims - an array to hold the sizes of the dimensions of the array--this is allocated and
3454// managed by the caller
3455// Return Value: S_OK on success or E_INVALIDARG
3456HRESULT CordbArrayValue::GetDimensions(ULONG32 cdim, ULONG32 dims[])
3457{
3458 PUBLIC_REENTRANT_API_ENTRY(this);
3459 FAIL_IF_NEUTERED(this);
3460 VALIDATE_POINTER_TO_OBJECT_ARRAY(dims, SIZE_T, cdim, true, true);
3461 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
3462
3463 // Rank info is duplicated for sanity checking - double check it here.
3464 _ASSERTE(m_info.arrayInfo.rank == m_type->m_rank);
3465 if (cdim != m_type->m_rank)
3466 return E_INVALIDARG;
3467
3468 // SDArrays don't have bounds info, so return the component count.
3469 if (cdim == 1)
3470 dims[0] = (ULONG32)m_info.arrayInfo.componentCount;
3471 else
3472 {
3473 _ASSERTE(m_info.arrayInfo.offsetToUpperBounds != 0);
3474 _ASSERTE(m_arrayUpperBase != NULL);
3475
3476 // The upper bounds info in the array is the true size of each
3477 // dimension.
3478 for (unsigned int i = 0; i < cdim; i++)
3479 dims[i] = m_arrayUpperBase[i];
3480 }
3481
3482 return S_OK;
3483} // CordbArrayValue::GetDimensions
3484
3485//
3486// indicates whether the array has base indices
3487// Arguments:
3488// output: pbHasBaseIndices - true iff the array has more than one dimension and pbHasBaseIndices is not null
3489// Return Value: S_OK on success or E_INVALIDARG if pbHasBaseIndices is null
3490HRESULT CordbArrayValue::HasBaseIndicies(BOOL *pbHasBaseIndices)
3491{
3492 PUBLIC_REENTRANT_API_ENTRY(this);
3493 FAIL_IF_NEUTERED(this);
3494 VALIDATE_POINTER_TO_OBJECT(pbHasBaseIndices, BOOL *);
3495
3496 *pbHasBaseIndices = m_info.arrayInfo.offsetToLowerBounds != 0;
3497 return S_OK;
3498} // CordbArrayValue::HasBaseIndicies
3499
3500// gets the base indices for a multidimensional array
3501// Arguments:
3502// input: cdim - the number of dimensions (this must be the same as the actual rank of the array)
3503// indices - an array to hold the base indices for the array dimensions (allocated and managed
3504// by the caller, it must have space for cdim elements)
3505// Return Value: S_OK on success or E_INVALIDARG if cdim is not equal to the array rank or indices is null
3506HRESULT CordbArrayValue::GetBaseIndicies(ULONG32 cdim, ULONG32 indices[])
3507{
3508 PUBLIC_REENTRANT_API_ENTRY(this);
3509 FAIL_IF_NEUTERED(this);
3510 VALIDATE_POINTER_TO_OBJECT_ARRAY(indices, SIZE_T, cdim, true, true);
3511
3512 // Rank info is duplicated for sanity checking - double check it here.
3513 _ASSERTE(m_info.arrayInfo.rank == m_type->m_rank);
3514 if ((cdim != m_type->m_rank) ||
3515 (m_info.arrayInfo.offsetToLowerBounds == 0))
3516 return E_INVALIDARG;
3517
3518 _ASSERTE(m_arrayLowerBase != NULL);
3519
3520 for (unsigned int i = 0; i < cdim; i++)
3521 indices[i] = m_arrayLowerBase[i];
3522
3523 return S_OK;
3524} // CordbArrayValue::GetBaseIndicies
3525
3526// Get an element at the position indicated by the values in indices (one index for each dimension)
3527// Arguments:
3528// input: cdim - the number of dimensions and thus the number of elements in indices. This must match
3529// the actual rank of the array value.
3530// indices - an array of indices to specify the position of the element. For example, to get a[2][1][0],
3531// indices would contain 2, 1, and 0 in that order.
3532// output: ppValue - an ICDValue representing the element, unless an error occurs
3533// Return Value: S_OK on success or E_INVALIDARG if cdim != rank, indices is NULL or ppValue is NULL
3534// or a variety of possible failures: OOM, E_FAIL, errors from
3535// ReadProcessMemory.
3536HRESULT CordbArrayValue::GetElement(ULONG32 cdim,
3537 ULONG32 indices[],
3538 ICorDebugValue **ppValue)
3539{
3540 PUBLIC_REENTRANT_API_ENTRY(this);
3541 VALIDATE_POINTER_TO_OBJECT_ARRAY(indices, SIZE_T, cdim, true, true);
3542 VALIDATE_POINTER_TO_OBJECT(ppValue, ICorDebugValue **);
3543 FAIL_IF_NEUTERED(this);
3544 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
3545
3546 *ppValue = NULL;
3547
3548 // Rank info is duplicated for sanity checking - double check it here.
3549 _ASSERTE(m_info.arrayInfo.rank == m_type->m_rank);
3550 if ((cdim != m_type->m_rank) || (indices == NULL))
3551 return E_INVALIDARG;
3552
3553 // If the array has lower bounds, adjust the indices.
3554 if (m_info.arrayInfo.offsetToLowerBounds != 0)
3555 {
3556 _ASSERTE(m_arrayLowerBase != NULL);
3557
3558 for (unsigned int i = 0; i < cdim; i++)
3559 indices[i] -= m_arrayLowerBase[i];
3560 }
3561
3562 SIZE_T offset = 0;
3563
3564 // SDArrays don't have upper bounds
3565 if (cdim == 1)
3566 {
3567 offset = indices[0];
3568
3569 // Bounds check
3570 if (offset >= m_info.arrayInfo.componentCount)
3571 return E_INVALIDARG;
3572 }
3573 else
3574 {
3575 _ASSERTE(m_info.arrayInfo.offsetToUpperBounds != 0);
3576 _ASSERTE(m_arrayUpperBase != NULL);
3577
3578 // Calculate the offset in bytes for all dimensions.
3579 SIZE_T multiplier = 1;
3580
3581 for (int i = cdim - 1; i >= 0; i--)
3582 {
3583 // Bounds check
3584 if (indices[i] >= m_arrayUpperBase[i])
3585 return E_INVALIDARG;
3586
3587 offset += indices[i] * multiplier;
3588 multiplier *= m_arrayUpperBase[i];
3589 }
3590
3591 _ASSERTE(offset < m_info.arrayInfo.componentCount);
3592 }
3593
3594 return GetElementAtPosition((ULONG32)offset, ppValue);
3595} // CordbArrayValue::GetElement
3596
3597// get an ICDValue to represent the element at a given position
3598// Arguments:
3599// input: nPosition - the offset from the beginning of the array to the element
3600// output: ppValue - the ICDValue representing the array element on success
3601// Return Value: S_OK on success, E_INVALIDARG or a variety of possible failures: OOM, E_FAIL, errors from
3602// ReadProcessMemory.
3603HRESULT CordbArrayValue::GetElementAtPosition(ULONG32 nPosition,
3604 ICorDebugValue **ppValue)
3605{
3606 PUBLIC_REENTRANT_API_ENTRY(this);
3607 VALIDATE_POINTER_TO_OBJECT(ppValue, ICorDebugValue **);
3608 FAIL_IF_NEUTERED(this);
3609 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
3610
3611 if (nPosition >= m_info.arrayInfo.componentCount)
3612 {
3613 *ppValue = NULL;
3614 return E_INVALIDARG;
3615 }
3616
3617 // Rank info is duplicated for sanity checking - double check it here.
3618 _ASSERTE(m_info.arrayInfo.rank == m_type->m_rank);
3619
3620 // The header consists of two DWORDs for each dimension, representing the upper and lower bound for that dimension. A
3621 // vector of lower bounds comes first, followed by a vector of upper bounds. We want to copy a range of
3622 // elements into m_pObjectCopy following these vectors, so we need to compute the address where the
3623 // vectors end and the elements begin.
3624 const int cbHeader = 2 * m_type->m_rank * sizeof(DWORD);
3625 HRESULT hr = S_OK;
3626
3627 // Ensure that the proper subset is in the cache. m_idxLower and m_idxUpper are initialized to -1, so the
3628 // first time we hit this condition check, it will evaluate to true. We will set these inside the
3629 // consequent to the range starting at nPosition and ending at the last available cache position. Thus,
3630 // after the first time we hit this, we are asking if nPosition lies outside the range we've cached.
3631 if (nPosition < m_idxLower || nPosition >= m_idxUpper)
3632 {
3633 const SIZE_T cbElemSize = m_info.arrayInfo.elementSize;
3634 SIZE_T len = 1;
3635
3636 if (cbElemSize != 0)
3637 {
3638 // the element size could be bigger than the cache, but we want len to be at least 1.
3639 len = max(ARRAY_CACHE_SIZE / cbElemSize, len);
3640 }
3641 else _ASSERTE(cbElemSize != 0);
3642
3643 m_idxLower = nPosition;
3644 m_idxUpper = min(m_idxLower + len, m_info.arrayInfo.componentCount);
3645 _ASSERTE(m_idxLower < m_idxUpper);
3646
3647 SIZE_T cbOffsetFrom = m_info.arrayInfo.offsetToArrayBase + m_idxLower * cbElemSize;
3648
3649 SIZE_T cbSize = (m_idxUpper - m_idxLower) * cbElemSize; // we'll copy the largest range of ellements possible
3650
3651 _ASSERTE(cbSize <= m_info.objSize);
3652 // Copy the proper subrange of the array over
3653 EX_TRY
3654 {
3655 m_valueHome.GetInternalValue(MemoryRange(m_pObjectCopy + cbHeader, cbSize), cbOffsetFrom); // throws
3656 }
3657 EX_CATCH_HRESULT(hr);
3658 IfFailRet(hr);
3659 }
3660
3661 SIZE_T size = m_info.arrayInfo.elementSize;
3662 _ASSERTE(size <= m_info.objSize);
3663
3664 SIZE_T offset = m_info.arrayInfo.offsetToArrayBase + (nPosition * size);
3665 void * localAddress = m_pObjectCopy + cbHeader + ((nPosition - m_idxLower) * size);
3666
3667 EX_TRY
3668 {
3669 m_valueHome.CreateInternalValue(m_elemtype,
3670 offset,
3671 localAddress,
3672 (ULONG32)size,
3673 ppValue); // throws
3674 }
3675 EX_CATCH_HRESULT(hr);
3676 return hr;
3677
3678} // CordbArrayValue::GetElementAtPosition
3679
3680HRESULT CordbArrayValue::IsValid(BOOL *pbValid)
3681{
3682 VALIDATE_POINTER_TO_OBJECT(pbValid, BOOL *);
3683
3684 // <TODO>@todo: implement tracking of objects across collections.</TODO>
3685
3686 return E_NOTIMPL;
3687}
3688
3689HRESULT CordbArrayValue::CreateRelocBreakpoint(
3690 ICorDebugValueBreakpoint **ppBreakpoint)
3691{
3692 VALIDATE_POINTER_TO_OBJECT(ppBreakpoint, ICorDebugValueBreakpoint **);
3693
3694 return E_NOTIMPL;
3695}
3696
3697// Creates a handle of the given type for this heap value.
3698// Not Implemented In-Proc.
3699// Arguments:
3700// input: handleType - type of the handle to be created
3701// output: ppHandle - on success, the newly created handle
3702// Return Value: S_OK on success or E_INVALIDARG, E_OUTOFMEMORY, or CORDB_E_HELPER_MAY_DEADLOCK
3703HRESULT CordbArrayValue::CreateHandle(
3704 CorDebugHandleType handleType,
3705 ICorDebugHandleValue ** ppHandle)
3706{
3707 PUBLIC_API_ENTRY(this);
3708 FAIL_IF_NEUTERED(this);
3709 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
3710
3711 return CordbValue::InternalCreateHandle(handleType, ppHandle);
3712} // CordbArrayValue::CreateHandle
3713
3714// get a copy of the array
3715// Arguments
3716// output: pTo - pointer to a caller-allocated and managed buffer to hold the copy. The caller must guarantee
3717// that this is large enough to hold the entire array
3718// Return Value: S_OK on success, E_INVALIDARG or read process memory errors on failure
3719HRESULT CordbArrayValue::GetValue(void *pTo)
3720{
3721 VALIDATE_POINTER_TO_OBJECT_ARRAY(pTo, void *, 1, false, true);
3722 FAIL_IF_NEUTERED(this);
3723
3724 HRESULT hr = S_OK;
3725 EX_TRY
3726 {
3727 // Copy out the value, which is the whole array.
3728 // There's no lazy-evaluation here, so this could be rather large
3729 m_valueHome.GetValue(MemoryRange(pTo, m_size)); // throws
3730 }
3731 EX_CATCH_HRESULT(hr);
3732 return hr;
3733} // CordbArrayValue::GetValue
3734
3735HRESULT CordbArrayValue::SetValue(void *pFrom)
3736{
3737 // You're not allowed to set a whole array at once.
3738 return E_INVALIDARG;
3739}
3740
3741// initialize a new instance of CordbArrayValue
3742// Arguments: none
3743// Return Value: S_OK on success or E_OUTOFMEMORY or read process memory errors on failure
3744// Note: we are only initializing information about the array (rank, sizes, dimensions, etc) here. We will not
3745// attempt to read array contents until we receive a request to do so.
3746HRESULT CordbArrayValue::Init()
3747{
3748 INTERNAL_SYNC_API_ENTRY(this->GetProcess()); //
3749 HRESULT hr = S_OK;
3750
3751 SIZE_T cbVector = m_info.arrayInfo.rank * sizeof(DWORD);
3752 _ASSERTE(cbVector <= m_info.objSize);
3753
3754 int cbHeader = 2 * (int)cbVector;
3755
3756 // Find largest data size that will fit in cache
3757 SIZE_T cbData = m_info.arrayInfo.componentCount * m_info.arrayInfo.elementSize;
3758 if (cbData > ARRAY_CACHE_SIZE)
3759 {
3760 cbData = (ARRAY_CACHE_SIZE / m_info.arrayInfo.elementSize)
3761 * m_info.arrayInfo.elementSize;
3762 }
3763
3764 if (cbData < m_info.arrayInfo.elementSize)
3765 {
3766 cbData = m_info.arrayInfo.elementSize;
3767 }
3768
3769 // Allocate memory
3770 m_pObjectCopy = new (nothrow) BYTE[cbHeader + cbData];
3771 if (m_pObjectCopy == NULL)
3772 return E_OUTOFMEMORY;
3773
3774
3775 m_arrayLowerBase = NULL;
3776 m_arrayUpperBase = NULL;
3777
3778 // Copy base vectors into header. (Offsets are 0 if the vectors aren't used)
3779 if (m_info.arrayInfo.offsetToLowerBounds != 0)
3780 {
3781 m_arrayLowerBase = (DWORD*)(m_pObjectCopy);
3782 EX_TRY
3783 {
3784 m_valueHome.GetInternalValue(MemoryRange(m_arrayLowerBase, cbVector),
3785 m_info.arrayInfo.offsetToLowerBounds); // throws
3786 }
3787 EX_CATCH_HRESULT(hr);
3788 IfFailRet(hr);
3789 }
3790
3791
3792 if (m_info.arrayInfo.offsetToUpperBounds != 0)
3793 {
3794 m_arrayUpperBase = (DWORD*)(m_pObjectCopy + cbVector);
3795 EX_TRY
3796 {
3797 m_valueHome.GetInternalValue(MemoryRange(m_arrayUpperBase, cbVector),
3798 m_info.arrayInfo.offsetToUpperBounds); // throws
3799 }
3800 EX_CATCH_HRESULT(hr);
3801 IfFailRet(hr);
3802 }
3803
3804 // That's all for now. We'll do lazy-evaluation for the array contents.
3805
3806 return hr;
3807} // CordbArrayValue::Init
3808
3809// CordbArrayValue::GetThreadOwningMonitorLock
3810// If a managed thread owns the monitor lock on this object then *ppThread
3811// will point to that thread and S_OK will be returned. The thread object is valid
3812// until the thread exits. *pAcquisitionCount will indicate the number of times
3813// this thread would need to release the lock before it returns to being
3814// unowned.
3815// If no managed thread owns the monitor lock on this object then *ppThread
3816// and pAcquisitionCount will be unchanged and S_FALSE returned.
3817// If ppThread or pAcquisitionCount is not a valid pointer the result is
3818// undefined.
3819// If any error occurs such that it cannot be determined which, if any, thread
3820// owns the monitor lock on this object then a failing HRESULT will be returned
3821HRESULT CordbArrayValue::GetThreadOwningMonitorLock(ICorDebugThread **ppThread, DWORD *pAcquisitionCount)
3822{
3823 PUBLIC_API_ENTRY(this);
3824 FAIL_IF_NEUTERED(this);
3825 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
3826
3827 return CordbHeapValue3Impl::GetThreadOwningMonitorLock(GetProcess(),
3828 GetValueHome()->GetAddress(), ppThread, pAcquisitionCount);
3829}
3830
3831// CordbArrayValue::GetMonitorEventWaitList
3832// Provides an ordered list of threads which are queued on the event associated
3833// with a monitor lock. The first thread in the list is the first thread which
3834// will be released by the next call to Monitor.Pulse, the next thread in the list
3835// will be released on the following call, and so on.
3836// If this list is non-empty S_OK will be returned, if it is empty S_FALSE
3837// will be returned (the enumeration is still valid, just empty).
3838// In either case the enumeration interface is only usable for the duration
3839// of the current synchronized state, however the threads interfaces dispensed
3840// from it are valid until the thread exits.
3841// If ppThread is not a valid pointer the result is undefined.
3842// If any error occurs such that it cannot be determined which, if any, threads
3843// are waiting for the monitor then a failing HRESULT will be returned
3844HRESULT CordbArrayValue::GetMonitorEventWaitList(ICorDebugThreadEnum **ppThreadEnum)
3845{
3846 PUBLIC_API_ENTRY(this);
3847 FAIL_IF_NEUTERED(this);
3848 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
3849
3850 return CordbHeapValue3Impl::GetMonitorEventWaitList(GetProcess(),
3851 GetValueHome()->GetAddress(),
3852 ppThreadEnum);
3853}
3854
3855/* ------------------------------------------------------------------------- *
3856 * Handle Value
3857 * ------------------------------------------------------------------------- */
3858// constructor
3859// Arguments:
3860// input:
3861// pAppDomain - app domain to which the value belongs
3862// pType - type information for the value
3863// handleType - indicates whether we are constructing a strong or weak handle
3864CordbHandleValue::CordbHandleValue(
3865 CordbAppDomain * pAppdomain,
3866 CordbType * pType, // The type of object that we create handle on
3867 CorDebugHandleType handleType) // strong or weak handle
3868 : CordbValue(pAppdomain, pType, NULL, false,
3869 pAppdomain->GetSweepableExitNeuterList()
3870 )
3871{
3872 m_vmHandle = VMPTR_OBJECTHANDLE::NullPtr();
3873 m_fCanBeValid = TRUE;
3874
3875 m_handleType = handleType;
3876 m_size = sizeof(void*);
3877} // CordbHandleValue::CordbHandleValue
3878
3879//-----------------------------------------------------------------------------
3880// Assign internal handle to the given value, and update pertinent counters
3881//
3882// Arguments:
3883// handle - non-null CLR ObjectHandle that this CordbHandleValue will represent
3884//
3885// Notes:
3886// Call code:CordbHandleValue::ClearHandle to clear the handle value.
3887void CordbHandleValue::AssignHandle(VMPTR_OBJECTHANDLE handle)
3888{
3889 _ASSERTE(GetProcess()->ThreadHoldsProcessLock());
3890 _ASSERTE(m_vmHandle.IsNull());
3891
3892 // Use code:CordbHandleValue::ClearHandle to clear the handle value.
3893 _ASSERTE(!handle.IsNull());
3894
3895 m_vmHandle = handle;
3896 GetProcess()->IncrementOutstandingHandles();
3897}
3898
3899//-----------------------------------------------------------------------------
3900// Clear the handle value
3901//
3902// Assumptions:
3903// Caller only clears if not already cleared.
3904//
3905// Notes:
3906// This is the inverse of code:CordbHandleValue::AssignHandle
3907void CordbHandleValue::ClearHandle()
3908{
3909 _ASSERTE(GetProcess()->ThreadHoldsProcessLock());
3910 _ASSERTE(!m_vmHandle.IsNull());
3911
3912 m_vmHandle = VMPTR_OBJECTHANDLE::NullPtr();
3913 GetProcess()->DecrementOutstandingHandles();
3914}
3915
3916// initialize a new instance of CordbHandleValue
3917// Arguments:
3918// input: pHandle - non-null CLR ObjectHandle that this CordbHandleValue will represent
3919// Return Value: S_OK on success or CORDBG_E_TARGET_INCONSISTENT, E_INVALIDARG, read process memory errors.
3920HRESULT CordbHandleValue::Init(VMPTR_OBJECTHANDLE pHandle)
3921{
3922 INTERNAL_SYNC_API_ENTRY(GetProcess());
3923 HRESULT hr = S_OK;
3924
3925 {
3926 RSLockHolder lockHolder(GetProcess()->GetProcessLock());
3927 // If it is a strong handle, m_pHandle will not be NULL unless Dispose method is called.
3928 // If it is a weak handle, m_pHandle can be NULL when Dispose is called.
3929 AssignHandle(pHandle);
3930 }
3931
3932 // This will init m_info.
3933 IfFailRet(RefreshHandleValue());
3934
3935 // objRefBad is currently overloaded to mean that 1) the object ref is invalid, or 2) the object ref is NULL.
3936 // NULL is clearly not a bad object reference, but in either case we have no more type data to work with,
3937 // so don't attempt to assign more specific type information to the reference.
3938 if (!m_info.objRefBad)
3939 {
3940 // We need to get the type info from the left side.
3941 CordbType *newtype;
3942
3943 IfFailRet(CordbType::TypeDataToType(m_appdomain, &m_info.objTypeData, &newtype));
3944
3945 m_type.Assign(newtype);
3946 }
3947
3948 return hr;
3949} // CordbHandleValue::Init
3950
3951// destructor
3952CordbHandleValue::~CordbHandleValue()
3953{
3954 DTOR_ENTRY(this);
3955
3956 _ASSERTE(IsNeutered());
3957} // CordbHandleValue::~CordbHandleValue
3958
3959// Free left-side resources, mainly the GC handle keeping the object alive.
3960void CordbHandleValue::NeuterLeftSideResources()
3961{
3962 Dispose();
3963
3964 RSLockHolder lockHolder(GetProcess()->GetProcessLock());
3965 Neuter();
3966} // CordbHandleValue::NeuterLeftSideResources
3967
3968// Neuter
3969// Notes:
3970// CordbHandleValue may hold Left-Side resources via the GC handle.
3971// By the time we neuter it, those resources must have been freed,
3972// either explicitly by calling code:CordbHandleValue::Dispose, or
3973// implicitly by the left-side process exiting.
3974void CordbHandleValue::Neuter()
3975{
3976 // CordbHandleValue is on the AppDomainExit neuter list.
3977
3978 // We should have cleaned up our Left-side resource by now (m_vmHandle
3979 // should be null). If AppDomain / Process has already exited, then the LS
3980 // already cleaned them up for us, and so we don't worry about them.
3981 bool fAppDomainIsAlive = (m_appdomain != NULL && !m_appdomain->IsNeutered());
3982 if (fAppDomainIsAlive)
3983 {
3984 BOOL fTargetIsDead = !GetProcess()->IsSafeToSendEvents() || GetProcess()->m_exiting;
3985 if (!fTargetIsDead)
3986 {
3987 _ASSERTE(m_vmHandle.IsNull());
3988 }
3989 }
3990
3991 CordbValue::Neuter();
3992} // CordbHandleValue::Neuter
3993
3994// Helper: Refresh the handle value object.
3995// Gets information about the object to which the handle points.
3996// Arguments: none
3997// Return Value: S_OK on success, CORDBG_E_HANDLE_HAS_BEEN_DISPOSED, CORDBG_E_BAD_REFERENCE_VALUE,
3998// errors from read process memory.
3999HRESULT CordbHandleValue::RefreshHandleValue()
4000{
4001 INTERNAL_SYNC_API_ENTRY(this->GetProcess()); //
4002 _ASSERTE(m_appdomain != NULL);
4003 _ASSERTE(!m_appdomain->IsNeutered());
4004
4005 // If Dispose has been called, don't bother to refresh handle value.
4006 if (m_vmHandle.IsNull())
4007 {
4008 return CORDBG_E_HANDLE_HAS_BEEN_DISPOSED;
4009 }
4010
4011 // If weak handle and the object was dead, no point to refresh the handle value
4012 if (m_fCanBeValid == FALSE)
4013 {
4014 return CORDBG_E_BAD_REFERENCE_VALUE;
4015 }
4016
4017 HRESULT hr = S_OK;
4018 CorElementType type = m_type->m_elementType;
4019
4020 _ASSERTE((m_pProcess != NULL));
4021
4022 _ASSERTE (type != ELEMENT_TYPE_GENERICINST);
4023 _ASSERTE (type != ELEMENT_TYPE_VAR);
4024 _ASSERTE (type != ELEMENT_TYPE_MVAR);
4025
4026 CordbProcess * pProcess = GetProcess();
4027 void * objectAddress = NULL;
4028 CORDB_ADDRESS objectHandle = 0;
4029
4030 EX_TRY
4031 {
4032 objectHandle = pProcess->GetDAC()->GetHandleAddressFromVmHandle(m_vmHandle);
4033 if (type != ELEMENT_TYPE_TYPEDBYREF)
4034 {
4035 pProcess->SafeReadBuffer(TargetBuffer(objectHandle, sizeof(void *)), (BYTE *)&objectAddress);
4036 }
4037 }
4038 EX_CATCH_HRESULT(hr);
4039 IfFailRet(hr);
4040 EX_TRY
4041 {
4042 if (type == ELEMENT_TYPE_TYPEDBYREF)
4043 {
4044 CordbReferenceValue::GetTypedByRefData(pProcess,
4045 objectHandle,
4046 type,
4047 m_appdomain->GetADToken(),
4048 &m_info);
4049 }
4050 else
4051 {
4052 CordbReferenceValue::GetObjectData(pProcess,
4053 objectAddress,
4054 type,
4055 m_appdomain->GetADToken(),
4056 &m_info);
4057 }
4058 }
4059 EX_CATCH_HRESULT(hr);
4060 IfFailRet(hr);
4061
4062 // If reference is already gone bad or reference is NULL,
4063 // don't bother to refetch in the future.
4064 //
4065 if ((m_info.objRefBad) || (m_info.objRef == NULL))
4066 {
4067 m_fCanBeValid = FALSE;
4068 }
4069
4070 return hr;
4071}
4072 // CordbHandleValue::RefreshHandleValue
4073
4074HRESULT CordbHandleValue::QueryInterface(REFIID id, void **pInterface)
4075{
4076 VALIDATE_POINTER_TO_OBJECT(pInterface, void **);
4077
4078 if (id == IID_ICorDebugValue)
4079 {
4080 *pInterface = static_cast<ICorDebugValue*>(this);
4081 }
4082 else if (id == IID_ICorDebugValue2)
4083 {
4084 *pInterface = static_cast<ICorDebugValue2*>(this);
4085 }
4086 else if (id == IID_ICorDebugValue3)
4087 {
4088 *pInterface = static_cast<ICorDebugValue3*>(this);
4089 }
4090 else if (id == IID_ICorDebugReferenceValue)
4091 {
4092 *pInterface = static_cast<ICorDebugReferenceValue*>(this);
4093 }
4094 else if (id == IID_ICorDebugHandleValue)
4095 {
4096 *pInterface = static_cast<ICorDebugHandleValue*>(this);
4097 }
4098 else if (id == IID_IUnknown)
4099 {
4100 *pInterface = static_cast<IUnknown*>(static_cast<ICorDebugHandleValue*>(this));
4101 }
4102 else
4103 {
4104 *pInterface = NULL;
4105 return E_NOINTERFACE;
4106 }
4107
4108 ExternalAddRef();
4109 return S_OK;
4110} // CordbHandleValue::QueryInterface
4111
4112
4113// return handle type. Currently we have strong and weak.
4114// Arguments:
4115// output: pType - the handle type unless pType is null
4116// Return Value: S_OK on success or E_INVALIDARG or CORDBG_E_HANDLE_HAS_BEEN_DISPOSED on failure
4117HRESULT CordbHandleValue::GetHandleType(CorDebugHandleType *pType)
4118{
4119 PUBLIC_REENTRANT_API_ENTRY(this);
4120 VALIDATE_POINTER_TO_OBJECT(pType, CorDebugHandleType *);
4121 FAIL_IF_NEUTERED(this);
4122 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
4123 _ASSERTE(m_appdomain != NULL);
4124 _ASSERTE(!m_appdomain->IsNeutered());
4125
4126 if (m_vmHandle.IsNull())
4127 {
4128 // handle has been disposed!
4129 return CORDBG_E_HANDLE_HAS_BEEN_DISPOSED;
4130 }
4131 *pType = m_handleType;
4132 return S_OK;
4133} // CordbHandleValue::GetHandleType
4134
4135// Dispose will cause handle to be recycled.
4136// Arguments: none
4137// Return Value: S_OK on success, CORDBG_E_HANDLE_HAS_BEEN_DISPOSED or errors from the
4138// DB_IPCE_DISPOSE_HANDLE event
4139
4140// @dbgtodo Microsoft inspection: remove the dispose handle hresults when the IPC events are eliminated
4141HRESULT CordbHandleValue::Dispose()
4142{
4143 PUBLIC_REENTRANT_API_ENTRY(this);
4144 FAIL_IF_NEUTERED(this);
4145 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
4146 _ASSERTE(m_appdomain != NULL);
4147 _ASSERTE(!m_appdomain->IsNeutered());
4148
4149 HRESULT hr = S_OK;
4150 DebuggerIPCEvent event;
4151 CordbProcess *process;
4152
4153 process = GetProcess();
4154
4155 // Process should still be alive because it would have neutered us if it became invalid.
4156 _ASSERTE(process != NULL);
4157
4158 VMPTR_OBJECTHANDLE vmObjHandle = VMPTR_OBJECTHANDLE::NullPtr();
4159 {
4160 RSLockHolder lockHolder(GetProcess()->GetProcessLock());
4161 if (m_vmHandle.IsNull())
4162 {
4163 // handle has been disposed!
4164 return CORDBG_E_HANDLE_HAS_BEEN_DISPOSED;
4165 }
4166
4167 vmObjHandle = m_vmHandle;
4168 ClearHandle(); // set m_pHandle to null.
4169
4170 if (process->m_exiting)
4171 {
4172 // process is exiting. Don't do anything
4173 return S_OK;
4174 }
4175 }
4176
4177 // recycle the handle to EE
4178 process->InitIPCEvent(&event,
4179 DB_IPCE_DISPOSE_HANDLE,
4180 false,
4181 m_appdomain->GetADToken());
4182
4183 event.DisposeHandle.vmObjectHandle = vmObjHandle;
4184 if (m_handleType == HANDLE_STRONG)
4185 {
4186 event.DisposeHandle.fStrong = TRUE;
4187 }
4188 else
4189 {
4190 event.DisposeHandle.fStrong = FALSE;
4191 }
4192
4193 // Note: one-way event here...
4194 hr = process->SendIPCEvent(&event, sizeof(DebuggerIPCEvent));
4195
4196 hr = WORST_HR(hr, event.hr);
4197
4198 return hr;
4199} // CordbHandleValue::Dispose
4200
4201// get the type of the object to which the handle points
4202// Arguments:
4203// output: pType - the object type on success
4204// Return Value: S_OK on success, CORDBG_E_HANDLE_HAS_BEEN_DISPOSED, CORDBG_E_CLASS_NOT_LOADED or synchronization errors on
4205// failure
4206HRESULT CordbHandleValue::GetType(CorElementType *pType)
4207{
4208 PUBLIC_REENTRANT_API_ENTRY(this);
4209 VALIDATE_POINTER_TO_OBJECT(pType, CorElementType *);
4210 FAIL_IF_NEUTERED(this);
4211 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
4212 _ASSERTE(m_appdomain != NULL);
4213 _ASSERTE(!m_appdomain->IsNeutered());
4214
4215 HRESULT hr = S_OK;
4216
4217 if (m_vmHandle.IsNull())
4218 {
4219 return CORDBG_E_HANDLE_HAS_BEEN_DISPOSED;
4220 }
4221
4222 bool isBoxedVCObject = false;
4223 if ((m_type->m_pClass != NULL) && (m_type->m_elementType != ELEMENT_TYPE_STRING))
4224 {
4225 EX_TRY
4226 {
4227 isBoxedVCObject = m_type->m_pClass->IsValueClass();
4228 }
4229 EX_CATCH_HRESULT(hr);
4230 if (FAILED(hr))
4231 return hr;
4232 }
4233
4234 if (isBoxedVCObject)
4235 {
4236 // if we create the handle to a boxed value type, then the type is
4237 // E_T_CLASS. m_type is the underlying value type. That is incorrect to
4238 // return.
4239 //
4240 *pType = ELEMENT_TYPE_CLASS;
4241 return S_OK;
4242 }
4243
4244 return m_type->GetType(pType);
4245} // CordbHandleValue::GetType
4246
4247// get the size of the handle-- this will always return the size of the handle itself (just pointer size), so
4248// it's not particularly interesting.
4249// Arguments:
4250// output: pSize - the size of the handle (on success). This must be non-null. Memory management belongs
4251// to the caller.
4252// Return Value: S_OK on success, E_INVALIDARG (if pSize is null), or CORDBG_E_HANDLE_HAS_BEEN_DISPOSED on failure
4253HRESULT CordbHandleValue::GetSize(ULONG32 *pSize)
4254{
4255 PUBLIC_REENTRANT_API_ENTRY(this);
4256 VALIDATE_POINTER_TO_OBJECT(pSize, ULONG32 *);
4257 FAIL_IF_NEUTERED(this);
4258 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
4259 _ASSERTE(m_appdomain != NULL);
4260 _ASSERTE(!m_appdomain->IsNeutered());
4261
4262 if (m_vmHandle.IsNull())
4263 {
4264 return CORDBG_E_HANDLE_HAS_BEEN_DISPOSED;
4265 }
4266
4267 if (m_size > ULONG_MAX)
4268 {
4269 *pSize = ULONG_MAX;
4270 return (COR_E_OVERFLOW);
4271 }
4272
4273 //return the size of reference
4274 *pSize = (ULONG)m_size;
4275 return S_OK;
4276} // CordbHandleValue::GetSize
4277
4278// get the size of the handle-- this will always return the size of the handle itself (just pointer size), so
4279// it's not particularly interesting.
4280// Arguments:
4281// output: pSize - the size of the handle (on success). This must be non-null. Memory management belongs
4282// to the caller.
4283// Return Value: S_OK on success, E_INVALIDARG (if pSize is null), or CORDBG_E_HANDLE_HAS_BEEN_DISPOSED on failure
4284HRESULT CordbHandleValue::GetSize64(ULONG64 *pSize)
4285{
4286 PUBLIC_REENTRANT_API_ENTRY(this);
4287 VALIDATE_POINTER_TO_OBJECT(pSize, ULONG64 *);
4288 FAIL_IF_NEUTERED(this);
4289 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
4290 _ASSERTE(m_appdomain != NULL);
4291 _ASSERTE(!m_appdomain->IsNeutered());
4292
4293 if (m_vmHandle.IsNull())
4294 {
4295 return CORDBG_E_HANDLE_HAS_BEEN_DISPOSED;
4296 }
4297
4298 //return the size of reference
4299 *pSize = m_size;
4300 return S_OK;
4301} // CordbHandleValue::GetSize
4302
4303// Get the target address of the handle
4304// Arguments:
4305// output: pAddress - handle address on success. This must be non-null and memory is managed by the caller
4306// Return Value: S_OK on success or CORDBG_E_HANDLE_HAS_BEEN_DISPOSED or E_INVALIDARG on failure
4307HRESULT CordbHandleValue::GetAddress(CORDB_ADDRESS *pAddress)
4308{
4309 PUBLIC_REENTRANT_API_ENTRY(this);
4310 VALIDATE_POINTER_TO_OBJECT(pAddress, CORDB_ADDRESS *);
4311 FAIL_IF_NEUTERED(this);
4312 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
4313 _ASSERTE(m_appdomain != NULL);
4314 _ASSERTE(!m_appdomain->IsNeutered());
4315
4316 if (m_vmHandle.IsNull())
4317 {
4318 return CORDBG_E_HANDLE_HAS_BEEN_DISPOSED;
4319 }
4320
4321 HRESULT hr = S_OK;
4322 EX_TRY
4323 {
4324 *pAddress = GetProcess()->GetDAC()->GetHandleAddressFromVmHandle(m_vmHandle);
4325 }
4326 EX_CATCH_HRESULT(hr);
4327 return hr;
4328} // CordbHandleValue::GetAddress
4329
4330HRESULT CordbHandleValue::CreateBreakpoint(ICorDebugValueBreakpoint **ppBreakpoint)
4331{
4332 return E_NOTIMPL;
4333} // CreateBreakpoint
4334
4335// indicates whether a handle is null
4336// Arguments:
4337// output: pbNull - true iff the handle is null and pbNull is non-null.Memory is managed by the caller
4338// Return Value: S_OK on success or CORDBG_E_HANDLE_HAS_BEEN_DISPOSED or E_INVALIDARG, CORDBG_E_BAD_REFERENCE_VALUE,
4339// errors from read process memory.
4340HRESULT CordbHandleValue::IsNull(BOOL *pbNull)
4341{
4342 PUBLIC_REENTRANT_API_ENTRY(this);
4343 VALIDATE_POINTER_TO_OBJECT(pbNull, BOOL *);
4344 FAIL_IF_NEUTERED(this);
4345 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
4346 _ASSERTE(m_appdomain != NULL);
4347 _ASSERTE(!m_appdomain->IsNeutered());
4348
4349 HRESULT hr = S_OK;
4350
4351 *pbNull = FALSE;
4352
4353 if (m_vmHandle.IsNull())
4354 {
4355 return CORDBG_E_HANDLE_HAS_BEEN_DISPOSED;
4356 }
4357
4358
4359 // Only return true if handle is long weak handle and is disposed.
4360 if (m_handleType == HANDLE_WEAK_TRACK_RESURRECTION)
4361 {
4362 hr = RefreshHandleValue();
4363 if (FAILED(hr))
4364 {
4365 return hr;
4366 }
4367
4368 if (m_info.objRef == NULL)
4369 {
4370 *pbNull = TRUE;
4371 }
4372 }
4373 else if (m_info.objRef == NULL)
4374 {
4375 *pbNull = TRUE;
4376 }
4377
4378 // strong handle always return false for IsNull
4379
4380 return S_OK;
4381} // CordbHandleValue::IsNull
4382
4383// gets a copy of the value of the handle
4384// Arguments:
4385// output: pValue - handle { on success. This must be non-null and memory is managed by the caller
4386// Return Value: S_OK on success or CORDBG_E_HANDLE_HAS_BEEN_DISPOSED or E_INVALIDARG, CORDBG_E_BAD_REFERENCE_VALUE,
4387// errors from read process memory.
4388HRESULT CordbHandleValue::GetValue(CORDB_ADDRESS *pValue)
4389{
4390 PUBLIC_REENTRANT_API_ENTRY(this);
4391 VALIDATE_POINTER_TO_OBJECT(pValue, CORDB_ADDRESS *);
4392 FAIL_IF_NEUTERED(this);
4393 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
4394 _ASSERTE(m_appdomain != NULL);
4395 _ASSERTE(!m_appdomain->IsNeutered());
4396
4397 if (m_vmHandle.IsNull())
4398 {
4399 return CORDBG_E_HANDLE_HAS_BEEN_DISPOSED;
4400 }
4401
4402 RefreshHandleValue();
4403 *pValue = PTR_TO_CORDB_ADDRESS(m_info.objRef);
4404 return S_OK;
4405} // CordbHandleValue::GetValue
4406
4407HRESULT CordbHandleValue::SetValue(CORDB_ADDRESS value)
4408{
4409 // do not support SetValue on Handle
4410 return E_FAIL;
4411} // CordbHandleValue::GetValue
4412
4413// get an ICDValue to represent the object to which the handle refers
4414// Arguments:
4415// output: ppValue - pointer to the ICDValue for the handle referent as long as ppValue is non-null
4416// Return Value: S_OK on success or CORDBG_E_HANDLE_HAS_BEEN_DISPOSED or E_INVALIDARG, CORDBG_E_BAD_REFERENCE_VALUE,
4417// errors from read process memory.
4418HRESULT CordbHandleValue::Dereference(ICorDebugValue **ppValue)
4419{
4420 HRESULT hr = S_OK;
4421 PUBLIC_REENTRANT_API_ENTRY(this);
4422 VALIDATE_POINTER_TO_OBJECT(ppValue, ICorDebugValue **);
4423 FAIL_IF_NEUTERED(this);
4424 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
4425 _ASSERTE(m_appdomain != NULL);
4426 _ASSERTE(!m_appdomain->IsNeutered());
4427
4428 *ppValue = NULL;
4429
4430 if (m_vmHandle.IsNull())
4431 {
4432 return CORDBG_E_HANDLE_HAS_BEEN_DISPOSED;
4433 }
4434
4435 hr = RefreshHandleValue();
4436 if (FAILED(hr))
4437 {
4438 return hr;
4439 }
4440
4441 if ((m_info.objRefBad) || (m_info.objRef == NULL))
4442 {
4443 return CORDBG_E_BAD_REFERENCE_VALUE;
4444 }
4445
4446 EX_TRY
4447 {
4448 hr = CordbReferenceValue::DereferenceCommon(m_appdomain,
4449 m_type,
4450 NULL, // don't support typed-by-refs
4451 &m_info,
4452 ppValue);
4453 }
4454 EX_CATCH_HRESULT(hr);
4455 return hr;
4456} // CordbHandleValue::Dereference
4457
4458HRESULT CordbHandleValue::DereferenceStrong(ICorDebugValue **ppValue)
4459{
4460 return E_NOTIMPL;
4461}
4462
4463// CordbHeapValue3Impl::GetThreadOwningMonitorLock
4464// If a managed thread owns the monitor lock on this object then *ppThread
4465// will point to that thread and S_OK will be returned. The thread object is valid
4466// until the thread exits. *pAcquisitionCount will indicate the number of times
4467// this thread would need to release the lock before it returns to being
4468// unowned.
4469// If no managed thread owns the monitor lock on this object then *ppThread
4470// and pAcquisitionCount will be unchanged and S_FALSE returned.
4471// If ppThread or pAcquisitionCount is not a valid pointer the result is
4472// undefined.
4473// If any error occurs such that it cannot be determined which, if any, thread
4474// owns the monitor lock on this object then a failing HRESULT will be returned
4475HRESULT CordbHeapValue3Impl::GetThreadOwningMonitorLock(CordbProcess* pProcess,
4476 CORDB_ADDRESS remoteObjAddress,
4477 ICorDebugThread **ppThread,
4478 DWORD *pAcquisitionCount)
4479{
4480 HRESULT hr = S_OK;
4481 EX_TRY
4482 {
4483 IDacDbiInterface *pDac = pProcess->GetDAC();
4484 VMPTR_Object vmObj = pDac->GetObject(remoteObjAddress);
4485 MonitorLockInfo info = pDac->GetThreadOwningMonitorLock(vmObj);
4486 if(info.acquisitionCount == 0)
4487 {
4488 // unowned
4489 *ppThread = NULL;
4490 *pAcquisitionCount = 0;
4491 hr = S_FALSE;
4492 }
4493 else
4494 {
4495 RSLockHolder lockHolder(pProcess->GetProcessLock());
4496 CordbThread* pThread = pProcess->LookupOrCreateThread(info.lockOwner);
4497 pThread->QueryInterface(__uuidof(ICorDebugThread), (VOID**) ppThread);
4498 *pAcquisitionCount = info.acquisitionCount;
4499 hr = S_OK;
4500 }
4501 }
4502 EX_CATCH_HRESULT(hr);
4503 return hr;
4504}
4505
4506// A small helper for CordbHeapValue3Impl::GetMonitorEventWaitList that adds each enumerated thread to an array
4507// Arguments:
4508// vmThread - The thread to add
4509// puserData - the array to add it to
4510VOID ThreadEnumerationCallback(VMPTR_Thread vmThread, VOID* pUserData)
4511{
4512 CQuickArrayList<VMPTR_Thread>* pThreadList = (CQuickArrayList<VMPTR_Thread>*) pUserData;
4513 pThreadList->Push(vmThread);
4514}
4515
4516// CordbHeapValue3Impl::GetMonitorEventWaitList
4517// Provides an ordered list of threads which are queued on the event associated
4518// with a monitor lock. The first thread in the list is the first thread which
4519// will be released by the next call to Monitor.Pulse, the next thread in the list
4520// will be released on the following call, and so on.
4521// If this list is non-empty S_OK will be returned, if it is empty S_FALSE
4522// will be returned (the enumeration is still valid, just empty).
4523// In either case the enumeration interface is only usable for the duration
4524// of the current synchronized state, however the threads interfaces dispensed
4525// from it are valid until the thread exits.
4526// If ppThread is not a valid pointer the result is undefined.
4527// If any error occurs such that it cannot be determined which, if any, threads
4528// are waiting for the monitor then a failing HRESULT will be returned
4529HRESULT CordbHeapValue3Impl::GetMonitorEventWaitList(CordbProcess* pProcess,
4530 CORDB_ADDRESS remoteObjAddress,
4531 ICorDebugThreadEnum **ppThreadEnum)
4532{
4533 HRESULT hr = S_OK;
4534 RSSmartPtr<CordbThread> *rsThreads = NULL;
4535 EX_TRY
4536 {
4537 IDacDbiInterface *pDac = pProcess->GetDAC();
4538 VMPTR_Object vmObj = pDac->GetObject(remoteObjAddress);
4539 CQuickArrayList<VMPTR_Thread> threads;
4540 pDac->EnumerateMonitorEventWaitList(vmObj,
4541 (IDacDbiInterface::FP_THREAD_ENUMERATION_CALLBACK)ThreadEnumerationCallback, (VOID*)&threads);
4542
4543 rsThreads = new RSSmartPtr<CordbThread>[threads.Size()];
4544 {
4545 RSLockHolder lockHolder(pProcess->GetProcessLock());
4546 for(DWORD i = 0; i < threads.Size(); i++)
4547 {
4548 rsThreads[i].Assign(pProcess->LookupOrCreateThread(threads[i]));
4549 }
4550 }
4551
4552 CordbThreadEnumerator* threadEnum =
4553 new CordbThreadEnumerator(pProcess, rsThreads, (DWORD)threads.Size());
4554 pProcess->GetContinueNeuterList()->Add(pProcess, threadEnum);
4555 threadEnum->QueryInterface(__uuidof(ICorDebugThreadEnum), (VOID**)ppThreadEnum);
4556 if(threads.Size() == 0)
4557 {
4558 hr = S_FALSE;
4559 }
4560 }
4561 EX_CATCH_HRESULT(hr);
4562 delete [] rsThreads;
4563 return hr;
4564}
4565