Skip to content

Commit

Permalink
Add support for ISOSDacInterface15 - MethodTable enumeration api (#4767)
Browse files Browse the repository at this point in the history
- Support iterating methods from the new ISOSDacInterface15
- Re-plumb the existing logic as a local implementation of
ISOSDacInterface15 on top of apis that have been present for a long time

This is dependent on dotnet/runtime#101580
  • Loading branch information
davidwrighton authored Jul 17, 2024
1 parent 2654bbe commit 43dfee3
Show file tree
Hide file tree
Showing 6 changed files with 501 additions and 44 deletions.
110 changes: 66 additions & 44 deletions src/SOS/Strike/strike.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1239,72 +1239,94 @@ DECLARE_API(DumpMT)

if (bDumpMDTable)
{
table.ReInit(4, POINTERSIZE_HEX, AlignRight);
table.ReInit(5, POINTERSIZE_HEX, AlignRight);
table.SetColAlignment(3, AlignLeft);
table.SetColWidth(2, 6);

Print("--------------------------------------\n");
Print("MethodDesc Table\n");

table.WriteRow("Entry", "MethodDesc", "JIT", "Name");
table.WriteRow("Entry", "MethodDesc", "JIT", "Slot", "Name");

for (DWORD n = 0; n < vMethTable.wNumMethods; n++)
ISOSMethodEnum *pMethodEnumerator;
if (SUCCEEDED(g_sos15->GetMethodTableSlotEnumerator(dwStartAddr, &pMethodEnumerator)))
{
JITTypes jitType;
DWORD_PTR methodDesc=0;
DWORD_PTR gcinfoAddr;

CLRDATA_ADDRESS entry;
if (g_sos->GetMethodTableSlot(dwStartAddr, n, &entry) != S_OK)
SOSMethodData entry;
unsigned int fetched;
while (SUCCEEDED(pMethodEnumerator->Next(1, &entry, &fetched)) && fetched != 0)
{
PrintLn("<error getting slot ", Decimal(n), ">");
continue;
}
JITTypes jitType = TYPE_UNKNOWN;
DWORD_PTR methodDesc = (DWORD_PTR)entry.MethodDesc;
DWORD_PTR methodDescFromIP2MD = 0;
DWORD_PTR gcinfoAddr = 0;

if (entry.Entrypoint != 0)
{
IP2MethodDesc((DWORD_PTR)entry.Entrypoint, methodDescFromIP2MD, jitType, gcinfoAddr);
if ((methodDescFromIP2MD != methodDesc) && methodDesc != 0)
{
ExtOut("MethodDesc from IP2MD does not match MethodDesc from enumerator\n");
}
}

IP2MethodDesc((DWORD_PTR)entry, methodDesc, jitType, gcinfoAddr);
table.WriteColumn(0, entry);
table.WriteColumn(1, MethodDescPtr(methodDesc));
table.WriteColumn(0, entry.Entrypoint);
table.WriteColumn(1, MethodDescPtr(methodDesc));

if (jitType == TYPE_UNKNOWN && methodDesc != (TADDR)0)
{
// We can get a more accurate jitType from NativeCodeAddr of the methoddesc,
// because the methodtable entry hasn't always been patched.
DacpMethodDescData tmpMethodDescData;
if (tmpMethodDescData.Request(g_sos, TO_CDADDR(methodDesc)) == S_OK)
if (jitType == TYPE_UNKNOWN && methodDesc != (TADDR)0)
{
DacpCodeHeaderData codeHeaderData;
if (codeHeaderData.Request(g_sos,tmpMethodDescData.NativeCodeAddr) == S_OK)
// We can get a more accurate jitType from NativeCodeAddr of the methoddesc,
// because the methodtable entry hasn't always been patched.
DacpMethodDescData tmpMethodDescData;
if (tmpMethodDescData.Request(g_sos, TO_CDADDR(methodDesc)) == S_OK)
{
jitType = (JITTypes) codeHeaderData.JITType;
DacpCodeHeaderData codeHeaderData;
if (codeHeaderData.Request(g_sos,tmpMethodDescData.NativeCodeAddr) == S_OK)
{
jitType = (JITTypes) codeHeaderData.JITType;
}
}
}
}

const char *pszJitType = "NONE";
if (jitType == TYPE_JIT)
pszJitType = "JIT";
else if (jitType == TYPE_PJIT)
pszJitType = "PreJIT";
else
{
DacpMethodDescData MethodDescData;
if (MethodDescData.Request(g_sos, TO_CDADDR(methodDesc)) == S_OK)
const char *pszJitType = "NONE";
if (jitType == TYPE_JIT)
pszJitType = "JIT";
else if (jitType == TYPE_PJIT)
pszJitType = "PreJIT";
else
{
// Is it an fcall?
ULONG64 baseAddress = g_pRuntime->GetModuleAddress();
ULONG64 size = g_pRuntime->GetModuleSize();
if ((TO_TADDR(MethodDescData.NativeCodeAddr) >= TO_TADDR(baseAddress)) &&
((TO_TADDR(MethodDescData.NativeCodeAddr) < TO_TADDR(baseAddress + size))))
DacpMethodDescData MethodDescData;
if (MethodDescData.Request(g_sos, TO_CDADDR(methodDesc)) == S_OK)
{
pszJitType = "FCALL";
// Is it an fcall?
ULONG64 baseAddress = g_pRuntime->GetModuleAddress();
ULONG64 size = g_pRuntime->GetModuleSize();
if ((TO_TADDR(MethodDescData.NativeCodeAddr) >= TO_TADDR(baseAddress)) &&
((TO_TADDR(MethodDescData.NativeCodeAddr) < TO_TADDR(baseAddress + size))))
{
pszJitType = "FCALL";
}
}
}
}

table.WriteColumn(2, pszJitType);
table.WriteColumn(2, pszJitType);
table.WriteColumn(3, entry.Slot);

NameForMD_s(methodDesc,g_mdName,mdNameLen);
table.WriteColumn(3, g_mdName);
if (methodDesc != 0)
NameForMD_s(methodDesc,g_mdName,mdNameLen);
else
{
DacpModuleData moduleData;
if(moduleData.Request(g_sos, entry.DefiningModule)==S_OK)
{
NameForToken_s(&moduleData, entry.Token, g_mdName, mdNameLen, true);
}
else
{
_snwprintf_s(g_mdName, mdNameLen, _TRUNCATE, W("Unknown Module!%08x"), entry.Token);
}
}
table.WriteColumn(4, g_mdName);
}
}
}
return Status;
Expand Down
156 changes: 156 additions & 0 deletions src/SOS/Strike/util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ const char * const CorElementTypeNamespace[ELEMENT_TYPE_MAX]=

