Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
1d370ea
Add ISOSMemoryEnum and HandleTable enum
leculver Apr 5, 2023
d6b0760
Update comment
leculver Apr 5, 2023
2b51bf6
Add GC Bookkeeping data to the dac
leculver Apr 6, 2023
08a7c69
Add assert
leculver Apr 6, 2023
f8cc6a1
Add support for free gc regions
leculver Apr 6, 2023
15ec230
Don't require card_table_element_layout
leculver Apr 6, 2023
880e428
Fix issue with naming in request
leculver Apr 7, 2023
04b0127
Remote DEFINE_MISSING_FIELD from dac
leculver Apr 7, 2023
dc1e10f
Whitespace fix
leculver Apr 7, 2023
28a193d
Break if we loop
leculver Apr 7, 2023
464d65d
Fix static_assert
leculver Apr 7, 2023
216a213
Segment fixes
leculver Apr 7, 2023
ae71dd0
Defensive coding
leculver Apr 7, 2023
ffa86c7
free_region fixes
leculver Apr 8, 2023
8afc64e
Remove hardcoding of region list
leculver Apr 8, 2023
eaae614
Fix gcc warnings
leculver Apr 8, 2023
2d57280
Remove unneeded #define
leculver Apr 8, 2023
de347e8
Add freeable_soh_segment/freeable_uoh_segment
leculver Apr 13, 2023
cec7940
Add more card table checks
leculver Apr 13, 2023
4a9c4a2
Fix field definition issue
leculver Apr 13, 2023
86c1e5a
Fix pointer issue
leculver Apr 14, 2023
33566b0
Fix compile issue
leculver Apr 14, 2023
47abfdc
Rename bookkeeping_covered_start to bookkeeping_start
cshung Apr 15, 2023
3aff855
Update src/coreclr/debug/daccess/daccess.cpp
leculver Apr 17, 2023
7974efb
Code review feedback
leculver Apr 17, 2023
05a6c2c
Remove unused parameter
leculver Apr 17, 2023
9abf2f3
Add heap number
leculver Apr 17, 2023
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
232 changes: 231 additions & 1 deletion src/coreclr/debug/daccess/daccess.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7654,7 +7654,6 @@ void DacHandleWalker::WalkHandles()
{
if (mask & 1)
{
dac_handle_table *pTable = hTable;
PTR_AppDomain pDomain = AppDomain::GetCurrentDomain();
param.AppDomain = TO_CDADDR(pDomain.GetAddr());
param.Type = handleType;
Expand Down Expand Up @@ -8285,3 +8284,234 @@ HRESULT DacStackReferenceErrorEnum::Next(unsigned int count, SOSStackRefError re
*pFetched = i;
return i < count ? S_FALSE : S_OK;
}


HRESULT DacMemoryEnumerator::Skip(unsigned int count)
{
mIteratorIndex += count;
return S_OK;
}

HRESULT DacMemoryEnumerator::Reset()
{
mIteratorIndex = 0;
return S_OK;
}

HRESULT DacMemoryEnumerator::GetCount(unsigned int* pCount)
{
if (!pCount)
return E_POINTER;

mRegions.GetCount();
return S_OK;
}

HRESULT DacMemoryEnumerator::Next(unsigned int count, SOSMemoryRegion regions[], unsigned int* pFetched)
{
if (!pFetched)
return E_POINTER;

if (!regions)
return E_POINTER;

unsigned int i = 0;
while (i < count && mIteratorIndex < mRegions.GetCount())
{
regions[i++] = mRegions.Get(mIteratorIndex++);
}

*pFetched = i;
return i < count ? S_FALSE : S_OK;
}


HRESULT DacGCBookkeepingEnumerator::Init()
{
if (g_gcDacGlobals->bookkeeping_start == nullptr)
return E_FAIL;

TADDR ctiAddr = TO_TADDR(*g_gcDacGlobals->bookkeeping_start);
if (ctiAddr == 0)
return E_FAIL;

DPTR(dac_card_table_info) card_table_info(ctiAddr);

SOSMemoryRegion mem = {0};
if (card_table_info->recount && card_table_info->size)
{
mem.Start = card_table_info.GetAddr();
mem.Size = card_table_info->size;
mRegions.Add(mem);
}

size_t card_table_info_size = g_gcDacGlobals->card_table_info_size;
TADDR next = card_table_info->next_card_table;

// Cap the number of regions we will walk in case we have run into some kind of
// memory corruption. We shouldn't have more than a few linked card tables anyway.
int maxRegions = 32;
Comment thread
leculver marked this conversation as resolved.

// This loop is effectively "while (next != 0)" but with an added check to make
// sure we don't underflow next when subtracting card_table_info_size if we encounter
// a bad pointer.
while (next > card_table_info_size)
{
DPTR(dac_card_table_info) ct(next - card_table_info_size);

if (ct->recount && ct->size)
{
mem = {0};
mem.Start = ct.GetAddr();
mem.Size = ct->size;
mRegions.Add(mem);
}

next = ct->next_card_table;
if (next == card_table_info->next_card_table)
break;

if (--maxRegions <= 0)
break;
}

return S_OK;
}


HRESULT DacHandleTableMemoryEnumerator::Init()
{
int max_slots = 1;

#ifdef FEATURE_SVR_GC
if (GCHeapUtilities::IsServerHeap())
max_slots = GCHeapCount();
#endif // FEATURE_SVR_GC

// Cap the number of regions we will walk in case we hit an infinite loop due
// to memory corruption
int maxRegions = 8192;

for (dac_handle_table_map *map = g_gcDacGlobals->handle_table_map; map && maxRegions >= 0; map = map->pNext, maxRegions--)
{
for (int i = 0; i < INITIAL_HANDLE_TABLE_ARRAY_SIZE; ++i)
{
if (map->pBuckets[i] != NULL)
{
for (int j = 0; j < max_slots ; ++j)
{
DPTR(dac_handle_table) pTable = map->pBuckets[i]->pTable[j];
DPTR(dac_handle_table_segment) pFirstSegment = pTable->pSegmentList;
DPTR(dac_handle_table_segment) curr = pFirstSegment;

do
{
SOSMemoryRegion mem = {0};
mem.Start = curr.GetAddr();
mem.Size = HANDLE_SEGMENT_SIZE;
mem.Heap = j; // heap number

mRegions.Add(mem);

curr = curr->pNextSegment;
} while (curr != nullptr && curr != pFirstSegment);
}
}
}
}

return S_OK;
}

void DacFreeRegionEnumerator::AddSingleSegment(const dac_heap_segment &curr, FreeRegionKind kind, int heap)
{
SOSMemoryRegion mem = {0};
mem.Start = TO_CDADDR(curr.mem);
Comment thread
cshung marked this conversation as resolved.
mem.ExtraData = (CLRDATA_ADDRESS)kind;
mem.Heap = heap;

if (curr.mem < curr.committed)
mem.Size = TO_CDADDR(curr.committed) - mem.Start;

if (mem.Start)
mRegions.Add(mem);
}

void DacFreeRegionEnumerator::AddSegmentList(DPTR(dac_heap_segment) start, FreeRegionKind kind, int heap)
{
int iterationMax = 2048;

DPTR(dac_heap_segment) curr = start;
while (curr != nullptr)
{
AddSingleSegment(*curr, kind, heap);

curr = curr->next;
if (curr == start)
break;

if (iterationMax-- <= 0)
break;
}
}

void DacFreeRegionEnumerator::AddFreeList(DPTR(dac_region_free_list) free_list, FreeRegionKind kind)
{
if (free_list != nullptr)
{
AddSegmentList(free_list->head_free_region, kind);
}
}

HRESULT DacFreeRegionEnumerator::Init()
{
// Cap the number of free regions we will walk at a sensible number. This is to protect against
// memory corruption, un-initialized data, or just a bug.
int count_free_region_kinds = g_gcDacGlobals->count_free_region_kinds;
count_free_region_kinds = min(count_free_region_kinds, 16);

unsigned int index = 0;
if (g_gcDacGlobals->global_free_huge_regions != nullptr)
{
DPTR(dac_region_free_list) global_free_huge_regions(g_gcDacGlobals->global_free_huge_regions);
AddFreeList(global_free_huge_regions, FreeRegionKind::FreeGlobalHugeRegion);
}

if (g_gcDacGlobals->global_regions_to_decommit != nullptr)
{
DPTR(dac_region_free_list) regionList(g_gcDacGlobals->global_regions_to_decommit);
if (regionList != nullptr)
for (int i = 0; i < count_free_region_kinds; i++, regionList++)
AddFreeList(regionList, FreeRegionKind::FreeGlobalRegion);
}

#if defined(FEATURE_SVR_GC)
if (GCHeapUtilities::IsServerHeap())
{
AddServerRegions();
}
else
#endif //FEATURE_SVR_GC
{
DPTR(dac_region_free_list) regionList(g_gcDacGlobals->free_regions);
if (regionList != nullptr)
for (int i = 0; i < count_free_region_kinds; i++, regionList++)
AddFreeList(regionList, FreeRegionKind::FreeRegion);

Comment thread
leculver marked this conversation as resolved.
if (g_gcDacGlobals->freeable_soh_segment != nullptr)
{
DPTR(DPTR(dac_heap_segment)) freeable_soh_segment_ptr(g_gcDacGlobals->freeable_soh_segment);
if (freeable_soh_segment_ptr != nullptr)
AddSegmentList(*freeable_soh_segment_ptr, FreeRegionKind::FreeSohSegment);
}

if (g_gcDacGlobals->freeable_uoh_segment != nullptr)
{
DPTR(DPTR(dac_heap_segment)) freeable_uoh_segment_ptr(g_gcDacGlobals->freeable_uoh_segment);
if (freeable_uoh_segment_ptr != nullptr)
AddSegmentList(*freeable_uoh_segment_ptr, FreeRegionKind::FreeUohSegment);
}
}

return S_OK;
}
54 changes: 54 additions & 0 deletions src/coreclr/debug/daccess/dacimpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -1211,6 +1211,10 @@ class ClrDataAccess
virtual HRESULT STDMETHODCALLTYPE GetDomainLoaderAllocator(CLRDATA_ADDRESS domainAddress, CLRDATA_ADDRESS *pLoaderAllocator);
virtual HRESULT STDMETHODCALLTYPE GetLoaderAllocatorHeapNames(int count, const char **ppNames, int *pNeeded);
virtual HRESULT STDMETHODCALLTYPE GetLoaderAllocatorHeaps(CLRDATA_ADDRESS loaderAllocator, int count, CLRDATA_ADDRESS *pLoaderHeaps, LoaderHeapKind *pKinds, int *pNeeded);
virtual HRESULT STDMETHODCALLTYPE GetHandleTableMemoryRegions(ISOSMemoryEnum **ppEnum);
virtual HRESULT STDMETHODCALLTYPE GetGCBookkeepingMemoryRegions(ISOSMemoryEnum **ppEnum);
virtual HRESULT STDMETHODCALLTYPE GetGCFreeRegions(ISOSMemoryEnum **ppEnum);
virtual HRESULT STDMETHODCALLTYPE LockedFlush();

//
// ClrDataAccess.
Expand Down Expand Up @@ -1954,6 +1958,56 @@ class DacReferenceList
unsigned int _capacity;
};


class DacMemoryEnumerator : public DefaultCOMImpl<ISOSMemoryEnum, IID_ISOSMemoryEnum>
{
public:
DacMemoryEnumerator()
: mIteratorIndex(0)
{
}

virtual ~DacMemoryEnumerator() {}
virtual HRESULT Init() = 0;

HRESULT STDMETHODCALLTYPE Skip(unsigned int count);
HRESULT STDMETHODCALLTYPE Reset();
HRESULT STDMETHODCALLTYPE GetCount(unsigned int *pCount);
HRESULT STDMETHODCALLTYPE Next(unsigned int count,
SOSMemoryRegion regions[],
unsigned int *pFetched);

protected:
DacReferenceList<SOSMemoryRegion> mRegions;

private:
unsigned int mIteratorIndex;
};

class DacHandleTableMemoryEnumerator : public DacMemoryEnumerator
{
public:
virtual HRESULT Init();
};

class DacGCBookkeepingEnumerator : public DacMemoryEnumerator
{
public:
virtual HRESULT Init();
};

class DacFreeRegionEnumerator : public DacMemoryEnumerator
{
public:
virtual HRESULT Init();

private:
void AddSingleSegment(const dac_heap_segment &seg, FreeRegionKind kind, int heap);
void AddSegmentList(DPTR(dac_heap_segment) seg, FreeRegionKind kind, int heap = 0);
void AddFreeList(DPTR(dac_region_free_list) freeList, FreeRegionKind kind);
void AddServerRegions();
};

struct DacGcReference;
/* DacStackReferenceWalker.
*/
Expand Down
Loading