]> git.saurik.com Git - apple/xnu.git/blob - osfmk/kern/printf.c
1f7015c87b0e8e7d236961f7dc453b122d78e4df
[apple/xnu.git] / osfmk / kern / printf.c
1 /*
2 * Copyright (c) 2000-2006 Apple Computer, 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. It accepts, but
98 * ignores, an `l' as in %ld, %lo, %lx, and %lu, and therefore will not
99 * work correctly on machines for which sizeof(long) != sizeof(int).
100 *
101 * As mentioned, this version does not return any reasonable value.
102 *
103 * Permission is granted to use, modify, or propagate this code as
104 * long as this notice is incorporated.
105 *
106 * Steve Summit 3/25/87
107 *
108 * Tweaked for long long support and extended to support the hexdump %D
109 * specifier by dbg 05/02/02.
110 */
111
112 /*
113 * Added formats for decoding device registers:
114 *
115 * printf("reg = %b", regval, "<base><arg>*")
116 *
117 * where <base> is the output base expressed as a control character:
118 * i.e. '\10' gives octal, '\20' gives hex. Each <arg> is a sequence of
119 * characters, the first of which gives the bit number to be inspected
120 * (origin 1), and the rest (up to a control character (<= 32)) give the
121 * name of the register. Thus
122 * printf("reg = %b\n", 3, "\10\2BITTWO\1BITONE")
123 * would produce
124 * reg = 3<BITTWO,BITONE>
125 *
126 * If the second character in <arg> is also a control character, it
127 * indicates the last bit of a bit field. In this case, printf will extract
128 * bits <1> to <2> and print it. Characters following the second control
129 * character are printed before the bit field.
130 * printf("reg = %b\n", 0xb, "\10\4\3FIELD1=\2BITTWO\1BITONE")
131 * would produce
132 * reg = b<FIELD1=2,BITONE>
133 *
134 * The %B format is like %b but the bits are numbered from the most
135 * significant (the bit weighted 31), which is called 1, to the least
136 * significant, called 32.
137 */
138 /*
139 * Added for general use:
140 * # prefix for alternate format:
141 * 0x (0X) for hex
142 * leading 0 for octal
143 * + print '+' if positive
144 * blank print ' ' if positive
145 *
146 * z signed hexadecimal
147 * r signed, 'radix'
148 * n unsigned, 'radix'
149 *
150 * D,U,O,Z same as corresponding lower-case versions
151 * (compatibility)
152 */
153 /*
154 * Added support for print long long (64-bit) integers.
155 * Use %lld, %Ld or %qd to print a 64-bit int. Other
156 * output bases such as x, X, u, U, o, and O also work.
157 */
158
159 #include <debug.h>
160 #include <mach_kdb.h>
161 #include <mach_kdp.h>
162 #include <platforms.h>
163 #include <mach/boolean.h>
164 #include <kern/cpu_number.h>
165 #include <kern/lock.h>
166 #include <kern/thread.h>
167 #include <kern/sched_prim.h>
168 #include <kern/misc_protos.h>
169 #include <stdarg.h>
170 #include <string.h>
171 #include <mach_assert.h>
172 #ifdef MACH_BSD
173 #include <sys/msgbuf.h>
174 #endif
175 #include <console/serial_protos.h>
176
177 #ifdef __ppc__
178 #include <ppc/Firmware.h>
179 #endif
180
181 #define isdigit(d) ((d) >= '0' && (d) <= '9')
182 #define Ctod(c) ((c) - '0')
183
184 #define MAXBUF (sizeof(long long int) * 8) /* enough for binary */
185 static char digs[] = "0123456789abcdef";
186
187
188 #if CONFIG_NO_PRINTF_STRINGS
189 #undef printf(x, ...)
190 #endif
191
192 static int
193 printnum(
194 unsigned long long int u, /* number to print */
195 int base,
196 void (*putc)(int, void *),
197 void *arg)
198 {
199 char buf[MAXBUF]; /* build number here */
200 char * p = &buf[MAXBUF-1];
201 int nprinted = 0;
202
203 do {
204 *p-- = digs[u % base];
205 u /= base;
206 } while (u != 0);
207
208 while (++p != &buf[MAXBUF]) {
209 (*putc)(*p, arg);
210 nprinted++;
211 }
212
213 return nprinted;
214 }
215
216 boolean_t _doprnt_truncates = FALSE;
217
218 int
219 __doprnt(
220 const char *fmt,
221 va_list *argp,
222 /* character output routine */
223 void (*putc)(int, void *arg),
224 void *arg,
225 int radix) /* default radix - for '%r' */
226 {
227 int length;
228 int prec;
229 boolean_t ladjust;
230 char padc;
231 long long n;
232 unsigned long long u;
233 int plus_sign;
234 int sign_char;
235 boolean_t altfmt, truncate;
236 int base;
237 char c;
238 int capitals;
239 int long_long;
240 int nprinted = 0;
241
242 while ((c = *fmt) != '\0') {
243 if (c != '%') {
244 (*putc)(c, arg);
245 nprinted++;
246 fmt++;
247 continue;
248 }
249
250 fmt++;
251
252 long_long = 0;
253 length = 0;
254 prec = -1;
255 ladjust = FALSE;
256 padc = ' ';
257 plus_sign = 0;
258 sign_char = 0;
259 altfmt = FALSE;
260
261 while (TRUE) {
262 c = *fmt;
263 if (c == '#') {
264 altfmt = TRUE;
265 }
266 else if (c == '-') {
267 ladjust = TRUE;
268 }
269 else if (c == '+') {
270 plus_sign = '+';
271 }
272 else if (c == ' ') {
273 if (plus_sign == 0)
274 plus_sign = ' ';
275 }
276 else
277 break;
278 fmt++;
279 }
280
281 if (c == '0') {
282 padc = '0';
283 c = *++fmt;
284 }
285
286 if (isdigit(c)) {
287 while(isdigit(c)) {
288 length = 10 * length + Ctod(c);
289 c = *++fmt;
290 }
291 }
292 else if (c == '*') {
293 length = va_arg(*argp, int);
294 c = *++fmt;
295 if (length < 0) {
296 ladjust = !ladjust;
297 length = -length;
298 }
299 }
300
301 if (c == '.') {
302 c = *++fmt;
303 if (isdigit(c)) {
304 prec = 0;
305 while(isdigit(c)) {
306 prec = 10 * prec + Ctod(c);
307 c = *++fmt;
308 }
309 }
310 else if (c == '*') {
311 prec = va_arg(*argp, int);
312 c = *++fmt;
313 }
314 }
315
316 if (c == 'l') {
317 c = *++fmt; /* need it if sizeof(int) < sizeof(long) */
318 if (c == 'l') {
319 long_long = 1;
320 c = *++fmt;
321 }
322 } else if (c == 'q' || c == 'L') {
323 long_long = 1;
324 c = *++fmt;
325 }
326
327 truncate = FALSE;
328 capitals=0; /* Assume lower case printing */
329
330 switch(c) {
331 case 'b':
332 case 'B':
333 {
334 register char *p;
335 boolean_t any;
336 register int i;
337
338 if (long_long) {
339 u = va_arg(*argp, unsigned long long);
340 } else {
341 u = va_arg(*argp, unsigned long);
342 }
343 p = va_arg(*argp, char *);
344 base = *p++;
345 nprinted += printnum(u, base, putc, arg);
346
347 if (u == 0)
348 break;
349
350 any = FALSE;
351 while ((i = *p++) != '\0') {
352 if (*fmt == 'B')
353 i = 33 - i;
354 if (*p <= 32) {
355 /*
356 * Bit field
357 */
358 register int j;
359 if (any)
360 (*putc)(',', arg);
361 else {
362 (*putc)('<', arg);
363 any = TRUE;
364 }
365 nprinted++;
366 j = *p++;
367 if (*fmt == 'B')
368 j = 32 - j;
369 for (; (c = *p) > 32; p++) {
370 (*putc)(c, arg);
371 nprinted++;
372 }
373 nprinted += printnum((unsigned)( (u>>(j-1)) & ((2<<(i-j))-1)),
374 base, putc, arg);
375 }
376 else if (u & (1<<(i-1))) {
377 if (any)
378 (*putc)(',', arg);
379 else {
380 (*putc)('<', arg);
381 any = TRUE;
382 }
383 nprinted++;
384 for (; (c = *p) > 32; p++) {
385 (*putc)(c, arg);
386 nprinted++;
387 }
388 }
389 else {
390 for (; *p > 32; p++)
391 continue;
392 }
393 }
394 if (any) {
395 (*putc)('>', arg);
396 nprinted++;
397 }
398 break;
399 }
400
401 case 'c':
402 c = va_arg(*argp, int);
403 (*putc)(c, arg);
404 nprinted++;
405 break;
406
407 case 's':
408 {
409 register const char *p;
410 register const char *p2;
411
412 if (prec == -1)
413 prec = 0x7fffffff; /* MAXINT */
414
415 p = va_arg(*argp, char *);
416
417 if (p == NULL)
418 p = "";
419
420 if (length > 0 && !ladjust) {
421 n = 0;
422 p2 = p;
423
424 for (; *p != '\0' && n < prec; p++)
425 n++;
426
427 p = p2;
428
429 while (n < length) {
430 (*putc)(' ', arg);
431 n++;
432 nprinted++;
433 }
434 }
435
436 n = 0;
437
438 while ((n < prec) && (!(length > 0 && n >= length))) {
439 if (*p == '\0') {
440 break;
441 }
442 (*putc)(*p++, arg);
443 nprinted++;
444 n++;
445 }
446
447 if (n < length && ladjust) {
448 while (n < length) {
449 (*putc)(' ', arg);
450 n++;
451 nprinted++;
452 }
453 }
454
455 break;
456 }
457
458 case 'o':
459 truncate = _doprnt_truncates;
460 case 'O':
461 base = 8;
462 goto print_unsigned;
463
464 case 'D': {
465 unsigned char *up;
466 char *q, *p;
467
468 up = (unsigned char *)va_arg(*argp, unsigned char *);
469 p = (char *)va_arg(*argp, char *);
470 if (length == -1)
471 length = 16;
472 while(length--) {
473 (*putc)(digs[(*up >> 4)], arg);
474 (*putc)(digs[(*up & 0x0f)], arg);
475 nprinted += 2;
476 up++;
477 if (length) {
478 for (q=p;*q;q++) {
479 (*putc)(*q, arg);
480 nprinted++;
481 }
482 }
483 }
484 break;
485 }
486
487 case 'd':
488 truncate = _doprnt_truncates;
489 base = 10;
490 goto print_signed;
491
492 case 'u':
493 truncate = _doprnt_truncates;
494 case 'U':
495 base = 10;
496 goto print_unsigned;
497
498 case 'p':
499 altfmt = TRUE;
500 case 'x':
501 truncate = _doprnt_truncates;
502 base = 16;
503 goto print_unsigned;
504
505 case 'X':
506 base = 16;
507 capitals=16; /* Print in upper case */
508 goto print_unsigned;
509
510 case 'z':
511 truncate = _doprnt_truncates;
512 base = 16;
513 goto print_signed;
514
515 case 'Z':
516 base = 16;
517 capitals=16; /* Print in upper case */
518 goto print_signed;
519
520 case 'r':
521 truncate = _doprnt_truncates;
522 case 'R':
523 base = radix;
524 goto print_signed;
525
526 case 'n':
527 truncate = _doprnt_truncates;
528 case 'N':
529 base = radix;
530 goto print_unsigned;
531
532 print_signed:
533 if (long_long) {
534 n = va_arg(*argp, long long);
535 } else {
536 n = va_arg(*argp, long);
537 }
538 if (n >= 0) {
539 u = n;
540 sign_char = plus_sign;
541 }
542 else {
543 u = -n;
544 sign_char = '-';
545 }
546 goto print_num;
547
548 print_unsigned:
549 if (long_long) {
550 u = va_arg(*argp, unsigned long long);
551 } else {
552 u = va_arg(*argp, unsigned long);
553 }
554 goto print_num;
555
556 print_num:
557 {
558 char buf[MAXBUF]; /* build number here */
559 register char * p = &buf[MAXBUF-1];
560 static char digits[] = "0123456789abcdef0123456789ABCDEF";
561 const char *prefix = NULL;
562
563 if (truncate) u = (long long)((int)(u));
564
565 if (u != 0 && altfmt) {
566 if (base == 8)
567 prefix = "0";
568 else if (base == 16)
569 prefix = "0x";
570 }
571
572 do {
573 /* Print in the correct case */
574 *p-- = digits[(u % base)+capitals];
575 u /= base;
576 } while (u != 0);
577
578 length -= (&buf[MAXBUF-1] - p);
579 if (sign_char)
580 length--;
581 if (prefix)
582 length -= strlen(prefix);
583
584 if (padc == ' ' && !ladjust) {
585 /* blank padding goes before prefix */
586 while (--length >= 0) {
587 (*putc)(' ', arg);
588 nprinted++;
589 }
590 }
591 if (sign_char) {
592 (*putc)(sign_char, arg);
593 nprinted++;
594 }
595 if (prefix) {
596 while (*prefix) {
597 (*putc)(*prefix++, arg);
598 nprinted++;
599 }
600 }
601 if (padc == '0') {
602 /* zero padding goes after sign and prefix */
603 while (--length >= 0) {
604 (*putc)('0', arg);
605 nprinted++;
606 }
607 }
608 while (++p != &buf[MAXBUF]) {
609 (*putc)(*p, arg);
610 nprinted++;
611 }
612
613 if (ladjust) {
614 while (--length >= 0) {
615 (*putc)(' ', arg);
616 nprinted++;
617 }
618 }
619 break;
620 }
621
622 case '\0':
623 fmt--;
624 break;
625
626 default:
627 (*putc)(c, arg);
628 nprinted++;
629 }
630 fmt++;
631 }
632
633 return nprinted;
634 }
635
636 static void
637 dummy_putc(int ch, void *arg)
638 {
639 void (*real_putc)(char) = arg;
640
641 real_putc(ch);
642 }
643
644 void
645 _doprnt(
646 register const char *fmt,
647 va_list *argp,
648 /* character output routine */
649 void (*putc)(char),
650 int radix) /* default radix - for '%r' */
651 {
652 __doprnt(fmt, argp, dummy_putc, putc, radix);
653 }
654
655 #if MP_PRINTF
656 boolean_t new_printf_cpu_number = FALSE;
657 #endif /* MP_PRINTF */
658
659
660 decl_simple_lock_data(,printf_lock)
661 decl_simple_lock_data(,bsd_log_spinlock)
662 extern void bsd_log_init(void);
663 void bsd_log_lock(void);
664 void bsd_log_unlock(void);
665
666 void
667 printf_init(void)
668 {
669 /*
670 * Lock is only really needed after the first thread is created.
671 */
672 simple_lock_init(&printf_lock, 0);
673 simple_lock_init(&bsd_log_spinlock, 0);
674 bsd_log_init();
675 }
676
677 void
678 bsd_log_lock(void)
679 {
680 simple_lock(&bsd_log_spinlock);
681 }
682
683 void
684 bsd_log_unlock(void)
685 {
686 simple_unlock(&bsd_log_spinlock);
687 }
688
689 /* derived from boot_gets */
690 void
691 safe_gets(
692 char *str,
693 int maxlen)
694 {
695 register char *lp;
696 register int c;
697 char *strmax = str + maxlen - 1; /* allow space for trailing 0 */
698
699 lp = str;
700 for (;;) {
701 c = cngetc();
702 switch (c) {
703 case '\n':
704 case '\r':
705 printf("\n");
706 *lp++ = 0;
707 return;
708
709 case '\b':
710 case '#':
711 case '\177':
712 if (lp > str) {
713 printf("\b \b");
714 lp--;
715 }
716 continue;
717
718 case '@':
719 case 'u'&037:
720 lp = str;
721 printf("\n\r");
722 continue;
723
724 default:
725 if (c >= ' ' && c < '\177') {
726 if (lp < strmax) {
727 *lp++ = c;
728 printf("%c", c);
729 }
730 else {
731 printf("%c", '\007'); /* beep */
732 }
733 }
734 }
735 }
736 }
737
738 extern int disableConsoleOutput;
739
740 void
741 conslog_putc(
742 char c)
743 {
744 if ((debug_mode && !disable_debug_output) || !disableConsoleOutput)
745 cnputc(c);
746
747 #ifdef MACH_BSD
748 if (debug_mode == 0)
749 log_putc(c);
750 #endif
751 }
752
753 #if MACH_KDB
754 extern void db_putchar(char c);
755 #endif
756
757 void
758 dbugprintf(__unused const char *fmt, ...)
759 {
760
761 #if MACH_KDB
762 va_list listp;
763
764 va_start(listp, fmt);
765 _doprnt(fmt, &listp, db_putchar, 16);
766 va_end(listp);
767 #endif
768 return;
769 }
770
771 int
772 printf(const char *fmt, ...)
773 {
774 va_list listp;
775
776 if (fmt) {
777 disable_preemption();
778 va_start(listp, fmt);
779 _doprnt(fmt, &listp, conslog_putc, 16);
780 va_end(listp);
781 enable_preemption();
782 }
783 return 0;
784 }
785
786 void
787 consdebug_putc(char c)
788 {
789 if ((debug_mode && !disable_debug_output) || !disableConsoleOutput)
790 cnputc(c);
791
792 debug_putc(c);
793
794 if (!console_is_serial())
795 if (!disable_serial_output)
796 PE_kputc(c);
797 }
798
799 int
800 kdb_printf(const char *fmt, ...)
801 {
802 va_list listp;
803
804 va_start(listp, fmt);
805 _doprnt(fmt, &listp, consdebug_putc, 16);
806 va_end(listp);
807 return 0;
808 }
809
810 static void
811 copybyte(int c, void *arg)
812 {
813 /*
814 * arg is a pointer (outside pointer) to the pointer
815 * (inside pointer) which points to the character.
816 * We pass a double pointer, so that we can increment
817 * the inside pointer.
818 */
819 char** p = arg; /* cast outside pointer */
820 **p = c; /* store character */
821 (*p)++; /* increment inside pointer */
822 }
823
824 /*
825 * Deprecation Warning:
826 * sprintf() is being deprecated. Please use snprintf() instead.
827 */
828 int
829 sprintf(char *buf, const char *fmt, ...)
830 {
831 va_list listp;
832 char *copybyte_str;
833
834 va_start(listp, fmt);
835 copybyte_str = buf;
836 __doprnt(fmt, &listp, copybyte, &copybyte_str, 16);
837 va_end(listp);
838 *copybyte_str = '\0';
839 return strlen(buf);
840 }