Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Explicit hash/eq for dataflow objects #417

Merged
merged 4 commits into from
Jun 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 80 additions & 13 deletions decompiler/structures/pseudo/expressions.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@

from ...util.insertion_ordered_set import InsertionOrderedSet
from .complextypes import Enum
from .typing import ArrayType, CustomType, Type, UnknownType
from .typing import CustomType, Type, UnknownType

T = TypeVar("T")
DecompiledType = TypeVar("DecompiledType", bound=Type)
Expand All @@ -58,18 +58,6 @@ class DataflowObject(ABC):
def __init__(self, tags: Optional[Tuple[Tag, ...]] = None):
self.tags = tags

def __eq__(self, other) -> bool:
"""Check for equality."""
return type(other) == type(self) and hash(self) == hash(other)

def __hash__(self) -> int:
"""Return a hash value for the expression."""
return hash(repr(self))

def __repr__(self):
"""Return a debug representation."""
return str(self)

@abstractmethod
def __iter__(self) -> Iterator[DataflowObject]:
"""Iterate all nested DataflowObjects."""
Expand Down Expand Up @@ -149,6 +137,12 @@ def __init__(self, msg: str, tags: Optional[Tuple[Tag, ...]] = None):
self.msg = msg
super().__init__(tags)

def __eq__(self, __value):
return isinstance(__value, UnknownExpression) and self.msg == __value.msg

def __hash__(self):
return hash(self.msg)