IXCLRDataProcess *g_clrData = NULL;
ISOSDacInterface *g_sos = NULL;
ISOSDacInterface15 *g_sos15 = NULL;

#ifndef IfFailRet
#define IfFailRet(EXPR) do { Status = (EXPR); if(FAILED(Status)) { return (Status); } } while (0)
Expand Down Expand Up @@ -3930,6 +3931,154 @@ void ResetGlobals(void)
Output::ResetIndent();
}

class SOSDacInterface15Simulator : public ISOSDacInterface15
{
class SOSMethodEnum : public ISOSMethodEnum
{
CLRDATA_ADDRESS pMT;
unsigned int index;
unsigned int slotCount;
ULONG refCount;
public:
SOSMethodEnum(CLRDATA_ADDRESS mt) : pMT(mt), refCount(1)
{
}

virtual ~SOSMethodEnum() {}

virtual HRESULT STDMETHODCALLTYPE Reset()
{
index = 0;
DacpMethodTableData vMethTable;
HRESULT hr = vMethTable.Request(g_sos, pMT);
if (FAILED(hr))
return hr;

slotCount = vMethTable.wNumMethods;
return S_OK;
}

virtual HRESULT STDMETHODCALLTYPE GetCount(unsigned int *pc)
{
*pc = slotCount;
return S_OK;
}

virtual HRESULT STDMETHODCALLTYPE Skip(unsigned int skipCount)
{
index += skipCount;
return S_OK;
}

virtual HRESULT STDMETHODCALLTYPE Next(
/* [in] */ unsigned int count,
/* [length_is][size_is][out] */ SOSMethodData methods[ ],
/* [out] */ unsigned int *pFetched)
{
if (!pFetched)
return E_POINTER;

if (!methods)
return E_POINTER;

unsigned int i = 0;
while (i < count && index < slotCount)
{
SOSMethodData methodData = { 0 };

JITTypes jitType;
DWORD_PTR methodDesc=0;
DWORD_PTR gcinfoAddr;

CLRDATA_ADDRESS entry;
methodData.Slot = index;
HRESULT hr = g_sos->GetMethodTableSlot(pMT, index++, &entry);
if (hr != S_OK)
{
PrintLn("<error getting slot ", Decimal(index - 1), ">");
continue;
}

IP2MethodDesc((DWORD_PTR)entry, methodDesc, jitType, gcinfoAddr);

methodData.MethodDesc = methodDesc;
methodData.Entrypoint = entry;

methods[i++] = methodData;
}

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

STDMETHOD_(ULONG, AddRef)() { return ++refCount; }
STDMETHOD_(ULONG, Release)()
{
--refCount;
if (refCount == 0)
{
delete this;
return 0;
}
return refCount;
}

STDMETHOD(QueryInterface)(
THIS_
___in REFIID InterfaceId,
___out PVOID* Interface
)
{
if (InterfaceId == IID_IUnknown ||
InterfaceId == IID_ISOSMethodEnum)
{
*Interface = (ISOSMethodEnum*)this;
AddRef();
return S_OK;
}
*Interface = NULL;
return E_NOINTERFACE;
}
};

public:
STDMETHOD_(ULONG, AddRef)() { return 1; };
STDMETHOD_(ULONG, Release)() { return 1; };
STDMETHOD(QueryInterface)(
THIS_
___in REFIID InterfaceId,
___out PVOID* Interface
)
{
if (InterfaceId == IID_IUnknown ||
InterfaceId == IID_ISOSDacInterface15)
{
*Interface = (ISOSDacInterface15*)this;
return S_OK;
}
*Interface = NULL;
return E_NOINTERFACE;
}

virtual HRESULT STDMETHODCALLTYPE GetMethodTableSlotEnumerator(
CLRDATA_ADDRESS mt,
ISOSMethodEnum **enumerator)
{
SOSMethodEnum *simulator = new(std::nothrow) SOSMethodEnum(mt);
*enumerator = simulator;
if (simulator == NULL)
{
return E_OUTOFMEMORY;
}
HRESULT hr = simulator->Reset();
if (FAILED(hr))
{
simulator->Release();
}
return hr;
}
} SOSDacInterface15Simulator_Instance;

//---------------------------------------------------------------------------------------
//
// Loads private DAC interface, and points g_clrData to it.
Expand Down Expand Up @@ -3960,6 +4109,13 @@ HRESULT LoadClrDebugDll(void)
g_sos = NULL;
return hr;
}

