]> git.saurik.com Git - apple/xnu.git/blobdiff - osfmk/kern/printf.c
xnu-1228.3.13.tar.gz
[apple/xnu.git] / osfmk / kern / printf.c
index bf870083e0cc6b3cdbf52d694d20fcee598b69a9..6faceb7aaa58dbd44bd96e28c31bedfc399f312b 100644 (file)
@@ -1,23 +1,29 @@
 /*
- * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  * 
- * The contents of this file constitute Original Code as defined in and
- * are subject to the Apple Public Source License Version 1.1 (the
- * "License").  You may not use this file except in compliance with the
- * License.  Please obtain a copy of the License at
- * http://www.apple.com/publicsource and read it before using this file.
+ * 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. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
  * 
- * This Original Code and all software distributed under the License are
- * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * 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 OR NON-INFRINGEMENT.  Please see the
- * License for the specific language governing rights and limitations
- * under the License.
+ * 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@
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
  */
 /*
  * @OSF_COPYRIGHT@
@@ -78,6 +84,8 @@
  *     %u      unsigned conversion
  *     %x      hexadecimal conversion
  *     %X      hexadecimal conversion with capital letters
+ *      %D      hexdump, ptr & separator string ("%6D", ptr, ":") -> XX:XX:XX:XX:XX:XX
+ *              if you use, "%*D" then there's a length, the data ptr and then the separator
  *     %o      octal conversion
  *     %c      character
  *     %s      string
@@ -89,8 +97,6 @@
  *  This version does not implement %f, %e, or %g.  It accepts, but
  *  ignores, an `l' as in %ld, %lo, %lx, and %lu, and therefore will not
  *  work correctly on machines for which sizeof(long) != sizeof(int).
- *  It does not even parse %D, %O, or %U; you should be using %ld, %o and
- *  %lu if you mean long conversion.
  *
  *  As mentioned, this version does not return any reasonable value.
  *
  *  long as this notice is incorporated.
  *
  *  Steve Summit 3/25/87
+ *
+ *  Tweaked for long long support and extended to support the hexdump %D
+ *  specifier by dbg 05/02/02.
  */
 
 /*
  *     D,U,O,Z same as corresponding lower-case versions
  *             (compatibility)
  */
+/*
+ * Added support for print long long (64-bit) integers.
+ * Use %lld, %Ld or %qd to print a 64-bit int.  Other
+ * output bases such as x, X, u, U, o, and O also work.
+ */
 
+#include <debug.h>
+#include <mach_kdb.h>
+#include <mach_kdp.h>
 #include <platforms.h>
 #include <mach/boolean.h>
-#include <cpus.h>
 #include <kern/cpu_number.h>
 #include <kern/lock.h>
 #include <kern/thread.h>
 #ifdef  MACH_BSD
 #include <sys/msgbuf.h>
 #endif
+#include <console/serial_protos.h>
 
 #ifdef __ppc__
 #include <ppc/Firmware.h>
 #endif
 
-/*
- * Forward declarations
- */
-void printnum(
-       register unsigned int   u,
-       register int            base,
-       void                    (*putc)(char));
-
-
 #define isdigit(d) ((d) >= '0' && (d) <= '9')
 #define Ctod(c) ((c) - '0')
 
-#define MAXBUF (sizeof(long int) * 8)           /* enough for binary */
+#define MAXBUF (sizeof(long long int) * 8)     /* enough for binary */
+static char digs[] = "0123456789abcdef";
 
-void
+
+#if CONFIG_NO_PRINTF_STRINGS
+#undef printf(x, ...)
+#endif
+
+static int
 printnum(
-       register unsigned int   u,              /* number to print */
-       register int            base,
-       void                    (*putc)(char))
+       unsigned long long int  u,      /* number to print */
+       int             base,
+       void                    (*putc)(int, void *),
+       void                    *arg)
 {
        char    buf[MAXBUF];    /* build number here */
-       register char * p = &buf[MAXBUF-1];
-       static char digs[] = "0123456789abcdef";
+       char *  p = &buf[MAXBUF-1];
+       int nprinted = 0;
 
        do {
            *p-- = digs[u % base];
            u /= base;
        } while (u != 0);
 
-       while (++p != &buf[MAXBUF])
-           (*putc)(*p);
+       while (++p != &buf[MAXBUF]) {
+           (*putc)(*p, arg);
+           nprinted++;
+       }
 
+       return nprinted;
 }
 
 boolean_t      _doprnt_truncates = FALSE;
 
