from ..backend_object import BackendObject
[docs]class Segment:
[docs] def __init__(self, offset, size=0):
self.offset = offset
self.size = size
def __repr__(self):
return "Seg (%s [ %d ])" % (hex(self.offset), self.size)
[docs]class AbstractLocation(BackendObject):
[docs] def __init__(self, bbl_key, stmt_id, region_id, segment_list=None, region_offset=None, size=None):
self._bbl_key = -1 if bbl_key is None else bbl_key
self._stmt_id = -1 if stmt_id is None else stmt_id
self._region_id = region_id
self._segment_list = [] if not segment_list else segment_list[::]
if region_offset and size:
self._add_segment(region_offset, size)
def _add_segment(self, offset, size):
segment_added = False
last_pos = 0
segment_end = offset + size
for i, s in enumerate(self._segment_list):
# Case 1
s_end = s.offset + s.size
if offset >= s.offset and segment_end <= s_end:
# It has been covered
return False
if s.offset == offset or s.offset == (offset - 1) or s.offset == (offset + 1):
s.offset = min(s.offset, offset)
s.size = max(s_end, segment_end) - s.offset
segment_added = True
break
# Case 2
if s_end == segment_end or s_end == (segment_end - 1) or s_end == (segment_end + 1):
s.offset = min(s.offset, offset)
s.size = max(s_end, segment_end) - s.offset
segment_added = True
break
if s.offset < offset:
last_pos = i + 1
if not segment_added:
# We create a new segment and add it to the list
s = Segment(offset, size)
self._segment_list.insert(last_pos, s)
# Check for possible merges
i = 0
while i < len(self._segment_list) - 1:
s = self._segment_list[i]
t = self._segment_list[i + 1]
if s.offset + s.size >= t.offset:
# They should be merged!
new_s = Segment(s.offset, max(s.offset + s.size, t.offset + t.size) - s.offset)
self._segment_list[i : i + 2] = [new_s]
else:
i += 1
return True
@property
def basicblock_key(self):
return self._bbl_key
@property
def statement_id(self):
return self._stmt_id
@property
def region(self):
return self._region_id
@property
def segments(self):
return self._segment_list
[docs] def update(self, region_offset, size):
updated = self._add_segment(region_offset, size)
return updated
[docs] def copy(self):
return AbstractLocation(self._bbl_key, self._stmt_id, self._region_id, self._segment_list)
[docs] def merge(self, other):
merged = False
for s in other._segment_list:
merged |= self.update(s.offset, s.size)
return merged
def __contains__(self, offset):
for s in self._segment_list:
if s.offset <= offset and s.offset + s.size > offset:
return True
if s.offset > offset:
break
return False
def __repr__(self):
return "(%xh, %d) %s" % (
(self.basicblock_key if self.basicblock_key is not None else -1),
(self.statement_id if self.statement_id is not None else -1),
self._segment_list,
)