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