Source code for angr.analyses.decompiler.region_simplifiers.cascading_cond_transformer
# pylint:disable=no-self-use,arguments-renamed,isinstance-second-argument-not-valid-type
from typing import Optional
import ailment
import claripy
from ..structuring.structurer_nodes import ConditionNode, CascadingConditionNode
from ..sequence_walker import SequenceWalker
[docs]class CascadingConditionTransformer(SequenceWalker):
"""
Identifies and transforms `if { ... } else { if { ... } else { ... } }` to
`if { ... } else if { ... } else if { ... }`.
"""
def __init__(self, node):
handlers = {
ConditionNode: self._handle_Condition,
}
super().__init__(handlers)
self.cascading_if_node: Optional[CascadingConditionNode] = None
self.walk(node)
def _negate_ailexpr(self, expr: ailment.Expression) -> ailment.Expression:
return ailment.UnaryOp(None, "Not", expr, **expr.tags)
def _handle_Condition(self, cond_node: ConditionNode, **kwargs):
if (
cond_node.false_node is not None
and isinstance(cond_node.false_node, (ConditionNode, CascadingConditionNode))
and not isinstance(cond_node.true_node, (ConditionNode, CascadingConditionNode))
and cond_node.true_node is not None
):
cond_0 = cond_node.condition
node_0 = cond_node.true_node
remaining_node = cond_node.false_node
elif (
cond_node.true_node is not None
and isinstance(cond_node.true_node, (ConditionNode, CascadingConditionNode))
and not isinstance(cond_node.false_node, (ConditionNode, CascadingConditionNode))
and cond_node.false_node is not None
):
if isinstance(cond_node.condition, claripy.ast.Base):
cond_0 = claripy.Not(cond_node.condition)
else:
cond_0 = self._negate_ailexpr(cond_node.condition)
node_0 = cond_node.false_node
remaining_node = cond_node.true_node
else:
return super()._handle_Condition(cond_node, **kwargs)
# structure else_node
if not isinstance(remaining_node, CascadingConditionNode):
structured = self._handle_Condition(remaining_node)
if structured is None:
structured = remaining_node
else:
structured = remaining_node
if isinstance(structured, ConditionNode):
if structured.true_node is None and structured.false_node is not None:
if isinstance(structured.condition, claripy.ast.Base):
negated_structured_condition = claripy.Not(structured.condition)
else:
negated_structured_condition = self._negate_ailexpr(structured.condition)
cond_and_nodes = [
(cond_0, node_0),
(negated_structured_condition, structured.false_node),
]
else_node = None
elif structured.true_node is not None and structured.false_node is None:
cond_and_nodes = [
(cond_0, node_0),
(structured.condition, structured.true_node),
]
else_node = None
else:
cond_and_nodes = [
(cond_0, node_0),
(structured.condition, structured.true_node),
]
else_node = structured.false_node
elif isinstance(structured, CascadingConditionNode):
# merge two nodes
cond_and_nodes = [(cond_0, node_0)] + structured.condition_and_nodes
else_node = structured.else_node
else:
# unexpected!
raise RuntimeError("Impossible happened")
return CascadingConditionNode(cond_node.addr, cond_and_nodes, else_node=else_node)