docs: def _pre_analysis(self):
          """
          Executed before analysis starts. Necessary initializations are performed here.
  
          :return: None
          """
  
          l.debug("Starting from %#x", self._start)
  
          # initialize the task stack
          self._task_stack = [ ]
  
          # initialize the execution counter dict
          self._execution_counter = defaultdict(int)
  
          # Generate a CFG if no CFG is provided
          if not self._cfg:
              l.debug("Generating a CFG, since none was given...")
              # TODO: can we use a fast CFG instead? note that fast CFG does not care of context sensitivity at all, but
              # TODO: for state merging, we also don't really care about context sensitivity.
              self._cfg = self.project.analyses.CFGEmulated(context_sensitivity_level=self._context_sensitivity_level,
                  starts=(self._start,)
              )
  
          if not self._cfg.normalized:
              l.warning("The given CFG is not normalized, which might impact the performance/accuracy of the VFG "
                        "analysis.")
  
          # Prepare the state
          initial_state = self._prepare_initial_state(self._start, self._initial_state)
          initial_state.ip = self._start
  
          if self.project.arch.name.startswith('MIPS'):
              initial_state.regs.t9 = self._start
  
          # clear function merge points cache
          self._function_merge_points = {}
  
          # Create the initial state
          state = initial_state.copy()
  
          if self._start_at_function:
              # set the return address to an address so we can catch it and terminate the VSA analysis
              # TODO: Properly pick an address that will not conflict with any existing code and data in the program
              self._final_address = 0x4fff0000
              self._set_return_address(state, self._final_address)
  
          call_stack = None
          if not self._start_at_function:
              # we should build a custom call stack
              call_stack = CallStack()
              call_stack = call_stack.call(None, self._function_start, retn_target=self._final_address)
  
          job = VFGJob(state.addr, state, self._context_sensitivity_level,
                       jumpkind='Ijk_Boring', final_return_address=self._final_address,
                       call_stack=call_stack
                       )
          block_id = BlockID.new(state.addr, job.get_call_stack_suffix(), job.jumpkind)
          job._block_id = block_id
  
          self._insert_job(job)
  
          # create the task
          function_analysis_task = FunctionAnalysis(self._function_start, self._final_address)
          function_analysis_task.jobs.append(job)
          self._task_stack.append(function_analysis_task)