reprospect.testing.binaries.sass.sequence.sequence module

Combine matchers from reprospect.testing.binaries.sass.instruction into sequence matchers.

class reprospect.testing.binaries.sass.sequence.sequence.AllInSequenceMatcher(matcher)View on GitHub

Bases: object

Use InSequenceMatcher to find all matches for matcher in a sequence of instructions.

__init__(matcher) None

Method generated by attrs for class AllInSequenceMatcher.

match(instructions: Sequence[Instruction | str]) list[InstructionMatch] | list[list[InstructionMatch]]View on GitHub
matcher: InSequenceMatcher
class reprospect.testing.binaries.sass.sequence.sequence.AnyOfMatcher(*matchers: SequenceMatcher | InstructionMatcher)View on GitHub

Bases: SequenceMatcher

Match any of the matchers.

Note

It is not decorated with dataclasses.dataclass() because of https://github.com/mypyc/mypyc/issues/1061.

__init__(*matchers: SequenceMatcher | InstructionMatcher) NoneView on GitHub
explain(*, instructions: Sequence[Instruction | str]) strView on GitHub
match(instructions: Sequence[Instruction | str]) list[InstructionMatch] | NoneView on GitHub

Loop over the matchers and return the first match.

matched: int
matchers: Final[tuple[SequenceMatcher | InstructionMatcher, ...]]
property next_index: intView on GitHub
class reprospect.testing.binaries.sass.sequence.sequence.CountInSequenceMatcher(matcher: InstructionMatcher, count: int)View on GitHub

Bases: SequenceMatcher

Count how many times it matches in a sequence.

Note

It is not decorated with dataclasses.dataclass() because of https://github.com/mypyc/mypyc/issues/1061.

__init__(matcher: InstructionMatcher, count: int) NoneView on GitHub
count: Final[int]
explain(*, instructions: Sequence[Instruction | str]) strView on GitHub
match(instructions: Sequence[Instruction | str]) list[InstructionMatch] | NoneView on GitHub
matcher: Final[InstructionMatcher]
property next_index: intView on GitHub
class reprospect.testing.binaries.sass.sequence.sequence.Fluentizer(matcher: InstructionMatcher)View on GitHub

Bases: InstructionMatcher

Note

It is not decorated with dataclasses.dataclass() because of https://github.com/mypyc/mypyc/issues/1061.

__init__(matcher: InstructionMatcher) NoneView on GitHub
final match(inst: Instruction | str) InstructionMatch | NoneView on GitHub
matcher: Final[InstructionMatcher]
one_or_more_times() OneOrMoreInSequenceMatcherView on GitHub

Match matcher one or more times (consecutively).

times(num: int) InSequenceAtMatcher | OrderedInSequenceMatcherView on GitHub

Match matcher num times (consecutively).

Note

If num is 0, it tests for the absence of a match.

with_modifier(modifier: str, index: int | None = None) FluentizerView on GitHub
>>> from reprospect.testing.binaries.sass.sequence import instruction_is
>>> from reprospect.testing.binaries.sass.instruction import AnyMatcher
>>> matcher = instruction_is(AnyMatcher()).with_modifier(modifier='U32').with_operand(index=0, operand='R4')
>>> matcher.match(inst='IMAD.WIDE.U32 R4, R7, 0x4, R4')
InstructionMatch(opcode='IMAD', modifiers=('WIDE', 'U32'), operands=('R4', 'R7', '0x4', 'R4'), predicate=None, additional=None)
with_operand(operand: str | AddressMatcher | ConstantMatcher | RegisterMatcher, index: int | None = None) FluentizerView on GitHub
>>> from reprospect.testing.binaries.sass.sequence import instruction_is
>>> from reprospect.testing.binaries.sass.instruction import Fp32AddMatcher, RegisterMatcher
>>> from reprospect.tools.binaries.sass.decoder     import RegisterType
>>> matcher = instruction_is(Fp32AddMatcher()).with_operand(index = 1, operand = RegisterMatcher(rtype = RegisterType.GPR, index = 8))
>>> matcher.match(inst = 'FADD R5, R9, R10')
>>> matcher.match(inst = 'FADD R5, R8, R9')
InstructionMatch(opcode='FADD', modifiers=(), operands=('R5', 'R8', 'R9'), predicate=None, additional={'dst': ['R5']})
with_operands(operands: Collection[tuple[int, str | AddressMatcher | ConstantMatcher | RegisterMatcher]]) FluentizerView on GitHub

