Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 27 Aug 1995 11:07:50 +1000
From:      Bruce Evans <bde@zeta.org.au>
To:        CVS-commiters@freefall.FreeBSD.org, bde@freefall.FreeBSD.org, cvs-sys@freefall.FreeBSD.org
Subject:   Re: cvs commit: src/sys/vm vm_map.h vm_map.c
Message-ID:  <199508270107.LAA23799@godzilla.zeta.org.au>

next in thread | raw e-mail | index | archive | help
>bde         95/08/26 16:18:39

>  Modified:    sys/vm    vm_map.h vm_map.c
>  Log:
>  Change vm_map_print() to have the correct number and type of args for
>  a ddb command.

Mach apparently used lint to get the args right for all the old ddb
commands.  We used neither prototypes nor lint and got the args wrong
for almost all the recently added ddb commands.  We will soon use
-Wstrict-prototypes to avoid mismatched args.  This is painful to get
right for function pointers.  `gcc -Wstrict-prototypes' warns about
incomplete function pointer types in structs, so we want complete
function pointer types in structs, but completing them exposed about
2000 abuses of incomplete function pointers, including many easy to
fix gratuitous ones like the above.

The abuses include the following:

1) for syscalls.  The conversion from the application's args is
   magic, but it would be nice to limit the type puns to one stage.
   Currently, for the i386, the following occurs:
   a) the app pushes the args onto the user stack.
   b) the args are copied and converted from the user stack to a
      local array `int args[8]'.  The conversion is actually null.
      It works by magic.
   c) the address of the kernel copy of the args is passed to the
      function that handles the syscall, e.g., open().  The address
      has type `int *' and is magically converted to a `struct
      foo_args *' for the function foo().  The effect of the call is
      undefined because the arg types are incompatible.  This is
      with the function pointer type (*sy_call)() having an empty
      arg list.  If (*sy_call)() is declared to match the way it is
      used (this is what I do now), then there are hundreds of
      warnings about bogus initializations of sysent structs.  If
      (*sy_call)() is declared right for calling foo(), then it is
      wrong for calling bar(), although it is very unlikely that
      `struct foo_args *' is physicaly, incompatible with `struct
      bar_args *'.  Perhaps the right method is to pass a `void *'
      or `int *' and convert it in each function, like you have to
      do for qsort().  This would be painful because there are so
      many functions.

2) for protoswitch functions.  The number and type of args sometimes
   depends on the protocol.  This is OK if the function pointer
   type is incomplete and the number and type of args in the callers
   matches the number and type of args in the callees, but this can't
   be checked at compile time using prototypes and more importantly,
   the incomplete function pointer types cause noisy warnings when
   you turn on enough type checking to check plain function calls.
   Perhaps the right method is to use an arbitrary complete function
   pointer type in the struct and cast it in the calls.  This would
   be relatively painless because there aren't many calls.

3) for vfs switch functions.  The args are copied and converted
   (wasting time and space) to vop_foo_args structs.  I think there
   is no problem at run time (the machine-generated conversion
   functions in vnode_if.h correspond to the conversions that
   would fix syscall functions), but if the vnode function pointer
   types are made complete then gcc warns about thousands of
   compile-time conversions without casts in the vfs initializers.
   Adding casts would defeat type checking.  Perhaps the right
   method is to use an arbitrary complete function pointer type
   in the struct and cast it in the conversion functions.  This
   would be relativly painless because the casts can be machine-
   generated.

If everything passed the correct number and type of args then we
could compile the kernel with -mrtd -mregparm to save a few cycles.
-mregparm is officially supported for the i386 in gcc-2.7.0.

Bruce



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199508270107.LAA23799>