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/analysis/expression_range.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/analysis/expression_range.py')
| -rw-r--r-- | src/miasm/analysis/expression_range.py | 70 |
1 files changed, 70 insertions, 0 deletions
diff --git a/src/miasm/analysis/expression_range.py b/src/miasm/analysis/expression_range.py new file mode 100644 index 00000000..5a31873a --- /dev/null +++ b/src/miasm/analysis/expression_range.py @@ -0,0 +1,70 @@ +"""Naive range analysis for expression""" + +from future.builtins import zip +from functools import reduce + +from miasm.analysis.modularintervals import ModularIntervals + +_op_range_handler = { + "+": lambda x, y: x + y, + "&": lambda x, y: x & y, + "|": lambda x, y: x | y, + "^": lambda x, y: x ^ y, + "*": lambda x, y: x * y, + "a>>": lambda x, y: x.arithmetic_shift_right(y), + "<<": lambda x, y: x << y, + ">>": lambda x, y: x >> y, + ">>>": lambda x, y: x.rotation_right(y), + "<<<": lambda x, y: x.rotation_left(y), +} + +def expr_range(expr): + """Return a ModularIntervals containing the range of possible values of + @expr""" + max_bound = (1 << expr.size) - 1 + if expr.is_int(): + return ModularIntervals(expr.size, [(int(expr), int(expr))]) + elif expr.is_id() or expr.is_mem(): + return ModularIntervals(expr.size, [(0, max_bound)]) + elif expr.is_slice(): + interval_mask = ((1 << expr.start) - 1) ^ ((1 << expr.stop) - 1) + arg = expr_range(expr.arg) + # Mask for possible range, and shift range + return ((arg & interval_mask) >> expr.start).size_update(expr.size) + elif expr.is_compose(): + sub_ranges = [expr_range(arg) for arg in expr.args] + args_idx = [info[0] for info in expr.iter_args()] + + # No shift for the first one + ret = sub_ranges[0].size_update(expr.size) + + # Doing it progressively (2 by 2) + for shift, sub_range in zip(args_idx[1:], sub_ranges[1:]): + ret |= sub_range.size_update(expr.size) << shift + return ret + elif expr.is_op(): + # A few operation are handled with care + # Otherwise, overapproximate (ie. full range interval) + if expr.op in _op_range_handler: + sub_ranges = [expr_range(arg) for arg in expr.args] + return reduce( + _op_range_handler[expr.op], + (sub_range for sub_range in sub_ranges[1:]), + sub_ranges[0] + ) + elif expr.op == "-": + assert len(expr.args) == 1 + return - expr_range(expr.args[0]) + elif expr.op == "%": + assert len(expr.args) == 2 + op, mod = [expr_range(arg) for arg in expr.args] + if mod.intervals.length == 1: + # Modulo intervals is not supported + return op % mod.intervals.hull()[0] + + # Operand not handled, return the full domain + return ModularIntervals(expr.size, [(0, max_bound)]) + elif expr.is_cond(): + return expr_range(expr.src1).union(expr_range(expr.src2)) + else: + raise TypeError("Unsupported type: %s" % expr.__class__) |