Ghidra Decompiler Analysis Engine
Public Member Functions | List of all members
ConditionalExecution Class Reference

A class for simplifying a series of conditionally executed statements. More...

#include <condexe.hh>

Public Member Functions

 ConditionalExecution (Funcdata *f)
 Constructor. More...
 
bool trial (BlockBasic *ib)
 Test for a modifiable configuration around the given block. More...
 
void execute (void)
 Eliminate the unnecessary path join at iblock. More...
 

Detailed Description

A class for simplifying a series of conditionally executed statements.

This class tries to perform transformations like the following:

if (a) { if (a) {
BODY1
} ==> BODY1
if (a) { BODY2
BODY2
} }

Other similar configurations where two CBRANCHs are based on the same condition are handled. The main variation, referred to as a directsplit in the code looks like:

if (a) { if (a && new_boolean()) {
a = new_boolean();
} ==> BODY1
if (a) {
BODY1
} }

The value of 'a' doesn't need to be reevaluated if it is false.

In the first scenario, there is a block where two flows come together but don't need to, as the evaluation of the boolean is redundant. This block is the iblock. The original evaluation of the boolean occurs in initblock. There are two paths from here to iblock, called the prea path and preb path, either of which may contain additional 1in/1out blocks. There are also two paths out of iblock, posta, and postb. The ConditionalExecution class determines if the CBRANCH in iblock is redundant by determining if the boolean value is either the same as, or the complement of, the boolean value in initblock. If the CBRANCH is redundant, iblock is removed, linking prea to posta and preb to postb (or vice versa depending on whether the booleans are complements of each other). If iblock is to be removed, modifications to data-flow made by iblock must be preserved. For MULTIEQUALs in iblock, reads are examined to see if they came from the posta path, or the postb path, then the are replaced by the MULTIEQUAL slot corresponding to the matching prea or preb branch. If posta and postb merge at an exitblock, the MULTIEQUAL must be pushed into the exitblock and reads which can't be attributed to the posta or postb path are replaced by the exitblock MULTIEQUAL.

In theory, other operations performed in iblock could be pushed into exitblock if they are not read in the posta or postb paths, but currently non MULTIEQUAL operations in iblock terminate the action.

In the second scenario, the boolean evaluated in initblock remains unmodified along only one of the two paths out, prea or reb. The boolean in iblock (modulo complementing) will evaluate in the same way. We define posta as the path out of iblock that will be followed by this unmodified path. The transform that needs to be made is to have the unmodified path out of initblock flow immediately into the posta path without having to reevalute the condition in iblock. iblock is not removed because flow from the "modified" path may also flow into posta, depending on how the boolean was modified. Adjustments to data-flow are similar to the first scenario but slightly more complicated. The first block along the posta path is referred to as the posta_block, this block will have a new block flowing into it.

Constructor & Destructor Documentation

◆ ConditionalExecution()

ConditionalExecution::ConditionalExecution ( Funcdata f)

Constructor.

Set up for testing ConditionalExecution on multiple iblocks

Parameters
fis the function to do testing on

Member Function Documentation

◆ execute()

void ConditionalExecution::execute ( void  )

Eliminate the unnecessary path join at iblock.

We assume the last call to verify() returned true.

◆ trial()

bool ConditionalExecution::trial ( BlockBasic ib)

Test for a modifiable configuration around the given block.

The given block is tested as a possible iblock. If this configuration works and is not a directsplit, true is returned. If the configuration works as a directsplit, then recursively check that its posta_block works as an iblock. If it does work, keep this iblock, otherwise revert to the directsplit configuration. In either case return true. Processing the directsplit first may prevent posta_block from being an iblock.

Parameters
ibis the trial iblock
Returns
true if (some) configuration is recognized and can be modified

The documentation for this class was generated from the following files: