private bool FindMatchingInterfaceSlot(IntPtr moduleHandle, NativeReader nativeLayoutReader, ref NativeParser entryParser, ref ExternalReferencesTable extRefs, ref RuntimeTypeHandle declaringType, ref MethodNameAndSignature methodNameAndSignature, RuntimeTypeHandle openTargetTypeHandle, RuntimeTypeHandle[] targetTypeInstantiation, bool variantDispatch) { uint numTargetImplementations = entryParser.GetUnsigned(); for (uint j = 0; j < numTargetImplementations; j++) { uint nameAndSigToken = extRefs.GetRvaFromIndex(entryParser.GetUnsigned()); MethodNameAndSignature targetMethodNameAndSignature = GetMethodNameAndSignatureFromNativeReader(nativeLayoutReader, nameAndSigToken); RuntimeTypeHandle targetTypeHandle = extRefs.GetRuntimeTypeHandleFromIndex(entryParser.GetUnsigned()); #if REFLECTION_EXECUTION_TRACE ReflectionExecutionLogger.WriteLine(" Searching for GVM implementation on targe type = " + GetTypeNameDebug(targetTypeHandle)); #endif uint numIfaceImpls = entryParser.GetUnsigned(); for (uint k = 0; k < numIfaceImpls; k++) { RuntimeTypeHandle implementingTypeHandle = extRefs.GetRuntimeTypeHandleFromIndex(entryParser.GetUnsigned()); uint numIfaceSigs = entryParser.GetUnsigned(); if (!openTargetTypeHandle.Equals(implementingTypeHandle)) { // Skip over signatures data for (uint l = 0; l < numIfaceSigs; l++) entryParser.GetUnsigned(); continue; } for (uint l = 0; l < numIfaceSigs; l++) { RuntimeTypeHandle currentIfaceTypeHandle = default(RuntimeTypeHandle); NativeParser ifaceSigParser = new NativeParser(nativeLayoutReader, extRefs.GetRvaFromIndex(entryParser.GetUnsigned())); IntPtr currentIfaceSigPtr = ifaceSigParser.Reader.OffsetToAddress(ifaceSigParser.Offset); if (TypeLoaderEnvironment.Instance.GetTypeFromSignatureAndContext(currentIfaceSigPtr, targetTypeInstantiation, null, out currentIfaceTypeHandle, out currentIfaceSigPtr)) { Debug.Assert(!currentIfaceTypeHandle.IsNull()); if ((!variantDispatch && declaringType.Equals(currentIfaceTypeHandle)) || (variantDispatch && RuntimeAugments.IsAssignableFrom(declaringType, currentIfaceTypeHandle))) { #if REFLECTION_EXECUTION_TRACE ReflectionExecutionLogger.WriteLine(" " + (declaringType.Equals(currentIfaceTypeHandle) ? "Exact" : "Variant-compatible") + " match found on this target type!"); #endif // We found the GVM slot target for the input interface GVM call, so let's update the interface GVM slot and return success to the caller declaringType = targetTypeHandle; methodNameAndSignature = targetMethodNameAndSignature; return true; } } } } } return false; }
public MethodNameAndSignature GetMethodNameAndSignatureFromNativeReader(NativeReader nativeLayoutReader, uint nativeLayoutOffset) { NativeParser parser = new NativeParser(nativeLayoutReader, nativeLayoutOffset); string methodName = parser.GetString(); // Signatures are indirected to through a relative offset so that we don't have to parse them // when not comparing signatures (parsing them requires resolving types and is tremendously // expensive). NativeParser sigParser = parser.GetParserFromRelativeOffset(); IntPtr methodSigPtr = sigParser.Reader.OffsetToAddress(sigParser.Offset); return new MethodNameAndSignature(methodName, methodSigPtr); }
public bool TryGetAt(byte[] image, uint index, ref int pOffset) { if (index >= _nElements) { return(false); } uint offset = 0; if (_entryIndexSize == 0) { int i = (int)(_baseOffset + (index / _blockSize)); offset = NativeReader.ReadByte(image, ref i); } else if (_entryIndexSize == 1) { int i = (int)(_baseOffset + 2 * (index / _blockSize)); offset = NativeReader.ReadUInt16(image, ref i); } else { int i = (int)(_baseOffset + 4 * (index / _blockSize)); offset = NativeReader.ReadUInt32(image, ref i); } offset += _baseOffset; for (uint bit = _blockSize >> 1; bit > 0; bit >>= 1) { uint val = 0; uint offset2 = NativeReader.DecodeUnsigned(image, offset, ref val); if ((index & bit) != 0) { if ((val & 2) != 0) { offset = offset + (val >> 2); continue; } } else { if ((val & 1) != 0) { offset = offset2; continue; } } // Not found if ((val & 3) == 0) { // Matching special leaf node? if ((val >> 2) == (index & (_blockSize - 1))) { offset = offset2; break; } } return(false); } pOffset = (int)offset; return(true); }
private List <List <BaseGcSlot> > GetLiveSlotsAtSafepoints(byte[] image, ref int bitOffset) { // For each safe point, enumerates a list of GC slots that are alive at that point var result = new List <List <BaseGcSlot> >(); uint numSlots = SlotTable.NumTracked; if (numSlots == 0) { return(null); } uint numBitsPerOffset = 0; // Duplicate the encoder's heuristic to determine if we have indirect live // slot table (similar to the chunk pointers) if (NativeReader.ReadBits(image, 1, ref bitOffset) != 0) { numBitsPerOffset = NativeReader.DecodeVarLengthUnsigned(image, _gcInfoTypes.POINTER_SIZE_ENCBASE, ref bitOffset) + 1; Debug.Assert(numBitsPerOffset != 0); } uint offsetTablePos = (uint)bitOffset; for (uint safePointIndex = 0; safePointIndex < NumSafePoints; safePointIndex++) { bitOffset = (int)offsetTablePos; var liveSlots = new List <BaseGcSlot>(); if (numBitsPerOffset != 0) { bitOffset += (int)(numBitsPerOffset * safePointIndex); uint liveStatesOffset = (uint)NativeReader.ReadBits(image, (int)numBitsPerOffset, ref bitOffset); uint liveStatesStart = (uint)((offsetTablePos + NumSafePoints * numBitsPerOffset + 7) & (~7)); bitOffset = (int)(liveStatesStart + liveStatesOffset); if (NativeReader.ReadBits(image, 1, ref bitOffset) != 0) { // RLE encoded bool skip = NativeReader.ReadBits(image, 1, ref bitOffset) == 0; bool report = true; uint readSlots = NativeReader.DecodeVarLengthUnsigned(image, skip ? _gcInfoTypes.LIVESTATE_RLE_SKIP_ENCBASE : _gcInfoTypes.LIVESTATE_RLE_RUN_ENCBASE, ref bitOffset); skip = !skip; while (readSlots < numSlots) { uint cnt = NativeReader.DecodeVarLengthUnsigned(image, skip ? _gcInfoTypes.LIVESTATE_RLE_SKIP_ENCBASE : _gcInfoTypes.LIVESTATE_RLE_RUN_ENCBASE, ref bitOffset) + 1; if (report) { for (uint slotIndex = readSlots; slotIndex < readSlots + cnt; slotIndex++) { int trackedSlotIndex = 0; foreach (var slot in SlotTable.GcSlots) { if (slot.Flags != GcSlotFlags.GC_SLOT_UNTRACKED) { if (slotIndex == trackedSlotIndex) { liveSlots.Add(slot); break; } trackedSlotIndex++; } } } } readSlots += cnt; skip = !skip; report = !report; } Debug.Assert(readSlots == numSlots); result.Add(liveSlots); continue; } // Just a normal live state (1 bit per slot), so use the normal decoding loop } else { bitOffset += (int)(safePointIndex * numSlots); } for (uint slotIndex = 0; slotIndex < numSlots; slotIndex++) { bool isLive = NativeReader.ReadBits(image, 1, ref bitOffset) != 0; if (isLive) { int trackedSlotIndex = 0; foreach (var slot in SlotTable.GcSlots) { if (slot.Flags != GcSlotFlags.GC_SLOT_UNTRACKED) { if (slotIndex == trackedSlotIndex) { liveSlots.Add(slot); break; } trackedSlotIndex++; } } } } result.Add(liveSlots); } return(result); }
/// <summary> /// Initialize the GcInfo header /// based on <a href="https://github.com/dotnet/runtime/blob/main/src/coreclr/inc/gcdecoder.cpp">src\inc\gcdecoder.cpp</a> DecodeHeader and <a href="https://github.com/dotnet/runtime/blob/main/src/coreclr/gcdump/i386/gcdumpx86.cpp">GCDump::DumpInfoHdr</a> /// </summary> public static InfoHdrSmall DecodeHeader(byte[] image, ref int offset, int codeLength) { byte nextByte = image[offset++]; byte encoding = (byte)(nextByte & 0x7f); InfoHdrSmall header = GetInfoHdr(encoding); while ((nextByte & (uint)InfoHdrAdjustConstants.MORE_BYTES_TO_FOLLOW) != 0) { nextByte = image[offset++]; encoding = (byte)(nextByte & (uint)InfoHdrAdjustConstants.ADJ_ENCODING_MAX); if (encoding < (uint)InfoHdrAdjust.NEXT_FOUR_START) { if (encoding < (uint)InfoHdrAdjust.SET_ARGCOUNT) { header.FrameSize = (byte)(encoding - (uint)InfoHdrAdjust.SET_FRAMESIZE); } else if (encoding < (uint)InfoHdrAdjust.SET_PROLOGSIZE) { header.ArgCount = (byte)(encoding - (uint)InfoHdrAdjust.SET_ARGCOUNT); } else if (encoding < (uint)InfoHdrAdjust.SET_EPILOGSIZE) { header.PrologSize = (byte)(encoding - (uint)InfoHdrAdjust.SET_PROLOGSIZE); } else if (encoding < (uint)InfoHdrAdjust.SET_EPILOGCNT) { header.EpilogSize = (byte)(encoding - (uint)InfoHdrAdjust.SET_EPILOGSIZE); } else if (encoding < (uint)InfoHdrAdjust.SET_UNTRACKED) { header.EpilogCount = (byte)((encoding - (uint)InfoHdrAdjust.SET_EPILOGCNT) / 2); header.EpilogAtEnd = ((encoding - (uint)InfoHdrAdjust.SET_EPILOGCNT) & 1) == 1 ? true : false; } else if (encoding < (uint)InfoHdrAdjust.FIRST_FLIP) { header.UntrackedCnt = (byte)(encoding - (uint)InfoHdrAdjust.SET_UNTRACKED); } else { switch (encoding) { case (byte)InfoHdrAdjust.FLIP_EDI_SAVED: header.EdiSaved = !header.EdiSaved; break; case (byte)InfoHdrAdjust.FLIP_ESI_SAVED: header.EsiSaved = !header.EsiSaved; break; case (byte)InfoHdrAdjust.FLIP_EBX_SAVED: header.EbxSaved = !header.EbxSaved; break; case (byte)InfoHdrAdjust.FLIP_EBP_SAVED: header.EbpSaved = !header.EbpSaved; break; case (byte)InfoHdrAdjust.FLIP_EBP_FRAME: header.EbpFrame = !header.EbpFrame; break; case (byte)InfoHdrAdjust.FLIP_INTERRUPTIBLE: header.Interruptible = !header.Interruptible; break; case (byte)InfoHdrAdjust.FLIP_DOUBLE_ALIGN: header.DoubleAlign = !header.DoubleAlign; break; case (byte)InfoHdrAdjust.FLIP_SECURITY: header.Security = !header.Security; break; case (byte)InfoHdrAdjust.FLIP_HANDLERS: header.Handlers = !header.Handlers; break; case (byte)InfoHdrAdjust.FLIP_LOCALLOC: header.Localloc = !header.Localloc; break; case (byte)InfoHdrAdjust.FLIP_EDITnCONTINUE: header.EditNcontinue = !header.EditNcontinue; break; case (byte)InfoHdrAdjust.FLIP_VAR_PTR_TABLE_SZ: header.VarPtrTableSize ^= HAS_VARPTR; break; case (byte)InfoHdrAdjust.FFFF_UNTRACKED_CNT: header.UntrackedCnt = HAS_UNTRACKED; break; case (byte)InfoHdrAdjust.FLIP_VARARGS: header.Varargs = !header.Varargs; break; case (byte)InfoHdrAdjust.FLIP_PROF_CALLBACKS: header.ProfCallbacks = !header.ProfCallbacks; break; case (byte)InfoHdrAdjust.FLIP_HAS_GENERICS_CONTEXT: header.GenericsContext ^= 1; break; case (byte)InfoHdrAdjust.FLIP_GENERICS_CONTEXT_IS_METHODDESC: header.GenericsContextIsMethodDesc ^= 1; break; case (byte)InfoHdrAdjust.FLIP_HAS_GS_COOKIE: header.GsCookieOffset ^= HAS_GS_COOKIE_OFFSET; break; case (byte)InfoHdrAdjust.FLIP_SYNC: header.SyncStartOffset ^= HAS_SYNC_OFFSET; break; case (byte)InfoHdrAdjust.FLIP_REV_PINVOKE_FRAME: header.RevPInvokeOffset ^= HAS_REV_PINVOKE_FRAME_OFFSET; break; case (byte)InfoHdrAdjust.NEXT_OPCODE: nextByte = image[offset++]; encoding = (byte)(nextByte & (int)InfoHdrAdjustConstants.ADJ_ENCODING_MAX); // encoding here always corresponds to codes in InfoHdrAdjust2 set if (encoding < (int)InfoHdrAdjustConstants.SET_RET_KIND_MAX) { header.ReturnKind = (ReturnKinds)encoding; } else { throw new BadImageFormatException("Unexpected gcinfo header encoding"); } break; default: throw new BadImageFormatException("Unexpected gcinfo header encoding"); } } } else { byte lowBits; switch (encoding >> 4) { case 5: lowBits = (byte)(encoding & 0xf); header.FrameSize <<= 4; header.FrameSize += lowBits; break; case 6: lowBits = (byte)(encoding & 0xf); header.ArgCount <<= 4; header.ArgCount += lowBits; break; case 7: if ((encoding & 0x8) == 0) { lowBits = (byte)(encoding & 0x7); header.PrologSize <<= 3; header.PrologSize += lowBits; } else { lowBits = (byte)(encoding & 0x7); header.EpilogSize <<= 3; header.EpilogSize += lowBits; } break; default: throw new BadImageFormatException("Unexpected gcinfo header encoding"); } } } if (header.UntrackedCnt == HAS_UNTRACKED) { header.HasArgTabOffset = true; header.UntrackedCnt = NativeReader.DecodeUnsignedGc(image, ref offset); } if (header.VarPtrTableSize == HAS_VARPTR) { header.HasArgTabOffset = true; header.VarPtrTableSize = NativeReader.DecodeUnsignedGc(image, ref offset); } if (header.GsCookieOffset == HAS_GS_COOKIE_OFFSET) { header.GsCookieOffset = NativeReader.DecodeUnsignedGc(image, ref offset); } if (header.SyncStartOffset == HAS_SYNC_OFFSET) { header.SyncStartOffset = NativeReader.DecodeUnsignedGc(image, ref offset); header.SyncEndOffset = NativeReader.DecodeUnsignedGc(image, ref offset); } if (header.RevPInvokeOffset == HAS_REV_PINVOKE_FRAME_OFFSET) { header.RevPInvokeOffset = NativeReader.DecodeUnsignedGc(image, ref offset); } header.Epilogs = new List <int>(); if (header.EpilogCount > 1 || (header.EpilogCount != 0 && !header.EpilogAtEnd)) { uint offs = 0; for (int i = 0; i < header.EpilogCount; i++) { offs = NativeReader.DecodeUDelta(image, ref offset, offs); header.Epilogs.Add((int)offs); } } else { if (header.EpilogCount != 0) { header.Epilogs.Add(codeLength - (int)header.EpilogSize); } } if (header.HasArgTabOffset) { header.ArgTabOffset = NativeReader.DecodeUnsignedGc(image, ref offset); } return(header); }
private void GetTransitionsNoEbp(byte[] image, ref int offset) { uint curOffs = 0; uint lastSkip = 0; uint imask = 0; for (; ;) { uint val = image[offset++]; if ((val & 0x80) == 0) { if ((val & 0x40) == 0) { if ((val & 0x20) == 0) { // push 000DDDDD push one item, 5-bit delta curOffs += val & 0x1F; AddNewTransition(new GcTransitionRegister((int)curOffs, Registers.ESP, Action.PUSH)); } else { // push 00100000 [pushCount] ESP push multiple items uint pushCount = NativeReader.DecodeUnsignedGc(image, ref offset); AddNewTransition(new GcTransitionRegister((int)curOffs, Registers.ESP, Action.PUSH, false, false, (int)pushCount)); } } else { uint popSize; uint skip; if ((val & 0x3f) == 0) { // // skip 01000000 [Delta] Skip arbitrary sized delta // skip = NativeReader.DecodeUnsignedGc(image, ref offset); curOffs += skip; lastSkip = skip; } else { // pop 01CCDDDD pop CC items, 4-bit delta popSize = (val & 0x30) >> 4; skip = val & 0x0f; curOffs += skip; if (popSize > 0) { AddNewTransition(new GcTransitionRegister((int)curOffs, Registers.ESP, Action.POP, false, false, (int)popSize)); } else { lastSkip = skip; } } } } else { uint callArgCnt; uint callRegMask; bool callPndTab = false; uint callPndMask = 0; uint callPndTabCnt = 0, callPndTabSize = 0; switch ((val & 0x70) >> 4) { default: // // call 1PPPPPPP Call Pattern, P=[0..79] // CallPattern.DecodeCallPattern((val & 0x7f), out callArgCnt, out callRegMask, out callPndMask, out lastSkip); curOffs += lastSkip; SaveCallTransition(image, ref offset, val, curOffs, callRegMask, callPndTab, callPndTabCnt, callPndMask, lastSkip, ref imask); break; case 5: // // call 1101RRRR DDCCCMMM Call RegMask=RRRR,ArgCnt=CCC, // ArgMask=MMM Delta=commonDelta[DD] // callRegMask = val & 0xf; // EBP,EBX,ESI,EDI val = image[offset++]; callPndMask = (val & 0x7); callArgCnt = (val >> 3) & 0x7; lastSkip = CallPattern.callCommonDelta[val >> 6]; curOffs += lastSkip; SaveCallTransition(image, ref offset, val, curOffs, callRegMask, callPndTab, callPndTabCnt, callPndMask, lastSkip, ref imask); break; case 6: // // call 1110RRRR [ArgCnt] [ArgMask] // Call ArgCnt,RegMask=RRR,ArgMask // callRegMask = val & 0xf; // EBP,EBX,ESI,EDI callArgCnt = NativeReader.DecodeUnsignedGc(image, ref offset); callPndMask = NativeReader.DecodeUnsignedGc(image, ref offset); SaveCallTransition(image, ref offset, val, curOffs, callRegMask, callPndTab, callPndTabCnt, callPndMask, lastSkip, ref imask); break; case 7: switch (val & 0x0C) { case 0x00: // iptr 11110000 [IPtrMask] Arbitrary Interior Pointer Mask imask = NativeReader.DecodeUnsignedGc(image, ref offset); AddNewTransition(new IPtrMask((int)curOffs, imask)); break; case 0x04: AddNewTransition(new CalleeSavedRegister((int)curOffs, (CalleeSavedRegisters)(val & 0x3))); break; case 0x08: val = image[offset++]; callRegMask = val & 0xF; imask = val >> 4; lastSkip = NativeReader.ReadUInt32(image, ref offset); curOffs += lastSkip; callArgCnt = NativeReader.ReadUInt32(image, ref offset); callPndTabCnt = NativeReader.ReadUInt32(image, ref offset); callPndTabSize = NativeReader.ReadUInt32(image, ref offset); callPndTab = true; SaveCallTransition(image, ref offset, val, curOffs, callRegMask, callPndTab, callPndTabCnt, callPndMask, lastSkip, ref imask); break; case 0x0C: return; default: throw new BadImageFormatException("Invalid GC encoding"); } break; } } } }
/// <summary> /// based on <a href="https://github.com/dotnet/coreclr/blob/master/src/gcdump/i386/gcdumpx86.cpp">GCDump::DumpGCTable</a> /// </summary> private void GetTransitionsFullyInterruptible(byte[] image, ref int offset) { uint argCnt = 0; bool isThis = false; bool iptr = false; uint curOffs = 0; while (true) { uint isPop; uint argOffs; uint val = image[offset++]; if ((val & 0x80) == 0) { /* A small 'regPtr' encoding */ curOffs += val & 0x7; Action isLive = Action.LIVE; if ((val & 0x40) == 0) { isLive = Action.DEAD; } AddNewTransition(new GcTransitionRegister((int)curOffs, (Registers)((val >> 3) & 7), isLive, isThis, iptr)); isThis = false; iptr = false; continue; } /* This is probably an argument push/pop */ argOffs = (val & 0x38) >> 3; /* 6 [110] and 7 [111] are reserved for other encodings */ if (argOffs < 6) { /* A small argument encoding */ curOffs += (val & 0x07); isPop = (val & 0x40); ArgEncoding(image, ref isPop, ref argOffs, ref argCnt, ref curOffs, ref isThis, ref iptr); continue; } else if (argOffs == 6) { if ((val & 0x40) != 0) { curOffs += (((val & 0x07) + 1) << 3); } else { // non-ptr arg push curOffs += (val & 0x07); argCnt++; AddNewTransition(new GcTransitionPointer((int)curOffs, argOffs, argCnt, Action.PUSH, Header.EbpFrame, false, false, false)); } continue; } // argOffs was 7 [111] which is reserved for the larger encodings switch (val) { case 0xFF: return; case 0xBC: isThis = true; break; case 0xBF: iptr = true; break; case 0xB8: val = NativeReader.DecodeUnsignedGc(image, ref offset); curOffs += val; break; case 0xF8: case 0xFC: isPop = val & 0x04; argOffs = NativeReader.DecodeUnsignedGc(image, ref offset); ArgEncoding(image, ref isPop, ref argOffs, ref argCnt, ref curOffs, ref isThis, ref iptr); break; case 0xFD: argOffs = NativeReader.DecodeUnsignedGc(image, ref offset); AddNewTransition(new GcTransitionPointer((int)curOffs, argOffs, argCnt, Action.KILL, Header.EbpFrame)); break; case 0xF9: argOffs = NativeReader.DecodeUnsignedGc(image, ref offset); argCnt += argOffs; break; default: throw new BadImageFormatException($"Unexpected special code {val}"); } } }
private unsafe int PatchStatics(TileMatrix matrix, string dataPath, string indexPath, string lookupPath) { using var staticsDataStream = new FileStream(dataPath, FileMode.Open, FileAccess.Read, FileShare.Read); using var staticsIndexStream = new FileStream(indexPath, FileMode.Open, FileAccess.Read, FileShare.Read); using var staticsLookupStream = new FileStream(lookupPath, FileMode.Open, FileAccess.Read, FileShare.Read); var staticsIndexReader = new BinaryReader(staticsIndexStream); var staticsLookupReader = new BinaryReader(staticsLookupStream); var count = (int)(staticsIndexReader.BaseStream.Length / 4); var lists = new TileList[8][]; for (var x = 0; x < 8; ++x) { lists[x] = new TileList[8]; for (var y = 0; y < 8; ++y) { lists[x][y] = new TileList(); } } for (var i = 0; i < count; ++i) { var blockID = staticsIndexReader.ReadInt32(); var blockX = blockID / matrix.BlockHeight; var blockY = blockID % matrix.BlockHeight; var offset = staticsLookupReader.ReadInt32(); var length = staticsLookupReader.ReadInt32(); staticsLookupReader.ReadInt32(); // Extra if (offset < 0 || length <= 0) { matrix.SetStaticBlock(blockX, blockY, matrix.EmptyStaticBlock); continue; } staticsDataStream.Seek(offset, SeekOrigin.Begin); var tileCount = length / 7; if (_tileBuffer.Length < tileCount) { _tileBuffer = new StaticTile[tileCount]; } var staTiles = _tileBuffer; fixed(StaticTile *pTiles = staTiles) { NativeReader.Read(staticsDataStream.SafeFileHandle.DangerousGetHandle(), pTiles, length); StaticTile *pCur = pTiles, pEnd = pTiles + tileCount; while (pCur < pEnd) { lists[pCur->X & 0x7][pCur->Y & 0x7].Add(pCur->Id, (sbyte)pCur->Z); pCur += 1; } var tiles = new StaticTile[8][][]; for (var x = 0; x < 8; ++x) { tiles[x] = new StaticTile[8][]; for (var y = 0; y < 8; ++y) { tiles[x][y] = lists[x][y].ToArray(); } } matrix.SetStaticBlock(blockX, blockY, tiles); } } staticsIndexReader.Close(); staticsLookupReader.Close(); return(count); }
public static uint Read(this NativeReader reader, uint offset, out long value) { return(reader.DecodeSignedLong(offset, out value)); }
private static void HighLevelDebugFuncEvalHelper() { uint parameterBufferSize = RuntimeAugments.RhpGetFuncEvalParameterBufferSize(); IntPtr writeParameterCommandPointer; IntPtr debuggerBufferPointer; unsafe { byte *debuggerBufferRawPointer = stackalloc byte[(int)parameterBufferSize]; debuggerBufferPointer = new IntPtr(debuggerBufferRawPointer); WriteParameterCommand writeParameterCommand = new WriteParameterCommand { commandCode = 1, bufferAddress = debuggerBufferPointer.ToInt64() }; writeParameterCommandPointer = new IntPtr(&writeParameterCommand); RuntimeAugments.RhpSendCustomEventToDebugger(writeParameterCommandPointer, Unsafe.SizeOf <WriteParameterCommand>()); // .. debugger magic ... the debuggerBuffer will be filled with parameter data TypesAndValues typesAndValues = new TypesAndValues(); uint trash; uint parameterCount; uint parameterValue; uint eeTypeCount; ulong eeType; uint offset = 0; NativeReader reader = new NativeReader(debuggerBufferRawPointer, parameterBufferSize); offset = reader.DecodeUnsigned(offset, out trash); // The VertexSequence always generate a length, I don't really need it. offset = reader.DecodeUnsigned(offset, out parameterCount); typesAndValues.parameterValues = new int[parameterCount]; for (int i = 0; i < parameterCount; i++) { offset = reader.DecodeUnsigned(offset, out parameterValue); typesAndValues.parameterValues[i] = (int)parameterValue; } offset = reader.DecodeUnsigned(offset, out eeTypeCount); for (int i = 0; i < eeTypeCount; i++) { // TODO: Stuff these eeType values into the external reference table offset = reader.DecodeUnsignedLong(offset, out eeType); } TypeSystemContext typeSystemContext = TypeSystemContextFactory.Create(); bool hasThis; TypeDesc[] parameters; bool[] parametersWithGenericDependentLayout; bool result = TypeLoaderEnvironment.Instance.GetCallingConverterDataFromMethodSignature_NativeLayout_Debugger(typeSystemContext, RuntimeSignature.CreateFromNativeLayoutSignatureForDebugger(offset), Instantiation.Empty, Instantiation.Empty, out hasThis, out parameters, out parametersWithGenericDependentLayout, reader); typesAndValues.types = new RuntimeTypeHandle[parameters.Length]; bool needToDynamicallyLoadTypes = false; for (int i = 0; i < typesAndValues.types.Length; i++) { if (!parameters[i].RetrieveRuntimeTypeHandleIfPossible()) { needToDynamicallyLoadTypes = true; break; } typesAndValues.types[i] = parameters[i].GetRuntimeTypeHandle(); } if (needToDynamicallyLoadTypes) { TypeLoaderEnvironment.Instance.RunUnderTypeLoaderLock(() => { typeSystemContext.FlushTypeBuilderStates(); GenericDictionaryCell[] cells = new GenericDictionaryCell[parameters.Length]; for (int i = 0; i < cells.Length; i++) { cells[i] = GenericDictionaryCell.CreateTypeHandleCell(parameters[i]); } IntPtr[] eetypePointers; TypeBuilder.ResolveMultipleCells(cells, out eetypePointers); for (int i = 0; i < parameters.Length; i++) { typesAndValues.types[i] = ((EEType *)eetypePointers[i])->ToRuntimeTypeHandle(); } }); } TypeSystemContextFactory.Recycle(typeSystemContext); LocalVariableType[] argumentTypes = new LocalVariableType[parameters.Length]; for (int i = 0; i < parameters.Length; i++) { // TODO: What these false really means? Need to make sure our format contains those information argumentTypes[i] = new LocalVariableType(typesAndValues.types[i], false, false); } LocalVariableSet.SetupArbitraryLocalVariableSet <TypesAndValues>(HighLevelDebugFuncEvalHelperWithVariables, ref typesAndValues, argumentTypes); } }
public unsafe LowLevelNativeFormatReader(byte *buffer, uint bufferSize) { _nativeReader = new NativeReader(buffer, bufferSize); _offset = 0; }
private static MethodNameAndSignature GetMethodNameAndSignatureFromNativeReader(NativeReader nativeLayoutReader, TypeManagerHandle moduleHandle, uint nativeLayoutOffset) { NativeParser parser = new NativeParser(nativeLayoutReader, nativeLayoutOffset); string methodName = parser.GetString(); // Signatures are indirected to through a relative offset so that we don't have to parse them // when not comparing signatures (parsing them requires resolving types and is tremendously // expensive). NativeParser sigParser = parser.GetParserFromRelativeOffset(); RuntimeSignature methodSig = RuntimeSignature.CreateFromNativeLayoutSignature(moduleHandle, sigParser.Offset); return(new MethodNameAndSignature(methodName, methodSig)); }
private unsafe static bool TryGetNativeReaderForBlob(IntPtr module, ReflectionMapBlob blob, out NativeReader reader) { byte *pBlob; uint cbBlob; if (RuntimeAugments.FindBlob(module, (int)blob, (IntPtr)(&pBlob), (IntPtr)(&cbBlob))) { reader = new NativeReader(pBlob, cbBlob); return(true); } reader = default(NativeReader); return(false); }
private static async void OnImportSoundCommand(bool forceMono) { var asset = _currentEditor.Asset; var soundWave = (SoundWaveAsset)asset.RootObject; byte chunkIndex = 0; if (soundWave.Localization != null && soundWave.Localization.Count > 0) { var english = soundWave.Localization[0]; chunkIndex = soundWave.RuntimeVariations[english.FirstVariationIndex].ChunkIndex; } var chunk = soundWave.Chunks[chunkIndex]; var chunkEntry = App.AssetManager.GetChunkEntry(chunk.ChunkId); var ofd = new OpenFileDialog(); ofd.Filter = "All Media Files|*.wav;*.mp3"; ofd.Title = "Open Audio"; ofd.Multiselect = true; if (ofd.ShowDialog(_mainWindow) != true) { return; } FrostyTask2.Begin("Importing Chunk", ""); await Task.Run(() => { var imports = new List <SoundImport>(); var totalChunkSize = 0u; foreach (var fileName in ofd.FileNames) { var tempFile = Path.GetTempFileName(); #if DEBUG var tempFile2 = Path.GetTempFileName(); var decoder = new CSCore.Ffmpeg.FfmpegDecoder(fileName); var source = decoder.ChangeSampleRate(48000); if (forceMono) { decoder.ToMono(); } using (var encoder = MediaFoundationEncoder.CreateMP3Encoder(source.WaveFormat, tempFile2)) { var buffer = new byte[source.WaveFormat.BytesPerSecond]; int read; while ((read = source.Read(buffer, 0, buffer.Length)) > 0) { encoder.Write(buffer, 0, read); } } #else var tempFile2 = fileName; #endif try { var fileNameEncoded = EncodeParameterArgument(tempFile2); App.Logger.Log($"- \"{fileNameEncoded}\""); var result = Primrose.Utility.ExternalTool.Run(@"dandev-el3.exe", $"{fileNameEncoded} -o {tempFile}", out var stdout, out var stderr); if (!string.IsNullOrEmpty(stderr)) { App.Logger.LogError(stderr); } if (result == 0) { using (var nativeReader = new NativeReader( new FileStream(tempFile, FileMode.Open, FileAccess.Read))) { var end = nativeReader.ReadToEnd(); if (end.Length > 0 && end[0] == 0x48) { var lines = stdout.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); foreach (var line in lines) { App.Logger.Log("> " + line); } var chunkSize = uint.Parse(lines.First(l => l.StartsWith("ChunkSize:")).Substring(10)); var segmentLength = float.Parse(lines.First(l => l.StartsWith("SegmentLength:")).Substring(15)); imports.Add(new SoundImport { SourceFile = fileName, Chunk = end, ChunkOffset = totalChunkSize, ChunkSize = chunkSize, SegmentLength = segmentLength }); totalChunkSize += chunkSize; } } } } catch (Exception e) { App.Logger.LogError(e.Message); App.Logger.LogError(e.StackTrace); } finally { try { File.Delete(tempFile); } catch (Exception) { /* ignored */ } try { File.Delete(tempFile2); } catch (Exception) { /* ignored */ } } } if (soundWave.Localization.Count > 0) { var english = soundWave.Localization[0]; if (soundWave.Localization.Count > 1) { soundWave.Localization.RemoveRange(1, soundWave.Localization.Count - 1); } english.FirstVariationIndex = 0; english.VariationCount = (ushort)imports.Count; } soundWave.Segments.Clear(); soundWave.RuntimeVariations.Clear(); var combinedChunk = new byte[totalChunkSize]; for (var i = 0; i < imports.Count; i++) { var import = imports[i]; App.Logger.Log($"Import[{i}] - SampleOffset: {import.ChunkOffset} - SegmentLength: {import.SegmentLength} - SourceFile: {import.SourceFile}"); soundWave.Segments.Add(new SoundWaveVariationSegment { SamplesOffset = import.ChunkOffset, SeekTableOffset = uint.MaxValue, SegmentLength = import.SegmentLength, }); soundWave.RuntimeVariations.Add(new SoundWaveRuntimeVariation { ChunkIndex = chunkIndex, FirstLoopSegmentIndex = 0, FirstSegmentIndex = (ushort)i, LastLoopSegmentIndex = 0, PersistentDataSize = 0, SegmentCount = 1, Weight = 100, }); Debug.Assert(import.ChunkSize == import.Chunk.Length); Array.Copy(import.Chunk, 0, combinedChunk, (int)import.ChunkOffset, import.ChunkSize); } App.AssetManager.ModifyChunk(chunkEntry.Id, combinedChunk); chunk.ChunkSize = totalChunkSize; asset.Update(); _app.Dispatcher.InvokeAsync(() => { App.AssetManager.ModifyEbx(_currentEditor.AssetEntry.Name, asset); }); }); FrostyTask2.End(); }
private static unsafe bool TryGetNativeReaderForBlob(TypeManagerHandle module, ReflectionMapBlob blob, out NativeReader reader) { byte *pBlob; uint cbBlob; if (RuntimeImports.RhFindBlob(module, (uint)blob, &pBlob, &cbBlob)) { reader = new NativeReader(pBlob, cbBlob); return(true); } reader = default(NativeReader); return(false); }
internal bool GetCallingConverterDataFromMethodSignature_NativeLayout_Common(TypeSystemContext context, RuntimeSignature methodSig, Instantiation typeInstantiation, Instantiation methodInstantiation, out bool hasThis, out TypeDesc[] parameters, out bool[] parametersWithGenericDependentLayout, NativeReader nativeReader, ulong[] debuggerPreparedExternalReferences) { bool isNotDebuggerCall = nativeReader == null; hasThis = false; parameters = null; NativeLayoutInfoLoadContext nativeLayoutContext = new NativeLayoutInfoLoadContext(); nativeLayoutContext._module = isNotDebuggerCall ? (NativeFormatModuleInfo)methodSig.GetModuleInfo() : null; nativeLayoutContext._typeSystemContext = context; nativeLayoutContext._typeArgumentHandles = typeInstantiation; nativeLayoutContext._methodArgumentHandles = methodInstantiation; nativeLayoutContext._debuggerPreparedExternalReferences = debuggerPreparedExternalReferences; NativeReader reader = isNotDebuggerCall ? GetNativeLayoutInfoReader(methodSig) : nativeReader; NativeFormatModuleInfo module = isNotDebuggerCall ? ModuleList.Instance.GetModuleInfoByHandle(new TypeManagerHandle(methodSig.ModuleHandle)) : null; NativeParser parser = new NativeParser(reader, methodSig.NativeLayoutOffset); MethodCallingConvention callingConvention = (MethodCallingConvention)parser.GetUnsigned(); hasThis = !callingConvention.HasFlag(MethodCallingConvention.Static); uint numGenArgs = callingConvention.HasFlag(MethodCallingConvention.Generic) ? parser.GetUnsigned() : 0; uint parameterCount = parser.GetUnsigned(); parameters = new TypeDesc[parameterCount + 1]; parametersWithGenericDependentLayout = new bool[parameterCount + 1]; // One extra parameter to account for the return type for (uint i = 0; i <= parameterCount; i++) { // NativeParser is a struct, so it can be copied. NativeParser parserCopy = parser; // Parse the signature twice. The first time to find out the exact type of the signature // The second time to identify if the parameter loaded via the signature should be forced to be // passed byref as part of the universal generic calling convention. parameters[i] = GetConstructedTypeFromParserAndNativeLayoutContext(ref parser, nativeLayoutContext); parametersWithGenericDependentLayout[i] = TypeSignatureHasVarsNeedingCallingConventionConverter(ref parserCopy, module, context, HasVarsInvestigationLevel.Parameter); if (parameters[i] == null) { return(false); } } return(true); }
public static uint Read(this NativeReader reader, uint offset, out byte value) { value = reader.ReadUInt8(offset); return(offset + 1); }
static public uint Read(this NativeReader reader, uint offset, out string value) { return(reader.DecodeString(offset, out value)); }
public static uint Read(this NativeReader reader, uint offset, out float value) { value = reader.ReadFloat(offset); return(offset + 4); }
public UnwindInfo(byte[] image, int offset) { FunctionLength = NativeReader.DecodeUnsignedGc(image, ref offset); Size = sizeof(int); }
private static unsafe bool TryGetNativeReaderForBlob(NativeFormatModuleInfo module, ReflectionMapBlob blob, out NativeReader reader) { byte *pBlob; uint cbBlob; if (module.TryFindBlob((int)blob, out pBlob, out cbBlob)) { reader = new NativeReader(pBlob, cbBlob); return(true); } reader = default(NativeReader); return(false); }
private bool FindMatchingInterfaceSlot(NativeFormatModuleInfo module, NativeReader nativeLayoutReader, ref NativeParser entryParser, ref ExternalReferencesTable extRefs, ref RuntimeTypeHandle declaringType, ref MethodNameAndSignature methodNameAndSignature, RuntimeTypeHandle instanceTypeHandle, RuntimeTypeHandle openTargetTypeHandle, RuntimeTypeHandle[] targetTypeInstantiation, bool variantDispatch, bool defaultMethods) { uint numTargetImplementations = entryParser.GetUnsigned(); #if GVM_RESOLUTION_TRACE Debug.WriteLine(" :: Declaring type = " + GetTypeNameDebug(declaringType)); Debug.WriteLine(" :: Target type = " + GetTypeNameDebug(openTargetTypeHandle)); #endif for (uint j = 0; j < numTargetImplementations; j++) { uint nameAndSigToken = entryParser.GetUnsigned(); MethodNameAndSignature targetMethodNameAndSignature = null; RuntimeTypeHandle targetTypeHandle = default; bool isDefaultInterfaceMethodImplementation; if (nameAndSigToken != SpecialGVMInterfaceEntry.Diamond && nameAndSigToken != SpecialGVMInterfaceEntry.Reabstraction) { targetMethodNameAndSignature = GetMethodNameAndSignatureFromNativeReader(nativeLayoutReader, module.Handle, nameAndSigToken); targetTypeHandle = extRefs.GetRuntimeTypeHandleFromIndex(entryParser.GetUnsigned()); isDefaultInterfaceMethodImplementation = RuntimeAugments.IsInterface(targetTypeHandle); #if GVM_RESOLUTION_TRACE Debug.WriteLine(" Searching for GVM implementation on targe type = " + GetTypeNameDebug(targetTypeHandle)); #endif } else { isDefaultInterfaceMethodImplementation = true; } uint numIfaceImpls = entryParser.GetUnsigned(); for (uint k = 0; k < numIfaceImpls; k++) { RuntimeTypeHandle implementingTypeHandle = extRefs.GetRuntimeTypeHandleFromIndex(entryParser.GetUnsigned()); #if GVM_RESOLUTION_TRACE Debug.WriteLine(" -> Current implementing type = " + GetTypeNameDebug(implementingTypeHandle)); #endif uint numIfaceSigs = entryParser.GetUnsigned(); if (!openTargetTypeHandle.Equals(implementingTypeHandle) || defaultMethods != isDefaultInterfaceMethodImplementation) { // Skip over signatures data for (uint l = 0; l < numIfaceSigs; l++) { entryParser.GetUnsigned(); } continue; } for (uint l = 0; l < numIfaceSigs; l++) { RuntimeTypeHandle currentIfaceTypeHandle = default(RuntimeTypeHandle); NativeParser ifaceSigParser = new NativeParser(nativeLayoutReader, entryParser.GetUnsigned()); if (TypeLoaderEnvironment.Instance.GetTypeFromSignatureAndContext(ref ifaceSigParser, module.Handle, targetTypeInstantiation, null, out currentIfaceTypeHandle)) { #if GVM_RESOLUTION_TRACE Debug.WriteLine(" -> Current interface on type = " + GetTypeNameDebug(currentIfaceTypeHandle)); #endif Debug.Assert(!currentIfaceTypeHandle.IsNull()); if ((!variantDispatch && declaringType.Equals(currentIfaceTypeHandle)) || (variantDispatch && RuntimeAugments.IsAssignableFrom(declaringType, currentIfaceTypeHandle))) { #if GVM_RESOLUTION_TRACE Debug.WriteLine(" " + (declaringType.Equals(currentIfaceTypeHandle) ? "Exact" : "Variant-compatible") + " match found on this target type!"); #endif if (targetMethodNameAndSignature == null) { if (nameAndSigToken == SpecialGVMInterfaceEntry.Diamond) { throw new AmbiguousImplementationException(); } else { Debug.Assert(nameAndSigToken == SpecialGVMInterfaceEntry.Reabstraction); throw new EntryPointNotFoundException(); } } // We found the GVM slot target for the input interface GVM call, so let's update the interface GVM slot and return success to the caller if (!RuntimeAugments.IsInterface(targetTypeHandle) || !RuntimeAugments.IsGenericTypeDefinition(targetTypeHandle)) { // Not a default interface method or default interface method on a non-generic type. // We have a usable type handle. declaringType = targetTypeHandle; } else if (RuntimeAugments.IsGenericType(currentIfaceTypeHandle) && RuntimeAugments.GetGenericDefinition(currentIfaceTypeHandle).Equals(targetTypeHandle)) { // Default interface method implemented on the same type that declared the slot. // Use the instantiation as-is from what we found. declaringType = currentIfaceTypeHandle; } else { declaringType = default; // Default interface method implemented on a different generic interface. // We need to find a usable instantiation. There should be only one match because we // would be dealing with a diamond otherwise. int numInstanceInterfaces = RuntimeAugments.GetInterfaceCount(instanceTypeHandle); for (int instIntfIndex = 0; instIntfIndex < numInstanceInterfaces; instIntfIndex++) { RuntimeTypeHandle instIntf = RuntimeAugments.GetInterface(instanceTypeHandle, instIntfIndex); if (RuntimeAugments.IsGenericType(instIntf) && RuntimeAugments.GetGenericDefinition(instIntf).Equals(targetTypeHandle)) { // Got a potential interface. Check if the implementing interface is in the interface // list. We don't want IsAssignableFrom because we need an exact match. int numIntInterfaces = RuntimeAugments.GetInterfaceCount(instIntf); for (int intIntfIndex = 0; intIntfIndex < numIntInterfaces; intIntfIndex++) { if (RuntimeAugments.GetInterface(instIntf, intIntfIndex).Equals(currentIfaceTypeHandle)) { Debug.Assert(declaringType.IsNull()); declaringType = instIntf; #if !DEBUG break; #endif } } #if !DEBUG if (!declaringType.IsNull()) { break; } #endif } } Debug.Assert(!declaringType.IsNull()); } methodNameAndSignature = targetMethodNameAndSignature; return(true); } } } } } return(false); }
/// <summary> /// based on <a href="https://github.com/dotnet/coreclr/blob/master/src/gcdump/i386/gcdumpx86.cpp">GCDump::DumpGCTable</a> /// </summary> private void GetTransitionsEbpFrame(byte[] image, ref int offset) { while (true) { uint argMask = 0, byrefArgMask = 0; uint regMask, byrefRegMask = 0; uint argCnt = 0; int argOffset = offset; uint argTabSize; uint val, nxt; uint curOffs = 0; // Get the next byte and check for a 'special' entry uint encType = image[offset++]; GcTransitionCall transition = null; switch (encType) { default: // A tiny or small call entry val = encType; if ((val & 0x80) == 0x00) { if ((val & 0x0F) != 0) { // A tiny call entry curOffs += (val & 0x0F); regMask = (val & 0x70) >> 4; argMask = 0; } else { Registers reg; if ((val & 0x10) != 0) { reg = Registers.EDI; } else if ((val & 0x20) != 0) { reg = Registers.ESI; } else if ((val & 0x40) != 0) { reg = Registers.EBX; } else { throw new BadImageFormatException("Invalid register"); } transition = new GcTransitionCall((int)curOffs); transition.CallRegisters.Add(new GcTransitionCall.CallRegister(reg, false)); AddNewTransition(transition); continue; } } else { // A small call entry curOffs += (val & 0x7F); val = image[offset++]; regMask = val >> 5; argMask = val & 0x1F; } break; case 0xFD: // medium encoding argMask = image[offset++]; val = image[offset++]; argMask |= (val & 0xF0) << 4; nxt = image[offset++]; curOffs += (val & 0x0F) + ((nxt & 0x1F) << 4); regMask = nxt >> 5; // EBX,ESI,EDI break; case 0xF9: // medium encoding with byrefs curOffs += image[offset++]; val = image[offset++]; argMask = val & 0x1F; regMask = val >> 5; val = image[offset++]; byrefArgMask = val & 0x1F; byrefRegMask = val >> 5; break; case 0xFE: // large encoding case 0xFA: // large encoding with byrefs val = image[offset++]; regMask = val & 0x7; byrefRegMask = val >> 4; curOffs += NativeReader.ReadUInt32(image, ref offset); argMask = NativeReader.ReadUInt32(image, ref offset); if (encType == 0xFA) // read byrefArgMask { byrefArgMask = NativeReader.ReadUInt32(image, ref offset); } break; case 0xFB: // huge encoding val = image[offset++]; regMask = val & 0x7; byrefRegMask = val >> 4; curOffs = NativeReader.ReadUInt32(image, ref offset); argCnt = NativeReader.ReadUInt32(image, ref offset); argTabSize = NativeReader.ReadUInt32(image, ref offset); argOffset = offset; offset += (int)argTabSize; break; case 0xFF: return; } /* * Here we have the following values: * * curOffs ... the code offset of the call * regMask ... mask of live pointer register variables * argMask ... bitmask of pushed pointer arguments * byrefRegMask ... byref qualifier for regMask * byrefArgMask ... byrer qualifier for argMask */ transition = new GcTransitionCall((int)curOffs, Header.EbpFrame, regMask, byrefRegMask); AddNewTransition(transition); if (argCnt != 0) { do { val = NativeReader.DecodeUnsignedGc(image, ref argOffset); uint stkOffs = val & ~byref_OFFSET_FLAG; uint lowBit = val & byref_OFFSET_FLAG; transition.PtrArgs.Add(new GcTransitionCall.PtrArg(stkOffs, lowBit)); }while (--argCnt > 0); } else { transition.ArgMask = argMask; if (byrefArgMask != 0) { transition.IArgs = byrefArgMask; } } } }
private InstantiatedMethod TryGetGenericMethodTemplate_Internal(InstantiatedMethod concreteMethod, CanonicalFormKind kind, out NativeFormatModuleInfo nativeLayoutInfoModule, out uint nativeLayoutInfoToken) { nativeLayoutInfoModule = null; nativeLayoutInfoToken = 0; var canonForm = concreteMethod.GetCanonMethodTarget(kind); var hashCode = canonForm.GetHashCode(); foreach (NativeFormatModuleInfo moduleInfo in ModuleList.EnumerateModules()) { NativeReader nativeLayoutReader = TypeLoaderEnvironment.Instance.GetNativeLayoutInfoReader(moduleInfo.Handle); if (nativeLayoutReader == null) { continue; } NativeHashtable genericMethodTemplatesHashtable = LoadHashtable(moduleInfo, ReflectionMapBlob.GenericMethodsTemplateMap, out _); if (genericMethodTemplatesHashtable.IsNull) { continue; } var context = new NativeLayoutInfoLoadContext { _typeSystemContext = concreteMethod.Context, _typeArgumentHandles = concreteMethod.OwningType.Instantiation, _methodArgumentHandles = concreteMethod.Instantiation, _module = moduleInfo }; var enumerator = genericMethodTemplatesHashtable.Lookup(hashCode); NativeParser entryParser; while (!(entryParser = enumerator.GetNext()).IsNull) { var methodSignatureParser = new NativeParser(nativeLayoutReader, entryParser.GetUnsigned()); // Get the unified generic method holder and convert it to its canonical form var candidateTemplate = (InstantiatedMethod)context.GetMethod(ref methodSignatureParser); Debug.Assert(candidateTemplate.Instantiation.Length > 0); if (canonForm == candidateTemplate.GetCanonMethodTarget(kind)) { TypeLoaderLogger.WriteLine("Found template for generic method " + concreteMethod.ToString() + ": " + candidateTemplate.ToString()); nativeLayoutInfoModule = moduleInfo; nativeLayoutInfoToken = entryParser.GetUnsigned(); if (nativeLayoutInfoToken == BadTokenFixupValue) { // TODO: once multifile gets fixed up, make this throw a BadImageFormatException TypeLoaderLogger.WriteLine("ERROR: template not fixed up, skipping"); continue; } Debug.Assert( (kind != CanonicalFormKind.Universal) || (kind == CanonicalFormKind.Universal && candidateTemplate == candidateTemplate.GetCanonMethodTarget(kind))); return(candidateTemplate); } } } TypeLoaderLogger.WriteLine("ERROR: Cannot find a suitable template for generic method " + concreteMethod.ToString()); return(null); }
private bool FindMatchingInterfaceSlot(NativeFormatModuleInfo module, NativeReader nativeLayoutReader, ref NativeParser entryParser, ref ExternalReferencesTable extRefs, ref RuntimeTypeHandle declaringType, ref MethodNameAndSignature methodNameAndSignature, RuntimeTypeHandle openTargetTypeHandle, RuntimeTypeHandle[] targetTypeInstantiation, bool variantDispatch) { uint numTargetImplementations = entryParser.GetUnsigned(); for (uint j = 0; j < numTargetImplementations; j++) { uint nameAndSigToken = extRefs.GetExternalNativeLayoutOffset(entryParser.GetUnsigned()); MethodNameAndSignature targetMethodNameAndSignature = GetMethodNameAndSignatureFromNativeReader(nativeLayoutReader, module.Handle, nameAndSigToken); RuntimeTypeHandle targetTypeHandle = extRefs.GetRuntimeTypeHandleFromIndex(entryParser.GetUnsigned()); #if REFLECTION_EXECUTION_TRACE ReflectionExecutionLogger.WriteLine(" Searching for GVM implementation on targe type = " + GetTypeNameDebug(targetTypeHandle)); #endif uint numIfaceImpls = entryParser.GetUnsigned(); for (uint k = 0; k < numIfaceImpls; k++) { RuntimeTypeHandle implementingTypeHandle = extRefs.GetRuntimeTypeHandleFromIndex(entryParser.GetUnsigned()); uint numIfaceSigs = entryParser.GetUnsigned(); if (!openTargetTypeHandle.Equals(implementingTypeHandle)) { // Skip over signatures data for (uint l = 0; l < numIfaceSigs; l++) { entryParser.GetUnsigned(); } continue; } for (uint l = 0; l < numIfaceSigs; l++) { RuntimeTypeHandle currentIfaceTypeHandle = default(RuntimeTypeHandle); NativeParser ifaceSigParser = new NativeParser(nativeLayoutReader, extRefs.GetExternalNativeLayoutOffset(entryParser.GetUnsigned())); if (TypeLoaderEnvironment.Instance.GetTypeFromSignatureAndContext(ref ifaceSigParser, module.Handle, targetTypeInstantiation, null, out currentIfaceTypeHandle)) { Debug.Assert(!currentIfaceTypeHandle.IsNull()); if ((!variantDispatch && declaringType.Equals(currentIfaceTypeHandle)) || (variantDispatch && RuntimeAugments.IsAssignableFrom(declaringType, currentIfaceTypeHandle))) { #if REFLECTION_EXECUTION_TRACE ReflectionExecutionLogger.WriteLine(" " + (declaringType.Equals(currentIfaceTypeHandle) ? "Exact" : "Variant-compatible") + " match found on this target type!"); #endif // We found the GVM slot target for the input interface GVM call, so let's update the interface GVM slot and return success to the caller declaringType = targetTypeHandle; methodNameAndSignature = targetMethodNameAndSignature; return(true); } } } } } return(false); }
private unsafe static void NewParameterizedArray(byte *parameterBuffer, uint parameterBufferSize) { uint offset = 0; NativeReader reader = new NativeReader(parameterBuffer, parameterBufferSize); ulong[] debuggerPreparedExternalReferences; offset = BuildDebuggerPreparedExternalReferences(reader, offset, out debuggerPreparedExternalReferences); NativeLayoutInfoLoadContext nativeLayoutContext = new NativeLayoutInfoLoadContext(); TypeSystemContext typeSystemContext = TypeSystemContextFactory.Create(); nativeLayoutContext._module = null; nativeLayoutContext._typeSystemContext = typeSystemContext; nativeLayoutContext._typeArgumentHandles = Instantiation.Empty; nativeLayoutContext._methodArgumentHandles = Instantiation.Empty; nativeLayoutContext._debuggerPreparedExternalReferences = debuggerPreparedExternalReferences; NativeParser parser = new NativeParser(reader, offset); TypeDesc arrElementType = TypeLoaderEnvironment.Instance.GetConstructedTypeFromParserAndNativeLayoutContext(ref parser, nativeLayoutContext); TypeSystemContextFactory.Recycle(typeSystemContext); uint rank = parser.GetUnsigned(); int[] dims = new int[rank]; int[] lowerBounds = new int[rank]; for (uint i = 0; i < rank; ++i) { dims[i] = (int)parser.GetUnsigned(); } for (uint i = 0; i < rank; ++i) { lowerBounds[i] = (int)parser.GetUnsigned(); } RuntimeTypeHandle typeHandle = arrElementType.GetRuntimeTypeHandle(); RuntimeTypeHandle arrayTypeHandle = default(RuntimeTypeHandle); Array returnValue; // Get an array RuntimeTypeHandle given an element's RuntimeTypeHandle and rank. // Pass false for isMdArray, and rank == -1 for SzArrays bool succeed = false; if (rank == 1 && lowerBounds[0] == 0) { succeed = TypeLoaderEnvironment.Instance.TryGetArrayTypeForElementType( typeHandle, false, -1, out arrayTypeHandle); Debug.Assert(succeed); returnValue = Internal.Runtime.Augments.RuntimeAugments.NewArray( arrayTypeHandle, dims[0]); } else { succeed = TypeLoaderEnvironment.Instance.TryGetArrayTypeForElementType( typeHandle, true, (int)rank, out arrayTypeHandle ); Debug.Assert(succeed); returnValue = Internal.Runtime.Augments.RuntimeAugments.NewMultiDimArray( arrayTypeHandle, dims, lowerBounds ); } GCHandle returnValueHandle = GCHandle.Alloc(returnValue); IntPtr returnValueHandlePointer = GCHandle.ToIntPtr(returnValueHandle); uint returnHandleIdentifier = RuntimeAugments.RhpRecordDebuggeeInitiatedHandle(returnValueHandlePointer); ReturnToDebuggerWithReturn(returnHandleIdentifier, returnValueHandlePointer, false); }
/// <summary> /// based on <a href="https://github.com/dotnet/coreclr/blob/master/src/vm/gcinfodecoder.cpp">GcInfoDecoder::GcInfoDecoder</a> /// </summary> public GcInfo(byte[] image, int offset, Machine machine, ushort majorVersion) { Offset = offset; _gcInfoTypes = new GcInfoTypes(machine); _machine = machine; SecurityObjectStackSlot = -1; GSCookieStackSlot = -1; PSPSymStackSlot = -1; SecurityObjectStackSlot = -1; GenericsInstContextStackSlot = -1; StackBaseRegister = 0xffffffff; SizeOfEditAndContinuePreservedArea = 0xffffffff; ReversePInvokeFrameStackSlot = -1; Version = ReadyToRunVersionToGcInfoVersion(majorVersion); int bitOffset = offset * 8; int startBitOffset = bitOffset; ParseHeaderFlags(image, ref bitOffset); if (Version >= MIN_GCINFO_VERSION_WITH_RETURN_KIND) // IsReturnKindAvailable { int returnKindBits = (_slimHeader) ? _gcInfoTypes.SIZE_OF_RETURN_KIND_SLIM : _gcInfoTypes.SIZE_OF_RETURN_KIND_FAT; ReturnKind = (ReturnKinds)NativeReader.ReadBits(image, returnKindBits, ref bitOffset); } CodeLength = _gcInfoTypes.DenormalizeCodeLength((int)NativeReader.DecodeVarLengthUnsigned(image, _gcInfoTypes.CODE_LENGTH_ENCBASE, ref bitOffset)); if (_hasGSCookie) { uint normPrologSize = NativeReader.DecodeVarLengthUnsigned(image, _gcInfoTypes.NORM_PROLOG_SIZE_ENCBASE, ref bitOffset) + 1; uint normEpilogSize = NativeReader.DecodeVarLengthUnsigned(image, _gcInfoTypes.NORM_EPILOG_SIZE_ENCBASE, ref bitOffset); ValidRangeStart = normPrologSize; ValidRangeEnd = (uint)CodeLength - normEpilogSize; } else if (_hasSecurityObject || _hasGenericsInstContext) { ValidRangeStart = NativeReader.DecodeVarLengthUnsigned(image, _gcInfoTypes.NORM_PROLOG_SIZE_ENCBASE, ref bitOffset) + 1; ValidRangeEnd = ValidRangeStart + 1; } if (_hasSecurityObject) { SecurityObjectStackSlot = _gcInfoTypes.DenormalizeStackSlot(NativeReader.DecodeVarLengthSigned(image, _gcInfoTypes.SECURITY_OBJECT_STACK_SLOT_ENCBASE, ref bitOffset)); } if (_hasGSCookie) { GSCookieStackSlot = _gcInfoTypes.DenormalizeStackSlot(NativeReader.DecodeVarLengthSigned(image, _gcInfoTypes.GS_COOKIE_STACK_SLOT_ENCBASE, ref bitOffset)); } if (_hasPSPSym) { PSPSymStackSlot = _gcInfoTypes.DenormalizeStackSlot(NativeReader.DecodeVarLengthSigned(image, _gcInfoTypes.PSP_SYM_STACK_SLOT_ENCBASE, ref bitOffset)); } if (_hasGenericsInstContext) { GenericsInstContextStackSlot = _gcInfoTypes.DenormalizeStackSlot(NativeReader.DecodeVarLengthSigned(image, _gcInfoTypes.GENERICS_INST_CONTEXT_STACK_SLOT_ENCBASE, ref bitOffset)); } if (_hasStackBaseRegister && !_slimHeader) { StackBaseRegister = _gcInfoTypes.DenormalizeStackBaseRegister(NativeReader.DecodeVarLengthUnsigned(image, _gcInfoTypes.STACK_BASE_REGISTER_ENCBASE, ref bitOffset)); } if (_hasSizeOfEditAndContinuePreservedArea) { SizeOfEditAndContinuePreservedArea = NativeReader.DecodeVarLengthUnsigned(image, _gcInfoTypes.SIZE_OF_EDIT_AND_CONTINUE_PRESERVED_AREA_ENCBASE, ref bitOffset); } if (_hasReversePInvokeFrame) { ReversePInvokeFrameStackSlot = NativeReader.DecodeVarLengthSigned(image, _gcInfoTypes.REVERSE_PINVOKE_FRAME_ENCBASE, ref bitOffset); } // FIXED_STACK_PARAMETER_SCRATCH_AREA (this macro is always defined in _gcInfoTypes.h) if (!_slimHeader) { SizeOfStackOutgoingAndScratchArea = _gcInfoTypes.DenormalizeSizeOfStackArea(NativeReader.DecodeVarLengthUnsigned(image, _gcInfoTypes.SIZE_OF_STACK_AREA_ENCBASE, ref bitOffset)); } // PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED (this macro is always defined in _gcInfoTypes.h) NumSafePoints = NativeReader.DecodeVarLengthUnsigned(image, _gcInfoTypes.NUM_SAFE_POINTS_ENCBASE, ref bitOffset); if (!_slimHeader) { NumInterruptibleRanges = NativeReader.DecodeVarLengthUnsigned(image, _gcInfoTypes.NUM_INTERRUPTIBLE_RANGES_ENCBASE, ref bitOffset); } // PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED (this macro is always defined in _gcInfoTypes.h) SafePointOffsets = EnumerateSafePoints(image, ref bitOffset); InterruptibleRanges = EnumerateInterruptibleRanges(image, _gcInfoTypes.INTERRUPTIBLE_RANGE_DELTA1_ENCBASE, _gcInfoTypes.INTERRUPTIBLE_RANGE_DELTA2_ENCBASE, ref bitOffset); SlotTable = new GcSlotTable(image, machine, _gcInfoTypes, ref bitOffset); // Try partially interruptible first if (NumSafePoints > 0) { LiveSlotsAtSafepoints = GetLiveSlotsAtSafepoints(image, ref bitOffset); } else { Transitions = GetTransitions(image, ref bitOffset); } Size = bitOffset - startBitOffset; }
public static uint Read(this NativeReader reader, uint offset, out double value) { value = reader.ReadDouble(offset); return(offset + 8); }
/// <summary> /// based on end of <a href="https://github.com/dotnet/coreclr/blob/master/src/vm/gcinfodecoder.cpp">GcInfoDecoder::EnumerateLiveSlots and GcInfoEncoder::Build</a> /// </summary> public Dictionary <int, List <BaseGcTransition> > GetTransitions(byte[] image, ref int bitOffset) { int totalInterruptibleLength = 0; if (NumInterruptibleRanges == 0) { totalInterruptibleLength = CodeLength; } else { foreach (InterruptibleRange range in InterruptibleRanges) { totalInterruptibleLength += (int)(range.StopOffset - range.StartOffset); } } int numChunks = (totalInterruptibleLength + _gcInfoTypes.NUM_NORM_CODE_OFFSETS_PER_CHUNK - 1) / _gcInfoTypes.NUM_NORM_CODE_OFFSETS_PER_CHUNK; int numBitsPerPointer = (int)NativeReader.DecodeVarLengthUnsigned(image, _gcInfoTypes.POINTER_SIZE_ENCBASE, ref bitOffset); if (numBitsPerPointer == 0) { return(new Dictionary <int, List <BaseGcTransition> >()); } // get offsets of each chunk int[] chunkPointers = new int[numChunks]; for (int i = 0; i < numChunks; i++) { chunkPointers[i] = NativeReader.ReadBits(image, numBitsPerPointer, ref bitOffset); } // Offset to m_Info2 containing all the info on register liveness int info2Offset = (int)Math.Ceiling(bitOffset / 8.0) * 8; List <GcTransition> transitions = new List <GcTransition>(); bool[] liveAtEnd = new bool[SlotTable.NumTracked]; // true if slot is live at the end of the chunk for (int currentChunk = 0; currentChunk < numChunks; currentChunk++) { if (chunkPointers[currentChunk] == 0) { continue; } else { bitOffset = info2Offset + chunkPointers[currentChunk] - 1; } int couldBeLiveOffset = bitOffset; // points to the couldBeLive bit array (array of bits indicating the slot changed state in the chunk) int slotId = 0; bool fSimple = (NativeReader.ReadBits(image, 1, ref couldBeLiveOffset) == 0); bool fSkipFirst = false; int couldBeLiveCnt = 0; if (!fSimple) { fSkipFirst = (NativeReader.ReadBits(image, 1, ref couldBeLiveOffset) == 0); slotId = -1; } uint numCouldBeLiveSlots = GetNumCouldBeLiveSlots(image, ref bitOffset); // count the number of set bits in the couldBeLive array int finalStateOffset = bitOffset; // points to the finalState bit array (array of bits indicating if the slot is live at the end of the chunk) bitOffset += (int)numCouldBeLiveSlots; // points to the array of code offsets int normChunkBaseCodeOffset = currentChunk * _gcInfoTypes.NUM_NORM_CODE_OFFSETS_PER_CHUNK; // the sum of the sizes of all preceeding chunks for (int i = 0; i < numCouldBeLiveSlots; i++) { // get the index of the next couldBeLive slot slotId = GetNextSlotId(image, fSimple, fSkipFirst, slotId, ref couldBeLiveCnt, ref couldBeLiveOffset); // set the liveAtEnd for the slot at slotId bool isLive = !liveAtEnd[slotId]; liveAtEnd[slotId] = (NativeReader.ReadBits(image, 1, ref finalStateOffset) != 0); // Read all the code offsets where the slot at slotId changed state while (NativeReader.ReadBits(image, 1, ref bitOffset) != 0) { int transitionOffset = NativeReader.ReadBits(image, _gcInfoTypes.NUM_NORM_CODE_OFFSETS_PER_CHUNK_LOG2, ref bitOffset) + normChunkBaseCodeOffset; transitions.Add(new GcTransition(transitionOffset, slotId, isLive, currentChunk, SlotTable, _machine)); isLive = !isLive; } slotId++; } } // convert normCodeOffsetDelta to the actual CodeOffset transitions.Sort((s1, s2) => s1.CodeOffset.CompareTo(s2.CodeOffset)); return(UpdateTransitionCodeOffset(transitions)); }
public static uint Read(this NativeReader reader, uint offset, out bool value) { value = (reader.ReadUInt8(offset) != 0) ? true : false; return(offset + 1); }
/// <summary> /// Unwinde code parsing is based on <a href="https://github.com/dotnet/coreclr/blob/master/src/jit/unwindamd64.cpp">src\jit\unwindamd64.cpp</a> DumpUnwindInfo /// </summary> public UnwindCode(byte[] image, ref int frameOffset, ref int offset) { CodeOffset = NativeReader.ReadByte(image, ref offset); byte op = NativeReader.ReadByte(image, ref offset); UnwindOp = (UnwindOpCodes)(op & 15); OpInfo = (byte)(op >> 4); OffsetLow = CodeOffset; OffsetHigh = OpInfo; FrameOffset = frameOffset; switch (UnwindOp) { case UnwindOpCodes.UWOP_PUSH_NONVOL: OpInfoStr = $"{(Registers)OpInfo}({OpInfo})"; break; case UnwindOpCodes.UWOP_ALLOC_LARGE: OpInfoStr = $"{OpInfo} - "; if (OpInfo == 0) { OpInfoStr += "Scaled small"; NextFrameOffset = 8 * NativeReader.ReadUInt16(image, ref offset); } else if (OpInfo == 1) { OpInfoStr += "Unscaled large"; uint nextOffset = NativeReader.ReadUInt16(image, ref offset); NextFrameOffset = (int)((uint)(NativeReader.ReadUInt16(image, ref offset) << 16) | nextOffset); } else { throw new BadImageFormatException(); } break; case UnwindOpCodes.UWOP_ALLOC_SMALL: int opInfo = OpInfo * 8 + 8; OpInfoStr = $"{opInfo}"; break; case UnwindOpCodes.UWOP_SET_FPREG: OpInfoStr = $"Unused({OpInfo})"; break; case UnwindOpCodes.UWOP_SET_FPREG_LARGE: { OpInfoStr = $"Unused({OpInfo})"; uint nextOffset = NativeReader.ReadUInt16(image, ref offset); nextOffset = ((uint)(NativeReader.ReadUInt16(image, ref offset) << 16) | nextOffset); NextFrameOffset = (int)nextOffset * 16; if ((NextFrameOffset & 0xF0000000) != 0) { throw new BadImageFormatException("Warning: Illegal unwindInfo unscaled offset: too large"); } } break; case UnwindOpCodes.UWOP_SAVE_NONVOL: { OpInfoStr = $"{(Registers)OpInfo}({OpInfo})"; NextFrameOffset = NativeReader.ReadUInt16(image, ref offset) * 8; } break; case UnwindOpCodes.UWOP_SAVE_NONVOL_FAR: { OpInfoStr = $"{(Registers)OpInfo}({OpInfo})"; uint nextOffset = NativeReader.ReadUInt16(image, ref offset); NextFrameOffset = (int)((uint)(NativeReader.ReadUInt16(image, ref offset) << 16) | nextOffset); } break; case UnwindOpCodes.UWOP_SAVE_XMM128: { OpInfoStr = $"XMM{OpInfo}({OpInfo})"; NextFrameOffset = (int)NativeReader.ReadUInt16(image, ref offset) * 16; } break; case UnwindOpCodes.UWOP_SAVE_XMM128_FAR: { OpInfoStr = $"XMM{OpInfo}({OpInfo})"; uint nextOffset = NativeReader.ReadUInt16(image, ref offset); NextFrameOffset = (int)((uint)(NativeReader.ReadUInt16(image, ref offset) << 16) | nextOffset); } break; default: throw new NotImplementedException(UnwindOp.ToString()); } NextFrameOffset = frameOffset; }
public static uint Read(this NativeReader reader, uint offset, out uint value) { return(reader.DecodeUnsigned(offset, out value)); }