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