private void ReadMainFunction() { var debugInfo = new FunctionDebugInfo(); debugInfo.Id = 0; Reader.ReadInt32(); int instructionCount = Reader.ReadInt32(); Int64 constantCount = Reader.ReadInt64(); // unk null Reader.ReadInt64(); Int64 fileNameLength = Reader.ReadInt64(); debugInfo.Filename = Encoding.ASCII.GetString(Reader.ReadBytes((int)(fileNameLength - 1))); Reader.ReadByte(); Int64 chunkNameLength = Reader.ReadInt64(); debugInfo.ChunkName = Encoding.ASCII.GetString(Reader.ReadBytes((int)(chunkNameLength - 1))); Reader.ReadByte(); for (int i = 0; i < instructionCount; i++) { debugInfo.InstructionLocations.Add(Reader.ReadInt32()); } for (int i = 0; i < constantCount; i++) { debugInfo.VariableNames.Add(ReadVariableData()); } debugInfo.VariableNames = debugInfo.VariableNames.Where(v => !v.Name.StartsWith("(")).ToList(); DebugInfo.Add(debugInfo); }
private void OnBreakpointTriggered(BkBreakpointTriggered bp) { Stack = TracePrinter.BreakpointToStack(bp); Stopped = true; PauseRequested = false; var stopped = new DAPStoppedEvent { reason = "breakpoint", threadId = 1 }; Stream.SendEvent("stopped", stopped); LastQueryFunc = null; LastQueryResults = null; if (bp.QueryResults != null) { var node = DebugInfo.Nodes[bp.QueryNodeId]; if (node.FunctionName != null) { var function = DebugInfo.Functions[node.FunctionName]; LastQueryFunc = function; LastQueryResults = new List <DebugVariable>(); for (var i = 0; i < bp.QueryResults.Column.Count; i++) { if (function.Params[i].Out) { var col = bp.QueryResults.Column[i]; var resultVar = new DebugVariable { Name = "@" + function.Params[i].Name, Type = function.Params[i].TypeId.ToString(), // TODO name Value = Formatter.ValueToString(col), TypedValue = col }; LastQueryResults.Add(resultVar); } } } } if (bp.QuerySucceeded != BkBreakpointTriggered.Types.QueryStatus.NotAQuery) { var queryResult = new DAPCustomQueryResultEvent { succeeded = (bp.QuerySucceeded == BkBreakpointTriggered.Types.QueryStatus.Succeeded) }; Stream.SendEvent("osirisQueryResult", queryResult); } }
private FunctionDebugInfoMsg ToProtobuf(FunctionDebugInfo debugInfo) { var msg = new FunctionDebugInfoMsg { Name = debugInfo.Name, TypeId = debugInfo.TypeId }; foreach (var param in debugInfo.Params) { msg.Params.Add(ToProtobuf(param)); } return(msg); }
private FunctionDebugInfo FromProtobuf(FunctionDebugInfoMsg msg) { var debugInfo = new FunctionDebugInfo { Name = msg.Name, Params = new List <FunctionParamDebugInfo>(), TypeId = msg.TypeId }; foreach (var param in msg.Params) { debugInfo.Params.Add(FromProtobuf(param)); } return(debugInfo); }
private FunctionDebugInfo ReadFunction() { var debugInfo = new FunctionDebugInfo(); // Is always 1 int funcStart = Reader.ReadInt32(); int instructionCount = Reader.ReadInt32(); int variableNameCount = Reader.ReadInt32(); int upvalueNameCount = Reader.ReadInt32(); debugInfo.FunctionStart = Reader.ReadInt32(); debugInfo.FunctionEnd = Reader.ReadInt32(); // Unk null Int64 nullPtr = Reader.ReadInt64(); Int64 funcNameLength = Reader.ReadInt64(); if (funcNameLength > 0) { string funcName = Encoding.ASCII.GetString(Reader.ReadBytes((int)(funcNameLength - 1))); Reader.ReadByte(); debugInfo.ChunkName = funcName; } for (int i = 0; i < instructionCount; i++) { debugInfo.InstructionLocations.Add(Reader.ReadInt32()); } for (int i = 0; i < variableNameCount; i++) { debugInfo.VariableNames.Add(ReadVariableData()); } debugInfo.VariableNames = debugInfo.VariableNames.Where(v => !v.Name.StartsWith("(")).ToList(); for (int i = 0; i < upvalueNameCount; i++) { Int64 upvalueStrLength = Reader.ReadInt64(); string funcName = Encoding.ASCII.GetString(Reader.ReadBytes((int)(upvalueStrLength - 1))); Reader.ReadByte(); debugInfo.UpvalueNames.Add(funcName); } return(debugInfo); }
public void Convert(Function function, ILuaFunction luaFunc) { _symbolTable = function.SymbolTable; var luaFunction = (HavokLuaFunction)luaFunc; FunctionDebugInfo debugFunc = null; if (luaFunction.LuaFile is HavokLuaFileT7 ht7 && ht7.DebugFile != null) { var debugInfo = ht7.DebugFile.DebugInfo; debugFunc = debugInfo.Find(d => d.Id == function.Id); function.FunctionDebugInfo = debugFunc; function.ArgumentNames = debugFunc.VariableNames.Where(v => v.Start == 0).Select(l => new Local() { Name = l.Name, End = l.End, Start = l.Start }).ToList(); } // Loop over all instructions for (int pos = 0; pos < luaFunction.Instructions.Count; pos++) { var i = (HavokInstruction)luaFunction.Instructions[pos]; List <IInstruction> instrs = new List <IInstruction>(); switch (i.HavokOpCode) { case LuaHavokOpCode.HKS_OPCODE_MOVE: instrs.Add(new Assignment( _symbolTable.GetRegister(i.A), RegisterReference(i.B) )); break; case LuaHavokOpCode.HKS_OPCODE_LOADK: instrs.Add(new Assignment( _symbolTable.GetRegister(i.A), ConvertLuaConstant(luaFunction.Constants[(int)i.Bx], (int)i.Bx) )); break; case LuaHavokOpCode.HKS_OPCODE_LOADBOOL: var assn = new Assignment(_symbolTable.GetRegister(i.A), new Constant(i.B == 1, -1)); instrs.Add(assn); if (i.C > 0) { instrs.Add(new Jump(function.GetLabel((uint)(pos + 2)))); } break; case LuaHavokOpCode.HKS_OPCODE_LOADNIL: var nlist = new List <IdentifierReference>(); for (int arg = (int)i.A; arg <= i.B; arg++) { nlist.Add(new IdentifierReference(_symbolTable.GetRegister((uint)arg))); } assn = new Assignment(nlist, new Constant(ValueType.Nil, -1)); instrs.Add(assn); break; case LuaHavokOpCode.HKS_OPCODE_GETUPVAL: Identifier up = function.UpvalueBindings[(int)i.B]; up.IsClosureBound = true; instrs.Add(new Assignment( _symbolTable.GetRegister(i.A), new IdentifierReference(up))); break; case LuaHavokOpCode.HKS_OPCODE_SETUPVAL: case LuaHavokOpCode.HKS_OPCODE_SETUPVAL_R1: up = _symbolTable.GetUpValue(i.B, function.UpvalueBindings[(int)i.B].Name); if (luaFunction.Upvalues.Any() && !up.UpValueResolved) { up.Name = luaFunction.Upvalues[(int)i.B].Name; up.UpValueResolved = true; } instrs.Add(new Assignment(up, new IdentifierReference(_symbolTable.GetRegister(i.A)))); break; case LuaHavokOpCode.HKS_OPCODE_GETGLOBAL_MEM: case LuaHavokOpCode.HKS_OPCODE_GETGLOBAL: instrs.Add(new Assignment( _symbolTable.GetRegister(i.A), new IdentifierReference(_symbolTable.GetGlobal(luaFunction.Constants[(int)i.Bx].ToString(), (int)i.Bx)) )); break; case LuaHavokOpCode.HKS_OPCODE_SETGLOBAL: instrs.Add(new Assignment( _symbolTable.GetGlobal(luaFunction.Constants[(int)i.Bx].ToString(), (int)i.Bx), new IdentifierReference(_symbolTable.GetRegister(i.A)))); break; case LuaHavokOpCode.HKS_OPCODE_GETTABLE_S: case LuaHavokOpCode.HKS_OPCODE_GETTABLE: instrs.Add(new Assignment( _symbolTable.GetRegister(i.A), new IdentifierReference(_symbolTable.GetRegister(i.B), GetConstantBitFix(luaFunction, i.C, i.ExtraCBit)) )); break; case LuaHavokOpCode.HKS_OPCODE_NEWTABLE: instrs.Add(new Assignment( _symbolTable.GetRegister(i.A), new InitializerList() )); break; case LuaHavokOpCode.HKS_OPCODE_SELF: var op = new Assignment(_symbolTable.GetRegister(i.A + 1), new IdentifierReference(_symbolTable.GetRegister(i.B))); op.IsSelfAssignment = true; instrs.Add(op); op = new Assignment(_symbolTable.GetRegister(i.A), new IdentifierReference(_symbolTable.GetRegister(i.B), GetConstantBitFix(luaFunction, i.C, i.ExtraCBit))); op.IsSelfAssignment = true; instrs.Add(op); break; case LuaHavokOpCode.HKS_OPCODE_ADD: instrs.Add(new Assignment( _symbolTable.GetRegister(i.A), new BinOp(RegisterReference(i.B), GetConstantBitFix(luaFunction, i.C, i.ExtraCBit), BinOperationType.OpAdd) )); break; case LuaHavokOpCode.HKS_OPCODE_ADD_BK: instrs.Add(new Assignment( _symbolTable.GetRegister(i.A), new BinOp(ConvertLuaConstant(luaFunction.Constants[(int)i.B], (int)i.B), RegisterReference(i.C), BinOperationType.OpAdd) )); break; case LuaHavokOpCode.HKS_OPCODE_SUB: instrs.Add(new Assignment( _symbolTable.GetRegister(i.A), new BinOp(RegisterReference(i.B), GetConstantBitFix(luaFunction, i.C, i.ExtraCBit), BinOperationType.OpSub) )); break; case LuaHavokOpCode.HKS_OPCODE_SUB_BK: instrs.Add(new Assignment( _symbolTable.GetRegister(i.A), new BinOp(ConvertLuaConstant(luaFunction.Constants[(int)i.B], (int)i.B), RegisterReference(i.C), BinOperationType.OpSub) )); break; case LuaHavokOpCode.HKS_OPCODE_MUL: instrs.Add(new Assignment( _symbolTable.GetRegister(i.A), new BinOp(RegisterReference(i.B), GetConstantBitFix(luaFunction, i.C, i.ExtraCBit), BinOperationType.OpMul) )); break; case LuaHavokOpCode.HKS_OPCODE_MUL_BK: instrs.Add(new Assignment( _symbolTable.GetRegister(i.A), new BinOp(ConvertLuaConstant(luaFunction.Constants[(int)i.B], (int)i.B), RegisterReference(i.C), BinOperationType.OpMul) )); break; case LuaHavokOpCode.HKS_OPCODE_DIV: instrs.Add(new Assignment( _symbolTable.GetRegister(i.A), new BinOp(RegisterReference(i.B), GetConstantBitFix(luaFunction, i.C, i.ExtraCBit), BinOperationType.OpDiv) )); break; case LuaHavokOpCode.HKS_OPCODE_DIV_BK: instrs.Add(new Assignment( _symbolTable.GetRegister(i.A), new BinOp(ConvertLuaConstant(luaFunction.Constants[(int)i.B], (int)i.B), RegisterReference(i.C), BinOperationType.OpDiv) )); break; case LuaHavokOpCode.HKS_OPCODE_MOD: instrs.Add(new Assignment( _symbolTable.GetRegister(i.A), new BinOp(RegisterReference(i.B), GetConstantBitFix(luaFunction, i.C, i.ExtraCBit), BinOperationType.OpMod) )); break; case LuaHavokOpCode.HKS_OPCODE_MOD_BK: instrs.Add(new Assignment( _symbolTable.GetRegister(i.A), new BinOp(ConvertLuaConstant(luaFunction.Constants[(int)i.B], (int)i.B), RegisterReference(i.C), BinOperationType.OpMod) )); break; case LuaHavokOpCode.HKS_OPCODE_POW: instrs.Add(new Assignment( _symbolTable.GetRegister(i.A), new BinOp(RegisterReference(i.B), GetConstantBitFix(luaFunction, i.C, i.ExtraCBit), BinOperationType.OpPow) )); break; case LuaHavokOpCode.HKS_OPCODE_POW_BK: instrs.Add(new Assignment( _symbolTable.GetRegister(i.A), new BinOp(ConvertLuaConstant(luaFunction.Constants[(int)i.B], (int)i.B), RegisterReference(i.C), BinOperationType.OpPow) )); break; case LuaHavokOpCode.HKS_OPCODE_UNM: instrs.Add(new Assignment( _symbolTable.GetRegister(i.A), new UnaryOp(new IdentifierReference(_symbolTable.GetRegister(i.B)), UnOperationType.OpNegate) )); break; case LuaHavokOpCode.HKS_OPCODE_NOT: case LuaHavokOpCode.HKS_OPCODE_NOT_R1: instrs.Add(new Assignment( _symbolTable.GetRegister(i.A), new UnaryOp(new IdentifierReference(_symbolTable.GetRegister(i.B)), UnOperationType.OpNot) )); break; case LuaHavokOpCode.HKS_OPCODE_LEN: instrs.Add(new Assignment( _symbolTable.GetRegister(i.A), new UnaryOp(new IdentifierReference(_symbolTable.GetRegister(i.B)), UnOperationType.OpLength) )); break; case LuaHavokOpCode.HKS_OPCODE_SHIFT_LEFT: instrs.Add(new Assignment( _symbolTable.GetRegister(i.A), new BinOp(RegisterReference(i.B), GetConstantBitFix(luaFunction, i.C, i.ExtraCBit), BinOperationType.OpShiftLeft) )); break; case LuaHavokOpCode.HKS_OPCODE_SHIFT_LEFT_BK: instrs.Add(new Assignment( _symbolTable.GetRegister(i.A), new BinOp(ConvertLuaConstant(luaFunction.Constants[(int)i.B], (int)i.B), RegisterReference(i.C), BinOperationType.OpShiftLeft) )); break; case LuaHavokOpCode.HKS_OPCODE_SHIFT_RIGHT: instrs.Add(new Assignment( _symbolTable.GetRegister(i.A), new BinOp(RegisterReference(i.B), GetConstantBitFix(luaFunction, i.C, i.ExtraCBit), BinOperationType.OpShiftRight) )); break; case LuaHavokOpCode.HKS_OPCODE_SHIFT_RIGHT_BK: instrs.Add(new Assignment( _symbolTable.GetRegister(i.A), new BinOp(ConvertLuaConstant(luaFunction.Constants[(int)i.B], (int)i.B), RegisterReference(i.C), BinOperationType.OpShiftRight) )); break; case LuaHavokOpCode.HKS_OPCODE_BITWISE_AND: instrs.Add(new Assignment( _symbolTable.GetRegister(i.A), new BinOp(RegisterReference(i.B), GetConstantBitFix(luaFunction, i.C, i.ExtraCBit), BinOperationType.OpBAnd) )); break; case LuaHavokOpCode.HKS_OPCODE_BITWISE_AND_BK: instrs.Add(new Assignment( _symbolTable.GetRegister(i.A), new BinOp(ConvertLuaConstant(luaFunction.Constants[(int)i.B], (int)i.B), RegisterReference(i.C), BinOperationType.OpBAnd) )); break; case LuaHavokOpCode.HKS_OPCODE_BITWISE_OR: instrs.Add(new Assignment( _symbolTable.GetRegister(i.A), new BinOp(RegisterReference(i.B), GetConstantBitFix(luaFunction, i.C, i.ExtraCBit), BinOperationType.OpBOr) )); break; case LuaHavokOpCode.HKS_OPCODE_BITWISE_OR_BK: instrs.Add(new Assignment( _symbolTable.GetRegister(i.A), new BinOp(ConvertLuaConstant(luaFunction.Constants[(int)i.B], (int)i.B), RegisterReference(i.C), BinOperationType.OpBOr) )); break; case LuaHavokOpCode.HKS_OPCODE_CONCAT: var args = new List <IExpression>(); for (int arg = (int)i.B; arg <= i.C; arg++) { args.Add(new IdentifierReference(_symbolTable.GetRegister((uint)arg))); } instrs.Add(new Assignment( _symbolTable.GetRegister(i.A), new Concat(args) )); break; case LuaHavokOpCode.HKS_OPCODE_JMP: instrs.Add(new Jump(function.GetLabel((uint)(pos + 1 + i.SBx)))); break; case LuaHavokOpCode.HKS_OPCODE_EQ: var operation = BinOperationType.OpEqual; if (i.A == 1) { operation = BinOperationType.OpNotEqual; } instrs.Add(new Jump(function.GetLabel((uint)(pos + 2)), new BinOp(RegisterReference(i.B), GetConstantBitFix(luaFunction, i.C, i.ExtraCBit), operation))); break; case LuaHavokOpCode.HKS_OPCODE_EQ_BK: operation = BinOperationType.OpEqual; if (i.A == 1) { operation = BinOperationType.OpNotEqual; } instrs.Add(new Jump(function.GetLabel((uint)(pos + 2)), new BinOp(ConvertLuaConstant(luaFunction.Constants[(int)i.B], (int)i.B), RegisterReference(i.C), operation))); break; case LuaHavokOpCode.HKS_OPCODE_LT: operation = BinOperationType.OpLessThan; if (i.A == 1) { operation = BinOperationType.OpGreaterEqual; } instrs.Add(new Jump(function.GetLabel((uint)(pos + 2)), new BinOp(RegisterReference(i.B), GetConstantBitFix(luaFunction, i.C, i.ExtraCBit), operation))); break; case LuaHavokOpCode.HKS_OPCODE_LT_BK: operation = BinOperationType.OpLessThan; if (i.A == 1) { operation = BinOperationType.OpGreaterEqual; } instrs.Add(new Jump(function.GetLabel((uint)(pos + 2)), new BinOp(ConvertLuaConstant(luaFunction.Constants[(int)i.B], (int)i.B), RegisterReference(i.C), operation))); break; case LuaHavokOpCode.HKS_OPCODE_LE: operation = BinOperationType.OpLessEqual; if (i.A == 1) { operation = BinOperationType.OpGreaterThan; } instrs.Add(new Jump(function.GetLabel((uint)(pos + 2)), new BinOp(RegisterReference(i.B), GetConstantBitFix(luaFunction, i.C, i.ExtraCBit), operation))); break; case LuaHavokOpCode.HKS_OPCODE_LE_BK: operation = BinOperationType.OpLessEqual; if (i.A == 1) { operation = BinOperationType.OpGreaterThan; } instrs.Add(new Jump(function.GetLabel((uint)(pos + 2)), new BinOp(ConvertLuaConstant(luaFunction.Constants[(int)i.B], (int)i.B), RegisterReference(i.C), operation))); break; case LuaHavokOpCode.HKS_OPCODE_TEST: case LuaHavokOpCode.HKS_OPCODE_TEST_R1: instrs.Add(i.C == 0 ? new Jump(function.GetLabel((uint)(pos + 2)), RegisterReference(i.A)) : new Jump(function.GetLabel((uint)(pos + 2)), new UnaryOp(RegisterReference(i.A), UnOperationType.OpNot))); break; case LuaHavokOpCode.HKS_OPCODE_TESTSET: instrs.Add(i.C == 0 ? new Jump(function.GetLabel((uint)(pos + 2)), RKIR(luaFunction, i.B)) { TestsetType = BinOperationType.OpAnd, TestsetLocation = _symbolTable.GetRegister(i.A) } : new Jump(function.GetLabel((uint)(pos + 2)), RKIR(luaFunction, i.B)) { TestsetType = BinOperationType.OpOr, TestsetLocation = _symbolTable.GetRegister(i.A) }); instrs.Add(new Assignment(_symbolTable.GetRegister(i.A), new IdentifierReference(_symbolTable.GetRegister(i.B)))); break; case LuaHavokOpCode.HKS_OPCODE_SETTABLE: case LuaHavokOpCode.HKS_OPCODE_SETTABLE_S: instrs.Add(new Assignment( new IdentifierReference(_symbolTable.GetRegister(i.A), RegisterReference(i.B)), GetConstantBitFix(luaFunction, i.C, i.ExtraCBit) )); break; case LuaHavokOpCode.HKS_OPCODE_TAILCALL: case LuaHavokOpCode.HKS_OPCODE_TAILCALL_I: case LuaHavokOpCode.HKS_OPCODE_TAILCALL_I_R1: args = new List <IExpression>(); for (int arg = (int)i.A + 1; arg < i.A + i.B; arg++) { args.Add(new IdentifierReference(_symbolTable.GetRegister((uint)arg))); } var funCall = new FunctionCall(new IdentifierReference(_symbolTable.GetRegister(i.A)), args); funCall.IsIndeterminateArgumentCount = (i.B == 0); funCall.BeginArg = i.A + 1; instrs.Add(new Return(funCall) { IsTailReturn = true }); break; case LuaHavokOpCode.HKS_OPCODE_SETTABLE_S_BK: instrs.Add(new Assignment( new IdentifierReference(_symbolTable.GetRegister(i.A), ConvertLuaConstant(luaFunction.Constants[(int)i.B], (int)i.B)), GetConstantBitFix(luaFunction, i.C, i.ExtraCBit))); break; case LuaHavokOpCode.HKS_OPCODE_CALL_I: case LuaHavokOpCode.HKS_OPCODE_CALL_I_R1: case LuaHavokOpCode.HKS_OPCODE_CALL: args = new List <IExpression>(); var rets = new List <IdentifierReference>(); for (int arg = (int)i.A + 1; arg < i.A + i.B; arg++) { args.Add(new IdentifierReference(_symbolTable.GetRegister((uint)arg))); } for (int r = (int)i.A + 1; r < i.A + i.C; r++) { rets.Add(new IdentifierReference(_symbolTable.GetRegister((uint)r - 1))); } if (i.C == 0) { rets.Add(new IdentifierReference(_symbolTable.GetRegister(i.A))); } funCall = new FunctionCall(new IdentifierReference(_symbolTable.GetRegister(i.A)), args); funCall.IsIndeterminateArgumentCount = (i.B == 0); funCall.IsIndeterminateReturnCount = (i.C == 0); funCall.BeginArg = i.A + 1; assn = new Assignment(rets, funCall); instrs.Add(assn); break; case LuaHavokOpCode.HKS_OPCODE_RETURN: args = new List <IExpression>(); if (i.B != 0) { for (int arg = (int)i.A; arg < i.A + i.B - 1; arg++) { args.Add(new IdentifierReference(_symbolTable.GetRegister((uint)arg))); } } var ret = new Return(args); if (i.B == 0) { ret.BeginRet = i.A; ret.IsIndeterminateReturnCount = true; } instrs.Add(ret); break; case LuaHavokOpCode.HKS_OPCODE_FORLOOP: instrs.Add(new Assignment(new IdentifierReference(_symbolTable.GetRegister(i.A)), new BinOp(new IdentifierReference(_symbolTable.GetRegister(i.A)), new IdentifierReference(_symbolTable.GetRegister(i.A + 2)), BinOperationType.OpAdd))); var jmp = new Jump(function.GetLabel((uint)(pos + 1 + i.SBx)), new BinOp(new IdentifierReference(_symbolTable.GetRegister(i.A)), new IdentifierReference(_symbolTable.GetRegister(i.A + 1)), BinOperationType.OpLoopCompare)); var pta = new Assignment(_symbolTable.GetRegister(i.A + 3), RegisterReference(i.A)); pta.PropagateAlways = true; jmp.PostTakenAssignment = pta; if (debugFunc != null) { var indexVariable = debugFunc.VariableNames.Where(v => v.Start == pos + 1 + i.SBx).ToList(); if (indexVariable.Count == 1) { var forIndexIdentifier = _symbolTable.GetRegister(i.A); for (int j = pos + i.SBx; j >= 0; j--) { var opCodeInstrs = function.Instructions.Where(ins => ins.OpLocation == j).ToList(); if (opCodeInstrs.Count == 1 && opCodeInstrs[0] is Assignment a && a.Left.Count == 1 && a.Left[0].Identifier == forIndexIdentifier) { a.LocalAssignments = indexVariable; break; } } var forStepIdentifier = _symbolTable.GetRegister(i.A + 2); for (int j = pos + i.SBx; j >= 0; j--) { var opCodeInstrs = function.Instructions.Where(ins => ins.OpLocation == j).ToList(); if (opCodeInstrs.Count == 1 && opCodeInstrs[0] is Assignment a && a.Left.Count == 1 && a.Left[0].Identifier == forStepIdentifier && a.LocalAssignments.Count == 3) { var forLimitIdentifier = _symbolTable.GetRegister(i.A + 1); for (int k = pos + i.SBx; k >= 0; k--) { var opLimitCodeInstrs = function.Instructions.Where(ins => ins.OpLocation == k).ToList(); if (opLimitCodeInstrs.Count == 1 && opLimitCodeInstrs[0] is Assignment a2 && a2.Left.Count == 1 && a2.Left[0].Identifier == forLimitIdentifier) { a2.LocalAssignments = new List <Local>() { a.LocalAssignments[1] }; break; } } a.LocalAssignments = new List <Local>() { a.LocalAssignments[2] }; break; } } } } instrs.Add(jmp); break; case LuaHavokOpCode.HKS_OPCODE_TFORLOOP: args = new List <IExpression>(); rets = new List <IdentifierReference>(); args.Add(new IdentifierReference(_symbolTable.GetRegister(i.A + 1))); args.Add(new IdentifierReference(_symbolTable.GetRegister(i.A + 2))); if (i.C == 0) { rets.Add(new IdentifierReference(_symbolTable.GetRegister(i.A + 3))); } else { for (int r = (int)i.A + 3; r <= i.A + i.C + 2; r++) { rets.Add(new IdentifierReference(_symbolTable.GetRegister((uint)r))); } } var fCall = new FunctionCall(new IdentifierReference(_symbolTable.GetRegister(i.A)), args); fCall.IsIndeterminateReturnCount = (i.C == 0); assn = new Assignment(rets, fCall); if (debugFunc != null) { var nextOp = ((HavokInstruction)luaFunction.Instructions[pos + 1]); if (nextOp.HavokOpCode == LuaHavokOpCode.HKS_OPCODE_JMP) { assn.LocalAssignments = debugFunc.VariableNames .Where(v => v.Start == pos + nextOp.SBx + 2).ToList(); } } instrs.Add(assn); instrs.Add(new Jump(function.GetLabel((uint)(pos + 2)), new BinOp(RegisterReference(i.A + 3), new Constant(ValueType.Nil, -1), BinOperationType.OpEqual))); instrs.Add(new Assignment(_symbolTable.GetRegister(i.A + 2), new IdentifierReference(_symbolTable.GetRegister(i.A + 3)))); break; case LuaHavokOpCode.HKS_OPCODE_FORPREP: // The VM technically does a subtract, but we don't actually emit it since it simplifies things to map better to the high level Lua //instructions.Add(new IR.Assignment(new IR.IdentifierReference(SymbolTable.GetRegister(a)), new IR.BinOp(new IR.IdentifierReference(SymbolTable.GetRegister(a)), // new IR.IdentifierReference(SymbolTable.GetRegister(a + 2)), IR.BinOp.OperationType.OpSub))); instrs.Add(new Jump(function.GetLabel((uint)(pos + 1 + i.SBx)))); break; case LuaHavokOpCode.HKS_OPCODE_SETLIST: if (i.B == 0) { if (i.C == 1) { assn = new Assignment(_symbolTable.GetRegister(i.A), RegisterReference(i.A + 1)) { VarargAssignmentReg = i.A, IsIndeterminateVararg = true }; instrs.Add(assn); } } else { for (int j = 1; j <= i.B; j++) { assn = new Assignment(new IdentifierReference(_symbolTable.GetRegister(i.A), new Constant((double)(i.C - 1) * 32 + j, -1)), new IdentifierReference(_symbolTable.GetRegister(i.A + (uint)j))); instrs.Add(assn); } } break; case LuaHavokOpCode.HKS_OPCODE_CLOSURE: instrs.Add(new Assignment(_symbolTable.GetRegister(i.A), new Closure(function.Closures[(int)i.Bx]))); break; case LuaHavokOpCode.HKS_OPCODE_GETFIELD: case LuaHavokOpCode.HKS_OPCODE_GETFIELD_R1: assn = new Assignment(RegisterReference(i.A), new IdentifierReference(_symbolTable.GetRegister(i.B), new Constant(luaFunction.Constants[(int)i.C].ToString(), -1))); instrs.Add(assn); break; case LuaHavokOpCode.HKS_OPCODE_DATA: if (i.A != 0) { Function closureFunc = null; int index = pos; while (index >= 0) { var instru = (HavokInstruction)luaFunction.Instructions[index]; if (instru.HavokOpCode == LuaHavokOpCode.HKS_OPCODE_CLOSURE) { closureFunc = function.Closures[(int)instru.Bx]; break; } index--; } if (closureFunc == null) { continue; } if (debugFunc != null && function.Instructions.Any() && function.Instructions.Last() is Assignment a && a.Right is Closure) { if (a.LocalAssignments == null) { a.LocalAssignments = new List <Local>(); } a.LocalAssignments.AddRange(debugFunc.VariableNames.Where(v => v.Start == pos + 1).ToList()); } if (i.A == 1) { closureFunc.UpvalueBindings.Add(_symbolTable.GetRegister(i.C)); } else if (i.A == 2) { closureFunc.UpvalueBindings.Add(function.UpvalueBindings[(int)i.C]); } } else { var dat = new Data(i); if (debugFunc != null) { dat.Locals = debugFunc.VariableNames.Where(v => v.Start == pos + 1).ToList(); } instrs.Add(dat); } break; case LuaHavokOpCode.HKS_OPCODE_SETFIELD: case LuaHavokOpCode.HKS_OPCODE_SETFIELD_R1: assn = new Assignment(new IdentifierReference(_symbolTable.GetRegister(i.A), new Constant(luaFunction.Constants[(int)i.B].ToString(), (int)i.B)), GetConstantBitFix(luaFunction, i.C, i.ExtraCBit)); instrs.Add(assn); break; case LuaHavokOpCode.HKS_OPCODE_VARARG: var varArgs = new List <IdentifierReference>(); for (int arg = (int)i.A; arg <= i.A + i.B - 1; arg++) { varArgs.Add(new IdentifierReference(_symbolTable.GetRegister((uint)arg))); } if (i.B != 0) { assn = new Assignment(varArgs, new IdentifierReference(_symbolTable.GetVarargs())); } else { assn = new Assignment(_symbolTable.GetRegister(i.A), new IdentifierReference(_symbolTable.GetVarargs())); assn.IsIndeterminateVararg = true; assn.VarargAssignmentReg = i.A; } instrs.Add(assn); function.IsVarArgs = true; break; case LuaHavokOpCode.HKS_OPCODE_CLOSE: // LUA source : close all variables in the stack up to (>=) R(A) // Let's ignore this for now, doesn't print anything and don't know if it affects SSA instrs.Add(new Close()); break; default: Console.WriteLine($@"Missing op: {i.HavokOpCode} {i.A} {i.B} {i.C}"); instrs.Add(new PlaceholderInstruction($@"{i.HavokOpCode} {i.A} {i.B} {i.C}")); break; } foreach (var instr in instrs) { if (debugFunc != null) { if (instr is Assignment a && a.LocalAssignments == null) { a.LocalAssignments = debugFunc.VariableNames.Where(v => v.Start == pos + 1).ToList(); } if (debugFunc.InstructionLocations.Count >= pos) { instr.LineLocation = debugFunc.InstructionLocations[pos]; } } instr.OpLocation = pos; function.Instructions.Add(instr); } } }