Studio:How do I work around variable arguments for stubs?

From STRIDE Wiki
Revision as of 22:04, 31 January 2008 by Robg (talk | contribs)
Jump to navigation Jump to search

STRIDE does not directly support variable argument lists; however, it is possible to call interfaces with variable arguments as stubs. Currently there is no workaround for proxies or dynamic delegates.
Interfaces with variable arguments can be wrapped using helper functions in the SCL file. The wrapper function depends on the number of variable arguments and the interface.
For example, the UNIX system call "open" is defined as:

extern int open (const char *__file, int __oflag, ...);

In most cases, the variable argument is NULL; however, when creating a file, the file permission can be specified as an optional argument. In this case, it is simplest to call a wrapper function to the SCL file which has 3 arguments (the 3rd one being the mode). The wrapper function would be defined as follows:

static int scl_file_open (const char *file, int oflag, mode_t mode)
{
return open(file, oflag, mode);
}

The wrapper function calls the open interface with the three arguments. The SCL pragmas would be applied to scl_file_open:

#pragma scl_function(scl_file_open)
#pragma scl_string(scl_file_open.file, MAX_FILE_NAME_LENGTH)

Having a wrapper function for each possible variable argument could require a number of different wrapper functions if the variable argument can be of different types (e.g., a pointer to different structures), depending on the mandatory arguments. In this case, it would be easier to define the variable arguments as a union of all possible types. The UNIX system call "ioctl" could be an example of such an interface:

extern int ioctl (int __fd, unsigned long int __request, ...) ;

In most cases the variable argument (if there is one) is a pointer to a structure. The structure depends on the request value. An ioctl request has encoded in it whether the argument is an "in" parameter or "out" parameter, and the size of the variable argument in bytes.

Click here for a list of possible ioctl requests and the variable argument types. In this case, the variable argument could be wrapped by a union. The following example demonstrates a possible union definition in the SCL file:

typedef union
{
struct termios* p_termios; /* TCGETS, TCSETS, TCSETSW, TCSETSF, TIOCGLCKTRMIOS, TIOCSLCKTRMIOS */
struct termio* p_termio; /* TCGETA, TCSETA, TCSETAW, TCSETAF */
int data; /* TCSBRK, TCXONC, TCFLSH, TIOCSCTTY, TCSBRKP, TIOCSBRK, TIOCCBRK, TIOCMIWAIT, TIOCGICOUNT, IOCGHAYESESP, TIOCSHAYESESP */
int* p_int; /* TIOCOUTQ, TIOCMGET, TIOCMBIS,TIOCMBIC, TIOCMSET, TIOCGSOFTCAR, TIOCSSOFTCAR, FIONREAD, TIOCINQ, IOCPKT, FIONBIO, TIOCSETD, TIOCGETD, FIOASYNC, TIOCSERGWILD, TIOCSERSWILD, TIOCSERGETLSR, FIOQSIZE */
pid_t* p_pid; /* TIOCGPGRP, TIOCSPGRP, TIOCGSID */
char* p_char; /* TIOCSTI, TIOCLINUX */
struct winsize* p_winsize; /* TIOCGWINSZ, TIOCSWINSZ */
struct serial_struct* p_serial_struct; /* TIOCGSERIAL, TIOCSSERIAL */
struct async_struct* p_async_struct; /* TIOCSERGSTRUCT */
struct serial_multiport_struct* p_serial_mp; /* TIOCSERGETMULTI, TIOCSERSETMULTI */
/* void: TIOCNXCL, TIOCCONS, TIOCNOTTY, FIONCLEX, FIOCLEX, TIOCSERCONFIG, TIOCEXCL, */ } scl_ioctl_u;

The wrapper function will take a pointer to the union as the third argument. Depending on the request, the variable argument can be an input or output pointer. The request argument (union discriminate) is passed by value and therefore is an input only.

STRIDE does not support output pointers to unions without a discriminate value (or input only discriminate).

To have a discriminate value in both the input and output direction, the request parameter has to be passed as a pointer to the wrapper function. When the request is passed as a pointer, the discriminate is available in both the input and output direction. The wrapper function is defined as follows:

