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