summaryrefslogtreecommitdiff
path: root/python
diff options
context:
space:
mode:
Diffstat (limited to 'python')
-rw-r--r--python/basicblock.py126
-rw-r--r--python/function.py4
-rw-r--r--python/highlight.py122
3 files changed, 91 insertions, 161 deletions
diff --git a/python/basicblock.py b/python/basicblock.py
index 65069f6c..ba2e44e0 100644
--- a/python/basicblock.py
+++ b/python/basicblock.py
@@ -66,15 +66,31 @@ class BasicBlock:
core.BNFreeBasicBlock(self.handle)
def __repr__(self):
- arch = self.arch
- if arch:
- return f"<block: {arch.name}@{self.start:#x}-{self.end:#x}>"
- else:
- return f"<block: {self.start:#x}-{self.end:#x}>"
+ return f"<block: {self.arch.name}@{self.start:#x}-{self.end:#x}>"
def __len__(self):
return int(core.BNGetBasicBlockLength(self.handle))
+ def __lt__(self, other: 'BasicBlock') -> bool:
+ if not isinstance(other, self.__class__):
+ return NotImplemented
+ return self.start < other.start
+
+ def __gt__(self, other: 'BasicBlock') -> bool:
+ if not isinstance(other, self.__class__):
+ return NotImplemented
+ return self.start > other.start
+
+ def __le__(self, other: 'BasicBlock') -> bool:
+ if not isinstance(other, self.__class__):
+ return NotImplemented
+ return self.start <= other.start
+
+ def __ge__(self, other: 'BasicBlock') -> bool:
+ if not isinstance(other, self.__class__):
+ return NotImplemented
+ return self.start >= other.start
+
def __eq__(self, other):
if not isinstance(other, self.__class__):
return NotImplemented
@@ -88,15 +104,7 @@ class BasicBlock:
def __hash__(self):
return hash((self.start, self.end, self.arch))
- def __setattr__(self, name, value):
- try:
- object.__setattr__(self, name, value)
- except AttributeError:
- raise AttributeError(f"attribute '{name}' is read only")
-
def __iter__(self) -> Generator[Tuple[List['_function.InstructionTextToken'], int], None, None]:
- if self.arch is None:
- raise Exception("Attempting to iterate a BasicBlock object with no Architecture set")
if self.view is None:
raise Exception("Attempting to iterate a Basic Block with no BinaryView")
if self._instStarts is None:
@@ -104,7 +112,9 @@ class BasicBlock:
idx = self.start
while idx < self.end:
data = self.view.read(idx, min(self.arch.max_instr_length, self.end - idx))
- text, size = self.arch.get_instruction_text(data, idx)
+ result = self.arch.get_instruction_text(data, idx)
+ assert result is not None
+ text, size = result
if size == 0:
break
yield text, size
@@ -112,7 +122,9 @@ class BasicBlock:
else:
assert self._instLengths is not None
for start, length in zip(self._instStarts, self._instLengths):
- text, size = self.arch.get_instruction_text(self.view.read(start, length), start)
+ result = self.arch.get_instruction_text(self.view.read(start, length), start)
+ assert result is not None
+ text, size = result
if size == 0:
break
yield text, size
@@ -121,8 +133,6 @@ class BasicBlock:
self._buildStartCache()
assert self._instStarts is not None
assert self._instLengths is not None
- if self.arch is None:
- raise Exception("Attempting to iterate a BasicBlock object with no Architecture set")
if self.view is None:
raise Exception("Attempting to iterate a Basic Block with no BinaryView")
@@ -152,7 +162,8 @@ class BasicBlock:
self._instStarts.append(start)
start += length
- def _create_instance(self, handle: core.BNBasicBlockHandle, view: 'binaryview.BinaryView') -> 'BasicBlock':
+ @staticmethod
+ def _create_instance(handle: core.BNBasicBlockHandle, view: Optional['binaryview.BinaryView']) -> 'BasicBlock':
"""Internal method used to instantiate child instances"""
return BasicBlock(handle, view)
@@ -184,15 +195,14 @@ class BasicBlock:
return self._view
@property
- def arch(self) -> Optional['architecture.Architecture']:
+ def arch(self) -> 'architecture.Architecture':
"""Basic block architecture (read-only)"""
# The arch for a BasicBlock isn't going to change so just cache
# it the first time we need it
if self._arch is not None:
return self._arch
arch = core.BNGetBasicBlockArchitecture(self.handle)
- if arch is None:
- return None
+ assert arch is not None, "core.BNGetBasicBlockArchitecture returned None"
self._arch = architecture.CoreArchitecture._from_cache(arch)
return self._arch
@@ -234,7 +244,7 @@ class BasicBlock:
branch_type = BranchType(edges[i].type)
handle = core.BNNewBasicBlockReference(edges[i].target)
assert handle is not None
- target = self._create_instance(handle, self.view)
+ target = BasicBlock._create_instance(handle, self.view)
if direction:
sink, source = target, self
else:
@@ -276,14 +286,15 @@ class BasicBlock:
"""Whether basic block has any invalid instructions (read-only)"""
return core.BNBasicBlockHasInvalidInstructions(self.handle)
- def _make_blocks(self, blocks, count: int) -> List['BasicBlock']:
+ @staticmethod
+ def _make_blocks(blocks, count: int, view: Optional['binaryview.BinaryView'] = None) -> List['BasicBlock']:
assert blocks is not None, "core returned empty block list"
- result: List['BasicBlock'] = []
try:
+ result: List['BasicBlock'] = []
for i in range(0, count):
handle = core.BNNewBasicBlockReference(blocks[i])
assert handle is not None
- result.append(self._create_instance(handle, self.view))
+ result.append(BasicBlock._create_instance(handle, view))
return result
finally:
core.BNFreeBasicBlockList(blocks, count)
@@ -291,89 +302,71 @@ class BasicBlock:
@property
def dominators(self) -> List['BasicBlock']:
"""List of dominators for this basic block (read-only)"""
- if self.view is None:
- raise Exception("Attempting to call BasicBlock.dominators when BinaryView is None")
count = ctypes.c_ulonglong()
- return self._make_blocks(core.BNGetBasicBlockDominators(self.handle, count, False), count.value)
+ blocks = core.BNGetBasicBlockDominators(self.handle, count, False)
+ return BasicBlock._make_blocks(blocks, count.value, self.view)
@property
def post_dominators(self) -> List['BasicBlock']:
"""List of dominators for this basic block (read-only)"""
- if self.view is None:
- raise Exception("Attempting to call BasicBlock.post_dominators when BinaryView is None")
count = ctypes.c_ulonglong()
- return self._make_blocks(core.BNGetBasicBlockDominators(self.handle, count, True), count.value)
+ blocks = core.BNGetBasicBlockDominators(self.handle, count, True)
+ return BasicBlock._make_blocks(blocks, count.value, self.view)
@property
def strict_dominators(self) -> List['BasicBlock']:
"""List of strict dominators for this basic block (read-only)"""
- if self.view is None:
- raise Exception("Attempting to call BasicBlock.strict_dominators when BinaryView is None")
count = ctypes.c_ulonglong()
- return self._make_blocks(core.BNGetBasicBlockStrictDominators(self.handle, count, False), count.value)
+ blocks = core.BNGetBasicBlockStrictDominators(self.handle, count, False)
+ return BasicBlock._make_blocks(blocks, count.value, self.view)
@property
def immediate_dominator(self) -> Optional['BasicBlock']:
"""Immediate dominator of this basic block (read-only)"""
- if self.view is None:
- raise Exception("Attempting to call BasicBlock.immediate_dominator when BinaryView is None")
-
result = core.BNGetBasicBlockImmediateDominator(self.handle, False)
if not result:
return None
- return self._create_instance(result, self.view)
+ return BasicBlock._create_instance(result, self.view)
@property
def immediate_post_dominator(self) -> Optional['BasicBlock']:
"""Immediate dominator of this basic block (read-only)"""
- if self.view is None:
- raise Exception("Attempting to call BasicBlock.immediate_post_dominator when BinaryView is None")
-
result = core.BNGetBasicBlockImmediateDominator(self.handle, True)
if not result:
return None
- return self._create_instance(result, self.view)
+ return BasicBlock._create_instance(result, self.view)
@property
def dominator_tree_children(self) -> List['BasicBlock']:
"""List of child blocks in the dominator tree for this basic block (read-only)"""
- if self.view is None:
- raise Exception("Attempting to call BasicBlock.dominator_tree_children when BinaryView is None")
-
count = ctypes.c_ulonglong()
- return self._make_blocks(core.BNGetBasicBlockDominatorTreeChildren(self.handle, count, False), count.value)
+ blocks = core.BNGetBasicBlockDominatorTreeChildren(self.handle, count, False)
+ return BasicBlock._make_blocks(blocks, count.value, self.view)
@property
def post_dominator_tree_children(self) -> List['BasicBlock']:
"""List of child blocks in the post dominator tree for this basic block (read-only)"""
- if self.view is None:
- raise Exception("Attempting to call BasicBlock.post_dominator_tree_children when BinaryView is None")
-
count = ctypes.c_ulonglong()
- return self._make_blocks(core.BNGetBasicBlockDominatorTreeChildren(self.handle, count, True), count.value)
+ blocks = core.BNGetBasicBlockDominatorTreeChildren(self.handle, count, True)
+ return BasicBlock._make_blocks(blocks, count.value, self.view)
@property
def dominance_frontier(self) -> List['BasicBlock']:
"""Dominance frontier for this basic block (read-only)"""
- if self.view is None:
- raise Exception("Attempting to call BasicBlock.dominance_frontier when BinaryView is None")
-
count = ctypes.c_ulonglong()
- return self._make_blocks(core.BNGetBasicBlockDominanceFrontier(self.handle, count, False), count.value)
+ blocks = core.BNGetBasicBlockDominanceFrontier(self.handle, count, False)
+ return BasicBlock._make_blocks(blocks, count.value, self.view)
@property
def post_dominance_frontier(self) -> List['BasicBlock']:
"""Post dominance frontier for this basic block (read-only)"""
- if self.view is None:
- raise Exception("Attempting to call BasicBlock.post_dominance_frontier when BinaryView is None")
count = ctypes.c_ulonglong()
- return self._make_blocks(core.BNGetBasicBlockDominanceFrontier(self.handle, count, True), count.value)
+ blocks = core.BNGetBasicBlockDominanceFrontier(self.handle, count, True)
+ return BasicBlock._make_blocks(blocks, count.value, self.view)
@property
def annotations(self) -> List[List['_function.InstructionTextToken']]:
"""List of automatic annotations for the start of this block (read-only)"""
- if self.arch is None:
- raise ValueError("attempting to get annotation from BasicBlock without architecture")
if self.function is None:
raise ValueError("Attempting to call BasicBlock.annotations when Function is None")
@@ -428,7 +421,7 @@ class BasicBlock:
return core.BNIsHighLevelILBasicBlock(self.handle)
@staticmethod
- def get_iterated_dominance_frontier(blocks: List['BasicBlock']) -> List['BasicBlock']:
+ def get_iterated_dominance_frontier(blocks: List['BasicBlock'], view: Optional['binaryview.BinaryView'] = None) -> List['BasicBlock']:
if len(blocks) == 0:
return []
block_set = (ctypes.POINTER(core.BNBasicBlock) * len(blocks))() # type: ignore
@@ -436,22 +429,13 @@ class BasicBlock:
block_set[i] = blocks[i].handle
count = ctypes.c_ulonglong()
out_blocks = core.BNGetBasicBlockIteratedDominanceFrontier(block_set, len(blocks), count)
- assert out_blocks is not None, "core.BNGetBasicBlockIteratedDominanceFrontier returned None"
- result = []
- try:
- for i in range(0, count.value):
- handle = core.BNNewBasicBlockReference(out_blocks[i])
- assert handle is not None
- result.append(BasicBlock(handle, blocks[0].view))
- return result
- finally:
- core.BNFreeBasicBlockList(out_blocks, count.value)
+ return BasicBlock._make_blocks(out_blocks, count.value, view)
def mark_recent_use(self) -> None:
core.BNMarkBasicBlockAsRecentlyUsed(self.handle)
def get_disassembly_text(self,
- settings: '_function.DisassemblySettings' = None) -> List['_function.DisassemblyTextLine']:
+ settings: Optional['_function.DisassemblySettings'] = None) -> List['_function.DisassemblyTextLine']:
"""
``get_disassembly_text`` returns a list of DisassemblyTextLine objects for the current basic block.
diff --git a/python/function.py b/python/function.py
index d093c076..b60776e2 100644
--- a/python/function.py
+++ b/python/function.py
@@ -3465,8 +3465,8 @@ class DisassemblyTextLine:
il_instruction: Optional[ILInstructionType]
def __init__(
- self, tokens: List['InstructionTextToken'], address: int = None, il_instr: ILInstructionType = None,
- color: Union['_highlight.HighlightColor', HighlightStandardColor] = None
+ self, tokens: List['InstructionTextToken'], address: Optional[int] = None, il_instr: Optional[ILInstructionType] = None,
+ color: Optional[Union['_highlight.HighlightColor', HighlightStandardColor]] = None
):
self.address = address
self.tokens = tokens
diff --git a/python/highlight.py b/python/highlight.py
index a224ef30..652a4bc9 100644
--- a/python/highlight.py
+++ b/python/highlight.py
@@ -21,96 +21,47 @@
# Binary Ninja components
from . import _binaryninjacore as core
from .enums import HighlightColorStyle, HighlightStandardColor
+from dataclasses import dataclass
+from typing import Optional
-
+@dataclass
class HighlightColor:
+ color: Optional[HighlightStandardColor] = None
+ mix_color: Optional[HighlightStandardColor] = None
+ mix: Optional[int] = None
+ red: Optional[int] = None
+ green: Optional[int] = None
+ blue: Optional[int] = None
+ alpha: int = 255
+
def __init__(self, color=None, mix_color=None, mix=None, red=None, green=None, blue=None, alpha=255):
+ self.alpha = alpha
+ self._style : Optional[HighlightColorStyle] = None
if (red is not None) and (green is not None) and (blue is not None):
self._style = HighlightColorStyle.CustomHighlightColor
- self._red = red
- self._green = green
- self._blue = blue
+ self.red = red
+ self.green = green
+ self.blue = blue
elif (mix_color is not None) and (mix is not None):
- self._style = HighlightColorStyle.MixedHighlightColor
+ self.style = HighlightColorStyle.MixedHighlightColor
if color is None:
- self._color = HighlightStandardColor.NoHighlightColor
+ self.color = HighlightStandardColor.NoHighlightColor
else:
- self._color = color
- self._mix_color = mix_color
- self._mix = mix
+ self.color = color
+ self.mix_color = mix_color
+ self.mix = mix
else:
- self.style = HighlightColorStyle.StandardHighlightColor
+ self._style = HighlightColorStyle.StandardHighlightColor
if color is None:
- self._color = HighlightStandardColor.NoHighlightColor
+ self.color = HighlightStandardColor.NoHighlightColor
else:
- self._color = color
- self._alpha = alpha
-
- @property
- def alpha(self):
- return self._alpha
-
- @alpha.setter
- def alpha(self, value):
- self._alpha = value
-
- @property
- def mix(self):
- return self._mix
-
- @mix.setter
- def mix(self, value):
- self._mix = value
-
- @property
- def mix_color(self):
- return self._mix_color
-
- @mix_color.setter
- def mix_color(self, value):
- self._mix_color = value
-
- @property
- def color(self):
- return self._color
-
- @color.setter
- def color(self, value):
- self._color = value
+ self.color = color
@property
- def style(self):
+ def style(self) -> Optional[HighlightColorStyle]:
return self._style
- @style.setter
- def style(self, value):
- self._style = value
-
- @property
- def green(self):
- return self._green
-
- @green.setter
- def green(self, value):
- self._green = value
-
- @property
- def red(self):
- return self._red
-
- @red.setter
- def red(self, value):
- self._red = value
-
- @property
- def blue(self):
- return self._blue
-
- @blue.setter
- def blue(self, value):
- self._blue = value
-
- def _standard_color_to_str(self, color):
+ def _standard_color_to_str(self, color: Optional[HighlightStandardColor]) -> str:
if color == HighlightStandardColor.NoHighlightColor:
return "none"
if color == HighlightStandardColor.BlueHighlightColor:
@@ -131,26 +82,21 @@ class HighlightColor:
return "white"
if color == HighlightStandardColor.BlackHighlightColor:
return "black"
- return "%d" % color
+ return f"{color}"
def __repr__(self):
if self.style == HighlightColorStyle.StandardHighlightColor:
if self.alpha == 255:
- return "<color: %s>" % self._standard_color_to_str(self.color)
- return "<color: %s, alpha %d>" % (self._standard_color_to_str(self.color), self.alpha)
+ return f"<color: {self._standard_color_to_str(self.color)}>"
+ return f"<color: {self._standard_color_to_str(self.color)}, alpha {self.alpha}>"
if self.style == HighlightColorStyle.MixedHighlightColor:
if self.alpha == 255:
- return "<color: mix %s to %s factor %d>" % (
- self._standard_color_to_str(self.color), self._standard_color_to_str(self.mix_color), self.mix
- )
- return "<color: mix %s to %s factor %d, alpha %d>" % (
- self._standard_color_to_str(self.color), self._standard_color_to_str(self.mix_color
- ), self.mix, self.alpha
- )
+ return f"<color: mix {self._standard_color_to_str(self.color)} to {self._standard_color_to_str(self.mix_color)} factor {self.mix}>"
+ return f"<color: mix {self._standard_color_to_str(self.color)} to {self._standard_color_to_str(self.mix_color)} factor {self.mix}, alpha {self.alpha}>"
if self.style == HighlightColorStyle.CustomHighlightColor:
if self.alpha == 255:
- return "<color: #%.2x%.2x%.2x>" % (self.red, self.green, self.blue)
- return "<color: #%.2x%.2x%.2x, alpha %d>" % (self.red, self.green, self.blue, self.alpha)
+ return f"<color: #{self.red:02x}{self.green:02x}{self.blue:02x}>"
+ return f"<color: #{self.red:02x}{self.green:02x}{self.blue:02x}, alpha {self.alpha}>"
return "<color>"
def _to_core_struct(self) -> core.BNHighlightColor:
@@ -178,7 +124,7 @@ class HighlightColor:
return result
@staticmethod
- def _from_core_struct(color):
+ def _from_core_struct(color: core.BNHighlightColor) -> 'HighlightColor':
if color.style == HighlightColorStyle.StandardHighlightColor:
return HighlightColor(color=color.color, alpha=color.alpha)
elif color.style == HighlightColorStyle.MixedHighlightColor: