(self, addr, all_jobs, job, exit_target, jumpkind)
return new_call_stack
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
Creates a new call stack, and according to the jumpkind performs appropriate actions.
Creates a new call stack and according to the jumpkind performs appropriate actions .
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
def _create_new_call_stack ( self , addr , all_jobs , job , exit_target , jumpkind ) : 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