]> git.saurik.com Git - apple/xnu.git/blobdiff - osfmk/kern/printf.c
xnu-4903.231.4.tar.gz
[apple/xnu.git] / osfmk / kern / printf.c
index 6faceb7aaa58dbd44bd96e28c31bedfc399f312b..c8abeb624fd7f4d0e07cbc7665d95d8d09a5b754 100644 (file)
@@ -94,9 +94,7 @@
  *     %0m.n   zero-padding
  *     %*.*    width and precision taken from arguments
  *
- *  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).
+ *  This version does not implement %f, %e, or %g.
  *
  *  As mentioned, this version does not return any reasonable value.
  *
  *     +       print '+' if positive
  *     blank   print ' ' if positive
  *
- *     z       signed hexadecimal
+ *     z       set length equal to size_t
  *     r       signed, 'radix'
  *     n       unsigned, 'radix'
  *
  */
 
 #include <debug.h>
-#include <mach_kdb.h>
 #include <mach_kdp.h>
-#include <platforms.h>
 #include <mach/boolean.h>
 #include <kern/cpu_number.h>
-#include <kern/lock.h>
 #include <kern/thread.h>
+#include <kern/debug.h>
 #include <kern/sched_prim.h>
 #include <kern/misc_protos.h>
 #include <stdarg.h>
 #include <sys/msgbuf.h>
 #endif
 #include <console/serial_protos.h>
+#include <os/log_private.h>
 
-#ifdef __ppc__
-#include <ppc/Firmware.h>
+#ifdef __x86_64__
+#include <i386/cpu_data.h>
+#endif /* __x86_64__ */
+
+#if __arm__ || __arm64__
+#include <arm/cpu_data_internal.h>
 #endif
 
+
 #define isdigit(d) ((d) >= '0' && (d) <= '9')
 #define Ctod(c) ((c) - '0')
 
 #define MAXBUF (sizeof(long long int) * 8)     /* enough for binary */
 static char digs[] = "0123456789abcdef";
 
-
 #if CONFIG_NO_PRINTF_STRINGS
-#undef printf(x, ...)
+/* Prevent CPP from breaking the definition below */
+#undef printf
 #endif
 
