docs: 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.")