Beispiel #1
0
        internal static bool AreInstructionAdjacent(DalvikInstruction x, DalvikInstruction y)
        {
            if (null == x) { throw new ArgumentNullException(); }
            if (null == y) { throw new ArgumentNullException(); }
            if (object.ReferenceEquals(x, y)) { throw new InvalidOperationException(); }
            DalvikInstruction first;
            DalvikInstruction second;
            if (x.MethodRelativeOffset < y.MethodRelativeOffset) {
                first = x;
                second = y;
            } else {
                first = y;
                second = x;
            }

            return (first.MethodRelativeOffset + first.InstructionSize) == second.MethodRelativeOffset;
        }
Beispiel #2
0
        /// <summary></summary>
        /// <param name="method"></param>
        /// <param name="rootAstNode"></param>
        /// <returns></returns>
        internal static CfgNode BuildBasicTree(IMethod method, DalvikInstruction[] instructions,
            #if DBGCFG
            bool debugMethodCfg = false
            #endif
            )
        {
            CfgNode result =
            #if DBGCFG
                new CfgNode(debugMethodCfg);
            #else
                new CfgNode();
            #endif

            CreateBasicBlocks(result, method, instructions);
            EnsureExitNodeUniqueness(result);
            #if DBGCFG
            if (debugMethodCfg) { result.DumpGraph(); }
            #endif
            return result;
        }
Beispiel #3
0
        /// <summary>Bind the given instruction to this block. The instruction must either
        /// be the first one to be bound to the block or be at offset immediately after the
        /// last already bound instruction from the block.</summary>
        /// <param name="instruction">The instruction to be bound.</param>
        internal void Bind(DalvikInstruction instruction)
        {
            if ((null != Successors) && (0 < Successors.Length)) {
                // We want successorc always to be from the last instruction of the
                // block so once a successor is set on a block binding additional
                // instructions is not possible anymore.
                throw new InvalidOperationException();
            }
#if DBGCFG
            if (DebugEnabled && (null != instruction)) {
                Console.WriteLine("[{0}] += <{1:X4}>", NodeId, instruction.MethodRelativeOffset);
            }
#endif
            if (null == instruction) { throw new ArgumentNullException(); }
            if (null == _instructions) {
                // First instruction to be bound to this block. Easy to handle.
                _instructions = new List<DalvikInstruction>();
                _instructions.Add(instruction);
                _size += instruction.InstructionSize;
                return;
            }
            // Prevent double insertion.
            if (_instructions.Contains(instruction)) {
                throw new InvalidOperationException();
            }

            // The new instruction must be adjacent to the last already bound AND be
            // at a greater offset.
            DalvikInstruction lastInstruction = _instructions[_instructions.Count - 1];
            uint expectedOffset = lastInstruction.MethodRelativeOffset + lastInstruction.InstructionSize;
            if (expectedOffset != instruction.MethodRelativeOffset) {
                throw new InvalidOperationException();
            }
            _instructions.Add(instruction);
            _size += instruction.InstructionSize;
            return;
        }
