]> git.saurik.com Git - apple/xnu.git/blobdiff - osfmk/kern/printf.c
xnu-7195.81.3.tar.gz
[apple/xnu.git] / osfmk / kern / printf.c
index 9fb14d2628975d70f4dac53a71f22f5e15c86228..898086d8ec3518c91e525bcb24f601d1f0228443 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2020 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  *
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  *
 #include <arm/cpu_data_internal.h>
 #endif
 
 #include <arm/cpu_data_internal.h>
 #endif
 
+#ifdef HAS_APPLE_PAC
+#include <mach/vm_param.h>
+#include <ptrauth.h>
+#endif /* HAS_APPLE_PAC */
 
 #define isdigit(d) ((d) >= '0' && (d) <= '9')
 #define Ctod(c) ((c) - '0')
 
 #define isdigit(d) ((d) >= '0' && (d) <= '9')
 #define Ctod(c) ((c) - '0')
@@ -256,8 +260,17 @@ __doprnt(
        char    c;
        int             capitals;
        int             long_long;
        char    c;
        int             capitals;
        int             long_long;
+       enum {
+               INT,
+               SHORT,
+               CHAR,
+       } numeric_type = INT;
        int             nprinted = 0;
 
        int             nprinted = 0;
 
+       if (radix < 2 || radix > 36) {
+               radix = 10;
+       }
+
        while ((c = *fmt) != '\0') {
                if (c != '%') {
                        (*putc)(c, arg);
        while ((c = *fmt) != '\0') {
                if (c != '%') {
                        (*putc)(c, arg);
@@ -269,6 +282,7 @@ __doprnt(
                fmt++;
 
                long_long = 0;
                fmt++;
 
                long_long = 0;
+               numeric_type = INT;
                length = 0;
                prec = -1;
                ladjust = FALSE;
                length = 0;
                prec = -1;
                ladjust = FALSE;
@@ -337,6 +351,13 @@ __doprnt(
                                long_long = 1;
                                c = *++fmt;
                        }
                                long_long = 1;
                                c = *++fmt;
                        }
+               } else if (c == 'h') {
+                       c = *++fmt;
+                       numeric_type = SHORT;
+                       if (c == 'h') {
+                               numeric_type = CHAR;
+                               c = *++fmt;
+                       }
                } else if (c == 'q' || c == 'L') {
                        long_long = 1;
                        c = *++fmt;
                } else if (c == 'q' || c == 'L') {
                        long_long = 1;
                        c = *++fmt;
@@ -426,7 +447,7 @@ __doprnt(
                }
 
                case 'c':
                }
 
                case 'c':
-                       c = va_arg(argp, int);
+                       c = (char)va_arg(argp, int);
                        (*putc)(c, arg);
                        nprinted++;
                        break;
                        (*putc)(c, arg);
                        nprinted++;
                        break;
@@ -486,6 +507,7 @@ __doprnt(
 
                case 'o':
                        truncate = _doprnt_truncates;
 
                case 'o':
                        truncate = _doprnt_truncates;
+                       OS_FALLTHROUGH;
                case 'O':
                        base = 8;
                        goto print_unsigned;
                case 'O':
                        base = 8;
                        goto print_unsigned;
@@ -515,12 +537,14 @@ __doprnt(
                }
 
                case 'd':
                }
 
                case 'd':
+               case 'i':
                        truncate = _doprnt_truncates;
                        base = 10;
                        goto print_signed;
 
                case 'u':
                        truncate = _doprnt_truncates;
                        truncate = _doprnt_truncates;
                        base = 10;
                        goto print_signed;
 
                case 'u':
                        truncate = _doprnt_truncates;
+                       OS_FALLTHROUGH;
                case 'U':
                        base = 10;
                        goto print_unsigned;
                case 'U':
                        base = 10;
                        goto print_unsigned;
@@ -530,6 +554,7 @@ __doprnt(
                        if (sizeof(int) < sizeof(void *)) {
                                long_long = 1;
                        }
                        if (sizeof(int) < sizeof(void *)) {
                                long_long = 1;
                        }
+                       OS_FALLTHROUGH;
                case 'x':
                        truncate = _doprnt_truncates;
                        base = 16;
                case 'x':
                        truncate = _doprnt_truncates;
                        base = 16;
@@ -542,12 +567,14 @@ __doprnt(
 
                case 'r':
                        truncate = _doprnt_truncates;
 
                case 'r':
                        truncate = _doprnt_truncates;
+                       OS_FALLTHROUGH;
                case 'R':
                        base = radix;
                        goto print_signed;
 
                case 'n':
                        truncate = _doprnt_truncates;
                case 'R':
                        base = radix;
                        goto print_signed;
 
                case 'n':
                        truncate = _doprnt_truncates;
+                       OS_FALLTHROUGH;
                case 'N':
                        base = radix;
                        goto print_unsigned;
                case 'N':
                        base = radix;
                        goto print_unsigned;
@@ -558,6 +585,16 @@ print_signed:
                        } else {
                                n = va_arg(argp, int);
                        }
                        } else {
                                n = va_arg(argp, int);
                        }
+                       switch (numeric_type) {
+                       case SHORT:
+                               n = (short)n;
+                               break;
+                       case CHAR:
+                               n = (char)n;
+                               break;
+                       default:
+                               break;
+                       }
                        if (n >= 0) {
                                u = n;
                                sign_char = plus_sign;
                        if (n >= 0) {
                                u = n;
                                sign_char = plus_sign;
@@ -573,6 +610,16 @@ print_unsigned:
                        } else {
                                u = va_arg(argp, unsigned int);
                        }
                        } else {
                                u = va_arg(argp, unsigned int);
                        }
+                       switch (numeric_type) {
+                       case SHORT:
+                               u = (unsigned short)u;
+                               break;
+                       case CHAR:
+                               u = (unsigned char)u;
+                               break;
+                       default:
+                               break;
+                       }
                        goto print_num;
 
 print_num:
                        goto print_num;
 
 print_num:
@@ -591,6 +638,13 @@ print_num:
                                        const char* strp = str;
                                        int strl = sizeof(str) - 1;
 
                                        const char* strp = str;
                                        int strl = sizeof(str) - 1;
 
+#ifdef HAS_APPLE_PAC
+                                       /**
+                                        * Strip out the pointer authentication code before
+                                        * checking whether the pointer is a kernel address.
+                                        */
+                                       u = (unsigned long long)VM_KERNEL_STRIP_PTR(u);
+#endif /* HAS_APPLE_PAC */
 
                                        if (u >= VM_MIN_KERNEL_AND_KEXT_ADDRESS && u <= VM_MAX_KERNEL_ADDRESS) {
                                                while (*strp != '\0') {
 
                                        if (u >= VM_MIN_KERNEL_AND_KEXT_ADDRESS && u <= VM_MAX_KERNEL_ADDRESS) {
                                                while (*strp != '\0') {
@@ -681,7 +735,19 @@ dummy_putc(int ch, void *arg)
 {
        void (*real_putc)(char) = arg;
 
 {
        void (*real_putc)(char) = arg;
 
-       real_putc(ch);
+       /*
+        * Attempts to panic (or otherwise log to console) during early boot
+        * can result in _doprnt() and _doprnt_log() being called from
+        * _kprintf() before PE_init_kprintf() has been called. This causes
+        * the "putc" param to _doprnt() and _doprnt_log() to be passed as
+        * NULL. That NULL makes its way here, and we would try jump to it.
+        * Given that this is a poor idea, and this happens at very early
+        * boot, there is not a way to report this easily (we are likely
+        * already panicing), so we'll just do nothing instead of crashing.
+        */
+       if (real_putc) {
+               real_putc((char)ch);
+       }
 }
 
 void
 }
 
 void
@@ -710,32 +776,44 @@ _doprnt_log(
 boolean_t       new_printf_cpu_number = FALSE;
 #endif  /* 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)
-
-lck_grp_t oslog_stream_lock_grp;
-decl_lck_spin_data(, oslog_stream_lock)
-void oslog_lock_init(void);
+SIMPLE_LOCK_DECLARE(bsd_log_spinlock, 0);
 
 
-extern void bsd_log_init(void);
-void bsd_log_lock(void);
+bool bsd_log_lock(bool);
+void bsd_log_lock_safe(void);
 void bsd_log_unlock(void);
 
 void bsd_log_unlock(void);
 
-void
-printf_init(void)
+/*
+ * Locks OS log lock and returns true if successful, false otherwise. Locking
+ * always succeeds in a safe context but may block. Locking in an unsafe context
+ * never blocks but fails if someone else is already holding the lock.
+ *
+ * A caller is responsible to decide whether the context is safe or not.
+ *
+ * As a rule of thumb following cases are *not* considered safe:
+ *   - Interrupts are disabled
+ *   - Pre-emption is disabled
+ *   - When in a debugger
+ *   - During a panic
+ */
+bool
+bsd_log_lock(bool safe)
 {
 {
-       /*
-        * Lock is only really needed after the first thread is created.
-        */
-       simple_lock_init(&printf_lock, 0);
-       simple_lock_init(&bsd_log_spinlock, 0);
-       bsd_log_init();
+       if (!safe) {
+               assert(!oslog_is_safe());
+               return simple_lock_try(&bsd_log_spinlock, LCK_GRP_NULL);
+       }
+       simple_lock(&bsd_log_spinlock, LCK_GRP_NULL);
+       return true;
 }
 
 }
 
+/*
+ * Locks OS log lock assuming the context is safe. See bsd_log_lock() comment
+ * for details.
+ */
 void
 void
-bsd_log_lock(void)
+bsd_log_lock_safe(void)
 {
 {
-       simple_lock(&bsd_log_spinlock, LCK_GRP_NULL);
+       (void) bsd_log_lock(true);
 }
 
 void
 }
 
 void
@@ -744,13 +822,6 @@ bsd_log_unlock(void)
        simple_unlock(&bsd_log_spinlock);
 }
 
        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(
 /* derived from boot_gets */
 void
 safe_gets(
@@ -758,12 +829,12 @@ safe_gets(
        int     maxlen)
 {
        char *lp;
        int     maxlen)
 {
        char *lp;
-       int c;
+       char c;
        char *strmax = str + maxlen - 1; /* allow space for trailing 0 */
 
        lp = str;
        for (;;) {
        char *strmax = str + maxlen - 1; /* allow space for trailing 0 */
 
        lp = str;
        for (;;) {
-               c = cngetc();
+               c = (char)cngetc();
                switch (c) {
                case '\n':
                case '\r':
                switch (c) {
                case '\n':
                case '\r':
@@ -923,7 +994,7 @@ paniclog_append_noflush(const char *fmt, ...)
        va_list listp;
 
        va_start(listp, fmt);
        va_list listp;
 
        va_start(listp, fmt);
-       _doprnt_log(fmt, &listp, consdebug_putc, 16);
+       _doprnt_log(fmt, &listp, consdebug_putc_unbuffered, 16);
        va_end(listp);
 
        return 0;
        va_end(listp);
 
        return 0;
@@ -938,7 +1009,7 @@ kdb_printf(const char *fmt, ...)
        _doprnt_log(fmt, &listp, consdebug_putc, 16);
        va_end(listp);
 
        _doprnt_log(fmt, &listp, consdebug_putc, 16);
        va_end(listp);
 
-#if CONFIG_EMBEDDED
+#if defined(__arm__) || defined(__arm64__)
        paniclog_flush();
 #endif
 
        paniclog_flush();
 #endif
 
@@ -954,7 +1025,7 @@ kdb_log(const char *fmt, ...)
        _doprnt(fmt, &listp, consdebug_log, 16);
        va_end(listp);
 
        _doprnt(fmt, &listp, consdebug_log, 16);
        va_end(listp);
 
-#if CONFIG_EMBEDDED
+#if defined(__arm__) || defined(__arm64__)
        paniclog_flush();
 #endif
 
        paniclog_flush();
 #endif
 
@@ -970,15 +1041,14 @@ kdb_printf_unbuffered(const char *fmt, ...)
        _doprnt(fmt, &listp, consdebug_putc_unbuffered, 16);
        va_end(listp);
 
        _doprnt(fmt, &listp, consdebug_putc_unbuffered, 16);
        va_end(listp);
 
-#if CONFIG_EMBEDDED
+#if defined(__arm__) || defined(__arm64__)
        paniclog_flush();
 #endif
 
        return 0;
 }
 
        paniclog_flush();
 #endif
 
        return 0;
 }
 
-#if !CONFIG_EMBEDDED
-
+#if CONFIG_VSPRINTF
 static void
 copybyte(int c, void *arg)
 {
 static void
 copybyte(int c, void *arg)
 {
@@ -989,7 +1059,7 @@ copybyte(int c, void *arg)
         * the inside pointer.
         */
        char** p = arg; /* cast outside pointer */
         * the inside pointer.
         */
        char** p = arg; /* cast outside pointer */
-       **p = c;        /* store character */
+       **p = (char)c;  /* store character */
        (*p)++;         /* increment inside pointer */
 }
 
        (*p)++;         /* increment inside pointer */
 }
 
@@ -1010,4 +1080,4 @@ sprintf(char *buf, const char *fmt, ...)
        *copybyte_str = '\0';
        return (int)strlen(buf);
 }
        *copybyte_str = '\0';
        return (int)strlen(buf);
 }
-#endif /* !CONFIG_EMBEDDED */
+#endif /* CONFIG_VSPRINTF */