(self, state, ret_addr, args, prototype, stack_base=None, alloc_base=None, grow_like_stack=True)
This function performs the actions of the caller getting ready to jump into a function.

        :param state:           The SimState to operate on
        :param ret_addr:        The address to return to when the called function finishes
        :param args:            The list of arguments that that the called function will see
        :param prototype:       The signature of the call you're making. Should include variadic args concretely.
        :param stack_base:      An optional pointer to use as the top of the stack, circa the function entry point
        :param alloc_base:      An optional pointer to use as the place to put excess argument data
        :param grow_like_stack: When allocating data at alloc_base, whether to allocate at decreasing addresses

        The idea here is that you can provide almost any kind of python type in `args` and it'll be translated to a
        binary format to be placed into simulated memory. Lists (representing arrays) must be entirely elements of the
        same type and size, while tuples (representing structs) can be elements of any type and size.
        If you'd like there to be a pointer to a given value, wrap the value in a `PointerWrapper`.

        If stack_base is not provided, the current stack pointer will be used, and it will be updated.
        If alloc_base is not provided, the stack base will be used and grow_like_stack will implicitly be True.

        grow_like_stack controls the behavior of allocating data at alloc_base. When data from args needs to be wrapped
        in a pointer, the pointer needs to point somewhere, so that data is dumped into memory at alloc_base. If you
        set alloc_base to point to somewhere other than the stack, set grow_like_stack to False so that sequential
        allocations happen at increasing addresses.
This function performs the actions of the caller getting ready to jump into a function.
This function performs the actions of the caller getting ready to jump into a function .
def setup_callsite(self, state, ret_addr, args, prototype, stack_base=None, alloc_base=None, grow_like_stack=True):
        """
        This function performs the actions of the caller getting ready to jump into a function.

        :param state:           The SimState to operate on
        :param ret_addr:        The address to return to when the called function finishes
        :param args:            The list of arguments that that the called function will see
        :param prototype:       The signature of the call you're making. Should include variadic args concretely.
        :param stack_base:      An optional pointer to use as the top of the stack, circa the function entry point
        :param alloc_base:      An optional pointer to use as the place to put excess argument data
        :param grow_like_stack: When allocating data at alloc_base, whether to allocate at decreasing addresses

        The idea here is that you can provide almost any kind of python type in `args` and it'll be translated to a
        binary format to be placed into simulated memory. Lists (representing arrays) must be entirely elements of the
        same type and size, while tuples (representing structs) can be elements of any type and size.
        If you'd like there to be a pointer to a given value, wrap the value in a `PointerWrapper`.

        If stack_base is not provided, the current stack pointer will be used, and it will be updated.
        If alloc_base is not provided, the stack base will be used and grow_like_stack will implicitly be True.

        grow_like_stack controls the behavior of allocating data at alloc_base. When data from args needs to be wrapped
        in a pointer, the pointer needs to point somewhere, so that data is dumped into memory at alloc_base. If you
        set alloc_base to point to somewhere other than the stack, set grow_like_stack to False so that sequential
        allocations happen at increasing addresses.
        """

        # STEP 0: clerical work

        allocator = AllocHelper(self.arch.bits)
        if type(prototype) is str:
            prototype = parse_signature(prototype, arch=self.arch)
        elif prototype._arch is None:
            prototype = prototype.with_arch(self.arch)

        #
        # STEP 1: convert all values into serialized form
        # this entails creating the vals list of simple values to store and also populating the allocator's
        # understanding of what aux data needs to be stored
        # This is also where we compute arg locations (arg_locs)
        #

        vals = [self._standardize_value(arg, ty, state, allocator.dump) for arg, ty in zip(args, prototype.args)]
        arg_locs = self.arg_locs(prototype)

        # step 1.5, gotta handle the SimReferenceArguments correctly
        for i, (loc, val) in enumerate(zip(arg_locs, vals)):
            if not isinstance(loc, SimReferenceArgument):
                continue
            dumped = allocator.dump(val, state, loc=val.main_loc)
            vals[i] = dumped
            arg_locs[i] = val.ptr_loc

        # step 1.75 allocate implicit outparam stuff
        if self.return_in_implicit_outparam(prototype.returnty):
            loc = self.return_val(prototype.returnty)
            assert isinstance(loc, SimReferenceArgument)
            # hack: because the allocator gives us a pointer that needs to be translated, we need to shove it into
            # the args list so it'll be translated and stored once everything is laid out
            vals.append(allocator.alloc(loc.main_loc.size))
            arg_locs.append(loc.ptr_loc)

        #
        # STEP 2: decide on memory storage locations
        # implement the contract for stack_base/alloc_base/grow_like_stack
        # after this, stack_base should be the final stack pointer, alloc_base should be the final aux storage location,
        # and the stack pointer should be updated
        #

        if stack_base is None:
            if alloc_base is None:
                alloc_size = allocator.size()
                state.regs.sp -= alloc_size
                alloc_base = state.regs.sp
                grow_like_stack = False

            state.regs.sp -= self.stack_space(arg_locs)

            # handle alignment
            alignment = (state.regs.sp + self.STACKARG_SP_DIFF) % self.STACK_ALIGNMENT
            state.regs.sp -= alignment

        else:
            state.regs.sp = stack_base

            if alloc_base is None:
                alloc_base = stack_base + self.stack_space(arg_locs)
                grow_like_stack = False

        if grow_like_stack:
            alloc_base -= allocator.size()
        if type(alloc_base) is int:
            alloc_base = claripy.BVV(alloc_base, state.arch.bits)

        for i, val in enumerate(vals):
            vals[i] = allocator.translate(val, alloc_base)

        #
        # STEP 3: store everything!
        #

        allocator.apply(state, alloc_base)

        for loc, val in zip(arg_locs, vals):
            loc.set_value(state, val, stack_base=stack_base)
        self.return_addr.set_value(state, ret_addr, stack_base=stack_base)