-void 
-_doprnt(
-       register const char     *fmt,
+int
+__doprnt(
+       const char      *fmt,
        va_list                 *argp,
                                                /* character output routine */
-       void                    (*putc)(char),
+       void                    (*putc)(int, void *arg),
+       void                    *arg,
        int                     radix)          /* default radix - for '%r' */
 {
        int             length;
        int             prec;
        boolean_t       ladjust;
        char            padc;
-       long            n;
-       unsigned long   u;
+       long long               n;
+       unsigned long long      u;
        int             plus_sign;
        int             sign_char;
        boolean_t       altfmt, truncate;
        int             base;
-       register char   c;
+       char    c;
        int             capitals;
+       int             long_long;
+       int             nprinted = 0;
 
        while ((c = *fmt) != '\0') {
            if (c != '%') {
-               (*putc)(c);
+               (*putc)(c, arg);
+               nprinted++;
                fmt++;
                continue;
            }
 
            fmt++;
 
+           long_long = 0;
            length = 0;
            prec = -1;
            ladjust = FALSE;
@@ -290,8 +313,16 @@ _doprnt(
                }
            }
 
-           if (c == 'l')
+           if (c == 'l') {
                c = *++fmt;     /* need it if sizeof(int) < sizeof(long) */
+               if (c == 'l') {
+                   long_long = 1;
+                   c = *++fmt;
+               }       
+           } else if (c == 'q' || c == 'L') {
+               long_long = 1;
+               c = *++fmt;
+           } 
 
            truncate = FALSE;
            capitals=0;         /* Assume lower case printing */
@@ -304,10 +335,14 @@ _doprnt(
                    boolean_t     any;
                    register int  i;
 
-                   u = va_arg(*argp, unsigned long);
+                   if (long_long) {
+                       u = va_arg(*argp, unsigned long long);
+                   } else {
+                       u = va_arg(*argp, unsigned long);
+                   }
                    p = va_arg(*argp, char *);
                    base = *p++;
-                   printnum(u, base, putc);
+                   nprinted += printnum(u, base, putc, arg);
 
                    if (u == 0)
                        break;
@@ -322,55 +357,64 @@ _doprnt(
                             */
                            register int j;
                            if (any)
-                               (*putc)(',');
+                               (*putc)(',', arg);
                            else {
-                               (*putc)('<');
+                               (*putc)('<', arg);
                                any = TRUE;
                            }
+                           nprinted++;
                            j = *p++;
                            if (*fmt == 'B')
                                j = 32 - j;
-                           for (; (c = *p) > 32; p++)
-                               (*putc)(c);
-                           printnum((unsigned)( (u>>(j-1)) & ((2<<(i-j))-1)),
-                                       base, putc);
+                           for (; (c = *p) > 32; p++) {
+                               (*putc)(c, arg);
+                               nprinted++;
+                           }
+                           nprinted += printnum((unsigned)( (u>>(j-1)) & ((2<<(i-j))-1)),
+                                                base, putc, arg);
                        }
                        else if (u & (1<<(i-1))) {
                            if (any)
-                               (*putc)(',');
+                               (*putc)(',', arg);
                            else {
-                               (*putc)('<');
+                               (*putc)('<', arg);
                                any = TRUE;
                            }
-                           for (; (c = *p) > 32; p++)
-                               (*putc)(c);
+                           nprinted++;
+                           for (; (c = *p) > 32; p++) {
+                               (*putc)(c, arg);
+                               nprinted++;
+                           }
                        }
                        else {
                            for (; *p > 32; p++)
                                continue;
                        }
                    }
-                   if (any)
-                       (*putc)('>');
+                   if (any) {
+                       (*putc)('>', arg);
+                       nprinted++;
+                   }
                    break;
                }
 
                case 'c':
                    c = va_arg(*argp, int);
-                   (*putc)(c);
+                   (*putc)(c, arg);
+                   nprinted++;
                    break;
 
                case 's':
                {
-                   register char *p;
-                   register char *p2;
+                   register const char *p;
+                   register const char *p2;
 
                    if (prec == -1)
                        prec = 0x7fffffff;      /* MAXINT */
 
                    p = va_arg(*argp, char *);
 
-                   if (p == (char *)0)
+                   if (p == NULL)
                        p = "";
 
                    if (length > 0 && !ladjust) {
@@ -383,8 +427,9 @@ _doprnt(
                        p = p2;
 
                        while (n < length) {
-                           (*putc)(' ');
+                           (*putc)(' ', arg);
                            n++;
+                           nprinted++;
                        }
                    }
 
@@ -394,13 +439,15 @@ _doprnt(
                        if (++n > prec || (length > 0 && n > length))
                            break;
 
-                       (*putc)(*p++);
+                       (*putc)(*p++, arg);
+                       nprinted++;
                    }
 
                    if (n < length && ladjust) {
                        while (n < length) {
-                           (*putc)(' ');
+                           (*putc)(' ', arg);
                            n++;
+                           nprinted++;
                        }
                    }
 
@@ -413,9 +460,31 @@ _doprnt(
                    base = 8;
                    goto print_unsigned;
 
+               case 'D': {
+                   unsigned char *up;
+                   char *q, *p;
+                   
+                       up = (unsigned char *)va_arg(*argp, unsigned char *);
+                       p = (char *)va_arg(*argp, char *);
+                       if (length == -1)
+                               length = 16;
+                       while(length--) {
+                               (*putc)(digs[(*up >> 4)], arg);
+                               (*putc)(digs[(*up & 0x0f)], arg);
+                               nprinted += 2;
+                               up++;
+                               if (length) {
+                                   for (q=p;*q;q++) {
+                                               (*putc)(*q, arg);
+                                               nprinted++;
+                                   }
+                               }
+                       }
+                       break;
+               }
+
                case 'd':
                    truncate = _doprnt_truncates;
-               case 'D':
                    base = 10;
                    goto print_signed;
 
@@ -460,7 +529,11 @@ _doprnt(
                    goto print_unsigned;
 
                print_signed:
-                   n = va_arg(*argp, long);
+                   if (long_long) {
+                       n = va_arg(*argp, long long);
+                   } else {
+                       n = va_arg(*argp, long);
+                   }
                    if (n >= 0) {
                        u = n;
                        sign_char = plus_sign;
@@ -472,7 +545,11 @@ _doprnt(
                    goto print_num;
 
                print_unsigned:
-                   u = va_arg(*argp, unsigned long);
+                   if (long_long) {
+                       u = va_arg(*argp, unsigned long long);
+                   } else { 
+                       u = va_arg(*argp, unsigned long);
+                   }
                    goto print_num;
 
                print_num:
@@ -480,9 +557,9 @@ _doprnt(
                    char        buf[MAXBUF];    /* build number here */
                    register char *     p = &buf[MAXBUF-1];
                    static char digits[] = "0123456789abcdef0123456789ABCDEF";
-                   char *prefix = 0;
+                   const char *prefix = NULL;
 
-                   if (truncate) u = (long)((int)(u));
+                   if (truncate) u = (long long)((int)(u));
 
                    if (u != 0 && altfmt) {
                        if (base == 8)
@@ -501,29 +578,42 @@ _doprnt(
                    if (sign_char)
                        length--;
                    if (prefix)
-                       length -= strlen((const char *) prefix);
+                       length -= strlen(prefix);
 
                    if (padc == ' ' && !ladjust) {
                        /* blank padding goes before prefix */
-                       while (--length >= 0)
-                           (*putc)(' ');
+                       while (--length >= 0) {
+                           (*putc)(' ', arg);
+                           nprinted++;
+                       }                           
+                   }
+                   if (sign_char) {
+                       (*putc)(sign_char, arg);
+                       nprinted++;
+                   }
+                   if (prefix) {
+                       while (*prefix) {
+                           (*putc)(*prefix++, arg);
+                           nprinted++;
+                       }
                    }
-                   if (sign_char)
-                       (*putc)(sign_char);
-                   if (prefix)
-                       while (*prefix)
-                           (*putc)(*prefix++);
                    if (padc == '0') {
                        /* zero padding goes after sign and prefix */
-                       while (--length >= 0)
-                           (*putc)('0');
+                       while (--length >= 0) {
+                           (*putc)('0', arg);
+                           nprinted++;
+                       }                           
                    }
-                   while (++p != &buf[MAXBUF])
-                       (*putc)(*p);
-
+                   while (++p != &buf[MAXBUF]) {
+                       (*putc)(*p, arg);
+                       nprinted++;
+                   }
+                   
                    if (ladjust) {
-                       while (--length >= 0)
-                           (*putc)(' ');
+                       while (--length >= 0) {
+                           (*putc)(' ', arg);
+                           nprinted++;
+                       }
                    }
                    break;
                }
@@ -533,10 +623,32 @@ _doprnt(
                    break;
 
                default:
-                   (*putc)(c);
+                   (*putc)(c, arg);
+                   nprinted++;
            }
        fmt++;
        }
+
+       return nprinted;
+}
+
+static void
+dummy_putc(int ch, void *arg)
+{
+    void (*real_putc)(char) = arg;
+    
+    real_putc(ch);
+}
+
+void 
+_doprnt(
+       register const char     *fmt,
+       va_list                 *argp,
+                                               /* character output routine */
+       void                    (*putc)(char),
+       int                     radix)          /* default radix - for '%r' */
+{
+    __doprnt(fmt, argp, dummy_putc, putc, radix);
 }
 
 #if    MP_PRINTF 
@@ -545,7 +657,10 @@ boolean_t  new_printf_cpu_number = FALSE;
 
 
 decl_simple_lock_data(,printf_lock)
-decl_mutex_data(,sprintf_lock)
+decl_simple_lock_data(,bsd_log_spinlock)
+extern void bsd_log_init(void);
+void bsd_log_lock(void);
+void bsd_log_unlock(void);
 
 void
 printf_init(void)
@@ -553,8 +668,21 @@ printf_init(void)
        /*
         * Lock is only really needed after the first thread is created.
         */
-       simple_lock_init(&printf_lock, ETAP_MISC_PRINTF);
-       mutex_init(&sprintf_lock, ETAP_MISC_PRINTF);
+       simple_lock_init(&printf_lock, 0);
+       simple_lock_init(&bsd_log_spinlock, 0);
+       bsd_log_init();
+}
+
+void
+bsd_log_lock(void)
+{
+       simple_lock(&bsd_log_spinlock);
+}
+
+void
+bsd_log_unlock(void)
+{
+       simple_unlock(&bsd_log_spinlock);
 }
 
 /* derived from boot_gets */
@@ -606,13 +734,13 @@ safe_gets(
        }
 }
 
+extern int disableConsoleOutput;
+
 void
 conslog_putc(
        char c)
 {
-       extern unsigned int debug_mode, disableDebugOuput, disableConsoleOutput;
-
-       if ((debug_mode && !disableDebugOuput) || !disableConsoleOutput)
+       if ((debug_mode && !disable_debug_output) || !disableConsoleOutput)
                cnputc(c);
 
 #ifdef MACH_BSD
@@ -620,38 +748,91 @@ conslog_putc(
 #endif
 }
 
+#if    MACH_KDB
+extern void db_putchar(char c);
+#endif
+
 void
-printf(const char *fmt, ...)
+dbugprintf(__unused const char *fmt, ...)
 {
+
+#if    MACH_KDB
        va_list listp;
 
-       disable_preemption();
        va_start(listp, fmt);
-       _doprnt(fmt, &listp, conslog_putc, 16);
+       _doprnt(fmt, &listp, db_putchar, 16);
        va_end(listp);
-       enable_preemption();
+#endif
+       return;
+}
+
+int
+printf(const char *fmt, ...)
+{
+       va_list listp;
+
+       if (fmt) {
+               disable_preemption();
+               va_start(listp, fmt);
+               _doprnt(fmt, &listp, conslog_putc, 16);
+               va_end(listp);
+               enable_preemption();
+       }
+       return 0;
+}
+
+void
+consdebug_putc(char c)
+{
+       if ((debug_mode && !disable_debug_output) || !disableConsoleOutput)
+               cnputc(c);
+
+       debug_putc(c);
+
+       if (!console_is_serial())
+               if (!disable_serial_output)
+                       PE_kputc(c);
 }
 
-static char *copybyte_str;
+int
+kdb_printf(const char *fmt, ...)
+{
+       va_list listp;
+
+       va_start(listp, fmt);
+       _doprnt(fmt, &listp, consdebug_putc, 16);
+       va_end(listp);
+       return 0;
+}
 
 static void
-copybyte(
-        char byte)
+copybyte(int c, void *arg)
 {
-  *copybyte_str++ = byte;
-  *copybyte_str = '\0';
+       /*
+        * arg is a pointer (outside pointer) to the pointer
+        * (inside pointer) which points to the character.
+        * We pass a double pointer, so that we can increment
+        * the inside pointer.
+        */
+       char** p = arg; /* cast outside pointer */
+       **p = c;        /* store character */
+       (*p)++;         /* increment inside pointer */
 }
 
+/*
+ * Deprecation Warning:
+ *     sprintf() is being deprecated. Please use snprintf() instead.
+ */
 int
 sprintf(char *buf, const char *fmt, ...)
 {
         va_list listp;
+       char *copybyte_str;
 
         va_start(listp, fmt);
-       mutex_lock(&sprintf_lock);
         copybyte_str = buf;
-        _doprnt(fmt, &listp, copybyte, 16);
-       mutex_unlock(&sprintf_lock);
+        __doprnt(fmt, &listp, copybyte, &copybyte_str, 16);
         va_end(listp);
+       *copybyte_str = '\0';
         return strlen(buf);
 }