public static Instruction DissasembleFromReader(int address, BinaryReader r) { Instruction ret = new Instruction(address); uint raw = r.ReadUInt32(); ret.Code = GMCodeUtil.getFromRaw(raw); if (DissasembleRawCode(ret, raw)) { switch (ret.Code) { case GMCode.Call: case GMCode.Pop: ret.Operand = r.ReadInt32(); break; case GMCode.Push: { switch (ret.Types[0]) { case GM_Type.Long: ret.Operand = r.ReadInt64(); break; case GM_Type.Double: ret.Operand = r.ReadDouble(); break; case GM_Type.Float: ret.Operand = r.ReadSingle(); break; case GM_Type.Bool: ret.Operand = r.ReadInt32() != 0 ? true : false; // tested, yess this is silly break; case GM_Type.String: case GM_Type.Var: case GM_Type.Int: ret.Operand = r.ReadInt32(); break; case GM_Type.Short: break; // already read in DissasembleRawCode } } break; } Debug.Assert(ret.Operand != null); } return(ret); }
/// <summary> /// Diassembles a raw opcode. /// </summary> /// <param name="i"></param> /// <param name="raw"></param> /// <returns>Returns truee if operand is needed</returns> public static bool DissasembleRawCode(Instruction i, uint raw) { i.Code = GMCodeUtil.getFromRaw(raw); i.Types = null; i.Operand = null; i.OperandText = null; // we clear eveything just in case i._extra = (short)(0xFFFF & raw); // default for almost eveything switch (i.Code) { case GMCode.Call: i.Types = new GM_Type[] { (GM_Type)((raw >> 16) & 15) }; return(true); case GMCode.Exit: case GMCode.Ret: case GMCode.Not: case GMCode.Neg: case GMCode.Popz: i.Types = new GM_Type[] { (GM_Type)((raw >> 16) & 15) }; break; case GMCode.Pop: i.Types = new GM_Type[] { (GM_Type)((raw >> 16) & 15), (GM_Type)((raw >> 20) & 15) }; return(true); case GMCode.Push: i.Types = new GM_Type[] { (GM_Type)((raw >> 16) & 15) }; // this should be in the operand, but just in case make sure extra is right if (i.Types[0] == GM_Type.Short) { i.Operand = i._extra; // convert it to int break; // set the operand ourselfs don't need it } else { return(true); // need to read an operand } case GMCode.Add: case GMCode.Sub: case GMCode.Mul: case GMCode.Div: case GMCode.Mod: case GMCode.Or: case GMCode.And: case GMCode.Dup: case GMCode.Sal: case GMCode.Seq: case GMCode.Sge: case GMCode.Sgt: case GMCode.Sle: case GMCode.Sne: case GMCode.Conv: case GMCode.Rem: case GMCode.Slt: case GMCode.Xor: i.Types = new GM_Type[] { (GM_Type)((raw >> 16) & 15), (GM_Type)((raw >> 20) & 15) }; break; case GMCode.Break: // i._extra = (int)(0x00FFFFFFF & raw); // never seen the need for more than this break; case GMCode.B: case GMCode.Bf: case GMCode.Bt: i._extra = i.Address + GMCodeUtil.getBranchOffset(raw); break; case GMCode.Popenv: // Debug.WriteLine("Popenv: Address: {0}, Extra: {1} {1:X8} Calc: {2}",i.Address, raw, GMCodeUtil.getBranchOffset(raw)); if (0xBCF00000 == raw) // its a popbreak { i._extra = 0; } else { i._extra = i.Address + GMCodeUtil.getBranchOffset(raw); } break; case GMCode.Pushenv: // Debug.WriteLine("Pushenv: Address: {0}, Extra: {1} {1:X8} Calc: {2}",i.Address, raw, GMCodeUtil.getBranchOffset(raw)); i._extra = i.Address + GMCodeUtil.getBranchOffset(raw); break; case GMCode.BadOp: throw new Exception("Bad opcode?"); default: throw new Exception("Unkonwn opcode"); } return(false); }