/// <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); }