summaryrefslogtreecommitdiff
path: root/python/basicblock.py
diff options
context:
space:
mode:
authorPeter LaFosse <peter@vector35.com>2019-03-08 13:59:10 -0500
committerPeter LaFosse <peter@vector35.com>2019-03-08 13:59:23 -0500
commit73c6fc68b205fcb8937bb7c7dd4b9df2652eb1ac (patch)
tree57fada9edf92f1cd6a9877e4d609502d32da55ac /python/basicblock.py
parent5ca01c0091667160be5cd38d091177bd4dfe0914 (diff)
Add ability to index into functions and basicblocks
Diffstat (limited to 'python/basicblock.py')
-rw-r--r--python/basicblock.py95
1 files changed, 64 insertions, 31 deletions
diff --git a/python/basicblock.py b/python/basicblock.py
index 4bf2f3b2..27eadd51 100644
--- a/python/basicblock.py
+++ b/python/basicblock.py
@@ -25,6 +25,7 @@ import binaryninja
from binaryninja import highlight
from binaryninja import _binaryninjacore as core
from binaryninja.enums import BranchType, HighlightColorStyle, HighlightStandardColor, InstructionTextTokenType
+from binaryninja import log
# 2-3 compatibility
from binaryninja import range
@@ -61,6 +62,8 @@ class BasicBlock(object):
self.handle = core.handle_of_type(handle, core.BNBasicBlock)
self._arch = None
self._func = None
+ self._instStarts = None
+ self._instLengths = None
def __del__(self):
core.BNFreeBasicBlock(self.handle)
@@ -75,12 +78,71 @@ class BasicBlock(object):
return True
return ctypes.addressof(self.handle.contents) != ctypes.addressof(value.handle.contents)
+ def __setattr__(self, name, value):
+ try:
+ object.__setattr__(self, name, value)
+ except AttributeError:
+ raise AttributeError("attribute '%s' is read only" % name)
+
+ def __len__(self):
+ return int(core.BNGetBasicBlockLength(self.handle))
+
+ def __repr__(self):
+ arch = self.arch
+ if arch:
+ return "<block: %s@%#x-%#x>" % (arch.name, self.start, self.end)
+ else:
+ return "<block: %#x-%#x>" % (self.start, self.end)
+
+ def __iter__(self):
+ if self._instStarts is None:
+ # no cache is instruction start cache is built so we don't build one
+ # because the user is likely iterating only
+ idx = self.start
+ while idx < self.end:
+ data = self.view.read(idx, min(self.arch.max_instr_length, self.end - idx))
+ inst_text = self.arch.get_instruction_text(data, idx)
+ if inst_text[1] == 0:
+ break
+ yield inst_text
+ idx += inst_text[1]
+ else:
+ for start, length in zip(self._instStarts, self._instLengths):
+ inst_text = self.arch.get_instruction_text(self.view.read(start, length), start)
+ if inst_text[1] == 0:
+ break
+ yield inst_text
+
+ def __getitem__(self, i):
+ self._buildStartCache()
+ start = self._instStarts[i]
+ length = self._instLengths[i]
+ data = self.view.read(start, length)
+ return self.arch.get_instruction_text(data, start)
+
+ def __hash__(self):
+ return hash((self.start, self.end, self.arch.name))
+
+ def _buildStartCache(self):
+ if self._instStarts is None:
+ # build the instruction start cache
+ self._instLengths = []
+ self._instStarts = []
+ start = self.start
+ while start < self.end:
+ length = self.view.get_instruction_length(start)
+ self._instLengths.append(length)
+ self._instStarts.append(start)
+ start += length
+
def _create_instance(self, handle, view):
"""Internal method used to instantiate child instances"""
return BasicBlock(handle, view)
- def __hash__(self):
- return hash((self.start, self.end, self.arch.name))
+ @property
+ def instruction_count(self):
+ self._buildStartCache()
+ return len(self._instStarts)
@property
def function(self):
@@ -290,35 +352,6 @@ class BasicBlock(object):
core.BNFreeBasicBlockList(out_blocks, count.value)
return result
- def __setattr__(self, name, value):
- try:
- object.__setattr__(self, name, value)
- except AttributeError:
- raise AttributeError("attribute '%s' is read only" % name)
-
- def __len__(self):
- return int(core.BNGetBasicBlockLength(self.handle))
-
- def __repr__(self):
- arch = self.arch
- if arch:
- return "<block: %s@%#x-%#x>" % (arch.name, self.start, self.end)
- else:
- return "<block: %#x-%#x>" % (self.start, self.end)
-
- def __iter__(self):
- start = self.start
- end = self.end
-
- idx = start
- while idx < end:
- data = self.view.read(idx, min(self.arch.max_instr_length, end - idx))
- inst_text = self.arch.get_instruction_text(data, idx)
- if inst_text[1] == 0:
- break
- yield inst_text
- idx += inst_text[1]
-
def mark_recent_use(self):
core.BNMarkBasicBlockAsRecentlyUsed(self.handle)