Similar to with_operand() for many operands.

>>> from reprospect.testing.binaries.sass.sequence   import instruction_is
>>> from reprospect.testing.binaries.sass.instruction import Fp32AddMatcher
>>> matcher = instruction_is(Fp32AddMatcher()).with_operands(
...     operands = ((1, 'R8'), (2, 'R9')),
... )
>>> matcher.match(inst = 'FADD R5, R9, R10')
>>> matcher.match(inst = 'FADD R5, R8, R9')
InstructionMatch(opcode='FADD', modifiers=(), operands=('R5', 'R8', 'R9'), predicate=None, additional={'dst': ['R5']})
zero_or_more_times() ZeroOrMoreInSequenceMatcherView on GitHub

Match matcher zero or more times (consecutively).

class reprospect.testing.binaries.sass.sequence.sequence.InSequenceAtMatcher(matcher: InstructionMatcher)View on GitHub

Bases: SequenceMatcher

Check that the element matches exactly.

Note

It is not decorated with dataclasses.dataclass() because of https://github.com/mypyc/mypyc/issues/1061.

__init__(matcher: InstructionMatcher) NoneView on GitHub
explain(*, instructions: Sequence[Instruction | str]) strView on GitHub
match(instructions: Sequence[Instruction | str]) list[InstructionMatch] | NoneView on GitHub
matcher: Final[InstructionMatcher]
property next_index: intView on GitHub
class reprospect.testing.binaries.sass.sequence.sequence.InSequenceMatcher(matcher: SequenceMatcher | InstructionMatcher)View on GitHub

Bases: SequenceMatcher

Check that a sequence contains an element that matches exactly.

Note

It is not decorated with dataclasses.dataclass() because of https://github.com/mypyc/mypyc/issues/1061.

__init__(matcher: SequenceMatcher | InstructionMatcher) NoneView on GitHub
explain(*, instructions: Sequence[Instruction | str]) strView on GitHub
match(instructions: Sequence[Instruction | str]) list[InstructionMatch] | NoneView on GitHub
matcher: Final[SequenceMatcher | InstructionMatcher]
property next_index: intView on GitHub
class reprospect.testing.binaries.sass.sequence.sequence.OneOrMoreInSequenceMatcher(matcher: InstructionMatcher)View on GitHub

Bases: SequenceMatcher

Match one or more times.

Note

It is not decorated with dataclasses.dataclass() because of https://github.com/mypyc/mypyc/issues/1061.

__init__(matcher: InstructionMatcher) NoneView on GitHub
explain(*, instructions: Sequence[Instruction | str]) strView on GitHub
match(instructions: Sequence[Instruction | str]) list[InstructionMatch] | NoneView on GitHub
matcher: Final[InstructionMatcher]
property next_index: intView on GitHub
class reprospect.testing.binaries.sass.sequence.sequence.OrderedInSequenceMatcher(matchers: Iterable[SequenceMatcher | InstructionMatcher])View on GitHub

Bases: SequenceMatcher

Match a sequence of matchers in the order they are provided.

Note

It is not decorated with dataclasses.dataclass() because of https://github.com/mypyc/mypyc/issues/1061.

__init__(matchers: Iterable[SequenceMatcher | InstructionMatcher]) NoneView on GitHub
explain(*, instructions: Sequence[Instruction | str]) strView on GitHub
match(instructions: Sequence[Instruction | str]) list[InstructionMatch] | NoneView on GitHub
matchers: Final[tuple[SequenceMatcher | InstructionMatcher, ...]]
property next_index: intView on GitHub
class reprospect.testing.binaries.sass.sequence.sequence.OrderedInterleavedInSequenceMatcher(matchers: Iterable[SequenceMatcher | InstructionMatcher])View on GitHub

Bases: SequenceMatcher

Match a sequence of matchers in the order they are provided, allowing interleaved unmatched instructions in between.

Note

It is not decorated with dataclasses.dataclass() because of https://github.com/mypyc/mypyc/issues/1061.

