public void RemoveCaller(DecodedFunction caller) { if (_callers.Remove(caller) && _callers.Count == 0) { Type = FunctionType.Unused; } }
public static DecodedProgram Decode(ShaderConfig config, ulong startAddress) { Queue <DecodedFunction> functionsQueue = new Queue <DecodedFunction>(); Dictionary <ulong, DecodedFunction> functionsVisited = new Dictionary <ulong, DecodedFunction>(); DecodedFunction EnqueueFunction(ulong address) { if (!functionsVisited.TryGetValue(address, out DecodedFunction function)) { functionsVisited.Add(address, function = new DecodedFunction(address)); functionsQueue.Enqueue(function); } return(function); } DecodedFunction mainFunction = EnqueueFunction(0); while (functionsQueue.TryDequeue(out DecodedFunction currentFunction)) { List <Block> blocks = new List <Block>(); Queue <Block> workQueue = new Queue <Block>(); Dictionary <ulong, Block> visited = new Dictionary <ulong, Block>(); Block GetBlock(ulong blkAddress) { if (!visited.TryGetValue(blkAddress, out Block block)) { block = new Block(blkAddress); workQueue.Enqueue(block); visited.Add(blkAddress, block); } return(block); } GetBlock(currentFunction.Address); bool hasNewTarget; do { 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."); } nBlock.Split(currBlock); blocks.Insert(nBlkIndex + 1, currBlock); continue; } // 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; } } FillBlock(config, currBlock, limitAddress, startAddress); if (currBlock.OpCodes.Count != 0) { // We should have blocks for all possible branch targets, // including those from SSY/PBK instructions. foreach (PushOpInfo pushOp in currBlock.PushOpCodes) { GetBlock(pushOp.Op.GetAbsoluteAddress()); } // 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 // or end of program, Next is null. InstOp lastOp = currBlock.GetLastOp(); if (lastOp.Name == InstName.Cal) { EnqueueFunction(lastOp.GetAbsoluteAddress()).AddCaller(currentFunction); } else if (lastOp.Name == InstName.Bra) { Block succBlock = GetBlock(lastOp.GetAbsoluteAddress()); currBlock.Successors.Add(succBlock); succBlock.Predecessors.Add(currBlock); } if (!IsUnconditionalBranch(ref lastOp)) { Block succBlock = GetBlock(currBlock.EndAddress); currBlock.Successors.Insert(0, succBlock); succBlock.Predecessors.Add(currBlock); } } // 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); } } // Propagate SSY/PBK addresses into their uses (SYNC/BRK). foreach (Block block in blocks.Where(x => x.PushOpCodes.Count != 0)) { for (int pushOpIndex = 0; pushOpIndex < block.PushOpCodes.Count; pushOpIndex++) { PropagatePushOp(visited, block, pushOpIndex); } } // Try to find targets for BRX (indirect branch) instructions. hasNewTarget = FindBrxTargets(config, blocks, GetBlock); // If we discovered new branch targets from the BRX instruction, // we need another round of decoding to decode the new blocks. // Additionally, we may have more SSY/PBK targets to propagate, // and new BRX instructions. }while (hasNewTarget); currentFunction.SetBlocks(blocks.ToArray()); } return(new DecodedProgram(mainFunction, functionsVisited)); }
public void AddCaller(DecodedFunction caller) { _callers.Add(caller); }