def setup_callsite ( self , state , ret_addr , args , prototype , stack_base = None , alloc_base = None , grow_like_stack = True ) : # STEP 0: clerical work allocator = AllocHelper ( self . arch . bits ) if type ( prototype ) is str : prototype = parse_signature ( prototype , arch = self . arch ) elif prototype . _arch is None : prototype = prototype . with_arch ( self . arch ) # # STEP 1: convert all values into serialized form # this entails creating the vals list of simple values to store and also populating the allocator's # understanding of what aux data needs to be stored # This is also where we compute arg locations (arg_locs) # vals = [ self . _standardize_value ( arg , ty , state , allocator . dump ) for arg , ty in zip ( args , prototype . args ) ] arg_locs = self . arg_locs ( prototype ) # step 1.5, gotta handle the SimReferenceArguments correctly for i , ( loc , val ) in enumerate ( zip ( arg_locs , vals ) ) : if not isinstance ( loc , SimReferenceArgument ) : continue dumped = allocator . dump ( val , state , loc = val . main_loc ) vals [ i ] = dumped arg_locs [ i ] = val . ptr_loc # step 1.75 allocate implicit outparam stuff if self . return_in_implicit_outparam ( prototype . returnty ) : loc = self . return_val ( prototype . returnty ) assert isinstance ( loc , SimReferenceArgument ) # hack: because the allocator gives us a pointer that needs to be translated, we need to shove it into # the args list so it'll be translated and stored once everything is laid out vals . append ( allocator . alloc ( loc . main_loc . size ) ) arg_locs . append ( loc . ptr_loc ) # # STEP 2: decide on memory storage locations # implement the contract for stack_base/alloc_base/grow_like_stack # after this, stack_base should be the final stack pointer, alloc_base should be the final aux storage location, # and the stack pointer should be updated # if stack_base is None : if alloc_base is None : alloc_size = allocator . size ( ) state . regs . sp -= alloc_size alloc_base = state . regs . sp grow_like_stack = False state . regs . sp -= self . stack_space ( arg_locs ) # handle alignment alignment = ( state . regs . sp + self . STACKARG_SP_DIFF ) % self . STACK_ALIGNMENT state . regs . sp -= alignment else : state . regs . sp = stack_base if alloc_base is None : alloc_base = stack_base + self . stack_space ( arg_locs ) grow_like_stack = False if grow_like_stack : alloc_base -= allocator . size ( ) if type ( alloc_base ) is int : alloc_base = claripy . BVV ( alloc_base , state . arch . bits ) for i , val in enumerate ( vals ) : vals [ i ] = allocator . translate ( val , alloc_base ) # # STEP 3: store everything! # allocator . apply ( state , alloc_base ) for loc , val in zip ( arg_locs , vals ) : loc . set_value ( state , val , stack_base = stack_base ) self . return_addr . set_value ( state , ret_addr , stack_base = stack_base )