bool Object::VerifyMemberFields(TADDR pMT, TADDR obj, WORD &numInstanceFields) { DacpMethodTableData vMethTable; if (FAILED(vMethTable.Request(g_sos, pMT))) return false; // Recursively verify the parent (this updates numInstanceFields) if (vMethTable.ParentMethodTable) { if (!VerifyMemberFields(TO_TADDR(vMethTable.ParentMethodTable), obj, numInstanceFields)) return false; } DacpMethodTableFieldData vMethodTableFields; // Verify all fields on the object. CLRDATA_ADDRESS dwAddr = vMethodTableFields.FirstField; DacpFieldDescData vFieldDesc; while (numInstanceFields < vMethodTableFields.wNumInstanceFields) { CheckInterrupt(); if (FAILED(vFieldDesc.Request(g_sos, dwAddr))) return false; if (vFieldDesc.Type >= ELEMENT_TYPE_MAX) return false; dwAddr = vFieldDesc.NextField; if (!vFieldDesc.bIsStatic) { numInstanceFields++; TADDR dwTmp = TO_TADDR(obj + vFieldDesc.dwOffset + sizeof(BaseObject)); if (vFieldDesc.Type == ELEMENT_TYPE_CLASS) { // Is it a valid object? if (FAILED(MOVE(dwTmp, dwTmp))) return false; if (dwTmp != NULL) { DacpObjectData objData; if (FAILED(objData.Request(g_sos, TO_CDADDR(dwTmp)))) return false; } } } } return true; }
TADDR Object::GetComponentMT() const { if (mMT != NULL && mMT != sos::MethodTable::GetArrayMT()) return NULL; DacpObjectData objData; if (FAILED(objData.Request(g_sos, TO_CDADDR(mAddress)))) sos::Throw<DataRead>("Failed to request object data for %s.", DMLListNearObj(mAddress)); if (mMT == NULL) mMT = TO_TADDR(objData.MethodTable) & ~3; return TO_TADDR(objData.ElementTypeHandle); }
bool Object::IsValid(TADDR address, bool verifyFields) { DacpObjectData objectData; if (FAILED(objectData.Request(g_sos, TO_CDADDR(address)))) return false; if (verifyFields && objectData.MethodTable != g_special_usefulGlobals.FreeMethodTable && !MethodTable::IsZombie(TO_TADDR(objectData.MethodTable))) { return VerifyMemberFields(TO_TADDR(objectData.MethodTable), address); } return true; }
HRESULT ClrDataAccess::ServerGCHeapDetails(CLRDATA_ADDRESS heapAddr, DacpGcHeapDetails *detailsData) { if (!heapAddr) { // PREfix. return E_INVALIDARG; } SVR::gc_heap *pHeap = PTR_SVR_gc_heap(TO_TADDR(heapAddr)); int i; detailsData->heapAddr = heapAddr; detailsData->lowest_address = PTR_CDADDR(g_lowest_address); detailsData->highest_address = PTR_CDADDR(g_highest_address); detailsData->card_table = PTR_CDADDR(g_card_table); detailsData->alloc_allocated = (CLRDATA_ADDRESS)(ULONG_PTR) pHeap->alloc_allocated; detailsData->ephemeral_heap_segment = (CLRDATA_ADDRESS)(ULONG_PTR) pHeap->ephemeral_heap_segment; for (i=0;i<NUMBERGENERATIONS;i++) { detailsData->generation_table[i].start_segment = (CLRDATA_ADDRESS)(ULONG_PTR) pHeap->generation_table[i].start_segment; detailsData->generation_table[i].allocation_start = (CLRDATA_ADDRESS)(ULONG_PTR) pHeap->generation_table[i].allocation_start; detailsData->generation_table[i].allocContextPtr = (CLRDATA_ADDRESS)(ULONG_PTR) pHeap->generation_table[i].allocation_context.alloc_ptr; detailsData->generation_table[i].allocContextLimit = (CLRDATA_ADDRESS)(ULONG_PTR) pHeap->generation_table[i].allocation_context.alloc_limit; } TADDR pFillPointerArray = TO_TADDR(pHeap->finalize_queue) + offsetof(SVR::CFinalize,m_FillPointers); for(i=0;i<(NUMBERGENERATIONS+SVR::CFinalize::ExtraSegCount);i++) { ULONG32 returned = sizeof(size_t); size_t pValue; m_target->ReadVirtual(pFillPointerArray+(i*sizeof(size_t)), (PBYTE)&pValue, sizeof(size_t),&returned); if (returned != sizeof(size_t)) { return E_FAIL; } detailsData->finalization_fill_pointers[i] = (CLRDATA_ADDRESS) pValue; } return S_OK; }
HRESULT ClrDataAccess::ServerOomData(CLRDATA_ADDRESS addr, DacpOomData *oomData) { DPTR(dac_gc_heap) pHeap = __DPtr<dac_gc_heap>(TO_TADDR(addr)); oom_history pOOMInfo = pHeap->oom_info; oomData->reason = pOOMInfo.reason; oomData->alloc_size = pOOMInfo.alloc_size; oomData->available_pagefile_mb = pOOMInfo.available_pagefile_mb; oomData->gc_index = pOOMInfo.gc_index; oomData->fgm = pOOMInfo.fgm; oomData->size = pOOMInfo.size; oomData->loh_p = pOOMInfo.loh_p; return S_OK; }
HRESULT ClrDataAccess::ServerGCHeapAnalyzeData(CLRDATA_ADDRESS heapAddr, DacpGcHeapAnalyzeData *analyzeData) { if (!heapAddr) { // PREfix. return E_INVALIDARG; } DPTR(dac_gc_heap) pHeap = __DPtr<dac_gc_heap>(TO_TADDR(heapAddr)); analyzeData->heapAddr = heapAddr; analyzeData->internal_root_array = (CLRDATA_ADDRESS)pHeap->internal_root_array; analyzeData->internal_root_array_index = (size_t)pHeap->internal_root_array_index; analyzeData->heap_analyze_success = (BOOL)pHeap->heap_analyze_success; return S_OK; }
void Object::CalculateSizeAndPointers() const { TADDR mt = GetMT(); MethodTableInfo* info = g_special_mtCache.Lookup((DWORD_PTR)mt); if (!info->IsInitialized()) { // this is the first time we see this method table, so we need to get the information // from the target FillMTData(); info->BaseSize = mMTData->BaseSize; info->ComponentSize = mMTData->ComponentSize; info->bContainsPointers = mMTData->bContainsPointers; // The following request doesn't work on older runtimes. For those, the // objects would just look like non-collectible, which is acceptable. DacpMethodTableCollectibleData mtcd; if (SUCCEEDED(mtcd.Request(g_sos, GetMT()))) { info->bCollectible = mtcd.bCollectible; info->LoaderAllocatorObjectHandle = TO_TADDR(mtcd.LoaderAllocatorObjectHandle); } } if (mSize == (size_t)~0) { mSize = info->BaseSize; if (info->ComponentSize) { // this is an array, so the size has to include the size of the components. We read the number // of components from the target and multiply by the component size to get the size. mSize += info->ComponentSize * GetNumComponents(GetAddress()); } // On x64 we do an optimization to save 4 bytes in almost every string we create. #ifdef _WIN64 // Pad to min object size if necessary if (mSize < min_obj_size) mSize = min_obj_size; #endif // _WIN64 } mPointers = info->bContainsPointers != FALSE; }
HRESULT ClrDataAccess::ServerGCHeapDetails(CLRDATA_ADDRESS heapAddr, DacpGcHeapDetails *detailsData) { if (!heapAddr) { // PREfix. return E_INVALIDARG; } DPTR(dac_gc_heap) pHeap = __DPtr<dac_gc_heap>(TO_TADDR(heapAddr)); int i; //get global information first detailsData->heapAddr = heapAddr; detailsData->lowest_address = PTR_CDADDR(g_lowest_address); detailsData->highest_address = PTR_CDADDR(g_highest_address); detailsData->card_table = PTR_CDADDR(g_card_table); // now get information specific to this heap (server mode gives us several heaps; we're getting // information about only one of them. detailsData->alloc_allocated = (CLRDATA_ADDRESS)pHeap->alloc_allocated; detailsData->ephemeral_heap_segment = (CLRDATA_ADDRESS)dac_cast<TADDR>(pHeap->ephemeral_heap_segment); // get bounds for the different generations for (i=0; i<NUMBERGENERATIONS; i++) { DPTR(dac_generation) generation = ServerGenerationTableIndex(pHeap, i); detailsData->generation_table[i].start_segment = (CLRDATA_ADDRESS)dac_cast<TADDR>(generation->start_segment); detailsData->generation_table[i].allocation_start = (CLRDATA_ADDRESS)(ULONG_PTR)generation->allocation_start; DPTR(gc_alloc_context) alloc_context = dac_cast<TADDR>(generation) + offsetof(dac_generation, allocation_context); detailsData->generation_table[i].allocContextPtr = (CLRDATA_ADDRESS)(ULONG_PTR) alloc_context->alloc_ptr; detailsData->generation_table[i].allocContextLimit = (CLRDATA_ADDRESS)(ULONG_PTR) alloc_context->alloc_limit; } DPTR(dac_finalize_queue) fq = pHeap->finalize_queue; DPTR(uint8_t*) pFillPointerArray= dac_cast<TADDR>(fq) + offsetof(dac_finalize_queue, m_FillPointers); for(i=0; i<(NUMBERGENERATIONS+dac_finalize_queue::ExtraSegCount); i++) { detailsData->finalization_fill_pointers[i] = (CLRDATA_ADDRESS) pFillPointerArray[i]; } return S_OK; }
bool Object::TryGetHeader(ULONG &outHeader) const { struct ObjectHeader { #ifdef _WIN64 ULONG _alignpad; #endif ULONG SyncBlockValue; // the Index and the Bits }; ObjectHeader header; if (SUCCEEDED(rvCache->Read(TO_TADDR(GetAddress() - sizeof(ObjectHeader)), &header, sizeof(ObjectHeader), NULL))) { outHeader = header.SyncBlockValue; return true; } return false; }
HRESULT GetServerHeapData(CLRDATA_ADDRESS addr, DacpHeapSegmentData *pSegment) { if (!addr) { // PREfix. return E_INVALIDARG; } SVR::heap_segment *pHeapSegment = __DPtr<SVR::heap_segment>(TO_TADDR(addr)); pSegment->segmentAddr = addr; pSegment->allocated = (CLRDATA_ADDRESS)(ULONG_PTR) pHeapSegment->allocated; pSegment->committed = (CLRDATA_ADDRESS)(ULONG_PTR) pHeapSegment->committed; pSegment->reserved = (CLRDATA_ADDRESS)(ULONG_PTR) pHeapSegment->reserved; pSegment->used = (CLRDATA_ADDRESS)(ULONG_PTR) pHeapSegment->used; pSegment->mem = (CLRDATA_ADDRESS)(ULONG_PTR) pHeapSegment->mem; pSegment->next = (CLRDATA_ADDRESS)(ULONG_PTR) pHeapSegment->next; pSegment->gc_heap = (CLRDATA_ADDRESS)(ULONG_PTR) pHeapSegment->heap; return S_OK; }
bool Object::GetThinLock(ThinLockInfo &out) const { ULONG header = GetHeader(); if (header & (BIT_SBLK_IS_HASH_OR_SYNCBLKINDEX | BIT_SBLK_SPIN_LOCK)) { return false; } out.ThreadId = header & SBLK_MASK_LOCK_THREADID; out.Recursion = (header & SBLK_MASK_LOCK_RECLEVEL) >> SBLK_RECLEVEL_SHIFT; CLRDATA_ADDRESS threadPtr = NULL; if (g_sos->GetThreadFromThinlockID(out.ThreadId, &threadPtr) != S_OK) { out.ThreadPtr = NULL; } else { out.ThreadPtr = TO_TADDR(threadPtr); } return out.ThreadId != 0 && out.ThreadPtr != NULL; }
HRESULT GetServerHeapData(CLRDATA_ADDRESS addr, DacpHeapSegmentData *pSegment) { // get field values (target addresses) for the heap segment at addr if (!addr) { // PREfix. return E_INVALIDARG; } // marshal the segment from target to host dac_heap_segment *pHeapSegment = __DPtr<dac_heap_segment>(TO_TADDR(addr)); // initialize fields by copying from the marshaled segment (note that these are all target addresses) pSegment->segmentAddr = addr; pSegment->allocated = (CLRDATA_ADDRESS)(ULONG_PTR) pHeapSegment->allocated; pSegment->committed = (CLRDATA_ADDRESS)(ULONG_PTR) pHeapSegment->committed; pSegment->reserved = (CLRDATA_ADDRESS)(ULONG_PTR) pHeapSegment->reserved; pSegment->used = (CLRDATA_ADDRESS)(ULONG_PTR) pHeapSegment->used; pSegment->mem = (CLRDATA_ADDRESS)(ULONG_PTR) (pHeapSegment->mem); pSegment->next = (CLRDATA_ADDRESS)dac_cast<TADDR>(pHeapSegment->next); pSegment->gc_heap = (CLRDATA_ADDRESS)pHeapSegment->heap; return S_OK; }
HRESULT ClrDataAccess::ServerGCInterestingInfoData(CLRDATA_ADDRESS addr, DacpGCInterestingInfoData *interestingInfoData) { #ifdef GC_CONFIG_DRIVEN dac_gc_heap *pHeap = __DPtr<dac_gc_heap>(TO_TADDR(addr)); size_t* dataPoints = (size_t*)&(pHeap->interesting_data_per_heap); for (int i = 0; i < NUM_GC_DATA_POINTS; i++) interestingInfoData->interestingDataPoints[i] = dataPoints[i]; size_t* mechanisms = (size_t*)&(pHeap->compact_reasons_per_heap); for (int i = 0; i < MAX_COMPACT_REASONS_COUNT; i++) interestingInfoData->compactReasons[i] = mechanisms[i]; mechanisms = (size_t*)&(pHeap->expand_mechanisms_per_heap); for (int i = 0; i < MAX_EXPAND_MECHANISMS_COUNT; i++) interestingInfoData->expandMechanisms[i] = mechanisms[i]; mechanisms = (size_t*)&(pHeap->interesting_mechanism_bits_per_heap); for (int i = 0; i < MAX_GC_MECHANISM_BITS_COUNT; i++) interestingInfoData->bitMechanisms[i] = mechanisms[i]; return S_OK; #else return E_NOTIMPL; #endif //GC_CONFIG_DRIVEN }