Example #1
0
        private IEnumerable <Group> GroupInstruction()
        {
            var body = this._Function.Body;

            if (_Index >= body.Length)
            {
                yield break;
            }

            var instruction = body[_Index++];

            IEnumerable <Group> enumerable;

            var info = OpcodeInfo.Get(instruction.Op);

            if (info.ChainCount >= 0)
            {
                enumerable = GroupBasicInstruction(info.ChainCount);
            }
            else if (instruction.Op == Opcode.Construct)
            {
                (var parameterCount, _) = ((byte, ClassDefinition))instruction.Argument;
                enumerable = GroupBasicInstruction(parameterCount);
            }
            else if (instruction.Op == Opcode.Call)
            {
                (_, _, var functionType) = ((short, ushort, FunctionDefinition))instruction.Argument;
                var parameterCount = functionType.Parameters == null
                    ? 0
                    : functionType.Parameters.Length;
                parameterCount++; // EndCall
                enumerable = GroupBasicInstruction(parameterCount);
            }
            else if (instruction.Op == Opcode.Switch)
            {
                enumerable = GroupSwitchInstruction();
            }
            else if (instruction.Op == Opcode.SwitchCase)
            {
                enumerable = GroupSwitchCaseInstruction();
            }
            else if (instruction.Op == Opcode.SwitchDefault)
            {
                enumerable = GroupSwitchDefaultInstruction();
            }
            else
            {
                throw new NotImplementedException();
            }

            var group = new Group(instruction);

            foreach (var child in enumerable)
            {
                group.Children.Add(child);
            }
            yield return(group);
        }
Example #2
0
        private static unsafe delegate*<VirtualMachine, void> GetFunctionPointer(OpcodeInfo opcode, int mode)
        {
            if (opcode == null)
                return null;

            if (opcode.Emulators[mode] != null)
                return (delegate*<VirtualMachine, void>)((IntPtr)typeof(Delegate).GetField("_methodPtrAux", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).GetValue(opcode.Emulators[mode])).ToPointer();

            return null;
        }
Example #3
0
 public static DecodedOperands?TryDecode(OpcodeInfo opcode, ReadOnlySpan <byte> rawData, PrefixState prefixes)
 {
     try
     {
         return(Decode(opcode, rawData, prefixes, out _));
     }
     catch
     {
         return(null);
     }
 }
Example #4
0
        /// <summary>
        /// Initializes a new instance of the Instruction class.
        /// </summary>
        /// <param name="opcodeInfo">Information about the instruction opcode.</param>
        /// <param name="rawCodes">Machine code for the instruction.</param>
        /// <param name="cs">Segment where instruction was decoded from.</param>
        /// <param name="ip">Offset where instruction was decoded from.</param>
        /// <param name="bigMode">Indicates whether the instruction should be decoded in big (32-bit) mode.</param>
        internal Instruction(OpcodeInfo opcodeInfo, byte[] rawCodes, ushort cs, uint ip, bool bigMode)
        {
            if (opcodeInfo != null)
            {
                for (int i = 0; i < 12; i++)
                {
                    this.operandCodes[i] = rawCodes[opcodeInfo.Length + i];
                }
            }

            this.Opcode  = opcodeInfo;
            this.CS      = cs;
            this.offset  = ip;
            this.BigMode = bigMode;
        }
Example #5
0
        /// <summary>
        /// Assigns new values to the instruction instance.
        /// </summary>
        /// <param name="opcodeInfo">Information about the instruction opcode.</param>
        /// <param name="rawCodes">Operand data starting with the first byte after the opcode.</param>
        /// <param name="cs">Code segment of the instruction.</param>
        /// <param name="ip">Offset in the current code segment of the instruction.</param>
        /// <param name="bigMode">Indicates whether the instruction should be decoded in big (32-bit) mode.</param>
        internal void Assign(OpcodeInfo opcodeInfo, IntPtr rawCodes, ushort cs, uint ip, bool bigMode)
        {
            unsafe
            {
                byte *ptr = (byte *)rawCodes.ToPointer();
                for (int i = 0; i < this.operandCodes.Length; i++)
                {
                    this.operandCodes[i] = ptr[i];
                }
            }

            this.Opcode         = opcodeInfo;
            this.CS             = cs;
            this.offset         = ip;
            this.BigMode        = bigMode;
            this.formattedValue = null;
        }
