diff options
| author | Theofilos Augoustis <theofilos.augoustis@gmail.com> | 2025-10-14 09:09:29 +0000 |
|---|---|---|
| committer | Theofilos Augoustis <theofilos.augoustis@gmail.com> | 2025-10-14 09:09:29 +0000 |
| commit | 579cf1d03fb932083e6317967d1613d5c2587fb6 (patch) | |
| tree | 629f039935382a2a7391bce9253f6c9968159049 /src/miasm/expression/expression_reduce.py | |
| parent | 51c15d3ea2e16d4fc5f0f01a3b9befc66b1f982e (diff) | |
| download | focaccia-miasm-ta/nix.tar.gz focaccia-miasm-ta/nix.zip | |
Convert to src-layout ta/nix
Diffstat (limited to 'src/miasm/expression/expression_reduce.py')
| -rw-r--r-- | src/miasm/expression/expression_reduce.py | 280 |
1 files changed, 280 insertions, 0 deletions
diff --git a/src/miasm/expression/expression_reduce.py b/src/miasm/expression/expression_reduce.py new file mode 100644 index 00000000..41891a09 --- /dev/null +++ b/src/miasm/expression/expression_reduce.py @@ -0,0 +1,280 @@ +""" +Expression reducer: +Apply reduction rules to an Expression ast +""" + +import logging +from miasm.expression.expression import ExprInt, ExprId, ExprLoc, ExprOp, \ + ExprSlice, ExprCompose, ExprMem, ExprCond + +log_reduce = logging.getLogger("expr_reduce") +console_handler = logging.StreamHandler() +console_handler.setFormatter(logging.Formatter("[%(levelname)-8s]: %(message)s")) +log_reduce.addHandler(console_handler) +log_reduce.setLevel(logging.WARNING) + + + +class ExprNode(object): + """Clone of Expression object with additional information""" + + def __init__(self, expr): + self.expr = expr + + +class ExprNodeInt(ExprNode): + def __init__(self, expr): + assert expr.is_int() + super(ExprNodeInt, self).__init__(expr) + self.arg = None + + def __repr__(self): + if self.info is not None: + out = repr(self.info) + else: + out = str(self.expr) + return out + + +class ExprNodeId(ExprNode): + def __init__(self, expr): + assert expr.is_id() + super(ExprNodeId, self).__init__(expr) + self.arg = None + + def __repr__(self): + if self.info is not None: + out = repr(self.info) + else: + out = str(self.expr) + return out + + +class ExprNodeLoc(ExprNode): + def __init__(self, expr): + assert expr.is_loc() + super(ExprNodeLoc, self).__init__(expr) + self.arg = None + + def __repr__(self): + if self.info is not None: + out = repr(self.info) + else: + out = str(self.expr) + return out + + +class ExprNodeMem(ExprNode): + def __init__(self, expr): + assert expr.is_mem() + super(ExprNodeMem, self).__init__(expr) + self.ptr = None + + def __repr__(self): + if self.info is not None: + out = repr(self.info) + else: + out = "@%d[%r]" % (self.expr.size, self.ptr) + return out + + +class ExprNodeOp(ExprNode): + def __init__(self, expr): + assert expr.is_op() + super(ExprNodeOp, self).__init__(expr) + self.args = None + + def __repr__(self): + if self.info is not None: + out = repr(self.info) + else: + if len(self.args) == 1: + out = "(%s(%r))" % (self.expr.op, self.args[0]) + else: + out = "(%s)" % self.expr.op.join(repr(arg) for arg in self.args) + return out + + +class ExprNodeSlice(ExprNode): + def __init__(self, expr): + assert expr.is_slice() + super(ExprNodeSlice, self).__init__(expr) + self.arg = None + + def __repr__(self): + if self.info is not None: + out = repr(self.info) + else: + out = "%r[%d:%d]" % (self.arg, self.expr.start, self.expr.stop) + return out + + +class ExprNodeCompose(ExprNode): + def __init__(self, expr): + assert expr.is_compose() + super(ExprNodeCompose, self).__init__(expr) + self.args = None + + def __repr__(self): + if self.info is not None: + out = repr(self.info) + else: + out = "{%s}" % ', '.join(repr(arg) for arg in self.args) + return out + + +class ExprNodeCond(ExprNode): + def __init__(self, expr): + assert expr.is_cond() + super(ExprNodeCond, self).__init__(expr) + self.cond = None + self.src1 = None + self.src2 = None + + def __repr__(self): + if self.info is not None: + out = repr(self.info) + else: + out = "(%r?%r:%r)" % (self.cond, self.src1, self.src2) + return out + + +class ExprReducer(object): + """Apply reduction rules to an expr + + reduction_rules: list of ordered reduction rules + + List of function representing reduction rules + Function API: + reduction_xxx(self, node, lvl=0) + with: + * node: the ExprNode to qualify + * lvl: [optional] the recursion level + Returns: + * None if the reduction rule is not applied + * the resulting information to store in the ExprNode.info + + allow_none_result: allow missing reduction rules + """ + + reduction_rules = [] + allow_none_result = False + + def expr2node(self, expr): + """Build ExprNode mirror of @expr + + @expr: Expression to analyze + """ + + if isinstance(expr, ExprId): + node = ExprNodeId(expr) + elif isinstance(expr, ExprLoc): + node = ExprNodeLoc(expr) + elif isinstance(expr, ExprInt): + node = ExprNodeInt(expr) + elif isinstance(expr, ExprMem): + son = self.expr2node(expr.ptr) + node = ExprNodeMem(expr) + node.ptr = son + elif isinstance(expr, ExprSlice): + son = self.expr2node(expr.arg) + node = ExprNodeSlice(expr) + node.arg = son + elif isinstance(expr, ExprOp): + sons = [self.expr2node(arg) for arg in expr.args] + node = ExprNodeOp(expr) + node.args = sons + elif isinstance(expr, ExprCompose): + sons = [self.expr2node(arg) for arg in expr.args] + node = ExprNodeCompose(expr) + node.args = sons + elif isinstance(expr, ExprCond): + node = ExprNodeCond(expr) + node.cond = self.expr2node(expr.cond) + node.src1 = self.expr2node(expr.src1) + node.src2 = self.expr2node(expr.src2) + else: + raise TypeError("Unknown Expr Type %r", type(expr)) + return node + + def reduce(self, expr, **kwargs): + """Returns an ExprNode tree mirroring @expr tree. The ExprNode is + computed by applying reduction rules to the expression @expr + + @expr: an Expression + """ + + node = self.expr2node(expr) + return self.categorize(node, lvl=0, **kwargs) + + def categorize(self, node, lvl=0, **kwargs): + """Recursively apply rules to @node + + @node: ExprNode to analyze + @lvl: actual recursion level + """ + + expr = node.expr + log_reduce.debug("\t" * lvl + "Reduce...: %s", node.expr) + if isinstance(expr, ExprId): + node = ExprNodeId(expr) + elif isinstance(expr, ExprInt): + node = ExprNodeInt(expr) + elif isinstance(expr, ExprLoc): + node = ExprNodeLoc(expr) + elif isinstance(expr, ExprMem): + ptr = self.categorize(node.ptr, lvl=lvl + 1, **kwargs) + node = ExprNodeMem(ExprMem(ptr.expr, expr.size)) + node.ptr = ptr + elif isinstance(expr, ExprSlice): + arg = self.categorize(node.arg, lvl=lvl + 1, **kwargs) + node = ExprNodeSlice(ExprSlice(arg.expr, expr.start, expr.stop)) + node.arg = arg + elif isinstance(expr, ExprOp): + new_args = [] + for arg in node.args: + new_a = self.categorize(arg, lvl=lvl + 1, **kwargs) + assert new_a.expr.size == arg.expr.size + new_args.append(new_a) + node = ExprNodeOp(ExprOp(expr.op, *[x.expr for x in new_args])) + node.args = new_args + expr = node.expr + elif isinstance(expr, ExprCompose): + new_args = [] + new_expr_args = [] + for arg in node.args: + arg = self.categorize(arg, lvl=lvl + 1, **kwargs) + new_args.append(arg) + new_expr_args.append(arg.expr) + new_expr = ExprCompose(*new_expr_args) + node = ExprNodeCompose(new_expr) + node.args = new_args + elif isinstance(expr, ExprCond): + cond = self.categorize(node.cond, lvl=lvl + 1, **kwargs) + src1 = self.categorize(node.src1, lvl=lvl + 1, **kwargs) + src2 = self.categorize(node.src2, lvl=lvl + 1, **kwargs) + node = ExprNodeCond(ExprCond(cond.expr, src1.expr, src2.expr)) + node.cond, node.src1, node.src2 = cond, src1, src2 + else: + raise TypeError("Unknown Expr Type %r", type(expr)) + + node.info = self.apply_rules(node, lvl=lvl, **kwargs) + log_reduce.debug("\t" * lvl + "Reduce result: %s %r", + node.expr, node.info) + return node + + def apply_rules(self, node, lvl=0, **kwargs): + """Find and apply reduction rules to @node + + @node: ExprNode to analyse + @lvl: actuel recursion level + """ + + for rule in self.reduction_rules: + ret = rule(self, node, lvl=lvl, **kwargs) + + if ret is not None: + log_reduce.debug("\t" * lvl + "Rule found: %r", rule) + return ret + if not self.allow_none_result: + raise RuntimeError('Missing reduction rule for %r' % node.expr) |