]> git.saurik.com Git - apple/xnu.git/blame - osfmk/kern/printf.c
xnu-6153.141.1.tar.gz
[apple/xnu.git] / osfmk / kern / printf.c
CommitLineData
1c79356b 1/*
cb323159 2 * Copyright (c) 2000-2019 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
A
269
270 while ((c = *fmt) != '\0') {
0a7de745
A
271 if (c != '%') {
272 (*putc)(c, arg);
273 nprinted++;
274 fmt++;
275 continue;
1c79356b 276 }
1c79356b 277
0a7de745 278 fmt++;
1c79356b 279
0a7de745 280 long_long = 0;
cb323159 281 numeric_type = INT;
0a7de745
A
282 length = 0;
283 prec = -1;
284 ladjust = FALSE;
285 padc = ' ';
286 plus_sign = 0;
287 sign_char = 0;
288 altfmt = FALSE;
289
290 while (TRUE) {
291 c = *fmt;
292 if (c == '#') {
293 altfmt = TRUE;
294 } else if (c == '-') {
295 ladjust = TRUE;
296 } else if (c == '+') {
297 plus_sign = '+';
298 } else if (c == ' ') {
299 if (plus_sign == 0) {
300 plus_sign = ' ';
301 }
302 } else {
303 break;
304 }
305 fmt++;
1c79356b 306 }
0a7de745
A
307
308 if (c == '0') {
309 padc = '0';
310 c = *++fmt;
1c79356b 311 }
1c79356b 312
1c79356b 313 if (isdigit(c)) {
0a7de745
A
314 while (isdigit(c)) {
315 length = 10 * length + Ctod(c);
316 c = *++fmt;
317 }
318 } else if (c == '*') {
319 length = va_arg(argp, int);
1c79356b 320 c = *++fmt;
0a7de745
A
321 if (length < 0) {
322 ladjust = !ladjust;
323 length = -length;
324 }
1c79356b 325 }
0a7de745
A
326
327 if (c == '.') {
328 c = *++fmt;
329 if (isdigit(c)) {
330 prec = 0;
331 while (isdigit(c)) {
332 prec = 10 * prec + Ctod(c);
333 c = *++fmt;
334 }
335 } else if (c == '*') {
336 prec = va_arg(argp, int);
337 c = *++fmt;
338 }
1c79356b 339 }
1c79356b 340
9bccf70c 341 if (c == 'l') {
0a7de745
A
342 c = *++fmt; /* need it if sizeof(int) < sizeof(long) */
343 if (sizeof(int) < sizeof(long)) {
344 long_long = 1;
345 }
346 if (c == 'l') {
347 long_long = 1;
348 c = *++fmt;
349 }
cb323159
A
350 } else if (c == 'h') {
351 c = *++fmt;
352 numeric_type = SHORT;
353 if (c == 'h') {
354 numeric_type = CHAR;
355 c = *++fmt;
356 }
0a7de745
A
357 } else if (c == 'q' || c == 'L') {
358 long_long = 1;
359 c = *++fmt;
360 }
361
362 if (c == 'z' || c == 'Z') {
363 c = *++fmt;
364 if (sizeof(size_t) == sizeof(unsigned long)) {
365 long_long = 1;
366 }
367 }
368
369 truncate = FALSE;
370 capitals = 0; /* Assume lower case printing */
371
372 switch (c) {
1c79356b
A
373 case 'b':
374 case 'B':
375 {
0a7de745
A
376 char *p;
377 boolean_t any;
378 int i;
379
380 if (long_long) {
381 u = va_arg(argp, unsigned long long);
382 } else {
383 u = va_arg(argp, unsigned int);
384 }
385 p = va_arg(argp, char *);
386 base = *p++;
387 nprinted += printnum(u, base, putc, arg);
1c79356b 388
0a7de745
A
389 if (u == 0) {
390 break;
1c79356b 391 }
0a7de745
A
392
393 any = FALSE;
394 while ((i = *p++) != '\0') {
395 if (*fmt == 'B') {
396 i = 33 - i;
397 }
398 if (*p <= 32) {
399 /*
400 * Bit field
401 */
402 int j;
403 if (any) {
404 (*putc)(',', arg);
405 } else {
406 (*putc)('<', arg);
407 any = TRUE;
408 }
409 nprinted++;
410 j = *p++;
411 if (*fmt == 'B') {
412 j = 32 - j;
413 }
414 for (; (c = *p) > 32; p++) {
415 (*putc)(c, arg);
416 nprinted++;
417 }
418 nprinted += printnum((unsigned)((u >> (j - 1)) & ((2 << (i - j)) - 1)),
419 base, putc, arg);
420 } else if (u & (1 << (i - 1))) {
421 if (any) {
422 (*putc)(',', arg);
423 } else {
424 (*putc)('<', arg);
425 any = TRUE;
426 }
427 nprinted++;
428 for (; (c = *p) > 32; p++) {
429 (*putc)(c, arg);
430 nprinted++;
431 }
432 } else {
433 for (; *p > 32; p++) {
434 continue;
435 }
436 }
1c79356b 437 }
0a7de745
A
438 if (any) {
439 (*putc)('>', arg);
440 nprinted++;
1c79356b 441 }
0a7de745 442 break;
1c79356b
A
443 }
444
445 case 'c':
0a7de745
A
446 c = va_arg(argp, int);
447 (*putc)(c, arg);
448 nprinted++;
449 break;
1c79356b
A
450
451 case 's':
452 {
0a7de745
A
453 const char *p;
454 const char *p2;
1c79356b 455
0a7de745
A
456 if (prec == -1) {
457 prec = 0x7fffffff; /* MAXINT */
458 }
459 p = va_arg(argp, char *);
1c79356b 460
0a7de745
A
461 if (p == NULL) {
462 p = "";
463 }
1c79356b 464
0a7de745
A
465 if (length > 0 && !ladjust) {
466 n = 0;
467 p2 = p;
1c79356b 468
0a7de745
A
469 for (; *p != '\0' && n < prec; p++) {
470 n++;
471 }
1c79356b 472
0a7de745 473 p = p2;
1c79356b 474
0a7de745
A
475 while (n < length) {
476 (*putc)(' ', arg);
477 n++;
478 nprinted++;
479 }
480 }
1c79356b 481
0a7de745
A
482 n = 0;
483
484 while ((n < prec) && (!(length > 0 && n >= length))) {
485 if (*p == '\0') {
486 break;
487 }
488 (*putc)(*p++, arg);
489 nprinted++;
490 n++;
1c79356b 491 }
0a7de745
A
492
493 if (n < length && ladjust) {
494 while (n < length) {
495 (*putc)(' ', arg);
496 n++;
497 nprinted++;
498 }
1c79356b 499 }
1c79356b 500
0a7de745 501 break;
1c79356b
A
502 }
503
504 case 'o':
0a7de745 505 truncate = _doprnt_truncates;
1c79356b 506 case 'O':
0a7de745
A
507 base = 8;
508 goto print_unsigned;
1c79356b 509
9bccf70c 510 case 'D': {
0a7de745
A
511 unsigned char *up;
512 char *q, *p;
513
b0d623f7
A
514 up = (unsigned char *)va_arg(argp, unsigned char *);
515 p = (char *)va_arg(argp, char *);
0a7de745 516 if (length == -1) {
9bccf70c 517 length = 16;
0a7de745
A
518 }
519 while (length--) {
9bccf70c
A
520 (*putc)(digs[(*up >> 4)], arg);
521 (*putc)(digs[(*up & 0x0f)], arg);
522 nprinted += 2;
523 up++;
524 if (length) {
0a7de745 525 for (q = p; *q; q++) {
9bccf70c
A
526 (*putc)(*q, arg);
527 nprinted++;
0a7de745 528 }
9bccf70c
A
529 }
530 }
531 break;
532 }
533
1c79356b 534 case 'd':
0a7de745
A
535 truncate = _doprnt_truncates;
536 base = 10;
537 goto print_signed;
1c79356b
A
538
539 case 'u':
0a7de745 540 truncate = _doprnt_truncates;
cb323159 541 /* FALLTHROUGH */
1c79356b 542 case 'U':
0a7de745
A
543 base = 10;
544 goto print_unsigned;
1c79356b
A
545
546 case 'p':
0a7de745
A
547 altfmt = TRUE;
548 if (sizeof(int) < sizeof(void *)) {
549 long_long = 1;
550 }
cb323159 551 /* FALLTHROUGH */
1c79356b 552 case 'x':
0a7de745
A
553 truncate = _doprnt_truncates;
554 base = 16;
555 goto print_unsigned;
1c79356b
A
556
557 case 'X':
0a7de745
A
558 base = 16;
559 capitals = 16; /* Print in upper case */
560 goto print_unsigned;
561
1c79356b 562 case 'r':
0a7de745 563 truncate = _doprnt_truncates;
cb323159 564 /* FALLTHROUGH */
1c79356b 565 case 'R':
0a7de745
A
566 base = radix;
567 goto print_signed;
1c79356b
A
568
569 case 'n':
0a7de745 570 truncate = _doprnt_truncates;
cb323159 571 /* FALLTHROUGH */
1c79356b 572 case 'N':
0a7de745
A
573 base = radix;
574 goto print_unsigned;
575
576print_signed:
577 if (long_long) {
578 n = va_arg(argp, long long);
579 } else {
580 n = va_arg(argp, int);
3e170ce0 581 }
cb323159
A
582 switch (numeric_type) {
583 case SHORT:
584 n = (short)n;
585 break;
586 case CHAR:
587 n = (char)n;
588 break;
589 default:
590 break;
591 }
0a7de745
A
592 if (n >= 0) {
593 u = n;
594 sign_char = plus_sign;
595 } else {
596 u = -n;
597 sign_char = '-';
9bccf70c 598 }
0a7de745
A
599 goto print_num;
600
601print_unsigned:
602 if (long_long) {
603 u = va_arg(argp, unsigned long long);
604 } else {
605 u = va_arg(argp, unsigned int);
606 }
cb323159
A
607 switch (numeric_type) {
608 case SHORT:
609 u = (unsigned short)u;
610 break;
611 case CHAR:
612 u = (unsigned char)u;
613 break;
614 default:
615 break;
616 }
0a7de745
A
617 goto print_num;
618
619print_num:
620 {
621 char buf[MAXBUF];/* build number here */
622 char * p = &buf[MAXBUF - 1];
623 static char digits[] = "0123456789abcdef0123456789ABCDEF";
624 const char *prefix = NULL;
625
626 if (truncate) {
627 u = (long long)((int)(u));
628 }
629
630 if (doprnt_hide_pointers && is_log) {
631 const char str[] = "<ptr>";
632 const char* strp = str;
633 int strl = sizeof(str) - 1;
634
cb323159
A
635#ifdef HAS_APPLE_PAC
636 /**
637 * Strip out the pointer authentication code before
638 * checking whether the pointer is a kernel address.
639 */
640 u = (unsigned long long)VM_KERNEL_STRIP_PTR(u);
641#endif /* HAS_APPLE_PAC */
0a7de745
A
642
643 if (u >= VM_MIN_KERNEL_AND_KEXT_ADDRESS && u <= VM_MAX_KERNEL_ADDRESS) {
644 while (*strp != '\0') {
645 (*putc)(*strp, arg);
646 strp++;
647 }
648 nprinted += strl;
649 break;
650 }
651 }
652
653 if (u != 0 && altfmt) {
654 if (base == 8) {
655 prefix = "0";
656 } else if (base == 16) {
657 prefix = "0x";
658 }
659 }
660
661 do {
662 /* Print in the correct case */
663 *p-- = digits[(u % base) + capitals];
664 u /= base;
665 } while (u != 0);
666
667 length -= (int)(&buf[MAXBUF - 1] - p);
668 if (sign_char) {
669 length--;
670 }
671 if (prefix) {
672 length -= (int)strlen(prefix);
673 }
674
675 if (padc == ' ' && !ladjust) {
676 /* blank padding goes before prefix */
677 while (--length >= 0) {
678 (*putc)(' ', arg);
679 nprinted++;
680 }
681 }
682 if (sign_char) {
683 (*putc)(sign_char, arg);
684 nprinted++;
685 }
686 if (prefix) {
687 while (*prefix) {
688 (*putc)(*prefix++, arg);
689 nprinted++;
690 }
691 }
692 if (padc == '0') {
693 /* zero padding goes after sign and prefix */
694 while (--length >= 0) {
695 (*putc)('0', arg);
696 nprinted++;
697 }
698 }
699 while (++p != &buf[MAXBUF]) {
700 (*putc)(*p, arg);
701 nprinted++;
702 }
703
704 if (ladjust) {
705 while (--length >= 0) {
706 (*putc)(' ', arg);
707 nprinted++;
708 }
709 }
710 break;
9bccf70c 711 }
1c79356b
A
712
713 case '\0':
0a7de745
A
714 fmt--;
715 break;
1c79356b
A
716
717 default:
0a7de745
A
718 (*putc)(c, arg);
719 nprinted++;
720 }
721 fmt++;
1c79356b 722 }
9bccf70c
A
723
724 return nprinted;
725}
726
727static void
728dummy_putc(int ch, void *arg)
729{
0a7de745
A
730 void (*real_putc)(char) = arg;
731
cb323159
A
732 /*
733 * Attempts to panic (or otherwise log to console) during early boot
734 * can result in _doprnt() and _doprnt_log() being called from
735 * _kprintf() before PE_init_kprintf() has been called. This causes
736 * the "putc" param to _doprnt() and _doprnt_log() to be passed as
737 * NULL. That NULL makes its way here, and we would try jump to it.
738 * Given that this is a poor idea, and this happens at very early
739 * boot, there is not a way to report this easily (we are likely
740 * already panicing), so we'll just do nothing instead of crashing.
741 */
742 if (real_putc) {
743 real_putc(ch);
744 }
9bccf70c
A
745}
746
0a7de745 747void
9bccf70c 748_doprnt(
0a7de745
A
749 const char *fmt,
750 va_list *argp,
751 /* character output routine */
752 void (*putc)(char),
753 int radix) /* default radix - for '%r' */
9bccf70c 754{
0a7de745 755 __doprnt(fmt, *argp, dummy_putc, putc, radix, FALSE);
3e170ce0
A
756}
757
0a7de745 758void
3e170ce0 759_doprnt_log(
0a7de745
A
760 const char *fmt,
761 va_list *argp,
762 /* character output routine */
763 void (*putc)(char),
764 int radix) /* default radix - for '%r' */
3e170ce0 765{
0a7de745 766 __doprnt(fmt, *argp, dummy_putc, putc, radix, TRUE);
1c79356b
A
767}
768
0a7de745
A
769#if MP_PRINTF
770boolean_t new_printf_cpu_number = FALSE;
771#endif /* MP_PRINTF */
1c79356b 772
cb323159
A
773decl_simple_lock_data(, printf_lock);
774decl_simple_lock_data(, bsd_log_spinlock);
39037602 775
0a7de745 776lck_grp_t oslog_stream_lock_grp;
cb323159 777decl_lck_spin_data(, oslog_stream_lock);
39037602
A
778void oslog_lock_init(void);
779
91447636
A
780extern void bsd_log_init(void);
781void bsd_log_lock(void);
782void bsd_log_unlock(void);
1c79356b
A
783
784void
785printf_init(void)
786{
787 /*
788 * Lock is only really needed after the first thread is created.
789 */
91447636
A
790 simple_lock_init(&printf_lock, 0);
791 simple_lock_init(&bsd_log_spinlock, 0);
792 bsd_log_init();
91447636
A
793}
794
795void
2d21ac55 796bsd_log_lock(void)
91447636 797{
0a7de745 798 simple_lock(&bsd_log_spinlock, LCK_GRP_NULL);
91447636
A
799}
800
801void
2d21ac55 802bsd_log_unlock(void)
91447636
A
803{
804 simple_unlock(&bsd_log_spinlock);
1c79356b
A
805}
806
39037602
A
807void
808oslog_lock_init(void)
809{
810 lck_grp_init(&oslog_stream_lock_grp, "oslog stream", LCK_GRP_ATTR_NULL);
811 lck_spin_init(&oslog_stream_lock, &oslog_stream_lock_grp, LCK_ATTR_NULL);
812}
813
1c79356b
A
814/* derived from boot_gets */
815void
816safe_gets(
0a7de745
A
817 char *str,
818 int maxlen)
1c79356b 819{
39037602
A
820 char *lp;
821 int c;
1c79356b
A
822 char *strmax = str + maxlen - 1; /* allow space for trailing 0 */
823
824 lp = str;
825 for (;;) {
826 c = cngetc();
827 switch (c) {
828 case '\n':
829 case '\r':
830 printf("\n");
831 *lp++ = 0;
832 return;
0a7de745 833
1c79356b
A
834 case '\b':
835 case '#':
836 case '\177':
837 if (lp > str) {
838 printf("\b \b");
839 lp--;
840 }
841 continue;
842
843 case '@':
844 case 'u'&037:
845 lp = str;
846 printf("\n\r");
847 continue;
848
849 default:
850 if (c >= ' ' && c < '\177') {
851 if (lp < strmax) {
852 *lp++ = c;
853 printf("%c", c);
0a7de745 854 } else {
1c79356b
A
855 printf("%c", '\007'); /* beep */
856 }
857 }
858 }
859 }
860}
861
2d21ac55
A
862extern int disableConsoleOutput;
863
1c79356b
A
864void
865conslog_putc(
866 char c)
867{
0a7de745 868 if (!disableConsoleOutput) {
1c79356b 869 cnputc(c);
0a7de745 870 }
1c79356b 871
0a7de745
A
872#ifdef MACH_BSD
873 if (!kernel_debugger_entry_count) {
593a1d5f 874 log_putc(c);
0a7de745 875 }
1c79356b
A
876#endif
877}
878
6d2010ae
A
879void
880cons_putc_locked(
881 char c)
882{
0a7de745 883 if (!disableConsoleOutput) {
6d2010ae 884 cnputc(c);
0a7de745 885 }
6d2010ae
A
886}
887
39037602
A
888static int
889vprintf_internal(const char *fmt, va_list ap_in, void *caller)
1c79356b 890{
5ba3f43e 891 cpu_data_t * cpu_data_p;
2d21ac55 892 if (fmt) {
5ba3f43e
A
893 struct console_printbuf_state info_data;
894 cpu_data_p = current_cpu_datap();
895
39037602
A
896 va_list ap;
897 va_copy(ap, ap_in);
5ba3f43e
A
898 /*
899 * for early boot printf()s console may not be setup,
900 * fallback to good old cnputc
901 */
902 if (cpu_data_p->cpu_console_buf != NULL) {
903 console_printbuf_state_init(&info_data, TRUE, TRUE);
904 __doprnt(fmt, ap, console_printbuf_putc, &info_data, 16, TRUE);
905 console_printbuf_clear(&info_data);
906 } else {
907 disable_preemption();
908 _doprnt_log(fmt, &ap, cons_putc_locked, 16);
909 enable_preemption();
910 }
39037602
A
911
912 va_end(ap);
913
5ba3f43e 914 os_log_with_args(OS_LOG_DEFAULT, OS_LOG_TYPE_DEFAULT, fmt, ap_in, caller);
2d21ac55
A
915 }
916 return 0;
1c79356b
A
917}
918
0a7de745 919__attribute__((noinline, not_tail_called))
39037602
A
920int
921printf(const char *fmt, ...)
922{
923 int ret;
924
925 va_list ap;
926 va_start(ap, fmt);
927 ret = vprintf_internal(fmt, ap, __builtin_return_address(0));
928 va_end(ap);
929
930 return ret;
931}
932
0a7de745 933__attribute__((noinline, not_tail_called))
39037602
A
934int
935vprintf(const char *fmt, va_list ap)
936{
937 return vprintf_internal(fmt, ap, __builtin_return_address(0));
938}
939
9bccf70c 940void
2d21ac55 941consdebug_putc(char c)
9bccf70c 942{
0a7de745 943 if (!disableConsoleOutput) {
9bccf70c 944 cnputc(c);
0a7de745 945 }
9bccf70c
A
946
947 debug_putc(c);
91447636 948
0a7de745 949 if (!console_is_serial() && !disable_serial_output) {
5ba3f43e 950 PE_kputc(c);
0a7de745 951 }
9bccf70c
A
952}
953
b0d623f7
A
954void
955consdebug_putc_unbuffered(char c)
956{
0a7de745 957 if (!disableConsoleOutput) {
b0d623f7 958 cnputc_unbuffered(c);
0a7de745 959 }
b0d623f7
A
960
961 debug_putc(c);
962
0a7de745
A
963 if (!console_is_serial() && !disable_serial_output) {
964 PE_kputc(c);
965 }
b0d623f7 966}
c910b4d9
A
967
968void
969consdebug_log(char c)
970{
971 debug_putc(c);
972}
973
5ba3f43e
A
974/*
975 * Append contents to the paniclog buffer but don't flush
976 * it. This is mainly used for writing the actual paniclog
977 * contents since flushing once for every line written
978 * would be prohibitively expensive for the paniclog
979 */
980int
981paniclog_append_noflush(const char *fmt, ...)
982{
0a7de745 983 va_list listp;
5ba3f43e
A
984
985 va_start(listp, fmt);
986 _doprnt_log(fmt, &listp, consdebug_putc, 16);
987 va_end(listp);
988
989 return 0;
990}
991
2d21ac55 992int
9bccf70c
A
993kdb_printf(const char *fmt, ...)
994{
0a7de745 995 va_list listp;
9bccf70c
A
996
997 va_start(listp, fmt);
3e170ce0 998 _doprnt_log(fmt, &listp, consdebug_putc, 16);
9bccf70c 999 va_end(listp);
5ba3f43e
A
1000
1001#if CONFIG_EMBEDDED
1002 paniclog_flush();
1003#endif
1004
2d21ac55 1005 return 0;
9bccf70c
A
1006}
1007
c910b4d9
A
1008int
1009kdb_log(const char *fmt, ...)
1010{
0a7de745 1011 va_list listp;
c910b4d9
A
1012
1013 va_start(listp, fmt);
1014 _doprnt(fmt, &listp, consdebug_log, 16);
1015 va_end(listp);
5ba3f43e
A
1016
1017#if CONFIG_EMBEDDED
1018 paniclog_flush();
1019#endif
1020
c910b4d9
A
1021 return 0;
1022}
1023
b0d623f7
A
1024int
1025kdb_printf_unbuffered(const char *fmt, ...)
1026{
0a7de745 1027 va_list listp;
b0d623f7
A
1028
1029 va_start(listp, fmt);
1030 _doprnt(fmt, &listp, consdebug_putc_unbuffered, 16);
1031 va_end(listp);
5ba3f43e
A
1032
1033#if CONFIG_EMBEDDED
1034 paniclog_flush();
1035#endif
1036
b0d623f7
A
1037 return 0;
1038}
1039
5ba3f43e 1040#if !CONFIG_EMBEDDED
6d2010ae 1041
1c79356b 1042static void
2d21ac55 1043copybyte(int c, void *arg)
1c79356b 1044{
2d21ac55
A
1045 /*
1046 * arg is a pointer (outside pointer) to the pointer
1047 * (inside pointer) which points to the character.
1048 * We pass a double pointer, so that we can increment
1049 * the inside pointer.
1050 */
0a7de745
A
1051 char** p = arg; /* cast outside pointer */
1052 **p = c; /* store character */
1053 (*p)++; /* increment inside pointer */
1c79356b
A
1054}
1055
2d21ac55
A
1056/*
1057 * Deprecation Warning:
1058 * sprintf() is being deprecated. Please use snprintf() instead.
1059 */
1c79356b
A
1060int
1061sprintf(char *buf, const char *fmt, ...)
1062{
0a7de745 1063 va_list listp;
2d21ac55 1064 char *copybyte_str;
1c79356b 1065
0a7de745
A
1066 va_start(listp, fmt);
1067 copybyte_str = buf;
1068 __doprnt(fmt, listp, copybyte, &copybyte_str, 16, FALSE);
1069 va_end(listp);
2d21ac55 1070 *copybyte_str = '\0';
0a7de745 1071 return (int)strlen(buf);
1c79356b 1072}
5ba3f43e 1073#endif /* !CONFIG_EMBEDDED */