Example #6
0
        /// <summary>
        /// Writes a start trace of the Dispatch method.
        /// </summary>
        /// <param name="opcode">The dispatched opcode.</param>
        /// <param name="index">Optional dispatch paremeter.</param>
        /// <param name="value">Optional dispatch paremeter.</param>
        /// <param name="ptr">Optional dispatch paremeter.</param>
        /// <param name="opt">Optional dispatch paremeter.</param>
        /// <remarks>
        /// The trace text is output as a <see cref="TraceEventType.Verbose"/> event type.
        /// </remarks>
        public void WriteDispatchBegin(int opcode, int index, IntPtr value, IntPtr ptr, float opt)
        {
            if (_traceSource.Switch.ShouldTrace(TraceEventType.Verbose))
            {
                string     message    = "Dispatch (Begin) ";
                OpcodeInfo opcodeInfo = LookupOpcodeInfo(opcode);

                if (opcodeInfo != null)
                {
                    message += opcodeInfo.FormatArguments(index, value, ptr, opt);
                }
                else
                {
                    message += String.Format("Opcode={0} Index={1}, Value={2} Ptr={3} Opt={4}.", opcode, index, value, ptr, opt);
                }

                WriteEvent(TraceEventType.Verbose, message);
            }
        }
Example #7
0
        internal void Assign(OpcodeInfo opcodeInfo, IntPtr rawCodes, Processor processor, uint ip)
        {
            base.Assign(opcodeInfo, rawCodes, processor.CS, ip, processor.GlobalSize != 0);

            this.EAX   = (uint)processor.EAX;
            this.EBX   = (uint)processor.EBX;
            this.ECX   = (uint)processor.ECX;
            this.EDX   = (uint)processor.EDX;
            this.ESI   = processor.ESI;
            this.EDI   = processor.EDI;
            this.EBP   = processor.EBP;
            this.DS    = processor.DS;
            this.ES    = processor.ES;
            this.FS    = processor.FS;
            this.GS    = processor.GS;
            this.SS    = processor.SS;
            this.ESP   = processor.ESP;
            this.Flags = processor.Flags.Value & ~EFlags.Reserved1;
            this.CR0   = processor.CR0;
        }
Example #8
0
        internal static void Initialize()
        {
            var isb = new InstructionSetBuilder();
            isb.BuildSet();

            foreach (var info in isb.OneByteOpcodes)
                oneByteCodes[info.Opcode] = new OpcodeInfo(info);

            foreach (var info in isb.TwoByteOpcodes)
            {
                int byte1 = info.Opcode & 0xFF;
                int byte2 = (info.Opcode >> 8) & 0xFF;

                if (info.ModRmByte != ModRmInfo.OnlyRm)
                {
                    if (twoByteCodes[byte1] == null)
                        twoByteCodes[byte1] = new OpcodeInfo[256];
                    twoByteCodes[byte1][byte2] = new OpcodeInfo(info);
                }
                else
                {
                    if (twoByteRmCodes[byte1] == null)
                        twoByteRmCodes[byte1] = new OpcodeInfo[256][];
                    if (twoByteRmCodes[byte1][byte2] == null)
                        twoByteRmCodes[byte1][byte2] = new OpcodeInfo[8];
                    twoByteRmCodes[byte1][byte2][info.ExtendedRmOpcode] = new OpcodeInfo(info);
                }
            }

            foreach (var info in isb.ExtendedOpcodes)
            {
                if (rmCodes[info.Opcode] == null)
                    rmCodes[info.Opcode] = new OpcodeInfo[8];
                rmCodes[info.Opcode][info.ExtendedRmOpcode] = new OpcodeInfo(info);
            }

            allCodes = new OpcodeCollection();

            InitializeNativeArrays();
        }
