private IEnumerable <ProgramState> ProcessSwt(ILInstruction instruction, ProgramState next) { var result = new List <ProgramState>(); var symbolicTableSlot = next.Stack.Pop(); var symbolicValue = next.Stack.Pop(); instruction.Dependencies.AddOrMerge(0, symbolicTableSlot); instruction.Dependencies.AddOrMerge(1, symbolicValue); var annotation = new JumpAnnotation { InferredPopCount = instruction.Dependencies.Count, InferredPushCount = 0 }; ulong tableAddress = symbolicTableSlot.InferStackValue().U8; var reader = KoiStream.Contents.CreateReader(); reader.Offset = (uint)(tableAddress - 2); ushort count = reader.ReadUInt16(); for (int i = 0; i < count; i++) { int relativeOffset = reader.ReadInt32(); ulong nextIp = (ulong)((long)next.IP + relativeOffset); Logger.Debug2(Tag, $"Inferred edge IL_{instruction.Offset:X4} -> IL_{nextIp:X4}"); var caseState = next.Copy(); caseState.IP = nextIp; result.Add(caseState); annotation.InferredJumpTargets.Add(nextIp); } result.Add(next); instruction.Annotation = annotation; return(result); }
private JumpAnnotation InferJumpTargets(ILInstruction instruction) { try { var metadata = new JumpAnnotation(); var symbolicAddress = instruction.Dependencies[instruction.Dependencies.Count - 1]; foreach (var dataSource in symbolicAddress.DataSources) { var emulator = new InstructionEmulator(); emulator.EmulateDependentInstructions(dataSource); emulator.EmulateInstruction(dataSource); // After partial emulation, IP is on stack. uint nextIp = (uint)emulator.Stack.Pop().U8; Logger.Debug2(Tag, $"Inferred edge IL_{instruction.Offset:X4} -> IL_{nextIp:X4}"); if (nextIp > (ulong)KoiStream.Contents.GetPhysicalSize()) { Logger.Warning(Tag, $"Jump instruction at IL_{instruction.Offset:X4} " + $"transfers control to an instruction outside of the KoiVM stream (IL_{nextIp:X4}."); } metadata.InferredJumpTargets.Add(nextIp); } instruction.Annotation = metadata; return(metadata); } catch (NotSupportedException e) { Logger.Warning(Tag, $"Could not infer jump target for {instruction.Offset:X4}. {e.Message}"); } return(null); }