diff options
Diffstat (limited to 'python')
| -rw-r--r-- | python/basicblock.py | 126 | ||||
| -rw-r--r-- | python/function.py | 4 | ||||
| -rw-r--r-- | python/highlight.py | 122 |
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: |