Example #9
0
 public static DecodedOperands Decode(OpcodeInfo opcode, ReadOnlySpan <byte> rawData, PrefixState prefixes) => Decode(opcode, rawData, prefixes, out _);
Example #10
0
        private static DecodedOperands Decode(OpcodeInfo opcode, ReadOnlySpan <byte> rawData, PrefixState prefixes, out int length)
        {
            var reader   = new OperandReader(rawData);
            var operands = new DecodedOperands();

            length = 0;

            if (opcode.Operands.Count == 0)
            {
                return(operands);
            }

            if (opcode.ModRmInfo != ModRmInfo.None)
            {
                byte modRmByte = reader.ReadByte();
                int  mod       = (modRmByte & 0xC0) >> 6;
                int  rm        = modRmByte & 0x07;

                for (int i = 0; i < opcode.Operands.Count; i++)
                {
                    var type = opcode.Operands[i];
                    if (type == OperandType.RegisterOrMemoryByte)
                    {
                        operands.SetOperand(i, DecodeRmbw(mod, rm, true, prefixes, ref reader));
                    }
                    else if (IsPointerOperand(type))
                    {
                        var operand = DecodeRmbw(mod, rm, false, prefixes, ref reader);
                        if (type == OperandType.EffectiveAddress)
                        {
                            operand.Type = CodeOperandType.EffectiveAddress;
                        }
                        else if (type == OperandType.FullLinearAddress)
                        {
                            operand.Type = CodeOperandType.FullLinearAddress;
                        }
                        else if (type == OperandType.RegisterOrMemoryWordNearPointer)
                        {
                            operand.Type = CodeOperandType.AbsoluteJumpAddress;
                        }
                        else if (type == OperandType.IndirectFarPointer)
                        {
                            operand.Type = CodeOperandType.IndirectFarMemoryAddress;
                        }
                        else if (type == OperandType.MemoryInt16 || type == OperandType.RegisterOrMemory16)
                        {
                            operand.OperandSize = CodeOperandSize.Word;
                        }
                        else if (type == OperandType.MemoryInt32 || type == OperandType.RegisterOrMemory32)
                        {
                            operand.OperandSize = CodeOperandSize.DoubleWord;
                        }
                        else if (type == OperandType.MemoryInt64)
                        {
                            operand.OperandSize = CodeOperandSize.QuadWord;
                        }
                        else if (type == OperandType.MemoryFloat32)
                        {
                            operand.OperandSize = CodeOperandSize.Single;
                        }
                        else if (type == OperandType.MemoryFloat64)
                        {
                            operand.OperandSize = CodeOperandSize.Double;
                        }
                        else if (type == OperandType.MemoryFloat80)
                        {
                            operand.OperandSize = CodeOperandSize.LongDouble;
                        }

                        operands.SetOperand(i, operand);
                    }
                }

                if (opcode.ModRmInfo == ModRmInfo.All)
                {
                    int reg = (modRmByte & 0x38) >> 3;
                    for (int i = 0; i < opcode.Operands.Count; i++)
                    {
                        var type = opcode.Operands[i];
                        if (type == OperandType.RegisterByte)
                        {
                            operands.SetOperand(i, DecodeRb(reg));
                        }
                        else if (type == OperandType.RegisterWord)
                        {
                            operands.SetOperand(i, DecodeRw(reg, prefixes));
                        }
                        else if (type == OperandType.SegmentRegister)
                        {
                            operands.SetOperand(i, DecodeSreg(reg));
                        }
                    }
                }
            }

            for (int i = 0; i < opcode.Operands.Count; i++)
            {
                var type = opcode.Operands[i];
                if (IsKnownRegister(type))
                {
                    operands.SetOperand(i, new CodeOperand(DecodeKnownRegister(type, (prefixes & PrefixState.OperandSize) != 0)));
                }
                else if (type == OperandType.ImmediateByte)
                {
                    operands.SetOperand(i, new CodeOperand(CodeOperandType.Immediate, reader.ReadByte(), CodeOperandSize.Byte));
                }
                else if (type == OperandType.ImmediateByteExtend || type == OperandType.ImmediateRelativeByte)
                {
                    var operand = new CodeOperand(CodeOperandType.Immediate, (uint)(int)reader.ReadSByte(), GetOperandSize(false, prefixes));
                    if (type == OperandType.ImmediateRelativeByte)
                    {
                        operand.Type = CodeOperandType.RelativeJumpAddress;
                    }

                    operands.SetOperand(i, operand);
                }
                else if (type == OperandType.ImmediateInt16)
                {
                    operands.SetOperand(i, new CodeOperand(CodeOperandType.Immediate, reader.ReadUInt16(), CodeOperandSize.Word));
                }
                else if (type == OperandType.ImmediateInt32)
                {
                    operands.SetOperand(i, new CodeOperand(CodeOperandType.Immediate, reader.ReadUInt32(), CodeOperandSize.DoubleWord));
                }
                else if (type == OperandType.ImmediateWord)
                {
                    uint value;
                    if ((prefixes & PrefixState.OperandSize) == 0)
                    {
                        value = reader.ReadUInt16();
                    }
                    else
                    {
                        value = reader.ReadUInt32();
                    }

                    operands.SetOperand(i, new CodeOperand(CodeOperandType.Immediate, value, GetOperandSize(false, prefixes)));
                }
                else if (type == OperandType.ImmediateRelativeWord)
                {
                    uint value;
                    if ((prefixes & PrefixState.OperandSize) == 0)
                    {
                        value = (uint)(int)reader.ReadInt16();
                    }
                    else
                    {
                        value = reader.ReadUInt32();
                    }

                    operands.SetOperand(i, new CodeOperand(CodeOperandType.RelativeJumpAddress, value, GetOperandSize(false, prefixes)));
                }
                else if (type == OperandType.MemoryOffsetByte || type == OperandType.MemoryOffsetWord)
                {
                    uint value;
                    if ((prefixes & PrefixState.AddressSize) == 0)
                    {
                        value = (uint)(int)reader.ReadInt16();
                    }
                    else
                    {
                        value = reader.ReadUInt32();
                    }

                    operands.SetOperand(i, new CodeOperand(CodeMemoryBase.DisplacementOnly, value, GetOperandSize(type == OperandType.MemoryOffsetByte, prefixes)));
                }
                else if (type == OperandType.ImmediateFarPointer)
                {
                    uint value;
                    if ((prefixes & PrefixState.AddressSize) == 0)
                    {
                        value = reader.ReadUInt16();
                    }
                    else
                    {
                        value = reader.ReadUInt32();
                    }

                    ushort segment = reader.ReadUInt16();
                    operands.SetOperand(i, CodeOperand.FarPointer(segment, value));
                }
            }

            length = reader.Position;
            return(operands);
        }
