]> git.saurik.com Git - apple/xnu.git/blame - osfmk/kern/printf.c
xnu-7195.50.7.100.1.tar.gz
[apple/xnu.git] / osfmk / kern / printf.c
CommitLineData
1c79356b 1/*
f427ee49 2 * Copyright (c) 2000-2020 Apple Inc. All rights reserved.
1c79356b 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
0a7de745 5 *
2d21ac55
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
0a7de745 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
0a7de745 17 *
2d21ac55
A
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
0a7de745 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
27 */
28/*
29 * @OSF_COPYRIGHT@
30 */
31
0a7de745 32/*
1c79356b
A
33 * Mach Operating System
34 * Copyright (c) 1991,1990,1989,1988 Carnegie Mellon University
35 * All Rights Reserved.
0a7de745 36 *
1c79356b
A
37 * Permission to use, copy, modify and distribute this software and its
38 * documentation is hereby granted, provided that both the copyright
39 * notice and this permission notice appear in all copies of the
40 * software, derivative works or modified versions, and any portions
41 * thereof, and that both notices appear in supporting documentation.
0a7de745 42 *
1c79356b
A
43 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
44 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
45 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
0a7de745 46 *
1c79356b 47 * Carnegie Mellon requests users of this software to return to
0a7de745 48 *
1c79356b
A
49 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
50 * School of Computer Science
51 * Carnegie Mellon University
52 * Pittsburgh PA 15213-3890
0a7de745 53 *
1c79356b
A
54 * any improvements or extensions that they make and grant Carnegie Mellon
55 * the rights to redistribute these changes.
56 */
57
58/*
59 * Common code for printf et al.
60 *
61 * The calling routine typically takes a variable number of arguments,
62 * and passes the address of the first one. This implementation
63 * assumes a straightforward, stack implementation, aligned to the
64 * machine's wordsize. Increasing addresses are assumed to point to
65 * successive arguments (left-to-right), as is the case for a machine
66 * with a downward-growing stack with arguments pushed right-to-left.
67 *
68 * To write, for example, fprintf() using this routine, the code
69 *
70 * fprintf(fd, format, args)
71 * FILE *fd;
72 * char *format;
73 * {
74 * _doprnt(format, &args, fd);
75 * }
76 *
77 * would suffice. (This example does not handle the fprintf's "return
78 * value" correctly, but who looks at the return value of fprintf
79 * anyway?)
80 *
81 * This version implements the following printf features:
82 *
83 * %d decimal conversion
84 * %u unsigned conversion
85 * %x hexadecimal conversion
86 * %X hexadecimal conversion with capital letters
9bccf70c
A
87 * %D hexdump, ptr & separator string ("%6D", ptr, ":") -> XX:XX:XX:XX:XX:XX
88 * if you use, "%*D" then there's a length, the data ptr and then the separator
1c79356b
A
89 * %o octal conversion
90 * %c character
91 * %s string
92 * %m.n field width, precision
93 * %-m.n left adjustment
94 * %0m.n zero-padding
95 * %*.* width and precision taken from arguments
96 *
b0d623f7 97 * This version does not implement %f, %e, or %g.
1c79356b
A
98 *
99 * As mentioned, this version does not return any reasonable value.
100 *
101 * Permission is granted to use, modify, or propagate this code as
102 * long as this notice is incorporated.
103 *
104 * Steve Summit 3/25/87
9bccf70c
A
105 *
106 * Tweaked for long long support and extended to support the hexdump %D
107 * specifier by dbg 05/02/02.
1c79356b
A
108 */
109
110/*
111 * Added formats for decoding device registers:
112 *
113 * printf("reg = %b", regval, "<base><arg>*")
114 *
115 * where <base> is the output base expressed as a control character:
116 * i.e. '\10' gives octal, '\20' gives hex. Each <arg> is a sequence of
117 * characters, the first of which gives the bit number to be inspected
118 * (origin 1), and the rest (up to a control character (<= 32)) give the
119 * name of the register. Thus
120 * printf("reg = %b\n", 3, "\10\2BITTWO\1BITONE")
121 * would produce
122 * reg = 3<BITTWO,BITONE>
123 *
124 * If the second character in <arg> is also a control character, it
125 * indicates the last bit of a bit field. In this case, printf will extract
126 * bits <1> to <2> and print it. Characters following the second control
127 * character are printed before the bit field.
128 * printf("reg = %b\n", 0xb, "\10\4\3FIELD1=\2BITTWO\1BITONE")
129 * would produce
130 * reg = b<FIELD1=2,BITONE>
131 *
132 * The %B format is like %b but the bits are numbered from the most
133 * significant (the bit weighted 31), which is called 1, to the least
134 * significant, called 32.
135 */
136/*
137 * Added for general use:
138 * # prefix for alternate format:
139 * 0x (0X) for hex
140 * leading 0 for octal
141 * + print '+' if positive
142 * blank print ' ' if positive
143 *
5ba3f43e 144 * z set length equal to size_t
1c79356b
A
145 * r signed, 'radix'
146 * n unsigned, 'radix'
147 *
148 * D,U,O,Z same as corresponding lower-case versions
149 * (compatibility)
150 */
9bccf70c
A
151/*
152 * Added support for print long long (64-bit) integers.
153 * Use %lld, %Ld or %qd to print a 64-bit int. Other
154 * output bases such as x, X, u, U, o, and O also work.
155 */
1c79356b 156
55e303ae 157#include <debug.h>
55e303ae 158#include <mach_kdp.h>
1c79356b 159#include <mach/boolean.h>
1c79356b 160#include <kern/cpu_number.h>
1c79356b 161#include <kern/thread.h>
5ba3f43e 162#include <kern/debug.h>
1c79356b
A
163#include <kern/sched_prim.h>
164#include <kern/misc_protos.h>
165#include <stdarg.h>
166#include <string.h>
167#include <mach_assert.h>
168#ifdef MACH_BSD
169#include <sys/msgbuf.h>
170#endif
2d21ac55 171#include <console/serial_protos.h>
39037602 172#include <os/log_private.h>
1c79356b 173
5ba3f43e
A
174#ifdef __x86_64__
175#include <i386/cpu_data.h>
176#endif /* __x86_64__ */
177
178#if __arm__ || __arm64__
179#include <arm/cpu_data_internal.h>
180#endif
181
cb323159
A
182#ifdef HAS_APPLE_PAC
183#include <mach/vm_param.h>
184#include <ptrauth.h>
185#endif /* HAS_APPLE_PAC */
d9a64523 186
1c79356b
A
187#define isdigit(d) ((d) >= '0' && (d) <= '9')
188#define Ctod(c) ((c) - '0')
189
0a7de745 190#define MAXBUF (sizeof(long long int) * 8) /* enough for binary */
9bccf70c 191static char digs[] = "0123456789abcdef";
1c79356b 192
2d21ac55 193#if CONFIG_NO_PRINTF_STRINGS
b0d623f7
A
194/* Prevent CPP from breaking the definition below */
195#undef printf
2d21ac55
A
196#endif
197
0a7de745
A
198int
199_consume_printf_args(int a __unused, ...)
b0d623f7 200{
0a7de745 201 return 0;
b0d623f7 202}
0a7de745
A
203void
204_consume_kprintf_args(int a __unused, ...)
b0d623f7
A
205{
206}
207
9bccf70c 208static int
1c79356b 209printnum(
0a7de745
A
210 unsigned long long int u, /* number to print */
211 int base,
212 void (*putc)(int, void *),
9bccf70c 213 void *arg)
1c79356b 214{
0a7de745
A
215 char buf[MAXBUF]; /* build number here */
216 char * p = &buf[MAXBUF - 1];
9bccf70c 217 int nprinted = 0;
1c79356b
A
218
219 do {
0a7de745
A
220 *p-- = digs[u % base];
221 u /= base;
1c79356b
A
222 } while (u != 0);
223
9bccf70c 224 while (++p != &buf[MAXBUF]) {
0a7de745
A
225 (*putc)(*p, arg);
226 nprinted++;
9bccf70c 227 }
1c79356b 228
9bccf70c 229 return nprinted;
1c79356b
A
230}
231
0a7de745 232boolean_t _doprnt_truncates = FALSE;
1c79356b 233
0a7de745
A
234#if (DEVELOPMENT || DEBUG)
235boolean_t doprnt_hide_pointers = FALSE;
3e170ce0 236#else
0a7de745 237boolean_t doprnt_hide_pointers = TRUE;
3e170ce0
A
238#endif
239
9bccf70c
A
240int
241__doprnt(
0a7de745
A
242 const char *fmt,
243 va_list argp,
244 /* character output routine */
245 void (*putc)(int, void *arg),
9bccf70c 246 void *arg,
0a7de745
A
247 int radix, /* default radix - for '%r' */
248 int is_log)
1c79356b 249{
0a7de745
A
250 int length;
251 int prec;
252 boolean_t ladjust;
253 char padc;
254 long long n;
255 unsigned long long u;
256 int plus_sign;
257 int sign_char;
258 boolean_t altfmt, truncate;
259 int base;
260 char c;
261 int capitals;
262 int long_long;
cb323159
A
263 enum {
264 INT,
265 SHORT,
266 CHAR,
267 } numeric_type = INT;
9bccf70c 268 int nprinted = 0;
1c79356b 269
f427ee49
A
270 if (radix < 2 || radix > 36) {
271 radix = 10;
272 }
273
1c79356b 274 while ((c = *fmt) != '\0') {
0a7de745
A
275 if (c != '%') {
276 (*putc)(c, arg);
277 nprinted++;
278 fmt++;
279 continue;
1c79356b 280 }
1c79356b 281
0a7de745 282 fmt++;
1c79356b 283
0a7de745 284 long_long = 0;
cb323159 285 numeric_type = INT;
0a7de745
A
286 length = 0;
287 prec = -1;
288 ladjust = FALSE;
289 padc = ' ';
290 plus_sign = 0;
291 sign_char = 0;
292 altfmt = FALSE;
293
294 while (TRUE) {
295 c = *fmt;
296 if (c == '#') {
297 altfmt = TRUE;
298 } else if (c == '-') {
299 ladjust = TRUE;
300 } else if (c == '+') {
301 plus_sign = '+';
302 } else if (c == ' ') {
303 if (plus_sign == 0) {
304 plus_sign = ' ';
305 }
306 } else {
307 break;
308 }
309 fmt++;
1c79356b 310 }
0a7de745
A
311
312 if (c == '0') {
313 padc = '0';
314 c = *++fmt;
1c79356b 315 }
1c79356b 316
1c79356b 317 if (isdigit(c)) {
0a7de745
A
318 while (isdigit(c)) {
319 length = 10 * length + Ctod(c);
320 c = *++fmt;
321 }
322 } else if (c == '*') {
323 length = va_arg(argp, int);
1c79356b 324 c = *++fmt;
0a7de745
A
325 if (length < 0) {
326 ladjust = !ladjust;
327 length = -length;
328 }
1c79356b 329 }
0a7de745
A
330
331 if (c == '.') {
332 c = *++fmt;
333 if (isdigit(c)) {
334 prec = 0;
335 while (isdigit(c)) {
336 prec = 10 * prec + Ctod(c);
337 c = *++fmt;
338 }
339 } else if (c == '*') {
340 prec = va_arg(argp, int);
341 c = *++fmt;
342 }
1c79356b 343 }
1c79356b 344
9bccf70c 345 if (c == 'l') {
0a7de745
A
346 c = *++fmt; /* need it if sizeof(int) < sizeof(long) */
347 if (sizeof(int) < sizeof(long)) {
348 long_long = 1;
349 }
350 if (c == 'l') {
351 long_long = 1;
352 c = *++fmt;
353 }
cb323159
A
354 } else if (c == 'h') {
355 c = *++fmt;
356 numeric_type = SHORT;
357 if (c == 'h') {
358 numeric_type = CHAR;
359 c = *++fmt;
360 }
0a7de745
A
361 } else if (c == 'q' || c == 'L') {
362 long_long = 1;
363 c = *++fmt;
364 }
365
366 if (c == 'z' || c == 'Z') {
367 c = *++fmt;
368 if (sizeof(size_t) == sizeof(unsigned long)) {
369 long_long = 1;
370 }
371 }
372
373 truncate = FALSE;
374 capitals = 0; /* Assume lower case printing */
375
376 switch (c) {
1c79356b
A
377 case 'b':
378 case 'B':
379 {
0a7de745
A
380 char *p;
381 boolean_t any;
382 int i;
383
384 if (long_long) {
385 u = va_arg(argp, unsigned long long);
386 } else {
387 u = va_arg(argp, unsigned int);
388 }
389 p = va_arg(argp, char *);
390 base = *p++;
391 nprinted += printnum(u, base, putc, arg);
1c79356b 392
0a7de745
A
393 if (u == 0) {
394 break;
1c79356b 395 }
0a7de745
A
396
397 any = FALSE;
398 while ((i = *p++) != '\0') {
399 if (*fmt == 'B') {
400 i = 33 - i;
401 }
402 if (*p <= 32) {
403 /*
404 * Bit field
405 */
406 int j;
407 if (any) {
408 (*putc)(',', arg);
409 } else {
410 (*putc)('<', arg);
411 any = TRUE;
412 }
413 nprinted++;
414 j = *p++;
415 if (*fmt == 'B') {
416 j = 32 - j;
417 }
418 for (; (c = *p) > 32; p++) {
419 (*putc)(c, arg);
420 nprinted++;
421 }
422 nprinted += printnum((unsigned)((u >> (j - 1)) & ((2 << (i - j)) - 1)),
423 base, putc, arg);
424 } else if (u & (1 << (i - 1))) {
425 if (any) {
426 (*putc)(',', arg);
427 } else {
428 (*putc)('<', arg);
429 any = TRUE;
430 }
431 nprinted++;
432 for (; (c = *p) > 32; p++) {
433 (*putc)(c, arg);
434 nprinted++;
435 }
436 } else {
437 for (; *p > 32; p++) {
438 continue;
439 }
440 }
1c79356b 441 }
0a7de745
A
442 if (any) {
443 (*putc)('>', arg);
444 nprinted++;
1c79356b 445 }
0a7de745 446 break;
1c79356b
A
447 }
448
449 case 'c':
f427ee49 450 c = (char)va_arg(argp, int);
0a7de745
A
451 (*putc)(c, arg);
452 nprinted++;
453 break;
1c79356b
A
454
455 case 's':
456 {
0a7de745
A
457 const char *p;
458 const char *p2;
1c79356b 459
0a7de745
A
460 if (prec == -1) {
461 prec = 0x7fffffff; /* MAXINT */
462 }
463 p = va_arg(argp, char *);
1c79356b 464
0a7de745
A
465 if (p == NULL) {
466 p = "";
467 }
1c79356b 468
0a7de745
A
469 if (length > 0 && !ladjust) {
470 n = 0;
471 p2 = p;
1c79356b 472
0a7de745
A
473 for (; *p != '\0' && n < prec; p++) {
474 n++;
475 }
1c79356b 476
0a7de745 477 p = p2;
1c79356b 478
0a7de745
A
479 while (n < length) {
480 (*putc)(' ', arg);
481 n++;
482 nprinted++;
483 }
484 }
1c79356b 485
0a7de745
A
486 n = 0;
487
488 while ((n < prec) && (!(length > 0 && n >= length))) {
489 if (*p == '\0') {
490 break;
491 }
492 (*putc)(*p++, arg);
493 nprinted++;
494 n++;
1c79356b 495 }
0a7de745
A
496
497 if (n < length && ladjust) {
498 while (n < length) {
499 (*putc)(' ', arg);
500 n++;
501 nprinted++;
502 }
1c79356b 503 }
1c79356b 504
0a7de745 505 break;
1c79356b
A
506 }
507
508 case 'o':
0a7de745 509 truncate = _doprnt_truncates;
f427ee49 510 OS_FALLTHROUGH;
1c79356b 511 case 'O':
0a7de745
A
512 base = 8;
513 goto print_unsigned;
1c79356b 514
9bccf70c 515 case 'D': {
0a7de745
A
516 unsigned char *up;
517 char *q, *p;
518
b0d623f7
A
519 up = (unsigned char *)va_arg(argp, unsigned char *);
520 p = (char *)va_arg(argp, char *);
0a7de745 521 if (length == -1) {
9bccf70c 522 length = 16;
0a7de745
A
523 }
524 while (length--) {
9bccf70c
A
525 (*putc)(digs[(*up >> 4)], arg);
526 (*putc)(digs[(*up & 0x0f)], arg);
527 nprinted += 2;
528 up++;
529 if (length) {
0a7de745 530 for (q = p; *q; q++) {
9bccf70c
A
531 (*putc)(*q, arg);
532 nprinted++;
0a7de745 533 }
9bccf70c
A
534 }
535 }
536 break;
537 }
538
1c79356b 539 case 'd':
f427ee49 540 case 'i':
0a7de745
A
541 truncate = _doprnt_truncates;
542 base = 10;
543 goto print_signed;
1c79356b
A
544
545 case 'u':
0a7de745 546 truncate = _doprnt_truncates;
f427ee49 547 OS_FALLTHROUGH;
1c79356b 548 case 'U':
0a7de745
A
549 base = 10;
550 goto print_unsigned;
1c79356b
A
551
552 case 'p':
0a7de745
A
553 altfmt = TRUE;
554 if (sizeof(int) < sizeof(void *)) {
555 long_long = 1;
556 }
f427ee49 557 OS_FALLTHROUGH;
1c79356b 558 case 'x':
0a7de745
A
559 truncate = _doprnt_truncates;
560 base = 16;
561 goto print_unsigned;
1c79356b
A
562
563 case 'X':
0a7de745
A
564 base = 16;
565 capitals = 16; /* Print in upper case */
566 goto print_unsigned;
567
1c79356b 568 case 'r':
0a7de745 569 truncate = _doprnt_truncates;
f427ee49 570 OS_FALLTHROUGH;
1c79356b 571 case 'R':
0a7de745
A
572 base = radix;
573 goto print_signed;
1c79356b
A
574
575 case 'n':
0a7de745 576 truncate = _doprnt_truncates;
f427ee49 577 OS_FALLTHROUGH;
1c79356b 578 case 'N':
0a7de745
A
579 base = radix;
580 goto print_unsigned;
581
582print_signed:
583 if (long_long) {
584 n = va_arg(argp, long long);
585 } else {
586 n = va_arg(argp, int);
3e170ce0 587 }
cb323159
A
588 switch (numeric_type) {
589 case SHORT:
590 n = (short)n;
591 break;
592 case CHAR:
593 n = (char)n;
594 break;
595 default:
596 break;
597 }
0a7de745
A
598 if (n >= 0) {
599 u = n;
600 sign_char = plus_sign;
601 } else {
602 u = -n;
603 sign_char = '-';
9bccf70c 604 }
0a7de745
A
605 goto print_num;
606
607print_unsigned:
608 if (long_long) {
609 u = va_arg(argp, unsigned long long);
610 } else {
611 u = va_arg(argp, unsigned int);
612 }
cb323159
A
613 switch (numeric_type) {
614 case SHORT:
615 u = (unsigned short)u;
616 break;
617 case CHAR:
618 u = (unsigned char)u;
619 break;
620 default:
621 break;
622 }
0a7de745
A
623 goto print_num;
624
625print_num:
626 {
627 char buf[MAXBUF];/* build number here */
628 char * p = &buf[MAXBUF - 1];
629 static char digits[] = "0123456789abcdef0123456789ABCDEF";
630 const char *prefix = NULL;
631
632 if (truncate) {
633 u = (long long)((int)(u));
634 }
635
636 if (doprnt_hide_pointers && is_log) {
637 const char str[] = "<ptr>";
638 const char* strp = str;
639 int strl = sizeof(str) - 1;
640
cb323159
A
641#ifdef HAS_APPLE_PAC
642 /**
643 * Strip out the pointer authentication code before
644 * checking whether the pointer is a kernel address.
645 */
646 u = (unsigned long long)VM_KERNEL_STRIP_PTR(u);
647#endif /* HAS_APPLE_PAC */
0a7de745
A
648
649 if (u >= VM_MIN_KERNEL_AND_KEXT_ADDRESS && u <= VM_MAX_KERNEL_ADDRESS) {
650 while (*strp != '\0') {
651 (*putc)(*strp, arg);
652 strp++;
653 }
654 nprinted += strl;
655 break;
656 }
657 }
658
659 if (u != 0 && altfmt) {
660 if (base == 8) {
661 prefix = "0";
662 } else if (base == 16) {
663 prefix = "0x";
664 }
665 }
666
667 do {
668 /* Print in the correct case */
669 *p-- = digits[(u % base) + capitals];
670 u /= base;
671 } while (u != 0);
672
673 length -= (int)(&buf[MAXBUF - 1] - p);
674 if (sign_char) {
675 length--;
676 }
677 if (prefix) {
678 length -= (int)strlen(prefix);
679 }
680
681 if (padc == ' ' && !ladjust) {
682 /* blank padding goes before prefix */
683 while (--length >= 0) {
684 (*putc)(' ', arg);
685 nprinted++;
686 }
687 }
688 if (sign_char) {
689 (*putc)(sign_char, arg);
690 nprinted++;
691 }
692 if (prefix) {
693 while (*prefix) {
694 (*putc)(*prefix++, arg);
695 nprinted++;
696 }
697 }
698 if (padc == '0') {
699 /* zero padding goes after sign and prefix */
700 while (--length >= 0) {
701 (*putc)('0', arg);
702 nprinted++;
703 }
704 }
705 while (++p != &buf[MAXBUF]) {
706 (*putc)(*p, arg);
707 nprinted++;
708 }
709
710 if (ladjust) {
711 while (--length >= 0) {
712 (*putc)(' ', arg);
713 nprinted++;
714 }
715 }
716 break;
9bccf70c 717 }
1c79356b
A
718
719 case '\0':
0a7de745
A
720 fmt--;
721 break;
1c79356b
A
722
723 default:
0a7de745
A
724 (*putc)(c, arg);
725 nprinted++;
726 }
727 fmt++;
1c79356b 728 }
9bccf70c
A
729
730 return nprinted;
731}
732
733static void
734dummy_putc(int ch, void *arg)
735{
0a7de745
A
736 void (*real_putc)(char) = arg;
737
cb323159
A
738 /*
739 * Attempts to panic (or otherwise log to console) during early boot
740 * can result in _doprnt() and _doprnt_log() being called from
741 * _kprintf() before PE_init_kprintf() has been called. This causes
742 * the "putc" param to _doprnt() and _doprnt_log() to be passed as
743 * NULL. That NULL makes its way here, and we would try jump to it.
744 * Given that this is a poor idea, and this happens at very early
745 * boot, there is not a way to report this easily (we are likely
746 * already panicing), so we'll just do nothing instead of crashing.
747 */
748 if (real_putc) {
f427ee49 749 real_putc((char)ch);
cb323159 750 }
9bccf70c
A
751}
752
0a7de745 753void
9bccf70c 754_doprnt(
0a7de745
A
755 const char *fmt,
756 va_list *argp,
757 /* character output routine */
758 void (*putc)(char),
759 int radix) /* default radix - for '%r' */
9bccf70c 760{
0a7de745 761 __doprnt(fmt, *argp, dummy_putc, putc, radix, FALSE);
3e170ce0
A
762}
763
0a7de745 764void
3e170ce0 765_doprnt_log(
0a7de745
A
766 const char *fmt,
767 va_list *argp,
768 /* character output routine */
769 void (*putc)(char),
770 int radix) /* default radix - for '%r' */
3e170ce0 771{
0a7de745 772 __doprnt(fmt, *argp, dummy_putc, putc, radix, TRUE);
1c79356b
A
773}
774
0a7de745
A
775#if MP_PRINTF
776boolean_t new_printf_cpu_number = FALSE;
777#endif /* MP_PRINTF */
1c79356b 778
f427ee49 779SIMPLE_LOCK_DECLARE(bsd_log_spinlock, 0);
39037602 780
f427ee49
A
781bool bsd_log_lock(bool);
782void bsd_log_lock_safe(void);
91447636 783void bsd_log_unlock(void);
1c79356b 784
f427ee49
A
785/*
786 * Locks OS log lock and returns true if successful, false otherwise. Locking
787 * always succeeds in a safe context but may block. Locking in an unsafe context
788 * never blocks but fails if someone else is already holding the lock.
789 *
790 * A caller is responsible to decide whether the context is safe or not.
791 *
792 * As a rule of thumb following cases are *not* considered safe:
793 * - Interrupts are disabled
794 * - Pre-emption is disabled
795 * - When in a debugger
796 * - During a panic
797 */
798bool
799bsd_log_lock(bool safe)
1c79356b 800{
f427ee49
A
801 if (!safe) {
802 assert(!oslog_is_safe());
803 return simple_lock_try(&bsd_log_spinlock, LCK_GRP_NULL);
804 }
805 simple_lock(&bsd_log_spinlock, LCK_GRP_NULL);
806 return true;
91447636
A
807}
808
f427ee49
A
809/*
810 * Locks OS log lock assuming the context is safe. See bsd_log_lock() comment
811 * for details.
812 */
91447636 813void
f427ee49 814bsd_log_lock_safe(void)
91447636 815{
f427ee49 816 (void) bsd_log_lock(true);
91447636
A
817}
818
819void
2d21ac55 820bsd_log_unlock(void)
91447636
A
821{
822 simple_unlock(&bsd_log_spinlock);
1c79356b
A
823}
824
825/* derived from boot_gets */
826void
827safe_gets(
0a7de745
A
828 char *str,
829 int maxlen)
1c79356b 830{
39037602 831 char *lp;
f427ee49 832 char c;
1c79356b
A
833 char *strmax = str + maxlen - 1; /* allow space for trailing 0 */
834
835 lp = str;
836 for (;;) {
f427ee49 837 c = (char)cngetc();
1c79356b
A
838 switch (c) {
839 case '\n':
840 case '\r':
841 printf("\n");
842 *lp++ = 0;
843 return;
0a7de745 844
1c79356b
A
845 case '\b':
846 case '#':
847 case '\177':
848 if (lp > str) {
849 printf("\b \b");
850 lp--;
851 }
852 continue;
853
854 case '@':
855 case 'u'&037:
856 lp = str;
857 printf("\n\r");
858 continue;
859
860 default:
861 if (c >= ' ' && c < '\177') {
862 if (lp < strmax) {
863 *lp++ = c;
864 printf("%c", c);
0a7de745 865 } else {
1c79356b
A
866 printf("%c", '\007'); /* beep */
867 }
868 }
869 }
870 }
871}
872
2d21ac55
A
873extern int disableConsoleOutput;
874
1c79356b
A
875void
876conslog_putc(
877 char c)
878{
0a7de745 879 if (!disableConsoleOutput) {
1c79356b 880 cnputc(c);
0a7de745 881 }
1c79356b 882
0a7de745
A
883#ifdef MACH_BSD
884 if (!kernel_debugger_entry_count) {
593a1d5f 885 log_putc(c);
0a7de745 886 }
1c79356b
A
887#endif
888}
889
6d2010ae
A
890void
891cons_putc_locked(
892 char c)
893{
0a7de745 894 if (!disableConsoleOutput) {
6d2010ae 895 cnputc(c);
0a7de745 896 }
6d2010ae
A
897}
898
39037602
A
899static int
900vprintf_internal(const char *fmt, va_list ap_in, void *caller)
1c79356b 901{
5ba3f43e 902 cpu_data_t * cpu_data_p;
2d21ac55 903 if (fmt) {
5ba3f43e
A
904 struct console_printbuf_state info_data;
905 cpu_data_p = current_cpu_datap();
906
39037602
A
907 va_list ap;
908 va_copy(ap, ap_in);
5ba3f43e
A
909 /*
910 * for early boot printf()s console may not be setup,
911 * fallback to good old cnputc
912 */
913 if (cpu_data_p->cpu_console_buf != NULL) {
914 console_printbuf_state_init(&info_data, TRUE, TRUE);
915 __doprnt(fmt, ap, console_printbuf_putc, &info_data, 16, TRUE);
916 console_printbuf_clear(&info_data);
917 } else {
918 disable_preemption();
919 _doprnt_log(fmt, &ap, cons_putc_locked, 16);
920 enable_preemption();
921 }
39037602
A
922
923 va_end(ap);
924
5ba3f43e 925 os_log_with_args(OS_LOG_DEFAULT, OS_LOG_TYPE_DEFAULT, fmt, ap_in, caller);
2d21ac55
A
926 }
927 return 0;
1c79356b
A
928}
929
0a7de745 930__attribute__((noinline, not_tail_called))
39037602
A
931int
932printf(const char *fmt, ...)
933{
934 int ret;
935
936 va_list ap;
937 va_start(ap, fmt);
938 ret = vprintf_internal(fmt, ap, __builtin_return_address(0));
939 va_end(ap);
940
941 return ret;
942}
943
0a7de745 944__attribute__((noinline, not_tail_called))
39037602
A
945int
946vprintf(const char *fmt, va_list ap)
947{
948 return vprintf_internal(fmt, ap, __builtin_return_address(0));
949}
950
9bccf70c 951void
2d21ac55 952consdebug_putc(char c)
9bccf70c 953{
0a7de745 954 if (!disableConsoleOutput) {
9bccf70c 955 cnputc(c);
0a7de745 956 }
9bccf70c
A
957
958 debug_putc(c);
91447636 959
0a7de745 960 if (!console_is_serial() && !disable_serial_output) {
5ba3f43e 961 PE_kputc(c);
0a7de745 962 }
9bccf70c
A
963}
964
b0d623f7
A
965void
966consdebug_putc_unbuffered(char c)
967{
0a7de745 968 if (!disableConsoleOutput) {
b0d623f7 969 cnputc_unbuffered(c);
0a7de745 970 }
b0d623f7
A
971
972 debug_putc(c);
973
0a7de745
A
974 if (!console_is_serial() && !disable_serial_output) {
975 PE_kputc(c);
976 }
b0d623f7 977}
c910b4d9
A
978
979void
980consdebug_log(char c)
981{
982 debug_putc(c);
983}
984
5ba3f43e
A
985/*
986 * Append contents to the paniclog buffer but don't flush
987 * it. This is mainly used for writing the actual paniclog
988 * contents since flushing once for every line written
989 * would be prohibitively expensive for the paniclog
990 */
991int
992paniclog_append_noflush(const char *fmt, ...)
993{
0a7de745 994 va_list listp;
5ba3f43e
A
995
996 va_start(listp, fmt);
f427ee49 997 _doprnt_log(fmt, &listp, consdebug_putc_unbuffered, 16);
5ba3f43e
A
998 va_end(listp);
999
1000 return 0;
1001}
1002
2d21ac55 1003int
9bccf70c
A
1004kdb_printf(const char *fmt, ...)
1005{
0a7de745 1006 va_list listp;
9bccf70c
A
1007
1008 va_start(listp, fmt);
3e170ce0 1009 _doprnt_log(fmt, &listp, consdebug_putc, 16);
9bccf70c 1010 va_end(listp);
5ba3f43e 1011
f427ee49 1012#if defined(__arm__) || defined(__arm64__)
5ba3f43e
A
1013 paniclog_flush();
1014#endif
1015
2d21ac55 1016 return 0;
9bccf70c
A
1017}
1018
c910b4d9
A
1019int
1020kdb_log(const char *fmt, ...)
1021{
0a7de745 1022 va_list listp;
c910b4d9
A
1023
1024 va_start(listp, fmt);
1025 _doprnt(fmt, &listp, consdebug_log, 16);
1026 va_end(listp);
5ba3f43e 1027
f427ee49 1028#if defined(__arm__) || defined(__arm64__)
5ba3f43e
A
1029 paniclog_flush();
1030#endif
1031
c910b4d9
A
1032 return 0;
1033}
1034
b0d623f7
A
1035int
1036kdb_printf_unbuffered(const char *fmt, ...)
1037{
0a7de745 1038 va_list listp;
b0d623f7
A
1039
1040 va_start(listp, fmt);
1041 _doprnt(fmt, &listp, consdebug_putc_unbuffered, 16);
1042 va_end(listp);
5ba3f43e 1043
f427ee49 1044#if defined(__arm__) || defined(__arm64__)
5ba3f43e
A
1045 paniclog_flush();
1046#endif
1047
b0d623f7
A
1048 return 0;
1049}
1050
f427ee49 1051#if CONFIG_VSPRINTF
1c79356b 1052static void
2d21ac55 1053copybyte(int c, void *arg)
1c79356b 1054{
2d21ac55
A
1055 /*
1056 * arg is a pointer (outside pointer) to the pointer
1057 * (inside pointer) which points to the character.
1058 * We pass a double pointer, so that we can increment
1059 * the inside pointer.
1060 */
0a7de745 1061 char** p = arg; /* cast outside pointer */
f427ee49 1062 **p = (char)c; /* store character */
0a7de745 1063 (*p)++; /* increment inside pointer */
1c79356b
A
1064}
1065
2d21ac55
A
1066/*
1067 * Deprecation Warning:
1068 * sprintf() is being deprecated. Please use snprintf() instead.
1069 */
1c79356b
A
1070int
1071sprintf(char *buf, const char *fmt, ...)
1072{
0a7de745 1073 va_list listp;
2d21ac55 1074 char *copybyte_str;
1c79356b 1075
0a7de745
A
1076 va_start(listp, fmt);
1077 copybyte_str = buf;
1078 __doprnt(fmt, listp, copybyte, &copybyte_str, 16, FALSE);
1079 va_end(listp);
2d21ac55 1080 *copybyte_str = '\0';
0a7de745 1081 return (int)strlen(buf);
1c79356b 1082}
f427ee49 1083#endif /* CONFIG_VSPRINTF */