Beispiel #4
0
        /// <summary>Create basic blocks.</summary>
        /// <param name="rootNode">The root node of the graph.</param>
        /// <param name="method">The method which body is involved.</param>
        /// <param name="sparseInstructions">A sparse array of instructions to be analyzed.
        /// Some of the entries in this array are expected to be null references
        /// denoting no instruction starts at that particular offset within the method
        /// bytecode.</param>
        private static void CreateBasicBlocks(CfgNode rootNode, IMethod method,
            DalvikInstruction[] sparseInstructions)
        {
            #if DBGCFG
            List<CfgNode> methodNodes = new List<CfgNode>();
            #endif
            List<BlockNode> unreachableBlocks = new List<BlockNode>();
            BlockNode currentBlock = null;
            bool firstBlock = true;
            // An array that maps each bytecode byte to it's owning block if any.
            BlockNode[] blocksPerOffset = new BlockNode[method.ByteCodeSize];
            blocksPerOffset[0] = currentBlock;
            bool cfgDebuggingEnabled = rootNode.DebugEnabled;

            // Create basic blocks. These are set of consecutive instructions with
            // each instruction having a single successor that is the next instruction.
            foreach (DalvikInstruction scannedInstruction in sparseInstructions) {
                if (null == scannedInstruction) { continue; }
            #if DBGCFG
                if (cfgDebuggingEnabled) {
                    Console.WriteLine("@{0:X4} {1}", scannedInstruction.MethodRelativeOffset,
                        scannedInstruction.GetType().Name);
                }
            #endif
                if (null == currentBlock) {
                    // The previous instruction didn't fail in sequence. Either there is already a
                    // block defined for the current offset or we must create a new one.
                    currentBlock = blocksPerOffset[scannedInstruction.MethodRelativeOffset];
                    if (null == currentBlock) {
                        currentBlock = new BlockNode(cfgDebuggingEnabled);
            #if DBGCFG
                        methodNodes.Add(currentBlock);
            #endif
                        blocksPerOffset[scannedInstruction.MethodRelativeOffset] = currentBlock;
                        if (firstBlock) {
                            CfgNode.Link(rootNode, currentBlock);
            #if DBGCFG
                            Console.WriteLine("Created first block #{0}", currentBlock.NodeId);
            #endif
                            firstBlock = false;
                        }
                        else {
                            unreachableBlocks.Add(currentBlock);
            #if DBGCFG
                            AssertConsistency(blocksPerOffset, methodNodes);
                            if (cfgDebuggingEnabled) {
                                Console.WriteLine("Created unreachable block #{0}", currentBlock.NodeId);
                            }
            #endif
                        }
                    }
            #if DBGCFG
                    else {
                        if (cfgDebuggingEnabled) {
                            Console.WriteLine("Reusing block #{0}", currentBlock.NodeId);
                        }
                    }
            #endif
                }
                else {
                    // Last instruction failed in sequence. However we may have already defined a
                    // block for the current offset.
                    BlockNode alreadyDefined = blocksPerOffset[scannedInstruction.MethodRelativeOffset];

                    if (   (null != alreadyDefined)
                        && !object.ReferenceEquals(currentBlock, alreadyDefined))
                    {
            #if DBGCFG
                        if (cfgDebuggingEnabled) {
                            Console.WriteLine(
                                "Linking block #{0} to block #{1} and switching to the later",
                                currentBlock.NodeId, alreadyDefined.NodeId);
                        }
            #endif
                        // make the already defined the current block.
                        CfgNode.Link(currentBlock, alreadyDefined);
                        currentBlock = alreadyDefined;
                    }
            #if DBGCFG
                    else {
                        if (cfgDebuggingEnabled) {
                            Console.WriteLine("Continuing with block #{0}", currentBlock.NodeId);
                        }
                    }
            #endif
                }
                currentBlock.Bind(scannedInstruction);
                for(uint sizeIndex = 0; sizeIndex < scannedInstruction.InstructionSize; sizeIndex++) {
                    int offsetIndex = (int)(scannedInstruction.MethodRelativeOffset + sizeIndex);
                    if (   (null != blocksPerOffset[offsetIndex])
                        && !object.ReferenceEquals(blocksPerOffset[offsetIndex], currentBlock))
                    {
                        throw new ApplicationException();
                    }
                    blocksPerOffset[offsetIndex] = currentBlock;
            #if DBGCFG
                    AssertConsistency(blocksPerOffset, methodNodes);
            #endif
                }
                // Scan other targets if any.
                uint[] otherOffsets = scannedInstruction.AdditionalTargetMethodOffsets;
                if (null == otherOffsets) {
                    if (!scannedInstruction.ContinueInSequence) {
                        // Must switch to another block.
                        currentBlock = null;
                    }
                    continue;
                }

                // Must create a block for each possible target and link current
                // block to each of those blocks.
                for (int index = 0; index < otherOffsets.Length; index++) {
                    uint targetOffset = otherOffsets[index];
                    BlockNode targetBlock = blocksPerOffset[targetOffset];

                    if (null == targetBlock) {
                        // Block doesn't exists yet. Create and register it.
                        targetBlock = new BlockNode(currentBlock.DebugEnabled);
            #if DBGCFG
                        methodNodes.Add(targetBlock);
            #endif
                        blocksPerOffset[targetOffset] = targetBlock;
            #if DBGCFG
                        AssertConsistency(blocksPerOffset, methodNodes);
                        if (targetBlock.DebugEnabled) {
                            Console.WriteLine("Pre-registering block #{0} @{1:X4}",
                                targetBlock.NodeId, targetOffset);
                            Console.WriteLine("Linking block #{0} to block #{1}",
                                currentBlock.NodeId, targetBlock.NodeId);
                        }
            #endif
                        // Link current node and next one.
                        CfgNode.Link(currentBlock, targetBlock);
                        continue;
                    }
                    // The target block already exists albeit it may deserve a split.
                    // if (0 == targetOffset) { continue; }
                    BlockNode splitCandidate = targetBlock;
                    bool splitCandidateIsCurrentBlock =
                        object.ReferenceEquals(splitCandidate, currentBlock);
                    bool splitCandidateAlreadyAligned =
                        !object.ReferenceEquals(blocksPerOffset[targetOffset - 1], splitCandidate);
                    bool linkCurrentToSplitted = true;

                    try {
                        if (splitCandidateAlreadyAligned && !splitCandidateIsCurrentBlock) {
                            // The split candidate actually starts at target address
                            // and is not the current block. No split required.
                            continue;
                        }
                        // Need a split.
                        uint splitAt;
                        bool makeSplitResultCurrent;
                        if (!splitCandidateAlreadyAligned) {
                            splitAt = targetOffset;
                            makeSplitResultCurrent = false;
                        }
                        else {
                            // The target is the first instruction of current block. We
                            // split the last instruction from the current block.
                            if (!splitCandidateIsCurrentBlock) {
                                throw new AssertionException();
                            }
                            splitAt = scannedInstruction.MethodRelativeOffset;
                            linkCurrentToSplitted = false;
                            // From now on consider the newly created block to be the
                            // current one.
                            makeSplitResultCurrent = true;
                        }
            #if DBGCFG
                        if (targetBlock.DebugEnabled) {
                            Console.WriteLine("Spliting block #{0} @{1:X4}.",
                                splitCandidate.NodeId, splitAt);
                        }
            #endif
                        targetBlock = splitCandidate.Split(splitAt);
            #if DBGCFG
                        methodNodes.Add(targetBlock);
                        if (targetBlock.DebugEnabled) {
                            Console.WriteLine("New block #{0} created while spliting block #{1}.",
                                targetBlock.NodeId, splitCandidate.NodeId);
                        }
            #endif
                        if (makeSplitResultCurrent) {
                            currentBlock = targetBlock;
                        }
                        // Update offset to block mapping for new splited block. Also
                        // transfer instructions from existing block to split result.
                        for (int scannedOffset = (int)splitAt; scannedOffset < blocksPerOffset.Length; scannedOffset++) {
                            if (!object.ReferenceEquals(blocksPerOffset[scannedOffset], splitCandidate)) { break; }
                            blocksPerOffset[scannedOffset] = targetBlock;
                        }
            #if DBGCFG
                        AssertConsistency(blocksPerOffset, methodNodes);
            #endif
                    }
                    finally {
                        if (linkCurrentToSplitted) {
            #if DBGCFG
                            if ((null != currentBlock) && currentBlock.DebugEnabled) {
                                Console.WriteLine("Linking block #{0} to block #{1}",
                                    currentBlock.NodeId, targetBlock.NodeId);
                            }
            #endif
                            // Link current node and next one.
                            CfgNode.Link(currentBlock, targetBlock);
                        }
                        if (unreachableBlocks.Contains(targetBlock)) {
                            unreachableBlocks.Remove(targetBlock);
            #if DBGCFG
                            if (targetBlock.DebugEnabled) {
                                Console.WriteLine("Previously unreachable block #{0} now reachable.",
                                    targetBlock.NodeId);
                            }
            #endif
                        }
                    }
                }

                // Having other targets force a block reset AND the next instruction to be in
                // a separate block than the current one, provided the current instruction fails
                // in sequence.
                if (scannedInstruction.ContinueInSequence) {
                    uint nextInstructionOffset =
                        scannedInstruction.MethodRelativeOffset + scannedInstruction.InstructionSize;
                    BlockNode nextBlock = blocksPerOffset[nextInstructionOffset];
                    if (null == nextBlock) {
                        nextBlock = new BlockNode(currentBlock.DebugEnabled);
            #if DBGCFG
                        methodNodes.Add(nextBlock);
            #endif
                        blocksPerOffset[nextInstructionOffset] = nextBlock;
            #if DBGCFG
                        AssertConsistency(blocksPerOffset, methodNodes);
                        if (nextBlock.DebugEnabled) {
                            Console.WriteLine("Created next block #{0} @{1:X4}",
                                nextBlock.NodeId, nextInstructionOffset);
                            Console.WriteLine("Linking block #{0} to block #{1}",
                                currentBlock.NodeId, nextBlock.NodeId);
                        }
            #endif
                    }
                    // Link current node and next one.
                    CfgNode.Link(currentBlock, nextBlock);
                }
                // Next block will always be different from the current one.
                currentBlock = null;
            }
            #if DBGCFG
            if (cfgDebuggingEnabled) { Console.WriteLine("Basic blocks creation done."); }
            #endif
            // Link allunreachable blocks to the root node.
            foreach (BlockNode scannedBlock in unreachableBlocks) { CfgNode.Link(rootNode, scannedBlock); }
            return;
        }