Example #11
0
 public static int CalculateOperandLength(OpcodeInfo opcode, ReadOnlySpan <byte> rawData, PrefixState prefixes)
 {
     Decode(opcode, rawData, prefixes, out int length);
     return(length);
 }
Example #12
0
        private Instruction MakeInstruction(int offset, OpcodeInfo opcodeInfo, ushort extraData)
        {
            Operand operand1, operand2;

            // Handle simple instructions
            if (opcodeInfo.FirstOperand == DisassemblyOperand.None)
            {
                switch (opcodeInfo.Operation)
                {
                case Operation.Nop: return(new ControlInstruction(offset, ControlInstructionType.NoOperation));

                case Operation.Stop: return(new ControlInstruction(offset, ControlInstructionType.Stop));

                case Operation.Halt: return(new ControlInstruction(offset, ControlInstructionType.Halt));

                case Operation.Di: return(new ControlInstruction(offset, ControlInstructionType.DisableInterrupts));

                case Operation.Ei: return(new ControlInstruction(offset, ControlInstructionType.EnableInterrupts));

                case Operation.Ret: return(new ReturnInstruction(offset));

                case Operation.Reti: return(new ReturnInstruction(offset, true));

                case Operation.Rlca: return(new ShiftInstruction(offset, ShiftInstructionFlags.RotateRightCircular, Operand.DirectA));

                case Operation.Rrca: return(new ShiftInstruction(offset, ShiftInstructionFlags.RotateLeftCircular, Operand.DirectA));

                case Operation.Rla: return(new ShiftInstruction(offset, ShiftInstructionFlags.RotateRight, Operand.DirectA));

                case Operation.Rra: return(new ShiftInstruction(offset, ShiftInstructionFlags.RotateLeft, Operand.DirectA));

                case Operation.Daa: return(new UtilityInstruction(offset, UtilityOperation.DecimalAdjustAfter));

                case Operation.Cpl: return(new UtilityInstruction(offset, UtilityOperation.DecimalAdjustAfter));

                case Operation.Scf: return(new UtilityInstruction(offset, UtilityOperation.DecimalAdjustAfter));

                case Operation.Ccf: return(new UtilityInstruction(offset, UtilityOperation.DecimalAdjustAfter));

                default: throw new NotImplementedException() /*return new ControlInstruction(offset, ControlInstructionType.NoOperation)*/;
                }
            }
            // Handle jump instructions (and the conditional return instruction too)
            else if (opcodeInfo.Operation == Operation.Jp ||
                     opcodeInfo.Operation == Operation.Jr ||
                     opcodeInfo.Operation == Operation.Call ||
                     opcodeInfo.Operation == Operation.Rst ||
                     opcodeInfo.Operation == Operation.Ret)
            {
                Label     label;
                JumpType  jumpType;
                Condition condition;
                ushort    mappedOffset, destination;

                switch (opcodeInfo.FirstOperand)
                {
                case DisassemblyOperand.NotZero: condition = Condition.NotZero; break;

                case DisassemblyOperand.Zero: condition = Condition.Zero; break;

                case DisassemblyOperand.NotCarry: condition = Condition.CarryClear; break;

                case DisassemblyOperand.Carry: condition = Condition.CarrySet; break;

                default: condition = Condition.Always; break;
                }

                switch (opcodeInfo.Operation)
                {
                case Operation.Ret: return(new ReturnInstruction(offset, condition));

                case Operation.Jr: jumpType = JumpType.Relative; break;

                case Operation.Jp: jumpType = JumpType.Absolute; break;

                default: jumpType = JumpType.FunctionCall; break;
                }

                if (offset < 0x8000)
                {
                    mappedOffset = (ushort)offset;
                }
                else
                {
                    mappedOffset = (ushort)(0x4000 | (offset & 0x3FFF));
                }

                if (opcodeInfo.Operation == Operation.Rst)
                {
                    destination = opcodeInfo.EmbeddedValue;
                }
                else if (opcodeInfo.Operation == Operation.Jr)
                {
                    unchecked { destination = (ushort)(mappedOffset + 2 + (sbyte)(byte)extraData); }                     // Add 2 to the offset because of the jump instruction length
                }
                else
                {
                    destination = extraData;
                }

                if (destination >= 0x8000 || (IsRomBanked && destination >= 0x4000 && mappedOffset < 0x4000))
                {
                    return(new JumpInstruction(offset, jumpType, condition, extraData));
                }
                else if (jumpType == JumpType.FunctionCall)
                {
                    label = DefineFunctionLabel((offset & ~0x3FFF) | destination);
                }
                else
                {
                    label = DefineLabel((offset & ~0x3FFF) | destination);
                }
                return(new ResolvedJumpInstruction(offset, jumpType, condition, destination, label));
            }
            // Handle single-operand instructions
            else if (opcodeInfo.SecondOperand == DisassemblyOperand.None)
            {
                operand1 = MakeOperand(opcodeInfo.FirstOperand, opcodeInfo.EmbeddedValue, extraData);

                switch (opcodeInfo.Operation)
                {
                case Operation.Inc: return(new ArithmeticInstruction(offset, ArithmeticOperation.Add, operand1, new Operand <byte>(1)));

                case Operation.Dec: return(new ArithmeticInstruction(offset, ArithmeticOperation.Substract, operand1, new Operand <byte>(1)));

                case Operation.Pop: return(new PopInstruction(offset, operand1));

                case Operation.Push: return(new PushInstruction(offset, operand1));

                case Operation.Rlc: return(new ShiftInstruction(offset, ShiftInstructionFlags.RotateRightCircular, operand1));

                case Operation.Rrc: return(new ShiftInstruction(offset, ShiftInstructionFlags.RotateLeftCircular, operand1));

                case Operation.Rl: return(new ShiftInstruction(offset, ShiftInstructionFlags.RotateRight, operand1));

                case Operation.Rr: return(new ShiftInstruction(offset, ShiftInstructionFlags.RotateLeft, operand1));

                case Operation.Sla: return(new ShiftInstruction(offset, ShiftInstructionFlags.ShiftLeftArithmetical, operand1));

                case Operation.Sra: return(new ShiftInstruction(offset, ShiftInstructionFlags.ShiftRightArithmetical, operand1));

                case Operation.Srl: return(new ShiftInstruction(offset, ShiftInstructionFlags.ShiftRightLogical, operand1));

                case Operation.Swap: return(new SwapInstruction(offset, operand1));

                default: throw new InvalidOperationException();
                }
            }
            // Handle remaining instructions
            else
            {
                operand1 = MakeOperand(opcodeInfo.FirstOperand, opcodeInfo.EmbeddedValue, extraData);
                operand2 = MakeOperand(opcodeInfo.SecondOperand, opcodeInfo.EmbeddedValue, extraData);

                switch (opcodeInfo.Operation)
                {
                case Operation.Ld: return(new LoadInstruction(offset, operand1, operand2));

                case Operation.Ldi: return(new LoadInstruction(offset, LoadOperationType.IncrementHl, operand1, operand2));

                case Operation.Ldd: return(new LoadInstruction(offset, LoadOperationType.DecrementHl, operand1, operand2));

                case Operation.Add: return(new ArithmeticInstruction(offset, ArithmeticOperation.Add, operand1, operand2));

                case Operation.Adc: return(new ArithmeticInstruction(offset, ArithmeticOperation.AddWithCarry, operand1, operand2));

                case Operation.Sub: return(new ArithmeticInstruction(offset, ArithmeticOperation.Substract, operand1, operand2));

                case Operation.Sbc: return(new ArithmeticInstruction(offset, ArithmeticOperation.SubstractWithCarry, operand1, operand2));

                case Operation.And: return(new ArithmeticInstruction(offset, ArithmeticOperation.And, operand1, operand2));

                case Operation.Xor: return(new ArithmeticInstruction(offset, ArithmeticOperation.Xor, operand1, operand2));

                case Operation.Or: return(new ArithmeticInstruction(offset, ArithmeticOperation.Or, operand1, operand2));

                case Operation.Cp: return(new ArithmeticInstruction(offset, ArithmeticOperation.Compare, operand1, operand2));

                case Operation.Bit: return(new BitInstruction(offset, BitOperation.Test, operand1, operand2));

                case Operation.Set: return(new BitInstruction(offset, BitOperation.Set, operand1, operand2));

                case Operation.Res: return(new BitInstruction(offset, BitOperation.Clear, operand1, operand2));

                default: throw new InvalidOperationException();
                }
            }
        }
