Skip to content

Commit

Permalink
Fix enum memory code paths (dotnet#57981)
Browse files Browse the repository at this point in the history
  • Loading branch information
cshung authored Aug 24, 2021
1 parent 514b025 commit 7571649
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 27 deletions.
26 changes: 13 additions & 13 deletions src/coreclr/debug/daccess/request.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3768,24 +3768,24 @@ ClrDataAccess::EnumWksGlobalMemoryRegions(CLRDataEnumMemoryFlags flags)
Dereference(g_gcDacGlobals->finalize_queue).EnumMem();

// Enumerate the entire generation table, which has variable size
size_t gen_table_size = g_gcDacGlobals->generation_size * (*g_gcDacGlobals->max_gen + 2);
DacEnumMemoryRegion(dac_cast<TADDR>(g_gcDacGlobals->generation_table), gen_table_size);
EnumGenerationTable(dac_cast<TADDR>(g_gcDacGlobals->generation_table));

if (g_gcDacGlobals->generation_table.IsValid())
{
// enumerating the generations from max (which is normally gen2) to max+1 gives you
// the segment list for all the normal segements plus the large heap segment (max+1)
// 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++)
ULONG first = IsRegion() ? 0 : (*g_gcDacGlobals->max_gen);
// enumerating the first to max + 2 gives you
// the segment list for all the normal segments plus the pinned heap segment (max + 2)
// this is the convention in the GC so it is repeated here
for (ULONG i = first; i <= *g_gcDacGlobals->max_gen + 2; i++)
{
dac_generation gen = GenerationTableIndex(g_gcDacGlobals->generation_table, i);
__DPtr<dac_heap_segment> seg = dac_cast<TADDR>(gen.start_segment);
while (seg)
{
dac_generation gen = GenerationTableIndex(g_gcDacGlobals->generation_table, i);
__DPtr<dac_heap_segment> seg = dac_cast<TADDR>(gen.start_segment);
while (seg)
{
DacEnumMemoryRegion(dac_cast<TADDR>(seg), sizeof(dac_heap_segment));
seg = seg->next;
}
DacEnumMemoryRegion(dac_cast<TADDR>(seg), sizeof(dac_heap_segment));
seg = seg->next;
}
}
}
}

Expand Down
79 changes: 75 additions & 4 deletions src/coreclr/debug/daccess/request_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,15 @@ HeapTableIndex(DPTR(unused_gc_heap**) heaps, size_t index)
result.field_name = field_name; \
}

// if (field_offset != -1)
// p_field.EnumMem();
#define ENUM(field_name, field_type) \
LOAD_BASE(field_name, field_type) \
if (field_name##_offset != -1) \
{ \
p_##field_name.EnumMem(); \
}

// if (field_offset != -1)
// result.field = DPTR(field_type)field_name
#define LOAD_DPTR(field_name, field_type) \
Expand All @@ -87,6 +96,13 @@ HeapTableIndex(DPTR(unused_gc_heap**) heaps, size_t index)
} \
}

