public static Block[] Decode(IMemoryManager memory, ulong address, ExecutionMode mode, bool highCq, DecoderMode dMode) { List <Block> blocks = new List <Block>(); Queue <Block> workQueue = new Queue <Block>(); Dictionary <ulong, Block> visited = new Dictionary <ulong, Block>(); Debug.Assert(MaxInstsPerFunctionLowCq <= MaxInstsPerFunction); int opsCount = 0; int instructionLimit = highCq ? MaxInstsPerFunction : MaxInstsPerFunctionLowCq; Block GetBlock(ulong blkAddress) { if (!visited.TryGetValue(blkAddress, out Block block)) { block = new Block(blkAddress); if ((dMode != DecoderMode.MultipleBlocks && visited.Count >= 1) || opsCount > instructionLimit || !memory.IsMapped(blkAddress)) { block.Exit = true; block.EndAddress = blkAddress; } workQueue.Enqueue(block); visited.Add(blkAddress, block); } return(block); } GetBlock(address); while (workQueue.TryDequeue(out Block currBlock)) { // Check if the current block is inside another block. if (BinarySearch(blocks, currBlock.Address, out int nBlkIndex)) { Block nBlock = blocks[nBlkIndex]; if (nBlock.Address == currBlock.Address) { throw new InvalidOperationException("Found duplicate block address on the list."); } currBlock.Exit = false; nBlock.Split(currBlock); blocks.Insert(nBlkIndex + 1, currBlock); continue; } if (!currBlock.Exit) { // If we have a block after the current one, set the limit address. ulong limitAddress = ulong.MaxValue; if (nBlkIndex != blocks.Count) { Block nBlock = blocks[nBlkIndex]; int nextIndex = nBlkIndex + 1; if (nBlock.Address < currBlock.Address && nextIndex < blocks.Count) { limitAddress = blocks[nextIndex].Address; } else if (nBlock.Address > currBlock.Address) { limitAddress = blocks[nBlkIndex].Address; } } if (dMode == DecoderMode.SingleInstruction) { // Only read at most one instruction limitAddress = currBlock.Address + 1; } FillBlock(memory, mode, currBlock, limitAddress); opsCount += currBlock.OpCodes.Count; if (currBlock.OpCodes.Count != 0) { // Set child blocks. "Branch" is the block the branch instruction // points to (when taken), "Next" is the block at the next address, // executed when the branch is not taken. For Unconditional Branches // (except BL/BLR that are sub calls) or end of executable, Next is null. OpCode lastOp = currBlock.GetLastOp(); bool isCall = IsCall(lastOp); if (lastOp is IOpCodeBImm op && !isCall) { currBlock.Branch = GetBlock((ulong)op.Immediate); } if (isCall || !(IsUnconditionalBranch(lastOp) || IsTrap(lastOp))) { currBlock.Next = GetBlock(currBlock.EndAddress); } } } // Insert the new block on the list (sorted by address). if (blocks.Count != 0) { Block nBlock = blocks[nBlkIndex]; blocks.Insert(nBlkIndex + (nBlock.Address < currBlock.Address ? 1 : 0), currBlock); } else { blocks.Add(currBlock); } } if (blocks.Count == 1 && blocks[0].OpCodes.Count == 0) { Debug.Assert(blocks[0].Exit); Debug.Assert(blocks[0].Address == blocks[0].EndAddress); throw new InvalidOperationException($"Decoded a single empty exit block. Entry point = 0x{address:X}."); } if (dMode == DecoderMode.MultipleBlocks) { return(TailCallRemover.RunPass(address, blocks)); } else { return(blocks.ToArray()); } }
public static extern ZyanStatus EnableMode(ref Decoder decoder, DecoderMode decoderMode, [MarshalAs(UnmanagedType.I1)] bool enabled);