Beispiel #5
0
        /// <summary>Decode instructions for the given method.</summary>
        /// <param name="method">The method to be decoded.</param>
        /// <param name="objectResolver">An implementation of an object resolver to be
        /// used for retrieving classes and constant strings referenced from the bytecode.
        /// </param>
        /// <returns>An array indexed by the offset within method byte code and storing
        /// the instruction starting at this offset (if any).</returns>
        private static DalvikInstruction[] BuildInstructionList(IMethod method,
            IResolver objectResolver)
        {
            DalvikInstruction[] result = new DalvikInstruction[method.ByteCodeSize];
            byte[] byteCode = method.GetByteCode();
            List<uint> pendingInstructionsOffset = new List<uint>();

            // Add entry point.
            pendingInstructionsOffset.Add(0);
            // As well as catch blocks from the exception because they aren't
            // referenced from normal code.
            foreach (ITryBlock tryBlock in method.EnumerateTryBlocks()) {
                foreach (IGuardHandler handler in tryBlock.EnumerateHandlers()) {
                    uint addedOffset = handler.HandlerMethodOffset;
                    // For debugging purpose. Should never occur.
                    if (addedOffset >= byteCode.Length) { throw new ApplicationException(); }
                    pendingInstructionsOffset.Add(addedOffset);
                }
            }
            Console.WriteLine(
                "Decoding '{0}' method bytecode on {1} bytes starting at 0x{2:X8}.",
                Helpers.BuildMethodDeclarationString(method), byteCode.Length,
                method.ByteCodeRawAddress);

            while (0 < pendingInstructionsOffset.Count) {
                uint opCodeIndex = pendingInstructionsOffset[0];
                pendingInstructionsOffset.RemoveAt(0);
                bool fallInSequence = true;

                while (fallInSequence) {
                    // Avoid targeting twice a single instruction.
                    if (null != result[opCodeIndex]) { break; }
                    DalvikInstruction newNode = OpCodeDecoder.Decode(byteCode,
                        method.ByteCodeRawAddress, objectResolver, result,
                        ref opCodeIndex);

                    // Analyse possible targets after this instruction and augment
                    // pending instructions list accordingly.
                    fallInSequence = newNode.ContinueInSequence;
                    uint[] otherTargetMethodOffsets = newNode.AdditionalTargetMethodOffsets;
                    if (null != otherTargetMethodOffsets) {
                        for(int index = 0; index < otherTargetMethodOffsets.Length; index++) {
                            uint targetOffset = otherTargetMethodOffsets[index];

                            if (targetOffset >= byteCode.Length) { throw new ApplicationException(); }
                            if (!pendingInstructionsOffset.Contains(targetOffset)
                                && (null == result[targetOffset])) {
                                pendingInstructionsOffset.Add(targetOffset);
                            }
                        }
                    }
                }
            }
            return result;
        }
