docs: def _create_new_call_stack(self, addr, all_jobs, job, exit_target, jumpkind):
          """
          Creates a new call stack, and according to the jumpkind performs appropriate actions.
  
          :param int addr:                          Address to create at.
          :param Simsuccessors all_jobs:            Jobs to get stack pointer from or return address.
          :param CFGJob job:                        CFGJob to copy current call stack from.
          :param int exit_target:                   Address of exit target.
          :param str jumpkind:                      The type of jump performed.
          :returns:                                 New call stack for target block.
          :rtype:                                   CallStack
          """
  
          if self._is_call_jumpkind(jumpkind):
              new_call_stack = job.call_stack_copy()
              # Notice that in ARM, there are some freaking instructions
              # like
              # BLEQ <address>
              # It should give us three exits: Ijk_Call, Ijk_Boring, and
              # Ijk_Ret. The last exit is simulated.
              # Notice: We assume the last exit is the simulated one
              if len(all_jobs) > 1 and all_jobs[-1].history.jumpkind == "Ijk_FakeRet":
                  se = all_jobs[-1].solver
                  retn_target_addr = se.eval_one(all_jobs[-1].ip, default=0)
                  sp = se.eval_one(all_jobs[-1].regs.sp, default=0)
  
                  new_call_stack = new_call_stack.call(addr, exit_target,
                                      retn_target=retn_target_addr,
                                      stack_pointer=sp)
  
              elif jumpkind.startswith('Ijk_Sys') and len(all_jobs) == 1:
                  # This is a syscall. It returns to the same address as itself (with a different jumpkind)
                  retn_target_addr = exit_target
                  se = all_jobs[0].solver
                  sp = se.eval_one(all_jobs[0].regs.sp, default=0)
                  new_call_stack = new_call_stack.call(addr, exit_target,
                                      retn_target=retn_target_addr,
                                      stack_pointer=sp)
  
              else:
                  # We don't have a fake return exit available, which means
                  # this call doesn't return.
                  new_call_stack = CallStack()
                  se = all_jobs[-1].solver
                  sp = se.eval_one(all_jobs[-1].regs.sp, default=0)
  
                  new_call_stack = new_call_stack.call(addr, exit_target, retn_target=None, stack_pointer=sp)
  
          elif jumpkind == "Ijk_Ret":
              # Normal return
              new_call_stack = job.call_stack_copy()
              try:
                  new_call_stack = new_call_stack.ret(exit_target)
              except SimEmptyCallStackError:
                  pass
  
              se = all_jobs[-1].solver
              sp = se.eval_one(all_jobs[-1].regs.sp, default=0)
              old_sp = job.current_stack_pointer
  
              # Calculate the delta of stack pointer
              if sp is not None and old_sp is not None:
                  delta = sp - old_sp
                  func_addr = job.func_addr
  
                  if self.kb.functions.function(func_addr) is None:
                      # Create the function if it doesn't exist
                      # FIXME: But hell, why doesn't it exist in the first place?
                      l.error("Function 0x%x doesn't exist in function manager although it should be there."
                              "Look into this issue later.",
                              func_addr)
                      self.kb.functions.function(func_addr, create=True)
  
                  # Set sp_delta of the function
                  self.kb.functions.function(func_addr, create=True).sp_delta = delta
  
          elif jumpkind == 'Ijk_FakeRet':
              # The fake return...
              new_call_stack = job.call_stack
  
          else:
              # although the jumpkind is not Ijk_Call, it may still jump to a new function... let's see
              if self.project.is_hooked(exit_target):
                  hooker = self.project.hooked_by(exit_target)
                  if not hooker is procedures.stubs.UserHook.UserHook:
                      # if it's not a UserHook, it must be a function
                      # Update the function address of the most recent call stack frame
                      new_call_stack = job.call_stack_copy()
                      new_call_stack.current_function_address = exit_target
  
                  else:
                      # TODO: We need a way to mark if a user hook is a function or not
                      # TODO: We can add a map in Project to store this information
                      # For now we are just assuming they are not functions, which is mostly the case
                      new_call_stack = job.call_stack
  
              else:
                  # Normal control flow transition
                  new_call_stack = job.call_stack
  
          return new_call_stack