/// <summary> /// Adds all basic blocks, starting from the procedure's entry point, /// to the procedure's list of owning blocks. Note that multiple /// procedures may share one or more basic blocks. /// </summary> /// <param name="proc"></param> protected virtual bool AddBasicBlocksToProcedure(Procedure proc) { // TODO: introduce ProcedureAlias, so that we don't need to // analyze the same procedure twice. BasicBlock block = BasicBlocks.Find(proc.EntryPoint); if (block == null) { return(false); } Stack <BasicBlock> queue = new Stack <BasicBlock>(); queue.Push(block); while (queue.Count > 0) { BasicBlock parent = queue.Pop(); if (!proc.BasicBlocks.Contains(parent)) { proc.AddBasicBlock(parent); foreach (BasicBlock child in BasicBlocks.ControlFlowGraph.GetSuccessors(parent)) { queue.Push(child); } } } return(true); }
/// <summary> /// Generates control flow graph from existing xrefs. /// </summary> protected virtual void GenerateControlFlowGraph() { foreach (XRef xref in CrossReferences) { // Skip xrefs with unknown source (e.g. user-specified entry // point) or target (e.g. dynamic call or jump). if (xref.Source == Address.Invalid || xref.Target == Address.Invalid) { continue; } if (xref.Type == XRefType.NearCall || xref.Type == XRefType.FarCall) { continue; } // Find the basic blocks that owns the source location // and target location. BasicBlock sourceBlock = BasicBlocks.Find(xref.Source); BasicBlock targetBlock = BasicBlocks.Find(xref.Target); #if true if (sourceBlock == null || targetBlock == null) { System.Diagnostics.Debug.WriteLine("Cannot find block."); continue; } #else System.Diagnostics.Debug.Assert(sourceBlock != null); System.Diagnostics.Debug.Assert(targetBlock != null); #endif // Create a directed edge from the source basic block to // the target basic block. BasicBlocks.ControlFlowGraph.AddEdge( sourceBlock, targetBlock, xref); } }
/// <summary> /// Gets the image associated with the segment specified by its id. /// </summary> /// <param name="segmentId">Id of the segment to resolve.</param> /// <returns>The image associated with the given segment, or null if /// the segment id is invalid.</returns> //protected abstract ImageChunk ResolveSegment(int segmentId); #region Flow Analysis Methods /// <summary> /// Analyzes a contiguous sequence of instructions that form a basic /// block. A basic block terminates as soon as any of the following /// conditions is true: /// - An analysis error occurs /// - An block terminating instructions: RET, RETF, IRET, HLT. /// - A b/c/j instruction: Jcc, JMP, JMPF, LOOPcc. /// </summary> /// <param name="start">Address to begin analysis.</param> /// <param name="xrefs">Collection to add xrefs to.</param> /// <returns> /// A new BasicBlock if one was created during the analysis. /// If no new BasicBlocks are created, or if an existing block was /// split into two, returns null. /// </returns> // TODO: should be roll-back the entire basic block if we // encounters an error on our way? maybe not. protected virtual BasicBlock AnalyzeBasicBlock(XRef start, ICollection <XRef> xrefs) { Address ip = start.Target; // instruction pointer if (!image.IsAddressValid(ip)) { AddError(ip, ErrorCode.OutOfImage, "XRef target is outside of the image (referred from {0})", start.Source); return(null); } // Check if the entry address is already analyzed. ByteAttribute b = image[ip]; if (b.Type != ByteType.Unknown) { // Fail if we ran into data or padding while expecting code. if (b.Type != ByteType.Code) { AddError(ip, ErrorCode.RanIntoData, "XRef target is in the middle of data (referred from {0})", start.Source); return(null); } // Now the byte was previously analyzed as code. We must have // already created a basic block that contains this byte. BasicBlock block = BasicBlocks.Find(ip); System.Diagnostics.Debug.Assert(block != null); // If the existing block starts at this address, we're done. if (block.Location == ip) { return(null); } // TBD: recover the following in some way... #if false if (image[b.BasicBlock.StartAddress].Address.Segment != pos.Segment) { AddError(pos, ErrorCategory.Error, "Ran into the middle of a block [{0},{1}) from another segment " + "when processing block {2} referred from {3}", b.BasicBlock.StartAddress, b.BasicBlock.EndAddress, start.Target, start.Source); return(null); } #endif // Now split the existing basic block into two. This requires // that the cut-off point is at instruction boundary. if (!b.IsLeadByte) { AddError(ip, ErrorCode.RanIntoCode, "XRef target is in the middle of an instruction (referred from {0})", start.Source); return(null); } BasicBlock[] subBlocks = BasicBlocks.SplitBasicBlock(block, ip, image); // Create a xref from the previous block to this block. XRef xref = CreateFallThroughXRef(GetLastInstructionInBasicBlock(subBlocks[0]), ip); xrefs.Add(xref); return(null); } // TODO: Move the above into a separate procedure. // Analyze each instruction in sequence until we encounter // analyzed code, flow instruction, or an error condition. BasicBlockType blockType = BasicBlockType.Unknown; while (true) { // Decode an instruction at this location. Address instructionStart = ip; Instruction insn = CreateInstruction(ip, start); if (insn == null) { AddError(ip, ErrorCode.BrokenBasicBlock, "Basic block ended prematurally because of invalid instruction."); blockType = BasicBlockType.Broken; break; } Address instructionEnd = ip + insn.EncodedLength; // Advance the instruction pointer. ip = instructionEnd; // Determine whether this instruction affects control flow. XRefType flowType = GetFlowInstructionType(insn.Operation); if (flowType != XRefType.None) { // Creates an active cross reference if necessary. if (NeedsActiveXRef(flowType)) { XRef xref = CreateFlowXRef(flowType, instructionStart, insn); if (xref != null) { xrefs.Add(xref); } } // Creates a fall-through cross reference if necessary. if (CanFallThrough(flowType)) { XRef xref = CreateFallThroughXRef(instructionStart, instructionEnd); xrefs.Add(xref); } // Terminate the block. blockType = GetBasicBlockType(flowType); break; } // If the new location is already analyzed as code, create a // control-flow edge from the previous block to the existing // block, and we are done. if (!image.IsAddressValid(ip)) { blockType = BasicBlockType.Broken; break; } if (image[ip].Type == ByteType.Code) { System.Diagnostics.Debug.Assert(image[ip].IsLeadByte); XRef xref = CreateFallThroughXRef(instructionStart, instructionEnd); xrefs.Add(xref); blockType = BasicBlockType.FallThrough; break; } } // Create a basic block unless we failed on the first instruction. if (ip.Offset > start.Target.Offset) { BasicBlock block = new BasicBlock(start.Target, ip, blockType, image); BasicBlocks.Add(block); } return(null); }