'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 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`. Any value
that can\'t fit in a register will be automatically put 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 current stack pointer will be used, and it will be updated.
You might not like the results if you provide stack_base but not alloc_base.
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 sequencial
allocations happen at increasing addresses.'

def setup_callsite(self, state, ret_addr, args, stack_base=None, alloc_base=None, grow_like_stack=True):

    allocator = AllocHelper((alloc_base if (alloc_base is not None) else state.regs.sp), grow_like_stack, (self.arch.memory_endness == 'Iend_LE'))
    if (self.func_ty is not None):
        vals = [self._standardize_value(arg, ty, state, allocator.dump) for (arg, ty) in zip(args, self.func_ty.args)]
    else:
        vals = [self._standardize_value(arg, None, state, allocator.dump) for arg in args]
    arg_session = self.arg_session
    arg_locs = ([None] * len(args))
    for (i, (arg, val)) in enumerate(zip(args, vals)):
        if (self.is_fp_value(arg) or ((self.func_ty is not None) and isinstance(self.func_ty.args[i], SimTypeFloat))):
            arg_locs[i] = arg_session.next_arg(is_fp=True, size=(val.length / 8))
            continue
        if ((val.length > state.arch.bits) or ((self.func_ty is None) and isinstance(arg, (str, unicode, list, tuple)))):
            vals[i] = allocator.dump(val, state)
        elif (val.length < state.arch.bits):
            if (self.arch.memory_endness == 'Iend_LE'):
                vals[i] = val.concat(claripy.BVV(0, (state.arch.bits - val.length)))
            else:
                vals[i] = claripy.BVV(0, (state.arch.bits - val.length)).concat(val)
        arg_locs[i] = arg_session.next_arg(is_fp=False, size=(vals[i].length / 8))
    if (alloc_base is None):
        state.regs.sp = allocator.ptr
    if (stack_base is None):
        state.regs.sp -= (self.stack_space(arg_locs) + self.STACKARG_SP_DIFF)
    for (loc, val) in zip(arg_locs, vals):
        loc.set_value(state, val, endness='Iend_BE', stack_base=stack_base)
    self.return_addr.set_value(state, ret_addr, stack_base=stack_base)
