Class JitControlFlowModel

java.lang.Object
ghidra.pcode.emu.jit.analysis.JitControlFlowModel

public class JitControlFlowModel extends Object
The control flow analysis for JIT-accelerated emulation.

This implements the Control Flow Analysis phase of the JitCompiler. Some rudimentary analysis is performed during passage decoding — note the JitControlFlowModel.BlockSplitter is exported for use in DecoderForOneStride. This is necessary to evaluate whether an instruction (especially an inject-instrumented instruction) has fall-through. Without that information, the decoder cannot know whether it has reached the end of its stride. Note that the decoder records all the branches it encounters and includes them as metadata in the passage. Because branches need to record the source and target p-code op, the decoder is well suited. Additionally, it has to compute these anyway, and we'd rather avoid duplicative work by this analyzer.

The decoded passage contains a good deal of information, but the primary inputs at this point are the ordered list of p-code ops and the branches. This model's primary responsibility is to break the passage down into basic blocks at the p-code level. Even though the p-code ops have all been concatenated together when constructing the passage, we know, by definition, that each stride will end with an unconditional branch (or else a synthesized JitPassage.ExitPcodeOp. Note also that JitPassage.getBranches() only includes the non-fall-through branches, because these are all that are recorded by the decoder. Thus, it is also this model's responsibility to create the fall-through branches. These will occur to represent the "false" case of any conditional branches, and to represent "unconditional fall through."

The algorithm for this is fairly straightforward and has been implemented primarily in JitControlFlowModel.BlockSplitter. Most everything else in this class is data management and the types representing the model.

NOTE: It is technically possible for a userop to branch, but this analysis does not consider that. Instead, the emulator will decide how to handle those. Conventionally, I'd rather a userop never perform control flow. Instead, I'd rather see things like pc = my_control_op(); goto [pc];.