__init__(matchers: Iterable[SequenceMatcher | InstructionMatcher]) NoneView on GitHub
match(instructions: Sequence[Instruction | str]) list[InstructionMatch] | NoneView on GitHub
matchers: Final[tuple[InSequenceMatcher, ...]]
property next_index: intView on GitHub
class reprospect.testing.binaries.sass.sequence.sequence.SequenceMatcherView on GitHub

Bases: ABC

Base class for matchers of a sequence of instructions.

final assert_matches(instructions: Sequence[Instruction | str]) list[InstructionMatch]View on GitHub

Derived matchers are allowed to provide a nice message by implementing explain().

explain(*, instructions: Sequence[Instruction | str]) strView on GitHub
abstractmethod match(instructions: Sequence[Instruction | str]) list[InstructionMatch] | NoneView on GitHub

Note

The instructions may be consumed more than once, e.g. in reprospect.testing.binaries.sass.sequence.sequence.UnorderedInSequenceMatcher. Therefore, it must be a typing.Sequence, not a typing.Iterable.

abstract property next_index: intView on GitHub

Return the next index in the sequence of instructions that can be matched.

This is the index after the last matched instruction during the last call to match(), i.e. how far this matcher consumed the sequence “plus one”.

The return value is only meaningful if the last call to match() returned a non-None value.

class reprospect.testing.binaries.sass.sequence.sequence.UnorderedInSequenceMatcher(matchers: Iterable[SequenceMatcher | InstructionMatcher])View on GitHub

Bases: SequenceMatcher

Match a sequence of matchers in some permutation of the order they are provided.

Note

It is not decorated with dataclasses.dataclass() because of https://github.com/mypyc/mypyc/issues/1061.

__init__(matchers: Iterable[SequenceMatcher | InstructionMatcher]) NoneView on GitHub
explain(*, instructions: Sequence[Instruction | str]) strView on GitHub
match(instructions: Sequence[Instruction | str]) list[InstructionMatch] | NoneView on GitHub
matchers: Final[tuple[SequenceMatcher | InstructionMatcher, ...]]
property next_index: intView on GitHub
classmethod search(*, instructions: Sequence[Instruction | str], offset: int, matchers: tuple[SequenceMatcher | InstructionMatcher, ...]) tuple[int, list[InstructionMatch]] | NoneView on GitHub

Backtracking problem.

class reprospect.testing.binaries.sass.sequence.sequence.UnorderedInterleavedInSequenceMatcher(matchers: Iterable[SequenceMatcher | InstructionMatcher])View on GitHub

Bases: UnorderedInSequenceMatcher

Match a sequence of matchers in any order, allowing interleaved unmatched instructions in between.

__init__(matchers: Iterable[SequenceMatcher | InstructionMatcher]) NoneView on GitHub
matchers: Final[tuple[SequenceMatcher | InstructionMatcher, ...]]
class reprospect.testing.binaries.sass.sequence.sequence.ZeroOrMoreInSequenceMatcher(matcher: InstructionMatcher)View on GitHub

Bases: OneOrMoreInSequenceMatcher

Match zero or more times.

explain(*, instructions: Sequence[Instruction | str]) strView on GitHub
match(instructions: Sequence[Instruction | str]) list[InstructionMatch] | NoneView on GitHub
matcher: Final[InstructionMatcher]
reprospect.testing.binaries.sass.sequence.sequence.any_of(*matchers: InstructionMatcher | SequenceMatcher) AnyOfMatcherView on GitHub

Match a sequence of instructions against any of the matchers.

Note

Returns the first match.

>>> from reprospect.testing.binaries.sass.sequence   import any_of
>>> from reprospect.testing.binaries.sass.instruction import OpcodeModsMatcher
>>> matcher = any_of(
...     OpcodeModsMatcher(opcode = 'YIELD', operands = False),
...     OpcodeModsMatcher(opcode = 'NOP', operands = False),
... )
>>> matcher.match(instructions = ('FADD R1, R1, R2',)) is None
True
>>> matcher.match(instructions=('NOP',)) is not None
True
>>> matcher.matched
1
reprospect.testing.binaries.sass.sequence.sequence.findall(matcher: InstructionMatcher, instructions: Sequence[Instruction | str]) list[InstructionMatch]View on GitHub
reprospect.testing.binaries.sass.sequence.sequence.findall(matcher: SequenceMatcher, instructions: Sequence[Instruction | str]) list[list[InstructionMatch]]

