Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 18 additions & 13 deletions src/coreclr/debug/daccess/request.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2772,19 +2772,24 @@ ClrDataAccess::GetGCHeapDetails(CLRDATA_ADDRESS heap, struct DacpGcHeapDetails *
HRESULT
ClrDataAccess::GetGCHeapStaticData(struct DacpGcHeapDetails *detailsData)
{
// Make sure ClrDataAccess::ServerGCHeapDetails() is updated as well.
if (detailsData == NULL)
{
return E_INVALIDARG;
}

SOSDacEnter();

detailsData->heapAddr = NULL;

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->heapAddr = NULL;
detailsData->current_c_gc_state = (CLRDATA_ADDRESS)*g_gcDacGlobals->current_c_gc_state;

detailsData->alloc_allocated = (CLRDATA_ADDRESS)*g_gcDacGlobals->alloc_allocated;
detailsData->ephemeral_heap_segment = (CLRDATA_ADDRESS)*g_gcDacGlobals->ephemeral_heap_segment;
detailsData->card_table = PTR_CDADDR(g_card_table);
detailsData->mark_array = (CLRDATA_ADDRESS)*g_gcDacGlobals->mark_array;
detailsData->current_c_gc_state = (CLRDATA_ADDRESS)*g_gcDacGlobals->current_c_gc_state;
detailsData->next_sweep_obj = (CLRDATA_ADDRESS)*g_gcDacGlobals->next_sweep_obj;
if (g_gcDacGlobals->saved_sweep_ephemeral_seg != nullptr)
{
Expand All @@ -2801,13 +2806,12 @@ ClrDataAccess::GetGCHeapStaticData(struct DacpGcHeapDetails *detailsData)
detailsData->background_saved_lowest_address = (CLRDATA_ADDRESS)*g_gcDacGlobals->background_saved_lowest_address;
detailsData->background_saved_highest_address = (CLRDATA_ADDRESS)*g_gcDacGlobals->background_saved_highest_address;

for (unsigned int i=0; i < *g_gcDacGlobals->max_gen + 2; i++)
// get bounds for the different generations
for (unsigned int i=0; i < DAC_NUMBERGENERATIONS; i++)
{
DPTR(dac_generation) generation = GenerationTableIndex(g_gcDacGlobals->generation_table, i);
detailsData->generation_table[i].start_segment = (CLRDATA_ADDRESS) dac_cast<TADDR>(generation->start_segment);

detailsData->generation_table[i].allocation_start = (CLRDATA_ADDRESS) 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)alloc_context->alloc_ptr;
detailsData->generation_table[i].allocContextLimit = (CLRDATA_ADDRESS)alloc_context->alloc_limit;
Expand All @@ -2817,7 +2821,7 @@ ClrDataAccess::GetGCHeapStaticData(struct DacpGcHeapDetails *detailsData)
{
DPTR(dac_finalize_queue) fq = Dereference(g_gcDacGlobals->finalize_queue);
DPTR(uint8_t*) fillPointersTable = dac_cast<TADDR>(fq) + offsetof(dac_finalize_queue, m_FillPointers);
for (unsigned int i = 0; i<(*g_gcDacGlobals->max_gen + 2 + dac_finalize_queue::ExtraSegCount); i++)
for (unsigned int i = 0; i < DAC_NUMBERGENERATIONS + 3; i++)
{
detailsData->finalization_fill_pointers[i] = (CLRDATA_ADDRESS)*TableIndex(fillPointersTable, i, sizeof(uint8_t*));
}
Expand Down Expand Up @@ -4699,13 +4703,13 @@ HRESULT ClrDataAccess::GetGenerationTableSvr(CLRDATA_ADDRESS heapAddr, unsigned
}
else
{
DPTR(dac_gc_heap) pHeap = __DPtr<dac_gc_heap>(TO_TADDR(heapAddr));
TADDR heapAddress = TO_TADDR(heapAddr);

if (pHeap.IsValid())
if (heapAddress != 0)
{
for (unsigned int i = 0; i < numGenerationTableEntries; ++i)
{
DPTR(dac_generation) generation = ServerGenerationTableIndex(pHeap, i);
DPTR(dac_generation) generation = ServerGenerationTableIndex(heapAddress, i);
pGenerationData[i].start_segment = (CLRDATA_ADDRESS)dac_cast<TADDR>(generation->start_segment);
pGenerationData[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);
Expand Down Expand Up @@ -4749,10 +4753,11 @@ HRESULT ClrDataAccess::GetFinalizationFillPointersSvr(CLRDATA_ADDRESS heapAddr,
}
else
{
DPTR(dac_gc_heap) pHeap = __DPtr<dac_gc_heap>(TO_TADDR(heapAddr));

if (pHeap.IsValid())
TADDR heapAddress = TO_TADDR(heapAddr);
if (heapAddress != 0)
{
dac_gc_heap heap = LoadGcHeapData(heapAddress);
dac_gc_heap* pHeap = &heap;
DPTR(dac_finalize_queue) fq = pHeap->finalize_queue;
DPTR(uint8_t*) pFillPointerArray= dac_cast<TADDR>(fq) + offsetof(dac_finalize_queue, m_FillPointers);
for (unsigned int i = 0; i < numFillPointers; ++i)
Expand Down
107 changes: 96 additions & 11 deletions src/coreclr/debug/daccess/request_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,16 @@ DPTR(T) Dereference(DPTR(T*) ptr)
return __DPtr<T>(ptr_base);
}

// Indexes into the global heap table, returning a TADDR to the requested
// heap instance.
inline TADDR
HeapTableIndex(DPTR(opaque_gc_heap**) heaps, size_t index)
{
DPTR(opaque_gc_heap*) heap_table = Dereference(heaps);
DPTR(opaque_gc_heap*) ptr = TableIndex(heap_table, index, sizeof(void*));
return Dereference(ptr).GetAddr();
}

// Indexes into a given generation table, returning a DPTR to the
// requested element (the element at the given index) of the table.
inline DPTR(dac_generation)
Expand All @@ -34,24 +44,99 @@ GenerationTableIndex(DPTR(dac_generation) base, size_t index)
return TableIndex(base, index, g_gcDacGlobals->generation_size);
}

// Starting .NET 6, it is possible for the gc_heap object to have different layouts
// for coreclr.dll and clrgc.dll. Instead of using assuming dac_gc_heap and gc_heap
// have identical layout, we have the gc exported an array of field offsets instead.
// These offsets could be -1, indicating the field does not exist in the current
// gc_heap being used.

// field_offset = g_gcDacGlobals->gc_heap_field_offsets
// p_field_offset = field_offset[field_index]
// p_field = heap + p_field_offset
// field_index++
#define LOAD_BASE(field_name, field_type) \
DPTR(int) p_##field_name##_offset = TableIndex(field_offsets, field_index, sizeof(int)); \
int field_name##_offset = *p_##field_name##_offset; \
DPTR(field_type) p_##field_name = heap + field_name##_offset; \
field_index++;

// if (field_offset != -1)
// result.field = *p_field
#define LOAD(field_name, field_type) \
LOAD_BASE(field_name, field_type) \
if (field_name##_offset != -1) \
{ \
field_type field_name = *p_##field_name; \
result.field_name = field_name; \
}

// if (field_offset != -1)
// result.field = DPTR(field_type)field_name
#define LOAD_DPTR(field_name, field_type) \
LOAD_BASE(field_name, field_type*) \
if (field_name##_offset != -1) \
{ \
field_type* field_name = *p_##field_name; \
result.field_name = DPTR(field_type)((TADDR)field_name); \
}

// if (field_offset != -1)
// for i from 0 to array_length - 1
// result.field[i] = *p_field
// p_field = p_field + 1
#define LOAD_ARRAY(field_name, field_type, array_length) \
LOAD_BASE(field_name, field_type) \
if (field_name##_offset != -1) \
{ \
for (int i = 0; i < array_length; i++) \
{ \
result.field_name[i] = *p_##field_name; \
p_##field_name = p_##field_name + 1; \
} \
}

// Indexes into a heap's generation table, given the heap instance
// and the desired index. Returns a DPTR to the requested element.
inline DPTR(dac_generation)
ServerGenerationTableIndex(DPTR(dac_gc_heap) heap, size_t index)
ServerGenerationTableIndex(TADDR heap, size_t index)
{
TADDR base_addr = dac_cast<TADDR>(heap) + offsetof(dac_gc_heap, generation_table);
DPTR(dac_generation) base = __DPtr<dac_generation>(base_addr);
return TableIndex(base, index, g_gcDacGlobals->generation_size);
DPTR(int) field_offsets = g_gcDacGlobals->gc_heap_field_offsets;
int field_index = GENERATION_TABLE_FIELD_INDEX;
LOAD_BASE (generation_table, dac_generation);
assert (generation_table_offset != -1);
return TableIndex(p_generation_table, index, g_gcDacGlobals->generation_size);
}

// Indexes into the global heap table, returning a DPTR to the requested
// heap instance.
inline DPTR(dac_gc_heap)
HeapTableIndex(DPTR(dac_gc_heap**) heaps, size_t index)
// Load an instance of dac_gc_heap for the heap pointed by heap.
// Fields that does not exist in the current gc_heap instance is zero initialized.
// Return the dac_gc_heap object.
inline dac_gc_heap
LoadGcHeapData(TADDR heap)
{
DPTR(dac_gc_heap*) heap_table = Dereference(heaps);
DPTR(dac_gc_heap*) ptr = TableIndex(heap_table, index, sizeof(dac_gc_heap*));
return Dereference(ptr);
dac_gc_heap result;
memset(&result, 0, sizeof(dac_gc_heap));

DPTR(int) field_offsets = g_gcDacGlobals->gc_heap_field_offsets;
int field_index = 0;

#define ALL_FIELDS
#define DEFINE_FIELD(field_name, field_type) LOAD(field_name, field_type)
#define DEFINE_DPTR_FIELD(field_name, field_type) LOAD_DPTR(field_name, field_type)
#define DEFINE_ARRAY_FIELD(field_name, field_type, array_length) LOAD_ARRAY(field_name, field_type, array_length);

#include "../../gc/gc_typefields.h"

#undef DEFINE_ARRAY_FIELD
#undef DEFINE_DPTR_FIELD
#undef DEFINE_FIELD
#undef ALL_FIELDS

return result;
}

#undef LOAD_ARRAY
#undef LOAD_DPTR
#undef LOAD
#undef LOAD_BASE

#endif // _REQUEST_COMMON_H_
83 changes: 59 additions & 24 deletions src/coreclr/debug/daccess/request_svr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ HRESULT GetServerHeaps(CLRDATA_ADDRESS pGCHeaps[], ICorDebugDataTarget * pTarget
// heap addresses.
for (int i = 0; i < GCHeapCount(); i++)
{
pGCHeaps[i] = (CLRDATA_ADDRESS)HeapTableIndex(g_gcDacGlobals->g_heaps, i).GetAddr();
pGCHeaps[i] = (CLRDATA_ADDRESS)HeapTableIndex(g_gcDacGlobals->g_heaps, i);
}

return S_OK;
Expand All @@ -86,7 +86,7 @@ HRESULT ClrDataAccess::GetServerAllocData(unsigned int count, struct DacpGenerat

for (unsigned int n=0; n < heaps; n++)
{
DPTR(dac_gc_heap) pHeap = HeapTableIndex(g_gcDacGlobals->g_heaps, n);
TADDR pHeap = HeapTableIndex(g_gcDacGlobals->g_heaps, n);
for (int i=0;i<NUMBERGENERATIONS;i++)
{
dac_generation generation = *ServerGenerationTableIndex(pHeap, i);
Expand All @@ -99,33 +99,57 @@ HRESULT ClrDataAccess::GetServerAllocData(unsigned int count, struct DacpGenerat
return S_OK;
}

HRESULT ClrDataAccess::ServerGCHeapDetails(CLRDATA_ADDRESS heapAddr, DacpGcHeapDetails *detailsData)
HRESULT
ClrDataAccess::ServerGCHeapDetails(CLRDATA_ADDRESS heapAddr, DacpGcHeapDetails *detailsData)
{
// Make sure ClrDataAccess::GetGCHeapStaticData() is updated as well.
if (!heapAddr)
{
// PREfix.
return E_INVALIDARG;
}
if (detailsData == NULL)
{
return E_INVALIDARG;
}

DPTR(dac_gc_heap) pHeap = __DPtr<dac_gc_heap>(TO_TADDR(heapAddr));
int i;
TADDR heapAddress = TO_TADDR(heapAddr);
dac_gc_heap heap = LoadGcHeapData(heapAddress);
dac_gc_heap* pHeap = &heap;

//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);
detailsData->current_c_gc_state = (CLRDATA_ADDRESS)*g_gcDacGlobals->current_c_gc_state;

// 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);
detailsData->card_table = (CLRDATA_ADDRESS)pHeap->card_table;
detailsData->mark_array = (CLRDATA_ADDRESS)pHeap->mark_array;
detailsData->next_sweep_obj = (CLRDATA_ADDRESS)pHeap->next_sweep_obj;
if (pHeap->saved_sweep_ephemeral_seg.IsValid())
{
detailsData->saved_sweep_ephemeral_seg = (CLRDATA_ADDRESS)dac_cast<TADDR>(pHeap->saved_sweep_ephemeral_seg);
detailsData->saved_sweep_ephemeral_start = (CLRDATA_ADDRESS)*pHeap->saved_sweep_ephemeral_start;
}
else
{
// with regions, we don't have these variables anymore
// use special value -1 in saved_sweep_ephemeral_seg to signal the region case
detailsData->saved_sweep_ephemeral_seg = (CLRDATA_ADDRESS)-1;
detailsData->saved_sweep_ephemeral_start = 0;
}
detailsData->background_saved_lowest_address = (CLRDATA_ADDRESS)pHeap->background_saved_lowest_address;
detailsData->background_saved_highest_address = (CLRDATA_ADDRESS)pHeap->background_saved_highest_address;

// get bounds for the different generations
for (i=0; i<NUMBERGENERATIONS; i++)
for (unsigned int i=0; i < DAC_NUMBERGENERATIONS; i++)
{
DPTR(dac_generation) generation = ServerGenerationTableIndex(pHeap, i);
DPTR(dac_generation) generation = ServerGenerationTableIndex(heapAddress, 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);
Expand All @@ -134,10 +158,13 @@ HRESULT ClrDataAccess::ServerGCHeapDetails(CLRDATA_ADDRESS heapAddr, DacpGcHeapD
}

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++)
if (fq.IsValid())
{
detailsData->finalization_fill_pointers[i] = (CLRDATA_ADDRESS) pFillPointerArray[i];
DPTR(uint8_t*) fillPointersTable = dac_cast<TADDR>(fq) + offsetof(dac_finalize_queue, m_FillPointers);
for (unsigned int i = 0; i < DAC_NUMBERGENERATIONS + 3; i++)
{
detailsData->finalization_fill_pointers[i] = (CLRDATA_ADDRESS)*TableIndex(fillPointersTable, i, sizeof(uint8_t*));
}
}

return S_OK;
Expand All @@ -146,7 +173,9 @@ HRESULT ClrDataAccess::ServerGCHeapDetails(CLRDATA_ADDRESS heapAddr, DacpGcHeapD
HRESULT
ClrDataAccess::ServerOomData(CLRDATA_ADDRESS addr, DacpOomData *oomData)
{
DPTR(dac_gc_heap) pHeap = __DPtr<dac_gc_heap>(TO_TADDR(addr));
TADDR heapAddress = TO_TADDR(addr);
dac_gc_heap heap = LoadGcHeapData(heapAddress);
dac_gc_heap* pHeap = &heap;

oom_history pOOMInfo = pHeap->oom_info;
oomData->reason = pOOMInfo.reason;
Expand Down Expand Up @@ -193,7 +222,9 @@ HRESULT ClrDataAccess::ServerGCHeapAnalyzeData(CLRDATA_ADDRESS heapAddr, DacpGcH
return E_INVALIDARG;
}

DPTR(dac_gc_heap) pHeap = __DPtr<dac_gc_heap>(TO_TADDR(heapAddr));
TADDR heapAddress = TO_TADDR(heapAddr);
dac_gc_heap heap = LoadGcHeapData(heapAddress);
dac_gc_heap* pHeap = &heap;

analyzeData->heapAddr = heapAddr;
analyzeData->internal_root_array = (CLRDATA_ADDRESS)pHeap->internal_root_array;
Expand Down Expand Up @@ -221,7 +252,9 @@ ClrDataAccess::EnumSvrGlobalMemoryRegions(CLRDataEnumMemoryFlags flags)

for (int i = 0; i < heaps; i++)
{
DPTR(dac_gc_heap) pHeap = HeapTableIndex(g_gcDacGlobals->g_heaps, i);
TADDR heapAddress = HeapTableIndex(g_gcDacGlobals->g_heaps, i);
dac_gc_heap heap = LoadGcHeapData(heapAddress);
dac_gc_heap* pHeap = &heap;

size_t gen_table_size = g_gcDacGlobals->generation_size * (*g_gcDacGlobals->max_gen + 2);
DacEnumMemoryRegion(dac_cast<TADDR>(pHeap), sizeof(dac_gc_heap));
Expand All @@ -235,7 +268,7 @@ ClrDataAccess::EnumSvrGlobalMemoryRegions(CLRDataEnumMemoryFlags flags)
// this is the convention in the GC so it is repeated here
for (ULONG i = *g_gcDacGlobals->max_gen; i <= *g_gcDacGlobals->max_gen +1; i++)
{
DPTR(dac_heap_segment) seg = ServerGenerationTableIndex(pHeap, i)->start_segment;
DPTR(dac_heap_segment) seg = ServerGenerationTableIndex(heapAddress, i)->start_segment;
while (seg)
{
DacEnumMemoryRegion(PTR_HOST_TO_TADDR(seg), sizeof(dac_heap_segment));
Expand Down Expand Up @@ -270,18 +303,20 @@ HRESULT DacHeapWalker::InitHeapDataSvr(HeapData *&pHeaps, size_t &pCount)
for (int i = 0; i < heaps; ++i)
{
// Basic heap info.
DPTR(dac_gc_heap) heap = HeapTableIndex(g_gcDacGlobals->g_heaps, i);
dac_generation gen0 = *ServerGenerationTableIndex(heap, 0);
dac_generation gen1 = *ServerGenerationTableIndex(heap, 1);
dac_generation gen2 = *ServerGenerationTableIndex(heap, 2);
dac_generation loh = *ServerGenerationTableIndex(heap, 3);
dac_generation poh = *ServerGenerationTableIndex(heap, 4);
TADDR heapAddress = HeapTableIndex(g_gcDacGlobals->g_heaps, i);
dac_gc_heap heap = LoadGcHeapData(heapAddress);
dac_gc_heap* pHeap = &heap;
dac_generation gen0 = *ServerGenerationTableIndex(heapAddress, 0);
dac_generation gen1 = *ServerGenerationTableIndex(heapAddress, 1);
dac_generation gen2 = *ServerGenerationTableIndex(heapAddress, 2);
dac_generation loh = *ServerGenerationTableIndex(heapAddress, 3);
dac_generation poh = *ServerGenerationTableIndex(heapAddress, 4);

pHeaps[i].YoungestGenPtr = (CORDB_ADDRESS)gen0.allocation_context.alloc_ptr;
pHeaps[i].YoungestGenLimit = (CORDB_ADDRESS)gen0.allocation_context.alloc_limit;

pHeaps[i].Gen0Start = (CORDB_ADDRESS)gen0.allocation_start;
pHeaps[i].Gen0End = (CORDB_ADDRESS)heap->alloc_allocated;
pHeaps[i].Gen0End = (CORDB_ADDRESS)pHeap->alloc_allocated;
pHeaps[i].Gen1Start = (CORDB_ADDRESS)gen1.allocation_start;

// Segments
Expand All @@ -300,9 +335,9 @@ HRESULT DacHeapWalker::InitHeapDataSvr(HeapData *&pHeaps, size_t &pCount)
for (; seg && (j < count); ++j)
{
pHeaps[i].Segments[j].Start = (CORDB_ADDRESS)seg->mem;
if (seg.GetAddr() == heap->ephemeral_heap_segment.GetAddr())
if (seg.GetAddr() == pHeap->ephemeral_heap_segment.GetAddr())
{
pHeaps[i].Segments[j].End = (CORDB_ADDRESS)heap->alloc_allocated;
pHeaps[i].Segments[j].End = (CORDB_ADDRESS)pHeap->alloc_allocated;
pHeaps[i].EphemeralSegment = j;
pHeaps[i].Segments[j].Generation = 1;
}
Expand Down
Loading