summaryrefslogtreecommitdiff
path: root/src/debug/daccess/request_svr.cpp
diff options
context:
space:
mode:
authorJiyoung Yun <jy910.yun@samsung.com>2016-11-23 19:09:09 +0900
committerJiyoung Yun <jy910.yun@samsung.com>2016-11-23 19:09:09 +0900
commit4b4aad7217d3292650e77eec2cf4c198ea9c3b4b (patch)
tree98110734c91668dfdbb126fcc0e15ddbd93738ca /src/debug/daccess/request_svr.cpp
parentfa45f57ed55137c75ac870356a1b8f76c84b229c (diff)
downloadcoreclr-4b4aad7217d3292650e77eec2cf4c198ea9c3b4b.tar.gz
coreclr-4b4aad7217d3292650e77eec2cf4c198ea9c3b4b.tar.bz2
coreclr-4b4aad7217d3292650e77eec2cf4c198ea9c3b4b.zip
Imported Upstream version 1.1.0upstream/1.1.0
Diffstat (limited to 'src/debug/daccess/request_svr.cpp')
-rw-r--r--src/debug/daccess/request_svr.cpp348
1 files changed, 348 insertions, 0 deletions
diff --git a/src/debug/daccess/request_svr.cpp b/src/debug/daccess/request_svr.cpp
new file mode 100644
index 0000000000..429f30020f
--- /dev/null
+++ b/src/debug/daccess/request_svr.cpp
@@ -0,0 +1,348 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//*****************************************************************************
+
+//
+// File: request.cpp
+//
+// CorDataAccess::Request implementation.
+//
+//*****************************************************************************
+
+#include "stdafx.h"
+#include "dacdbiinterface.h"
+#include "dacdbiimpl.h"
+
+#if defined(FEATURE_SVR_GC)
+
+#include <sigformat.h>
+#include <win32threadpool.h>
+
+#include <gceesvr.cpp>
+
+
+int GCHeapCount()
+{
+ return SVR::gc_heap::n_heaps;
+}
+
+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
+ SVR::heap_segment *pHeapSegment =
+ __DPtr<SVR::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)(ULONG_PTR) pHeapSegment->heap;
+
+ return S_OK;
+}
+
+HRESULT GetServerHeaps(CLRDATA_ADDRESS pGCHeaps[], ICorDebugDataTarget * pTarget)
+{
+ // @todo Microsoft: It would be good to have an assert here to ensure pGCHeaps is large enough to
+ // hold all the addresses. Currently we check that in the only caller, but if we were to call this from
+ // somewhere else in the future, we could have a buffer overrun.
+
+ // The runtime declares its own global array of gc heap addresses for multiple heap scenarios. We need to get
+ // its starting address. This expression is a little tricky to parse, but in DAC builds, g_heaps is
+ // a DAC global (__GlobalPtr). The __GlobalPtr<...>::GetAddr() function gets the starting address of that global, but
+ // be sure to note this is a target address. We'll use this as our source for getting our local list of
+ // heap addresses.
+ TADDR ptr = SVR::gc_heap::g_heaps.GetAddr();
+ ULONG32 bytesRead = 0;
+
+ for (int i=0;i<GCHeapCount();i++)
+ {
+
+ LPVOID pGCHeapAddr;
+
+ // read the i-th element of g_heaps into pGCHeapAddr
+ // @todo Microsoft: Again, if we capture the HRESULT from ReadVirtual, we can print a more explanatory
+ // failure message.
+ if (pTarget->ReadVirtual(ptr + i*sizeof(TADDR),
+ (PBYTE) &pGCHeapAddr, sizeof(TADDR),
+ &bytesRead) != S_OK)
+ {
+ return E_FAIL;
+ }
+ if (bytesRead != sizeof(LPVOID))
+ {
+ return E_FAIL;
+ }
+
+ // store the heap's starting address in our array.
+ pGCHeaps[i] = (CLRDATA_ADDRESS)(ULONG_PTR) pGCHeapAddr;
+ }
+ return S_OK;
+}
+
+#define PTR_CDADDR(ptr) TO_CDADDR(PTR_TO_TADDR(ptr))
+#define HOST_CDADDR(host) TO_CDADDR(PTR_HOST_TO_TADDR(host))
+
+typedef DPTR(class SVR::gc_heap) PTR_SVR_gc_heap;
+
+HRESULT ClrDataAccess::GetServerAllocData(unsigned int count, struct DacpGenerationAllocData *data, unsigned int *pNeeded)
+{
+ unsigned int heaps = (unsigned int)SVR::gc_heap::n_heaps;
+ if (pNeeded)
+ *pNeeded = heaps;
+
+ if (data)
+ {
+ if (count > heaps)
+ count = heaps;
+
+ for (int n=0;n<SVR::gc_heap::n_heaps;n++)
+ {
+ PTR_SVR_gc_heap pHeap = PTR_SVR_gc_heap(SVR::gc_heap::g_heaps[n]);
+ for (int i=0;i<NUMBERGENERATIONS;i++)
+ {
+ data[n].allocData[i].allocBytes = (CLRDATA_ADDRESS)(ULONG_PTR) pHeap->generation_table[i].allocation_context.alloc_bytes;
+ data[n].allocData[i].allocBytesLoh = (CLRDATA_ADDRESS)(ULONG_PTR) pHeap->generation_table[i].allocation_context.alloc_bytes_loh;
+ }
+ }
+ }
+
+ return S_OK;
+}
+
+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;
+
+ //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)(ULONG_PTR) pHeap->alloc_allocated;
+ detailsData->ephemeral_heap_segment = (CLRDATA_ADDRESS)(ULONG_PTR) pHeap->ephemeral_heap_segment;
+
+ // get bounds for the different generations
+ for (i=0; i<NUMBERGENERATIONS; i++)
+ {
+ detailsData->generation_table[i].start_segment = (CLRDATA_ADDRESS)dac_cast<TADDR>(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;
+ }
+
+ // since these are all TADDRS, we have to compute the address of the m_FillPointers field explicitly
+ TADDR pFillPointerArray = dac_cast<TADDR>(pHeap->finalize_queue) + offsetof(SVR::CFinalize,m_FillPointers);
+
+ for(i=0; i<(NUMBERGENERATIONS+SVR::CFinalize::ExtraSegCount); i++)
+ {
+ ULONG32 returned = 0;
+ size_t pValue;
+ HRESULT hr = m_pTarget->ReadVirtual(pFillPointerArray+(i*sizeof(TADDR)),
+ (PBYTE)&pValue,
+ sizeof(TADDR),
+ &returned);
+ if (FAILED(hr) || (returned != sizeof(TADDR)))
+ {
+ return E_FAIL;
+ }
+
+ detailsData->finalization_fill_pointers[i] = (CLRDATA_ADDRESS) pValue;
+ }
+
+ return S_OK;
+}
+
+HRESULT
+ClrDataAccess::ServerOomData(CLRDATA_ADDRESS addr, DacpOomData *oomData)
+{
+ SVR::gc_heap *pHeap = PTR_SVR_gc_heap(TO_TADDR(addr));
+
+ oom_history* pOOMInfo = (oom_history*)((TADDR)pHeap + offsetof(SVR::gc_heap,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::ServerGCInterestingInfoData(CLRDATA_ADDRESS addr, DacpGCInterestingInfoData *interestingInfoData)
+{
+#ifdef GC_CONFIG_DRIVEN
+ SVR::gc_heap *pHeap = PTR_SVR_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
+}
+
+HRESULT ClrDataAccess::ServerGCHeapAnalyzeData(CLRDATA_ADDRESS heapAddr, DacpGcHeapAnalyzeData *analyzeData)
+{
+ if (!heapAddr)
+ {
+ // PREfix.
+ return E_INVALIDARG;
+ }
+
+ SVR::gc_heap *pHeap = PTR_SVR_gc_heap(TO_TADDR(heapAddr));
+
+ analyzeData->heapAddr = heapAddr;
+ analyzeData->internal_root_array = (CLRDATA_ADDRESS)(ULONG_PTR) 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
+ClrDataAccess::EnumSvrGlobalMemoryRegions(CLRDataEnumMemoryFlags flags)
+{
+ SUPPORTS_DAC;
+ SVR::gc_heap::n_heaps.EnumMem();
+ DacEnumMemoryRegion(SVR::gc_heap::g_heaps.GetAddr(),
+ sizeof(TADDR) * SVR::gc_heap::n_heaps);
+
+ SVR::gc_heap::g_heaps.EnumMem();
+
+ for (int i=0;i<SVR::gc_heap::n_heaps;i++)
+ {
+ PTR_SVR_gc_heap pHeap = PTR_SVR_gc_heap(SVR::gc_heap::g_heaps[i]);
+
+ DacEnumMemoryRegion(dac_cast<TADDR>(pHeap), sizeof(SVR::gc_heap));
+ DacEnumMemoryRegion(dac_cast<TADDR>(pHeap->finalize_queue), sizeof(SVR::CFinalize));
+
+ // 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 = GCHeap::GetMaxGeneration(); i <= GCHeap::GetMaxGeneration()+1; i++)
+ {
+ __DPtr<SVR::heap_segment> seg = dac_cast<TADDR>(pHeap->generation_table[i].start_segment);
+ while (seg)
+ {
+ DacEnumMemoryRegion(PTR_HOST_TO_TADDR(seg), sizeof(SVR::heap_segment));
+
+ seg = __DPtr<SVR::heap_segment>(dac_cast<TADDR>(seg->next));
+ }
+ }
+ }
+}
+
+DWORD DacGetNumHeaps()
+{
+ if (GCHeap::IsServerHeap())
+ return (DWORD)SVR::gc_heap::n_heaps;
+
+ // workstation gc
+ return 1;
+}
+
+HRESULT DacHeapWalker::InitHeapDataSvr(HeapData *&pHeaps, size_t &pCount)
+{
+ // Scrape basic heap details
+ int heaps = SVR::gc_heap::n_heaps;
+ pCount = heaps;
+ pHeaps = new (nothrow) HeapData[heaps];
+ if (pHeaps == NULL)
+ return E_OUTOFMEMORY;
+
+ for (int i = 0; i < heaps; ++i)
+ {
+ // Basic heap info.
+ PTR_SVR_gc_heap heap = PTR_SVR_gc_heap(SVR::gc_heap::g_heaps[i]);
+
+ pHeaps[i].YoungestGenPtr = (CORDB_ADDRESS)heap->generation_table[0].allocation_context.alloc_ptr;
+ pHeaps[i].YoungestGenLimit = (CORDB_ADDRESS)heap->generation_table[0].allocation_context.alloc_limit;
+
+ pHeaps[i].Gen0Start = (CORDB_ADDRESS)heap->generation_table[0].allocation_start;
+ pHeaps[i].Gen0End = (CORDB_ADDRESS)heap->alloc_allocated;
+ pHeaps[i].Gen1Start = (CORDB_ADDRESS)heap->generation_table[1].allocation_start;
+
+ // Segments
+ int count = GetSegmentCount(heap->generation_table[NUMBERGENERATIONS-1].start_segment);
+ count += GetSegmentCount(heap->generation_table[NUMBERGENERATIONS-2].start_segment);
+
+ pHeaps[i].SegmentCount = count;
+ pHeaps[i].Segments = new (nothrow) SegmentData[count];
+ if (pHeaps[i].Segments == NULL)
+ return E_OUTOFMEMORY;
+
+ // Small object heap segments
+ SVR::PTR_heap_segment seg = heap->generation_table[NUMBERGENERATIONS-2].start_segment;
+ int j = 0;
+ for (; seg && (j < count); ++j)
+ {
+ pHeaps[i].Segments[j].Start = (CORDB_ADDRESS)seg->mem;
+ if (seg.GetAddr() == TO_TADDR(heap->ephemeral_heap_segment))
+ {
+ pHeaps[i].Segments[j].End = (CORDB_ADDRESS)heap->alloc_allocated;
+ pHeaps[i].EphemeralSegment = j;
+ pHeaps[i].Segments[j].Generation = 1;
+ }
+ else
+ {
+ pHeaps[i].Segments[j].End = (CORDB_ADDRESS)seg->allocated;
+ pHeaps[i].Segments[j].Generation = 2;
+ }
+
+ seg = seg->next;
+ }
+
+
+ // Large object heap segments
+ seg = heap->generation_table[NUMBERGENERATIONS-1].start_segment;
+ for (; seg && (j < count); ++j)
+ {
+ pHeaps[i].Segments[j].Generation = 3;
+ pHeaps[i].Segments[j].Start = (CORDB_ADDRESS)seg->mem;
+ pHeaps[i].Segments[j].End = (CORDB_ADDRESS)seg->allocated;
+
+ seg = seg->next;
+ }
+ }
+
+ return S_OK;
+}
+
+#endif // defined(FEATURE_SVR_GC)