Find all matches for matcher in a sequence of instructions. Similarly to re.findall(), return an empty list if no match found.

>>> from reprospect.testing.binaries.sass.sequence import findall
>>> from reprospect.testing.binaries.sass.instruction import OpcodeModsMatcher
>>> findall(
...     OpcodeModsMatcher(opcode='FADD', operands=True),
...     (
...         'NOP',
...         'FADD R1, R1, R2',
...         'NOP',
...         'FADD R3, R4, R5',
... ))
[InstructionMatch(opcode='FADD', modifiers=(), operands=('R1', 'R1', 'R2'), predicate=None, additional=None), InstructionMatch(opcode='FADD', modifiers=(), operands=('R3', 'R4', 'R5'), predicate=None, additional=None)]
reprospect.testing.binaries.sass.sequence.sequence.findunique(matcher: InstructionMatcher, instructions: Sequence[Instruction | str]) InstructionMatchView on GitHub
reprospect.testing.binaries.sass.sequence.sequence.findunique(matcher: SequenceMatcher, instructions: Sequence[Instruction | str]) list[InstructionMatch]

Ensure that findall() matches once.

reprospect.testing.binaries.sass.sequence.sequence.instruction_count_is(matcher: InstructionMatcher, count: int) CountInSequenceMatcherView on GitHub

Match only if the matcher matches count times in the sequence.

>>> from reprospect.testing.binaries.sass.sequence import instruction_count_is
>>> from reprospect.testing.binaries.sass.instruction import Fp32AddMatcher
>>> matcher = instruction_count_is(Fp32AddMatcher(), count=2)
>>> matcher.match(instructions=('FADD R2, R2, R3',))
>>> matcher.match(instructions=('FADD R2, R2, R3', 'FADD R4, R4, R5'))
[InstructionMatch(opcode='FADD', modifiers=(), operands=('R2', 'R2', 'R3'), predicate=None, additional={'dst': ['R2']}), InstructionMatch(opcode='FADD', modifiers=(), operands=('R4', 'R4', 'R5'), predicate=None, additional={'dst': ['R4']})]
reprospect.testing.binaries.sass.sequence.sequence.instruction_is(matcher: InstructionMatcher) FluentizerView on GitHub

Match the current instruction with matcher.

>>> from reprospect.testing.binaries.sass.sequence   import instruction_is
>>> from reprospect.testing.binaries.sass.instruction import Fp32AddMatcher
>>> instruction_is(Fp32AddMatcher()).match(inst = 'FADD R2, R2, R3')
InstructionMatch(opcode='FADD', modifiers=(), operands=('R2', 'R2', 'R3'), predicate=None, additional={'dst': ['R2']})
>>> instruction_is(Fp32AddMatcher()).one_or_more_times().match(instructions = ('FADD R2, R2, R3', 'FADD R4, R4, R5'))
[InstructionMatch(opcode='FADD', modifiers=(), operands=('R2', 'R2', 'R3'), predicate=None, additional={'dst': ['R2']}), InstructionMatch(opcode='FADD', modifiers=(), operands=('R4', 'R4', 'R5'), predicate=None, additional={'dst': ['R4']})]
reprospect.testing.binaries.sass.sequence.sequence.instructions_are(*matchers: InstructionMatcher | SequenceMatcher) OrderedInSequenceMatcherView on GitHub

Match a sequence of instructions against matchers.

>>> from reprospect.testing.binaries.sass.sequence   import instructions_are
>>> from reprospect.testing.binaries.sass.instruction import OpcodeModsMatcher
>>> instructions_are(
...     OpcodeModsMatcher(opcode = 'YIELD', operands = False),
...     instruction_is(OpcodeModsMatcher(opcode = 'NOP', operands = False)).zero_or_more_times(),
... ).match(instructions = ('YIELD', 'NOP', 'NOP'))
[InstructionMatch(opcode='YIELD', modifiers=(), operands=(), predicate=None, additional=None), InstructionMatch(opcode='NOP', modifiers=(), operands=(), predicate=None, additional=None), InstructionMatch(opcode='NOP', modifiers=(), operands=(), predicate=None, additional=None)]
reprospect.testing.binaries.sass.sequence.sequence.instructions_contain(matcher: InstructionMatcher | SequenceMatcher) InSequenceMatcherView on GitHub

