Beispiel #1
0
        /// <inheritdoc />
        protected override IInstructionTraversalResult <TInstruction> CollectInstructions(long entrypoint, IEnumerable <long> knownBlockHeaders)
        {
            var result = new InstructionTraversalResult <TInstruction>(Architecture);

            result.BlockHeaders.Add(entrypoint);
            result.BlockHeaders.UnionWith(knownBlockHeaders);

            // Most instructions will have <= 2 successors.
            // - Immediate fallthrough successor or unconditional branch target.
            // - A single conditional branch target.

            // The only exception will be switch-like instructions.
            // Therefore we start off by renting a buffer of at least two elements.
            var successorsBufferPool = ArrayPool <SuccessorInfo> .Shared;
            var successorsBuffer     = successorsBufferPool.Rent(2);

            try
            {
                var visited = new HashSet <long>();

                // Start at the entrypoint and block headers.
                var agenda = new Stack <long>();
                foreach (var header in result.BlockHeaders)
                {
                    agenda.Push(header);
                }

                while (agenda.Count > 0)
                {
                    // Get the current offset to process.
                    long currentOffset = agenda.Pop();

                    if (visited.Add(currentOffset))
                    {
                        // Get the instruction at the provided offset, and figure out how many successors it has.
                        var instruction    = Instructions.GetInstructionAtOffset(currentOffset);
                        int successorCount = GetSuccessors(successorsBufferPool, ref successorsBuffer, instruction);

                        // Store collected data.
                        result.AddInstruction(instruction);

                        // Figure out next offsets to process.
                        bool nextInstructionIsSuccessor = false;
                        int  realSuccessorCount         = 0;
                        for (int i = 0; i < successorCount; i++)
                        {
                            var  successor          = successorsBuffer[i];
                            long destinationAddress = successor.DestinationAddress;

                            if (!successor.IsRealEdge)
                            {
                                // Successor is implied by the instruction but does not necessarily
                                // transfer control to it directly. Only register the block header.
                                result.BlockHeaders.Add(destinationAddress);
                                agenda.Push(destinationAddress);
                                continue;
                            }

                            realSuccessorCount++;
                            if (destinationAddress == currentOffset + Architecture.GetSize(instruction))
                            {
                                // Successor is just the next instruction.
                                nextInstructionIsSuccessor = true;
                            }
                            else
                            {
                                // Successor is a jump to another address. This is a new basic block header!
                                result.BlockHeaders.Add(destinationAddress);
                            }

                            result.RegisterSuccessor(instruction, successor);
                            agenda.Push(destinationAddress);
                        }

                        // If we have multiple successors (e.g. as with an if-else construct), or the next instruction is
                        // not a successor (e.g. with a return address), the next instruction is another block header.
                        if (!nextInstructionIsSuccessor ||
                            realSuccessorCount > 1 ||
                            (Architecture.GetFlowControl(instruction) & InstructionFlowControl.CanBranch) != 0)
                        {
                            result.BlockHeaders.Add(currentOffset + Architecture.GetSize(instruction));
                        }
                    }
                }
            }
            finally
            {
                successorsBufferPool.Return(successorsBuffer);
            }

            return(result);
        }