(self, state: 'angr.SimState', trace_curr_idx, state_desync_block_idx)
return state.history.recent_bbl_addrs[state_desync_block_idx] < big_block_end_addr
Check if desync occurred because large blocks are split up at different instructions by qemu and unicorn. This
        is done by reconstructing part of block executed so far from the trace and state history and checking if they
        the same
Check if desync occurred because large blocks are split up at different instructions by qemu and unicorn. This
        is done by reconstructing part of block executed so far from the trace and state history and checking if they
        the same
Check if desync occurred because large blocks are split up at different instructions by qemu and unicorn . This is done by reconstructing part of block executed so far from the trace and state history and checking if they the same
def _check_qemu_unicorn_large_block_split(self, state: 'angr.SimState', trace_curr_idx, state_desync_block_idx):
        """
        Check if desync occurred because large blocks are split up at different instructions by qemu and unicorn. This
        is done by reconstructing part of block executed so far from the trace and state history and checking if they
        the same
        """

        control_flow_insn_types = [CS_GRP_CALL, CS_GRP_IRET, CS_GRP_JUMP, CS_GRP_RET]

        prev_trace_block = state.project.factory.block(self._translate_trace_addr(self._trace[trace_curr_idx - 1]))
        for insn_type in control_flow_insn_types:
            if prev_trace_block.capstone.insns[-1].group(insn_type):
                # Previous block ends in a control flow instruction. It is not large block different split.
                return False

        # The previous block did not end in a control flow instruction. Let's find the start of this big block from
        # trace: it'll be the first block executed after a control flow instruction.
        big_block_start_addr = None
        for trace_block_idx in range(trace_curr_idx - 2, -1, -1):
            trace_block = state.project.factory.block(self._translate_trace_addr(self._trace[trace_block_idx]))
            trace_block_last_insn = trace_block.capstone.insns[-1]
            for insn_type in control_flow_insn_types:
                if trace_block_last_insn.group(insn_type):
                    big_block_start_addr = self._translate_trace_addr(self._trace[trace_block_idx + 1])
                    break

            if big_block_start_addr is not None:
                break
        else:
            # Failed to find end of the big basic block in trace. Treat as trace desync.
            return False

        # Now we check the part of the state history corresponding to this big basic block to ensure there are no
        # control flow instructions at end of any blocks in the part. This check moves backwards starting from the
        # desyncing block to the start of the big block we found earlier
        for state_history_block_addr in reversed(state.history.recent_bbl_addrs[:state_desync_block_idx]):
            state_history_block = state.project.factory.block(state_history_block_addr)
            state_history_block_last_insn = state_history_block.capstone.insns[-1]
            for insn_type in control_flow_insn_types:
                if state_history_block_last_insn.group(insn_type):
                    # We haven't found the start of big block according to the trace but found a block ending with a
                    # control flow instruction. It is a trace desync then.
                    return False

            if state_history_block_addr == big_block_start_addr:
                # We found start of the big block and no control flow statements in between that and the block where
                # desync happend.
                break

        # Let's find the address of the last byte of the big basic block using VEX lifter
        angr_big_block_end_addr = None
        curr_block_addr = big_block_start_addr
        while True:
            curr_block = state.project.factory.block(self._translate_trace_addr(curr_block_addr))
            curr_block_last_insn = curr_block.capstone.insns[-1]
            if any((curr_block_last_insn.group(insn_type) for insn_type in control_flow_insn_types)):
                # Found last block
                angr_big_block_end_addr = curr_block.addr + curr_block.size - 1
                break

            curr_block_addr = curr_block.addr + curr_block.size

        # Let's find the address of the last bytes of the big basic block from the trace
        big_block_end_addr = None
        for trace_block_idx in range(trace_curr_idx, len(self._trace)):
            trace_block = state.project.factory.block(self._translate_trace_addr(self._trace[trace_block_idx]))
            trace_block_last_insn = trace_block.capstone.insns[-1]
            for insn_type in control_flow_insn_types:
                if trace_block_last_insn.group(insn_type):
                    # Found first block in trace ending in a control flow instruction. Verify it matches the end of big
                    # block according to VEX lifter
                    big_block_end_addr = trace_block.addr + trace_block.size - 1
                    if angr_big_block_end_addr != big_block_end_addr:
                        # End does not match. Treat as trace desync.
                        return False
                    else:
                        break

            if big_block_end_addr is not None:
                break
        else:
            # Failed to find end of the big basic block in trace. Treat as trace desync.
            return False

        # At this point, we know the following:
        # - There is no control flow instruction between big_block_start_addr and big_block_end_addr
        # - There is no control flow instruction between big_block_start_addr and state_desync_block_addr
        # - state_desync_block_addr is definitely executed after big_block_start_addr
        # So it's enough to check if desyncing block's address is less than big_block_end_addr to ensure that it
        # is part of the big block
        return state.history.recent_bbl_addrs[state_desync_block_idx] < big_block_end_addr
