/*
- * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2020 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
* 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,
* 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.
*/
* %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>
#ifdef MACH_BSD
#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
+#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 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
+/* 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(
- register unsigned long long int u, /* number to print */
- register 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 */
- register 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;
+#else
+boolean_t doprnt_hide_pointers = TRUE;
+#endif
int
__doprnt(
- register 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 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;
- register 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;
+ if (radix < 2 || radix > 36) {
+ radix = 10;
+ }
+
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 (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 */
-
- switch(c) {
+ 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;
+ }
+ } 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;
+ }
+
+ 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 */
+
+ switch (c) {
case 'b':
case 'B':
{
- register char *p;
- boolean_t any;
- register int i;
-
- if (long_long) {
- u = va_arg(*argp, unsigned long long);
- } else {
- u = va_arg(*argp, unsigned long);
- }
- p = va_arg(*argp, char *);
- base = *p++;
- nprinted += printnum(u, base, putc, arg);
-
- if (u == 0)
- break;
+ char *p;
+ boolean_t any;
+ int i;
+
+ if (long_long) {
+ u = va_arg(argp, unsigned long long);
+ } else {
+ u = va_arg(argp, unsigned int);
+ }
+ p = va_arg(argp, char *);
+ base = *p++;
+ nprinted += printnum(u, base, putc, arg);
- any = FALSE;
- while ((i = *p++) != '\0') {
- if (*fmt == 'B')
- i = 33 - i;
- if (*p <= 32) {
- /*
- * Bit field
- */
- register 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);
+ 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 = (char)va_arg(argp, int);
+ (*putc)(c, arg);
+ nprinted++;
+ break;
case 's':
{
- register char *p;
- register char *p2;
-
- if (prec == -1)
- prec = 0x7fffffff; /* MAXINT */
+ const char *p;
+ const char *p2;
- p = va_arg(*argp, char *);
+ if (prec == -1) {
+ prec = 0x7fffffff; /* MAXINT */
+ }
+ p = va_arg(argp, char *);
- if (p == (char *)0)
- 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++;
+ for (; *p != '\0' && n < prec; p++) {
+ n++;
+ }
- p = p2;
+ p = p2;
- while (n < length) {
- (*putc)(' ', arg);
- n++;
- nprinted++;
+ while (n < length) {
+ (*putc)(' ', arg);
+ n++;
+ nprinted++;
+ }
}
- }
-
- n = 0;
- while (*p != '\0') {
- if (++n > prec || (length > 0 && n > length))
- break;
+ n = 0;
- (*putc)(*p++, arg);
- nprinted++;
- }
+ 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;
+ OS_FALLTHROUGH;
case 'O':
- base = 8;
- goto print_unsigned;
+ 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)
+ 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--) {
+ }
+ 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;
+ case 'i':
+ truncate = _doprnt_truncates;
+ base = 10;
+ goto print_signed;
case 'u':
- truncate = _doprnt_truncates;
+ truncate = _doprnt_truncates;
+ OS_FALLTHROUGH;
case 'U':
- base = 10;
- goto print_unsigned;
+ base = 10;
+ goto print_unsigned;
case 'p':
- altfmt = TRUE;
+ altfmt = TRUE;
+ if (sizeof(int) < sizeof(void *)) {
+ long_long = 1;
+ }
+ OS_FALLTHROUGH;
case 'x':
- truncate = _doprnt_truncates;
- base = 16;
- goto print_unsigned;
+ truncate = _doprnt_truncates;
+ base = 16;
+ goto print_unsigned;
case 'X':
- 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;
+ base = 16;
+ capitals = 16; /* Print in upper case */
+ goto print_unsigned;
case 'r':
- truncate = _doprnt_truncates;
+ truncate = _doprnt_truncates;
+ OS_FALLTHROUGH;
case 'R':
- base = radix;
- goto print_signed;
+ base = radix;
+ goto print_signed;
case 'n':
- truncate = _doprnt_truncates;
+ truncate = _doprnt_truncates;
+ OS_FALLTHROUGH;
case 'N':
- base = radix;
- goto print_unsigned;
-
- print_signed:
- if (long_long) {
- n = va_arg(*argp, long long);
- } else {
- n = va_arg(*argp, long);
- }
- 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 long);
- }
- goto print_num;
-
- print_num:
- {
- char buf[MAXBUF]; /* build number here */
- register char * p = &buf[MAXBUF-1];
- static char digits[] = "0123456789abcdef0123456789ABCDEF";
- char *prefix = 0;
-
- if (truncate) u = (long long)((int)(u));
-
- 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 -= (&buf[MAXBUF-1] - p);
- if (sign_char)
- length--;
- if (prefix)
- length -= strlen((const char *) 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++;
+ base = radix;
+ goto print_unsigned;
+
+print_signed:
+ if (long_long) {
+ n = va_arg(argp, long long);
+ } else {
+ n = va_arg(argp, int);
}
- }
- 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++;
+ 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;
+ } 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[] = "<ptr>";
+ 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;
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((char)ch);
+ }
}
-void
+void
_doprnt(
- register 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);
+ __doprnt(fmt, *argp, dummy_putc, putc, radix, FALSE);
}
-#if MP_PRINTF
-boolean_t new_printf_cpu_number = FALSE;
-#endif /* MP_PRINTF */
+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 */
+SIMPLE_LOCK_DECLARE(bsd_log_spinlock, 0);
-decl_simple_lock_data(,printf_lock)
-decl_simple_lock_data(,bsd_log_spinlock)
-decl_mutex_data(,sprintf_lock)
-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();
- mutex_init(&sprintf_lock, 0);
+ 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()
+bsd_log_lock_safe(void)
{
- simple_lock(&bsd_log_spinlock);
+ (void) bsd_log_lock(true);
}
void
-bsd_log_unlock()
+bsd_log_unlock(void)
{
simple_unlock(&bsd_log_spinlock);
}
/* derived from boot_gets */
void
safe_gets(
- char *str,
- int maxlen)
+ char *str,
+ int maxlen)
{
- register char *lp;
- register int c;
+ char *lp;
+ 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':
printf("\n");
*lp++ = 0;
return;
-
+
case '\b':
case '#':
case '\177':
if (lp < strmax) {
*lp++ = c;
printf("%c", c);
- }
- else {
+ } else {
printf("%c", '\007'); /* beep */
}
}
}
}
+extern int disableConsoleOutput;
+
void
conslog_putc(
char c)
{
- extern unsigned int debug_mode, disableDebugOuput, disableConsoleOutput;
-
- if ((debug_mode && !disableDebugOuput) || !disableConsoleOutput)
+ if (!disableConsoleOutput) {
cnputc(c);
+ }
-#ifdef MACH_BSD
- log_putc(c);
+#ifdef MACH_BSD
+ if (!kernel_debugger_entry_count) {
+ log_putc(c);
+ }
#endif
}
void
-dbugprintf(const char *fmt, ...)
+cons_putc_locked(
+ char c)
{
+ if (!disableConsoleOutput) {
+ cnputc(c);
+ }
+}
-#if MACH_KDB
+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();
+ }
- extern void db_putchar(char c);
- va_list listp;
+ va_end(ap);
- va_start(listp, fmt);
- _doprnt(fmt, &listp, db_putchar, 16);
- va_end(listp);
-#endif
- return;
+ os_log_with_args(OS_LOG_DEFAULT, OS_LOG_TYPE_DEFAULT, fmt, ap_in, caller);
+ }
+ return 0;
}
-void
+__attribute__((noinline, not_tail_called))
+int
printf(const char *fmt, ...)
{
- va_list listp;
+ int ret;
- disable_preemption();
- va_start(listp, fmt);
- _doprnt(fmt, &listp, conslog_putc, 16);
- va_end(listp);
- enable_preemption();
+ va_list ap;
+ va_start(ap, fmt);
+ ret = vprintf_internal(fmt, ap, __builtin_return_address(0));
+ va_end(ap);
+
+ return ret;
}
-void
-consdebug_putc(
- char c)
+__attribute__((noinline, not_tail_called))
+int
+vprintf(const char *fmt, va_list ap)
{
- extern unsigned int debug_mode, disableDebugOuput, disableConsoleOutput;
+ return vprintf_internal(fmt, ap, __builtin_return_address(0));
+}
- if ((debug_mode && !disableDebugOuput) || !disableConsoleOutput)
+void
+consdebug_putc(char c)
+{
+ if (!disableConsoleOutput) {
cnputc(c);
+ }
debug_putc(c);
-#ifdef __ppc__
- if (!console_is_serial())
- PE_kputc(c);
-#endif
+ 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_unbuffered, 16);
+ va_end(listp);
+
+ return 0;
+}
+
+int
kdb_printf(const char *fmt, ...)
{
- va_list listp;
+ va_list listp;
va_start(listp, fmt);
- _doprnt(fmt, &listp, consdebug_putc, 16);
+ _doprnt_log(fmt, &listp, consdebug_putc, 16);
va_end(listp);
+
+#if defined(__arm__) || defined(__arm64__)
+ 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 defined(__arm__) || defined(__arm64__)
+ paniclog_flush();
+#endif
+
+ return 0;
}
-static char *copybyte_str;
+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 defined(__arm__) || defined(__arm64__)
+ paniclog_flush();
+#endif
+
+ return 0;
+}
+#if CONFIG_VSPRINTF
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 = (char)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;
-
- va_start(listp, fmt);
- mutex_lock(&sprintf_lock);
- copybyte_str = buf;
- _doprnt(fmt, &listp, copybyte, 16);
- mutex_unlock(&sprintf_lock);
- va_end(listp);
- return strlen(buf);
+ va_list listp;
+ char *copybyte_str;
+
+ 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);
}
+#endif /* CONFIG_VSPRINTF */