def __str__(self) -> str:
"""Return the error message as string representation."""
return self.msg
Expand Down Expand Up @@ -183,6 +177,17 @@ def __init__(
self._pointee = pointee
super().__init__(tags)

def __eq__(self, __value):
return (
isinstance(__value, Constant)
and self.value == __value.value
and self._type == __value._type
and self._pointee == __value.pointee
)

def __hash__(self):
return hash((tuple(self.value) if isinstance(self.value, list) else self.value, self._type, self._pointee))

def __repr__(self) -> str:
value = str(self) if isinstance(self.value, str) else self.value
if self.pointee:
Expand Down Expand Up @@ -235,6 +240,12 @@ class NotUseableConstant(Constant):
def __init__(self, value: str, tags: Optional[Tuple[Tag, ...]] = None):
super().__init__(value, CustomType("double", 0), tags=tags)

def __eq__(self, __value):
return isinstance(__value, NotUseableConstant) and self.value == __value.value

def __hash__(self):
return hash(self.value)

def __str__(self) -> str:
"""Return a string because NotUseableConstant are string only"""
return self.value
Expand All @@ -255,6 +266,12 @@ def __init__(self, name: str, value: Union[int, float], vartype: Type = UnknownT
super().__init__(value, vartype, tags=tags)
self._name = name

def __eq__(self, __value):
return isinstance(__value, Symbol) and self._name == __value._name and self.value == __value.value

def __hash__(self):
return hash((self._name, self.value))

@property
def name(self) -> str:
return self._name
Expand All @@ -278,13 +295,25 @@ def copy(self) -> Symbol:
class FunctionSymbol(Symbol):
"""Represents a function name"""

def __eq__(self, __value):
return isinstance(__value, FunctionSymbol) and super().__eq__(__value)

def __hash__(self):
return super().__hash__()

def copy(self) -> FunctionSymbol:
return FunctionSymbol(self.name, self.value, self._type.copy(), self.tags)


class ImportedFunctionSymbol(FunctionSymbol):
"""Represents an imported function name"""

def __eq__(self, __value):
return isinstance(__value, ImportedFunctionSymbol) and super().__eq__(__value)

def __hash__(self):
return super().__hash__()

def copy(self) -> ImportedFunctionSymbol:
return ImportedFunctionSymbol(self._name, self.value, self._type.copy(), self.tags)

Expand All @@ -297,6 +326,12 @@ class IntrinsicSymbol(FunctionSymbol):
def __init__(self, name: str):
super().__init__(name, self.INTRINSIC_ADDRESS)

def __eq__(self, __value):
return isinstance(__value, IntrinsicSymbol) and self.name == __value.name

def __hash__(self):
return hash(self.name)

def __repr__(self):
return f"intrinsic '{self.name}'"

Expand Down Expand Up @@ -324,6 +359,18 @@ def __init__(
self.ssa_name = ssa_name
super().__init__(tags)

def __eq__(self, __value):
return (
isinstance(__value, Variable)
and self._name == __value._name
and self.ssa_label == __value.ssa_label
and self._type == __value._type
and self.is_aliased == __value.is_aliased
)

def __hash__(self):
return hash((self._name, self.ssa_label, self._type, self.is_aliased))

def __repr__(self) -> str:
"""Return a debug representation of the variable, which includes all the attributes"""
return f"{self.name}#{self.ssa_label} (type: {self.type} aliased: {self.is_aliased})"
Expand Down Expand Up @@ -399,6 +446,12 @@ def __init__(
self.initial_value = initial_value
self.is_constant = is_constant

def __eq__(self, __value):
return isinstance(__value, GlobalVariable) and super().__eq__(__value)

def __hash__(self):
return super().__hash__()

def copy(
self,
name: str = None,
Expand Down Expand Up @@ -445,6 +498,14 @@ def __init__(self, high: Variable, low: Variable, vartype: Type = UnknownType(),
self._low = low
self._type = vartype

def __eq__(self, __value):
return (
isinstance(__value, RegisterPair) and self._high == __value._high and self._low == __value._low and self._type == __value._type
)

def __hash__(self):
return hash((self._high, self._low, self._type))

def __repr__(self) -> str:
"""Return debug representation of register pair"""
return f"{repr(self._high)}:{repr(self._low)} type: {self.type}"
Expand Down Expand Up @@ -507,6 +568,12 @@ def __init__(self, value: list[Constant], vartype: DecompiledType = UnknownType(
tags,
)

def __eq__(self, __value):
return isinstance(__value, ConstantComposition) and super().__eq__(__value)

def __hash__(self):
return super().__hash__()

def __str__(self) -> str:
"""Return a string representation of the ConstantComposition"""
return "{" + ",".join([str(x) for x in self.value]) + "}"
Expand Down
60 changes: 60 additions & 0 deletions decompiler/structures/pseudo/instructions.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,12 @@ def __init__(self, comment: str, comment_style: str = "C", tags: Optional[Tuple[
self._comment_style = comment_style
self._open_comment, self._close_comment = self.STYLES.get(comment_style, self.STYLES[self.DEFAULT_STYLE])

def __eq__(self, __value):
return isinstance(__value, Comment) and self._comment == __value._comment and self._comment_style == __value._comment_style

def __hash__(self):
return hash((self._comment, self._comment_style))

def __repr__(self) -> str:
"""Return representation of comment."""
return f"{self._open_comment} {self._comment} {self._close_comment}"
Expand Down Expand Up @@ -161,6 +167,12 @@ def __init__(self, destination: Expression, value: Expression, tags: Optional[Tu
"""Init a new Assignment."""
super(Assignment, self).__init__(destination, value, tags=tags)

def __eq__(self, __value):
return isinstance(__value, Assignment) and self._destination == __value._destination and self._value == __value._value

def __hash__(self):
return hash((self._destination, self._value))

def __str__(self) -> str:
"""Return a string representation starting with the lhs."""
if isinstance(self._destination, ListOperation) and not self._destination.operands:
Expand Down Expand Up @@ -211,6 +223,12 @@ def __init__(self, destination: Variable, value: Variable, tags: Optional[Tuple[
"""Init a new Relation."""
super(Relation, self).__init__(destination, value, tags=tags)

def __eq__(self, __value):
return isinstance(__value, Relation) and self._destination == __value._destination and self._value == __value._value

def __hash__(self):
return hash((self._destination, self._value))

def __str__(self) -> str:
"""Return a string representation starting with the lhs."""
return f"{self.destination} -> {self.value}"
Expand Down Expand Up @@ -314,6 +332,12 @@ def __init__(self, condition: Condition, tags: Optional[Tuple[Tag, ...]] = None)
"""Init a new branch instruction."""
super(Branch, self).__init__(condition, tags=tags)

def __eq__(self, __value):
return isinstance(__value, Branch) and self._condition == __value._condition

def __hash__(self):
return hash(self._condition)

def __repr__(self) -> str:
"""Return a debug representation of a branch"""
return f"if {repr(self.condition)}"
Expand All @@ -333,6 +357,12 @@ def __init__(self, condition: Expression, tags: Optional[Tuple[Tag, ...]] = None
"""Init a new branch instruction."""
super(IndirectBranch, self).__init__(condition, tags=tags)

def __eq__(self, __value):
return isinstance(__value, IndirectBranch) and self._condition

def __hash__(self):
return hash(self._condition)

def __repr__(self) -> str:
"""Return a debug representation of a branch"""
return f"jmp {repr(self.condition)}"
Expand All @@ -355,6 +385,12 @@ def __init__(self, values, tags: Optional[Tuple[Tag, ...]] = None):
super().__init__(tags)
self._values = ListOperation(values)

def __eq__(self, __value):
return isinstance(__value, Return) and self._values == __value._values

def __hash__(self):
return hash(self._values)

def __repr__(self) -> str:
return f"return {repr(self._values)}"

Expand Down Expand Up @@ -395,6 +431,12 @@ def accept(self, visitor: DataflowObjectVisitorInterface[T]) -> T:


class Break(Instruction):
def __eq__(self, __value):
return isinstance(__value, Break)

def __hash__(self):
return hash(Break)

def __iter__(self) -> Iterator[Expression]:
yield from ()

Expand All @@ -417,6 +459,12 @@ def accept(self, visitor: DataflowObjectVisitorInterface[T]) -> T:


class Continue(Instruction):
def __eq__(self, __value):
return isinstance(__value, Continue)

def __hash__(self):
return hash(Continue)

def __iter__(self) -> Iterator[Expression]:
yield from ()

Expand Down Expand Up @@ -457,6 +505,12 @@ def __init__(
self._origin_block = origin_block if origin_block else {}
super().__init__(destination, ListOperation(value), tags=tags)

def __eq__(self, __value):
return isinstance(__value, Phi) and self._destination == __value._destination and self._value == __value._value

def __hash__(self):
return hash((self._destination, self._value))

def __repr__(self):
return f"{repr(self.destination)} = ϕ({repr(self.value)})"

Expand Down Expand Up @@ -516,6 +570,12 @@ class MemPhi(Phi):
def __init__(self, destination_var: Variable, source_vars: Sequence[Variable], tags: Optional[Tuple[Tag, ...]] = None):
super().__init__(destination_var, source_vars, tags=tags)

def __eq__(self, __value):
return isinstance(__value, MemPhi) and super().__eq__(__value)

def __hash__(self):
return super().__hash__()

def __str__(self) -> str:
return f"{self.destination} = ϕ({self.value})"

Expand Down
Loading
Loading