public void ReadDynamicTable(JumpTable jumpTable) { if (JumpTable.DynamicTableElems > 1) { throw new NotSupportedException(); } _dynamicTable.Clear(); for (int entry = 1; entry <= jumpTable.DynTableEnd; entry++) { IntPtr addr = jumpTable.GetEntryAddressDynamicTable(entry); long guestAddress = Marshal.ReadInt64(addr, 0); long hostAddress = Marshal.ReadInt64(addr, 8); IndirectHostAddress indirectHostAddress; if (hostAddress == DirectCallStubs.IndirectCallStub(false).ToInt64()) { indirectHostAddress = IndirectHostAddress.CallStub; } else if (hostAddress == DirectCallStubs.IndirectCallStub(true).ToInt64()) { indirectHostAddress = IndirectHostAddress.TailCallStub; } else { throw new InvalidOperationException($"({nameof(hostAddress)} = 0x{hostAddress:X16})"); } _dynamicTable.Add(new KeyValuePair <long, IndirectHostAddress>(guestAddress, indirectHostAddress)); } }
public void Setup() { _strings = GetStrings(100); _segments = new PathSegment[100]; for (var i = 0; i < _strings.Length; i++) { _segments[i] = new PathSegment(0, _strings[i].Length); } var samples = new int[Count]; for (var i = 0; i < samples.Length; i++) { samples[i] = i * (_strings.Length / Count); } var entries = new List <(string text, int _)>(); for (var i = 0; i < samples.Length; i++) { entries.Add((_strings[samples[i]], i)); } _linearSearch = new LinearSearchJumpTable(0, -1, entries.ToArray()); _dictionary = new DictionaryJumpTable(0, -1, entries.ToArray()); _trie = new ILEmitTrieJumpTable(0, -1, entries.ToArray(), vectorize: false, _dictionary); _vectorTrie = new ILEmitTrieJumpTable(0, -1, entries.ToArray(), vectorize: true, _dictionary); }
public void ReadJumpTable(JumpTable jumpTable) { _jumpTable.Clear(); for (int entry = 1; entry <= jumpTable.TableEnd; entry++) { IntPtr addr = jumpTable.GetEntryAddressJumpTable(entry); long guestAddress = Marshal.ReadInt64(addr, 0); long hostAddress = Marshal.ReadInt64(addr, 8); DirectHostAddress directHostAddress; if (hostAddress == DirectCallStubs.DirectCallStub(false).ToInt64()) { directHostAddress = DirectHostAddress.CallStub; } else if (hostAddress == DirectCallStubs.DirectCallStub(true).ToInt64()) { directHostAddress = DirectHostAddress.TailCallStub; } else { directHostAddress = DirectHostAddress.Host; } _jumpTable.Add(new KeyValuePair <long, DirectHostAddress>(guestAddress, directHostAddress)); } }
/// <summary> /// Builds the MacOS A5World, based on the contents of the jump table in CODE#0. /// </summary> /// <param name="jt"></param> /// <param name="addr"></param> /// <param name="codeSegs"></param> /// <returns></returns> public ImageSegment LoadA5World( JumpTable jt, Address addr, Dictionary <int, ImageSegment> codeSegs, SortedList <Address, ImageSymbol> symbols) { var size = jt.BelowA5Size + jt.AboveA5Size; var mem = new MemoryArea(addr, new byte[size]); var w = new BeImageWriter(mem, jt.BelowA5Size + jt.JumpTableOffset); int i = 0; foreach (var entry in jt.Entries) { w.WriteBeUInt16(entry.RoutineOffsetFromSegmentStart); int iSeg = (ushort)entry.Instruction; var targetSeg = codeSegs[iSeg]; var addrDst = targetSeg.Address + entry.RoutineOffsetFromSegmentStart; if (!symbols.ContainsKey(addrDst)) { symbols.Add(addrDst, ImageSymbol.Procedure(arch, addrDst)); } w.WriteBeUInt16(0x4EF9); // jmp (xxxxxxxxx).L w.WriteBeUInt32(addrDst.ToUInt32()); ++i; } return(new ImageSegment("A5World", mem, AccessMode.ReadWriteExecute)); }
public void ReadJumpTable(JumpTable jumpTable) { // Reads in-memory jump table state and store internally for PtcJumpTable serialization. _jumpTable.Clear(); IEnumerable <int> entries = jumpTable.Table.GetEntries(); foreach (int entry in entries) { IntPtr addr = jumpTable.GetEntryAddressJumpTable(entry); long guestAddress = Marshal.ReadInt64(addr, 0); long hostAddress = Marshal.ReadInt64(addr, 8); DirectHostAddress directHostAddress; if (hostAddress == DirectCallStubs.DirectCallStub(false).ToInt64()) { directHostAddress = DirectHostAddress.CallStub; } else if (hostAddress == DirectCallStubs.DirectCallStub(true).ToInt64()) { directHostAddress = DirectHostAddress.TailCallStub; } else { directHostAddress = DirectHostAddress.Host; } _jumpTable.Add(new TableEntry <DirectHostAddress>(entry, guestAddress, directHostAddress)); } }
public void Deconstruct(out Instruction[] instructions, out Endpoint[] endpoints, out JumpTable[] tables) { instructions = _instructions.ToArray(); endpoints = _endpoints.ToArray(); tables = new JumpTable[_tables.Count]; for (var i = 0; i < _tables.Count; i++) { tables[i] = _tables[i].Build(); } }
public DfaState( Candidate[] candidates, IEndpointSelectorPolicy[] policies, JumpTable pathTransitions, PolicyJumpTable policyTransitions) { Candidates = candidates; Policies = policies; PathTransitions = pathTransitions; PolicyTransitions = policyTransitions; }
public void WriteJumpTable(JumpTable jumpTable, ConcurrentDictionary <ulong, TranslatedFunction> funcs) { // Writes internal state to jump table in-memory, after PtcJumpTable was deserialized. foreach (var tableEntry in _jumpTable) { long guestAddress = tableEntry.GuestAddress; DirectHostAddress directHostAddress = tableEntry.HostAddress; long hostAddress; if (directHostAddress == DirectHostAddress.CallStub) { hostAddress = DirectCallStubs.DirectCallStub(false).ToInt64(); } else if (directHostAddress == DirectHostAddress.TailCallStub) { hostAddress = DirectCallStubs.DirectCallStub(true).ToInt64(); } else if (directHostAddress == DirectHostAddress.Host) { if (funcs.TryGetValue((ulong)guestAddress, out TranslatedFunction func)) { hostAddress = func.FuncPtr.ToInt64(); } else { if (!PtcProfiler.ProfiledFuncs.TryGetValue((ulong)guestAddress, out var value) || !value.HighCq) { throw new KeyNotFoundException($"({nameof(guestAddress)} = 0x{(ulong)guestAddress:X16})"); } hostAddress = 0L; } } else { throw new InvalidOperationException(nameof(directHostAddress)); } int entry = tableEntry.EntryIndex; jumpTable.Table.SetEntry(entry); jumpTable.ExpandIfNeededJumpTable(entry); IntPtr addr = jumpTable.GetEntryAddressJumpTable(entry); Marshal.WriteInt64(addr, 0, guestAddress); Marshal.WriteInt64(addr, 8, hostAddress); } }
public void Initialize(JumpTable jumpTable) { _targets.Clear(); foreach (ulong guestAddress in jumpTable.Targets.Keys) { _targets.Add(guestAddress); } _dependants.Clear(); foreach (var item in jumpTable.Dependants) { _dependants.Add(item.Key, new LinkedList <int>(item.Value)); } }
public string parse_c_instruction(string instruction) { string c_instruction_bin; string dest = "000"; string comp = "00000000"; string jump = "000"; Symbol Match; int index; index = instruction.IndexOf('='); if (index > 0) { jump = "000"; dest = instruction.Substring(0, index); Match = DestTable.FirstOrDefault(i => i.Name == dest); if (Match != null) { dest = Match.Value; } comp = instruction.Substring(index + 1, instruction.Length - index - 1); Match = CompTable.FirstOrDefault(i => i.Name == comp); if (Match != null) { comp = Match.Value; } } index = instruction.IndexOf(';'); if (index > 0) { dest = "000"; comp = instruction.Substring(0, index); Match = CompTable.FirstOrDefault(i => i.Name == comp); if (Match != null) { comp = Match.Value; } jump = instruction.Substring(index + 1, instruction.Length - index - 1); Match = JumpTable.FirstOrDefault(i => i.Name == jump); if (Match != null) { jump = Match.Value; } } c_instruction_bin = "11" + comp + dest + jump; return(c_instruction_bin); }
public void WriteJumpTable(JumpTable jumpTable, ConcurrentDictionary <ulong, TranslatedFunction> funcs) { jumpTable.ExpandIfNeededJumpTable(TableEnd); int entry = 0; foreach (var item in _jumpTable) { entry += 1; long guestAddress = item.Key; DirectHostAddress directHostAddress = item.Value; long hostAddress; if (directHostAddress == DirectHostAddress.CallStub) { hostAddress = DirectCallStubs.DirectCallStub(false).ToInt64(); } else if (directHostAddress == DirectHostAddress.TailCallStub) { hostAddress = DirectCallStubs.DirectCallStub(true).ToInt64(); } else if (directHostAddress == DirectHostAddress.Host) { if (funcs.TryGetValue((ulong)guestAddress, out TranslatedFunction func)) { hostAddress = func.FuncPtr.ToInt64(); } else { throw new KeyNotFoundException($"({nameof(guestAddress)} = 0x{(ulong)guestAddress:X16})"); } } else { throw new InvalidOperationException(nameof(directHostAddress)); } IntPtr addr = jumpTable.GetEntryAddressJumpTable(entry); Marshal.WriteInt64(addr, 0, guestAddress); Marshal.WriteInt64(addr, 8, hostAddress); } }
private static void PatchCode( Span <byte> code, RelocEntry[] relocEntries, IntPtr pageTablePointer, JumpTable jumpTable, EntryTable <uint> countTable, out Counter <uint> callCounter) { callCounter = null; foreach (RelocEntry relocEntry in relocEntries) { ulong imm; if (relocEntry.Index == PageTablePointerIndex) { imm = (ulong)pageTablePointer.ToInt64(); } else if (relocEntry.Index == JumpPointerIndex) { imm = (ulong)jumpTable.JumpPointer.ToInt64(); } else if (relocEntry.Index == DynamicPointerIndex) { imm = (ulong)jumpTable.DynamicPointer.ToInt64(); } else if (relocEntry.Index == CountTableIndex) { callCounter = new Counter <uint>(countTable); unsafe { imm = (ulong)Unsafe.AsPointer(ref callCounter.Value); } } else if (Delegates.TryGetDelegateFuncPtrByIndex(relocEntry.Index, out IntPtr funcPtr)) { imm = (ulong)funcPtr.ToInt64(); } else { throw new Exception($"Unexpected reloc entry {relocEntry}."); } BinaryPrimitives.WriteUInt64LittleEndian(code.Slice(relocEntry.Position, 8), imm); } }
public void Setup() { _table = new ZeroEntryJumpTable(0, -1); _strings = new string[] { "index/foo/2", "index/hello-world1/2", "index/hello-world/2", "index//2", "index/hillo-goodbye/2", }; _segments = new PathSegment[] { new PathSegment(6, 3), new PathSegment(6, 12), new PathSegment(6, 11), new PathSegment(6, 0), new PathSegment(6, 13), }; }
private void ProcessJumpTable(uint jtOffset) { var j = new JumpTable(); ImageReader ir = new BeImageReader(image, jtOffset); j.AboveA5Size = ir.ReadBeUInt32(); j.BelowA5Size = ir.ReadBeUInt32(); j.JumpTableSize = ir.ReadBeUInt32(); j.JumpTableOffset = ir.ReadBeUInt32(); uint size = j.JumpTableSize; while (size > 0) { JumpTableEntry jte = new JumpTableEntry(); jte.RoutineOffsetFromSegmentStart = ir.ReadBeUInt16(); jte.Instruction = ir.ReadBeUInt32(); jte.LoadSegTrapNumber = ir.ReadBeUInt16(); Debug.WriteLine(string.Format("Jump table entry: {0:x2} {1:X4} {2:X2}", jte.RoutineOffsetFromSegmentStart, jte.Instruction, jte.LoadSegTrapNumber)); size -= 8; } }
public void WriteDynamicTable(JumpTable jumpTable) { // Writes internal state to jump table in-memory, after PtcJumpTable was deserialized. if (JumpTable.DynamicTableElems > 1) { throw new NotSupportedException(); } foreach (var tableEntry in _dynamicTable) { long guestAddress = tableEntry.GuestAddress; IndirectHostAddress indirectHostAddress = tableEntry.HostAddress; long hostAddress; if (indirectHostAddress == IndirectHostAddress.CallStub) { hostAddress = DirectCallStubs.IndirectCallStub(false).ToInt64(); } else if (indirectHostAddress == IndirectHostAddress.TailCallStub) { hostAddress = DirectCallStubs.IndirectCallStub(true).ToInt64(); } else { throw new InvalidOperationException(nameof(indirectHostAddress)); } int entry = tableEntry.EntryIndex; jumpTable.DynTable.SetEntry(entry); jumpTable.ExpandIfNeededDynamicTable(entry); IntPtr addr = jumpTable.GetEntryAddressDynamicTable(entry); Marshal.WriteInt64(addr, 0, guestAddress); Marshal.WriteInt64(addr, 8, hostAddress); } }
public void WriteDynamicTable(JumpTable jumpTable) { if (JumpTable.DynamicTableElems > 1) { throw new NotSupportedException(); } jumpTable.ExpandIfNeededDynamicTable(DynTableEnd); int entry = 0; foreach (var item in _dynamicTable) { entry += 1; long guestAddress = item.Key; IndirectHostAddress indirectHostAddress = item.Value; long hostAddress; if (indirectHostAddress == IndirectHostAddress.CallStub) { hostAddress = DirectCallStubs.IndirectCallStub(false).ToInt64(); } else if (indirectHostAddress == IndirectHostAddress.TailCallStub) { hostAddress = DirectCallStubs.IndirectCallStub(true).ToInt64(); } else { throw new InvalidOperationException(nameof(indirectHostAddress)); } IntPtr addr = jumpTable.GetEntryAddressDynamicTable(entry); Marshal.WriteInt64(addr, 0, guestAddress); Marshal.WriteInt64(addr, 8, hostAddress); } }
public void ReadDynamicTable(JumpTable jumpTable) { // Reads in-memory jump table state and store internally for PtcJumpTable serialization. if (JumpTable.DynamicTableElems > 1) { throw new NotSupportedException(); } _dynamicTable.Clear(); IEnumerable <int> entries = jumpTable.DynTable.GetEntries(); foreach (int entry in entries) { IntPtr addr = jumpTable.GetEntryAddressDynamicTable(entry); long guestAddress = Marshal.ReadInt64(addr, 0); long hostAddress = Marshal.ReadInt64(addr, 8); IndirectHostAddress indirectHostAddress; if (hostAddress == DirectCallStubs.IndirectCallStub(false).ToInt64()) { indirectHostAddress = IndirectHostAddress.CallStub; } else if (hostAddress == DirectCallStubs.IndirectCallStub(true).ToInt64()) { indirectHostAddress = IndirectHostAddress.TailCallStub; } else { throw new InvalidOperationException($"({nameof(hostAddress)} = 0x{hostAddress:X16})"); } _dynamicTable.Add(new TableEntry <IndirectHostAddress>(entry, guestAddress, indirectHostAddress)); } }
public void Initialize(JumpTable jumpTable) { Targets.Clear(); foreach (ulong guestAddress in jumpTable.Targets.Keys) { Targets.Add(guestAddress); } Dependants.Clear(); foreach (var kv in jumpTable.Dependants) { Dependants.Add(kv.Key, new List <int>(kv.Value)); } Owners.Clear(); foreach (var kv in jumpTable.Owners) { Owners.Add(kv.Key, new List <int>(kv.Value)); } }
private JumpTable ProcessJumpTable(MemoryArea memJt, IDictionary <Address, ImageSymbol> symbols) { var j = new JumpTable(); var ir = memJt.CreateBeReader(0); j.AboveA5Size = ir.ReadBeUInt32(); j.BelowA5Size = ir.ReadBeUInt32(); j.JumpTableSize = ir.ReadBeUInt32(); j.JumpTableOffset = ir.ReadBeUInt32(); uint size = j.JumpTableSize; while (size > 0) { JumpTableEntry jte = new JumpTableEntry(); var addr = ir.Address; jte.RoutineOffsetFromSegmentStart = ir.ReadBeUInt16(); jte.Instruction = ir.ReadBeUInt32(); jte.LoadSegTrapNumber = ir.ReadBeUInt16(); j.Entries.Add(jte); Debug.Print("{0}", jte); size -= 8; } return(j); }
internal static void LoadTranslations( ConcurrentDictionary <ulong, TranslatedFunction> funcs, IMemoryManager memory, JumpTable jumpTable, EntryTable <uint> countTable) { if (AreCarriersEmpty()) { return; } long infosStreamLength = _infosStream.Length; long relocsStreamLength = _relocsStream.Length; long unwindInfosStreamLength = _unwindInfosStream.Length; _infosStream.Seek(0L, SeekOrigin.Begin); _relocsStream.Seek(0L, SeekOrigin.Begin); _unwindInfosStream.Seek(0L, SeekOrigin.Begin); using (BinaryReader relocsReader = new(_relocsStream, EncodingCache.UTF8NoBOM, true)) using (BinaryReader unwindInfosReader = new(_unwindInfosStream, EncodingCache.UTF8NoBOM, true)) { for (int index = 0; index < GetEntriesCount(); index++) { InfoEntry infoEntry = DeserializeStructure <InfoEntry>(_infosStream); if (infoEntry.Stubbed) { SkipCode(index, infoEntry.CodeLength); SkipReloc(infoEntry.RelocEntriesCount); SkipUnwindInfo(unwindInfosReader); continue; } bool isEntryChanged = infoEntry.Hash != ComputeHash(memory, infoEntry.Address, infoEntry.GuestSize); if (isEntryChanged || (!infoEntry.HighCq && PtcProfiler.ProfiledFuncs.TryGetValue(infoEntry.Address, out var value) && value.HighCq)) { infoEntry.Stubbed = true; infoEntry.CodeLength = 0; UpdateInfo(infoEntry); StubCode(index); StubReloc(infoEntry.RelocEntriesCount); StubUnwindInfo(unwindInfosReader); if (isEntryChanged) { PtcJumpTable.Clean(infoEntry.Address); Logger.Info?.Print(LogClass.Ptc, $"Invalidated translated function (address: 0x{infoEntry.Address:X16})"); } continue; } byte[] code = ReadCode(index, infoEntry.CodeLength); Counter <uint> callCounter = null; if (infoEntry.RelocEntriesCount != 0) { RelocEntry[] relocEntries = GetRelocEntries(relocsReader, infoEntry.RelocEntriesCount); PatchCode(code, relocEntries, memory.PageTablePointer, jumpTable, countTable, out callCounter); } UnwindInfo unwindInfo = ReadUnwindInfo(unwindInfosReader); TranslatedFunction func = FastTranslate(code, callCounter, infoEntry.GuestSize, unwindInfo, infoEntry.HighCq); bool isAddressUnique = funcs.TryAdd(infoEntry.Address, func); Debug.Assert(isAddressUnique, $"The address 0x{infoEntry.Address:X16} is not unique."); } } if (_infosStream.Length != infosStreamLength || _infosStream.Position != infosStreamLength || _relocsStream.Length != relocsStreamLength || _relocsStream.Position != relocsStreamLength || _unwindInfosStream.Length != unwindInfosStreamLength || _unwindInfosStream.Position != unwindInfosStreamLength) { throw new Exception("The length of a memory stream has changed, or its position has not reached or has exceeded its end."); } jumpTable.Initialize(PtcJumpTable, funcs); PtcJumpTable.WriteJumpTable(jumpTable, funcs); PtcJumpTable.WriteDynamicTable(jumpTable); Logger.Info?.Print(LogClass.Ptc, $"{funcs.Count} translated functions loaded"); }
public void AddResourcesToImageMap( Address addrLoad, MemoryArea mem, SegmentMap segmentMap, List <ImageSymbol> entryPoints, SortedList <Address, ImageSymbol> symbols) { JumpTable jt = null; var codeSegs = new Dictionary <int, ImageSegment>(); foreach (ResourceType type in ResourceTypes) { foreach (ResourceReference rsrc in type.References) { uint uSegOffset = rsrc.DataOffset + rsrcDataOff; int segmentSize = mem.ReadBeInt32(uSegOffset); // Skip the size longword at the beginning of the segment, and an extra 4 // if it is a code segement other than CODE#0. int bytesToSkip = 4; if (type.Name == "CODE" && rsrc.ResourceID != 0) { bytesToSkip += 4; } var abSegment = new byte[segmentSize]; Array.Copy(mem.Bytes, uSegOffset + bytesToSkip, abSegment, 0, segmentSize); Address addrSegment = addrLoad + uSegOffset + bytesToSkip; //$TODO pad to 16-byte boundary? var memSeg = new MemoryArea(addrSegment, abSegment); var segment = segmentMap.AddSegment(new ImageSegment( ResourceDescriptiveName(type, rsrc), memSeg, AccessMode.Read)); if (type.Name == "CODE") { if (rsrc.ResourceID == 0) { jt = ProcessJumpTable(memSeg, symbols); } else { codeSegs.Add(rsrc.ResourceID, segment); var macsBug = new MacsBugSymbolScanner(arch, segment.MemoryArea); var mbSymbols = macsBug.ScanForSymbols(); foreach (var symbol in mbSymbols) { symbols[symbol.Address] = symbol; } } } } } // We have found a jump table, so we allocate an A5World. if (jt != null) { // Find an address beyond all known segments. var addr = segmentMap.Segments.Values.Max(s => s.Address + s.Size).Align(0x10); var a5world = LoadA5World(jt, addr, codeSegs, symbols); platform.A5World = a5world; platform.A5Offset = jt.BelowA5Size; segmentMap.AddSegment(a5world); // Find first (and only!) segment containing the name %A5Init. var a5dataSegment = segmentMap.Segments.Values.SingleOrDefault(SegmentNamedA5Init); if (a5dataSegment == null) { return; } // Get an image reader to the start of the data. var a5dr = GetA5InitImageReader(a5dataSegment); if (a5dr == null) { return; } var a5dbelow = a5dr.ReadBeUInt32(); var a5dbankSize = a5dr.ReadBeUInt32(); var a5doffset = a5dr.ReadBeUInt32(); var a5dreloc = a5dr.ReadBeUInt32(); var a5dhdrend = a5dr.ReadBeUInt32(); if (a5dbankSize != 0x00010000) { // bank size not supported for compressed global data return; } A5Expand(a5dr, a5dbelow); } }
string OpCodeToString(OpCode opcode, Class currentClass, Method method, JumpTable jumpTable) { switch (opcode.Instruction) { case Instructions.Const: case Instructions.Const4: case Instructions.Const16: case Instructions.ConstHigh: case Instructions.ConstWide16: case Instructions.ConstWide32: case Instructions.ConstWide: case Instructions.ConstWideHigh: dynamic constOpCode = opcode; return(string.Format("{1} = #{2}", constOpCode.Name, GetRegisterName(constOpCode.Destination, method), constOpCode.Value)); case Instructions.Move: case Instructions.MoveFrom16: case Instructions.Move16: case Instructions.MoveWide: case Instructions.MoveWideFrom16: case Instructions.MoveWide16: case Instructions.MoveObject: case Instructions.MoveObjectFrom16: case Instructions.MoveObject16: dynamic moveOpCode = opcode; return(string.Format("{1} = {2}", moveOpCode.Name, GetRegisterName(moveOpCode.To, method), GetRegisterName(moveOpCode.From, method))); case Instructions.MoveResult: case Instructions.MoveResultWide: case Instructions.MoveResultObject: case Instructions.MoveException: dynamic moveResultOpCode = opcode; return(string.Format("{0} {1}", moveResultOpCode.Name, GetRegisterName(moveResultOpCode.Destination, method))); case Instructions.ConstString: case Instructions.ConstStringJumbo: dynamic constStringOpCode = opcode; return(string.Format("{1} = \"{2}\"", constStringOpCode.Name, GetRegisterName(constStringOpCode.Destination, method), _dex.GetString(constStringOpCode.StringIndex).Replace("\n", "\\n"))); case Instructions.ConstClass: return(string.Format("{0} = {1}", GetRegisterName(((ConstClassOpCode)opcode).Destination, method), _dex.GetTypeName(((ConstClassOpCode)opcode).TypeIndex))); case Instructions.CheckCast: var typeCheckCast = _dex.GetTypeName(((CheckCastOpCode)opcode).TypeIndex); return(string.Format("({1}){0}", GetRegisterName(((CheckCastOpCode)opcode).Destination, method), typeCheckCast)); case Instructions.InstanceOf: var typeInstanceOf = _dex.GetTypeName(((InstanceOfOpCode)opcode).TypeIndex); return(string.Format("instance-of v{0}, v{1}, {2}", ((InstanceOfOpCode)opcode).Destination, ((InstanceOfOpCode)opcode).Reference, typeInstanceOf)); case Instructions.NewInstance: var typeNewInstance = _dex.GetTypeName(((NewInstanceOpCode)opcode).TypeIndex); return(string.Format("{0} = new {1}", GetRegisterName(((NewInstanceOpCode)opcode).Destination, method), typeNewInstance)); case Instructions.NewArrayOf: var newArrayOpCode = (NewArrayOfOpCode)opcode; var typeNewArrayOfOpCode = _dex.GetTypeName(newArrayOpCode.TypeIndex); return(string.Format("{0} = new {1}", GetRegisterName(newArrayOpCode.Destination, method), typeNewArrayOfOpCode.Replace("[]", string.Format("[{0}]", GetRegisterName(newArrayOpCode.Size, method))))); case Instructions.FilledNewArrayOf: var typeFilledNewArrayOf = _dex.GetTypeName(((FilledNewArrayOfOpCode)opcode).TypeIndex); return(string.Format("filled-new-array {0}, {1}", string.Join(",", ((FilledNewArrayOfOpCode)opcode).Values), typeFilledNewArrayOf)); case Instructions.FilledNewArrayRange: var typeFilledNewArrayRange = _dex.GetTypeName(((FilledNewArrayRangeOpCode)opcode).TypeIndex); return(string.Format("filled-new-array/range {0}, {1}", string.Join(",", ((FilledNewArrayRangeOpCode)opcode).Values), typeFilledNewArrayRange)); case Instructions.ArrayLength: var arrayLengthOpcode = (ArrayLengthOpCode)opcode; return(string.Format("{0} = {1}.length", GetRegisterName(arrayLengthOpcode.Destination, method), GetRegisterName(arrayLengthOpcode.ArrayReference, method))); case Instructions.InvokeVirtual: case Instructions.InvokeSuper: case Instructions.InvokeDirect: case Instructions.InvokeStatic: case Instructions.InvokeInterface: var invokeOpcode = (InvokeOpCode)opcode; var invokeMethod = _dex.GetMethod(invokeOpcode.MethodIndex); string invokeObject; if (invokeMethod.IsStatic() || invokeOpcode.Instruction == Instructions.InvokeStatic) { invokeObject = _dex.GetTypeName(invokeMethod.ClassIndex); } else { invokeObject = GetRegisterName(invokeOpcode.ArgumentRegisters [0], method); } string[] registerNames = {}; if (invokeOpcode.ArgumentRegisters.Length > 0) { var instanceAdjustment = invokeMethod.IsStatic()?0:1; registerNames = new string[invokeOpcode.ArgumentRegisters.Length - instanceAdjustment]; for (int i = 0; i < registerNames.Length; i++) { registerNames [i] = GetRegisterName(invokeOpcode.ArgumentRegisters[i + instanceAdjustment], method); } } return(string.Format("{2}.{3}({1})", ((InvokeOpCode)opcode).Name, string.Join(",", registerNames), invokeObject, invokeMethod.Name)); case Instructions.Sput: case Instructions.SputWide: case Instructions.SputObject: case Instructions.SputBoolean: case Instructions.SputChar: case Instructions.SputShort: case Instructions.SputByte: var sputOpcode = (StaticOpOpCode)opcode; return(string.Format("{2} = {1}", sputOpcode.Name, GetRegisterName(sputOpcode.Destination, method), GetFieldName(sputOpcode.Index, currentClass, true))); case Instructions.Sget: case Instructions.SgetWide: case Instructions.SgetObject: case Instructions.SgetBoolean: case Instructions.SgetChar: case Instructions.SgetShort: case Instructions.SgetByte: var sgetOpcode = (StaticOpOpCode)opcode; return(string.Format("{1} = {2}", sgetOpcode.Name, GetRegisterName(sgetOpcode.Destination, method), GetFieldName(sgetOpcode.Index, currentClass, true))); case Instructions.Iput: case Instructions.IputWide: case Instructions.IputObject: case Instructions.IputBoolean: case Instructions.IputChar: case Instructions.IputShort: case Instructions.IputByte: var iputOpCode = (IinstanceOpOpCode)opcode; return(string.Format("{2} = {1}", iputOpCode.Name, GetRegisterName(iputOpCode.Destination, method), GetFieldName(iputOpCode.Index, currentClass))); case Instructions.Iget: case Instructions.IgetWide: case Instructions.IgetObject: case Instructions.IgetBoolean: case Instructions.IgetChar: case Instructions.IgetShort: case Instructions.IgetByte: var igetOpCode = (IinstanceOpOpCode)opcode; return(string.Format("{1} = {2}", igetOpCode.Name, GetRegisterName(igetOpCode.Destination, method), GetFieldName(igetOpCode.Index, currentClass))); case Instructions.Aput: case Instructions.AputWide: case Instructions.AputObject: case Instructions.AputBoolean: case Instructions.AputChar: case Instructions.AputShort: case Instructions.AputByte: var aputOpCode = (ArrayOpOpCode)opcode; return(string.Format("{2}[{3}] = {1}", aputOpCode.Name, GetRegisterName(aputOpCode.Destination, method), GetRegisterName(aputOpCode.Array, method), GetRegisterName(aputOpCode.Index, method))); case Instructions.Aget: case Instructions.AgetWide: case Instructions.AgetObject: case Instructions.AgetBoolean: case Instructions.AgetChar: case Instructions.AgetShort: case Instructions.AgetByte: var agetOpCode = (ArrayOpOpCode)opcode; return(string.Format("{1} = {2}[{3}]", agetOpCode.Name, GetRegisterName(agetOpCode.Destination, method), GetRegisterName(agetOpCode.Array, method), GetRegisterName(agetOpCode.Index, method))); case Instructions.AddInt: case Instructions.AddLong: case Instructions.AddFloat: case Instructions.AddDouble: return(FormatBinaryOperation((BinaryOpOpCode)opcode, "+", method)); case Instructions.SubInt: case Instructions.SubLong: case Instructions.SubFloat: case Instructions.SubDouble: return(FormatBinaryOperation((BinaryOpOpCode)opcode, "-", method)); case Instructions.MulInt: case Instructions.MulLong: case Instructions.MulFloat: case Instructions.MulDouble: return(FormatBinaryOperation((BinaryOpOpCode)opcode, "*", method)); case Instructions.DivInt: case Instructions.DivLong: case Instructions.DivFloat: case Instructions.DivDouble: return(FormatBinaryOperation((BinaryOpOpCode)opcode, "/", method)); case Instructions.RemInt: case Instructions.RemLong: case Instructions.RemFloat: case Instructions.RemDouble: return(FormatBinaryOperation((BinaryOpOpCode)opcode, "&", method)); case Instructions.AndInt: case Instructions.AndLong: return(FormatBinaryOperation((BinaryOpOpCode)opcode, "&", method)); case Instructions.OrInt: case Instructions.OrLong: return(FormatBinaryOperation((BinaryOpOpCode)opcode, "|", method)); case Instructions.XorInt: case Instructions.XorLong: return(FormatBinaryOperation((BinaryOpOpCode)opcode, "^", method)); case Instructions.ShlInt: case Instructions.ShlLong: return(FormatBinaryOperation((BinaryOpOpCode)opcode, "<<", method)); case Instructions.ShrInt: case Instructions.UshrInt: case Instructions.ShrLong: case Instructions.UshrLong: return(FormatBinaryOperation((BinaryOpOpCode)opcode, ">>", method)); case Instructions.IfEq: return(FormatIfOperation((IfOpCode)opcode, "=", method, jumpTable)); case Instructions.IfNe: return(FormatIfOperation((IfOpCode)opcode, "!=", method, jumpTable)); case Instructions.IfLt: return(FormatIfOperation((IfOpCode)opcode, "<", method, jumpTable)); case Instructions.IfGe: return(FormatIfOperation((IfOpCode)opcode, ">=", method, jumpTable)); case Instructions.IfGt: return(FormatIfOperation((IfOpCode)opcode, ">", method, jumpTable)); case Instructions.IfLe: return(FormatIfOperation((IfOpCode)opcode, "<=", method, jumpTable)); case Instructions.IfEqz: return(FormatIfzOperation((IfzOpCode)opcode, "=", method, jumpTable)); case Instructions.IfNez: return(FormatIfzOperation((IfzOpCode)opcode, "!=", method, jumpTable)); case Instructions.IfLtz: return(FormatIfzOperation((IfzOpCode)opcode, "<", method, jumpTable)); case Instructions.IfGez: return(FormatIfzOperation((IfzOpCode)opcode, ">=", method, jumpTable)); case Instructions.IfGtz: return(FormatIfzOperation((IfzOpCode)opcode, ">", method, jumpTable)); case Instructions.IfLez: return(FormatIfzOperation((IfzOpCode)opcode, "<=", method, jumpTable)); case Instructions.RsubInt: case Instructions.RsubIntLit8: dynamic rsubIntOpCode = opcode; return(string.Format("{0} = #{2} - {1}", GetRegisterName(rsubIntOpCode.Destination, method), GetRegisterName(rsubIntOpCode.Source, method), rsubIntOpCode.Constant)); case Instructions.AddIntLit16: case Instructions.AddIntLit8: return(FormatBinaryLiteralOperation(opcode, "+", method)); case Instructions.MulIntLit16: case Instructions.MulIntLit8: return(FormatBinaryLiteralOperation(opcode, "*", method)); case Instructions.DivIntLit16: case Instructions.DivIntLit8: return(FormatBinaryLiteralOperation(opcode, "/", method)); case Instructions.RemIntLit16: case Instructions.RemIntLit8: return(FormatBinaryLiteralOperation(opcode, "%", method)); case Instructions.AndIntLit16: case Instructions.AndIntLit8: return(FormatBinaryLiteralOperation(opcode, "&", method)); case Instructions.OrIntLit16: case Instructions.OrIntLit8: return(FormatBinaryLiteralOperation(opcode, "|", method)); case Instructions.XorIntLit16: case Instructions.XorIntLit8: return(FormatBinaryLiteralOperation(opcode, "^", method)); case Instructions.ShlIntLit8: return(FormatBinaryLiteralOperation(opcode, "<<", method)); case Instructions.ShrIntLit8: return(FormatBinaryLiteralOperation(opcode, ">>", method)); case Instructions.UshrIntLit8: return(FormatBinaryLiteralOperation(opcode, ">>", method)); case Instructions.AddInt2Addr: case Instructions.AddLong2Addr: case Instructions.AddFloat2Addr: case Instructions.AddDouble2Addr: return(FormatBinary2AddrOperation((BinaryOp2OpCode)opcode, "+", method)); case Instructions.SubInt2Addr: case Instructions.SubLong2Addr: case Instructions.SubFloat2Addr: case Instructions.SubDouble2Addr: return(FormatBinary2AddrOperation((BinaryOp2OpCode)opcode, "-", method)); case Instructions.MulInt2Addr: case Instructions.MulLong2Addr: case Instructions.MulFloat2Addr: case Instructions.MulDouble2Addr: return(FormatBinary2AddrOperation((BinaryOp2OpCode)opcode, "*", method)); case Instructions.DivInt2Addr: case Instructions.DivLong2Addr: case Instructions.DivFloat2Addr: case Instructions.DivDouble2Addr: return(FormatBinary2AddrOperation((BinaryOp2OpCode)opcode, "/", method)); case Instructions.RemInt2Addr: case Instructions.RemLong2Addr: case Instructions.RemFloat2Addr: case Instructions.RemDouble2Addr: return(FormatBinary2AddrOperation((BinaryOp2OpCode)opcode, "&", method)); case Instructions.AndInt2Addr: case Instructions.AndLong2Addr: return(FormatBinary2AddrOperation((BinaryOp2OpCode)opcode, "&", method)); case Instructions.OrInt2Addr: case Instructions.OrLong2Addr: return(FormatBinary2AddrOperation((BinaryOp2OpCode)opcode, "|", method)); case Instructions.XorInt2Addr: case Instructions.XorLong2Addr: return(FormatBinary2AddrOperation((BinaryOp2OpCode)opcode, "^", method)); case Instructions.ShlInt2Addr: case Instructions.ShlLong2Addr: return(FormatBinary2AddrOperation((BinaryOp2OpCode)opcode, "<<", method)); case Instructions.ShrInt2Addr: case Instructions.UshrInt2Addr: case Instructions.ShrLong2Addr: case Instructions.UshrLong2Addr: return(FormatBinary2AddrOperation((BinaryOp2OpCode)opcode, ">>", method)); case Instructions.Goto: case Instructions.Goto16: case Instructions.Goto32: dynamic gotoOpCode = opcode; return(string.Format("{0} {1}", gotoOpCode.Name, jumpTable.GetReferrerLabel(gotoOpCode.OpCodeOffset))); case Instructions.PackedSwitch: var packedSwitchOpCode = (PackedSwitchOpCode)opcode; return(string.Format("{0} {1} - First:{2} - [{3}]", opcode.Name, GetRegisterName(packedSwitchOpCode.Destination, method), packedSwitchOpCode.FirstKey, string.Join(",", jumpTable.GetReferrerLabels(packedSwitchOpCode.OpCodeOffset)))); case Instructions.SparseSwitch: var sparseSwitchOpCode = (SparseSwitchOpCode)opcode; return(string.Format("{0} {1} - Keys:[{2}] Targets:[{3}]", opcode.Name, GetRegisterName(sparseSwitchOpCode.Destination, method), string.Join(",", sparseSwitchOpCode.Keys), string.Join(",", jumpTable.GetReferrerLabels(sparseSwitchOpCode.OpCodeOffset)))); default: return(opcode.ToString()); } }
JumpTable BuildJumpTable(Method method) { var jumpTable = new JumpTable(); int gotoCounter = 0; int ifCounter = 0; int switchCounter = 0; foreach (var opcode in method.GetInstructions()) { switch (opcode.Instruction) { case Instructions.Goto: case Instructions.Goto16: case Instructions.Goto32: var gotoOpCode = (dynamic)opcode; jumpTable.AddTarget(gotoOpCode.OpCodeOffset, gotoOpCode.GetTargetAddress(), "goto_", ref gotoCounter); break; case Instructions.PackedSwitch: case Instructions.SparseSwitch: dynamic switchOpCode = opcode; foreach (var switchTarget in switchOpCode.GetTargetAddresses()) { jumpTable.AddTarget(switchOpCode.OpCodeOffset, switchTarget, "switch_", ref switchCounter); } break; case Instructions.IfEq: case Instructions.IfNe: case Instructions.IfLt: case Instructions.IfGe: case Instructions.IfGt: case Instructions.IfLe: case Instructions.IfEqz: case Instructions.IfNez: case Instructions.IfLtz: case Instructions.IfGez: case Instructions.IfGtz: case Instructions.IfLez: dynamic ifOpCode = opcode; jumpTable.AddTarget(ifOpCode.OpCodeOffset, ifOpCode.GetTargetAddress(), "if_", ref ifCounter); break; } } var catchCounter = 0; if (method.TryCatchBlocks != null) { foreach (var tryBlock in method.TryCatchBlocks) { foreach (var catchBlock in tryBlock.Handlers) { jumpTable.AddHandler(catchBlock, "catch_", ref catchCounter); } } } return(jumpTable); }
private void WriteOutCatchStatements(TextWriter output, Indentation indent, TryCatchBlock currentTryBlock, JumpTable jumpTable) { indent--; foreach (var catchBlock in currentTryBlock.Handlers) { output.WriteLine(string.Format("{0}catch({1}) :{2}", indent.ToString(), catchBlock.TypeIndex == 0 ? "ALL" : _dex.GetTypeName(catchBlock.TypeIndex), jumpTable.GetHandlerLabel(catchBlock))); } }
private string FormatIfzOperation(IfzOpCode opcode, string comparison, Method method, JumpTable jumpTable) { return(string.Format("if ({0} {2} 0) :{1}", GetRegisterName(opcode.Destination, method), jumpTable.GetReferrerLabel(opcode.OpCodeOffset), comparison)); }
private string FormatIfOperation(IfOpCode opcode, string comparison, Method method, JumpTable jumpTable) { return(string.Format("if ({0} {3} {1}) :{2}", GetRegisterName(opcode.First, method), GetRegisterName(opcode.Second, method), jumpTable.GetReferrerLabel(opcode.OpCodeOffset), comparison)); }
internal static void MakeAndSaveTranslations(ConcurrentDictionary <ulong, TranslatedFunction> funcs, IMemoryManager memory, JumpTable jumpTable) { var profiledFuncsToTranslate = PtcProfiler.GetProfiledFuncsToTranslate(funcs); if (profiledFuncsToTranslate.Count == 0) { return; } _translateCount = 0; ThreadPool.QueueUserWorkItem(TranslationLogger, profiledFuncsToTranslate.Count); void TranslateFuncs() { while (profiledFuncsToTranslate.TryDequeue(out var item)) { ulong address = item.address; Debug.Assert(PtcProfiler.IsAddressInStaticCodeRange(address)); TranslatedFunction func = Translator.Translate(memory, jumpTable, address, item.mode, item.highCq); bool isAddressUnique = funcs.TryAdd(address, func); Debug.Assert(isAddressUnique, $"The address 0x{address:X16} is not unique."); if (func.HighCq) { jumpTable.RegisterFunction(address, func); } Interlocked.Increment(ref _translateCount); if (State != PtcState.Enabled) { break; } } } int maxDegreeOfParallelism = (Environment.ProcessorCount * 3) / 4; List <Thread> threads = new List <Thread>(); for (int i = 0; i < maxDegreeOfParallelism; i++) { Thread thread = new Thread(TranslateFuncs); thread.IsBackground = true; threads.Add(thread); } threads.ForEach((thread) => thread.Start()); threads.ForEach((thread) => thread.Join()); threads.Clear(); Translator.ResetPools(); _loggerEvent.Set(); PtcJumpTable.Initialize(jumpTable); PtcJumpTable.ReadJumpTable(jumpTable); PtcJumpTable.ReadDynamicTable(jumpTable); ThreadPool.QueueUserWorkItem(PreSave); }
internal static void LoadTranslations(ConcurrentDictionary <ulong, TranslatedFunction> funcs, IMemoryManager memory, JumpTable jumpTable) { if ((int)_infosStream.Length == 0 || (int)_codesStream.Length == 0 || (int)_relocsStream.Length == 0 || (int)_unwindInfosStream.Length == 0) { return; } Debug.Assert(funcs.Count == 0); _infosStream.Seek(0L, SeekOrigin.Begin); _codesStream.Seek(0L, SeekOrigin.Begin); _relocsStream.Seek(0L, SeekOrigin.Begin); _unwindInfosStream.Seek(0L, SeekOrigin.Begin); using (BinaryReader infosReader = new BinaryReader(_infosStream, EncodingCache.UTF8NoBOM, true)) using (BinaryReader codesReader = new BinaryReader(_codesStream, EncodingCache.UTF8NoBOM, true)) using (BinaryReader relocsReader = new BinaryReader(_relocsStream, EncodingCache.UTF8NoBOM, true)) using (BinaryReader unwindInfosReader = new BinaryReader(_unwindInfosStream, EncodingCache.UTF8NoBOM, true)) { for (int i = 0; i < GetInfosEntriesCount(); i++) { InfoEntry infoEntry = ReadInfo(infosReader); if (infoEntry.Stubbed) { SkipCode(infoEntry.CodeLen); SkipReloc(infoEntry.RelocEntriesCount); SkipUnwindInfo(unwindInfosReader); } else if (infoEntry.HighCq || !PtcProfiler.ProfiledFuncs.TryGetValue(infoEntry.Address, out var value) || !value.highCq) { byte[] code = ReadCode(codesReader, infoEntry.CodeLen); if (infoEntry.RelocEntriesCount != 0) { RelocEntry[] relocEntries = GetRelocEntries(relocsReader, infoEntry.RelocEntriesCount); PatchCode(code, relocEntries, memory.PageTablePointer, jumpTable); } UnwindInfo unwindInfo = ReadUnwindInfo(unwindInfosReader); TranslatedFunction func = FastTranslate(code, infoEntry.GuestSize, unwindInfo, infoEntry.HighCq); bool isAddressUnique = funcs.TryAdd(infoEntry.Address, func); Debug.Assert(isAddressUnique, $"The address 0x{infoEntry.Address:X16} is not unique."); } else { infoEntry.Stubbed = true; UpdateInfo(infoEntry); StubCode(infoEntry.CodeLen); StubReloc(infoEntry.RelocEntriesCount); StubUnwindInfo(unwindInfosReader); } } } if (_infosStream.Position < _infosStream.Length || _codesStream.Position < _codesStream.Length || _relocsStream.Position < _relocsStream.Length || _unwindInfosStream.Position < _unwindInfosStream.Length) { throw new Exception("Could not reach the end of one or more memory streams."); } jumpTable.Initialize(PtcJumpTable, funcs); PtcJumpTable.WriteJumpTable(jumpTable, funcs); PtcJumpTable.WriteDynamicTable(jumpTable); Logger.Info?.Print(LogClass.Ptc, $"{funcs.Count} translated functions loaded"); }
internal static void MakeAndSaveTranslations(ConcurrentDictionary <ulong, TranslatedFunction> funcs, IMemoryManager memory, JumpTable jumpTable) { if (PtcProfiler.ProfiledFuncs.Count == 0) { return; } _translateCount = 0; _rejitCount = 0; ThreadPool.QueueUserWorkItem(TranslationLogger, (funcs.Count, PtcProfiler.ProfiledFuncs.Count)); int maxDegreeOfParallelism = (Environment.ProcessorCount * 3) / 4; Parallel.ForEach(PtcProfiler.ProfiledFuncs, new ParallelOptions { MaxDegreeOfParallelism = maxDegreeOfParallelism }, (item, state) => { ulong address = item.Key; Debug.Assert(PtcProfiler.IsAddressInStaticCodeRange(address)); if (!funcs.ContainsKey(address)) { TranslatedFunction func = Translator.Translate(memory, jumpTable, address, item.Value.mode, item.Value.highCq); funcs.TryAdd(address, func); if (func.HighCq) { jumpTable.RegisterFunction(address, func); } Interlocked.Increment(ref _translateCount); } else if (item.Value.highCq && !funcs[address].HighCq) { TranslatedFunction func = Translator.Translate(memory, jumpTable, address, item.Value.mode, highCq: true); funcs[address] = func; jumpTable.RegisterFunction(address, func); Interlocked.Increment(ref _rejitCount); } if (State != PtcState.Enabled) { state.Stop(); } }); _loggerEvent.Set(); if (_translateCount != 0 || _rejitCount != 0) { PtcJumpTable.Initialize(jumpTable); PtcJumpTable.ReadJumpTable(jumpTable); PtcJumpTable.ReadDynamicTable(jumpTable); ThreadPool.QueueUserWorkItem(PreSave); } }
public override void Eval(Executor exec) { int n = exec.PopInt(); Function f = exec.TypedPop<Function>(); Function g = exec.TypedPeek<Function>(); if (g is JumpTable) { JumpTable jt = g as JumpTable; jt.AddCase(n, f); } else { exec.Pop(); JumpTable jt = new JumpTable(g); exec.Push(jt); } }
internal static void MakeAndSaveTranslations( ConcurrentDictionary <ulong, TranslatedFunction> funcs, IMemoryManager memory, JumpTable jumpTable, EntryTable <uint> countTable) { var profiledFuncsToTranslate = PtcProfiler.GetProfiledFuncsToTranslate(funcs); _translateCount = 0; _translateTotalCount = profiledFuncsToTranslate.Count; int degreeOfParallelism = new DegreeOfParallelism(4d, 75d, 12.5d).GetDegreeOfParallelism(0, 32); if (_translateTotalCount == 0 || degreeOfParallelism == 0) { ResetCarriersIfNeeded(); PtcJumpTable.ClearIfNeeded(); GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce; return; } Logger.Info?.Print(LogClass.Ptc, $"{_translateCount} of {_translateTotalCount} functions translated | Thread count: {degreeOfParallelism}"); PtcStateChanged?.Invoke(PtcLoadingState.Start, _translateCount, _translateTotalCount); using AutoResetEvent progressReportEvent = new AutoResetEvent(false); Thread progressReportThread = new Thread(ReportProgress) { Name = "Ptc.ProgressReporter", Priority = ThreadPriority.Lowest, IsBackground = true }; progressReportThread.Start(progressReportEvent); void TranslateFuncs() { while (profiledFuncsToTranslate.TryDequeue(out var item)) { ulong address = item.address; Debug.Assert(PtcProfiler.IsAddressInStaticCodeRange(address)); TranslatedFunction func = Translator.Translate(memory, jumpTable, countTable, address, item.funcProfile.Mode, item.funcProfile.HighCq); bool isAddressUnique = funcs.TryAdd(address, func); Debug.Assert(isAddressUnique, $"The address 0x{address:X16} is not unique."); if (func.HighCq) { jumpTable.RegisterFunction(address, func); } Interlocked.Increment(ref _translateCount); if (State != PtcState.Enabled) { break; } } Translator.DisposePools(); } List <Thread> threads = new List <Thread>(); for (int i = 0; i < degreeOfParallelism; i++) { Thread thread = new Thread(TranslateFuncs); thread.IsBackground = true; threads.Add(thread); } threads.ForEach((thread) => thread.Start()); threads.ForEach((thread) => thread.Join()); threads.Clear(); progressReportEvent.Set(); progressReportThread.Join(); PtcStateChanged?.Invoke(PtcLoadingState.Loaded, _translateCount, _translateTotalCount); Logger.Info?.Print(LogClass.Ptc, $"{_translateCount} of {_translateTotalCount} functions translated | Thread count: {degreeOfParallelism}"); PtcJumpTable.Initialize(jumpTable); PtcJumpTable.ReadJumpTable(jumpTable); PtcJumpTable.ReadDynamicTable(jumpTable); Thread preSaveThread = new Thread(PreSave); preSaveThread.IsBackground = true; preSaveThread.Start(); }
public override void Eval(Executor exec) { QuotedFunction f = exec.TypedPop<QuotedFunction>(); f.GetSubFxns().Insert(0, new Pop()); JumpTable jt = new JumpTable(f); exec.Push(jt); }