Check that a sequence of instructions contains at least one instruction matching matcher.

Note

Stops on the first match.

>>> from reprospect.testing.binaries.sass.sequence   import instructions_are, instructions_contain
>>> from reprospect.testing.binaries.sass.instruction import OpcodeModsMatcher
>>> matcher = instructions_contain(instructions_are(
...     OpcodeModsMatcher(opcode = 'YIELD', operands = False),
...     OpcodeModsMatcher(opcode = 'FADD', operands = True),
... ))
>>> matcher.match(instructions = ('NOP', 'NOP', 'YIELD', 'FADD R1, R1, R2'))
[InstructionMatch(opcode='YIELD', modifiers=(), operands=(), predicate=None, additional=None), InstructionMatch(opcode='FADD', modifiers=(), operands=('R1', 'R1', 'R2'), predicate=None, additional=None)]
>>> matcher.next_index
4
reprospect.testing.binaries.sass.sequence.sequence.interleaved_instructions_are(*matchers: InstructionMatcher | SequenceMatcher) OrderedInterleavedInSequenceMatcherView on GitHub

Match a sequence of instructions against matchers, allowing matched instructions to be interleaved with unmatched instructions.

>>> from reprospect.testing.binaries.sass.sequence import interleaved_instructions_are
>>> from reprospect.testing.binaries.sass.instruction import OpcodeModsMatcher
>>> matcher = interleaved_instructions_are(
...     OpcodeModsMatcher(opcode = 'YIELD', operands = False),
...     OpcodeModsMatcher(opcode = 'NOP', operands = False),
... )
>>> matcher.match(instructions = ('YIELD', 'NOP')) is not None
True
>>> matcher.match(instructions = ('NOP', 'YIELD')) is None
True
>>> matcher.match(instructions = ('YIELD', 'FADD R0, R1, R2', 'NOP')) is not None
True
reprospect.testing.binaries.sass.sequence.sequence.unordered_instructions_are(*matchers: InstructionMatcher | SequenceMatcher) UnorderedInSequenceMatcherView on GitHub

Match a sequence of instructions against matchers (unordered).

>>> from reprospect.testing.binaries.sass.sequence   import unordered_instructions_are
>>> from reprospect.testing.binaries.sass.instruction import OpcodeModsMatcher
>>> unordered_instructions_are(
...     OpcodeModsMatcher(opcode = 'YIELD', operands = False),
...     OpcodeModsMatcher(opcode = 'NOP', operands = False),
... ).match(instructions = ('NOP', 'YIELD'))
[InstructionMatch(opcode='NOP', modifiers=(), operands=(), predicate=None, additional=None), InstructionMatch(opcode='YIELD', modifiers=(), operands=(), predicate=None, additional=None)]
reprospect.testing.binaries.sass.sequence.sequence.unordered_interleaved_instructions_are(*matchers: InstructionMatcher | SequenceMatcher) UnorderedInterleavedInSequenceMatcherView on GitHub

Match a sequence of instructions against matchers (unordered), allowing matched instructions to be interleaved with unmatched instructions.

>>> from reprospect.testing.binaries.sass.sequence import unordered_interleaved_instructions_are
>>> from reprospect.testing.binaries.sass.instruction import OpcodeModsMatcher
>>> matcher = unordered_interleaved_instructions_are(
...     OpcodeModsMatcher(opcode = 'YIELD', operands = False),
...     OpcodeModsMatcher(opcode = 'NOP', operands = False),
... )
>>> matcher.match(instructions = ('YIELD', 'NOP')) is not None
True
>>> matcher.match(instructions = ('NOP', 'YIELD')) is not None
True
>>> matcher.match(instructions = ('YIELD', 'FADD R0, R1, R2', 'NOP')) is not None
True
>>> matcher.match(instructions = ('YIELD',)) is None
True