Beispiel #6
0
        /// <summary>This method decodes additional content associated with instructions
        /// haing a "31t" format identifier.</summary>
        /// <param name="opCodes"></param>
        /// <param name="index"></param>
        /// <param name="baseOffset">Offset within method code of the opcode that is referencing
        /// this additional content. This is meaningfull only for switch instructions in order to
        /// compute targets offset.</param>
        /// <returns>Depending on the kind of additional content this is either :
        /// 1°) an array of bytes to be used for array initialization
        /// 2°) a dictionnary of method related offsets to jump locations keyed by the switch
        /// matching value for packed switch management.</returns>
        private static object DecodeAdditionalContent(byte[] opCodes, uint index,
            DalvikInstruction[] instructions, uint baseOffset)
        {
            uint initialIndexValue = index;

            // Additional content must be aligned on a doubleword boundary. We use a little
            // trick to attempt to discover a nop opCode that may exist prior to the additional
            // content.
            if ((sizeof(ushort) <= index) && (0 == opCodes[index - 1]) && (0 == opCodes[index - 2])) {
                // Found a nop. At least consider this as a covered word.
                // TODO : Consider creating a Nop instruction instance.
                instructions[initialIndexValue] = null;
            }

            byte opCode = opCodes[index++];
            byte codeArg = opCodes[index++];
            // Initial value accounts for opCode and codeArg. Later augmented depending on the
            // kind of codeArg
            uint coveredWordsCount = 1;

            if (0 != opCode) { throw new REException(); }
            uint dataSize;
            int[] keys;
            Dictionary<int, uint> targetMethodOffsets;

            switch (codeArg) {
                case 0x01:
                    dataSize = GetNextDecodedUInt16(opCodes, ref index);
                    targetMethodOffsets = new Dictionary<int,uint>();
                    int firstKey = GetNextDecodedInt32(opCodes, ref index);
                    coveredWordsCount += (sizeof(ushort) + sizeof(int) + (sizeof(uint) * dataSize)) / sizeof(ushort);
                    for (int targetIndex = 0; targetIndex < dataSize; targetIndex++) {
                        // WARNING : The retrieved double word is a word count not a byte count.
                        uint targetMethodOffset = (uint)(baseOffset + (sizeof(ushort) * GetNextDecodedInt32(opCodes, ref index)));
                        targetMethodOffsets[targetIndex + firstKey] = targetMethodOffset;
                    }
                    return targetMethodOffsets;
                case 0x02:
                    dataSize = GetNextDecodedUInt16(opCodes, ref index);
                    keys = new int[dataSize];
                    targetMethodOffsets = new Dictionary<int,uint>();
                    coveredWordsCount += (sizeof(ushort) + ((sizeof(int) + sizeof(uint)) * dataSize)) / sizeof(ushort);
                    for (int targetIndex = 0; targetIndex < dataSize; targetIndex++) {
                        int key = GetNextDecodedInt32(opCodes, ref index);
                        // WARNING : The retrieved double word is a word count not a byte count.
                        uint targetMethodOffset = (uint)(baseOffset + (sizeof(ushort) * (GetNextDecodedUInt32(opCodes, ref index))));
                        targetMethodOffsets[key] = targetMethodOffset;
                    }
                    return targetMethodOffsets;
                case 0x03:
                    ushort elementSize = GetNextDecodedUInt16(opCodes, ref index);
                    uint elementsCount = GetNextDecodedUInt32(opCodes, ref index);
                    uint rawDataSize = elementsCount * elementSize;
                    coveredWordsCount += (sizeof(ushort) + sizeof(uint) + (rawDataSize + 1)) / 2;
                    byte[] initializationData = new byte[(int)rawDataSize];
                    Buffer.BlockCopy(opCodes, (int)index, initializationData, 0, initializationData.Length);
                    return initializationData;
                default:
                    throw new REException();
            }
        }
