public AGSBinaryInstruction(AGSOpcodes opcode, string mnemonic, params AGSBinaryArgumentType[] arguments) { Opcode = opcode; Mnemonic = mnemonic; Arguments = arguments; }
//TODO(adm244): parse fixups in AGSScript and convert them, so that we only pass here AGSScript and ip public static AGSInstruction DisassembleInstruction(AGSScript script, AGSFixupType[] fixups, int[] code, int ip) { AGSInstruction instruction = new AGSInstruction(); byte instanceId = (byte)((code[ip] >> 24) & 0xFF); Int32 opcodeRaw = (Int32)(code[ip] & 0x00FFFFFF); Debug.Assert(Enum.IsDefined(typeof(AGSOpcodes), opcodeRaw)); AGSOpcodes opcode = (AGSOpcodes)(opcodeRaw); for (int i = 0; i < Instructions.Length; ++i) { if (Instructions[i].Opcode == opcode) { instruction.InstanceId = instanceId; instruction.Opcode = opcode; instruction.Mnemonic = Instructions[i].Mnemonic; Debug.Assert((ip + Instructions[i].ArgumentsCount) < code.Length); instruction.Arguments = new AGSArgument[Instructions[i].ArgumentsCount]; for (int arg = 0; arg < instruction.ArgumentsCount; ++arg) { int index = ip + arg + 1; int value = code[index]; instruction.Arguments[arg].Type = AGSArgumentType.None; instruction.Arguments[arg].IntValue = 0; instruction.Arguments[arg].FloatValue = float.NaN; instruction.Arguments[arg].Name = string.Empty; switch (Instructions[i].Arguments[arg]) { //NOTE(adm244): integer literal can also store a float number // e.g. movlit instruction can load floats as well as ints case AGSBinaryArgumentType.IntLiteral: { AGSFixupType fixuptype = fixups[index]; //Debug.Assert(Enum.IsDefined(typeof(AGSArgumentType), type)); AGSArgumentType type = GetArgumentType(fixuptype, Instructions[i].Arguments[arg]); instruction.Arguments[arg].Type = type; switch (type) { case AGSArgumentType.IntConstant: case AGSArgumentType.StackOffset: //FIX(adm244): get actual stack value from StackOffset instruction.Arguments[arg].IntValue = value; break; case AGSArgumentType.ImportsOffset: instruction.Arguments[arg].Name = script.Imports[value]; break; case AGSArgumentType.FunctionOffset: int exportIndex = GetExportIndex(script, value); instruction.Arguments[arg].Name = script.Exports[exportIndex].Name; break; case AGSArgumentType.StringsOffset: int stringIndex = GetStringIndex(script, value); instruction.Arguments[arg].Name = '"' + script.Strings[stringIndex] + '"'; break; default: Debug.Assert(false, "Unknown argument type!"); break; } } break; case AGSBinaryArgumentType.FloatLiteral: instruction.Arguments[arg].Type = AGSArgumentType.FloatConstant; instruction.Arguments[arg].FloatValue = IEEE754Utils.Int32BitsToFloat(value); break; case AGSBinaryArgumentType.Register: instruction.Arguments[arg].Type = AGSArgumentType.RegisterIndex; instruction.Arguments[arg].IntValue = value; instruction.Arguments[arg].Name = RegisterNames[value]; break; default: Debug.Assert(false, "Unknown binary argument type!"); break; } Debug.Assert(instruction.Arguments[arg].Type != AGSArgumentType.None); } break; } } //NOTE(adm244): swap arguments to match "mov <dest>, <src>" pattern if (instruction.Opcode == AGSOpcodes.REGTOREG) { Debug.Assert(instruction.ArgumentsCount == 2); AGSArgument temp = instruction.Arguments[0]; instruction.Arguments[0] = instruction.Arguments[1]; instruction.Arguments[1] = temp; } return(instruction); }