[文档]classCrossJumpReverter(StructuringOptimizationPass):""" This is an implementation to revert the compiler optimization Cross Jumping, and ISC optimization discussed in the USENIX 2024 paper SAILR. This optimization is somewhat aggressive and as such should be run last in your decompiler deoptimization chain. This deoptimization will take any goto it finds and attempt to duplicate its target block if its target only has one outgoing edge. There are some heuristics in place to prevent duplication everywhere. First, this deoptimization will only run a max of max_opt_iters times. Second, it will not duplicate a block with too many calls. """STAGE=OptimizationPassStage.DURING_REGION_IDENTIFICATIONNAME="Duplicate linear blocks with gotos"DESCRIPTION=inspect.cleandoc(__doc__).strip()
[文档]def__init__(self,func,# internal parameters that should be used by Clinicnode_idx_start:int=0,# settingsmax_opt_iters:int=3,max_call_duplications:int=1,**kwargs,):super().__init__(func,max_opt_iters=max_opt_iters,strictly_less_gotos=True,**kwargs)self.node_idx=count(start=node_idx_start)self._max_call_dup=max_call_duplicationsself.analyze()
def_check(self):returnTrue,Nonedef_analyze(self,cache=None):to_update=defaultdict(list)fornodeinself.out_graph.nodes:gotos=self._goto_manager.gotos_in_block(node)# TODO: support if-stmtsifnotgotosorlen(gotos)>=2:continue# only blocks that have a single outgoing goto are candidates# for duplicatesgoto=next(iter(gotos))forgoto_targetinself.out_graph.successors(node):ifgoto_target.addr==goto.dst_addr:breakelse:goto_target=None# the target goto block should only have a single outgoing edge# this prevents duplication of conditionsifgoto_targetisNoneorself.out_graph.out_degree(goto_target)!=1:continue# minimize the number of calls in the target block that can be duplicated# to prevent duplication of big blockscounter=AILBlockCallCounter()counter.walk(goto_target)ifcounter.calls>self._max_call_dup:continue# [goto_target] = (pred1, pred2, ...)to_update[goto_target].append(node)ifnotto_update:returnFalseupdates=Falsesorted_targets=sorted(to_update.items(),key=lambdax:x[0].addr)forgoto_target,pred_to_updateinsorted_targets:pred_to_update=sorted(pred_to_update,key=lambdax:x.addr)# do some sanity checksupdate_edges=[(pred,goto_target)forpredinpred_to_update]ifnotall(self.out_graph.has_edge(*edge)foredgeinupdate_edges):continuecurrent_preds=list(self.out_graph.predecessors(goto_target))delete_original=len(current_preds)==len(pred_to_update)# update the edgesforsrc,goto_blkinupdate_edges:cp=copy.deepcopy(goto_blk)cp.idx=next(self.node_idx)self.out_graph.remove_edge(src,goto_blk)self.out_graph.add_edge(src,cp)updates=Trueifdelete_original:self.out_graph.remove_node(goto_target)returnupdates