// Always have an instance of the MethodTable enumerator
hr = g_clrData->QueryInterface(__uuidof(ISOSDacInterface15), (void**)&g_sos15);
if (FAILED(hr))
{
g_sos15 = &SOSDacInterface15Simulator_Instance;
}
return S_OK;
}

Expand Down
1 change: 1 addition & 0 deletions src/SOS/Strike/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ enum EEFLAVOR {UNKNOWNEE, MSCOREE, MSCORWKS, MSCOREND};
#include "sospriv.h"
extern IXCLRDataProcess *g_clrData;
extern ISOSDacInterface *g_sos;
extern ISOSDacInterface15 *g_sos15;

#include "dacprivate.h"

Expand Down
43 changes: 43 additions & 0 deletions src/shared/inc/sospriv.idl
Original file line number Diff line number Diff line change
Expand Up @@ -519,3 +519,46 @@ interface ISOSDacInterface14 : IUnknown
HRESULT GetThreadStaticBaseAddress(CLRDATA_ADDRESS methodTable, CLRDATA_ADDRESS thread, CLRDATA_ADDRESS *nonGCStaticsAddress, CLRDATA_ADDRESS *GCStaticsAddress);
HRESULT GetMethodTableInitializationFlags(CLRDATA_ADDRESS methodTable, MethodTableInitializationFlags *initializationStatus);
}

cpp_quote("#ifndef _SOS_MethodData")
cpp_quote("#define _SOS_MethodData")

typedef struct _SOSMethodData
{
// At least one of MethodDesc, Entrypoint, or Token/DefiningMethodTable/DefiningModule is guaranteed to be set.
// Multiple of them may be set as well
CLRDATA_ADDRESS MethodDesc;

CLRDATA_ADDRESS Entrypoint;

CLRDATA_ADDRESS DefininingMethodTable; // Useful for when the method is inherited from a parent type which is instantiated
CLRDATA_ADDRESS DefiningModule;
unsigned int Token;

// Slot data, a given MethodDesc may be present in multiple slots for a single MethodTable
unsigned int Slot; // Will be set to 0xFFFFFFFF for EnC added methods
} SOSMethodData;

cpp_quote("#endif //_SOS_MethodData")

[
object,
local,
uuid(3c0fe725-c324-4a4f-8100-d399588a662e)
]
interface ISOSMethodEnum : ISOSEnum
{
HRESULT Next([in] unsigned int count,
[out, size_is(count), length_is(*pNeeded)] SOSMethodData handles[],
[out] unsigned int *pNeeded);
}

[
object,
local,
uuid(7ed81261-52a9-4a23-a358-c3313dea30a8)
]
interface ISOSDacInterface15 : IUnknown
{
HRESULT GetMethodTableSlotEnumerator(CLRDATA_ADDRESS mt, ISOSMethodEnum **enumerator);
}
6 changes: 6 additions & 0 deletions src/shared/pal/prebuilt/idl/sospriv_i.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,12 @@ MIDL_DEFINE_GUID(IID, IID_ISOSDacInterface13,0x3176a8ed,0x597b,0x4f54,0xa7,0x1f,

MIDL_DEFINE_GUID(IID, IID_ISOSDacInterface14,0x9aa22aca,0x6dc6,0x4a0c,0xb4,0xe0,0x70,0xd2,0x41,0x6b,0x98,0x37);


MIDL_DEFINE_GUID(IID, IID_ISOSMethodEnum,0x3c0fe725,0xc324,0x4a4f,0x81,0x00,0xd3,0x99,0x58,0x8a,0x66,0x2e);


MIDL_DEFINE_GUID(IID, IID_ISOSDacInterface15,0x7ed81261,0x52a9,0x4a23,0xa3,0x58,0xc3,0x31,0x3d,0xea,0x30,0xa8);

#undef MIDL_DEFINE_GUID

#ifdef __cplusplus
Expand Down
Loading

0 comments on commit 43dfee3

Please sign in to comment.