From: Jan Kotas Date: Mon, 10 Aug 2015 17:02:28 +0000 (-0700) Subject: Implement /disassemble nidump option for readytorun images X-Git-Tag: accepted/tizen/base/20180629.140029~6509^2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=85cfcef249fdf2c705c2ddc88aed33222399d324;p=platform%2Fupstream%2Fcoreclr.git Implement /disassemble nidump option for readytorun images [tfs-changeset: 1512604] --- diff --git a/src/debug/daccess/nidump.cpp b/src/debug/daccess/nidump.cpp index c370bd5..44569d9 100644 --- a/src/debug/daccess/nidump.cpp +++ b/src/debug/daccess/nidump.cpp @@ -3440,6 +3440,11 @@ size_t NativeImageDumper::TranslateSymbol(IXCLRDisassemblySupport *dis, CLRDATA_ADDRESS addr, __out_ecount(nameSize) WCHAR *name, SIZE_T nameSize, DWORDLONG *offset) { +#ifdef FEATURE_READYTORUN + if (m_pReadyToRunHeader != NULL) + return 0; +#endif + if (isInRange((TADDR)addr)) { COUNT_T rva = (COUNT_T)(addr - PTR_TO_TADDR(m_decoder.GetBase())); @@ -3768,7 +3773,6 @@ void NativeImageDumper::DumpModule( PTR_Module module ) _ASSERTE(file == NULL); DisplayWriteFieldPointer( m_file, DPtrToPreferredAddr(file), Module, MODULE ); - //DumpPEFile( file, "PEFile" ); PTR_MethodDesc dllMain( TO_TADDR(module->m_pDllMain) ); WriteFieldMethodDesc( m_pDllMain, dllMain, Module, @@ -9279,11 +9283,45 @@ StandardEntryDisplay: } #ifdef FEATURE_READYTORUN +IMAGE_DATA_DIRECTORY * NativeImageDumper::FindReadyToRunSection(DWORD type) +{ + PTR_READYTORUN_SECTION pSections = dac_cast(dac_cast(m_pReadyToRunHeader) + sizeof(READYTORUN_HEADER)); + for (DWORD i = 0; i < m_pReadyToRunHeader->NumberOfSections; i++) + { + // Verify that section types are sorted + _ASSERTE(i == 0 || (pSections[i - 1].Type < pSections[i].Type)); + + READYTORUN_SECTION * pSection = pSections + i; + if (pSection->Type == type) + return &pSection->Section; + } + return NULL; +} + // // Ready to Run specific dumping methods // void NativeImageDumper::DumpReadyToRun() { + m_pReadyToRunHeader = m_decoder.GetReadyToRunHeader(); + + m_nativeReader = NativeFormat::NativeReader(dac_cast(m_decoder.GetBase()), m_decoder.GetVirtualSize()); + + IMAGE_DATA_DIRECTORY * pRuntimeFunctionsDir = FindReadyToRunSection(READYTORUN_SECTION_RUNTIME_FUNCTIONS); + if (pRuntimeFunctionsDir != NULL) + { + m_pRuntimeFunctions = dac_cast(m_decoder.GetDirectoryData(pRuntimeFunctionsDir)); + m_nRuntimeFunctions = pRuntimeFunctionsDir->Size / sizeof(RUNTIME_FUNCTION); + } + else + { + m_nRuntimeFunctions = 0; + } + + IMAGE_DATA_DIRECTORY * pEntryPointsDir = FindReadyToRunSection(READYTORUN_SECTION_METHODDEF_ENTRYPOINTS); + if (pEntryPointsDir != NULL) + m_methodDefEntryPoints = NativeFormat::NativeArray(&m_nativeReader, pEntryPointsDir->VirtualAddress); + DisplayStartCategory("NativeInfo", NATIVE_INFO); IF_OPT(NATIVE_INFO) @@ -9291,6 +9329,9 @@ void NativeImageDumper::DumpReadyToRun() DisplayEndCategory(NATIVE_INFO); //NativeInfo + IF_OPT_OR3(METHODS, GC_INFO, DISASSEMBLE_CODE) + DumpReadyToRunMethods(); + IF_OPT(RELOCATIONS) DumpBaseRelocs(); } @@ -9304,25 +9345,163 @@ const NativeImageDumper::EnumMnemonics s_ReadyToRunFlags[] = void NativeImageDumper::DumpReadyToRunHeader() { - PTR_READYTORUN_HEADER nativeHeader(m_decoder.GetReadyToRunHeader()); - IF_OPT(NATIVE_INFO) { m_display->StartStructure( "READYTORUN_HEADER", - DPtrToPreferredAddr(nativeHeader), - sizeof(*nativeHeader) ); + DPtrToPreferredAddr(dac_cast(m_pReadyToRunHeader)), + sizeof(*m_pReadyToRunHeader) ); - DisplayWriteFieldUInt( Signature, nativeHeader->Signature, READYTORUN_HEADER, ALWAYS ); - DisplayWriteFieldUInt( MajorVersion, nativeHeader->MajorVersion, READYTORUN_HEADER, ALWAYS ); - DisplayWriteFieldUInt( MinorVersion, nativeHeader->MinorVersion, READYTORUN_HEADER, ALWAYS ); + DisplayWriteFieldUInt( Signature, m_pReadyToRunHeader->Signature, READYTORUN_HEADER, ALWAYS ); + DisplayWriteFieldUInt( MajorVersion, m_pReadyToRunHeader->MajorVersion, READYTORUN_HEADER, ALWAYS ); + DisplayWriteFieldUInt( MinorVersion, m_pReadyToRunHeader->MinorVersion, READYTORUN_HEADER, ALWAYS ); - DisplayWriteFieldEnumerated( Flags, nativeHeader->Flags, + DisplayWriteFieldEnumerated( Flags, m_pReadyToRunHeader->Flags, READYTORUN_HEADER, s_ReadyToRunFlags, W(", "), NATIVE_INFO ); m_display->EndStructure(); //READYTORUN_HEADER } } + +void NativeImageDumper::DumpReadyToRunMethods() +{ + DisplayStartArray("Methods", NULL, METHODS); + + for (uint rid = 1; rid <= m_methodDefEntryPoints.GetCount(); rid++) + { + uint offset; + if (!m_methodDefEntryPoints.TryGetAt(rid - 1, &offset)) + continue; + + uint id; + offset = m_nativeReader.DecodeUnsigned(offset, &id); + + if (id & 1) + { + if (id & 2) + { + uint val; + m_nativeReader.DecodeUnsigned(offset, &val); + offset -= val; + } + + // TODO: Dump fixups from dac_cast(m_pLayout->GetBase()) + offset + + id >>= 2; + } + else + { + id >>= 1; + } + + _ASSERTE(id < m_nRuntimeFunctions); + PTR_RUNTIME_FUNCTION pRuntimeFunction = m_pRuntimeFunctions + id; + PCODE pEntryPoint = dac_cast(m_decoder.GetBase()) + pRuntimeFunction->BeginAddress; + + SString buf; + AppendTokenName(TokenFromRid(rid, mdtMethodDef), buf, m_import); + + DumpReadyToRunMethod(pEntryPoint, pRuntimeFunction, buf); + } + + DisplayEndArray("Total Methods", METHODS); //Methods +} + +extern PTR_VOID GetUnwindDataBlob(TADDR moduleBase, PTR_RUNTIME_FUNCTION pRuntimeFunction, /* out */ SIZE_T * pSize); + +void NativeImageDumper::DumpReadyToRunMethod(PCODE pEntryPoint, PTR_RUNTIME_FUNCTION pRuntimeFunction, SString& name) +{ + //Read the GCInfo to get the total method size. + unsigned methodSize = 0; + unsigned gcInfoSize = UINT_MAX; + + SIZE_T nUnwindDataSize; + PTR_VOID pUnwindData = GetUnwindDataBlob(dac_cast(m_decoder.GetBase()), pRuntimeFunction, &nUnwindDataSize); + + // GCInfo immediatelly follows unwind data + PTR_CBYTE gcInfo = dac_cast(pUnwindData) + nUnwindDataSize; + + void(*stringOutFn)(const char *, ...); + IF_OPT(GC_INFO) + { + stringOutFn = stringOut; + } + else + { + stringOutFn = nullStringOut; + } + if (gcInfo != NULL) + { + PTR_CBYTE curGCInfoPtr = gcInfo; + g_holdStringOutData.Clear(); + GCDump gcDump; + gcDump.gcPrintf = stringOutFn; +#if !defined(_TARGET_X86_) && defined(USE_GC_INFO_DECODER) + GcInfoDecoder gcInfoDecoder(curGCInfoPtr, DECODE_CODE_LENGTH, 0); + methodSize = gcInfoDecoder.GetCodeLength(); +#endif + + //dump the data to a string first so we can get the gcinfo size. +#ifdef _TARGET_X86_ + InfoHdr hdr; + stringOutFn("method info Block:\n"); + curGCInfoPtr += gcDump.DumpInfoHdr(curGCInfoPtr, &hdr, &methodSize, 0); + stringOutFn("\n"); +#endif + + IF_OPT(METHODS) + { +#ifdef _TARGET_X86_ + stringOutFn("PointerTable:\n"); + curGCInfoPtr += gcDump.DumpGCTable(curGCInfoPtr, + hdr, + methodSize, 0); + gcInfoSize = curGCInfoPtr - gcInfo; +#elif defined(USE_GC_INFO_DECODER) + stringOutFn("PointerTable:\n"); + curGCInfoPtr += gcDump.DumpGCTable(curGCInfoPtr, + methodSize, 0); + gcInfoSize = (unsigned)(curGCInfoPtr - gcInfo); +#endif + } + + //data is output below. + } + + DisplayStartElement("Method", METHODS); + DisplayWriteElementStringW("Name", (const WCHAR *)name, METHODS); + + DisplayStartStructure("GCInfo", + DPtrToPreferredAddr(gcInfo), + gcInfoSize, + METHODS); + + DisplayStartTextElement("Contents", GC_INFO); + DisplayWriteXmlTextBlock(("%S", (const WCHAR *)g_holdStringOutData), GC_INFO); + DisplayEndTextElement(GC_INFO); //Contents + + DisplayEndStructure(METHODS); //GCInfo + + DisplayStartStructure("Code", DataPtrToDisplay(pEntryPoint), methodSize, + METHODS); + + IF_OPT(DISASSEMBLE_CODE) + { + // Disassemble hot code. Read the code into the host process. + /* REVISIT_TODO Mon 10/24/2005 + * Is this align up right? + */ + BYTE * codeStartHost = + reinterpret_cast(PTR_READ(pEntryPoint, + (ULONG32)ALIGN_UP(methodSize, + CODE_SIZE_ALIGN))); + DisassembleMethod(codeStartHost, methodSize); + } + + DisplayEndStructure(METHODS); //Code + + DisplayEndElement(METHODS); //Method +} #endif // FEATURE_READYTORUN #if 0 @@ -9338,36 +9517,6 @@ mdTypeRef NativeImageDumper::FindTypeRefForMT( PTR_MethodTable mt ) #endif -#if 0 -void NativeImageDumper::DumpPEFile( PTR_PEFile file, const char * name ) -{ - IF_OPT(PE_INFO) - { - m_display->StartStructure( name, DPtrToPreferredAddr(file), - sizeof(*file) ); - } - _ASSERTE(file->m_identity); - _ASSERTE(file->m_ILimage); - _ASSERTE(file->m_nativeImage); - DumpPEImage( file->m_identity, "ThisImage" ); - DumpPEImage( file->m_ILimage, "ILImage" ); - DumpPEImage( file->m_nativeImage, "NativeImage" ); - - IF_OPT(PE_INFO) - { - m_display->WriteElementFlag( "CanUseNativeImage", - file->m_fCanUseNativeImage ); - m_display->WriteElementFlag( "HasPersistentMDImport", - file->m_bHasPersistentMDImport ); - } -#ifdef _DEBUG - _ASSERTE( !"Look at m_pDebugName and m_debugName. Also look at IMDstuff" ); -#endif - IF_OPT(PE_INFO) - m_display->EndStructure(); //name -} -#endif - /* REVISIT_TODO Mon 10/10/2005 * Here is where it gets bad. There is no DAC build of gcdump, so instead * build it directly into the the dac. That's what all these ugly defines diff --git a/src/debug/daccess/nidump.h b/src/debug/daccess/nidump.h index ff97b1f..4efec37 100644 --- a/src/debug/daccess/nidump.h +++ b/src/debug/daccess/nidump.h @@ -243,18 +243,24 @@ public: void FieldDescToString( PTR_FieldDesc fd, mdFieldDef tok, SString& buf ); #ifdef FEATURE_READYTORUN - void DumpReadyToRun(); - void DumpReadyToRunHeader(); -#endif +private: + READYTORUN_HEADER * m_pReadyToRunHeader; -#if 0 - void DumpPEFile( PTR_PEFile file, const char * name ); - void DumpPEImage( PTR_PEImage image, const char * name ); -#endif + PTR_RUNTIME_FUNCTION m_pRuntimeFunctions; + DWORD m_nRuntimeFunctions; + NativeFormat::NativeReader m_nativeReader; + NativeFormat::NativeArray m_methodDefEntryPoints; + + IMAGE_DATA_DIRECTORY * FindReadyToRunSection(DWORD type); + +public: + void DumpReadyToRun(); + void DumpReadyToRunHeader(); + void DumpReadyToRunMethods(); + void DumpReadyToRunMethod(PCODE pEntryPoint, PTR_RUNTIME_FUNCTION pRuntimeFunction, SString& name); +#endif // FEATURE_READYTORUN - inline PTR_VOID BaseAddress() const { return m_baseAddress; } - private: PEDecoder m_decoder; const WCHAR * const m_name;