Handle the switch between the concrete execution and angr.
        This method takes care of:
        1- Synchronize registers.
        2- Set a concrete target to the memory backer so the memory reads are redirected in the concrete process memory.
        3- If possible restore the SimProcedures with the real addresses inside the concrete process.
        4- Set an inspect point to sync the segments register as soon as they are read during the symbolic execution.
        5- Flush all the pages loaded until now.

        :return:

def sync(self):
        """
        Handle the switch between the concrete execution and angr.
        This method takes care of:
        1- Synchronize registers.
        2- Set a concrete target to the memory backer so the memory reads are redirected in the concrete process memory.
        3- If possible restore the SimProcedures with the real addresses inside the concrete process.
        4- Set an inspect point to sync the segments register as soon as they are read during the symbolic execution.
        5- Flush all the pages loaded until now.

        :return:
        """

        def _sync_segments(state):
            """
            Segment registers synchronization is on demand as soon as the
            symbolic execution access a segment register.
            """
            concr_target = state.project.concrete_target

            if isinstance(state.arch, ArchAMD64):
                state.project.simos.initialize_segment_register_x64(state, concr_target)
            elif isinstance(state.arch, ArchX86):
                gdt = state.project.simos.initialize_gdt_x86(state, concr_target)
                state.concrete.whitelist.append((gdt.addr, gdt.addr + gdt.limit))

            state.inspect.remove_breakpoint('reg_read', bp=state.concrete.fs_register_bp)
            state.concrete.segment_registers_initialized = True

            state.concrete.fs_register_bp = None

        l.debug("Sync the state with the concrete memory inside the Concrete plugin")

        target = self.state.project.concrete_target

        # Setting a concrete memory backend
        self.state.memory.mem._memory_backer.set_concrete_target(target)

        # Sync angr registers with the one getting from the concrete target
        # registers that we don't want to concretize.
        l.debug("Synchronizing general purpose registers")

        to_sync_register = list(filter(lambda x: x.concrete, self.state.arch.register_list))

        for register in to_sync_register:

            # before let's sync all the subregisters of the current register.
            # sometimes this can be helpful ( i.e. ymmm0 e xmm0 )
            if register.subregisters:
                subregisters_names = map(lambda x: x[0], register.subregisters)
                self._sync_registers(subregisters_names, target)

            # finally let's synchronize the whole register
            self._sync_registers([register.name], target)

        if self.synchronize_cle:
            self._sync_cle(target)

        # Synchronize the imported functions addresses (.got, IAT) in the
        # concrete process with ones used in the SimProcedures dictionary
        if self.state.project._should_use_sim_procedures and not self.state.project.loader.main_object.pic:
            l.debug("Restoring SimProc using concrete memory")

            for reloc in self.state.project.loader.main_object.relocs:
                if reloc.symbol:  # consider only reloc with a symbol
                    l.debug("Trying to re-hook SimProc %s", reloc.symbol.name)
                    # l.debug("reloc.rebased_addr: %#x " % reloc.rebased_addr)
                    func_address = target.read_memory(reloc.rebased_addr, self.state.project.arch.bits / 8)
                    func_address = struct.unpack(self.state.project.arch.struct_fmt(), func_address)[0]
                    l.debug("Function address hook is now: %#x ", func_address)
                    self.state.project.rehook_symbol(func_address, reloc.symbol.name)

                    if self.synchronize_cle and not self.state.project.loader.main_object.contains_addr(func_address):
                        old_func_symbol = self.state.project.loader.find_symbol(reloc.symbol.name)

                        if old_func_symbol:  # if we actually have a symbol
                            owner_obj = old_func_symbol.owner

                            # calculating the new real address
                            new_relative_address = func_address - owner_obj.mapped_base

                            new_func_symbol = cle.backends.Symbol(owner_obj, old_func_symbol.name, new_relative_address,
                                                                  old_func_symbol.size, old_func_symbol.type)

                            for new_reloc in self.state.project.loader.find_relevant_relocations(old_func_symbol.name):
                                if new_reloc.symbol.name == new_func_symbol.name and \
                                        new_reloc.value != new_func_symbol.rebased_addr:

                                    l.debug("Updating CLE symbols metadata, moving %s from 0x%x to 0x%x",
                                            new_reloc.symbol.name,
                                            new_reloc.value,
                                            new_func_symbol.rebased_addr)

                                    new_reloc.resolve(new_func_symbol)
                                    new_reloc.relocate([])

        else:
            l.debug("SimProc not restored, you are going to simulate also the code of external libraries!")

        # flush the angr memory in order to synchronize them with the content of the
        # concrete process memory when a read/write to the page is performed
        self.state.memory.flush_pages(self.whitelist)
        l.info("Exiting SimEngineConcrete: simulated address %x concrete address %x ", self.state.addr,
               target.read_register("pc"))

        # now we have to register a SimInspect in order to synchronize the segments register
        # on demand when the symbolic execution accesses it
        if not self.segment_registers_callback_initialized:
            segment_register_name = self.state.project.simos.get_segment_register_name()
            if segment_register_name:
                self.fs_register_bp = self.state.inspect.b('reg_read',
                                                           reg_read_offset=segment_register_name,
                                                           action=_sync_segments)

                self.segment_registers_callback_initialized = True

                l.debug("Set SimInspect breakpoint to the new state!")
            else:
                l.error("Can't set breakpoint to synchronize segments registers, horrible things will happen.")