diff options
| author | serpilliere <devnull@localhost> | 2014-06-03 10:27:56 +0200 |
|---|---|---|
| committer | serpilliere <devnull@localhost> | 2014-06-03 10:27:56 +0200 |
| commit | ed5c3668cc9f545b52674ad699fc2b0ed1ccb575 (patch) | |
| tree | 07faf97d7e4d083173a1f7e1bfd249baed2d74f9 /miasm2/core/interval.py | |
| parent | a183e1ebd525453710306695daa8c410fd0cb2af (diff) | |
| download | miasm-ed5c3668cc9f545b52674ad699fc2b0ed1ccb575.tar.gz miasm-ed5c3668cc9f545b52674ad699fc2b0ed1ccb575.zip | |
Miasm v2
* API has changed, so old scripts need updates * See example for API usage * Use tcc or llvm for jit emulation * Go to test and run test_all.py to check install Enjoy !
Diffstat (limited to 'miasm2/core/interval.py')
| -rw-r--r-- | miasm2/core/interval.py | 238 |
1 files changed, 238 insertions, 0 deletions
diff --git a/miasm2/core/interval.py b/miasm2/core/interval.py new file mode 100644 index 00000000..cd2a793e --- /dev/null +++ b/miasm2/core/interval.py @@ -0,0 +1,238 @@ +INT_EQ = 0 +INT_B_IN_A = 1 +INT_A_IN_B = -1 +INT_DISJOIN = 2 +INT_JOIN = 3 +INT_JOIN_AB = 4 +INT_JOIN_BA = 5 + +# 0 => eq +# 1 => b in a +# -1 => a in b +# 2 => disjoin +# 3 => join +# 4 => join a,b touch +# 5 => join b,a touch + + +def cmp_interval(a, b): + if a == b: + return INT_EQ + a1, a2 = a + b1, b2 = b + if a1 <= b1 and a2 >= b2: + return INT_B_IN_A + if b1 <= a1 and b2 >= a2: + return INT_A_IN_B + if a2 + 1 == b1: + return INT_JOIN_AB + if b2 + 1 == a1: + return INT_JOIN_BA + if a1 > b2 + 1 or b1 > a2 + 1: + return INT_DISJOIN + return INT_JOIN + +# interval is: [a, b] + + +class interval: + + def __init__(self, a=None): + if a is None: + a = [] + if isinstance(a, interval): + a = a.intervals + self.is_cannon = False + self.intervals = a + self.cannon() + + def __iter__(self): + for x in self.intervals: + yield x + + @classmethod + def cannon_list(cls, tmp): + """ + Return a cannonizes list of intervals + """ + tmp = sorted([x for x in tmp if x[0] <= x[1]]) + out = [] + if not tmp: + return out + out.append(tmp.pop()) + while tmp: + x = tmp.pop() + rez = cmp_interval(out[-1], x) + # print out[-1], x, rez + if rez == INT_EQ: + continue + elif rez == INT_DISJOIN: + out.append(x) + elif rez == INT_B_IN_A: + continue + elif rez in [INT_JOIN, INT_JOIN_AB, INT_JOIN_BA, INT_A_IN_B]: + u, v = x + while out and cmp_interval(out[-1], (u, v)) in [ + INT_JOIN, INT_JOIN_AB, INT_JOIN_BA, INT_A_IN_B]: + u = min(u, out[-1][0]) + v = max(v, out[-1][1]) + out.pop() + out.append((u, v)) + else: + raise ValueError('unknown state', rez) + return out[::-1] + + def cannon(self): + if self.is_cannon is True: + return + self.intervals = interval.cannon_list(self.intervals) + self.is_cannon = True + + def __repr__(self): + if self.intervals: + o = " U ".join(["[0x%X 0x%X]" % (x[0], x[1]) + for x in self.intervals]) + else: + o = "[]" + return o + + def __contains__(self, i): + if isinstance(i, interval): + for x in self.intervals: + is_out = True + for y in i.intervals: + if cmp_interval(x, y) in [INT_EQ, INT_B_IN_A]: + is_out = False + break + if is_out: + return False + return True + else: + for x in self.intervals: + if x[0] <= i <= x[1]: + return True + return False + + def __eq__(self, i): + return self.intervals == i.intervals + + def __add__(self, i): + if isinstance(i, interval): + i = i.intervals + i = interval(self.intervals + i) + return i + + def __sub__(self, v): + to_test = self.intervals[:] + i = -1 + to_del = v.intervals[:] + while i < len(to_test) - 1: + i += 1 + x = to_test[i] + if x[0] > x[1]: + del(to_test[i]) + i -= 1 + continue + + while to_del and to_del[0][1] < x[0]: + del(to_del[0]) + + for y in to_del: + if y[0] > x[1]: + break + rez = cmp_interval(x, y) + if rez == INT_DISJOIN: + continue + elif rez == INT_EQ: + del(to_test[i]) + i -= 1 + break + elif rez == INT_A_IN_B: + del(to_test[i]) + i -= 1 + break + elif rez == INT_B_IN_A: + del(to_test[i]) + i1 = (x[0], y[0] - 1) + i2 = (y[1] + 1, x[1]) + to_test[i:i] = [i1, i2] + i -= 1 + break + elif rez in [INT_JOIN_AB, INT_JOIN_BA]: + continue + elif rez == INT_JOIN: + del(to_test[i]) + if x[0] < y[0]: + to_test[i:i] = [(x[0], y[0] - 1)] + else: + to_test[i:i] = [(y[1] + 1, x[1])] + i -= 1 + break + else: + raise ValueError('unknown state', rez) + return interval(to_test) + + def __and__(self, v): + out = [] + for x in self.intervals: + # print "x", x + if x[0] > x[1]: + continue + for y in v.intervals: + # print 'y', y + rez = cmp_interval(x, y) + # print x, y, rez + if rez == INT_DISJOIN: + continue + elif rez == INT_EQ: + out.append(x) + continue + elif rez == INT_A_IN_B: + out.append(x) + continue + elif rez == INT_B_IN_A: + out.append(y) + continue + elif rez == INT_JOIN_AB: + continue + elif rez == INT_JOIN_BA: + continue + elif rez == INT_JOIN: + if x[0] < y[0]: + out.append((y[0], x[1])) + else: + out.append((x[0], y[1])) + continue + else: + raise ValueError('unknown state', rez) + return interval(out) + + def hull(self): + if not self.intervals: + return None, None + return self.intervals[0][0], self.intervals[-1][1] + + def show(self, img_x=1350, img_y=20, dry_run=False): + """ + show image representing the itnerval + """ + try: + import Image + import ImageDraw + except ImportError: + print 'cannot import python PIL imaging' + return + + img = Image.new('RGB', (img_x, img_y), (100, 100, 100)) + draw = ImageDraw.Draw(img) + i_min, i_max = self.hull() + + print hex(i_min), hex(i_max) + + def addr2x(addr): + return (addr - i_min) * img_x / (i_max - i_min) + for a, b in self.intervals: + draw.rectangle((addr2x(a), 0, addr2x(b), img_y), (200, 0, 0)) + + if dry_run is False: + img.show() |