Example #13
0
        public void read(Reader reader)
        {
            foreach (ScriptSub sub in subs)
            {
                sub.scriptCode.Clear();
                sub.blankLines.Clear();
                sub.labels.Clear();
                sub.jumpTable.Clear();

                bool finishedScriptCode = false;

                int scriptCodeLength = reader.ReadByte() << 8;
                scriptCodeLength |= reader.ReadByte();

                sub.scriptCode.Clear();
                while (!finishedScriptCode)
                {
                    byte scriptOpcode = reader.ReadByte();
                    if (scriptOpcode == 0xFF)
                    {
                        scriptOpcode = reader.ReadByte();
                        if (scriptOpcode == 0xFF)
                        {
                            scriptOpcode = reader.ReadByte();
                            if (scriptOpcode == 0xFF)
                            {
                                scriptOpcode = reader.ReadByte();
                                if (scriptOpcode == 0xFF)
                                {
                                    finishedScriptCode = true;
                                }
                            }
                        }
                    }

                    if (!finishedScriptCode)
                    {
                        OpcodeInfo opInfo = new OpcodeInfo();

                        opInfo.opcode = scriptOpcode;

                        uint paramCount = (uint)opcodeList[scriptOpcode].paramCount;
                        opInfo.parameters.Clear();

                        for (int p = 0; p < paramCount; p++)
                        {
                            ParamInfo param = new ParamInfo();

                            int paramType = reader.ReadByte(); // if 0 then int constant, else variable

                            if (paramType != 0)
                            {
                                param.isVariable = true;

                                param.value = reader.ReadByte();

                                int arrayIndex = reader.ReadByte();
                                if (arrayIndex > 0x80)
                                {
                                    arrayIndex = 0x80 - arrayIndex;
                                }

                                param.arrayIndex = (sbyte)arrayIndex;
                            }
                            else
                            {
                                param.isVariable = false;
                                param.arrayIndex = -1;

                                int byte1    = reader.ReadByte();
                                int constVal = 0;
                                if (byte1 < 0x80) // unsigned uint16
                                {
                                    constVal  = byte1 << 8;
                                    constVal |= reader.ReadByte();
                                }
                                else // signed uint16
                                {
                                    constVal  = (byte1 - 0x80) << 8;
                                    constVal |= reader.ReadByte();
                                    constVal  = -constVal;
                                }

                                param.value = constVal;
                            }
                            opInfo.parameters.Add(param);
                        }

                        sub.scriptCode.Add(opInfo);
                    }
                }

                int blankLineUnused = reader.ReadByte();
                int blankLineCount  = reader.ReadByte();
                for (int u = 0; u < blankLineCount; u++)
                {
                    int blankLineID = reader.ReadByte() << 8;
                    blankLineID |= reader.ReadByte();
                    sub.blankLines.Add(blankLineID);
                }

                int labelUnused = reader.ReadByte();
                int labelCount  = reader.ReadByte();
                for (int l = 0; l < labelCount; l++)
                {
                    LabelInfo label = new LabelInfo();

                    label.scriptCodePos  = reader.ReadByte() << 8;
                    label.scriptCodePos |= reader.ReadByte();

                    label.id  = reader.ReadByte() << 8;
                    label.id |= reader.ReadByte();

                    label.lineID  = reader.ReadByte() << 8;
                    label.lineID |= reader.ReadByte();

                    sub.labels.Add(label);
                }

                int jumpTableUnused = reader.ReadByte();
                int jumpTableCount  = reader.ReadByte();
                for (int s = 0; s < jumpTableCount; ++s)
                {
                    SwitchInfo info = new SwitchInfo();

                    info.scriptCodePos  = reader.ReadByte() << 8;
                    info.scriptCodePos |= reader.ReadByte();

                    int caseCount = reader.ReadByte() << 8;
                    caseCount |= reader.ReadByte();

                    info.defaultScriptCodePos  = reader.ReadByte() << 8;
                    info.defaultScriptCodePos |= reader.ReadByte();

                    info.defaultCaseLineID  = reader.ReadByte() << 8;
                    info.defaultCaseLineID |= reader.ReadByte();

                    info.endScriptCodePos  = reader.ReadByte() << 8;
                    info.endScriptCodePos |= reader.ReadByte();

                    // if (info.defaultScriptCodePos == 0)
                    //     info.defaultScriptCodePos = info.endScriptCodePos;

                    int lowestCase  = 0x8000;
                    int highestCase = 0;
                    info.cases.Clear();
                    for (int c = 0; c < caseCount; c++)
                    {
                        SwitchCaseInfo caseInfo = new SwitchCaseInfo();

                        caseInfo.scriptCodePos  = reader.ReadByte() << 8;
                        caseInfo.scriptCodePos |= reader.ReadByte();

                        caseInfo.caseNum  = reader.ReadByte() << 8;
                        caseInfo.caseNum |= reader.ReadByte();

                        if (caseInfo.caseNum < lowestCase)
                        {
                            lowestCase = caseInfo.caseNum;
                        }

                        if (caseInfo.caseNum > highestCase)
                        {
                            highestCase = caseInfo.caseNum;
                        }

                        caseInfo.lineID  = reader.ReadByte() << 8;
                        caseInfo.lineID |= reader.ReadByte();

                        info.cases.Add(caseInfo);
                    }


                    info.lowestCase  = lowestCase;
                    info.highestCase = highestCase;

                    // Take any duds and make em default cases
                    // for (int m = lowestCase; m <= highestCase; ++m)
                    // {
                    //     int jump = sub.scriptCode[caseTablePos + m];
                    //     if (jump == 0)
                    //         sub.scriptCode[caseTablePos + m] = sub.jumpTable[startSwitchTablePos + 2];
                    // }

                    // wow this is weird
                    // it manually goes and sets up the offsets instead of doing it at compile-time like later RSDK versions
                    int pos = 0;
                    foreach (OpcodeInfo opcodeInfo in sub.scriptCode)
                    {
                        if (pos == info.scriptCodePos)
                        {
                            opcodeInfo.parameters[1].value = pos;
                            break;
                        }
                        pos += opcodeInfo.size;
                    }

                    sub.jumpTable.Add(info);
                }
            }

            reader.Close();
        }