def _check_qemu_unicorn_large_block_split ( self , state : 'angr.SimState' , trace_curr_idx , state_desync_block_idx ) : control_flow_insn_types = [ CS_GRP_CALL , CS_GRP_IRET , CS_GRP_JUMP , CS_GRP_RET ] prev_trace_block = state . project . factory . block ( self . _translate_trace_addr ( self . _trace [ trace_curr_idx - 1 ] ) ) for insn_type in control_flow_insn_types : if prev_trace_block . capstone . insns [ - 1 ] . group ( insn_type ) : # Previous block ends in a control flow instruction. It is not large block different split. return False # The previous block did not end in a control flow instruction. Let's find the start of this big block from # trace: it'll be the first block executed after a control flow instruction. big_block_start_addr = None for trace_block_idx in range ( trace_curr_idx - 2 , - 1 , - 1 ) : trace_block = state . project . factory . block ( self . _translate_trace_addr ( self . _trace [ trace_block_idx ] ) ) trace_block_last_insn = trace_block . capstone . insns [ - 1 ] for insn_type in control_flow_insn_types : if trace_block_last_insn . group ( insn_type ) : big_block_start_addr = self . _translate_trace_addr ( self . _trace [ trace_block_idx + 1 ] ) break if big_block_start_addr is not None : break else : # Failed to find end of the big basic block in trace. Treat as trace desync. return False # Now we check the part of the state history corresponding to this big basic block to ensure there are no # control flow instructions at end of any blocks in the part. This check moves backwards starting from the # desyncing block to the start of the big block we found earlier for state_history_block_addr in reversed ( state . history . recent_bbl_addrs [ : state_desync_block_idx ] ) : state_history_block = state . project . factory . block ( state_history_block_addr ) state_history_block_last_insn = state_history_block . capstone . insns [ - 1 ] for insn_type in control_flow_insn_types : if state_history_block_last_insn . group ( insn_type ) : # We haven't found the start of big block according to the trace but found a block ending with a # control flow instruction. It is a trace desync then. return False if state_history_block_addr == big_block_start_addr : # We found start of the big block and no control flow statements in between that and the block where # desync happend. break # Let's find the address of the last byte of the big basic block using VEX lifter angr_big_block_end_addr = None curr_block_addr = big_block_start_addr while True : curr_block = state . project . factory . block ( self . _translate_trace_addr ( curr_block_addr ) ) curr_block_last_insn = curr_block . capstone . insns [ - 1 ] if any ( ( curr_block_last_insn . group ( insn_type ) for insn_type in control_flow_insn_types ) ) : # Found last block angr_big_block_end_addr = curr_block . addr + curr_block . size - 1 break curr_block_addr = curr_block . addr + curr_block . size # Let's find the address of the last bytes of the big basic block from the trace big_block_end_addr = None for trace_block_idx in range ( trace_curr_idx , len ( self . _trace ) ) : trace_block = state . project . factory . block ( self . _translate_trace_addr ( self . _trace [ trace_block_idx ] ) ) trace_block_last_insn = trace_block . capstone . insns [ - 1 ] for insn_type in control_flow_insn_types : if trace_block_last_insn . group ( insn_type ) : # Found first block in trace ending in a control flow instruction. Verify it matches the end of big # block according to VEX lifter big_block_end_addr = trace_block . addr + trace_block . size - 1 if angr_big_block_end_addr != big_block_end_addr : # End does not match. Treat as trace desync. return False else : break if big_block_end_addr is not None : break else : # Failed to find end of the big basic block in trace. Treat as trace desync. return False # At this point, we know the following: # - There is no control flow instruction between big_block_start_addr and big_block_end_addr # - There is no control flow instruction between big_block_start_addr and state_desync_block_addr # - state_desync_block_addr is definitely executed after big_block_start_addr # So it's enough to check if desyncing block's address is less than big_block_end_addr to ensure that it # is part of the big block return state . history . recent_bbl_addrs [ state_desync_block_idx ] < big_block_end_addr