'Filter self.actions based on some common parameters.
:param block_addr:  Only return actions generated in blocks starting at this address.
:param block_stmt:  Only return actions generated in the nth statement of each block.
:param insn_addr:   Only return actions generated in the assembly instruction at this address.
:param read_from:   Only return actions that perform a read from the specified location.
:param write_to:    Only return actions that perform a write to the specified location.
Notes:
If IR optimization is turned on, reads and writes may not occur in the instruction
they originally came from. Most commonly, If a register is read from twice in the same
block, the second read will not happen, instead reusing the temp the value is already
stored in.
Valid values for read_from and write_to are the string literals \'reg\' or \'mem\' (matching
any read or write to registers or memory, respectively), any string (representing a read
or write to the named register), and any integer (representing a read or write to the
memory at this address).'

def filter_actions(self, block_addr=None, block_stmt=None, insn_addr=None, read_from=None, write_to=None):

    if (read_from is not None):
        if (write_to is not None):
            raise ValueError("Can't    handle    read_from    and    write_to    at    the    same    time!")
        if (read_from in ('reg', 'mem')):
            read_type = read_from
            read_offset = None
        elif isinstance(read_from, str):
            read_type = 'reg'
            read_offset = self._project.arch.registers[read_from][0]
        else:
            read_type = 'mem'
            read_offset = read_from
    if (write_to is not None):
        if (write_to in ('reg', 'mem')):
            write_type = write_to
            write_offset = None
        elif isinstance(write_to, str):
            write_type = 'reg'
            write_offset = self._project.arch.registers[write_to][0]
        else:
            write_type = 'mem'
            write_offset = write_to
    def addr_of_stmt(bbl_addr, stmt_idx):
        if (stmt_idx is None):
            return None
        stmts = self._project.factory.block(bbl_addr).vex.statements
        if (stmt_idx >= len(stmts)):
            return None
        for i in reversed(xrange((stmt_idx + 1))):
            if (stmts[i].tag == 'Ist_IMark'):
                return (stmts[i].addr + stmts[i].delta)
        return None
    def action_reads(action):
        if (action.type != read_type):
            return False
        if (action.action != 'read'):
            return False
        if (read_offset is None):
            return True
        addr = action.addr
        if isinstance(addr, SimActionObject):
            addr = addr.ast
        if isinstance(addr, claripy.ast.Base):
            if addr.symbolic:
                return False
            addr = self.state.se.any_int(addr)
        if (addr != read_offset):
            return False
        return True
    def action_writes(action):
        if (action.type != write_type):
            return False
        if (action.action != 'write'):
            return False
        if (write_offset is None):
            return True
        addr = action.addr
        if isinstance(addr, SimActionObject):
            addr = addr.ast
        if isinstance(addr, claripy.ast.Base):
            if addr.symbolic:
                return False
            addr = self.state.se.any_int(addr)
        if (addr != write_offset):
            return False
        return True
    return [x for x in reversed(self.actions) if (((block_addr is None) or (x.bbl_addr == block_addr)) and ((block_stmt is None) or (x.stmt_idx == block_stmt)) and ((read_from is None) or action_reads(x)) and ((write_to is None) or action_writes(x)) and ((insn_addr is None) or ((x.sim_procedure is None) and (addr_of_stmt(x.bbl_addr, x.stmt_idx) == insn_addr))))]