Beispiel #7
0
        /// <summary>Decode a single instruction into an <see cref="DalvikInstruction"/>
        /// having the given parent.</summary>
        /// <param name="opCodes">The method body being decoded.</param>
        /// <param name="baseAddress">The base address of the method body. Actually this
        /// is the offset within the dex file where the method body starts.</param>
        /// <param name="objectResolver"></param>
        /// <param name="coveredWord">An array of boolean that tell which of the opCode
        /// word are already disassembled.</param>
        /// <param name="index">The index of the first byte of the instruction being
        /// decoded.</param>
        /// <returns></returns>
        internal static DalvikInstruction Decode(byte[] opCodes, uint baseAddress,
            IResolver objectResolver, DalvikInstruction[] instructions, ref uint index)
        {
            if (null != instructions[index]) { throw new ApplicationException(); }
            uint initialIndexValue = index;
            uint thisAddress = (uint)(baseAddress + index);
            string address = string.Format("// {0:X8} : ", thisAddress);
            byte opCode = opCodes[index];
            byte codeArg = opCodes[index + 1];
            index += 2;
            StringBuilder extraArgBuilder;
            string assemblyCode;
            object additionalContent = null;

            // TODO : With big endian the opcode would be the second byte from the
            // current word.
            OpCodeDecoder decoder = _decoderPerOpCode[opCode];

            // Filter out unused instructions.
            if (null == decoder._opCodeName) { throw new REException(); }
            StringBuilder resultBuilder = new StringBuilder();
            List<object> printArgs = new List<object>();
            int argsCount;
            ushort resolverIndex;
            ushort extraWord;
            uint exclusion;
            long literalOrAddress = 0;
            ushort[] registers = null;
            DalvikInstruction result = null;

            try {
                switch (decoder._formatId)
                {
                    case "10t":
                        // GOTO : special case we compute the target address.
                        literalOrAddress = (int)((sizeof(ushort) * (sbyte)codeArg));
                        printArgs.Add(string.Format("{0:X8}", literalOrAddress));
                        break;
                    case "10x":
                        if (0 != codeArg) { throw new REException(); }
                        break;
                    case "11n":
                        registers = new ushort[] { (ushort)(codeArg & 0x0F) };
                        printArgs.Add(registers[0]);
                        literalOrAddress = ((codeArg & 0xF0) >> 4);
                        printArgs.Add(literalOrAddress);
                        break;
                    case "11x":
                        registers = new ushort[] { (ushort)codeArg };
                        printArgs.Add(registers[0]);
                        break;
                    case "12x":
                        registers = new ushort[] { (ushort)(codeArg & 0x0F), (ushort)((codeArg & 0xF0) >> 4) };
                        printArgs.Add(registers[0]);
                        printArgs.Add(registers[1]);
                        break;
                    case "20bc":
                        // TODO : Definition is unclear.
                        throw new NotSupportedException();
                    case "20t":
                        if (0 != codeArg) { throw new REException(); }
                        // GOTO/16 : special case we compute the target address.
                        literalOrAddress = (uint)((sizeof(ushort) * (short)GetNextDecodedUInt16(opCodes, ref index)));
                        printArgs.Add(string.Format("{0:X8}", literalOrAddress));
                        break;
                    case "21c":
                        resolverIndex = GetNextDecodedUInt16(opCodes, ref index);
                        registers = new ushort[] { (ushort)codeArg };
                        printArgs.Add(registers[0]);
                        // TODO : Must add an additional field in InstructionAstNode for this case.
                        printArgs.Add(decoder._argResolver(objectResolver, resolverIndex));
                        break;
                    case "21h":
                        registers = new ushort[] { (ushort)codeArg };
                        printArgs.Add(registers[0]);
                        literalOrAddress = GetNextDecodedInt16(opCodes, ref index) << (decoder._isWide ? 48 : 16);
                        printArgs.Add(literalOrAddress);
                        break;
                    case "21s":
                        registers = new ushort[] { (ushort)codeArg };
                        printArgs.Add(registers[0]);
                        literalOrAddress = GetNextDecodedInt16(opCodes, ref index);
                        printArgs.Add(literalOrAddress);
                        break;
                    case "21t":
                        registers = new ushort[] { (ushort)codeArg };
                        printArgs.Add(registers[0]);
                        literalOrAddress = GetNextDecodedInt16(opCodes, ref index);
                        printArgs.Add(literalOrAddress);
                        break;
                    case "22b":
                        goto case "23x";
                    case "22c":
                        resolverIndex = GetNextDecodedUInt16(opCodes, ref index);
                        registers = new ushort[] { (ushort)(codeArg & 0x0F), (ushort)((codeArg & 0xF0) >> 4) };
                        printArgs.Add(registers[0]);
                        printArgs.Add(registers[1]);
                        // TODO : Must add an additional field in InstructionAstNode for this case.
                        printArgs.Add(decoder._argResolver(objectResolver, resolverIndex));
                        break;
                    case "22s":
                    case "22t":
                        registers = new ushort[] { (ushort)(codeArg & 0x0F), (ushort)((codeArg & 0xF0) >> 4) };
                        printArgs.Add(registers[0]);
                        printArgs.Add(registers[1]);
                        literalOrAddress = GetNextDecodedInt16(opCodes, ref index);
                        printArgs.Add(literalOrAddress);
                        break;
                    case "22x":
                        registers = new ushort[] { (ushort)codeArg, GetNextDecodedUInt16(opCodes, ref index) };
                        printArgs.Add(registers[0]);
                        printArgs.Add(registers[1]);
                        break;
                    case "23x":
                        extraWord = GetNextDecodedUInt16(opCodes, ref index);
                        registers = new ushort[] { (ushort)codeArg, (ushort)(extraWord & 0x00FF),
                            (ushort)((extraWord & 0xFF00) >> 8) };
                        printArgs.Add(registers[0]);
                        printArgs.Add(registers[1]);
                        printArgs.Add(registers[2]);
                        break;
                    case "30t":
                        // GOTO/32 : special case we compute the target address.
                        literalOrAddress = ((sizeof(ushort) * (int)GetNextDecodedInt32(opCodes, ref index)));
                        printArgs.Add(string.Format("{0:X8}", literalOrAddress));
                        break;
                    case "31i":
                        registers = new ushort[] { (ushort)codeArg };
                        printArgs.Add(registers[0]);
                        literalOrAddress = GetNextDecodedInt32(opCodes, ref index);
                        printArgs.Add(literalOrAddress);
                        break;
                    case "31t":
                        registers = new ushort[] { (ushort)codeArg };
                        printArgs.Add(registers[0]);
                        // fill-array-data, packed-switch, sparse-switch
                        // Special case we compute the target address.
                        literalOrAddress = exclusion = (uint)(thisAddress + (sizeof(ushort) * (short)GetNextDecodedInt32(opCodes, ref index)));
                        additionalContent = DecodeAdditionalContent(opCodes,
                            (uint)(literalOrAddress - baseAddress), instructions,
                            initialIndexValue);
                        printArgs.Add(string.Format("{0:X8}", literalOrAddress));
                        break;
                    case "32x":
                        registers = new ushort[] {
                            GetNextDecodedUInt16(opCodes, ref index),
                            GetNextDecodedUInt16(opCodes, ref index)
                        };
                        printArgs.Add(registers[0]);
                        printArgs.Add(registers[1]);
                        break;
                    case "3rc":
                        literalOrAddress = resolverIndex = GetNextDecodedUInt16(opCodes, ref index);
                        extraWord = GetNextDecodedUInt16(opCodes, ref index);
                        extraArgBuilder = new StringBuilder();
                        extraArgBuilder.AppendFormat("{{v{0} .. v{1}}}", extraWord, (ushort)(extraWord + codeArg - 1));
                        printArgs.Add(extraArgBuilder.ToString());
                        printArgs.Add(decoder._argResolver(objectResolver, resolverIndex));
                        break;
                    case "35c":
                        literalOrAddress = resolverIndex = GetNextDecodedUInt16(opCodes, ref index);
                        argsCount = (codeArg & 0xF0) >> 4;
                        if (0 < argsCount) { registers = new ushort[argsCount]; }
                        extraWord = (0 == argsCount) ? (ushort)0 : GetNextDecodedUInt16(opCodes, ref index);
                        extraArgBuilder = new StringBuilder();
                        switch (argsCount)
                        {
                            case 0:
                                break;
                            case 5:
                                registers[4] = (ushort)((codeArg & 0x0F00) >> 8);
                                extraArgBuilder.Insert(0, " ,v" + registers[4].ToString());
                                goto case 4;
                            case 4:
                                registers[3] = (ushort)((extraWord & 0xF000) >> 12);
                                extraArgBuilder.Insert(0, " ,v" + registers[3].ToString());
                                goto case 3;
                            case 3:
                                registers[2] = (ushort)((extraWord & 0x0F00) >> 8);
                                extraArgBuilder.Insert(0, " ,v" + registers[2].ToString());
                                goto case 2;
                            case 2:
                                registers[1] = (ushort)((extraWord & 0x00F0) >> 4);
                                extraArgBuilder.Insert(0, " ,v" + registers[1].ToString());
                                goto case 1;
                            case 1:
                                registers[0] = (ushort)(extraWord & 0x000F);
                                extraArgBuilder.Insert(0, "v" + registers[0].ToString());
                                break;
                            default:
                                throw new REException();
                        }
                        extraArgBuilder.Insert(0, "{");
                        extraArgBuilder.Append("}");
                        printArgs.Add(extraArgBuilder.ToString());
                        printArgs.Add(decoder._argResolver(objectResolver, resolverIndex));
                        break;
                    case "51l":
                        registers = new ushort[] { (ushort)codeArg };
                        printArgs.Add(registers[0]);
                        literalOrAddress = GetNextDecodedInt64(opCodes, ref index);
                        printArgs.Add(literalOrAddress);
                        break;
                    default:
                        throw new ApplicationException();
                }
                printArgs.Insert(0, decoder._opCodeName);
                try { resultBuilder.AppendFormat(decoder._sourceCodeFormatString, printArgs.ToArray()); }
                catch { throw; }
                assemblyCode = address + resultBuilder.ToString();
                result = DalvikInstruction.Create(decoder._astNodeType, initialIndexValue,
                    (uint)(index - initialIndexValue), assemblyCode);
                result.LiteralOrAddress = literalOrAddress;
                result.Registers = registers;
                if (null != additionalContent) { result.SetAdditionalContent(additionalContent); }
                return result;
            }
            finally { instructions[initialIndexValue] = result; }
        }
