private void AnalyzeCodePath(Stack<StackValue> stack, CodePath path, ref int tempVarIndex) { HLInstruction instruction = path.GetFirstInstruction(); while (instruction != null) { try { if (instruction.BranchFunction != null) { if (!instruction.Instruction.HasStackUsageInfo) { instruction.Instruction.StackIn = instruction.BranchFunction.ParameterCount; instruction.Instruction.StackOut = instruction.BranchFunction.ReturnCount; instruction.Instruction.StackLeftOver = 0; instruction.Instruction.HasStackUsageInfo = true; } } if (instruction.UnconditionalBranch) { // One should not even occur //Debug.Assert(false); } else if (instruction.ExitFunction) { var value = new StackValueOperation(StackValueOperationType.Return); if (path.ParentFunction.ReturnCount > 0) { for (int i = 0; i < path.ParentFunction.ReturnCount; i++) { value.Operands.Add(stack.Pop()); } } instruction.ProcessedStackValue = value; } else if (instruction.IsConditionalBranch || instruction.IsSwitchBranch) { instruction.ProcessedStackValue = stack.Pop(); } else { bool processDefault = false; StackValueOperation operationValue = null; StackValue tempAnyValue; StackValueOperation tempOpValue; StackValueLiteral tempLiteralValue; StackValuePointerBase tempPointerValue; OpCode opCode = instruction.Instruction.OpCode; switch (opCode) { case OpCode.AddVec: VectorOperation(StackValueOperationType.Add, stack); break; case OpCode.SubVec: VectorOperation(StackValueOperationType.Sub, stack); break; case OpCode.MulVec: VectorOperation(StackValueOperationType.Mul, stack); break; case OpCode.DivVec: VectorOperation(StackValueOperationType.Div, stack); break; case OpCode.NegVec: VectorOperation(StackValueOperationType.Neg, stack); break; case OpCode.VecFromF: VectorOperation(StackValueOperationType.FromF, stack); break; case OpCode.PushS: stack.Push(new StackValueLiteral((short) instruction.Instruction.Operands[0])); break; case OpCode.Push: stack.Push(new StackValueLiteral((int) (uint) instruction.Instruction.Operands[0])); break; case OpCode.PushF: stack.Push(new StackValueLiteral((float) instruction.Instruction.Operands[0])); break; case OpCode.PushString: stack.Push(new StackValueLiteral((string) instruction.Instruction.Operands[0])); break; case OpCode.Dup: stack.Push(stack.Peek()); break; case OpCode.Pop: tempOpValue = stack.Peek() as StackValueOperation; if (tempOpValue != null && tempOpValue.OperationType == StackValueOperationType.Call) { operationValue = new StackValueOperation(StackValueOperationType.Pop); processDefault = true; } break; case OpCode.CallNative: operationValue = new StackValueOperation(instruction.Instruction.Operands[2].ToString()); processDefault = true; break; case OpCode.Call: operationValue = new StackValueOperation(instruction.BranchFunction.Name); processDefault = true; break; case OpCode.RefGet: stack.Push(new StackValueDeref(stack.Pop())); break; case OpCode.RefSet: instruction.ProcessedStackValue = new StackValueAssign(PopPointer(stack), stack.Pop()); break; case OpCode.RefPeekSet: tempAnyValue = stack.Pop(); // value! instruction.ProcessedStackValue = new StackValueAssign(PeekPointer(stack), tempAnyValue); break; case OpCode.ArrayExplode: // This is used to either pass a structure to a native/function call // or to explode the variables onto the stack to do a "shallow-copy" tempPointerValue = PopPointer(stack); tempLiteralValue = stack.Pop() as StackValueLiteral; Debug.Assert(tempLiteralValue != null && tempLiteralValue.ValueType == StackValueType.Integer); var explodeCount = (int) tempLiteralValue.Value; for (int i = 0; i < explodeCount; i++) { stack.Push(new StackValueDeref(new StackValuePointerIndex(tempPointerValue, i))); } break; case OpCode.ArrayImplode: // The only case this is ever used is for a shallow copy! tempPointerValue = PopPointer(stack); tempLiteralValue = stack.Pop() as StackValueLiteral; Debug.Assert(tempLiteralValue != null && tempLiteralValue.ValueType == StackValueType.Integer); var tempStack = new Stack<StackValue>(); var implodeCount = (int) tempLiteralValue.Value; for (int i = implodeCount - 1; i >= 0; i--) { tempStack.Push( new StackValueAssign(new StackValuePointerIndex(tempPointerValue, i), stack.Pop())); } var stackValueGroup = new ProcessedStackValueGroup(); stackValueGroup.Values.AddRange(tempStack.ToArray()); instruction.ProcessedStackValue = stackValueGroup; break; case OpCode.Var0: case OpCode.Var1: case OpCode.Var2: case OpCode.Var3: case OpCode.Var4: case OpCode.Var5: case OpCode.Var6: case OpCode.Var7: stack.Push(new StackValuePointerVar(StackValuePointerType.Stack, (opCode - OpCode.Var0))); break; case OpCode.Var: tempLiteralValue = stack.Pop() as StackValueLiteral; Debug.Assert(tempLiteralValue != null && tempLiteralValue.ValueType == StackValueType.Integer); stack.Push(new StackValuePointerVar(StackValuePointerType.Stack, (int) tempLiteralValue.Value)); break; case OpCode.LocalVar: tempLiteralValue = stack.Pop() as StackValueLiteral; Debug.Assert(tempLiteralValue != null && tempLiteralValue.ValueType == StackValueType.Integer); stack.Push(new StackValuePointerVar(StackValuePointerType.Local, (int) tempLiteralValue.Value)); break; case OpCode.GlobalVar: tempLiteralValue = stack.Pop() as StackValueLiteral; Debug.Assert(tempLiteralValue != null && tempLiteralValue.ValueType == StackValueType.Integer); stack.Push(new StackValuePointerVar(StackValuePointerType.Global, (int) tempLiteralValue.Value)); break; case OpCode.ArrayRef: tempPointerValue = PopPointer(stack); tempLiteralValue = stack.Pop() as StackValueLiteral; tempAnyValue = stack.Pop(); Debug.Assert(tempPointerValue != null); Debug.Assert(tempLiteralValue != null && tempLiteralValue.ValueType == StackValueType.Integer); stack.Push(new StackValuePointerArray(tempPointerValue, tempAnyValue, (int) tempLiteralValue.Value)); break; case OpCode.NullObj: stack.Push(new StackValuePointerVar(StackValuePointerType.Null)); break; case OpCode.Add: // Special case for pointer add tempAnyValue = stack.Pop(); tempPointerValue = stack.Peek() as StackValuePointerBase; if (tempPointerValue != null) { stack.Pop(); // tempPointerValue tempLiteralValue = tempAnyValue as StackValueLiteral; Debug.Assert(tempLiteralValue != null && (int) tempLiteralValue.Value%4 == 0); stack.Push(new StackValuePointerIndex(tempPointerValue, (int) tempLiteralValue.Value/4)); } else { stack.Push(tempAnyValue); operationValue = new StackValueOperation(opCode); processDefault = true; } break; case OpCode.StrCat: case OpCode.StrCatI: case OpCode.StrCpy: case OpCode.IntToStr: operationValue = new StackValueStringOperation(opCode, (byte)instruction.Instruction.Operands[0]); processDefault = true; break; case OpCode.StrVarCpy: tempPointerValue = PopPointer(stack); tempLiteralValue = stack.Pop() as StackValueLiteral; Debug.Assert(tempLiteralValue != null && tempLiteralValue.ValueType == StackValueType.Integer); var targetSize = (uint)(int)tempLiteralValue.Value; tempLiteralValue = stack.Pop() as StackValueLiteral; Debug.Assert(tempLiteralValue != null && tempLiteralValue.ValueType == StackValueType.Integer); var sourceSize = (uint)(int)tempLiteralValue.Value; var popSize = sourceSize; tempAnyValue = PopPointer(stack); // Pop till the last one for (var i = 1; i < popSize; i++) { tempAnyValue = PopPointer(stack); } operationValue = new StackValueStringOperation(opCode, targetSize, sourceSize); operationValue.Operands.Add(new StackValueRef(tempAnyValue)); // 0 = source operationValue.Operands.Add(tempPointerValue); // 1 = target instruction.ProcessedStackValue = operationValue; break; case OpCode.RefProtect: tempLiteralValue = stack.Pop() as StackValueLiteral; Debug.Assert(tempLiteralValue != null && tempLiteralValue.ValueType == StackValueType.Integer); var protectMode = (int)tempLiteralValue.Value; Debug.Assert(protectMode == 1 || protectMode == 2 || protectMode == 5 || protectMode == 6); tempLiteralValue = stack.Pop() as StackValueLiteral; Debug.Assert(tempLiteralValue != null && tempLiteralValue.ValueType == StackValueType.Integer); var protectCount = (int)tempLiteralValue.Value; //Debug.Assert(protectCount == 1); tempPointerValue = PopPointer(stack); operationValue = new StackValueOperation(StackValueOperationType.RefProtect); operationValue.Operands.Add(tempPointerValue); operationValue.Operands.Add(tempLiteralValue); if ((protectMode & 1) != 0) { stack.Push(operationValue); } break; default: if (instruction.Instruction is InstructionPush) { // PushD special case stack.Push(new StackValueLiteral((int) instruction.Instruction.Operands[0])); } else { operationValue = new StackValueOperation(opCode); processDefault = true; } break; } if (processDefault) { Debug.Assert(instruction.Instruction.HasStackUsageInfo); var stackValues = new Stack<StackValue>(); for (int i = 0; i < instruction.Instruction.StackIn; i++) { StackValue stackItem = stack.Pop(); stackValues.Push(stackItem); } operationValue.Operands.AddRange(stackValues); if (instruction.Instruction.StackLeftOver > 0) { for (int i = 0; i < instruction.Instruction.StackLeftOver; i++) { stackValues.Push(stackValues.Pop()); } } if (instruction.Instruction.StackOut > 0) { if (instruction.Instruction.StackOut > 1) { var multiAssign = new StackValueAssignMulti(operationValue); for (int i = 0; i < instruction.Instruction.StackOut; i++) { tempPointerValue = new StackValuePointerVar(StackValuePointerType.Temporary, tempVarIndex + i); multiAssign.AssignPointers.Add(tempPointerValue); stack.Push(new StackValueDeref(tempPointerValue)); } tempVarIndex += instruction.Instruction.StackOut; instruction.ProcessedStackValue = multiAssign; } else { stack.Push(operationValue); } } else { instruction.ProcessedStackValue = operationValue; } } } } catch (Exception e) { throw new Exception( "Error while decompiling instruction : " + instruction.Instruction + "\n", e); } instruction = instruction.GetNextInstruction(); } }
private void AnalyzeCodePath(Stack <StackValue> stack, CodePath path, ref int tempVarIndex) { HLInstruction instruction = path.GetFirstInstruction(); while (instruction != null) { try { if (instruction.BranchFunction != null) { if (!instruction.Instruction.HasStackUsageInfo) { instruction.Instruction.StackIn = instruction.BranchFunction.ParameterCount; instruction.Instruction.StackOut = instruction.BranchFunction.ReturnCount; instruction.Instruction.StackLeftOver = 0; instruction.Instruction.HasStackUsageInfo = true; } } if (instruction.UnconditionalBranch) { // One should not even occur //Debug.Assert(false); } else if (instruction.ExitFunction) { var value = new StackValueOperation(StackValueOperationType.Return); if (path.ParentFunction.ReturnCount > 0) { for (int i = 0; i < path.ParentFunction.ReturnCount; i++) { value.Operands.Add(stack.Pop()); } } instruction.ProcessedStackValue = value; } else if (instruction.IsConditionalBranch || instruction.IsSwitchBranch) { instruction.ProcessedStackValue = stack.Pop(); } else { bool processDefault = false; StackValueOperation operationValue = null; StackValue tempAnyValue; StackValueOperation tempOpValue; StackValueLiteral tempLiteralValue; StackValuePointerBase tempPointerValue; OpCode opCode = instruction.Instruction.OpCode; switch (opCode) { case OpCode.AddVec: VectorOperation(StackValueOperationType.Add, stack); break; case OpCode.SubVec: VectorOperation(StackValueOperationType.Sub, stack); break; case OpCode.MulVec: VectorOperation(StackValueOperationType.Mul, stack); break; case OpCode.DivVec: VectorOperation(StackValueOperationType.Div, stack); break; case OpCode.NegVec: VectorOperation(StackValueOperationType.Neg, stack); break; case OpCode.VecFromF: VectorOperation(StackValueOperationType.FromF, stack); break; case OpCode.PushS: stack.Push(new StackValueLiteral((short)instruction.Instruction.Operands[0])); break; case OpCode.Push: stack.Push(new StackValueLiteral((int)(uint)instruction.Instruction.Operands[0])); break; case OpCode.PushF: stack.Push(new StackValueLiteral((float)instruction.Instruction.Operands[0])); break; case OpCode.PushString: stack.Push(new StackValueLiteral((string)instruction.Instruction.Operands[0])); break; case OpCode.Dup: stack.Push(stack.Peek()); break; case OpCode.Pop: tempOpValue = stack.Peek() as StackValueOperation; if (tempOpValue != null && tempOpValue.OperationType == StackValueOperationType.Call) { operationValue = new StackValueOperation(StackValueOperationType.Pop); processDefault = true; } break; case OpCode.CallNative: operationValue = new StackValueOperation(instruction.Instruction.Operands[2].ToString()); processDefault = true; break; case OpCode.Call: operationValue = new StackValueOperation(instruction.BranchFunction.Name); processDefault = true; break; case OpCode.RefGet: stack.Push(new StackValueDeref(stack.Pop())); break; case OpCode.RefSet: instruction.ProcessedStackValue = new StackValueAssign(PopPointer(stack), stack.Pop()); break; case OpCode.RefPeekSet: tempAnyValue = stack.Pop(); // value! instruction.ProcessedStackValue = new StackValueAssign(PeekPointer(stack), tempAnyValue); break; case OpCode.ArrayExplode: // This is used to either pass a structure to a native/function call // or to explode the variables onto the stack to do a "shallow-copy" tempPointerValue = PopPointer(stack); tempLiteralValue = stack.Pop() as StackValueLiteral; Debug.Assert(tempLiteralValue != null && tempLiteralValue.ValueType == StackValueType.Integer); var explodeCount = (int)tempLiteralValue.Value; for (int i = 0; i < explodeCount; i++) { stack.Push(new StackValueDeref(new StackValuePointerIndex(tempPointerValue, i))); } break; case OpCode.ArrayImplode: // The only case this is ever used is for a shallow copy! tempPointerValue = PopPointer(stack); tempLiteralValue = stack.Pop() as StackValueLiteral; Debug.Assert(tempLiteralValue != null && tempLiteralValue.ValueType == StackValueType.Integer); var tempStack = new Stack <StackValue>(); var implodeCount = (int)tempLiteralValue.Value; for (int i = implodeCount - 1; i >= 0; i--) { tempStack.Push( new StackValueAssign(new StackValuePointerIndex(tempPointerValue, i), stack.Pop())); } var stackValueGroup = new ProcessedStackValueGroup(); stackValueGroup.Values.AddRange(tempStack.ToArray()); instruction.ProcessedStackValue = stackValueGroup; break; case OpCode.Var0: case OpCode.Var1: case OpCode.Var2: case OpCode.Var3: case OpCode.Var4: case OpCode.Var5: case OpCode.Var6: case OpCode.Var7: stack.Push(new StackValuePointerVar(StackValuePointerType.Stack, (opCode - OpCode.Var0))); break; case OpCode.Var: tempLiteralValue = stack.Pop() as StackValueLiteral; Debug.Assert(tempLiteralValue != null && tempLiteralValue.ValueType == StackValueType.Integer); stack.Push(new StackValuePointerVar(StackValuePointerType.Stack, (int)tempLiteralValue.Value)); break; case OpCode.LocalVar: tempLiteralValue = stack.Pop() as StackValueLiteral; Debug.Assert(tempLiteralValue != null && tempLiteralValue.ValueType == StackValueType.Integer); stack.Push(new StackValuePointerVar(StackValuePointerType.Local, (int)tempLiteralValue.Value)); break; case OpCode.GlobalVar: tempLiteralValue = stack.Pop() as StackValueLiteral; Debug.Assert(tempLiteralValue != null && tempLiteralValue.ValueType == StackValueType.Integer); stack.Push(new StackValuePointerVar(StackValuePointerType.Global, (int)tempLiteralValue.Value)); break; case OpCode.ArrayRef: tempPointerValue = PopPointer(stack); tempLiteralValue = stack.Pop() as StackValueLiteral; tempAnyValue = stack.Pop(); Debug.Assert(tempPointerValue != null); Debug.Assert(tempLiteralValue != null && tempLiteralValue.ValueType == StackValueType.Integer); stack.Push(new StackValuePointerArray(tempPointerValue, tempAnyValue, (int)tempLiteralValue.Value)); break; case OpCode.NullObj: stack.Push(new StackValuePointerVar(StackValuePointerType.Null)); break; case OpCode.Add: // Special case for pointer add tempAnyValue = stack.Pop(); tempPointerValue = stack.Peek() as StackValuePointerBase; if (tempPointerValue != null) { stack.Pop(); // tempPointerValue tempLiteralValue = tempAnyValue as StackValueLiteral; Debug.Assert(tempLiteralValue != null && (int)tempLiteralValue.Value % 4 == 0); stack.Push(new StackValuePointerIndex(tempPointerValue, (int)tempLiteralValue.Value / 4)); } else { stack.Push(tempAnyValue); operationValue = new StackValueOperation(opCode); processDefault = true; } break; case OpCode.StrCat: case OpCode.StrCatI: case OpCode.StrCpy: case OpCode.IntToStr: operationValue = new StackValueStringOperation(opCode, (byte)instruction.Instruction.Operands[0]); processDefault = true; break; case OpCode.StrVarCpy: tempPointerValue = PopPointer(stack); tempLiteralValue = stack.Pop() as StackValueLiteral; Debug.Assert(tempLiteralValue != null && tempLiteralValue.ValueType == StackValueType.Integer); var targetSize = (uint)(int)tempLiteralValue.Value; tempLiteralValue = stack.Pop() as StackValueLiteral; Debug.Assert(tempLiteralValue != null && tempLiteralValue.ValueType == StackValueType.Integer); var sourceSize = (uint)(int)tempLiteralValue.Value; var popSize = sourceSize; tempAnyValue = PopPointer(stack); // Pop till the last one for (var i = 1; i < popSize; i++) { tempAnyValue = PopPointer(stack); } operationValue = new StackValueStringOperation(opCode, targetSize, sourceSize); operationValue.Operands.Add(new StackValueRef(tempAnyValue)); // 0 = source operationValue.Operands.Add(tempPointerValue); // 1 = target instruction.ProcessedStackValue = operationValue; break; case OpCode.RefProtect: tempLiteralValue = stack.Pop() as StackValueLiteral; Debug.Assert(tempLiteralValue != null && tempLiteralValue.ValueType == StackValueType.Integer); var protectMode = (int)tempLiteralValue.Value; Debug.Assert(protectMode == 1 || protectMode == 2 || protectMode == 5 || protectMode == 6); tempLiteralValue = stack.Pop() as StackValueLiteral; Debug.Assert(tempLiteralValue != null && tempLiteralValue.ValueType == StackValueType.Integer); var protectCount = (int)tempLiteralValue.Value; //Debug.Assert(protectCount == 1); tempPointerValue = PopPointer(stack); operationValue = new StackValueOperation(StackValueOperationType.RefProtect); operationValue.Operands.Add(tempPointerValue); operationValue.Operands.Add(tempLiteralValue); if ((protectMode & 1) != 0) { stack.Push(operationValue); } break; default: if (instruction.Instruction is InstructionPush) { // PushD special case stack.Push(new StackValueLiteral((int)instruction.Instruction.Operands[0])); } else { operationValue = new StackValueOperation(opCode); processDefault = true; } break; } if (processDefault) { Debug.Assert(instruction.Instruction.HasStackUsageInfo); var stackValues = new Stack <StackValue>(); for (int i = 0; i < instruction.Instruction.StackIn; i++) { StackValue stackItem = stack.Pop(); stackValues.Push(stackItem); } operationValue.Operands.AddRange(stackValues); if (instruction.Instruction.StackLeftOver > 0) { for (int i = 0; i < instruction.Instruction.StackLeftOver; i++) { stackValues.Push(stackValues.Pop()); } } if (instruction.Instruction.StackOut > 0) { if (instruction.Instruction.StackOut > 1) { var multiAssign = new StackValueAssignMulti(operationValue); for (int i = 0; i < instruction.Instruction.StackOut; i++) { tempPointerValue = new StackValuePointerVar(StackValuePointerType.Temporary, tempVarIndex + i); multiAssign.AssignPointers.Add(tempPointerValue); stack.Push(new StackValueDeref(tempPointerValue)); } tempVarIndex += instruction.Instruction.StackOut; instruction.ProcessedStackValue = multiAssign; } else { stack.Push(operationValue); } } else { instruction.ProcessedStackValue = operationValue; } } } } catch (Exception e) { throw new Exception( "Error while decompiling instruction : " + instruction.Instruction + "\n", e); } instruction = instruction.GetNextInstruction(); } }