Beispiel #1
0
        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);
        }
Beispiel #2
0
        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());
        }
Beispiel #3
0
        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());
        }
Beispiel #4
0
        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);
        }
Beispiel #5
0
        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;
            }
        }