X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/0a7de7458d150b5d4dffc935ba399be265ef0a1a..a991bd8d3e7fe02dbca0644054bab73c5b75324a:/osfmk/kern/printf.c?ds=sidebyside diff --git a/osfmk/kern/printf.c b/osfmk/kern/printf.c index 9fb14d262..898086d8e 100644 --- a/osfmk/kern/printf.c +++ b/osfmk/kern/printf.c @@ -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@ * @@ -179,6 +179,10 @@ #include #endif +#ifdef HAS_APPLE_PAC +#include +#include +#endif /* HAS_APPLE_PAC */ #define isdigit(d) ((d) >= '0' && (d) <= '9') #define Ctod(c) ((c) - '0') @@ -256,8 +260,17 @@ __doprnt( char c; int capitals; int long_long; + enum { + INT, + SHORT, + CHAR, + } numeric_type = INT; int nprinted = 0; + if (radix < 2 || radix > 36) { + radix = 10; + } + while ((c = *fmt) != '\0') { if (c != '%') { (*putc)(c, arg); @@ -269,6 +282,7 @@ __doprnt( fmt++; long_long = 0; + numeric_type = INT; length = 0; prec = -1; ladjust = FALSE; @@ -337,6 +351,13 @@ __doprnt( 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; @@ -426,7 +447,7 @@ __doprnt( } case 'c': - c = va_arg(argp, int); + c = (char)va_arg(argp, int); (*putc)(c, arg); nprinted++; break; @@ -486,6 +507,7 @@ __doprnt( case 'o': truncate = _doprnt_truncates; + OS_FALLTHROUGH; case 'O': base = 8; goto print_unsigned; @@ -515,12 +537,14 @@ __doprnt( } case 'd': + case 'i': truncate = _doprnt_truncates; base = 10; goto print_signed; case 'u': truncate = _doprnt_truncates; + OS_FALLTHROUGH; case 'U': base = 10; goto print_unsigned; @@ -530,6 +554,7 @@ __doprnt( if (sizeof(int) < sizeof(void *)) { long_long = 1; } + OS_FALLTHROUGH; case 'x': truncate = _doprnt_truncates; base = 16; @@ -542,12 +567,14 @@ __doprnt( case 'r': truncate = _doprnt_truncates; + OS_FALLTHROUGH; case 'R': base = radix; goto print_signed; case 'n': truncate = _doprnt_truncates; + OS_FALLTHROUGH; case 'N': base = radix; goto print_unsigned; @@ -558,6 +585,16 @@ print_signed: } 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; @@ -573,6 +610,16 @@ print_unsigned: } 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: @@ -591,6 +638,13 @@ print_num: 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') { @@ -681,7 +735,19 @@ dummy_putc(int ch, void *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 @@ -710,32 +776,44 @@ _doprnt_log( 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 -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 -bsd_log_lock(void) +bsd_log_lock_safe(void) { - simple_lock(&bsd_log_spinlock, LCK_GRP_NULL); + (void) bsd_log_lock(true); } void @@ -744,13 +822,6 @@ 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( @@ -758,12 +829,12 @@ safe_gets( int maxlen) { char *lp; - int c; + char c; char *strmax = str + maxlen - 1; /* allow space for trailing 0 */ lp = str; for (;;) { - c = cngetc(); + c = (char)cngetc(); switch (c) { case '\n': case '\r': @@ -923,7 +994,7 @@ paniclog_append_noflush(const char *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; @@ -938,7 +1009,7 @@ kdb_printf(const char *fmt, ...) _doprnt_log(fmt, &listp, consdebug_putc, 16); va_end(listp); -#if CONFIG_EMBEDDED +#if defined(__arm__) || defined(__arm64__) paniclog_flush(); #endif @@ -954,7 +1025,7 @@ kdb_log(const char *fmt, ...) _doprnt(fmt, &listp, consdebug_log, 16); va_end(listp); -#if CONFIG_EMBEDDED +#if defined(__arm__) || defined(__arm64__) paniclog_flush(); #endif @@ -970,15 +1041,14 @@ kdb_printf_unbuffered(const char *fmt, ...) _doprnt(fmt, &listp, consdebug_putc_unbuffered, 16); va_end(listp); -#if CONFIG_EMBEDDED +#if defined(__arm__) || defined(__arm64__) paniclog_flush(); #endif return 0; } -#if !CONFIG_EMBEDDED - +#if CONFIG_VSPRINTF 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 */ - **p = c; /* store character */ + **p = (char)c; /* store character */ (*p)++; /* increment inside pointer */ } @@ -1010,4 +1080,4 @@ sprintf(char *buf, const char *fmt, ...) *copybyte_str = '\0'; return (int)strlen(buf); } -#endif /* !CONFIG_EMBEDDED */ +#endif /* CONFIG_VSPRINTF */