private bool isFunction(int i) { if (stack.Count == 0) { return(false); } int prev = stack.Peek().intValue(); VSMXGroup prevCode = mem.codes[prev]; if (prevCode.isOpcode(VSMXCode.VID_OPERATOR_ASSIGN)) { prev--; prevCode = mem.codes[prev]; } if (!prevCode.isOpcode(VSMXCode.VID_FUNCTION) || prevCode.value != i + 1) { return(false); } VSMXGroup prePrevCode = mem.codes[prev - 1]; if (prePrevCode.isOpcode(VSMXCode.VID_PROPERTY)) { prev--; prePrevCode = mem.codes[prev - 1]; } if (!prePrevCode.isOpcode(VSMXCode.VID_VARIABLE)) { return(false); } return(true); }
public virtual void debug() { for (int i = 0; i < mem.codes.Length; i++) { StringBuilder s = new StringBuilder(); VSMXGroup code = mem.codes[i]; int opcode = code.id & 0xFF; if (opcode >= 0 && opcode < VSMXCode.VsmxDecOps.Length) { s.Append(VSMXCode.VsmxDecOps[opcode]); } else { s.Append(string.Format("UNKNOWN_{0:X}", opcode)); } switch (opcode) { case VSMXCode.VID_CONST_BOOL: if (code.value == 1) { s.Append(" true"); } else if (code.value == 0) { s.Append(" false"); } else { s.Append(string.Format(" 0x{0:X}", code.value)); } break; case VSMXCode.VID_CONST_INT: case VSMXCode.VID_DEBUG_LINE: s.Append(string.Format(" {0:D}", code.value)); break; case VSMXCode.VID_CONST_FLOAT: s.Append(string.Format(" {0:F}", code.FloatValue)); break; case VSMXCode.VID_CONST_STRING: case VSMXCode.VID_DEBUG_FILE: s.Append(string.Format(" '{0}'", mem.texts[code.value])); break; case VSMXCode.VID_VARIABLE: s.Append(string.Format(" {0}", mem.names[code.value])); break; case VSMXCode.VID_PROPERTY: case VSMXCode.VID_METHOD: case VSMXCode.VID_SET_ATTR: case VSMXCode.VID_UNSET: case VSMXCode.VID_OBJ_ADD_ATTR: s.Append(string.Format(" {0}", mem.properties[code.value])); break; case VSMXCode.VID_FUNCTION: int n = (code.id >> 16) & 0xFF; if (n != 0) { Console.WriteLine(string.Format("Unexpected localvars value for function at line {0:D}, expected 0, got {1:D}", i, n)); } int args = (code.id >> 8) & 0xFF; int localVars = (code.id >> 24) & 0xFF; s.Append(string.Format(" args={0:D}, localVars={1:D}, startLine={2:D}", args, localVars, code.value)); break; case VSMXCode.VID_UNNAMED_VAR: s.Append(string.Format(" {0:D}", code.value)); break; // jumps case VSMXCode.VID_JUMP: case VSMXCode.VID_JUMP_TRUE: case VSMXCode.VID_JUMP_FALSE: s.Append(string.Format(" line={0:D}", code.value)); break; // function calls case VSMXCode.VID_CALL_FUNC: case VSMXCode.VID_CALL_METHOD: case VSMXCode.VID_CALL_NEW: s.Append(string.Format(" args={0:D}", code.value)); break; case VSMXCode.VID_MAKE_FLOAT_ARRAY: s.Append(string.Format(" items={0:D}", code.value)); break; // ops w/o arg - check for zero case VSMXCode.VID_OPERATOR_ASSIGN: case VSMXCode.VID_OPERATOR_ADD: case VSMXCode.VID_OPERATOR_SUBTRACT: case VSMXCode.VID_OPERATOR_MULTIPLY: case VSMXCode.VID_OPERATOR_DIVIDE: case VSMXCode.VID_OPERATOR_MOD: case VSMXCode.VID_OPERATOR_POSITIVE: case VSMXCode.VID_OPERATOR_NEGATE: case VSMXCode.VID_OPERATOR_NOT: case VSMXCode.VID_P_INCREMENT: case VSMXCode.VID_P_DECREMENT: case VSMXCode.VID_INCREMENT: case VSMXCode.VID_DECREMENT: case VSMXCode.VID_OPERATOR_TYPEOF: case VSMXCode.VID_OPERATOR_EQUAL: case VSMXCode.VID_OPERATOR_NOT_EQUAL: case VSMXCode.VID_OPERATOR_IDENTITY: case VSMXCode.VID_OPERATOR_NON_IDENTITY: case VSMXCode.VID_OPERATOR_LT: case VSMXCode.VID_OPERATOR_LTE: case VSMXCode.VID_OPERATOR_GT: case VSMXCode.VID_OPERATOR_GTE: case VSMXCode.VID_OPERATOR_B_AND: case VSMXCode.VID_OPERATOR_B_XOR: case VSMXCode.VID_OPERATOR_B_OR: case VSMXCode.VID_OPERATOR_B_NOT: case VSMXCode.VID_OPERATOR_LSHIFT: case VSMXCode.VID_OPERATOR_RSHIFT: case VSMXCode.VID_OPERATOR_URSHIFT: case VSMXCode.VID_STACK_COPY: case VSMXCode.VID_STACK_SWAP: case VSMXCode.VID_END_STMT: case VSMXCode.VID_CONST_NULL: case VSMXCode.VID_CONST_EMPTYARRAY: case VSMXCode.VID_CONST_OBJECT: case VSMXCode.VID_ARRAY: case VSMXCode.VID_THIS: case VSMXCode.VID_ARRAY_INDEX: case VSMXCode.VID_ARRAY_INDEX_ASSIGN: case VSMXCode.VID_ARRAY_PUSH: case VSMXCode.VID_RETURN: case VSMXCode.VID_END: if (code.value != 0) { Console.WriteLine(string.Format("Unexpected non-zero value at line #{0:D}: 0x{1:X}!", i, code.value)); } break; default: s.Append(string.Format(" 0x{0:X}", code.value)); break; } Console.WriteLine(string.Format("Line#{0:D}: {1}", i, s.ToString())); } Console.WriteLine(decompile()); }
private string decompile() { StringBuilder s = new StringBuilder(); prefix = ""; stack = new Stack <int>(); blockEnd = new Stack <int>(); switchState = SWITCH_STATE_NONE; ignoreFunctionSet = -1; statementStartLine = 0; needLineLabel = new HashSet <int>(); for (int i = 0; i < mem.codes.Length; i++) { VSMXGroup code = mem.codes[i]; int opcode = code.Opcode; while (blockEnd.Count > 0 && blockEnd.Peek().intValue() == i) { decrementIndent(); s.Append(string.Format("{0}}}\n", prefix)); } if (needLineLabel.remove(i)) { s.Append(string.Format("{0:D}:\n", i)); } switch (opcode) { case VSMXCode.VID_END_STMT: decompileStmt(s); statementStartLine = i + 1; break; case VSMXCode.VID_RETURN: case VSMXCode.VID_JUMP_FALSE: case VSMXCode.VID_JUMP_TRUE: i = decompileStmt(s, i); break; case VSMXCode.VID_JUMP: if (isSwitch(code.value) || detectSwitch(s, i)) { i = decompileSwitch(s, i, code.value); } else if (isFunction(i)) { decompileFunction(s, code.value); } else { if (blockEnd.Count > 0 && blockEnd.Peek().intValue() == i + 1) { decrementIndent(); s.Append(string.Format("{0}}} else {{\n", prefix)); } i = decompileStmt(s, i); } break; default: stack.Push(i); break; } } return(s.ToString()); }
private int decompileStmt(StringBuilder s, int i) { int initialLength = s.Length; VSMXGroup code = mem.codes[i]; int opcode = code.Opcode; StringBuilder op1; StringBuilder op2; StringBuilder op3; switch (opcode) { case VSMXCode.VID_OPERATOR_ASSIGN: op1 = new StringBuilder(); decompileOp(op1); op2 = new StringBuilder(); decompileOp(op2); s.Append(string.Format("{0}{1} = {2}", prefix, op2, op1)); break; case VSMXCode.VID_ARRAY_INDEX_ASSIGN: op1 = new StringBuilder(); decompileOp(op1); op2 = new StringBuilder(); decompileOp(op2); op3 = new StringBuilder(); decompileOp(op3); s.Append(string.Format("{0}{1}[{2}] = {3}", prefix, op3, op2, op1)); break; case VSMXCode.VID_CALL_FUNC: case VSMXCode.VID_CALL_METHOD: stack.Push(i); op1 = new StringBuilder(); decompileOp(op1); s.Append(string.Format("{0}{1}", prefix, op1)); break; case VSMXCode.VID_JUMP_TRUE: op1 = new StringBuilder(); if (isBooleanExpression(op1)) { addToBooleanExpression(op1, true); } else if (booleanExpression != null) { decompileOp(op1); addToBooleanExpression(op1, true); s.Append(string.Format("{0}if ({1}) {{", prefix, booleanExpression)); increaseIndent(code.value); booleanExpression = null; } else { decompileOp(op1); // this is probably a "for" loop s.Append(string.Format("{0:D}:\n", statementStartLine)); if (mem.codes[i + 1].isOpcode(VSMXCode.VID_JUMP)) { int elseGoto = mem.codes[i + 1].value; s.Append(string.Format("{0}if ({1}) goto {2:D}; else goto {3:D}", prefix, op1, code.value, elseGoto)); needLineLabel.Add(elseGoto); needLineLabel.Add(i + 2); i++; } else { s.Append(string.Format("{0}if ({1}) goto {2:D}", prefix, op1, code.value)); } needLineLabel.Add(code.value); } break; case VSMXCode.VID_JUMP_FALSE: op1 = new StringBuilder(); if (isBooleanExpression(op1)) { addToBooleanExpression(op1, false); } else if (booleanExpression != null) { decompileOp(op1); addToBooleanExpression(op1); s.Append(string.Format("{0}if ({1}) {{", prefix, booleanExpression)); increaseIndent(code.value); booleanExpression = null; } else { decompileOp(op1); s.Append(string.Format("{0}if ({1}) {{", prefix, op1)); increaseIndent(code.value); } break; case VSMXCode.VID_RETURN: op1 = new StringBuilder(); decompileOp(op1); s.Append(string.Format("{0}return {1}", prefix, op1)); break; case VSMXCode.VID_SET_ATTR: if (i == ignoreFunctionSet) { ignoreFunctionSet = -1; } else { op1 = new StringBuilder(); decompileOp(op1); op2 = new StringBuilder(); decompileOp(op2); s.Append(string.Format("{0}{1}.{2} = {3}", prefix, op2, mem.properties[code.value], op1)); } break; case VSMXCode.VID_INCREMENT: s.Append(prefix); operatorPost1(s, "++"); break; case VSMXCode.VID_DECREMENT: s.Append(prefix); operatorPost1(s, "--"); break; case VSMXCode.VID_P_INCREMENT: s.Append(prefix); operatorPre1(s, "++"); break; case VSMXCode.VID_P_DECREMENT: s.Append(prefix); operatorPre1(s, "--"); break; case VSMXCode.VID_OPERATOR_EQUAL: operator2(s, " == "); break; case VSMXCode.VID_JUMP: if (code.value > i) { increaseIndent(code.value); } else { // Backward loop s.Append(string.Format("{0}goto {1:D}", prefix, code.value)); } break; case VSMXCode.VID_VARIABLE: s.Append(prefix); s.Append(mem.names[code.value]); break; case VSMXCode.VID_UNNAMED_VAR: s.Append(prefix); s.Append(string.Format("var{0:D}", code.value)); break; case VSMXCode.VID_DEBUG_LINE: break; default: Console.WriteLine(string.Format("Line #{0:D}: decompileStmt({1}) unimplemented", i, VSMXCode.VsmxDecOps[opcode])); break; } if (s.Length != initialLength) { if (s[s.Length - 1] != '{') { s.Append(";"); } s.Append(string.Format(" // line {0:D}", i)); s.Append("\n"); } return(i); }
private void decompileOp(StringBuilder s) { if (stack.Count == 0) { return; } int i = stack.Pop(); VSMXGroup code = mem.codes[i]; int opcode = code.Opcode; int args; StringBuilder[] ops; StringBuilder op, op1, op2, method; switch (opcode) { case VSMXCode.VID_VARIABLE: s.Append(mem.names[code.value]); break; case VSMXCode.VID_UNNAMED_VAR: s.Append(string.Format("var{0:D}", code.value)); break; case VSMXCode.VID_CONST_BOOL: if (code.value == 1) { s.Append("true"); } else if (code.value == 0) { s.Append("false"); } else { s.Append(string.Format("0x{0:X}", code.value)); } break; case VSMXCode.VID_CONST_INT: s.Append(string.Format("{0:D}", code.value)); break; case VSMXCode.VID_CONST_FLOAT: s.Append(string.Format("{0:F}", code.FloatValue)); break; case VSMXCode.VID_CONST_STRING: case VSMXCode.VID_DEBUG_FILE: s.Append(string.Format("\"{0}\"", mem.texts[code.value])); break; case VSMXCode.VID_PROPERTY: op = new StringBuilder(); decompileOp(op); s.Append(string.Format("{0}.{1}", op, mem.properties[code.value])); break; case VSMXCode.VID_METHOD: case VSMXCode.VID_SET_ATTR: case VSMXCode.VID_UNSET: case VSMXCode.VID_OBJ_ADD_ATTR: s.Append(mem.properties[code.value]); break; case VSMXCode.VID_FUNCTION: args = (code.id >> 8) & 0xFF; s.Append("function("); for (int n = 0; n < args; n++) { if (n > 0) { s.Append(", "); } s.Append(string.Format("var{0:D}", n + 1)); } s.Append(string.Format(") {")); break; case VSMXCode.VID_CONST_EMPTYARRAY: s.Append("{}"); break; case VSMXCode.VID_CONST_NULL: s.Append("null"); break; case VSMXCode.VID_THIS: s.Append("this"); break; case VSMXCode.VID_ARRAY_INDEX: op1 = new StringBuilder(); decompileOp(op1); op2 = new StringBuilder(); decompileOp(op2); s.Append(string.Format("{0}[{1}]", op2, op1)); break; case VSMXCode.VID_ARRAY_INDEX_KEEP_OBJ: op1 = new StringBuilder(); decompileOp(op1); i = stack.Peek(); op2 = new StringBuilder(); decompileOp(op2); stack.Push(i); s.Append(string.Format("{0}[{1}]", op2, op1)); break; case VSMXCode.VID_CALL_NEW: args = code.value; ops = new StringBuilder[args]; for (int n = args - 1; n >= 0; n--) { ops[n] = new StringBuilder(); decompileOp(ops[n]); } op = new StringBuilder(); decompileOp(op); s.Append(string.Format("new {0}(", op)); for (int n = 0; n < args; n++) { if (n > 0) { s.Append(", "); } s.Append(ops[n]); } s.Append(")"); break; case VSMXCode.VID_CALL_METHOD: args = code.value; ops = new StringBuilder[args]; for (int n = args - 1; n >= 0; n--) { ops[n] = new StringBuilder(); decompileOp(ops[n]); } method = new StringBuilder(); decompileOp(method); op = new StringBuilder(); decompileOp(op); s.Append(string.Format("{0}.{1}(", op, method)); for (int n = 0; n < args; n++) { if (n > 0) { s.Append(", "); } s.Append(ops[n]); } s.Append(")"); break; case VSMXCode.VID_CALL_FUNC: args = code.value; ops = new StringBuilder[args]; for (int n = args - 1; n >= 0; n--) { ops[n] = new StringBuilder(); decompileOp(ops[n]); } method = new StringBuilder(); decompileOp(method); s.Append(string.Format("{0}(", method)); for (int n = 0; n < args; n++) { if (n > 0) { s.Append(", "); } s.Append(ops[n]); } s.Append(")"); break; case VSMXCode.VID_OPERATOR_EQUAL: operator2(s, " == "); break; case VSMXCode.VID_OPERATOR_NOT_EQUAL: operator2(s, " != "); break; case VSMXCode.VID_OPERATOR_GT: operator2(s, " > "); break; case VSMXCode.VID_OPERATOR_GTE: operator2(s, " >= "); break; case VSMXCode.VID_OPERATOR_LT: operator2(s, " < "); break; case VSMXCode.VID_OPERATOR_LTE: operator2(s, " <= "); break; case VSMXCode.VID_OPERATOR_NOT: operatorPre1(s, "!"); break; case VSMXCode.VID_OPERATOR_NEGATE: operatorPre1(s, "-"); break; case VSMXCode.VID_OPERATOR_ADD: operator2(s, " + "); break; case VSMXCode.VID_OPERATOR_SUBTRACT: operator2(s, " - "); break; case VSMXCode.VID_OPERATOR_MULTIPLY: operator2(s, " * "); break; case VSMXCode.VID_OPERATOR_DIVIDE: operator2(s, " / "); break; case VSMXCode.VID_OPERATOR_MOD: operator2(s, " % "); break; case VSMXCode.VID_OPERATOR_B_AND: operator2(s, " & "); break; case VSMXCode.VID_OPERATOR_B_XOR: operator2(s, " ^ "); break; case VSMXCode.VID_OPERATOR_B_OR: operator2(s, " | "); break; case VSMXCode.VID_OPERATOR_B_NOT: operatorPre1(s, "~"); break; case VSMXCode.VID_OPERATOR_LSHIFT: operator2(s, " << "); break; case VSMXCode.VID_OPERATOR_RSHIFT: operator2(s, " >> "); break; case VSMXCode.VID_OPERATOR_URSHIFT: operator2(s, " >>> "); break; case VSMXCode.VID_INCREMENT: operatorPost1(s, "++"); break; case VSMXCode.VID_DECREMENT: operatorPost1(s, "--"); break; case VSMXCode.VID_P_INCREMENT: operatorPre1(s, "++"); break; case VSMXCode.VID_P_DECREMENT: operatorPre1(s, "--"); break; case VSMXCode.VID_ARRAY_PUSH: op1 = new StringBuilder(); decompileOp(op1); if (stack.Count > 0 && mem.codes[stack.Peek().intValue()].isOpcode(VSMXCode.VID_ARRAY_PUSH)) { // Display nicely an array initialization while (stack.Count > 0 && mem.codes[stack.Peek().intValue()].isOpcode(VSMXCode.VID_ARRAY_PUSH)) { stack.Pop(); op2 = new StringBuilder(); decompileOp(op2); op1.Insert(0, string.Format(",\n{0} ", prefix)); op1.Insert(0, op2.ToString()); } op2 = new StringBuilder(); decompileOp(op2); s.Append(string.Format("{0} {{\n{1} {2}\n{3}}}", op2, prefix, op1, prefix)); } else { op2 = new StringBuilder(); decompileOp(op2); s.Append(string.Format("{0}.push({1})", op2, op1)); } break; case VSMXCode.VID_ARRAY: s.Append("new Array()"); break; case VSMXCode.VID_OPERATOR_ASSIGN: op1 = new StringBuilder(); decompileOp(op1); op2 = new StringBuilder(); decompileOp(op2); s.Append(string.Format("{0} = {1}", op2, op1)); break; case VSMXCode.VID_STACK_COPY: if (stack.Count > 0) { i = stack.Pop(); stack.Push(i); stack.Push(i); decompileOp(s); } break; case VSMXCode.VID_DEBUG_LINE: // Ignore debug line decompileOp(s); break; default: Console.WriteLine(string.Format("Line #{0:D}: decompileOp({1}) unimplemented", i, VSMXCode.VsmxDecOps[opcode])); break; } }