Example #14
0
 public Instruction(TokenStream tokenStream, OpcodeInfo opcode) : base(tokenStream)
 {
     this.opcode = opcode;
 }
        private IEnumerable <Group> GroupInstruction()
        {
            var body = this._Function.Body;

            if (_Index >= body.Count)
            {
                yield break;
            }

            var instruction = body[_Index++];

            IEnumerable <Group> enumerable;

            var info = OpcodeInfo.Get(instruction.Op);

            if (info.ChainCount >= 0)
            {
                enumerable = GroupBasicInstruction(info.ChainCount);
            }
            else if (instruction.Op == Opcode.Constructor)
            {
                var(parameterCount, _) = (Constructor)instruction.Argument;
                enumerable             = GroupBasicInstruction(parameterCount);
            }
            else if (instruction.Op == Opcode.FinalFunc)
            {
                var(_, _, function) = (FinalFunc)instruction.Argument;
                var parameterCount = function.Parameters.Count;
                parameterCount++; // EndCall
                enumerable = GroupBasicInstruction(parameterCount);
            }
            else if (instruction.Op == Opcode.VirtualFunc)
            {
                // TODO(gibbed): dodgy af

                /*var (_, _, name) = ((short, ushort, string))instruction.Argument;
                 * var candidates = this._Cache.Definitions.Where(d => d.Name == name).ToArray();
                 * if (candidates.Length != 1)
                 * {
                 *  enumerable = GroupBasicInstruction(1);
                 * }
                 * else
                 * {
                 *  var function = (FunctionDefinition)candidates[0];
                 *  var parameterCount = function.Parameters.Count;
                 *  parameterCount++; // EndCall
                 *  enumerable = GroupBasicInstruction(parameterCount);
                 * }*/
                enumerable = GroupCallNameInstruction();
            }
            else if (instruction.Op == Opcode.Switch)
            {
                enumerable = GroupSwitchInstruction();
            }
            else if (instruction.Op == Opcode.SwitchLabel)
            {
                enumerable = GroupSwitchCaseInstruction();
            }
            else if (instruction.Op == Opcode.SwitchDefault)
            {
                enumerable = GroupSwitchDefaultInstruction();
            }
            else
            {
                throw new NotImplementedException();
            }

            var group = new Group(instruction);

            foreach (var child in enumerable)
            {
                group.Children.Add(child);
            }
            yield return(group);
        }
Example #16
0
 private static Exception GetPartiallyNotImplementedException(VirtualMachine vm, OpcodeInfo info) => new NotImplementedException($"Instruction '{info.Name}' not implemented for {vm.Processor.AddressSize}-bit addressing, {vm.Processor.OperandSize}-bit operand size.");