#define ENUM_ARRAY(field_name, field_type, array_length) \
LOAD_BASE(field_name, field_type) \
if (field_name##_offset != -1) \
{ \
DacEnumMemoryRegion(p_##field_name.GetAddr(), sizeof(field_type) * array_length); \
}

inline bool IsRegion()
{
return (g_gcDacGlobals->minor_version_number & 1) != 0;
Expand Down Expand Up @@ -121,6 +137,26 @@ LoadGcHeapData(TADDR heap)
return result;
}

inline void EnumGcHeap(TADDR heap)
{
DPTR(int) field_offsets = g_gcDacGlobals->gc_heap_field_offsets;
int field_index = 0;

#define BASE heap
#define ALL_FIELDS
#define DEFINE_FIELD(field_name, field_type) ENUM(field_name, field_type)
#define DEFINE_DPTR_FIELD(field_name, field_type) ENUM(field_name, field_type)
#define DEFINE_ARRAY_FIELD(field_name, field_type, array_length) ENUM_ARRAY(field_name, field_type, array_length)

#include "../../gc/dac_gcheap_fields.h"

#undef DEFINE_ARRAY_FIELD
#undef DEFINE_DPTR_FIELD
#undef DEFINE_FIELD
#undef ALL_FIELDS
#undef BASE
}

// Load an instance of dac_generation for the generation pointed by generation.
// Fields that does not exist in the current generation instance is zero initialized.
// Return the dac_generation object.
Expand Down Expand Up @@ -148,27 +184,62 @@ LoadGeneration(TADDR generation)
return result;
}

inline void EnumGeneration(TADDR generation)
{
DPTR(int) field_offsets = g_gcDacGlobals->generation_field_offsets;
int field_index = 0;

#define BASE generation
#define ALL_FIELDS
#define DEFINE_FIELD(field_name, field_type) ENUM(field_name, field_type)
#define DEFINE_DPTR_FIELD(field_name, field_type) ENUM(field_name, field_type)
#define DEFINE_ARRAY_FIELD(field_name, field_type, array_length) ENUM_ARRAY(field_name, field_type, array_length)

#include "../../gc/dac_generation_fields.h"

#undef DEFINE_ARRAY_FIELD
#undef DEFINE_DPTR_FIELD
#undef DEFINE_FIELD
#undef ALL_FIELDS
#undef BASE
}

// Indexes into a given generation table, returning a dac_generation
inline dac_generation
GenerationTableIndex(DPTR(unused_generation) base, size_t index)
{
return LoadGeneration(TableIndex(base, index, g_gcDacGlobals->generation_size).GetAddr());
}

// Indexes into a heap's generation table, given the heap instance
// and the desired index. Returns a dac_generation
inline dac_generation
ServerGenerationTableIndex(TADDR heap, size_t index)
inline TADDR ServerGenerationTableAddress(TADDR heap)
{
DPTR(int) field_offsets = g_gcDacGlobals->gc_heap_field_offsets;
int field_index = GENERATION_TABLE_FIELD_INDEX;
#define BASE heap
LOAD_BASE (generation_table, unused_generation);
#undef BASE
assert (generation_table_offset != -1);
return p_generation_table.GetAddr();
}

// Indexes into a heap's generation table, given the heap instance
// and the desired index. Returns a dac_generation
inline dac_generation
ServerGenerationTableIndex(TADDR heap, size_t index)
{
DPTR(unused_generation) p_generation_table = ServerGenerationTableAddress(heap);
return LoadGeneration(TableIndex(p_generation_table, index, g_gcDacGlobals->generation_size).GetAddr());
}

inline void EnumGenerationTable(TADDR generation_table)
{
DPTR(unused_generation) p_generation_table = generation_table;
for (unsigned int i = 0; i < *g_gcDacGlobals->max_gen + 2; i++)
{
EnumGeneration(TableIndex(p_generation_table, i, g_gcDacGlobals->generation_size).GetAddr());
}
}

#undef LOAD_ARRAY
#undef LOAD_DPTR
#undef LOAD
Expand Down
18 changes: 8 additions & 10 deletions src/coreclr/debug/daccess/request_svr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -252,21 +252,19 @@ ClrDataAccess::EnumSvrGlobalMemoryRegions(CLRDataEnumMemoryFlags flags)

for (int i = 0; i < heaps; i++)
{
TADDR heapAddress = 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));
EnumGcHeap(heapAddress);
TADDR generationTable = ServerGenerationTableAddress(heapAddress);
EnumGenerationTable(generationTable);
DacEnumMemoryRegion(dac_cast<TADDR>(pHeap->finalize_queue), sizeof(dac_finalize_queue));

TADDR taddrTable = dac_cast<TADDR>(pHeap) + offsetof(dac_gc_heap, generation_table);
DacEnumMemoryRegion(taddrTable, gen_table_size);

// enumerating the generations from max (which is normally gen2) to max+1 gives you
// the segment list for all the normal segements plus the large heap segment (max+1)
ULONG first = IsRegion() ? 0 : (*g_gcDacGlobals->max_gen);
// enumerating the first to max + 2 gives you
// the segment list for all the normal segments plus the pinned heap segment (max + 2)
// 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++)
for (ULONG i = first; i <= *g_gcDacGlobals->max_gen + 2; i++)
{
dac_generation generation = ServerGenerationTableIndex(heapAddress, i);
DPTR(dac_heap_segment) seg = generation.start_segment;
Expand Down

0 comments on commit 7571649

Please sign in to comment.