Debug and error messages in AIXv3 device drivers and kernel extensions

Marc Kwiatkowski {Host Software-AIX} marc at mercutio.ultra.com
Fri May 24 13:06:02 AEST 1991


Can anyone recommend a good way to do the above?  I am writing
an AIXv3 device driver and would like to write error
messages and debug messages to the standard error device, using
the kernel routine errsave().  I wanted to use a front end
to errsave() to build an appropriate error record.  This required
using vsprintf() in order to accept and then pass on a variable argument
list.  I had in mind something like the following:

    #include <varargs.h>
    #include <sys/err_rec.h>    
    
    #define ERR_ID (1)
    
    #define ERR_NAME "dd"
    #define ERR_FMT  "dd error:"

    static char *err_msg_ptr = (char *)0;
    static int   err_msg_len = 0;

    void
    dd_err_log(format, va_alist)
        va_dcl
    /*
     * This function logs errors to the
     * standard error-log device.
     *
     * Parameters
     * ==========
     * char *format 
     *     printf format string.
     *
     * varargs
     *     Additional printf parameters.
     *
     * Returns
     * =======
     * void
     */
    {
        va_list ap;
        ERR_REC(ERR_REC_MAX) err_rec;    
        int cnt;
        
        va_start(ap);

        /*
         * If first time through, set-up static fields
         * in error record.
         */

        if(err_msg_ptr == (char *)0) {
     
            err_rec.error_id = DD_ERR_ID;
    
            bcopy(DD_ERR_NAME, err_rec.resource_name, ERR_NAMESIZE);
    
            err_msg_ptr = &err_rec.detail_data[0];

            /*
             * Stick the dd_error prefix into the error
             * message formatted string.
             */
    
            cnt = sprintf(err_msg_ptr, "%s", DD_ERR_FMT);
    
            err_msg_ptr += cnt;

            /*
             * Record the amount of the error message formatted
             * string that is available.
             */
            err_msg_len = ERR_REC_MAX - cnt;
        }
        
        cnt = vsprintf(err_msg, format, ap);

	/*
         * If we got an error message larger than can fit
	 * in an error record, then who knows what damage was
         * done by the above vsprintf.  panic, while we still can.
         */
    
        if(cnt > err_msg_len) {
            panic("dd_err_log: error message too long to log:\n\t<%s>\n",
     format);
        }
    
        /*
         * Log message with error devices.
         */
    
        errsave(&err_rec, ERR_REC_SIZE + ERR_REC_MAX);
    
        va_end(ap);
        return;
    }

I just discovered, much to my chagrin, that vsprintf is not supported
in the kernel.  Linking in libc.a causes all the kernel extensions
that I do want to be replaced by the libc.a versions, and, as far
as I can tell, there is no way to extract just vsprintf.o from libc.a.
Even if there were, I'm not sure it would be suitable for use in the
kernel.

So, I'm prevented from writing an error-log front-end that can
gracefully handle variable arguments.  I'm also prevented from
doing in-line macros for sprintf, because the xlc cpp doesn't
support variable argument macros either.  Two obvious, but
incredibly obnoxious solutions are to either, A, parse the format
string myself, or B, write a separate macro for each possible number
of printf-style parameter lists.  I find it hard to believe that
this is how other device-driver and extension writers handle this
problem.  I'd like to hear other solutions if any.  If the solution
is simply to use printf, then what is the point of errsave and the
error device?

I've noticed that AIXv3 seems  to have a number of deficiencies
of this sort.  System requirements strongly suggest you program
a certain way, but when you attempt to do so, you find things
aren't really set up to let you follow the prescribed method.  In addition
to the above example I've also noticed the following:

	The recommend VPD format includes a CRC checksum field.
	If the conscientious programmer wants to stick to the
	recommended VPD format, s/he must write her/his own
	CRC calculation routine, since one was not provided
	as a basic kernel extension.  This does not significantly
	increase the programmer's work, but it does mean that
	each driver will have a redundant piece of code, including
	a 256 byte look-up table.  I think the failure to realize
	this was a glaring oversight.

	Similarly, the kernel memory allocator, xmalloc, requires
	an alignment parameter.  Rather than specifying alignment
	as a power of 2, it requires the exponent.  That is,
	instead of 1024, one specifies an alignment of 10.  This
	format is somewhat peculiar, but would be completely acceptable
	if an integer log2 function were provided, so that I could
	write
		xmalloc(n*PAGESIZE, log2(PAGESIZE), pinned_heap).

	Again, it is no big deal to write a loop shift to calculate
	the log, but again, this is something every driver writer
	will have to do, adding unnecessary bloat to the kernel.

Well, glad I got that off my chest.

I suppose I should submit these as a DCR to IBM.  


	
	






    
    
    
    
        
    
    
    
    
    
    
    
    
    
    
-- 
        Marc P. Kwiatkowski			Ultra Network Technologies
        Internet: marc at ultra.com		101 Daggett Drive
        uucp: ...!ames!ultra!marc		San Jose, CA 95134 USA
        telephone: 408 922 0100 x249



More information about the Comp.unix.aix mailing list