Пример #1
0
 public Instruction(Int32 _instruction)
 {
     this.Raw      = _instruction;
     this.Opcode   = Instruction.GetOpcode(_instruction);
     this.Argument = (byte)((_instruction >> 16) & 0xFF);
     this.Data     = (Int16)(_instruction & 0xFFFF);
 }
Пример #2
0
 public InstructionDefinition(LOpcode _opcode)
 {
     this.Opcode = new LOpcode[] { _opcode };
 }
Пример #3
0
        public void Parse(Game _game)
        {
            // Parse all instructions
            while (this.Reader.BaseStream.Position < this.Reader.BaseStream.Length)
            {
                this.BranchTable[this.Reader.BaseStream.Position] = this.Instructions.Count;
                Int32   _instructionGet = this.Reader.ReadInt32();
                LOpcode _opcodeGet      = Instruction.GetOpcode(_instructionGet);
                if (Instruction.Ignore.Contains(_opcodeGet) == false)
                {
                    if (Instruction.Mapping.ContainsKey(_opcodeGet) == true)
                    {
                        this.Instructions.Add(Instruction.Mapping[_opcodeGet](_instructionGet, _game, this, this.Reader));
                    }
                    else
                    {
                        throw new Exception(String.Format("Could not find instruction mapping for {0} at {1} in {2}", _opcodeGet, this.Reader.BaseStream.Position, this.Name));
                    }
                }
            }

            // Map out branching & environments
            for (int i = 0; i < this.Instructions.Count; i++)
            {
                switch (this.Instructions[i].Opcode)
                {
                case LOpcode.b:
                case LOpcode.bt:
                case LOpcode.bf: {
                    Instructions.Branch _instructionBranch = this.Instructions[i] as Instructions.Branch;
                    if (this.BranchTable.ContainsKey(_instructionBranch.Offset) == true)
                    {
                        _instructionBranch.Jump = this.BranchTable[_instructionBranch.Offset] - 1;
                    }
                    else
                    {
                        _instructionBranch.Jump = this.Instructions.Count;
                    }
                    break;
                }

                case LOpcode.pushenv: {
                    Instructions.PushEnvironment _instructionEnv = this.Instructions[i] as Instructions.PushEnvironment;
                    if (this.BranchTable.ContainsKey(_instructionEnv.Offset) == true)
                    {
                        _instructionEnv.Jump = this.BranchTable[_instructionEnv.Offset];
                    }
                    else
                    {
                        _instructionEnv.Jump = this.Instructions.Count;
                    }
                    break;
                }

                case LOpcode.popenv: {
                    Instructions.PopEnvironment _instructionEnv = this.Instructions[i] as Instructions.PopEnvironment;
                    if (this.BranchTable.ContainsKey(_instructionEnv.Offset) == true)
                    {
                        _instructionEnv.Jump = this.BranchTable[_instructionEnv.Offset];
                    }
                    else
                    {
                        _instructionEnv.Jump = this.Instructions.Count;
                    }
                    break;
                }
                }
            }

            // Check for arrays
            for (int i = 0; i < this.Instructions.Count; i++)
            {
                switch (this.Instructions[i].Opcode)
                {
                case LOpcode.setowner: {
                    // Find next pop instruction
                    for (int j = i; j < this.Instructions.Count; j++)
                    {
                        if (this.Instructions[j].Opcode == LOpcode.pop)
                        {
                            this.Instructions.RemoveAt(--i);       // push.i <id>
                            break;
                        }
                        else if (this.Instructions[j].Opcode == LOpcode.call)
                        {
                            Instructions.Call _instructionGet = this.Instructions[j] as Instructions.Call;
                            if (_instructionGet.FunctionName == "@@NewGMLArray@@")
                            {
                                this.Instructions.RemoveAt(--i);
                                break;
                            }
                        }
                    }
                    break;
                }
                }
            }

#if (!DEBUG)
            // Print out finalized bytecode
            string _bytecodeOutput = this.Name + "\n";
            for (int i = 0; i < this.Instructions.Count; i++)
            {
                _bytecodeOutput += String.Format("[{1}] - {0}", this.Instructions[i].Opcode, this.Instructions[i].Raw.ToString("X"));
                switch (this.Instructions[i].Opcode)
                {
                case LOpcode.b: {
                    Instructions.Branch _instructionGet = this.Instructions[i] as Instructions.Branch;
                    _bytecodeOutput += String.Format("(Goto={0}:{1})", this.Instructions[_instructionGet.Jump].Opcode, _instructionGet.Jump);
                    break;
                }

                case LOpcode.call: {
                    Instructions.Call _instructionGet = this.Instructions[i] as Instructions.Call;
                    _bytecodeOutput += String.Format("(Function={0})", _instructionGet.FunctionName);
                    break;
                }

                case LOpcode.pop: {
                    Instructions.Pop _instructionGet = this.Instructions[i] as Instructions.Pop;
                    _bytecodeOutput += String.Format("(Variable={0}, Scope={1})", _instructionGet.Variable.Name, _instructionGet.Data);
                    break;
                }

                case LOpcode.push: {
                    Instructions.Push _instructionGet = this.Instructions[i] as Instructions.Push;
                    switch (_instructionGet.Type)
                    {
                    case LArgumentType.Variable: {
                        _bytecodeOutput += String.Format("(Variable={0})", _instructionGet.Variable.Name);
                        break;
                    }

                    default: {
                        _bytecodeOutput += String.Format("(Value={0})", _instructionGet.Value.Value);
                        break;
                    }
                    }
                    break;
                }

                case LOpcode.pushb: {
                    Instructions.PushBuiltin _instructionGet = this.Instructions[i] as Instructions.PushBuiltin;
                    _bytecodeOutput += String.Format("(Variable={0})", _instructionGet.Variable);
                    break;
                }

                case LOpcode.pushi: {
                    Instructions.PushImmediate _instructionGet = this.Instructions[i] as Instructions.PushImmediate;
                    _bytecodeOutput += String.Format("(Value={0})", _instructionGet.Value.Value);
                    break;
                }
                }
                _bytecodeOutput += "\n";
            }
            Console.WriteLine(_bytecodeOutput);

            // Print out decompiled bytecode
            try {
                Console.WriteLine("{0}:\n---\n{1}\n---", this.Name, Runner.Debug.Decompiler.Decompile(this.Instructions));
            } catch (Exception e) {
                Console.WriteLine("Failed to decompile {0}: {1}", this.Name, e.Message);
            }
#endif
        }