1/*
2 * Copyright (c) 2000-2020 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28/*
29 * @OSF_COPYRIGHT@
30 */
31
32/*
33 * Mach Operating System
34 * Copyright (c) 1991,1990,1989,1988 Carnegie Mellon University
35 * All Rights Reserved.
36 *
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.
42 *
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.
46 *
47 * Carnegie Mellon requests users of this software to return to
48 *
49 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
50 * School of Computer Science
51 * Carnegie Mellon University
52 * Pittsburgh PA 15213-3890
53 *
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
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
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 *
97 * This version does not implement %f, %e, or %g.
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
105 *
106 * Tweaked for long long support and extended to support the hexdump %D
107 * specifier by dbg 05/02/02.
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 *
144 * z set length equal to size_t
145 * r signed, 'radix'
146 * n unsigned, 'radix'
147 *
148 * D,U,O,Z same as corresponding lower-case versions
149 * (compatibility)
150 */
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 */
156
157#include <debug.h>
158#include <mach_kdp.h>
159#include <mach/boolean.h>
160#include <kern/cpu_number.h>
161#include <kern/thread.h>
162#include <kern/debug.h>
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
171#include <console/serial_protos.h>
172#include <os/log_private.h>
173
174#ifdef __x86_64__
175#include <i386/cpu_data.h>
176#endif /* __x86_64__ */
177
178#if __arm64__
179#include <arm/cpu_data_internal.h>
180#endif
181
182#ifdef HAS_APPLE_PAC
183#include <mach/vm_param.h>
184#include <ptrauth.h>
185#endif /* HAS_APPLE_PAC */
186
187#define isdigit(d) ((d) >= '0' && (d) <= '9')
188#define Ctod(c) ((c) - '0')
189
190#define MAXBUF (sizeof(long long int) * 8) /* enough for binary */
191static char digs[] = "0123456789abcdef";
192
193#if CONFIG_NO_PRINTF_STRINGS
194/* Prevent CPP from breaking the definition below */
195#undef printf
196#endif
197
198int
199_consume_printf_args(int a __unused, ...)
200{
201 return 0;
202}
203void
204_consume_kprintf_args(int a __unused, ...)
205{
206}
207
208static int
209printnum(
210 unsigned long long int u, /* number to print */
211 int base,
212 void (*putc)(int, void *),
213 void *arg)
214{
215 char buf[MAXBUF]; /* build number here */
216 char * p = &buf[MAXBUF - 1];
217 int nprinted = 0;
218
219 do {
220 *p-- = digs[u % base];
221 u /= base;
222 } while (u != 0);
223
224 while (++p != &buf[MAXBUF]) {
225 (*putc)(*p, arg);
226 nprinted++;
227 }
228
229 return nprinted;
230}
231
232boolean_t _doprnt_truncates = FALSE;
233
234#if (DEVELOPMENT || DEBUG)
235boolean_t doprnt_hide_pointers = FALSE;
236#else
237boolean_t doprnt_hide_pointers = TRUE;
238#endif
239
240int
241__doprnt(
242 const char *fmt,
243 va_list argp,
244 /* character output routine */
245 void (*putc)(int, void *arg),
246 void *arg,
247 int radix, /* default radix - for '%r' */
248 int is_log)
249{
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;
263 enum {
264 INT,
265 SHORT,
266 CHAR,
267 } numeric_type = INT;
268 int nprinted = 0;
269
270 if (radix < 2 || radix > 36) {
271 radix = 10;
272 }
273
274 while ((c = *fmt) != '\0') {
275 if (c != '%') {
276 (*putc)(c, arg);
277 nprinted++;
278 fmt++;
279 continue;
280 }
281
282 fmt++;
283
284 long_long = 0;
285 numeric_type = INT;
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++;
310 }
311
312 if (c == '0') {
313 padc = '0';
314 c = *++fmt;
315 }
316
317 if (isdigit(c)) {
318 while (isdigit(c)) {
319 length = 10 * length + Ctod(c);
320 c = *++fmt;
321 }
322 } else if (c == '*') {
323 length = va_arg(argp, int);
324 c = *++fmt;
325 if (length < 0) {
326 ladjust = !ladjust;
327 length = -length;
328 }
329 }
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 }
343 }
344
345 if (c == 'l') {
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 }
354 } else if (c == 'h') {
355 c = *++fmt;
356 numeric_type = SHORT;
357 if (c == 'h') {
358 numeric_type = CHAR;
359 c = *++fmt;
360 }
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 long)) {
369 long_long = 1;
370 }
371 } else if (c == 't') {
372 c = *++fmt;
373 if (sizeof(ptrdiff_t) == sizeof(unsigned long long)) {
374 long_long = 1;
375 }
376 } else if (c == 'j') {
377 c = *++fmt;
378 if (sizeof(intmax_t) == sizeof(unsigned long long)) {
379 long_long = 1;
380 }
381 }
382
383 truncate = FALSE;
384 capitals = 0; /* Assume lower case printing */
385
386 switch (c) {
387 case 'b':
388 case 'B':
389 {
390 char *p;
391 boolean_t any;
392 int i;
393
394 if (long_long) {
395 u = va_arg(argp, unsigned long long);
396 } else {
397 u = va_arg(argp, unsigned int);
398 }
399 p = va_arg(argp, char *);
400 base = *p++;
401 nprinted += printnum(u, base, putc, arg);
402
403 if (u == 0) {
404 break;
405 }
406
407 any = FALSE;
408 while ((i = *p++) != '\0') {
409 if (*fmt == 'B') {
410 i = 33 - i;
411 }
412 if (*p <= 32) {
413 /*
414 * Bit field
415 */
416 int j;
417 if (any) {
418 (*putc)(',', arg);
419 } else {
420 (*putc)('<', arg);
421 any = TRUE;
422 }
423 nprinted++;
424 j = *p++;
425 if (*fmt == 'B') {
426 j = 32 - j;
427 }
428 for (; (c = *p) > 32; p++) {
429 (*putc)(c, arg);
430 nprinted++;
431 }
432 nprinted += printnum(u: (unsigned)((u >> (j - 1)) & ((2 << (i - j)) - 1)),
433 base, putc, arg);
434 } else if (u & (1 << (i - 1))) {
435 if (any) {
436 (*putc)(',', arg);
437 } else {
438 (*putc)('<', arg);
439 any = TRUE;
440 }
441 nprinted++;
442 for (; (c = *p) > 32; p++) {
443 (*putc)(c, arg);
444 nprinted++;
445 }
446 } else {
447 for (; *p > 32; p++) {
448 continue;
449 }
450 }
451 }
452 if (any) {
453 (*putc)('>', arg);
454 nprinted++;
455 }
456 break;
457 }
458
459 case 'c':
460 c = (char)va_arg(argp, int);
461 (*putc)(c, arg);
462 nprinted++;
463 break;
464
465 case 's':
466 {
467 const char *p;
468 const char *p2;
469
470 if (prec == -1) {
471 prec = 0x7fffffff; /* MAXINT */
472 }
473 p = va_arg(argp, char *);
474
475 if (p == NULL) {
476 p = "";
477 }
478
479 if (length > 0 && !ladjust) {
480 n = 0;
481 p2 = p;
482
483 for (; *p != '\0' && n < prec; p++) {
484 n++;
485 }
486
487 p = p2;
488
489 while (n < length) {
490 (*putc)(' ', arg);
491 n++;
492 nprinted++;
493 }
494 }
495
496 n = 0;
497
498 while ((n < prec) && (!(length > 0 && n >= length))) {
499 if (*p == '\0') {
500 break;
501 }
502 (*putc)(*p++, arg);
503 nprinted++;
504 n++;
505 }
506
507 if (n < length && ladjust) {
508 while (n < length) {
509 (*putc)(' ', arg);
510 n++;
511 nprinted++;
512 }
513 }
514
515 break;
516 }
517
518 case 'o':
519 truncate = _doprnt_truncates;
520 OS_FALLTHROUGH;
521 case 'O':
522 base = 8;
523 goto print_unsigned;
524
525 case 'D': {
526 unsigned char *up;
527 char *q, *p;
528
529 up = (unsigned char *)va_arg(argp, unsigned char *);
530 p = (char *)va_arg(argp, char *);
531 if (length == -1) {
532 length = 16;
533 }
534 while (length--) {
535 (*putc)(digs[(*up >> 4)], arg);
536 (*putc)(digs[(*up & 0x0f)], arg);
537 nprinted += 2;
538 up++;
539 if (length) {
540 for (q = p; *q; q++) {
541 (*putc)(*q, arg);
542 nprinted++;
543 }
544 }
545 }
546 break;
547 }
548
549 case 'd':
550 case 'i':
551 truncate = _doprnt_truncates;
552 base = 10;
553 goto print_signed;
554
555 case 'u':
556 truncate = _doprnt_truncates;
557 OS_FALLTHROUGH;
558 case 'U':
559 base = 10;
560 goto print_unsigned;
561
562 case 'p':
563 altfmt = TRUE;
564 if (sizeof(int) < sizeof(void *)) {
565 long_long = 1;
566 }
567 OS_FALLTHROUGH;
568 case 'x':
569 truncate = _doprnt_truncates;
570 base = 16;
571 goto print_unsigned;
572
573 case 'X':
574 base = 16;
575 capitals = 16; /* Print in upper case */
576 goto print_unsigned;
577
578 case 'r':
579 truncate = _doprnt_truncates;
580 OS_FALLTHROUGH;
581 case 'R':
582 base = radix;
583 goto print_signed;
584
585 case 'n':
586 truncate = _doprnt_truncates;
587 OS_FALLTHROUGH;
588 case 'N':
589 base = radix;
590 goto print_unsigned;
591
592print_signed:
593 if (long_long) {
594 n = va_arg(argp, long long);
595 } else {
596 n = va_arg(argp, int);
597 }
598 switch (numeric_type) {
599 case SHORT:
600 n = (short)n;
601 break;
602 case CHAR:
603 n = (char)n;
604 break;
605 default:
606 break;
607 }
608 if (n >= 0) {
609 u = n;
610 sign_char = plus_sign;
611 } else {
612 u = -n;
613 sign_char = '-';
614 }
615 goto print_num;
616
617print_unsigned:
618 if (long_long) {
619 u = va_arg(argp, unsigned long long);
620 } else {
621 u = va_arg(argp, unsigned int);
622 }
623 switch (numeric_type) {
624 case SHORT:
625 u = (unsigned short)u;
626 break;
627 case CHAR:
628 u = (unsigned char)u;
629 break;
630 default:
631 break;
632 }
633 goto print_num;
634
635print_num:
636 {
637 char buf[MAXBUF];/* build number here */
638 char * p = &buf[MAXBUF - 1];
639 static char digits[] = "0123456789abcdef0123456789ABCDEF";
640 const char *prefix = NULL;
641
642 if (truncate) {
643 u = (long long)((int)(u));
644 }
645
646 if (doprnt_hide_pointers && is_log) {
647 const char str[] = "<ptr>";
648 const char* strp = str;
649 int strl = sizeof(str) - 1;
650 unsigned long long u_stripped = u;
651#ifdef HAS_APPLE_PAC
652 /**
653 * Strip out the pointer authentication code before
654 * checking whether the pointer is a kernel address.
655 */
656 u_stripped = (unsigned long long)VM_KERNEL_STRIP_PTR(u);
657#endif /* HAS_APPLE_PAC */
658
659 if (u_stripped >= VM_MIN_KERNEL_AND_KEXT_ADDRESS && u_stripped <= VM_MAX_KERNEL_ADDRESS) {
660 while (*strp != '\0') {
661 (*putc)(*strp, arg);
662 strp++;
663 }
664 nprinted += strl;
665 break;
666 }
667 }
668
669 if (u != 0 && altfmt) {
670 if (base == 8) {
671 prefix = "0";
672 } else if (base == 16) {
673 prefix = "0x";
674 }
675 }
676
677 do {
678 /* Print in the correct case */
679 *p-- = digits[(u % base) + capitals];
680 u /= base;
681 } while (u != 0);
682
683 length -= (int)(&buf[MAXBUF - 1] - p);
684 if (sign_char) {
685 length--;
686 }
687 if (prefix) {
688 length -= (int)strlen(s: prefix);
689 }
690
691 if (padc == ' ' && !ladjust) {
692 /* blank padding goes before prefix */
693 while (--length >= 0) {
694 (*putc)(' ', arg);
695 nprinted++;
696 }
697 }
698 if (sign_char) {
699 (*putc)(sign_char, arg);
700 nprinted++;
701 }
702 if (prefix) {
703 while (*prefix) {
704 (*putc)(*prefix++, arg);
705 nprinted++;
706 }
707 }
708 if (padc == '0') {
709 /* zero padding goes after sign and prefix */
710 while (--length >= 0) {
711 (*putc)('0', arg);
712 nprinted++;
713 }
714 }
715 while (++p != &buf[MAXBUF]) {
716 (*putc)(*p, arg);
717 nprinted++;
718 }
719
720 if (ladjust) {
721 while (--length >= 0) {
722 (*putc)(' ', arg);
723 nprinted++;
724 }
725 }
726 break;
727 }
728
729 case '\0':
730 fmt--;
731 break;
732
733 default:
734 (*putc)(c, arg);
735 nprinted++;
736 }
737 fmt++;
738 }
739
740 return nprinted;
741}
742
743static void
744dummy_putc(int ch, void *arg)
745{
746 void (*real_putc)(char) = arg;
747
748 /*
749 * Attempts to panic (or otherwise log to console) during early boot
750 * can result in _doprnt() and _doprnt_log() being called from
751 * _kprintf() before PE_init_kprintf() has been called. This causes
752 * the "putc" param to _doprnt() and _doprnt_log() to be passed as
753 * NULL. That NULL makes its way here, and we would try jump to it.
754 * Given that this is a poor idea, and this happens at very early
755 * boot, there is not a way to report this easily (we are likely
756 * already panicing), so we'll just do nothing instead of crashing.
757 */
758 if (real_putc) {
759 real_putc((char)ch);
760 }
761}
762
763void
764_doprnt(
765 const char *fmt,
766 va_list *argp,
767 /* character output routine */
768 void (*putc)(char),
769 int radix) /* default radix - for '%r' */
770{
771 __doprnt(fmt, argp: *argp, putc: dummy_putc, arg: putc, radix, FALSE);
772}
773
774void
775_doprnt_log(
776 const char *fmt,
777 va_list *argp,
778 /* character output routine */
779 void (*putc)(char),
780 int radix) /* default radix - for '%r' */
781{
782 __doprnt(fmt, argp: *argp, putc: dummy_putc, arg: putc, radix, TRUE);
783}
784
785#if MP_PRINTF
786boolean_t new_printf_cpu_number = FALSE;
787#endif /* MP_PRINTF */
788
789LCK_GRP_DECLARE(log_lock_grp, "log_group");
790
791#if defined(__x86_64__)
792SIMPLE_LOCK_DECLARE(log_lock, 0);
793#else
794LCK_TICKET_DECLARE(log_lock, &log_lock_grp);
795#endif /* __x86_64__ */
796
797bool bsd_log_lock(bool);
798void bsd_log_lock_safe(void);
799void bsd_log_unlock(void);
800
801/*
802 * Locks OS log lock and returns true if successful, false otherwise. Locking
803 * always succeeds in a safe context but may block. Locking in an unsafe context
804 * never blocks but fails if someone else is already holding the lock.
805 *
806 * A caller is responsible to decide whether the context is safe or not.
807 *
808 * As a rule of thumb following cases are *not* considered safe:
809 * - Interrupts are disabled
810 * - Pre-emption is disabled
811 * - When in a debugger
812 * - During a panic
813 */
814bool
815bsd_log_lock(bool safe)
816{
817 if (!safe) {
818 assert(!oslog_is_safe());
819#if defined(__x86_64__)
820 return simple_lock_try(&log_lock, &log_lock_grp);
821#else
822 return lck_ticket_lock_try(tlock: &log_lock, grp: &log_lock_grp);
823#endif /* __x86_64__ */
824 }
825#if defined(__x86_64__)
826 simple_lock(&log_lock, &log_lock_grp);
827#else
828 lck_ticket_lock(tlock: &log_lock, grp: &log_lock_grp);
829#endif /* __x86_64__ */
830 return true;
831}
832
833/*
834 * Locks OS log lock assuming the context is safe. See bsd_log_lock() comment
835 * for details.
836 */
837void
838bsd_log_lock_safe(void)
839{
840 (void) bsd_log_lock(true);
841}
842
843void
844bsd_log_unlock(void)
845{
846#if defined(__x86_64__)
847 simple_unlock(&log_lock);
848#else
849 lck_ticket_unlock(tlock: &log_lock);
850#endif /* __x86_64__ */
851}
852
853void
854conslog_putc(char c)
855{
856 console_write_char(c);
857
858#ifdef MACH_BSD
859 if (!kernel_debugger_entry_count) {
860 log_putc(c);
861 }
862#endif
863}
864
865void
866cons_putc_locked(char c)
867{
868 console_write_char(c);
869}
870
871__printflike(1, 0)
872static int
873vprintf_internal(const char *fmt, va_list ap_in, void *caller)
874{
875 if (fmt) {
876 struct console_printbuf_state info_data;
877
878 va_list ap;
879 va_copy(ap, ap_in);
880
881#pragma clang diagnostic push
882#pragma clang diagnostic ignored "-Wformat-nonliteral"
883 os_log_with_args(OS_LOG_DEFAULT, type: OS_LOG_TYPE_DEFAULT, format: fmt, args: ap_in, ret_addr: caller);
884#pragma clang diagnostic pop
885
886 console_printbuf_state_init(data: &info_data, TRUE, TRUE);
887 __doprnt(fmt, argp: ap, putc: console_printbuf_putc, arg: &info_data, radix: 16, TRUE);
888 console_printbuf_clear(info: &info_data);
889
890 va_end(ap);
891 }
892 return 0;
893}
894
895__attribute__((noinline, not_tail_called))
896int
897printf(const char *fmt, ...)
898{
899 int ret;
900
901 va_list ap;
902 va_start(ap, fmt);
903 ret = vprintf_internal(fmt, ap_in: ap, caller: __builtin_return_address(0));
904 va_end(ap);
905
906 return ret;
907}
908
909__attribute__((noinline, not_tail_called))
910int
911vprintf(const char *fmt, va_list ap)
912{
913 return vprintf_internal(fmt, ap_in: ap, caller: __builtin_return_address(0));
914}
915
916void
917consdebug_putc(char c)
918{
919 console_write_char(c);
920
921 debug_putc(c);
922
923 if (!console_is_serial() && !disable_serial_output) {
924 PE_kputc(c);
925 }
926}
927
928void
929consdebug_putc_unbuffered(char c)
930{
931 console_write_unbuffered(c);
932
933 debug_putc(c);
934
935 if (!console_is_serial() && !disable_serial_output) {
936 PE_kputc(c);
937 }
938}
939
940void
941consdebug_log(char c)
942{
943 debug_putc(c);
944}
945
946/*
947 * Append contents to the paniclog buffer but don't flush
948 * it. This is mainly used for writing the actual paniclog
949 * contents since flushing once for every line written
950 * would be prohibitively expensive for the paniclog
951 */
952int
953paniclog_append_noflush(const char *fmt, ...)
954{
955 va_list listp;
956
957 va_start(listp, fmt);
958 _doprnt_log(fmt, argp: &listp, putc: consdebug_putc_unbuffered, radix: 16);
959 va_end(listp);
960
961 return 0;
962}
963
964int
965kdb_printf(const char *fmt, ...)
966{
967 va_list listp;
968
969 va_start(listp, fmt);
970 _doprnt_log(fmt, argp: &listp, putc: consdebug_putc, radix: 16);
971 va_end(listp);
972
973#if defined(__arm64__)
974 paniclog_flush();
975#endif
976
977 return 0;
978}
979
980int
981kdb_log(const char *fmt, ...)
982{
983 va_list listp;
984
985 va_start(listp, fmt);
986 _doprnt(fmt, argp: &listp, putc: consdebug_log, radix: 16);
987 va_end(listp);
988
989#if defined(__arm64__)
990 paniclog_flush();
991#endif
992
993 return 0;
994}
995
996int
997kdb_printf_unbuffered(const char *fmt, ...)
998{
999 va_list listp;
1000
1001 va_start(listp, fmt);
1002 _doprnt(fmt, argp: &listp, putc: consdebug_putc_unbuffered, radix: 16);
1003 va_end(listp);
1004
1005#if defined(__arm64__)
1006 paniclog_flush();
1007#endif
1008
1009 return 0;
1010}
1011
1012#if CONFIG_VSPRINTF
1013static void
1014copybyte(int c, void *arg)
1015{
1016 /*
1017 * arg is a pointer (outside pointer) to the pointer
1018 * (inside pointer) which points to the character.
1019 * We pass a double pointer, so that we can increment
1020 * the inside pointer.
1021 */
1022 char** p = arg; /* cast outside pointer */
1023 **p = (char)c; /* store character */
1024 (*p)++; /* increment inside pointer */
1025}
1026
1027/*
1028 * Deprecation Warning:
1029 * sprintf() is being deprecated. Please use snprintf() instead.
1030 */
1031int
1032sprintf(char *buf, const char *fmt, ...)
1033{
1034 va_list listp;
1035 char *copybyte_str;
1036
1037 va_start(listp, fmt);
1038 copybyte_str = buf;
1039 __doprnt(fmt, listp, copybyte, &copybyte_str, 16, FALSE);
1040 va_end(listp);
1041 *copybyte_str = '\0';
1042 return (int)strlen(buf);
1043}
1044#endif /* CONFIG_VSPRINTF */
1045