// ブロック単位のデコード を繰り返して複数のブロックを返す // // Cq = Code quality public static Block[] Decode(IMemoryManager memory, ulong address, ExecutionMode mode, bool highCq, bool singleBlock) { // デコード処理したブロックが入っている これを返す 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; // blkAddressを先頭とするBlock構造体を返す // すでにBlock構造体を構築しているならそれを、そうでないなら新しく作ってworkQueueにpushしたあと返す Block GetBlock(ulong blkAddress) { if (!visited.TryGetValue(blkAddress, out Block block)) { block = new Block(blkAddress); if ((singleBlock && 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)) { // 処理対象のブロックがとあるブロックの内側に含まれている // blocks[nBlkIndex].Address <= currBlock.Address < blocks[nBlkIndex].EndAddress // currBlock.EndAddress <= blocks[nBlkIndex].EndAddress は成り立っているのか? 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 を分割して間にcurrBlockを差し込む nBlock.Split(currBlock); blocks.Insert(nBlkIndex + 1, currBlock); continue; } // NOTE: nBlkIndex = 新しいブロックが入るべきblocksのインデックス // Exit=false つまり現在のブロックの後にブロックがある場合は、リミットアドレスを設定する if (!currBlock.Exit) { ulong limitAddress = ulong.MaxValue; if (nBlkIndex != blocks.Count) // 念の為処理対象のブロックがblocksの最後のブロックでないか確認 { Block nBlock = blocks[nBlkIndex]; int nextIndex = nBlkIndex + 1; if (nBlock.Address < currBlock.Address && nextIndex < blocks.Count) { // nBlock <- currBlock <- blocks[nextIndex] の場合は blocks[nextIndex] まで limitAddress = blocks[nextIndex].Address; } else if (nBlock.Address > currBlock.Address) { // 新しいブロック -> nBlock の場合は nBlockまで limitAddress = blocks[nBlkIndex].Address; } } FillBlock(memory, mode, currBlock, limitAddress); opsCount += currBlock.OpCodes.Count; if (currBlock.OpCodes.Count != 0) { // 分岐命令だった場合に子ブロックを設定する // "Branch "は、分岐命令が指すブロック、"Next"は、分岐しなかった場合に実行される次のアドレスのブロックです // 無条件分岐(関数コールであるBL/BLRを除く)や実行ファイルの終了の場合、Nextはnullです。 OpCode lastOp = currBlock.GetLastOp(); bool isCall = IsCall(lastOp); if (lastOp is IOpCodeBImm op && !isCall) { currBlock.Branch = GetBlock((ulong)op.Immediate); } if (!IsUnconditionalBranch(lastOp) || isCall) { 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 (!singleBlock) { return(TailCallRemover.RunPass(address, blocks)); } else { return(blocks.ToArray()); } }
public static Block[] DecodeFunction(IMemoryManager memory, ulong address, ExecutionMode mode, bool highCq) { List <Block> blocks = new List <Block>(); Queue <Block> workQueue = new Queue <Block>(); Dictionary <ulong, Block> visited = new Dictionary <ulong, Block>(); int opsCount = 0; int instructionLimit = highCq ? MaxInstsPerFunction : MaxInstsPerFunctionLowCq; Block GetBlock(ulong blkAddress) { if (!visited.TryGetValue(blkAddress, out Block block)) { if (opsCount > instructionLimit || !memory.IsMapped(blkAddress)) { return(null); } block = new Block(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."); } 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(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 (!IsUnconditionalBranch(lastOp) || isCall) { 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); } } TailCallRemover.RunPass(address, blocks); return(blocks.ToArray()); }
private void LoadMod0Symbols(IMemoryManager memory, long textOffset) { long mod0Offset = textOffset + memory.ReadUInt32(textOffset + 4); if (mod0Offset < textOffset || !memory.IsMapped(mod0Offset) || (mod0Offset & 3) != 0) { return; } Dictionary <ElfDynamicTag, long> dynamic = new Dictionary <ElfDynamicTag, long>(); int mod0Magic = memory.ReadInt32(mod0Offset + 0x0); if (mod0Magic != Mod0) { return; } long dynamicOffset = memory.ReadInt32(mod0Offset + 0x4) + mod0Offset; long bssStartOffset = memory.ReadInt32(mod0Offset + 0x8) + mod0Offset; long bssEndOffset = memory.ReadInt32(mod0Offset + 0xc) + mod0Offset; long ehHdrStartOffset = memory.ReadInt32(mod0Offset + 0x10) + mod0Offset; long ehHdrEndOffset = memory.ReadInt32(mod0Offset + 0x14) + mod0Offset; long modObjOffset = memory.ReadInt32(mod0Offset + 0x18) + mod0Offset; // TODO: Elf32. while (true) { long tagVal = memory.ReadInt64(dynamicOffset + 0); long value = memory.ReadInt64(dynamicOffset + 8); dynamicOffset += 0x10; ElfDynamicTag tag = (ElfDynamicTag)tagVal; if (tag == ElfDynamicTag.DT_NULL) { break; } dynamic[tag] = value; } if (!dynamic.TryGetValue(ElfDynamicTag.DT_STRTAB, out long strTab) || !dynamic.TryGetValue(ElfDynamicTag.DT_SYMTAB, out long symTab) || !dynamic.TryGetValue(ElfDynamicTag.DT_SYMENT, out long symEntSize)) { return; } long strTblAddr = textOffset + strTab; long symTblAddr = textOffset + symTab; List <ElfSymbol> symbols = new List <ElfSymbol>(); while ((ulong)symTblAddr < (ulong)strTblAddr) { ElfSymbol sym = GetSymbol(memory, symTblAddr, strTblAddr); symbols.Add(sym); symTblAddr += symEntSize; } lock (_images) { _images.Add(new Image(textOffset, symbols.OrderBy(x => x.Value).ToArray())); } }