+int _consume_printf_args(int a __unused, ...)
+{
+    return 0;
+}
+void _consume_kprintf_args(int a __unused, ...)
+{
+}
+
 static int
 printnum(
        unsigned long long int  u,      /* number to print */
@@ -215,14 +225,21 @@ printnum(
 
 boolean_t      _doprnt_truncates = FALSE;
 
+#if (DEVELOPMENT || DEBUG) 
+boolean_t      doprnt_hide_pointers = FALSE;
+#else
+boolean_t      doprnt_hide_pointers = TRUE;
+#endif
+
 int
 __doprnt(
        const char      *fmt,
-       va_list                 *argp,
+       va_list                 argp,
                                                /* character output routine */
        void                    (*putc)(int, void *arg),
        void                    *arg,
-       int                     radix)          /* default radix - for '%r' */
+       int                     radix,          /* default radix - for '%r' */
+       int                     is_log)
 {
        int             length;
        int             prec;
@@ -290,7 +307,7 @@ __doprnt(
                }
            }
            else if (c == '*') {
-               length = va_arg(*argp, int);
+               length = va_arg(argp, int);
                c = *++fmt;
                if (length < 0) {
                    ladjust = !ladjust;
@@ -308,13 +325,15 @@ __doprnt(
                    }
                }
                else if (c == '*') {
-                   prec = va_arg(*argp, int);
+                   prec = va_arg(argp, int);
                    c = *++fmt;
                }
            }
 
            if (c == 'l') {
                c = *++fmt;     /* need it if sizeof(int) < sizeof(long) */
+               if (sizeof(int)<sizeof(long))
+                   long_long = 1;
                if (c == 'l') {
                    long_long = 1;
                    c = *++fmt;
@@ -322,7 +341,14 @@ __doprnt(
            } else if (c == 'q' || c == 'L') {
                long_long = 1;
                c = *++fmt;
-           } 
+           }
+
+           if (c == 'z' || c == 'Z') {
+                   c = *++fmt;
+                   if (sizeof(size_t) == sizeof(unsigned long)){
+                           long_long = 1;
+                   }
+           }
 
            truncate = FALSE;
            capitals=0;         /* Assume lower case printing */
@@ -331,16 +357,16 @@ __doprnt(
                case 'b':
                case 'B':
                {
-                   register char *p;
+                   char *p;
                    boolean_t     any;
-                   register int  i;
+                   int  i;
 
                    if (long_long) {
-                       u = va_arg(*argp, unsigned long long);
+                       u = va_arg(argp, unsigned long long);
                    } else {
-                       u = va_arg(*argp, unsigned long);
+                       u = va_arg(argp, unsigned int);
                    }
-                   p = va_arg(*argp, char *);
+                   p = va_arg(argp, char *);
                    base = *p++;
                    nprinted += printnum(u, base, putc, arg);
 
@@ -355,7 +381,7 @@ __doprnt(
                            /*
                             * Bit field
                             */
-                           register int j;
+                           int j;
                            if (any)
                                (*putc)(',', arg);
                            else {
@@ -399,20 +425,20 @@ __doprnt(
                }
 
                case 'c':
-                   c = va_arg(*argp, int);
+                   c = va_arg(argp, int);
                    (*putc)(c, arg);
                    nprinted++;
                    break;
 
                case 's':
                {
-                   register const char *p;
-                   register const char *p2;
+                   const char *p;
+                   const char *p2;
 
                    if (prec == -1)
                        prec = 0x7fffffff;      /* MAXINT */
 
-                   p = va_arg(*argp, char *);
+                   p = va_arg(argp, char *);
 
                    if (p == NULL)
                        p = "";
@@ -435,12 +461,13 @@ __doprnt(
 
                    n = 0;
 
-                   while (*p != '\0') {
-                       if (++n > prec || (length > 0 && n > length))
-                           break;
-
-                       (*putc)(*p++, arg);
-                       nprinted++;
+                   while ((n < prec) && (!(length > 0 && n >= length))) {
+                           if (*p == '\0') {
+                                   break;
+                           }
+                           (*putc)(*p++, arg);
+                           nprinted++;
+                           n++;
                    }
 
                    if (n < length && ladjust) {
@@ -464,8 +491,8 @@ __doprnt(
                    unsigned char *up;
                    char *q, *p;
                    
-                       up = (unsigned char *)va_arg(*argp, unsigned char *);
-                       p = (char *)va_arg(*argp, char *);
+                       up = (unsigned char *)va_arg(argp, unsigned char *);
+                       p = (char *)va_arg(argp, char *);
                        if (length == -1)
                                length = 16;
                        while(length--) {
@@ -496,6 +523,9 @@ __doprnt(
 
                case 'p':
                    altfmt = TRUE;
+                   if (sizeof(int)<sizeof(void *)) {
+                       long_long = 1;
+                   }
                case 'x':
                    truncate = _doprnt_truncates;
                    base = 16;
@@ -505,17 +535,7 @@ __doprnt(
                    base = 16;
                    capitals=16;        /* Print in upper case */
                    goto print_unsigned;
-
-               case 'z':
-                   truncate = _doprnt_truncates;
-                   base = 16;
-                   goto print_signed;
                        
-               case 'Z':
-                   base = 16;
-                   capitals=16;        /* Print in upper case */
-                   goto print_signed;
-
                case 'r':
                    truncate = _doprnt_truncates;
                case 'R':
@@ -530,9 +550,9 @@ __doprnt(
 
                print_signed:
                    if (long_long) {
-                       n = va_arg(*argp, long long);
+                       n = va_arg(argp, long long);
                    } else {
-                       n = va_arg(*argp, long);
+                       n = va_arg(argp, int);
                    }
                    if (n >= 0) {
                        u = n;
@@ -546,21 +566,37 @@ __doprnt(
 
                print_unsigned:
                    if (long_long) {
-                       u = va_arg(*argp, unsigned long long);
+                       u = va_arg(argp, unsigned long long);
                    } else { 
-                       u = va_arg(*argp, unsigned long);
+                       u = va_arg(argp, unsigned int);
                    }
                    goto print_num;
 
                print_num:
                {
                    char        buf[MAXBUF];    /* build number here */
-                   register char *     p = &buf[MAXBUF-1];
+                   char *      p = &buf[MAXBUF-1];
                    static char digits[] = "0123456789abcdef0123456789ABCDEF";
                    const char *prefix = NULL;
 
                    if (truncate) u = (long long)((int)(u));
 
+                   if (doprnt_hide_pointers && is_log) {
+                       const char str[] = "<ptr>";
+                       const char* strp = str;
+                       int strl = sizeof(str) - 1;
+
+
+                       if (u >= VM_MIN_KERNEL_AND_KEXT_ADDRESS && u <= VM_MAX_KERNEL_ADDRESS) {
+                           while(*strp != '\0') {
+                               (*putc)(*strp, arg);
+                               strp++;
+                           }
+                           nprinted += strl;
+                           break;
+                       }
+                   }
+
                    if (u != 0 && altfmt) {
                        if (base == 8)
                            prefix = "0";
@@ -574,11 +610,11 @@ __doprnt(
                        u /= base;
                    } while (u != 0);
 
-                   length -= (&buf[MAXBUF-1] - p);
+                   length -= (int)(&buf[MAXBUF-1] - p);
                    if (sign_char)
                        length--;
                    if (prefix)
-                       length -= strlen(prefix);
+                       length -= (int)strlen(prefix);
 
                    if (padc == ' ' && !ladjust) {
                        /* blank padding goes before prefix */
@@ -642,27 +678,46 @@ dummy_putc(int ch, void *arg)
 
 void 
 _doprnt(
-       register const char     *fmt,
+       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);
+    __doprnt(fmt, *argp, dummy_putc, putc, radix, FALSE);
+}
+
+void 
+_doprnt_log(
+       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, TRUE);
 }
 
 #if    MP_PRINTF 
 boolean_t      new_printf_cpu_number = FALSE;
 #endif /* MP_PRINTF */
 
-
 decl_simple_lock_data(,printf_lock)
 decl_simple_lock_data(,bsd_log_spinlock)
+
+/*
+ * Defined here to allow lock group to be statically allocated.
+ */
+static lck_grp_t oslog_stream_lock_grp;
+decl_lck_spin_data(,oslog_stream_lock)
+void oslog_lock_init(void);
+
 extern void bsd_log_init(void);
 void bsd_log_lock(void);
 void bsd_log_unlock(void);
 
 void
+
 printf_init(void)
 {
        /*
@@ -685,14 +740,21 @@ bsd_log_unlock(void)
        simple_unlock(&bsd_log_spinlock);
 }
 
+void
+oslog_lock_init(void)
+{
+       lck_grp_init(&oslog_stream_lock_grp, "oslog stream", LCK_GRP_ATTR_NULL);
+       lck_spin_init(&oslog_stream_lock, &oslog_stream_lock_grp, LCK_ATTR_NULL);
+}
+
 /* derived from boot_gets */
 void
 safe_gets(
        char    *str,
        int     maxlen)
 {
-       register char *lp;
-       register int c;
+       char *lp;
+       int c;
        char *strmax = str + maxlen - 1; /* allow space for trailing 0 */
 
        lp = str;
@@ -740,71 +802,173 @@ void
 conslog_putc(
        char c)
 {
-       if ((debug_mode && !disable_debug_output) || !disableConsoleOutput)
+       if (!disableConsoleOutput)
                cnputc(c);
 
 #ifdef MACH_BSD
-       log_putc(c);
+       if (!kernel_debugger_entry_count)
+               log_putc(c);
 #endif
 }
 
-#if    MACH_KDB
-extern void db_putchar(char c);
-#endif
-
 void
-dbugprintf(__unused const char *fmt, ...)
+cons_putc_locked(
+       char c)
 {
+       if (!disableConsoleOutput)
+               cnputc(c);
+}
 
-#if    MACH_KDB
-       va_list listp;
+static int
+vprintf_internal(const char *fmt, va_list ap_in, void *caller)
+{
+       cpu_data_t * cpu_data_p;
+       if (fmt) {
+               struct console_printbuf_state info_data;
+               cpu_data_p = current_cpu_datap();
+
+               va_list ap;
+               va_copy(ap, ap_in);
+               /*
+                * for early boot printf()s console may not be setup,
+                * fallback to good old cnputc
+                */
+               if (cpu_data_p->cpu_console_buf != NULL) {
+                       console_printbuf_state_init(&info_data, TRUE, TRUE);
+                       __doprnt(fmt, ap, console_printbuf_putc, &info_data, 16, TRUE);
+                       console_printbuf_clear(&info_data);
+               } else {
+                       disable_preemption();
+                       _doprnt_log(fmt, &ap, cons_putc_locked, 16);
+                       enable_preemption();
+               }
 
-       va_start(listp, fmt);
-       _doprnt(fmt, &listp, db_putchar, 16);
-       va_end(listp);
-#endif
-       return;
+               va_end(ap);
+
+               os_log_with_args(OS_LOG_DEFAULT, OS_LOG_TYPE_DEFAULT, fmt, ap_in, caller);
+       }
+       return 0;
 }
 
+__attribute__((noinline,not_tail_called))
 int
 printf(const char *fmt, ...)
 {
-       va_list listp;
+       int ret;
 
-       if (fmt) {
-               disable_preemption();
-               va_start(listp, fmt);
-               _doprnt(fmt, &listp, conslog_putc, 16);
-               va_end(listp);
-               enable_preemption();
-       }
-       return 0;
+       va_list ap;
+       va_start(ap, fmt);
+       ret = vprintf_internal(fmt, ap, __builtin_return_address(0));
+       va_end(ap);
+
+       return ret;
+}
+
+__attribute__((noinline,not_tail_called))
+int
+vprintf(const char *fmt, va_list ap)
+{
+       return vprintf_internal(fmt, ap, __builtin_return_address(0));
 }
 
 void
 consdebug_putc(char c)
 {
-       if ((debug_mode && !disable_debug_output) || !disableConsoleOutput)
+       if (!disableConsoleOutput)
                cnputc(c);
 
        debug_putc(c);
 
-       if (!console_is_serial())
-               if (!disable_serial_output)
+       if (!console_is_serial() && !disable_serial_output)
+               PE_kputc(c);
+}
+
+void
+consdebug_putc_unbuffered(char c)
+{
+       if (!disableConsoleOutput)
+               cnputc_unbuffered(c);
+
+       debug_putc(c);
+
+       if (!console_is_serial() && !disable_serial_output)
                        PE_kputc(c);
 }
 
+void
+consdebug_log(char c)
+{
+       debug_putc(c);
+}
+
+/*
+ * Append contents to the paniclog buffer but don't flush
+ * it. This is mainly used for writing the actual paniclog
+ * contents since flushing once for every line written
+ * would be prohibitively expensive for the paniclog
+ */
+int
+paniclog_append_noflush(const char *fmt, ...)
+{
+       va_list listp;
+
+       va_start(listp, fmt);
+       _doprnt_log(fmt, &listp, consdebug_putc, 16);
+       va_end(listp);
+
+       return 0;
+}
+
 int
 kdb_printf(const char *fmt, ...)
 {
        va_list listp;
 
        va_start(listp, fmt);
-       _doprnt(fmt, &listp, consdebug_putc, 16);
+       _doprnt_log(fmt, &listp, consdebug_putc, 16);
+       va_end(listp);
+
+#if CONFIG_EMBEDDED
+       paniclog_flush();
+#endif
+
+       return 0;
+}
+
+int
+kdb_log(const char *fmt, ...)
+{
+       va_list listp;
+
+       va_start(listp, fmt);
+       _doprnt(fmt, &listp, consdebug_log, 16);
        va_end(listp);
+
+#if CONFIG_EMBEDDED
+       paniclog_flush();
+#endif
+
        return 0;
 }
 
+int
+kdb_printf_unbuffered(const char *fmt, ...)
+{
+       va_list listp;
+
+       va_start(listp, fmt);
+       _doprnt(fmt, &listp, consdebug_putc_unbuffered, 16);
+       va_end(listp);
+
+#if CONFIG_EMBEDDED
+       paniclog_flush();
+#endif
+
+       return 0;
+}
+
+#if !CONFIG_EMBEDDED
+
 static void
 copybyte(int c, void *arg)
 {
@@ -831,8 +995,9 @@ sprintf(char *buf, const char *fmt, ...)
 
         va_start(listp, fmt);
         copybyte_str = buf;
-        __doprnt(fmt, &listp, copybyte, &copybyte_str, 16);
+        __doprnt(fmt, listp, copybyte, &copybyte_str, 16, FALSE);
         va_end(listp);
        *copybyte_str = '\0';
-        return strlen(buf);
+        return (int)strlen(buf);
 }
+#endif /* !CONFIG_EMBEDDED */