X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/d9a64523371fa019c4575bb400cbbc3a50ac9903..c6bf4f310a33a9262d455ea4d3f0630b1255e3fe:/osfmk/kern/printf.c diff --git a/osfmk/kern/printf.c b/osfmk/kern/printf.c index c8abeb624..0feea0aeb 100644 --- a/osfmk/kern/printf.c +++ b/osfmk/kern/printf.c @@ -1,8 +1,8 @@ /* - * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2019 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_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 @@ -11,10 +11,10 @@ * 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. - * + * * 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, @@ -22,35 +22,35 @@ * 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_OSREFERENCE_LICENSE_HEADER_END@ */ /* * @OSF_COPYRIGHT@ */ -/* +/* * Mach Operating System * Copyright (c) 1991,1990,1989,1988 Carnegie Mellon University * All Rights Reserved. - * + * * Permission to use, copy, modify and distribute this software and its * documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. - * + * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. - * + * * Carnegie Mellon requests users of this software to return to - * + * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 - * + * * any improvements or extensions that they make and grant Carnegie Mellon * the rights to redistribute these changes. */ @@ -179,11 +179,15 @@ #include #endif +#ifdef HAS_APPLE_PAC +#include +#include +#endif /* HAS_APPLE_PAC */ #define isdigit(d) ((d) >= '0' && (d) <= '9') #define Ctod(c) ((c) - '0') -#define MAXBUF (sizeof(long long int) * 8) /* enough for binary */ +#define MAXBUF (sizeof(long long int) * 8) /* enough for binary */ static char digs[] = "0123456789abcdef"; #if CONFIG_NO_PRINTF_STRINGS @@ -191,478 +195,530 @@ static char digs[] = "0123456789abcdef"; #undef printf #endif -int _consume_printf_args(int a __unused, ...) +int +_consume_printf_args(int a __unused, ...) { - return 0; + return 0; } -void _consume_kprintf_args(int a __unused, ...) +void +_consume_kprintf_args(int a __unused, ...) { } static int printnum( - unsigned long long int u, /* number to print */ - int base, - void (*putc)(int, void *), + unsigned long long int u, /* number to print */ + int base, + void (*putc)(int, void *), void *arg) { - char buf[MAXBUF]; /* build number here */ - char * p = &buf[MAXBUF-1]; + char buf[MAXBUF]; /* build number here */ + char * p = &buf[MAXBUF - 1]; int nprinted = 0; do { - *p-- = digs[u % base]; - u /= base; + *p-- = digs[u % base]; + u /= base; } while (u != 0); while (++p != &buf[MAXBUF]) { - (*putc)(*p, arg); - nprinted++; + (*putc)(*p, arg); + nprinted++; } return nprinted; } -boolean_t _doprnt_truncates = FALSE; +boolean_t _doprnt_truncates = FALSE; -#if (DEVELOPMENT || DEBUG) -boolean_t doprnt_hide_pointers = FALSE; +#if (DEVELOPMENT || DEBUG) +boolean_t doprnt_hide_pointers = FALSE; #else -boolean_t doprnt_hide_pointers = TRUE; +boolean_t doprnt_hide_pointers = TRUE; #endif int __doprnt( - const char *fmt, - va_list argp, - /* character output routine */ - void (*putc)(int, void *arg), + const char *fmt, + va_list argp, + /* character output routine */ + void (*putc)(int, void *arg), void *arg, - int radix, /* default radix - for '%r' */ - int is_log) + int radix, /* default radix - for '%r' */ + int is_log) { - int length; - int prec; - boolean_t ladjust; - char padc; - long long n; - unsigned long long u; - int plus_sign; - int sign_char; - boolean_t altfmt, truncate; - int base; - char c; - int capitals; - int long_long; + int length; + int prec; + boolean_t ladjust; + char padc; + long long n; + unsigned long long u; + int plus_sign; + int sign_char; + boolean_t altfmt, truncate; + int base; + char c; + int capitals; + int long_long; + enum { + INT, + SHORT, + CHAR, + } numeric_type = INT; int nprinted = 0; while ((c = *fmt) != '\0') { - if (c != '%') { - (*putc)(c, arg); - nprinted++; - fmt++; - continue; - } - - fmt++; - - long_long = 0; - length = 0; - prec = -1; - ladjust = FALSE; - padc = ' '; - plus_sign = 0; - sign_char = 0; - altfmt = FALSE; - - while (TRUE) { - c = *fmt; - if (c == '#') { - altfmt = TRUE; - } - else if (c == '-') { - ladjust = TRUE; - } - else if (c == '+') { - plus_sign = '+'; - } - else if (c == ' ') { - if (plus_sign == 0) - plus_sign = ' '; + if (c != '%') { + (*putc)(c, arg); + nprinted++; + fmt++; + continue; } - else - break; - fmt++; - } - if (c == '0') { - padc = '0'; - c = *++fmt; - } + fmt++; - if (isdigit(c)) { - while(isdigit(c)) { - length = 10 * length + Ctod(c); - c = *++fmt; + long_long = 0; + numeric_type = INT; + length = 0; + prec = -1; + ladjust = FALSE; + padc = ' '; + plus_sign = 0; + sign_char = 0; + altfmt = FALSE; + + while (TRUE) { + c = *fmt; + if (c == '#') { + altfmt = TRUE; + } else if (c == '-') { + ladjust = TRUE; + } else if (c == '+') { + plus_sign = '+'; + } else if (c == ' ') { + if (plus_sign == 0) { + plus_sign = ' '; + } + } else { + break; + } + fmt++; } - } - else if (c == '*') { - length = va_arg(argp, int); - c = *++fmt; - if (length < 0) { - ladjust = !ladjust; - length = -length; + + if (c == '0') { + padc = '0'; + c = *++fmt; } - } - if (c == '.') { - c = *++fmt; if (isdigit(c)) { - prec = 0; - while(isdigit(c)) { - prec = 10 * prec + Ctod(c); + while (isdigit(c)) { + length = 10 * length + Ctod(c); + c = *++fmt; + } + } else if (c == '*') { + length = va_arg(argp, int); c = *++fmt; - } + if (length < 0) { + ladjust = !ladjust; + length = -length; + } } - else if (c == '*') { - prec = va_arg(argp, int); - c = *++fmt; + + if (c == '.') { + c = *++fmt; + if (isdigit(c)) { + prec = 0; + while (isdigit(c)) { + prec = 10 * prec + Ctod(c); + c = *++fmt; + } + } else if (c == '*') { + prec = va_arg(argp, int); + c = *++fmt; + } } - } - if (c == 'l') { - c = *++fmt; /* need it if sizeof(int) < sizeof(long) */ - if (sizeof(int) 32; p++) { - (*putc)(c, arg); - nprinted++; - } - nprinted += printnum((unsigned)( (u>>(j-1)) & ((2<<(i-j))-1)), - base, putc, arg); + if (u == 0) { + break; } - else if (u & (1<<(i-1))) { - if (any) - (*putc)(',', arg); - else { - (*putc)('<', arg); - any = TRUE; - } - nprinted++; - for (; (c = *p) > 32; p++) { - (*putc)(c, arg); - nprinted++; - } + + any = FALSE; + while ((i = *p++) != '\0') { + if (*fmt == 'B') { + i = 33 - i; + } + if (*p <= 32) { + /* + * Bit field + */ + int j; + if (any) { + (*putc)(',', arg); + } else { + (*putc)('<', arg); + any = TRUE; + } + nprinted++; + j = *p++; + if (*fmt == 'B') { + j = 32 - j; + } + 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)(',', arg); + } else { + (*putc)('<', arg); + any = TRUE; + } + nprinted++; + for (; (c = *p) > 32; p++) { + (*putc)(c, arg); + nprinted++; + } + } else { + for (; *p > 32; p++) { + continue; + } + } } - else { - for (; *p > 32; p++) - continue; + if (any) { + (*putc)('>', arg); + nprinted++; } - } - if (any) { - (*putc)('>', arg); - nprinted++; - } - break; + break; } case 'c': - c = va_arg(argp, int); - (*putc)(c, arg); - nprinted++; - break; + c = va_arg(argp, int); + (*putc)(c, arg); + nprinted++; + break; case 's': { - const char *p; - const char *p2; + const char *p; + const char *p2; - if (prec == -1) - prec = 0x7fffffff; /* MAXINT */ + if (prec == -1) { + prec = 0x7fffffff; /* MAXINT */ + } + p = va_arg(argp, char *); - p = va_arg(argp, char *); + if (p == NULL) { + p = ""; + } - if (p == NULL) - p = ""; + if (length > 0 && !ladjust) { + n = 0; + p2 = p; - if (length > 0 && !ladjust) { - n = 0; - p2 = p; + for (; *p != '\0' && n < prec; p++) { + n++; + } + + p = p2; - for (; *p != '\0' && n < prec; p++) - n++; + while (n < length) { + (*putc)(' ', arg); + n++; + nprinted++; + } + } - p = p2; + n = 0; - while (n < length) { - (*putc)(' ', arg); - n++; - nprinted++; + while ((n < prec) && (!(length > 0 && n >= length))) { + if (*p == '\0') { + break; + } + (*putc)(*p++, arg); + nprinted++; + n++; } - } - - n = 0; - - while ((n < prec) && (!(length > 0 && n >= length))) { - if (*p == '\0') { - break; - } - (*putc)(*p++, arg); - nprinted++; - n++; - } - - if (n < length && ladjust) { - while (n < length) { - (*putc)(' ', arg); - n++; - nprinted++; + + if (n < length && ladjust) { + while (n < length) { + (*putc)(' ', arg); + n++; + nprinted++; + } } - } - break; + break; } case 'o': - truncate = _doprnt_truncates; + truncate = _doprnt_truncates; case 'O': - base = 8; - goto print_unsigned; + base = 8; + goto print_unsigned; case 'D': { - unsigned char *up; - char *q, *p; - + unsigned char *up; + char *q, *p; + up = (unsigned char *)va_arg(argp, unsigned char *); p = (char *)va_arg(argp, char *); - if (length == -1) + if (length == -1) { length = 16; - while(length--) { + } + while (length--) { (*putc)(digs[(*up >> 4)], arg); (*putc)(digs[(*up & 0x0f)], arg); nprinted += 2; up++; if (length) { - for (q=p;*q;q++) { + for (q = p; *q; q++) { (*putc)(*q, arg); nprinted++; - } + } } } break; } case 'd': - truncate = _doprnt_truncates; - base = 10; - goto print_signed; + truncate = _doprnt_truncates; + base = 10; + goto print_signed; case 'u': - truncate = _doprnt_truncates; + truncate = _doprnt_truncates; + /* FALLTHROUGH */ case 'U': - base = 10; - goto print_unsigned; + base = 10; + goto print_unsigned; case 'p': - altfmt = TRUE; - if (sizeof(int)= 0) { - u = n; - sign_char = plus_sign; - } - else { - u = -n; - sign_char = '-'; - } - goto print_num; - - print_unsigned: - if (long_long) { - u = va_arg(argp, unsigned long long); - } else { - u = va_arg(argp, unsigned int); - } - goto print_num; - - print_num: - { - char buf[MAXBUF]; /* build number here */ - 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[] = ""; - 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; + base = radix; + goto print_unsigned; + +print_signed: + if (long_long) { + n = va_arg(argp, long long); + } else { + n = va_arg(argp, int); } - } - - if (u != 0 && altfmt) { - if (base == 8) - prefix = "0"; - else if (base == 16) - prefix = "0x"; - } - - do { - /* Print in the correct case */ - *p-- = digits[(u % base)+capitals]; - u /= base; - } while (u != 0); - - length -= (int)(&buf[MAXBUF-1] - p); - if (sign_char) - length--; - if (prefix) - length -= (int)strlen(prefix); - - if (padc == ' ' && !ladjust) { - /* blank padding goes before prefix */ - while (--length >= 0) { - (*putc)(' ', arg); - nprinted++; - } - } - if (sign_char) { - (*putc)(sign_char, arg); - nprinted++; - } - if (prefix) { - while (*prefix) { - (*putc)(*prefix++, arg); - nprinted++; + switch (numeric_type) { + case SHORT: + n = (short)n; + break; + case CHAR: + n = (char)n; + break; + default: + break; } - } - if (padc == '0') { - /* zero padding goes after sign and prefix */ - while (--length >= 0) { - (*putc)('0', arg); - nprinted++; - } - } - while (++p != &buf[MAXBUF]) { - (*putc)(*p, arg); - nprinted++; - } - - if (ladjust) { - while (--length >= 0) { - (*putc)(' ', arg); - nprinted++; + if (n >= 0) { + u = n; + sign_char = plus_sign; + } else { + u = -n; + sign_char = '-'; + } + goto print_num; + +print_unsigned: + if (long_long) { + u = va_arg(argp, unsigned long long); + } 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: + { + char buf[MAXBUF];/* build number here */ + 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[] = ""; + 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') { + (*putc)(*strp, arg); + strp++; + } + nprinted += strl; + break; + } + } + + if (u != 0 && altfmt) { + if (base == 8) { + prefix = "0"; + } else if (base == 16) { + prefix = "0x"; + } + } + + do { + /* Print in the correct case */ + *p-- = digits[(u % base) + capitals]; + u /= base; + } while (u != 0); + + length -= (int)(&buf[MAXBUF - 1] - p); + if (sign_char) { + length--; + } + if (prefix) { + length -= (int)strlen(prefix); + } + + if (padc == ' ' && !ladjust) { + /* blank padding goes before prefix */ + while (--length >= 0) { + (*putc)(' ', arg); + nprinted++; + } + } + if (sign_char) { + (*putc)(sign_char, arg); + nprinted++; + } + if (prefix) { + while (*prefix) { + (*putc)(*prefix++, arg); + nprinted++; + } + } + if (padc == '0') { + /* zero padding goes after sign and prefix */ + while (--length >= 0) { + (*putc)('0', arg); + nprinted++; + } + } + while (++p != &buf[MAXBUF]) { + (*putc)(*p, arg); + nprinted++; + } + + if (ladjust) { + while (--length >= 0) { + (*putc)(' ', arg); + nprinted++; + } + } + break; } - } - break; - } case '\0': - fmt--; - break; + fmt--; + break; default: - (*putc)(c, arg); - nprinted++; - } - fmt++; + (*putc)(c, arg); + nprinted++; + } + fmt++; } return nprinted; @@ -671,45 +727,54 @@ __doprnt( static void dummy_putc(int ch, void *arg) { - void (*real_putc)(char) = arg; - - real_putc(ch); + void (*real_putc)(char) = arg; + + /* + * 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(ch); + } } -void +void _doprnt( - const char *fmt, - va_list *argp, - /* character output routine */ - void (*putc)(char), - int radix) /* default radix - for '%r' */ + 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, FALSE); + __doprnt(fmt, *argp, dummy_putc, putc, radix, FALSE); } -void +void _doprnt_log( - const char *fmt, - va_list *argp, - /* character output routine */ - void (*putc)(char), - int radix) /* default radix - for '%r' */ + 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); + __doprnt(fmt, *argp, dummy_putc, putc, radix, TRUE); } -#if MP_PRINTF -boolean_t new_printf_cpu_number = FALSE; -#endif /* MP_PRINTF */ +#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) +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) +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); @@ -717,7 +782,6 @@ void bsd_log_lock(void); void bsd_log_unlock(void); void - printf_init(void) { /* @@ -731,7 +795,7 @@ printf_init(void) void bsd_log_lock(void) { - simple_lock(&bsd_log_spinlock); + simple_lock(&bsd_log_spinlock, LCK_GRP_NULL); } void @@ -750,8 +814,8 @@ oslog_lock_init(void) /* derived from boot_gets */ void safe_gets( - char *str, - int maxlen) + char *str, + int maxlen) { char *lp; int c; @@ -766,7 +830,7 @@ safe_gets( printf("\n"); *lp++ = 0; return; - + case '\b': case '#': case '\177': @@ -787,8 +851,7 @@ safe_gets( if (lp < strmax) { *lp++ = c; printf("%c", c); - } - else { + } else { printf("%c", '\007'); /* beep */ } } @@ -802,12 +865,14 @@ void conslog_putc( char c) { - if (!disableConsoleOutput) + if (!disableConsoleOutput) { cnputc(c); + } -#ifdef MACH_BSD - if (!kernel_debugger_entry_count) +#ifdef MACH_BSD + if (!kernel_debugger_entry_count) { log_putc(c); + } #endif } @@ -815,8 +880,9 @@ void cons_putc_locked( char c) { - if (!disableConsoleOutput) + if (!disableConsoleOutput) { cnputc(c); + } } static int @@ -850,7 +916,7 @@ vprintf_internal(const char *fmt, va_list ap_in, void *caller) return 0; } -__attribute__((noinline,not_tail_called)) +__attribute__((noinline, not_tail_called)) int printf(const char *fmt, ...) { @@ -864,7 +930,7 @@ printf(const char *fmt, ...) return ret; } -__attribute__((noinline,not_tail_called)) +__attribute__((noinline, not_tail_called)) int vprintf(const char *fmt, va_list ap) { @@ -874,25 +940,29 @@ vprintf(const char *fmt, va_list ap) void consdebug_putc(char c) { - if (!disableConsoleOutput) + if (!disableConsoleOutput) { cnputc(c); + } debug_putc(c); - if (!console_is_serial() && !disable_serial_output) + if (!console_is_serial() && !disable_serial_output) { PE_kputc(c); + } } void consdebug_putc_unbuffered(char c) { - if (!disableConsoleOutput) + if (!disableConsoleOutput) { cnputc_unbuffered(c); + } debug_putc(c); - if (!console_is_serial() && !disable_serial_output) - PE_kputc(c); + if (!console_is_serial() && !disable_serial_output) { + PE_kputc(c); + } } void @@ -910,7 +980,7 @@ consdebug_log(char c) int paniclog_append_noflush(const char *fmt, ...) { - va_list listp; + va_list listp; va_start(listp, fmt); _doprnt_log(fmt, &listp, consdebug_putc, 16); @@ -922,7 +992,7 @@ paniclog_append_noflush(const char *fmt, ...) int kdb_printf(const char *fmt, ...) { - va_list listp; + va_list listp; va_start(listp, fmt); _doprnt_log(fmt, &listp, consdebug_putc, 16); @@ -938,7 +1008,7 @@ kdb_printf(const char *fmt, ...) int kdb_log(const char *fmt, ...) { - va_list listp; + va_list listp; va_start(listp, fmt); _doprnt(fmt, &listp, consdebug_log, 16); @@ -954,7 +1024,7 @@ kdb_log(const char *fmt, ...) int kdb_printf_unbuffered(const char *fmt, ...) { - va_list listp; + va_list listp; va_start(listp, fmt); _doprnt(fmt, &listp, consdebug_putc_unbuffered, 16); @@ -978,9 +1048,9 @@ copybyte(int c, void *arg) * 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 */ + char** p = arg; /* cast outside pointer */ + **p = c; /* store character */ + (*p)++; /* increment inside pointer */ } /* @@ -990,14 +1060,14 @@ copybyte(int c, void *arg) int sprintf(char *buf, const char *fmt, ...) { - va_list listp; + va_list listp; char *copybyte_str; - va_start(listp, fmt); - copybyte_str = buf; - __doprnt(fmt, listp, copybyte, ©byte_str, 16, FALSE); - va_end(listp); + va_start(listp, fmt); + copybyte_str = buf; + __doprnt(fmt, listp, copybyte, ©byte_str, 16, FALSE); + va_end(listp); *copybyte_str = '\0'; - return (int)strlen(buf); + return (int)strlen(buf); } #endif /* !CONFIG_EMBEDDED */