2 // Copyright (c) Microsoft. All rights reserved.
3 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
5 //*****************************************************************************
10 //*****************************************************************************
13 // We have an assert in ceemain.cpp that validates this assumption
14 #define FIELD_OFFSET_NEW_ENC_DB 0x07FFFFFB
21 //-----------------------------------------------------------------------------
23 // Represents a IL-Class in the debuggee, eg: List<T>, System.Console, etc
26 // m - module that the class is contained in.
27 // classMetadataToken - metadata token for the class, scoped to module m.
28 //-----------------------------------------------------------------------------
29 CordbClass::CordbClass(CordbModule *m, mdTypeDef classMetadataToken)
30 : CordbBase(m->GetProcess(), classMetadataToken, enumCordbClass),
31 m_loadLevel(Constructed),
32 m_fLoadEventSent(FALSE),
33 m_fHasBeenUnloaded(false),
35 m_token(classMetadataToken),
36 m_fIsValueClassKnown(false),
37 m_fIsValueClass(false),
38 m_fHasTypeParams(false),
39 m_continueCounterLastSync(0),
40 m_fCustomNotificationsEnabled(false)
47 A list of which resources owned by this object are accounted for.
50 CordbModule* m_module; // Assigned w/o AddRef()
51 FieldData *m_fields; // Deleted in ~CordbClass
52 CordbHangingFieldTable m_hangingFieldsStatic; // by value, ~CHashTableAndData frees
56 //-----------------------------------------------------------------------------
57 // Destructor for CordbClass
58 //-----------------------------------------------------------------------------
59 CordbClass::~CordbClass()
61 // We should have been explicitly neutered before our internal ref went to 0.
62 _ASSERTE(IsNeutered());
65 //-----------------------------------------------------------------------------
66 // Neutered by CordbModule
67 // See CordbBase::Neuter for semantics.
68 //-----------------------------------------------------------------------------
69 void CordbClass::Neuter()
71 // Reduce the reference count on the type object for this class
79 //-----------------------------------------------------------------------------
80 // Standard IUnknown::QI implementation.
81 // See IUnknown::QI for standard semantics.
82 //-----------------------------------------------------------------------------
83 HRESULT CordbClass::QueryInterface(REFIID id, void **pInterface)
85 if (id == IID_ICorDebugClass)
87 *pInterface = static_cast<ICorDebugClass*>(this);
89 else if (id == IID_ICorDebugClass2)
91 *pInterface = static_cast<ICorDebugClass2*>(this);
93 else if (id == IID_IUnknown)
95 *pInterface = static_cast<IUnknown*>(static_cast<ICorDebugClass*>(this));
100 return E_NOINTERFACE;
107 //-----------------------------------------------------------------------------
108 // Get a ICorDebugValue for a static field on this class.
111 // fieldDef - metadata token for field on this class. Can not be from an
113 // pFrame - frame used to resolve Thread-static, AppDomain-static, etc.
114 // ppValue - OUT: gets value of the field.
118 // CORDBG_E_STATIC_VAR_NOT_AVAILABLE
119 //-----------------------------------------------------------------------------
120 HRESULT CordbClass::GetStaticFieldValue(mdFieldDef fieldDef,
121 ICorDebugFrame *pFrame,
122 ICorDebugValue **ppValue)
124 PUBLIC_REENTRANT_API_ENTRY(this);
125 FAIL_IF_NEUTERED(this);
126 VALIDATE_POINTER_TO_OBJECT(ppValue, ICorDebugValue **);
127 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
131 BOOL fEnCHangingField = FALSE;
134 IMetaDataImport * pImport = NULL;
137 pImport = GetModule()->GetMetaDataImporter(); // throws
139 // Validate the token.
140 if (!pImport->IsValidToken(fieldDef) || (TypeFromToken(fieldDef) != mdtFieldDef))
142 ThrowHR(E_INVALIDARG);
145 // Make sure we have enough info about the class.
148 // Uninstantiated generics (eg, Foo<T>) don't have static data. Must use instantiated (eg Foo<int>)
149 // But all CordbClass instances are uninstantiated. So this should fail for all generic types.
150 // Normally, debuggers should be using ICorDebugType instead.
151 // Though in the forward compat case, they'll hit this.
154 ThrowHR(CORDBG_E_STATIC_VAR_NOT_AVAILABLE);
158 // Lookup the field given its metadata token.
159 FieldData *pFieldData;
161 hr = GetFieldInfo(fieldDef, &pFieldData);
163 // This field was added by EnC, need to use EnC specific code path
164 if (hr == CORDBG_E_ENC_HANGING_FIELD)
166 // Static fields added with EnC hang off the EnCFieldDesc
167 hr = GetEnCHangingField(fieldDef,
173 fEnCHangingField = TRUE;
175 // Note: the FieldOffset in pFieldData has been cooked to produce
176 // the correct address of the field in the syncBlock.
177 // @todo: extend Debugger_IPCEFieldData so we don't have to cook the offset here
183 Instantiation emptyInst;
185 hr = CordbClass::GetStaticFieldValue2(GetModule(),
191 // Let hr fall through
194 EX_CATCH_HRESULT(hr);
196 // Translate Failure HRs.
199 hr = CordbClass::PostProcessUnavailableHRESULT(hr, pImport, fieldDef);
206 //-----------------------------------------------------------------------------
207 // Common helper for accessing statics from both CordbClass and CordbType.
210 // pModule - module containing the class
211 // pFieldData - field data describing the field (this is correlated to a
212 // mdFieldDef, but has more specific data)
213 // fEnCHangingField - field storage hangs off the FieldDesc for EnC
214 // pInst - generic instantiation.
215 // pFrame - frame used for context for Thread-static, AD-static, etc.
216 // ppValue - OUT: out parameter to get value.
220 // CORDBG_E_FIELD_NOT_STATIC - if field isn't static.
221 // CORDBG_E_STATIC_VAR_NOT_AVAILABLE - if field storage is not available.
222 // Else some other failure.
224 HRESULT CordbClass::GetStaticFieldValue2(CordbModule * pModule,
225 FieldData * pFieldData,
226 BOOL fEnCHangingField,
227 const Instantiation * pInst,
228 ICorDebugFrame * pFrame,
229 ICorDebugValue ** ppValue)
231 FAIL_IF_NEUTERED(pModule);
232 INTERNAL_SYNC_API_ENTRY(pModule->GetProcess());
233 _ASSERTE((pModule->GetProcess()->GetShim() == NULL) || pModule->GetProcess()->GetSynchronized());
236 if (!pFieldData->m_fFldIsStatic)
238 return CORDBG_E_FIELD_NOT_STATIC;
241 CORDB_ADDRESS pRmtStaticValue = NULL;
242 CordbProcess * pProcess = pModule->GetProcess();
244 if (pFieldData->m_fFldIsCollectibleStatic)
248 pRmtStaticValue = pProcess->GetDAC()->GetCollectibleTypeStaticAddress(pFieldData->m_vmFieldDesc,
249 pModule->GetAppDomain()->GetADToken());
251 EX_CATCH_HRESULT(hr);
257 else if (!pFieldData->m_fFldIsTLS && !pFieldData->m_fFldIsContextStatic)
259 // Statics never move, so we always address them using their absolute address.
260 _ASSERTE(pFieldData->OkToGetOrSetStaticAddress());
261 pRmtStaticValue = pFieldData->GetStaticAddress();
265 // We've got a thread or context local static
267 if( fEnCHangingField )
269 // fEnCHangingField is set for fields added with EnC which hang off the FieldDesc.
270 // Thread-local and context-local statics cannot be added with EnC, so we shouldn't be here
271 // if this is an EnC field is thread- or context-local.
272 _ASSERTE(!pFieldData->m_fFldIsTLS );
273 _ASSERTE(!pFieldData->m_fFldIsContextStatic );
282 CordbFrame * pRealFrame = CordbFrame::GetCordbFrameFromInterface(pFrame);
283 _ASSERTE(pRealFrame != NULL);
285 // Get the thread we are working on
286 CordbThread * pThread = pRealFrame->m_pThread;
290 pRmtStaticValue = pProcess->GetDAC()->GetThreadOrContextStaticAddress(pFieldData->m_vmFieldDesc,
291 pThread->m_vmThreadToken);
293 EX_CATCH_HRESULT(hr);
302 if (pRmtStaticValue == NULL)
304 // type probably wasn't loaded yet.
305 // The debugger may chose to func-eval the creation of an instance of this type and try again.
306 return CORDBG_E_STATIC_VAR_NOT_AVAILABLE;
313 hr = pFieldData->GetFieldSignature(pModule, &sigParser);
315 EX_CATCH_HRESULT(hr);
319 IfFailRet (CordbType::SigToType(pModule, &sigParser, pInst, &pType));
321 bool fIsValueClass = false;
324 fIsValueClass = pType->IsValueType(); // throws
326 EX_CATCH_HRESULT(hr);
329 // Static value classes are stored as handles so that GC can deal with them properly. Thus, we need to follow the
330 // handle like an objectref. Do this by forcing CreateValueByType to think this is an objectref. Note: we don't do
331 // this for value classes that have an RVA, since they're layed out at the RVA with no handle.
332 bool fIsBoxed = (fIsValueClass &&
333 !pFieldData->m_fFldIsRVA &&
334 !pFieldData->m_fFldIsPrimitive &&
335 !pFieldData->m_fFldIsTLS &&
336 !pFieldData->m_fFldIsContextStatic);
338 TargetBuffer remoteValue(pRmtStaticValue, CordbValue::GetSizeForType(pType, fIsBoxed ? kBoxed : kUnboxed));
339 ICorDebugValue * pValue;
343 CordbValue::CreateValueByType(pModule->GetAppDomain(),
347 MemoryRange(NULL, 0),
351 EX_CATCH_HRESULT(hr);
362 //-----------------------------------------------------------------------------
363 // Public method to build a CordbType from a CordbClass.
364 // This is used to build up generic types. Eg, build:
365 // List<T> + { int } --> List<int>
368 // elementType - element type. Either ELEMENT_TYPE_CLASS, or ELEMENT_TYPE_VALUETYPE.
369 // We could technically figure this out from the metadata (by looking if it derives
370 // from System.ValueType).
371 // cTypeArgs - number of elements in rgpTypeArgs array
372 // rgpTypeArgs - array for type args.
373 // ppType - OUT: out parameter to hold resulting type.
376 // S_OK on success. Else false.
378 HRESULT CordbClass::GetParameterizedType(CorElementType elementType,
380 ICorDebugType * rgpTypeArgs[],
381 ICorDebugType ** ppType)
383 PUBLIC_API_ENTRY(this);
384 FAIL_IF_NEUTERED(this);
385 VALIDATE_POINTER_TO_OBJECT(ppType, ICorDebugType **);
386 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
388 // Note: Do not call Init() to find out if its a VC or not.
389 // Rather expect the client to tell us. This means the debug client
390 // can describe type instantiations not yet seen in the EE.
392 if ((elementType != ELEMENT_TYPE_CLASS) && (elementType != ELEMENT_TYPE_VALUETYPE))
397 // Prefast overflow check:
398 S_UINT32 allocSize = S_UINT32( cTypeArgs ) * S_UINT32( sizeof(CordbType *) );
400 if (allocSize.IsOverflow())
405 CordbAppDomain * pClassAppDomain = GetAppDomain();
407 // Note: casting from (ICorDebugType **) to (CordbType **) is not valid.
408 // Offsets may differ. Copy and validate the type array.
409 CordbType ** ppArgTypes = reinterpret_cast<CordbType **>(_alloca( allocSize.Value()));
411 for (unsigned int i = 0; i < cTypeArgs; i++)
413 ppArgTypes[i] = static_cast<CordbType *>( rgpTypeArgs[i] );
415 CordbAppDomain * pArgAppDomain = ppArgTypes[i]->GetAppDomain();
417 if ((pArgAppDomain != NULL) && (pArgAppDomain != pClassAppDomain))
419 return CORDBG_E_APPDOMAIN_MISMATCH;
424 CordbType * pResultType;
426 Instantiation typeInstantiation(cTypeArgs, ppArgTypes);
428 HRESULT hr = CordbType::MkType(pClassAppDomain, elementType, this, &typeInstantiation, &pResultType);
435 *ppType = pResultType;
447 //-----------------------------------------------------------------------------
448 // Returns true if the field is a static literal.
449 // In this case, the debugger should get the value from the metadata.
450 //-----------------------------------------------------------------------------
451 bool IsFieldStaticLiteral(IMetaDataImport *pImport, mdFieldDef fieldDef)
454 HRESULT hr2 = pImport->GetFieldProps(
467 if (SUCCEEDED(hr2) && IsFdLiteral(dwFieldAttr))
476 //-----------------------------------------------------------------------------
477 // Filter to determine a more descriptive failing HResult for a field lookup.
480 // hr - incoming ambiguous HR.
481 // pImport - metadata importer for this class.
482 // feildDef - field being looked up.
485 // hr - the incoming HR if no further HR can be determined.
486 // else another failing HR that it judged to be more specific that the incoming HR.
487 //-----------------------------------------------------------------------------
488 HRESULT CordbClass::PostProcessUnavailableHRESULT(HRESULT hr,
489 IMetaDataImport *pImport,
494 NOTHROW; // just translates an HR. shouldn't need to throw.
498 if (hr == CORDBG_E_FIELD_NOT_AVAILABLE)
500 if (IsFieldStaticLiteral(pImport, fieldDef))
502 return CORDBG_E_VARIABLE_IS_ACTUALLY_LITERAL;
509 //-----------------------------------------------------------------------------
510 // Public method to get the Module that this class lives in.
513 // ppModule - OUT: holds module that this class gets in.
517 //-----------------------------------------------------------------------------
518 HRESULT CordbClass::GetModule(ICorDebugModule **ppModule)
520 FAIL_IF_NEUTERED(this);
521 VALIDATE_POINTER_TO_OBJECT(ppModule, ICorDebugModule **);
523 *ppModule = static_cast<ICorDebugModule*> (m_pModule);
524 m_pModule->ExternalAddRef();
529 //-----------------------------------------------------------------------------
530 // Get the mdTypeDef token that this class corresponds to.
533 // pTypeDef - OUT: out param to get typedef token.
536 // S_OK - on success.
537 //-----------------------------------------------------------------------------
538 HRESULT CordbClass::GetToken(mdTypeDef *pTypeDef)
540 FAIL_IF_NEUTERED(this);
541 VALIDATE_POINTER_TO_OBJECT(pTypeDef, mdTypeDef *);
543 _ASSERTE(TypeFromToken(m_token) == mdtTypeDef);
550 //-----------------------------------------------------------------------------
551 // Set the JMC status on all of our member functions.
552 // The current implementation just uses the metadata to enumerate all
553 // methods and then calls SetJMCStatus on each method.
554 // This isn't great perf, but this should never be needed in a
555 // perf-critical situation.
558 // fIsUserCode - true to set entire class to user code. False to set to
562 // S_OK on success. On failure, the user-code status of the methods in the
564 //-----------------------------------------------------------------------------
565 HRESULT CordbClass::SetJMCStatus(BOOL fIsUserCode)
567 PUBLIC_REENTRANT_API_ENTRY(this);
568 FAIL_IF_NEUTERED(this);
569 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
571 // Get the member functions via a meta data interface
572 CordbModule * pModule = GetModule();
574 // Ensure that our process is in a sane state.
575 CordbProcess * pProcess = pModule->GetProcess();
576 _ASSERTE(pProcess != NULL);
578 IMetaDataImport * pImport = NULL;
583 mdMethodDef rTokens[100];
589 pImport = pModule->GetMetaDataImporter();
592 hr = pImport->EnumMethods(&phEnum, m_token, rTokens, NumItems(rTokens), &count);
595 for (i = 0; i < count; i++)
597 RSLockHolder lockHolder(pProcess->GetProcessLock());
598 // Need the ICorDebugFunction to query for JMC status.
599 CordbFunction * pFunction = pModule->LookupOrCreateFunctionLatestVersion(rTokens[i]);
601 lockHolder.Release(); // Must release before sending an IPC event
602 hr = pFunction->SetJMCStatus(fIsUserCode);
608 _ASSERTE(SUCCEEDED(hr));
610 EX_CATCH_HRESULT(hr);
612 if ((pImport != NULL) && (phEnum != 0))
614 pImport->CloseEnum(phEnum);
621 //-----------------------------------------------------------------------------
622 // We have to go the the EE to find out if a class is a value
623 // class or not. This is because there is no flag for this, but rather
624 // it depends on whether the class subclasses System.ValueType (apart
625 // from System.Enum...). Replicating all that resoultion logic
626 // does not seem like a good plan.
628 // We also accept other "evidence" that the class is or isn't a VC, in
630 // - It is definitely a VC if it has been used after a
631 // E_T_VALUETYPE in a signature.
632 // - It is definitely not a VC if it has been used after a
633 // E_T_CLASS in a signature.
634 // - It is definitely a VC if it has been used in combination with
635 // E_T_VALUETYPE in one of COM API operations that take both
636 // a ICorDebugClass and a CorElementType (e.g. GetParameterizedType)
638 // !!!Note the following!!!!
639 // - A class may still be a VC even if it has been
640 // used in combination with E_T_CLASS in one of COM API operations that take both
641 // a ICorDebugClass and a CorElementType (e.g. GetParameterizedType).
642 // We allow the user of the API to specify E_T_CLASS when the VC status
643 // is not known or is not important.
646 // indicates whether this is a value-class
649 // Throws CORDBG_E_CLASS_NOT_LOADED or synchronization errors on failure
650 //-----------------------------------------------------------------------------
651 bool CordbClass::IsValueClass()
653 INTERNAL_API_ENTRY(this);
654 THROW_IF_NEUTERED(this);
656 if (!m_fIsValueClassKnown)
658 ATT_REQUIRE_STOPPED_MAY_FAIL_OR_THROW(GetProcess(), ThrowHR);
661 return m_fIsValueClass;
664 //-----------------------------------------------------------------------------
665 // Get a CordbType for the 'this' pointer of a method in a CordbClass.
666 // The 'this' pointer is argument #0 in an instance method.
668 // For ReferenceTypes (ELEMENT_TYPE_CLASS), the 'this' pointer is just a
669 // normal reference, and so GetThisType() behaves like GetParameterizedType().
670 // For ValueTypes, the 'this' pointer is a byref.
673 // pInst - instantiation info (eg, the type parameters) to produce CordbType
674 // ppResultType - OUT: out parameter to hold outgoing CordbType.
677 // S_OK on success. Else failure.
679 HRESULT CordbClass::GetThisType(const Instantiation * pInst, CordbType ** ppResultType)
681 FAIL_IF_NEUTERED(this);
684 // Note: We have to call Init() here to find out if it really a VC or not.
685 bool fIsValueClass = false;
688 fIsValueClass = IsValueClass();
690 EX_CATCH_HRESULT(hr);
701 hr = CordbType::MkType(GetAppDomain(), // OK: this E_T_VALUETYPE will be normalized by MkType
702 ELEMENT_TYPE_VALUETYPE,
712 hr = CordbType::MkType(GetAppDomain(), ELEMENT_TYPE_BYREF, 0, pType, ppResultType);
721 hr = CordbType::MkType(GetAppDomain(), ELEMENT_TYPE_CLASS, this, pInst, ppResultType);
733 //-----------------------------------------------------------------------------
734 // Initialize the CordbClass.
735 // This will collect all the field information via the DAC, and also determine
736 // whether this Type is a ReferenceType or ValueType.
739 // fForceInit - if true, always reinitialize. If false, may skip
740 // initialization if we believe we already have the info.
743 // Throws CORDBG_E_CLASS_NOT_LOADED on failure
744 //-----------------------------------------------------------------------------
745 void CordbClass::Init(ClassLoadLevel desiredLoadLevel)
747 INTERNAL_SYNC_API_ENTRY(this->GetProcess());
749 CordbProcess * pProcess = GetProcess();
750 IDacDbiInterface* pDac = pProcess->GetDAC();
752 // If we've done a continue since the last time we got hanging static fields,
753 // we should clear out our cache, since everything may have moved.
754 if (m_continueCounterLastSync < GetProcess()->m_continueCounter)
756 m_hangingFieldsStatic.Clear();
757 m_continueCounterLastSync = GetProcess()->m_continueCounter;
760 if (m_loadLevel < desiredLoadLevel)
763 m_loadLevel = Constructed;
764 m_fIsValueClass = false;
765 m_fIsValueClassKnown = false;
766 m_fHasTypeParams = false;
768 // @dbgtodo Microsoft inspection: declare a constant to replace badbad
769 m_classInfo.m_objectSize = 0xbadbad;
770 VMPTR_TypeHandle vmTypeHandle = VMPTR_TypeHandle::NullPtr();
772 // basic info load level
773 if(desiredLoadLevel >= BasicInfo)
775 vmTypeHandle = pDac->GetTypeHandle(m_pModule->GetRuntimeModule(), GetToken());
776 SetIsValueClass(pDac->IsValueType(vmTypeHandle));
777 m_fHasTypeParams = !!pDac->HasTypeParams(vmTypeHandle);
778 m_loadLevel = BasicInfo;
781 // full info load level
782 if(desiredLoadLevel == FullInfo)
784 VMPTR_AppDomain vmAppDomain = VMPTR_AppDomain::NullPtr();
785 VMPTR_DomainFile vmDomainFile = m_pModule->GetRuntimeDomainFile();
786 if (!vmDomainFile.IsNull())
789 pDac->GetDomainFileData(vmDomainFile, &info);
790 vmAppDomain = info.vmAppDomain;
792 pDac->GetClassInfo(vmAppDomain, vmTypeHandle, &m_classInfo);
794 BOOL fGotUnallocatedStatic = GotUnallocatedStatic(&m_classInfo.m_fieldList);
796 // if we have an unallocated static don't record that we reached FullInfo stage
797 // this seems pretty ugly but I don't want to bite off cleaning this up just yet
798 // Not saving the FullInfo stage effectively means future calls to Init() will
799 // re-init everything and some parts of DBI may be depending on that re-initialization
800 // with alternate data in order to operate correctly
801 if(!fGotUnallocatedStatic)
802 m_loadLevel = FullInfo;
805 } // CordbClass::Init
807 // determine if any fields for a type are unallocated statics
808 BOOL CordbClass::GotUnallocatedStatic(DacDbiArrayList<FieldData> * pFieldList)
810 BOOL fGotUnallocatedStatic = FALSE;
812 while ((count < pFieldList->Count()) && !fGotUnallocatedStatic )
814 if ((*pFieldList)[count].OkToGetOrSetStaticAddress() &&
815 (*pFieldList)[count].GetStaticAddress() == NULL )
817 // The address for a regular static field isn't available yet
818 // How can this happen? Statics appear to get allocated during domain load.
819 // There may be some lazieness or a race-condition involved.
820 fGotUnallocatedStatic = TRUE;
824 return fGotUnallocatedStatic;
825 } // CordbClass::GotUnallocatedStatic
828 * FieldData::GetFieldSignature
830 * Get the field's full metadata signature. This may be cached, but for dynamic modules we'll always read it from
834 * pModule - pointer to the module that contains the field
836 * pSigParser - OUT: the full signature for the field.
839 * HRESULT for success or failure.
842 HRESULT FieldData::GetFieldSignature(CordbModule *pModule,
843 SigParser *pSigParser)
851 INTERNAL_SYNC_API_ENTRY(pModule->GetProcess());
855 IMetaDataImport * pImport = pModule->GetMetaDataImporter(); // throws;
857 PCCOR_SIGNATURE fieldSignature = NULL;
858 ULONG size = ((ULONG) -1);
860 _ASSERTE(pSigParser != NULL);
862 // If the module is dynamic, there had better not be a cached field signature.
863 _ASSERTE(!pModule->IsDynamic() || (m_fldSignatureCache == NULL));
865 // If the field signature cache is null, or if this is a dynamic module, then go read the signature from the
866 // matadata. We always read from the metadata for dynamic modules because our metadata blob is constantly
867 // getting deleted and re-allocated. If we kept a pointer to the signature, we'd end up pointing to bad data.
868 if (m_fldSignatureCache == NULL)
870 // Go to the metadata for all fields: previously the left-side tranferred over
871 // single-byte signatures as part of the field info. Since the left-side
872 // goes to the metadata anyway, and we already fetch plenty of other metadata,
873 // I don't believe that fetching it here instead of transferring it over
874 // is going to slow things down at all, and
875 // in any case will not be where the primary optimizations lie...
877 IfFailRet(pImport->GetFieldProps(m_fldMetadataToken, NULL, NULL, 0, NULL, NULL,
882 // Point past the calling convention
883 CorCallingConvention conv;
886 BYTE * pOldPtr = (BYTE*) fieldSignature;
887 conv = (CorCallingConvention) CorSigUncompressData(fieldSignature);
888 _ASSERTE(conv == IMAGE_CEE_CS_CALLCONV_FIELD);
889 size -= (ULONG) (((BYTE*) fieldSignature) - pOldPtr); // since we updated filedSignature, adjust size
891 // Although the pointer will keep updating, the size should be the same. So we assert that.
892 _ASSERTE((m_fldSignatureCacheSize == 0) || (m_fldSignatureCacheSize == size));
894 // Cache the value for non-dynamic modules, so this is faster later.
895 // Since we're caching in a FieldData, we can't store the actual SigParser object.
896 if (!pModule->IsDynamic())
898 m_fldSignatureCache = fieldSignature;
899 m_fldSignatureCacheSize = size;
904 // We have a cached value, so return it. Note: we should never have a cached value for a field in a dynamic
906 CONSISTENCY_CHECK_MSGF((!pModule->IsDynamic()),
907 ("We should never cache a field signature in a dynamic module! Module=%p This=%p",
910 fieldSignature = m_fldSignatureCache;
911 size = m_fldSignatureCacheSize;
914 _ASSERTE(fieldSignature != NULL);
915 _ASSERTE(size != ((ULONG) -1));
916 *pSigParser = SigParser(fieldSignature, size);
920 // CordbClass::InitEnCFieldInfo
921 // Initializes an instance of EnCHangingFieldInfo.
923 // input: fStatic - flag to indicate whether the EnC field is static
924 // pObject - For instance fields, the Object instance containing the the sync-block.
925 // For static fields (if this is being called from GetStaticFieldValue) object is NULL.
926 // fieldToken - token for the EnC field
927 // metadataToken - metadata token for this instance of CordbClass
928 // output: pEncField - the fields of this class will be appropriately initialized
929 void CordbClass::InitEnCFieldInfo(EnCHangingFieldInfo * pEncField,
931 CordbObjectValue * pObject,
932 mdFieldDef fieldToken,
933 mdTypeDef classToken)
935 IDacDbiInterface * pInterface = GetProcess()->GetDAC();
939 // the field is static, we don't need any additional data
940 pEncField->Init(VMPTR_Object::NullPtr(), /* vmObject */
941 NULL, /* offsetToVars */
945 m_pModule->GetRuntimeDomainFile());
949 // This is an instance field, we need to pass a bunch of type information back
950 _ASSERTE(pObject != NULL);
952 pEncField->Init(pInterface->GetObject(pObject->m_id), // VMPTR to the object instance of interest.
953 pObject->GetInfo().objOffsetToVars, // The offset from the beginning of the object
954 // to the beginning of the fields. Fields added
955 // with EnC don't actually reside in the object
956 // (they hang off the sync block instead), so
957 // this is used to compute the returned field
958 // offset (fieldData.m_fldInstanceOffset). This
959 // makes it appear to be an offset from the object.
960 // Ideally we wouldn't do any of this, and just
961 // explicitly deal with absolute addresses (instead
962 // of "offsets") for EnC hanging instance fields.
963 fieldToken, // Field token for the added field.
964 pObject->GetInfo().objTypeData.elementType, // An indication of the type of object to which
965 // we're adding a field (specifically,
966 // whether it's a value type or a class).
967 // This is used only for log messages, and could
969 classToken, // metadata token for the class
970 m_pModule->GetRuntimeDomainFile()); // Domain file for the class
972 } // CordbClass::InitFieldData
974 // CordbClass::GetEnCFieldFromDac
975 // Get information via the DAC about a field added with Edit and Continue.
977 // input: fStatic - flag to indicate whether the EnC field is static
978 // pObject - For instance fields, the Object instance containing the the sync-block.
979 // For static fields (if this is being called from GetStaticFieldValue) object is NULL.
980 // fieldToken - token for the EnC field
981 // output: pointer to an initialized instance of FieldData that has been added to the appropriate table
983 FieldData * CordbClass::GetEnCFieldFromDac(BOOL fStatic,
984 CordbObjectValue * pObject,
985 mdFieldDef fieldToken)
987 EnCHangingFieldInfo encField;
988 mdTypeDef metadataToken;
992 CordbProcess * pProcess = GetModule()->GetProcess();
994 _ASSERTE(pProcess != NULL);
995 IfFailThrow(GetToken(&metadataToken));
996 InitEnCFieldInfo(&encField, fStatic, pObject, fieldToken, metadataToken);
998 // Go get this particular field.
999 pProcess->GetDAC()->GetEnCHangingFieldInfo(&encField, &fieldData, &fDacStatic);
1000 _ASSERTE(fStatic == fDacStatic);
1002 // Save the field results in our cache and get a stable pointer to the data
1005 pInfo = m_hangingFieldsStatic.AddFieldInfo(&fieldData);
1009 pInfo = pObject->GetHangingFieldTable()->AddFieldInfo(&fieldData);
1012 // We should have a fresh copy of the data (don't want to return a pointer to data on our stack)
1013 _ASSERTE((void *)pInfo != (void *)&fieldData);
1014 _ASSERTE(pInfo->m_fFldIsStatic == (fStatic == TRUE));
1015 _ASSERTE(pInfo->m_fldMetadataToken == fieldToken);
1017 // Pass a pointer to the data out.
1019 } // CordbClass::GetEnCFieldFromDac
1021 //-----------------------------------------------------------------------------
1022 // Internal helper to get a FieldData for fields added by EnC after the type
1023 // was loaded. Since object and MethodTable layout has already been fixed,
1024 // such added fields are "hanging" off some other data structure. For instance
1025 // fields, they're stored in a syncblock off the object. For static fields
1026 // they're stored off the EnCFieldDesc.
1028 // The caller must have already determined this is a hanging field (i.e.
1029 // GetFieldInfo returned CORDBG_E_ENC_HANGING_FIELDF).
1032 // input: fldToken - field of interest to get.
1033 // pObject - For instance fields, the Object instance containing the the sync-block.
1034 // For static fields (if this is being called from GetStaticFieldValue) object is NULL.
1035 // output: ppFieldData - the FieldData matching the fldToken.
1038 // S_OK on success, failure code otherwise.
1039 //-----------------------------------------------------------------------------
1040 HRESULT CordbClass::GetEnCHangingField(mdFieldDef fldToken,
1041 FieldData **ppFieldData,
1042 CordbObjectValue * pObject)
1044 FAIL_IF_NEUTERED(this);
1045 INTERNAL_SYNC_API_ENTRY(GetProcess());
1048 _ASSERTE(pObject == NULL || !pObject->IsNeutered() );
1050 if (HasTypeParams())
1052 _ASSERTE(!"EnC hanging field not yet implemented on constructed types!");
1056 // This must be a static field if no object was supplied
1057 BOOL fStatic = (pObject == NULL);
1059 // Look for cached field information
1060 FieldData *pInfo = NULL;
1063 // Static fields should _NOT_ be cleared, since they stick around. Thus
1064 // the separate tables.
1065 pInfo = m_hangingFieldsStatic.GetFieldInfo(fldToken);
1069 // We must get new copies each time we call continue b/c we get the
1070 // actual Object ptr from the left side, which can move during a GC.
1071 pInfo = pObject->GetHangingFieldTable()->GetFieldInfo(fldToken);
1074 // We've found a previously located entry
1077 *ppFieldData = pInfo;
1081 // Field information not already available - go get it
1085 // We're not going to be able to get the instance-specific field
1086 // if we can't get the instance.
1087 if (!fStatic && pObject->GetInfo().objRefBad)
1089 ThrowHR(CORDBG_E_INVALID_OBJECT);
1092 *ppFieldData = GetEnCFieldFromDac(fStatic, pObject, fldToken);
1094 EX_CATCH_HRESULT(hr);
1098 //-----------------------------------------------------------------------------
1099 // Get a FieldData (which rich information, including details about storage)
1100 // from a metadata token.
1103 // fldToken - incoming metadata token specifying the field.
1104 // ppFieldData - OUT: resulting FieldData structure.
1107 // S_OK on success. else failure.
1108 //-----------------------------------------------------------------------------
1109 HRESULT CordbClass::GetFieldInfo(mdFieldDef fldToken, FieldData **ppFieldData)
1111 INTERNAL_SYNC_API_ENTRY(GetProcess());
1114 return SearchFieldInfo(GetModule(), &m_classInfo.m_fieldList, m_token, fldToken, ppFieldData);
1118 //-----------------------------------------------------------------------------
1119 // Search an array of FieldData (pFieldList) for a field (fldToken).
1120 // The FieldData array must match the class supplied by classToken, and live
1121 // in the supplied module.
1123 // Internal helper used by CordbType::GetFieldInfo, CordbClass::GetFieldInfo
1126 // module - module containing the class that the FieldData array matches.
1127 // pFieldList - array of fields to search through and the number of elements in
1129 // classToken - class that the data array matches. class must live in
1130 // the supplied moudle.
1131 // fldToken - metadata token of the field to search for. This field should be
1132 // on the class supplied by classToken.
1135 // CORDBG_E_ENC_HANGING_FIELD for "hanging fields" (fields added via Enc) (common error).
1136 // Returns S_OK, set ppFieldData = pointer into data array for matching field. (*retval)->m_fldMetadataToken == fldToken)
1137 // Throws on other errors.
1138 //-----------------------------------------------------------------------------
1140 HRESULT CordbClass::SearchFieldInfo(
1141 CordbModule * pModule,
1142 DacDbiArrayList<FieldData> * pFieldList,
1143 mdTypeDef classToken,
1144 mdFieldDef fldToken,
1145 FieldData **ppFieldData
1150 IMetaDataImport * pImport = pModule->GetMetaDataImporter(); // throws
1153 for (i = 0; i < pFieldList->Count(); i++)
1155 if ((*pFieldList)[i].m_fldMetadataToken == fldToken)
1157 // If the storage for this field isn't yet available (i.e. it is newly added with EnC)
1158 if (!(*pFieldList)[i].m_fFldStorageAvailable)
1160 // If we're a static literal, then return special HR to let
1161 // debugger know that it should look it up via the metadata.
1162 // Check m_fFldIsStatic first b/c that's fast.
1163 if ((*pFieldList)[i].m_fFldIsStatic)
1165 if (IsFieldStaticLiteral(pImport, fldToken))
1167 ThrowHR(CORDBG_E_VARIABLE_IS_ACTUALLY_LITERAL);
1171 // This is a field added by EnC, caller needs to get instance-specific info.
1172 return CORDBG_E_ENC_HANGING_FIELD;
1175 *ppFieldData = &((*pFieldList)[i]);
1180 // Hmmm... we didn't find the field on this class. See if the field really belongs to this class or not.
1183 hr = pImport->GetFieldProps(fldToken, &classTok, NULL, 0, NULL, NULL, NULL, 0, NULL, NULL, NULL);
1186 if (classTok == (mdTypeDef) classToken)
1188 // Well, the field belongs in this class. The assumption is that the Runtime optimized the field away.
1189 ThrowHR(CORDBG_E_FIELD_NOT_AVAILABLE);
1192 // Well, the field doesn't even belong to this class...
1193 ThrowHR(E_INVALIDARG);