예제 #1
0
        /// <summary>
        ///     Performs a pass over the method body instructions and identifies the basic blocks.
        ///     This pass essentially generates the nodes of the graph.
        /// </summary>
        private void ConstructBasicBlocks()
        {
            int basicBlockId      = 0;
            var currentBasicBlock = new CilBasicBlock(basicBlockId);

            foreach (var instruction in instructions)
            {
                currentBasicBlock.Instructions.Add(instruction);
                // Update the dictionary for the branch target instructions.
                if (branchTargetInstructionDictionary.ContainsKey(instruction))
                {
                    branchTargetInstructionDictionary[instruction] = currentBasicBlock;
                }
                if (instruction.Next == null ||
                    branchTargetInstructionDictionary.ContainsKey(instruction.Next) || // Next BB starts at branch target.
                    instruction.IsControlFlowInstruction()) // BB ends at branch.
                {
                    // When we reach the end of the Basic block
                    // we add it to the result list.
                    BasicBlocks.Add(currentBasicBlock);
                    currentBasicBlock = new CilBasicBlock(++basicBlockId);
                }
            }
        }
예제 #2
0
        /// <summary>
        /// Gets the image associated with the segment specified by its id.
        /// </summary>
        /// <param name="segmentId">Id of the segment to resolve.</param>
        /// <returns>The image associated with the given segment, or null if
        /// the segment id is invalid.</returns>
        //protected abstract ImageChunk ResolveSegment(int segmentId);

        #region Flow Analysis Methods

        /// <summary>
        /// Analyzes a contiguous sequence of instructions that form a basic
        /// block. A basic block terminates as soon as any of the following
        /// conditions is true:
        /// - An analysis error occurs
        /// - An block terminating instructions: RET, RETF, IRET, HLT.
        /// - A b/c/j instruction: Jcc, JMP, JMPF, LOOPcc.
        /// </summary>
        /// <param name="start">Address to begin analysis.</param>
        /// <param name="xrefs">Collection to add xrefs to.</param>
        /// <returns>
        /// A new BasicBlock if one was created during the analysis.
        /// If no new BasicBlocks are created, or if an existing block was
        /// split into two, returns null.
        /// </returns>
        // TODO: should be roll-back the entire basic block if we
        // encounters an error on our way? maybe not.
        protected virtual BasicBlock AnalyzeBasicBlock(XRef start, ICollection <XRef> xrefs)
        {
            Address ip = start.Target; // instruction pointer

            if (!image.IsAddressValid(ip))
            {
                AddError(ip, ErrorCode.OutOfImage,
                         "XRef target is outside of the image (referred from {0})",
                         start.Source);
                return(null);
            }

            // Check if the entry address is already analyzed.
            ByteAttribute b = image[ip];

            if (b.Type != ByteType.Unknown)
            {
                // Fail if we ran into data or padding while expecting code.
                if (b.Type != ByteType.Code)
                {
                    AddError(ip, ErrorCode.RanIntoData,
                             "XRef target is in the middle of data (referred from {0})",
                             start.Source);
                    return(null);
                }

                // Now the byte was previously analyzed as code. We must have
                // already created a basic block that contains this byte.
                BasicBlock block = BasicBlocks.Find(ip);
                System.Diagnostics.Debug.Assert(block != null);

                // If the existing block starts at this address, we're done.
                if (block.Location == ip)
                {
                    return(null);
                }

                // TBD: recover the following in some way...
#if false
                if (image[b.BasicBlock.StartAddress].Address.Segment != pos.Segment)
                {
                    AddError(pos, ErrorCategory.Error,
                             "Ran into the middle of a block [{0},{1}) from another segment " +
                             "when processing block {2} referred from {3}",
                             b.BasicBlock.StartAddress, b.BasicBlock.EndAddress,
                             start.Target, start.Source);
                    return(null);
                }
#endif

                // Now split the existing basic block into two. This requires
                // that the cut-off point is at instruction boundary.
                if (!b.IsLeadByte)
                {
                    AddError(ip, ErrorCode.RanIntoCode,
                             "XRef target is in the middle of an instruction (referred from {0})",
                             start.Source);
                    return(null);
                }
                BasicBlock[] subBlocks = BasicBlocks.SplitBasicBlock(block, ip, image);

                // Create a xref from the previous block to this block.
                XRef xref = CreateFallThroughXRef(GetLastInstructionInBasicBlock(subBlocks[0]), ip);
                xrefs.Add(xref);

                return(null);
            }
            // TODO: Move the above into a separate procedure.

            // Analyze each instruction in sequence until we encounter
            // analyzed code, flow instruction, or an error condition.
            BasicBlockType blockType = BasicBlockType.Unknown;
            while (true)
            {
                // Decode an instruction at this location.
                Address     instructionStart = ip;
                Instruction insn             = CreateInstruction(ip, start);
                if (insn == null)
                {
                    AddError(ip, ErrorCode.BrokenBasicBlock,
                             "Basic block ended prematurally because of invalid instruction.");
                    blockType = BasicBlockType.Broken;
                    break;
                }
                Address instructionEnd = ip + insn.EncodedLength;

                // Advance the instruction pointer.
                ip = instructionEnd;

                // Determine whether this instruction affects control flow.
                XRefType flowType = GetFlowInstructionType(insn.Operation);

                if (flowType != XRefType.None)
                {
                    // Creates an active cross reference if necessary.
                    if (NeedsActiveXRef(flowType))
                    {
                        XRef xref = CreateFlowXRef(flowType, instructionStart, insn);
                        if (xref != null)
                        {
                            xrefs.Add(xref);
                        }
                    }

                    // Creates a fall-through cross reference if necessary.
                    if (CanFallThrough(flowType))
                    {
                        XRef xref = CreateFallThroughXRef(instructionStart, instructionEnd);
                        xrefs.Add(xref);
                    }

                    // Terminate the block.
                    blockType = GetBasicBlockType(flowType);
                    break;
                }

                // If the new location is already analyzed as code, create a
                // control-flow edge from the previous block to the existing
                // block, and we are done.
                if (!image.IsAddressValid(ip))
                {
                    blockType = BasicBlockType.Broken;
                    break;
                }
                if (image[ip].Type == ByteType.Code)
                {
                    System.Diagnostics.Debug.Assert(image[ip].IsLeadByte);

                    XRef xref = CreateFallThroughXRef(instructionStart, instructionEnd);
                    xrefs.Add(xref);
                    blockType = BasicBlockType.FallThrough;
                    break;
                }
            }

            // Create a basic block unless we failed on the first instruction.
            if (ip.Offset > start.Target.Offset)
            {
                BasicBlock block = new BasicBlock(start.Target, ip, blockType, image);
                BasicBlocks.Add(block);
            }
            return(null);
        }