static int scl_ioctl (int fd, unsigned long int* request, scl_ioctl_u* args)
{
return ioctl(fd, *request, args->p_int);
}

Next we need to specify the interface and the union using SCL. The pragmas are:

#pragma scl_function(scl_ioctl)
#pragma scl_ptr(scl_ioctl.args, INOUT, PRIVATE)
#pragma scl_ptr(scl_ioctl.request, INOUT, PRIVATE)
#pragma scl_values(*(scl_ioctl.request), TCGETS, TCSETS, TCSETSW, \ TCSETSF, TCGETA, TCSETA, TCSETAW, TCSETAF, \ TCSBRK, TCXONC, TCFLSH, TIOCEXCL, TIOCNXCL, \ TIOCSCTTY, TIOCGPGRP, TIOCSPGRP, TIOCOUTQ, \ TIOCSTI, TIOCGWINSZ, TIOCSWINSZ, TIOCMGET, \ TIOCMBIS, TIOCMBIC, TIOCMSET, TIOCGSOFTCAR, \ TIOCSSOFTCAR, FIONREAD, TIOCINQ, TIOCLINUX, \ TIOCCONS, TIOCGSERIAL, TIOCSSERIAL, TIOCPKT,\ FIONBIO, TIOCNOTTY, TIOCSETD, TIOCGETD, \ TCSBRKP, TIOCSBRK, TIOCCBRK, \ TIOCGSID, FIONCLEX, FIOCLEX, FIOASYNC, \ TIOCSERCONFIG, TIOCSERGWILD, TIOCSERSWILD, \ TIOCGLCKTRMIOS, TIOCSLCKTRMIOS, \ TIOCSERGSTRUCT, TIOCSERGETLSR, \ TIOCSERGETMULTI, TIOCSERSETMULTI, \ TIOCMIWAIT, TIOCGICOUNT, TIOCGHAYESESP, \ TIOCSHAYESESP, FIOQSIZE);
#pragma scl_union(*(scl_ioctl.args), *(scl_ioctl.request));
#pragma scl_union_activate(*(scl_ioctl.args), p_termios, TCGETS, TCSETS, TCSETSW, TCSETSF, TIOCGLCKTRMIOS, TIOCSLCKTRMIOS);
#pragma scl_union_activate(*(scl_ioctl.args), p_termio, TCGETA, TCSETA, TCSETAW, TCSETAF);
#pragma scl_union_activate(*(scl_ioctl.args), data, TCSBRK, TCXONC, TCFLSH, TIOCSCTTY, TCSBRKP, TIOCSBRK, TIOCCBRK, TIOCMIWAIT, TIOCGICOUNT, TIOCGHAYESESP, TIOCSHAYESESP);
#pragma scl_union_activate(*(scl_ioctl.args), p_int, TIOCOUTQ, TIOCMGET, TIOCMBIS,TIOCMBIC, TIOCMSET, TIOCGSOFTCAR, TIOCSSOFTCAR, FIONREAD, TIOCPKT, FIONBIO, TIOCSETD, TIOCGETD, FIOASYNC, TIOCSERGWILD, TIOCSERSWILD, TIOCSERGETLSR, FIOQSIZE);
#pragma scl_union_activate(*(scl_ioctl.args), p_pid, TIOCGPGRP, TIOCSPGRP, TIOCGSID);
#pragma scl_union_activate(*(scl_ioctl.args), p_char, TIOCSTI, TIOCLINUX);
#pragma scl_union_activate(*(scl_ioctl.args), p_winsize, TIOCGWINSZ, TIOCSWINSZ);
#pragma scl_union_activate(*(scl_ioctl.args), p_serial_struct, TIOCGSERIAL, TIOCSSERIAL);
#pragma scl_union_activate(*(scl_ioctl.args), p_async_struct, TIOCSERGSTRUCT);
#pragma scl_union_activate(*(scl_ioctl.args), p_serial_mp, TIOCSERGETMULTI, TIOCSERSETMULTI);