From: Neeraj Date: Wed, 25 Sep 2019 03:50:50 +0000 (+0530) Subject: Complete the !u -il SOS command X-Git-Tag: submit/tizen/20200402.013218~14^2^2~46 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=6c4dbb395a23427805c431335bfc9d39ecc4b3bd;p=platform%2Fcore%2Fdotnet%2Fdiagnostics.git Complete the !u -il SOS command --- diff --git a/src/SOS/Strike/disasm.h b/src/SOS/Strike/disasm.h index 2dfc8d6b2..cec59b5a6 100644 --- a/src/SOS/Strike/disasm.h +++ b/src/SOS/Strike/disasm.h @@ -150,7 +150,8 @@ public: GCEncodingInfo * pGCEncodingInfo, SOSEHInfo *pEHInfo, BOOL bSuppressLines, - BOOL bDisplayOffsets) const; + BOOL bDisplayOffsets, + std::function displayIL) const; virtual void IsReturnAddress( TADDR retAddr, TADDR* whereCalled) const; @@ -215,7 +216,8 @@ public: GCEncodingInfo *pGCEncodingInfo, SOSEHInfo *pEHInfo, BOOL bSuppressLines, - BOOL bDisplayOffsets) const; + BOOL bDisplayOffsets, + std::function displayIL) const; virtual void IsReturnAddress( TADDR retAddr, TADDR* whereCalled) const; @@ -282,7 +284,8 @@ public: GCEncodingInfo *pGCEncodingInfo, SOSEHInfo *pEHInfo, BOOL bSuppressLines, - BOOL bDisplayOffsets) const; + BOOL bDisplayOffsets, + std::function displayIL) const; virtual void IsReturnAddress( TADDR retAddr, @@ -348,7 +351,8 @@ public: GCEncodingInfo *pGCEncodingInfo, SOSEHInfo *pEHInfo, BOOL bSuppressLines, - BOOL bDisplayOffsets) const; + BOOL bDisplayOffsets, + std::function displayIL) const; virtual void IsReturnAddress( TADDR retAddr, TADDR* whereCalled) const; diff --git a/src/SOS/Strike/disasmARM.cpp b/src/SOS/Strike/disasmARM.cpp index 1cb5c0ed1..86e40e5a4 100644 --- a/src/SOS/Strike/disasmARM.cpp +++ b/src/SOS/Strike/disasmARM.cpp @@ -355,7 +355,8 @@ void ARMMachine::Unassembly ( GCEncodingInfo *pGCEncodingInfo, SOSEHInfo *pEHInfo, BOOL bSuppressLines, - BOOL bDisplayOffsets) const + BOOL bDisplayOffsets, + std::function displayIL) const { ULONG_PTR PC = PCBegin; char line[1024]; @@ -366,6 +367,8 @@ void ARMMachine::Unassembly ( ULONG curLine = -1; WCHAR filename[MAX_LONGPATH]; ULONG linenum; + ULONG ilPosition = 0; + UINT ilIndentCount = 0; while (PC < PCEnd) { @@ -382,6 +385,7 @@ void ARMMachine::Unassembly ( ExtOut("\n%S @ %d:\n", filename, linenum); } } + displayIL(&ilPosition, &ilIndentCount, (BYTE*)PC); // // Print out any GC information corresponding to the current instruction offset. diff --git a/src/SOS/Strike/disasmARM64.cpp b/src/SOS/Strike/disasmARM64.cpp index 499eab9be..f099e3de4 100644 --- a/src/SOS/Strike/disasmARM64.cpp +++ b/src/SOS/Strike/disasmARM64.cpp @@ -149,7 +149,8 @@ void ARM64Machine::Unassembly ( GCEncodingInfo *pGCEncodingInfo, SOSEHInfo *pEHInfo, BOOL bSuppressLines, - BOOL bDisplayOffsets) const + BOOL bDisplayOffsets, + std::function displayIL) const { TADDR PC = PCBegin; char line[1024]; @@ -161,6 +162,8 @@ void ARM64Machine::Unassembly ( BOOL loBitsSet = FALSE; BOOL hiBitsSet = FALSE; char *szConstant = NULL; + ULONG ilPosition = 0; + UINT ilIndentCount = 0; while(PC < PCEnd) @@ -209,6 +212,7 @@ void ARM64Machine::Unassembly ( ExtOut("\n%S @ %d:\n", fileName, lineNum); } } + displayIL(&ilPosition, &ilIndentCount, (BYTE*)PC); // // Print out any GC information corresponding to the current instruction offset. diff --git a/src/SOS/Strike/disasmX86.cpp b/src/SOS/Strike/disasmX86.cpp index afc01a722..d2b1fda8d 100644 --- a/src/SOS/Strike/disasmX86.cpp +++ b/src/SOS/Strike/disasmX86.cpp @@ -510,7 +510,8 @@ void GCEncodingInfo *pGCEncodingInfo, SOSEHInfo *pEHInfo, BOOL bSuppressLines, - BOOL bDisplayOffsets) const + BOOL bDisplayOffsets, + std::function displayIL) const { ULONG_PTR IP = IPBegin; char line[1024]; @@ -524,6 +525,8 @@ void ULONG curLine = -1; WCHAR filename[MAX_LONGPATH]; ULONG linenum; + ULONG ilPosition = 0; + UINT ilIndentCount = 0; while (IP < IPEnd) { @@ -540,6 +543,7 @@ void ExtOut("\n%S @ %d:\n", filename, linenum); } } + displayIL(&ilPosition, &ilIndentCount, (BYTE*)IP); // // Print out any GC information corresponding to the current instruction offset. diff --git a/src/SOS/Strike/exts.h b/src/SOS/Strike/exts.h index 61b29e148..606078309 100644 --- a/src/SOS/Strike/exts.h +++ b/src/SOS/Strike/exts.h @@ -28,6 +28,7 @@ #include #include #include +#include // wdbgexts.h defines StackTrace which interferes with other parts of the // system that use the StackTrace identifier @@ -351,7 +352,8 @@ public: GCEncodingInfo *pGCEncodingInfo, SOSEHInfo *pEHInfo, BOOL bSuppressLines, - BOOL bDisplayOffsets) const = 0; + BOOL bDisplayOffsets, + std::function displayIL) const = 0; // Validates whether retAddr represents a return address by unassembling backwards. // If the instruction before retAddr represents a target-specific call instruction diff --git a/src/SOS/Strike/sildasm.cpp b/src/SOS/Strike/sildasm.cpp index d0d32eeb1..e8b93ff39 100644 --- a/src/SOS/Strike/sildasm.cpp +++ b/src/SOS/Strike/sildasm.cpp @@ -36,6 +36,10 @@ #include "corhlpr.h" #include "corhlpr.cpp" +#include "sildasm.h" + +#include + ////////////////////////////////////////////////////////////////////////////////////////////////////////// #undef printf #define printf ExtOut @@ -64,24 +68,21 @@ static OpCode opcodes[] = #include "opcode.def" }; -static ULONG position = 0; -static BYTE *pBuffer = NULL; - // The UNALIGNED is because on IA64 alignment rules would prevent // us from reading a pointer from an unaligned source. template -T readData ( ) { +T ReadData (const BYTE* const pBuffer, ULONG& position) { T val = *((T UNALIGNED*)(pBuffer+position)); position += sizeof(T); return val; } -unsigned int readOpcode() +unsigned int ReadOpcode(const BYTE* const pBuffer, ULONG& position) { - unsigned int c = readData(); + unsigned int c = ReadData(pBuffer, /* byref */position); if (c == 0xFE) { - c = readData(); + c = ReadData(pBuffer, /* byref */ position); c |= 0x100; } return c; @@ -281,22 +282,22 @@ void DisassembleToken(IMetaDataImport *i, ULONG cLen; WCHAR szName[50]; - if(TypeFromToken(cr) == mdtTypeRef) + if (TypeFromToken(cr) == mdtTypeRef) { if (FAILED(i->GetTypeRefProps(cr, NULL, szName, 50, &cLen))) { StringCchCopyW(szName, COUNTOF(szName), W("")); } } - else if(TypeFromToken(cr) == mdtTypeDef) + else if (TypeFromToken(cr) == mdtTypeDef) { if (FAILED(i->GetTypeDefProps(cr, szName, 49, &cLen, - NULL, NULL))) + NULL, NULL))) { StringCchCopyW(szName, COUNTOF(szName), W("")); } } - else if(TypeFromToken(cr) == mdtTypeSpec) + else if (TypeFromToken(cr) == mdtTypeSpec) { CQuickBytes out; ULONG cSig; @@ -308,18 +309,45 @@ void DisassembleToken(IMetaDataImport *i, else { PrettyPrintType(sig, &out, i); - MultiByteToWideChar (CP_ACP, 0, asString(&out), -1, szName, 50); + MultiByteToWideChar(CP_ACP, 0, asString(&out), -1, szName, 50); } } else { StringCchCopyW(szName, COUNTOF(szName), W("")); } - + printf("%S::%S", szName, pMemberName); methodPrettyPrinter.HandleArguments(); // Safe to call in all cases if HandleReturnType hasn't been called. Will do nothing. } break; + + case mdtString: + { + ULONG numChars; + WCHAR str[84]; + + if (i->GetUserString((mdString)token, str, 80, &numChars) == S_OK) + { + if (numChars < 80) + str[numChars] = 0; + wcscpy_s(&str[79], 4, W("...")); + WCHAR* ptr = str; + while (*ptr != 0) { + if (*ptr < 0x20 || *ptr >= 0x80) { + *ptr = '.'; + } + ptr++; + } + + printf("\"%S\"", str); + } + else + { + printf("STRING %x", token); + } + } + break; } } @@ -368,160 +396,151 @@ HRESULT DecodeILFromAddress(IMetaDataImport *pImport, TADDR ilAddr) return Status; } - + void DecodeIL(IMetaDataImport *pImport, BYTE *buffer, ULONG bufSize) { // First decode the header COR_ILMETHOD *pHeader = (COR_ILMETHOD *) buffer; COR_ILMETHOD_DECODER header(pHeader); - // Set globals - position = 0; - pBuffer = (BYTE *) header.Code; + ULONG position = 0; + BYTE* pBuffer = const_cast(header.Code); UINT indentCount = 0; ULONG endCodePosition = header.GetCodeSize(); - while(position < endCodePosition) - { - for (unsigned e=0;eEHClause(e,&ehBuff); - if (ehInfo->TryOffset == position) - { - printf ("%*s.try\n%*s{\n", indentCount, "", indentCount, ""); - indentCount+=2; - } - else if ((ehInfo->TryOffset + ehInfo->TryLength) == position) - { - indentCount-=2; - printf("%*s} // end .try\n", indentCount, ""); - } - if (ehInfo->HandlerOffset == position) - { - if (ehInfo->Flags == COR_ILEXCEPTION_CLAUSE_FINALLY) - printf("%*s.finally\n%*s{\n", indentCount, "", indentCount, ""); - else - printf("%*s.catch\n%*s{\n", indentCount, "", indentCount, ""); + while (position < endCodePosition) + { + std::tuple r = DecodeILAtPosition( + pImport, pBuffer, bufSize, + position, indentCount, header); + position = std::get<0>(r); + indentCount = std::get<1>(r); + printf("\n"); + } +} - indentCount+=2; - } - else if ((ehInfo->HandlerOffset + ehInfo->HandlerLength) == position) - { - indentCount-=2; - - if (ehInfo->Flags == COR_ILEXCEPTION_CLAUSE_FINALLY) - printf("%*s} // end .finally\n", indentCount, ""); - else - printf("%*s} // end .catch\n", indentCount, ""); - } - } - - printf("%*sIL_%04x: ", indentCount, "", position); - unsigned int c = readOpcode(); - OpCode opcode = opcodes[c]; - printf("%s ", opcode.name); +std::tuple DecodeILAtPosition( + IMetaDataImport *pImport, BYTE *pBuffer, ULONG bufSize, + ULONG position, UINT indentCount, COR_ILMETHOD_DECODER& header) +{ + for (unsigned e=0;e()); break; - case InlineVar: - printf("VAR OR ARG %d",readData()); break; - case InlineI: - printf("%d",readData()); - break; - case InlineR: - printf("%f",readData()); - break; - case InlineBrTarget: - printf("IL_%04x",readData() + position); break; - case ShortInlineBrTarget: - printf("IL_%04x",readData() + position); break; - case InlineI8: - printf("%ld", readData<__int64>()); break; - - case InlineMethod: - case InlineField: - case InlineType: - case InlineTok: - case InlineSig: + ehInfo = header.EH->EHClause(e,&ehBuff); + if (ehInfo->TryOffset == position) { - LONG l = readData(); - if (pImport != NULL) - { - DisassembleToken(pImport, l); - } - else - { - printf("TOKEN %x", l); - } - break; + printf ("%*s.try\n%*s{\n", indentCount, "", indentCount, ""); + indentCount+=2; } - - case InlineString: + else if ((ehInfo->TryOffset + ehInfo->TryLength) == position) { - LONG l = readData(); + indentCount-=2; + printf("%*s} // end .try\n", indentCount, ""); + } - ULONG numChars; - WCHAR str[84]; + if (ehInfo->HandlerOffset == position) + { + if (ehInfo->Flags == COR_ILEXCEPTION_CLAUSE_FINALLY) + printf("%*s.finally\n%*s{\n", indentCount, "", indentCount, ""); + else + printf("%*s.catch\n%*s{\n", indentCount, "", indentCount, ""); - if ((pImport != NULL) && (pImport->GetUserString((mdString) l, str, 80, &numChars) == S_OK)) - { - if (numChars < 80) - str[numChars] = 0; - wcscpy_s(&str[79], 4, W("...")); - WCHAR* ptr = str; - while(*ptr != 0) { - if (*ptr < 0x20 || * ptr >= 0x80) { - *ptr = '.'; - } - ptr++; - } + indentCount+=2; + } + else if ((ehInfo->HandlerOffset + ehInfo->HandlerLength) == position) + { + indentCount-=2; - printf("\"%S\"", str); - } + if (ehInfo->Flags == COR_ILEXCEPTION_CLAUSE_FINALLY) + printf("%*s} // end .finally\n", indentCount, ""); else - { - printf("STRING %x", l); - } - break; + printf("%*s} // end .catch\n", indentCount, ""); } - - case InlineSwitch: + } + std::function func = [&pImport](DWORD l) { + if (pImport != NULL) { - LONG cases = readData(); - LONG *pArray = new LONG[cases]; - LONG i=0; - for(i=0;i(); - } - printf("("); - for(i=0;i()); break; - case ShortInlineR: - printf("%f", readData()); break; - default: printf("Error, unexpected opcode type\n"); break; + else + { + printf("TOKEN %x", l); } + }; + position = DisplayILOperation(indentCount, pBuffer, position, func); + return std::make_tuple(position, indentCount); +} - printf("\n"); +ULONG DisplayILOperation(const UINT indentCount, BYTE *pBuffer, ULONG position, std::function& disassembleTokenFunc) +{ + printf("%*sIL_%04x: ", indentCount, "", position); + unsigned int c = ReadOpcode(pBuffer, position); + OpCode opcode = opcodes[c]; + printf("%s ", opcode.name); + + switch (opcode.args) + { + case InlineNone: break; + + case ShortInlineVar: + printf("VAR OR ARG %d", ReadData(pBuffer, /* byref */ position)); break; + case InlineVar: + printf("VAR OR ARG %d", ReadData(pBuffer, /* byref */ position)); break; + case InlineI: + printf("%d", ReadData(pBuffer, /* byref */ position)); + break; + case InlineR: + printf("%f", ReadData(pBuffer, /* byref */ position)); + break; + case InlineBrTarget: + printf("IL_%04x", ReadData(pBuffer, /* byref */ position) + position); break; + case ShortInlineBrTarget: + printf("IL_%04x", ReadData(pBuffer, /* byref */ position) + position); break; + case InlineI8: + printf("%ld", ReadData<__int64>(pBuffer, /* byref */ position)); break; + + case InlineMethod: + case InlineField: + case InlineType: + case InlineTok: + case InlineSig: + case InlineString: + { + LONG l = ReadData(pBuffer, /* byref */ position); + disassembleTokenFunc(l); + break; + } + + case InlineSwitch: + { + LONG cases = ReadData(pBuffer, /* byref */ position); + LONG* pArray = new LONG[cases]; + LONG i = 0; + for (i = 0;i(pBuffer, /* byref */ position); + } + printf("("); + for (i = 0;i(pBuffer, /* byref */ position)); break; + case ShortInlineR: + printf("%f", ReadData(pBuffer, /* byref */ position)); break; + default: printf("Error, unexpected opcode type\n"); break; + } + return position; } DWORD_PTR GetObj(DacpObjectData& tokenArray, UINT item) @@ -622,80 +641,18 @@ void DisassembleToken(DacpObjectData& tokenArray, void DecodeDynamicIL(BYTE *data, ULONG Size, DacpObjectData& tokenArray) { // There is no header for this dynamic guy. - // Set globals - position = 0; - pBuffer = data; + ULONG position = 0; + BYTE *pBuffer = data; // At this time no exception information will be displayed (fix soon) UINT indentCount = 0; ULONG endCodePosition = Size; while(position < endCodePosition) - { - printf("%*sIL_%04x: ", indentCount, "", position); - unsigned int c = readOpcode(); - OpCode opcode = opcodes[c]; - printf("%s ", opcode.name); - - switch(opcode.args) - { - case InlineNone: break; - - case ShortInlineVar: - printf("VAR OR ARG %d",readData()); break; - case InlineVar: - printf("VAR OR ARG %d",readData()); break; - case InlineI: - printf("%d",readData()); - break; - case InlineR: - printf("%f",readData()); - break; - case InlineBrTarget: - printf("IL_%04x",readData() + position); break; - case ShortInlineBrTarget: - printf("IL_%04x",readData() + position); break; - case InlineI8: - printf("%ld", readData<__int64>()); break; - - case InlineMethod: - case InlineField: - case InlineType: - case InlineTok: - case InlineSig: - case InlineString: - { - LONG l = readData(); - DisassembleToken(tokenArray, l); - break; - } - - case InlineSwitch: - { - LONG cases = readData(); - LONG *pArray = new LONG[cases]; - LONG i=0; - for(i=0;i(); - } - printf("("); - for(i=0;i()); break; - case ShortInlineR: - printf("%f", readData()); break; - default: printf("Error, unexpected opcode type\n"); break; - } - + { + std::function func = [&tokenArray](DWORD l) { + DisassembleToken(tokenArray, l); + }; + position = DisplayILOperation(indentCount, pBuffer, position, func); printf("\n"); } } @@ -709,7 +666,7 @@ static char* asString(CQuickBytes *out) { out->ReSize(oldSize + 1); char* cur = &((char*) out->Ptr())[oldSize]; *cur = 0; - out->ReSize(oldSize); // Don't count the null character + out->ReSize(oldSize); // Don't count the null character return((char*) out->Ptr()); } @@ -948,7 +905,7 @@ PCCOR_SIGNATURE PrettyPrintType( break; } - case ELEMENT_TYPE_PINNED : + case ELEMENT_TYPE_PINNED: str = " pinned"; goto MODIFIER; case ELEMENT_TYPE_PTR : str = "*"; goto MODIFIER; @@ -1008,7 +965,7 @@ swprintf_s(sz,16,W("$%s$%X"),szStdNamePrefix[tk>>24],tk&0x00FFFFFF); psz = sz; } const char* PrettyPrintClass( CQuickBytes *out, // where to put the pretty printed string - mdToken tk, // The class token to look up + mdToken tk, // The class token to look up IMetaDataImport *pIMD, // ptr to IMetaDataImport class with ComSig DWORD formatFlags /*= formatILDasm*/) { @@ -1109,7 +1066,7 @@ const char* PrettyPrintClass( case mdtAssemblyRef: { - LPCSTR szName = NULL; + LPCSTR szName = NULL; ULONG unused; ToRelease pAsmImport; if (SUCCEEDED(pIMD->QueryInterface(IID_IMetaDataAssemblyImport, (LPVOID *)&pAsmImport))) diff --git a/src/SOS/Strike/sildasm.h b/src/SOS/Strike/sildasm.h new file mode 100644 index 000000000..fffc021b2 --- /dev/null +++ b/src/SOS/Strike/sildasm.h @@ -0,0 +1,22 @@ +// 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. + +// ==++== +// + +// +// ==--== +#ifndef __sildasm_h__ +#define __sildasm_h__ + +#define _BLD_CLR 1 +#include "corhlpr.h" +#include "daccess.h" +#include "dacprivate.h" + +std::tuple DecodeILAtPosition( + IMetaDataImport *pImport, BYTE *buffer, ULONG bufSize, + ULONG position, UINT indentCount, COR_ILMETHOD_DECODER& header); + +#endif // __sildasm_h__ diff --git a/src/SOS/Strike/strike.cpp b/src/SOS/Strike/strike.cpp index d8207eeab..d3e0d55ee 100644 --- a/src/SOS/Strike/strike.cpp +++ b/src/SOS/Strike/strike.cpp @@ -85,6 +85,8 @@ #include #include #include +#include +#include #include "strike.h" #include "sos.h" @@ -153,6 +155,9 @@ const UINT kcMaxMethodDescsForProfiler = 100; #include #include #include +#include +#include +#include BOOL CallStatus; BOOL ControlC = FALSE; @@ -835,6 +840,15 @@ BOOL GatherDynamicInfo(TADDR DynamicMethodObj, DacpObjectData *codeArray, return bRet; } +typedef std::tuple GetILAddressResult; +GetILAddressResult GetILAddress(const DacpMethodDescData& MethodDescData); + +/**********************************************************************\ +* Routine Description: * +* * +* Displays the Microsoft intermediate language (MSIL) that is * +* associated with a managed method. * +\**********************************************************************/ DECLARE_API(DumpIL) { INIT_API(); @@ -904,64 +918,15 @@ DECLARE_API(DumpIL) } else { - TADDR ilAddr = NULL; - struct DacpProfilerILData ilData; - ReleaseHolder sos7; - if (SUCCEEDED(g_sos->QueryInterface(__uuidof(ISOSDacInterface7), &sos7)) && - SUCCEEDED(sos7->GetProfilerModifiedILInformation(MethodDescData.MethodDescPtr, &ilData))) - { - if (ilData.type == DacpProfilerILData::ILModified) - { - ExtOut("Found profiler modified IL\n"); - ilAddr = TO_TADDR(ilData.il); - } - } - - // Factor this so that it returns a map from IL offset to the textual representation of the decoding - // to be consumed by !u -il - // The disassemble function can give a MethodDescData as well as the set of keys IL offsets - - // This is not a dynamic method, print the IL for it. - // Get the module - DacpModuleData dmd; - if (dmd.Request(g_sos, MethodDescData.ModulePtr) != S_OK) + GetILAddressResult result = GetILAddress(MethodDescData); + if (std::get<0>(result) == NULL) { - ExtOut("Unable to get module\n"); - return Status; - } - - ToRelease pImport = MDImportForModule(&dmd); - if (pImport == NULL) - { - ExtOut("bad import\n"); - return Status; - } - - if (ilAddr == NULL) - { - ULONG pRva; - DWORD dwFlags; - if (pImport->GetRVA(MethodDescData.MDToken, &pRva, &dwFlags) != S_OK) - { - ExtOut("error in import\n"); - return Status; - } - - CLRDATA_ADDRESS ilAddrClr; - if (g_sos->GetILForModule(MethodDescData.ModulePtr, pRva, &ilAddrClr) != S_OK) - { - ExtOut("FindIL failed\n"); - return Status; - } - - ilAddr = TO_TADDR(ilAddrClr); - } - - if (ilAddr == NULL) - { - ExtOut("Unkown error in reading function IL\n"); + ExtOut("ilAddr is %p\n", SOS_PTR(std::get<0>(result))); return E_FAIL; } + ExtOut("ilAddr is %p pImport is %p\n", SOS_PTR(std::get<0>(result)), SOS_PTR(std::get<1>(result))); + TADDR ilAddr = std::get<0>(result); + ToRelease pImport(std::get<1>(result)); IfFailRet(DecodeILFromAddress(pImport, ilAddr)); } } @@ -2290,6 +2255,8 @@ struct StackTraceElement #include "sos_stacktrace.h" +#include "sildasm.h" + class StringOutput { public: @@ -4454,14 +4421,14 @@ void ExtOutTaskStateFlagsDescription(int stateFlags) void ExtOutStateMachineFields(AsyncRecord& ar) { - DacpMethodTableData mtabledata; - DacpMethodTableFieldData vMethodTableFields; - if (mtabledata.Request(g_sos, ar.StateMachineMT) == S_OK && - vMethodTableFields.Request(g_sos, ar.StateMachineMT) == S_OK && - vMethodTableFields.wNumInstanceFields + vMethodTableFields.wNumStaticFields > 0) - { - DisplayFields(ar.StateMachineMT, &mtabledata, &vMethodTableFields, (DWORD_PTR)ar.StateMachineAddr, TRUE, ar.IsValueType); - } + DacpMethodTableData mtabledata; + DacpMethodTableFieldData vMethodTableFields; + if (mtabledata.Request(g_sos, ar.StateMachineMT) == S_OK && + vMethodTableFields.Request(g_sos, ar.StateMachineMT) == S_OK && + vMethodTableFields.wNumInstanceFields + vMethodTableFields.wNumStaticFields > 0) + { + DisplayFields(ar.StateMachineMT, &mtabledata, &vMethodTableFields, (DWORD_PTR)ar.StateMachineAddr, TRUE, ar.IsValueType); + } } void FindStateMachineTypes(DWORD_PTR* corelibModule, mdTypeDef* stateMachineBox, mdTypeDef* debugStateMachineBox, mdTypeDef* task) @@ -4828,8 +4795,8 @@ DECLARE_API(DumpAsync) sos::MethodTable contMT = TO_TADDR(contAsyncRecord->second.StateMachineMT); if (contAsyncRecord->second.IsStateMachine) ExtOut("(%d) ", contAsyncRecord->second.StateValue); ExtOut("%S\n", contMT.GetName()); - if (contAsyncRecord->second.IsStateMachine && dumpFields) ExtOutStateMachineFields(contAsyncRecord->second); - } + if (contAsyncRecord->second.IsStateMachine && dumpFields) ExtOutStateMachineFields(contAsyncRecord->second); + } else { ExtOut("%S\n", cont.GetTypeName()); @@ -9179,6 +9146,80 @@ GetClrMethodInstance( ___in ULONG64 NativeOffset, ___out IXCLRDataMethodInstance** Method); +typedef std::tuple ExtractionCodeHeaderResult; + +ExtractionCodeHeaderResult extractCodeHeaderData(DWORD_PTR methodDesc, DWORD_PTR dwStartAddr); +HRESULT displayGcInfo(BOOL fWithGCInfo, const DacpCodeHeaderData& codeHeaderData); +HRESULT GetIntermediateLangMap(BOOL bIL, const DacpCodeHeaderData& codeHeaderData, + std::unique_ptr& map, + ULONG32& mapCount, + BOOL dumpMap); + +GetILAddressResult GetILAddress(const DacpMethodDescData& MethodDescData) +{ + GetILAddressResult error = std::make_tuple(NULL, nullptr); + TADDR ilAddr = NULL; + struct DacpProfilerILData ilData; + ReleaseHolder sos7; + if (SUCCEEDED(g_sos->QueryInterface(__uuidof(ISOSDacInterface7), &sos7)) && + SUCCEEDED(sos7->GetProfilerModifiedILInformation(MethodDescData.MethodDescPtr, &ilData))) + { + if (ilData.type == DacpProfilerILData::ILModified) + { + ExtOut("Found profiler modified IL\n"); + ilAddr = TO_TADDR(ilData.il); + } + } + + // Factor this so that it returns a map from IL offset to the textual representation of the decoding + // to be consumed by !u -il + // The disassemble function can give a MethodDescData as well as the set of keys IL offsets + + // This is not a dynamic method, print the IL for it. + // Get the module + DacpModuleData dmd; + if (dmd.Request(g_sos, MethodDescData.ModulePtr) != S_OK) + { + ExtOut("Unable to get module\n"); + return error; + } + + ToRelease pImport(MDImportForModule(&dmd)); + if (pImport == NULL) + { + ExtOut("bad import\n"); + return error; + } + + if (ilAddr == NULL) + { + ULONG pRva; + DWORD dwFlags; + if (pImport->GetRVA(MethodDescData.MDToken, &pRva, &dwFlags) != S_OK) + { + ExtOut("error in import\n"); + return error; + } + + CLRDATA_ADDRESS ilAddrClr; + if (g_sos->GetILForModule(MethodDescData.ModulePtr, pRva, &ilAddrClr) != S_OK) + { + ExtOut("FindIL failed\n"); + return error; + } + + ilAddr = TO_TADDR(ilAddrClr); + } + + if (ilAddr == NULL) + { + ExtOut("Unknown error in reading function IL\n"); + return error; + } + GetILAddressResult result = std::make_tuple(ilAddr, pImport.Detach()); + return result; +} + /**********************************************************************\ * Routine Description: * * * @@ -9249,8 +9290,247 @@ DECLARE_API(u) } } + ExtractionCodeHeaderResult p = extractCodeHeaderData(methodDesc, dwStartAddr); + Status = std::get<2>(p); + if (Status != S_OK) + { + return Status; + } + + NameForMD_s(methodDesc, g_mdName, mdNameLen); + ExtOut("%S\n", g_mdName); + + DacpMethodDescData& MethodDescData = std::get<0>(p); + DacpCodeHeaderData& codeHeaderData = std::get<1>(p); + std::unique_ptr map(nullptr); + ULONG32 mapCount = 0; + Status = GetIntermediateLangMap(bIL, codeHeaderData, map /*out*/, mapCount /* out */, false); + if (Status != S_OK) + { + return Status; + } + + // /////////////////////////////////////////////////////////////////////////// + // This can be reused with sildasm but kept as-is largely since it just + // works so it can be fixed later. + // /////////////////////////////////////////////////////////////////////////// + + if (MethodDescData.bIsDynamic && MethodDescData.managedDynamicMethodObject) + { + ExtOut("Can only work with dynamic not implemented\n"); + return Status; + } + + GetILAddressResult result = GetILAddress(MethodDescData); + if (std::get<0>(result) == NULL) + { + ExtOut("ilAddr is %p\n", SOS_PTR(std::get<0>(result))); + return E_FAIL; + } + ExtOut("ilAddr is %p pImport is %p\n", SOS_PTR(std::get<0>(result)), SOS_PTR(std::get<1>(result))); + TADDR ilAddr = std::get<0>(result); + ToRelease pImport(std::get<1>(result)); + + /// Taken from DecodeILFromAddress(IMetaDataImport *pImport, TADDR ilAddr) + ULONG Size = GetILSize(ilAddr); + if (Size == 0) + { + ExtOut("error decoding IL\n"); + return Status; + } + // Read the memory into a local buffer + ArrayHolder pArray = new BYTE[Size]; + Status = g_ExtData->ReadVirtual(TO_CDADDR(ilAddr), pArray, Size, NULL); + if (Status != S_OK) + { + ExtOut("Failed to read memory\n"); + return Status; + } + /// Taken from DecodeIL(pImport, pArray, Size); + // First decode the header + BYTE *buffer = pArray; + ULONG bufSize = Size; + COR_ILMETHOD *pHeader = (COR_ILMETHOD *) buffer; + COR_ILMETHOD_DECODER header(pHeader); + ULONG position = 0; + BYTE* pBuffer = const_cast(header.Code); + UINT indentCount = 0; + ULONG endCodePosition = header.GetCodeSize(); + struct ILLocationRange { + ULONG mStartPosition; + ULONG mEndPosition; + BYTE* mStartAddress; + BYTE* mEndAddress; + }; + std::deque ilCodePositions; + + if (mapCount > 0) + { + while (position < endCodePosition) + { + ULONG mapIndex = 0; + do + { + while ((mapIndex < mapCount) && (position != map[mapIndex].ilOffset)) + { + ++mapIndex; + } + if (map[mapIndex].endAddress > map[mapIndex].startAddress) + { + break; + } + ++mapIndex; + } while (mapIndex < mapCount); + std::tuple r = DecodeILAtPosition( + pImport, pBuffer, bufSize, + position, indentCount, header); + ExtOut("\n"); + if (mapIndex < mapCount) + { + ILLocationRange entry = { + position, + std::get<0>(r) - 1, + (BYTE*)map[mapIndex].startAddress, + (BYTE*)map[mapIndex].endAddress + }; + ilCodePositions.push_back(std::move(entry)); + } + else + { + if (!ilCodePositions.empty()) + { + auto& entry = ilCodePositions.back(); + entry.mEndPosition = position; + } + } + position = std::get<0>(r); + indentCount = std::get<1>(r); + } + } + + position = 0; + indentCount = 0; + std::function displayILFun = + [&pImport, &pBuffer, bufSize, &header, &ilCodePositions](ULONG *pPosition, UINT *pIndentCount, + BYTE *pIp) -> void { + for (auto iter = ilCodePositions.begin(); iter != ilCodePositions.end(); ++iter) + { + if ((pIp >= iter->mStartAddress) && (pIp < iter->mEndAddress)) + { + ULONG position = iter->mStartPosition; + ULONG endPosition = iter->mEndPosition; + while (position <= endPosition) + { + std::tuple r = DecodeILAtPosition( + pImport, pBuffer, bufSize, + position, *pIndentCount, header); + ExtOut("\n"); + position = std::get<0>(r); + *pIndentCount = std::get<1>(r); + } + ilCodePositions.erase(iter); + break; + } + } + }; + + if (codeHeaderData.ColdRegionStart != NULL) + { + ExtOut("Begin %p, size %x. Cold region begin %p, size %x\n", + SOS_PTR(codeHeaderData.MethodStart), codeHeaderData.HotRegionSize, + SOS_PTR(codeHeaderData.ColdRegionStart), codeHeaderData.ColdRegionSize); + } + else + { + ExtOut("Begin %p, size %x\n", SOS_PTR(codeHeaderData.MethodStart), codeHeaderData.MethodSize); + } + + Status = displayGcInfo(fWithGCInfo, codeHeaderData); + if (Status != S_OK) + { + return Status; + } + + SOSEHInfo *pInfo = NULL; + if (fWithEHInfo) + { + pInfo = new NOTHROW SOSEHInfo; + if (pInfo == NULL) + { + ReportOOM(); + } + else if (g_sos->TraverseEHInfo(codeHeaderData.MethodStart, gatherEh, (LPVOID)pInfo) != S_OK) + { + ExtOut("Failed to gather EHInfo data\n"); + delete pInfo; + pInfo = NULL; + } + } + + if (codeHeaderData.ColdRegionStart == NULL) + { + g_targetMachine->Unassembly ( + (DWORD_PTR) codeHeaderData.MethodStart, + ((DWORD_PTR)codeHeaderData.MethodStart) + codeHeaderData.MethodSize, + dwStartAddr, + (DWORD_PTR) MethodDescData.GCStressCodeCopy, + fWithGCInfo ? &g_gcEncodingInfo : NULL, + pInfo, + bSuppressLines, + bDisplayOffsets, + displayILFun); + } + else + { + ExtOut("Hot region:\n"); + g_targetMachine->Unassembly ( + (DWORD_PTR) codeHeaderData.MethodStart, + ((DWORD_PTR)codeHeaderData.MethodStart) + codeHeaderData.HotRegionSize, + dwStartAddr, + (DWORD_PTR) MethodDescData.GCStressCodeCopy, + fWithGCInfo ? &g_gcEncodingInfo : NULL, + pInfo, + bSuppressLines, + bDisplayOffsets, + displayILFun); + + ExtOut("Cold region:\n"); + + // Displaying gcinfo for a cold region requires knowing the size of + // the hot region preceeding. + g_gcEncodingInfo.hotSizeToAdd = codeHeaderData.HotRegionSize; + + g_targetMachine->Unassembly ( + (DWORD_PTR) codeHeaderData.ColdRegionStart, + ((DWORD_PTR)codeHeaderData.ColdRegionStart) + codeHeaderData.ColdRegionSize, + dwStartAddr, + ((DWORD_PTR) MethodDescData.GCStressCodeCopy) + codeHeaderData.HotRegionSize, + fWithGCInfo ? &g_gcEncodingInfo : NULL, + pInfo, + bSuppressLines, + bDisplayOffsets, + displayILFun); + + } + + if (pInfo) + { + delete pInfo; + pInfo = NULL; + } + + if (fWithGCInfo) + { + g_gcEncodingInfo.Deinitialize(); + } + + return Status; +} + +inline ExtractionCodeHeaderResult extractCodeHeaderData(DWORD_PTR methodDesc, DWORD_PTR dwStartAddr) +{ DacpMethodDescData MethodDescData; - Status = + HRESULT Status = g_sos->GetMethodDescData( TO_CDADDR(methodDesc), dwStartAddr == methodDesc ? NULL : dwStartAddr, @@ -9261,13 +9541,13 @@ DECLARE_API(u) if (Status != S_OK) { ExtOut("Failed to get method desc for %p.\n", SOS_PTR(dwStartAddr)); - return Status; - } + return ExtractionCodeHeaderResult(std::move(MethodDescData), DacpCodeHeaderData(), Status); + } if (!MethodDescData.bHasNativeCode) { ExtOut("Not jitted yet\n"); - return Status; + return ExtractionCodeHeaderResult(std::move(MethodDescData), DacpCodeHeaderData(), S_FALSE); } // Get the appropriate code header. If we were passed an MD, then use @@ -9276,26 +9556,25 @@ DECLARE_API(u) // disassemble the rejit version that the user explicitly specified with their IP. DacpCodeHeaderData codeHeaderData; if (codeHeaderData.Request( - g_sos, + g_sos, TO_CDADDR( - (dwStartAddr == methodDesc) ? MethodDescData.NativeCodeAddr : dwStartAddr) - ) != S_OK) - + (dwStartAddr == methodDesc) ? MethodDescData.NativeCodeAddr : dwStartAddr) + ) != S_OK) { ExtOut("Unable to get codeHeader information\n"); - return Status; - } - + return ExtractionCodeHeaderResult(std::move(MethodDescData), DacpCodeHeaderData(), S_FALSE); + } + if (codeHeaderData.MethodStart == 0) { ExtOut("not a valid MethodDesc\n"); - return Status; + return ExtractionCodeHeaderResult(std::move(MethodDescData), DacpCodeHeaderData(), S_FALSE); } - + if (codeHeaderData.JITType == TYPE_UNKNOWN) { ExtOut("unknown Jit\n"); - return Status; + return ExtractionCodeHeaderResult(std::move(MethodDescData), DacpCodeHeaderData(), S_FALSE); } else if (codeHeaderData.JITType == TYPE_JIT) { @@ -9305,58 +9584,11 @@ DECLARE_API(u) { ExtOut("preJIT generated code\n"); } + return ExtractionCodeHeaderResult(std::move(MethodDescData), std::move(codeHeaderData), S_OK); +} - NameForMD_s(methodDesc, g_mdName, mdNameLen); - ExtOut("%S\n", g_mdName); - - if (bIL) - { - ToRelease pMethodInst(NULL); - - if ((Status = GetClrMethodInstance(codeHeaderData.MethodStart, &pMethodInst)) != S_OK) - { - return Status; - } - - ArrayHolder map(nullptr); - ULONG32 mapCount = 0; - - if ((Status = pMethodInst->GetILAddressMap(mapCount, &mapCount, map)) != S_OK) - { - return Status; - } - - map = new NOTHROW CLRDATA_IL_ADDRESS_MAP[mapCount]; - if (map == NULL) - { - ReportOOM(); - return E_OUTOFMEMORY; - } - - if ((Status = pMethodInst->GetILAddressMap(mapCount, &mapCount, map)) != S_OK) - { - return Status; - } - - for (ULONG32 i = 0; i < mapCount; i++) - { - // TODO: These information should be interleaved with the disassembly - // Decoded IL can be obtained through refactoring DumpIL code. - ExtOut("%04x %p %p\n", map[i].ilOffset, map[i].startAddress, map[i].endAddress); - } - } - - if (codeHeaderData.ColdRegionStart != NULL) - { - ExtOut("Begin %p, size %x. Cold region begin %p, size %x\n", - SOS_PTR(codeHeaderData.MethodStart), codeHeaderData.HotRegionSize, - SOS_PTR(codeHeaderData.ColdRegionStart), codeHeaderData.ColdRegionSize); - } - else - { - ExtOut("Begin %p, size %x\n", SOS_PTR(codeHeaderData.MethodStart), codeHeaderData.MethodSize); - } - +HRESULT displayGcInfo(BOOL fWithGCInfo, const DacpCodeHeaderData& codeHeaderData) +{ // // Set up to mix gc info with the code if requested. To do this, we first generate all the textual // gc info up front. This text is the same as the "!gcinfo" command, and looks like: @@ -9446,13 +9678,13 @@ DECLARE_API(u) ExtOut("Could not allocate memory to read the gc info.\n"); return E_OUTOFMEMORY; } - - memset (table, 0, tableSize); + + memset(table, 0, tableSize); // We avoid using move here, because we do not want to return if (!SafeReadMemory(TO_TADDR(codeHeaderData.GCInfo), table, tableSize, NULL)) { ExtOut("Could not read memory %p\n", SOS_PTR(codeHeaderData.GCInfo)); - return Status; + return ERROR_INVALID_DATA; } // @@ -9464,85 +9696,56 @@ DECLARE_API(u) { return E_OUTOFMEMORY; } - + GCInfoToken gcInfoToken = { table, GCINFO_VERSION }; g_targetMachine->DumpGCInfo(gcInfoToken, methodSize, DecodeGCTableEntry, false /*encBytes*/, false /*bPrintHeader*/); - } + } + return S_OK; +} - SOSEHInfo *pInfo = NULL; - if (fWithEHInfo) +HRESULT GetIntermediateLangMap(BOOL bIL, const DacpCodeHeaderData& codeHeaderData, + std::unique_ptr& map, + ULONG32& mapCount, + BOOL dumpMap) +{ + HRESULT Status = S_OK; + if (bIL) { - pInfo = new NOTHROW SOSEHInfo; - if (pInfo == NULL) + ToRelease pMethodInst(NULL); + + if ((Status = GetClrMethodInstance(codeHeaderData.MethodStart, &pMethodInst)) != S_OK) { - ReportOOM(); + return Status; } - else if (g_sos->TraverseEHInfo(codeHeaderData.MethodStart, gatherEh, (LPVOID)pInfo) != S_OK) + + if ((Status = pMethodInst->GetILAddressMap(mapCount, &mapCount, map.get())) != S_OK) { - ExtOut("Failed to gather EHInfo data\n"); - delete pInfo; - pInfo = NULL; + return Status; } - } - - if (codeHeaderData.ColdRegionStart == NULL) - { - g_targetMachine->Unassembly ( - (DWORD_PTR) codeHeaderData.MethodStart, - ((DWORD_PTR)codeHeaderData.MethodStart) + codeHeaderData.MethodSize, - dwStartAddr, - (DWORD_PTR) MethodDescData.GCStressCodeCopy, - fWithGCInfo ? &g_gcEncodingInfo : NULL, - pInfo, - bSuppressLines, - bDisplayOffsets - ); - } - else - { - ExtOut("Hot region:\n"); - g_targetMachine->Unassembly ( - (DWORD_PTR) codeHeaderData.MethodStart, - ((DWORD_PTR)codeHeaderData.MethodStart) + codeHeaderData.HotRegionSize, - dwStartAddr, - (DWORD_PTR) MethodDescData.GCStressCodeCopy, - fWithGCInfo ? &g_gcEncodingInfo : NULL, - pInfo, - bSuppressLines, - bDisplayOffsets - ); - - ExtOut("Cold region:\n"); - - // Displaying gcinfo for a cold region requires knowing the size of - // the hot region preceeding. - g_gcEncodingInfo.hotSizeToAdd = codeHeaderData.HotRegionSize; - g_targetMachine->Unassembly ( - (DWORD_PTR) codeHeaderData.ColdRegionStart, - ((DWORD_PTR)codeHeaderData.ColdRegionStart) + codeHeaderData.ColdRegionSize, - dwStartAddr, - ((DWORD_PTR) MethodDescData.GCStressCodeCopy) + codeHeaderData.HotRegionSize, - fWithGCInfo ? &g_gcEncodingInfo : NULL, - pInfo, - bSuppressLines, - bDisplayOffsets - ); - - } + map.reset(new NOTHROW CLRDATA_IL_ADDRESS_MAP[mapCount]); + if (map.get() == NULL) + { + ReportOOM(); + return E_OUTOFMEMORY; + } - if (pInfo) - { - delete pInfo; - pInfo = NULL; - } + if ((Status = pMethodInst->GetILAddressMap(mapCount, &mapCount, map.get())) != S_OK) + { + return Status; + } - if (fWithGCInfo) - { - g_gcEncodingInfo.Deinitialize(); + if (dumpMap) + { + for (ULONG32 i = 0; i < mapCount; i++) + { + // TODO: These information should be interleaved with the disassembly + // Decoded IL can be obtained through refactoring DumpIL code. + ExtOut("%04x %p %p\n", map[i].ilOffset, map[i].startAddress, map[i].endAddress); + } + } } - - return Status; + return S_OK; } /**********************************************************************\ diff --git a/src/SOS/Strike/util.h b/src/SOS/Strike/util.h index 054d5b950..2ff025788 100644 --- a/src/SOS/Strike/util.h +++ b/src/SOS/Strike/util.h @@ -21,6 +21,7 @@ inline void RestoreSOToleranceState() {} #include #include #include +#include #if !defined(FEATURE_PAL) #include @@ -1547,10 +1548,12 @@ UINT GetMaxGeneration(); UINT GetGcHeapCount(); BOOL GetGcStructuresValid(); +void DisassembleToken(IMetaDataImport* i, DWORD token); ULONG GetILSize(DWORD_PTR ilAddr); // REturns 0 if error occurs HRESULT DecodeILFromAddress(IMetaDataImport *pImport, TADDR ilAddr); void DecodeIL(IMetaDataImport *pImport, BYTE *buffer, ULONG bufSize); void DecodeDynamicIL(BYTE *data, ULONG Size, DacpObjectData& tokenArray); +ULONG DisplayILOperation(const UINT indentCount, BYTE* pBuffer, ULONG position, std::function& func); HRESULT GetRuntimeModuleInfo(PULONG moduleIndex, PULONG64 moduleBase); EEFLAVOR GetEEFlavor (); @@ -3090,6 +3093,5 @@ public: private: HRESULT PrintCurrentInternalFrame(); }; - #include "sigparser.h" #endif // __util_h__