/*
 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
 *
 * @APPLE_LICENSE_HEADER_START@
 * 
 * This file contains Original Code and/or Modifications of Original Code
 * as defined in and that are subject to the Apple Public Source License
 * Version 2.0 (the 'License'). You may not use this file except in
 * compliance with the License. Please obtain a copy of the License at
 * http://www.opensource.apple.com/apsl/ and read it before using this
 * file.
 * 
 * The Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 * Please see the License for the specific language governing rights and
 * limitations under the License.
 * 
 * @APPLE_LICENSE_HEADER_END@
 */
#ifndef NO_DYLD_TRACING
#include <stdio.h>
#include <strings.h>
#include "stuff/bool.h"
#include "trace.h"

/*
 * Limit to size of pathname to be encoded.  This number is more or less
 * arbitrary and meant to fit as much of the path as possible without line
 * wrapping.  We can change this (probably a good idea), but beware that
 * performance tools rely on that behavior for VFS_USAGE.
 */
#define NUMPARMS 23

/*
 * trace_with_string() is passed the trace_type and a string.  It does the
 * syscall(180,...) for the trace and then a syscall(180,...) for the string.
 */
void
trace_with_string(
int trace_type,
char *name)
{
    unsigned int i, j, n;
    int namelen;
    int save_namelen;
    long parms[NUMPARMS];
    char buf[4];
    static char *filler;
    int string_identifier;

        filler = ">>>>";
	string_identifier = (SYSCALL_CODE(DYLD_CLASS,
			   		  DYLD_TRACE_STRING_SUBCLASS,
					  DYLD_TRACE_string_type) |
			     DBG_FUNC_NONE);

        /*
	 * If the name is invalid we can't do much, so print a generic trace
	 * message.
	 */
        if(name == NULL){
            syscall(180, trace_type, 0, 0, 0, 0, 0); 
            return;
        }

        /* Collect the pathname for tracing */
        namelen = strlen(name);
	/* fprintf(stderr, "name length: %d name %s: \n", namelen, name); */
        
        if(namelen > (int)(sizeof(parms)))
            namelen = sizeof(parms);

        /* Remember the length of name. */
        save_namelen = namelen;

	/*
         * Store characters in longs.  Longs are the parameters we need to pass
         * to kernel debug functions, so take each 4 character chunk in name, 
         * treat it as a long and copy it into on of the parms which we will
	 * pass to the kernel.  Decrement namelen as we go until all character
	 * are stored. 
	 */
        i = 0;
        while(namelen > 0){
            if(namelen >= 4){
                parms[i++] = *(long *)name;
                name += sizeof(long);
                namelen -= sizeof(long);
            } 
	    /*
             * buf is here to pick up the last few characters when there are no
             * more 4 byte chunks.
	     */
            else{
                for(n = 0; n < (unsigned int)namelen; n++)
                    buf[n] = *name++;
		/*
                 * All characters have been collected.  Now fill the rest of
		 * buff with '>'s if there are more left in the path, or with			 * nulls if the path has been entirely copied.
		 */
                while(n <= 3){
                    if(*name != '\0')
                        buf[n++] = '>';
                    else
                        buf[n++] = 0;
                }
                
                /* Finally, place buf in a parm. */
                parms[i++] = *(long *)&buf[0];

                break;
            }
        }

	/* 
         * Done reading 23 ints of the path into parms.  If we have reached the
	 * end of the path, put zeros in the rest of the parms.  I dunno how we
	 * could reach the first case, where we didn't fit the whole path, but
	 * somehow want to put filler in at the end anyway???
	 */
        while(i < NUMPARMS){
            if(*name != '\0')
                parms[i++] = *(long *)filler;
            else
                parms[i++] = 0;
        }

	/* 
         * String class identifier in arg4 indicates to the trace tool that its 
	 * arguments should be printed as a string.
	 */
        i = 0;
        syscall(180, trace_type, parms[i], parms[i+1], parms[i+2],
		string_identifier, 0);
	i = i + 3;
        /* Finally, loop writing the parms to the trace buffer. */
        for(namelen = save_namelen - 3 * (sizeof(long));
            namelen > 0;
            namelen -=(3 * sizeof(long))){
            /* fprintf(stderr, "trace type: |%d|.\n", trace_type); */
	    j = i;
            syscall(180, string_identifier, parms[j], parms[j+1], parms[j+2],
		    0, 0);
	    i = i + 3;
	}
}
#endif /* defined(NO_DYLD_TRACING) */
