def eval(self, ctx): cond = z3.simplify( z3.And(z3.Not(z3.Or(*ctx.forward_conds)), ctx.tmp_forward_cond)) if not z3.is_false(cond): ctx.return_states.append((cond, ctx.copy_attrs())) ctx.has_returned = True ctx.forward_conds.append(ctx.tmp_forward_cond)
def handle_select(self, ctx): switches = [] select_conds = [] forward_cond_copy = ctx.tmp_forward_cond match_list = ctx.resolve_expr(self.match) for parser_cond, parser_node in self.child: case_expr = ctx.resolve_expr(parser_cond) cond = build_select_cond(ctx, case_expr, match_list) # state forks here var_store = ctx.checkpoint() ctx.tmp_forward_cond = z3.And(forward_cond_copy, cond) parser_node.eval(ctx) select_conds.append(cond) if not (ctx.get_exited() or z3.is_false(cond)): switches.append((ctx.tmp_forward_cond, ctx.get_attrs())) ctx.set_exited(False) ctx.has_returned = False ctx.restore(var_store) # this hits when no select matches cond = z3.Not(z3.Or(*select_conds)) ctx.tmp_forward_cond = z3.And(forward_cond_copy, cond) self.default.eval(ctx) ctx.set_exited(False) ctx.has_returned = False ctx.tmp_forward_cond = forward_cond_copy for cond, then_vars in reversed(switches): merge_attrs(ctx, cond, then_vars)
def eval(self, ctx): cond = z3.simplify(ctx.resolve_expr(self.cond)) forward_cond_copy = ctx.tmp_forward_cond then_vars = None if not z3.is_false(cond): var_store = ctx.checkpoint() ctx.tmp_forward_cond = z3.And(forward_cond_copy, cond) try: self.then_block.eval(ctx) except ParserException: RejectState().eval(ctx) if not(ctx.has_returned or ctx.get_exited()): then_vars = ctx.get_attrs() ctx.set_exited(False) ctx.has_returned = False ctx.restore(var_store) if not z3.is_true(cond): var_store = ctx.checkpoint() ctx.tmp_forward_cond = z3.And(forward_cond_copy, z3.Not(cond)) try: self.else_block.eval(ctx) except ParserException: RejectState().eval(ctx) if ctx.get_exited() or ctx.has_returned: ctx.restore(var_store) ctx.set_exited(False) ctx.has_returned = False ctx.tmp_forward_cond = forward_cond_copy if then_vars: merge_attrs(ctx, cond, then_vars)
def eval_table(self, ctx): action_exprs = [] action_matches = [] forward_cond_copy = ctx.tmp_forward_cond # only bother to evaluate if the table can actually hit if not z3.is_false(self.locals["hit"]): # note: the action lists are pass by reference here # first evaluate all the constant entries self.eval_const_entries(ctx, action_exprs, action_matches) # then append dynamic table entries to the constant entries # only do this if the table can actually be manipulated if not self.immutable: self.eval_table_entries(ctx, action_exprs, action_matches) # finally start evaluating the default entry var_store = ctx.checkpoint() # this hits when the table is either missed, or no action matches cond = z3.Or(self.locals["miss"], z3.Not(z3.Or(*action_matches))) ctx.tmp_forward_cond = z3.And(forward_cond_copy, cond) self.eval_default(ctx) if ctx.get_exited(): ctx.restore(var_store) ctx.set_exited(False) ctx.tmp_forward_cond = forward_cond_copy # generate a nested set of if expressions per available action for cond, then_vars in action_exprs: merge_attrs(ctx, cond, then_vars)
def eval(self, ctx): # FIXME: This checkpointing should not be necessary # Figure out what is going on var_store = ctx.checkpoint() forward_conds = [] tmp_forward_conds = [] sub_ctx = ctx while not isinstance(sub_ctx, StaticContext): sub_ctx.copy_out(ctx) forward_conds.extend(sub_ctx.forward_conds) tmp_forward_conds.append(sub_ctx.tmp_forward_cond) sub_ctx = sub_ctx.parent_ctx cond = z3.simplify( z3.And(z3.Not(z3.Or(*forward_conds)), z3.And(*tmp_forward_conds))) if not z3.is_false(cond): ctx.add_exit_state(cond, ctx.get_p4_state().get_members(ctx)) ctx.set_exited(True) ctx.restore(var_store) ctx.forward_conds.append(ctx.tmp_forward_cond)
def eval_cases(self, ctx, cases): case_exprs = [] case_matches = [] forward_cond_copy = ctx.tmp_forward_cond fall_through_matches = [] for case_match, case_block in cases.values(): # there is no block for the switch # this expressions falls through to the next switch case if not case_block: fall_through_matches.append(case_match) continue # matches the condition OR all the other fall-through switches case_match = z3.Or(case_match, *fall_through_matches) fall_through_matches.clear() var_store = ctx.checkpoint() ctx.tmp_forward_cond = z3.And( forward_cond_copy, case_match) case_block.eval(ctx) if not (ctx.has_returned or ctx.get_exited()): then_vars = ctx.get_attrs() case_exprs.append((case_match, then_vars)) ctx.has_returned = False ctx.set_exited(False) ctx.restore(var_store) case_matches.append(case_match) var_store = ctx.checkpoint() # process the default expression cond = z3.Not(z3.Or(*case_matches)) if not z3.is_false(cond): ctx.tmp_forward_cond = z3.And(forward_cond_copy, cond) self.default_case.eval(ctx) if ctx.has_returned or ctx.get_exited(): ctx.restore(var_store) ctx.has_returned = False ctx.set_exited(False) ctx.tmp_forward_cond = forward_cond_copy # merge all the expressions in reverse order for cond, then_vars in reversed(case_exprs): merge_attrs(ctx, cond, then_vars)
def eval(self, ctx): if self.expr is None: expr = None else: # resolve the expr before restoring the state expr = ctx.resolve_expr(self.expr) if isinstance(ctx.return_type, z3.BitVecSortRef): expr = z3_cast(expr, ctx.return_type) # we return a complex typed expression list, instantiate if isinstance(expr, list): # name is meaningless here so keep it empty instance = ctx.gen_instance("", ctx.return_type) instance.set_list(expr) expr = instance cond = z3.simplify(z3.And(z3.Not(z3.Or(*ctx.forward_conds)), ctx.tmp_forward_cond)) if not z3.is_false(cond): ctx.return_states.append((cond, ctx.copy_attrs())) if expr is not None: ctx.return_exprs.append((cond, expr)) ctx.has_returned = True ctx.forward_conds.append(ctx.tmp_forward_cond)