Beispiel #8
0
        /// <summary>Split the current node in two separate nodes reltively to the given
        /// method relative offset. Existing block is left with its orginal predecessors,
        /// newly create block inherit the successors of the original block and both blocks
        /// (old and new) are linked together.</summary>
        /// <param name="methodOffset">The offset within the owning method of the instruction
        /// that must be migrated to the new node.</param>
        /// <returns>The newly created block. This block is already linked as a successor of
        /// the block that has been split.</returns>
        internal BlockNode Split(uint methodOffset)
        {
            int splitIndex;
#if DBGCFG
            if (DebugEnabled) {
                DalvikInstruction lastInstruction = _instructions[_instructions.Count - 1];
                Console.WriteLine("[{0}] ({1:X4}|{2:X4})/{3:X4}", NodeId,
                    _instructions[0].MethodRelativeOffset,
                    lastInstruction.MethodRelativeOffset + lastInstruction.InstructionSize - 1,
                    methodOffset);
            }
#endif
            // Find index of instruction with method relative offset matching the
            // given method offset.
            for (splitIndex = 0; splitIndex < _instructions.Count; splitIndex++) {
                if (_instructions[splitIndex].MethodRelativeOffset == methodOffset) { break; }
            }
            if (splitIndex >= _instructions.Count) { throw new ArgumentException(); }
            int movedRangeSize = _instructions.Count - splitIndex;
            DalvikInstruction[] movedRange = new DalvikInstruction[movedRangeSize];
            this._instructions.CopyTo(splitIndex, movedRange, 0, movedRange.Length);
            BlockNode result = new BlockNode(this.DebugEnabled);
            result._instructions = new List<DalvikInstruction>(movedRange);
            this._instructions.RemoveRange(splitIndex, movedRangeSize);
            // Also adjust block size for both blocks.
            uint sizeDelta = 0;
            foreach (DalvikInstruction movedIndstruction in result._instructions) {
                sizeDelta += movedIndstruction.InstructionSize;
            }
            this._size -= sizeDelta;
            result._size = sizeDelta;
            // We must also transfer existing successors from the splited block to the
            // newly created one.
            base.TransferSuccessors(result);
            // This link MUST occur after successors transfer.
            CfgNode.Link(this, result);
            return result;
        }