]> git.saurik.com Git - apple/xnu.git/blob - osfmk/kern/printf.c
xnu-344.21.73.tar.gz
[apple/xnu.git] / osfmk / kern / printf.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /*
26 * @OSF_COPYRIGHT@
27 */
28
29 /*
30 * Mach Operating System
31 * Copyright (c) 1991,1990,1989,1988 Carnegie Mellon University
32 * All Rights Reserved.
33 *
34 * Permission to use, copy, modify and distribute this software and its
35 * documentation is hereby granted, provided that both the copyright
36 * notice and this permission notice appear in all copies of the
37 * software, derivative works or modified versions, and any portions
38 * thereof, and that both notices appear in supporting documentation.
39 *
40 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
41 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
42 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
43 *
44 * Carnegie Mellon requests users of this software to return to
45 *
46 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
47 * School of Computer Science
48 * Carnegie Mellon University
49 * Pittsburgh PA 15213-3890
50 *
51 * any improvements or extensions that they make and grant Carnegie Mellon
52 * the rights to redistribute these changes.
53 */
54
55 /*
56 * Common code for printf et al.
57 *
58 * The calling routine typically takes a variable number of arguments,
59 * and passes the address of the first one. This implementation
60 * assumes a straightforward, stack implementation, aligned to the
61 * machine's wordsize. Increasing addresses are assumed to point to
62 * successive arguments (left-to-right), as is the case for a machine
63 * with a downward-growing stack with arguments pushed right-to-left.
64 *
65 * To write, for example, fprintf() using this routine, the code
66 *
67 * fprintf(fd, format, args)
68 * FILE *fd;
69 * char *format;
70 * {
71 * _doprnt(format, &args, fd);
72 * }
73 *
74 * would suffice. (This example does not handle the fprintf's "return
75 * value" correctly, but who looks at the return value of fprintf
76 * anyway?)
77 *
78 * This version implements the following printf features:
79 *
80 * %d decimal conversion
81 * %u unsigned conversion
82 * %x hexadecimal conversion
83 * %X hexadecimal conversion with capital letters
84 * %D hexdump, ptr & separator string ("%6D", ptr, ":") -> XX:XX:XX:XX:XX:XX
85 * if you use, "%*D" then there's a length, the data ptr and then the separator
86 * %o octal conversion
87 * %c character
88 * %s string
89 * %m.n field width, precision
90 * %-m.n left adjustment
91 * %0m.n zero-padding
92 * %*.* width and precision taken from arguments
93 *
94 * This version does not implement %f, %e, or %g. It accepts, but
95 * ignores, an `l' as in %ld, %lo, %lx, and %lu, and therefore will not
96 * work correctly on machines for which sizeof(long) != sizeof(int).
97 *
98 * As mentioned, this version does not return any reasonable value.
99 *
100 * Permission is granted to use, modify, or propagate this code as
101 * long as this notice is incorporated.
102 *
103 * Steve Summit 3/25/87
104 *
105 * Tweaked for long long support and extended to support the hexdump %D
106 * specifier by dbg 05/02/02.
107 */
108
109 /*
110 * Added formats for decoding device registers:
111 *
112 * printf("reg = %b", regval, "<base><arg>*")
113 *
114 * where <base> is the output base expressed as a control character:
115 * i.e. '\10' gives octal, '\20' gives hex. Each <arg> is a sequence of
116 * characters, the first of which gives the bit number to be inspected
117 * (origin 1), and the rest (up to a control character (<= 32)) give the
118 * name of the register. Thus
119 * printf("reg = %b\n", 3, "\10\2BITTWO\1BITONE")
120 * would produce
121 * reg = 3<BITTWO,BITONE>
122 *
123 * If the second character in <arg> is also a control character, it
124 * indicates the last bit of a bit field. In this case, printf will extract
125 * bits <1> to <2> and print it. Characters following the second control
126 * character are printed before the bit field.
127 * printf("reg = %b\n", 0xb, "\10\4\3FIELD1=\2BITTWO\1BITONE")
128 * would produce
129 * reg = b<FIELD1=2,BITONE>
130 *
131 * The %B format is like %b but the bits are numbered from the most
132 * significant (the bit weighted 31), which is called 1, to the least
133 * significant, called 32.
134 */
135 /*
136 * Added for general use:
137 * # prefix for alternate format:
138 * 0x (0X) for hex
139 * leading 0 for octal
140 * + print '+' if positive
141 * blank print ' ' if positive
142 *
143 * z signed hexadecimal
144 * r signed, 'radix'
145 * n unsigned, 'radix'
146 *
147 * D,U,O,Z same as corresponding lower-case versions
148 * (compatibility)
149 */
150 /*
151 * Added support for print long long (64-bit) integers.
152 * Use %lld, %Ld or %qd to print a 64-bit int. Other
153 * output bases such as x, X, u, U, o, and O also work.
154 */
155
156 #include <debug.h>
157 #include <mach_kdb.h>
158 #include <mach_kdp.h>
159 #include <platforms.h>
160 #include <mach/boolean.h>
161 #include <cpus.h>
162 #include <kern/cpu_number.h>
163 #include <kern/lock.h>
164 #include <kern/thread.h>
165 #include <kern/sched_prim.h>
166 #include <kern/misc_protos.h>
167 #include <stdarg.h>
168 #include <string.h>
169 #include <mach_assert.h>
170 #ifdef MACH_BSD
171 #include <sys/msgbuf.h>
172 #endif
173
174 #ifdef __ppc__
175 #include <ppc/Firmware.h>
176 #endif
177
178 #define isdigit(d) ((d) >= '0' && (d) <= '9')
179 #define Ctod(c) ((c) - '0')
180
181 #define MAXBUF (sizeof(long long int) * 8) /* enough for binary */
182 static char digs[] = "0123456789abcdef";
183
184 static int
185 printnum(
186 register unsigned long long int u, /* number to print */
187 register int base,
188 void (*putc)(int, void *),
189 void *arg)
190 {
191 char buf[MAXBUF]; /* build number here */
192 register char * p = &buf[MAXBUF-1];
193 int nprinted = 0;
194
195 do {
196 *p-- = digs[u % base];
197 u /= base;
198 } while (u != 0);
199
200 while (++p != &buf[MAXBUF]) {
201 (*putc)(*p, arg);
202 nprinted++;
203 }
204
205 return nprinted;
206 }
207
208 boolean_t _doprnt_truncates = FALSE;
209
210 int
211 __doprnt(
212 register const char *fmt,
213 va_list *argp,
214 /* character output routine */
215 void (*putc)(int, void *arg),
216 void *arg,
217 int radix) /* default radix - for '%r' */
218 {
219 int length;
220 int prec;
221 boolean_t ladjust;
222 char padc;
223 long long n;
224 unsigned long long u;
225 int plus_sign;
226 int sign_char;
227 boolean_t altfmt, truncate;
228 int base;
229 register char c;
230 int capitals;
231 int long_long;
232 int nprinted = 0;
233
234 while ((c = *fmt) != '\0') {
235 if (c != '%') {
236 (*putc)(c, arg);
237 nprinted++;
238 fmt++;
239 continue;
240 }
241
242 fmt++;
243
244 long_long = 0;
245 length = 0;
246 prec = -1;
247 ladjust = FALSE;
248 padc = ' ';
249 plus_sign = 0;
250 sign_char = 0;
251 altfmt = FALSE;
252
253 while (TRUE) {
254 c = *fmt;
255 if (c == '#') {
256 altfmt = TRUE;
257 }
258 else if (c == '-') {
259 ladjust = TRUE;
260 }
261 else if (c == '+') {
262 plus_sign = '+';
263 }
264 else if (c == ' ') {
265 if (plus_sign == 0)
266 plus_sign = ' ';
267 }
268 else
269 break;
270 fmt++;
271 }
272
273 if (c == '0') {
274 padc = '0';
275 c = *++fmt;
276 }
277
278 if (isdigit(c)) {
279 while(isdigit(c)) {
280 length = 10 * length + Ctod(c);
281 c = *++fmt;
282 }
283 }
284 else if (c == '*') {
285 length = va_arg(*argp, int);
286 c = *++fmt;
287 if (length < 0) {
288 ladjust = !ladjust;
289 length = -length;
290 }
291 }
292
293 if (c == '.') {
294 c = *++fmt;
295 if (isdigit(c)) {
296 prec = 0;
297 while(isdigit(c)) {
298 prec = 10 * prec + Ctod(c);
299 c = *++fmt;
300 }
301 }
302 else if (c == '*') {
303 prec = va_arg(*argp, int);
304 c = *++fmt;
305 }
306 }
307
308 if (c == 'l') {
309 c = *++fmt; /* need it if sizeof(int) < sizeof(long) */
310 if (c == 'l') {
311 long_long = 1;
312 c = *++fmt;
313 }
314 } else if (c == 'q' || c == 'L') {
315 long_long = 1;
316 c = *++fmt;
317 }
318
319 truncate = FALSE;
320 capitals=0; /* Assume lower case printing */
321
322 switch(c) {
323 case 'b':
324 case 'B':
325 {
326 register char *p;
327 boolean_t any;
328 register int i;
329
330 if (long_long) {
331 u = va_arg(*argp, unsigned long long);
332 } else {
333 u = va_arg(*argp, unsigned long);
334 }
335 p = va_arg(*argp, char *);
336 base = *p++;
337 nprinted += printnum(u, base, putc, arg);
338
339 if (u == 0)
340 break;
341
342 any = FALSE;
343 while ((i = *p++) != '\0') {
344 if (*fmt == 'B')
345 i = 33 - i;
346 if (*p <= 32) {
347 /*
348 * Bit field
349 */
350 register int j;
351 if (any)
352 (*putc)(',', arg);
353 else {
354 (*putc)('<', arg);
355 any = TRUE;
356 }
357 nprinted++;
358 j = *p++;
359 if (*fmt == 'B')
360 j = 32 - j;
361 for (; (c = *p) > 32; p++) {
362 (*putc)(c, arg);
363 nprinted++;
364 }
365 nprinted += printnum((unsigned)( (u>>(j-1)) & ((2<<(i-j))-1)),
366 base, putc, arg);
367 }
368 else if (u & (1<<(i-1))) {
369 if (any)
370 (*putc)(',', arg);
371 else {
372 (*putc)('<', arg);
373 any = TRUE;
374 }
375 nprinted++;
376 for (; (c = *p) > 32; p++) {
377 (*putc)(c, arg);
378 nprinted++;
379 }
380 }
381 else {
382 for (; *p > 32; p++)
383 continue;
384 }
385 }
386 if (any) {
387 (*putc)('>', arg);
388 nprinted++;
389 }
390 break;
391 }
392
393 case 'c':
394 c = va_arg(*argp, int);
395 (*putc)(c, arg);
396 nprinted++;
397 break;
398
399 case 's':
400 {
401 register char *p;
402 register char *p2;
403
404 if (prec == -1)
405 prec = 0x7fffffff; /* MAXINT */
406
407 p = va_arg(*argp, char *);
408
409 if (p == (char *)0)
410 p = "";
411
412 if (length > 0 && !ladjust) {
413 n = 0;
414 p2 = p;
415
416 for (; *p != '\0' && n < prec; p++)
417 n++;
418
419 p = p2;
420
421 while (n < length) {
422 (*putc)(' ', arg);
423 n++;
424 nprinted++;
425 }
426 }
427
428 n = 0;
429
430 while (*p != '\0') {
431 if (++n > prec || (length > 0 && n > length))
432 break;
433
434 (*putc)(*p++, arg);
435 nprinted++;
436 }
437
438 if (n < length && ladjust) {
439 while (n < length) {
440 (*putc)(' ', arg);
441 n++;
442 nprinted++;
443 }
444 }
445
446 break;
447 }
448
449 case 'o':
450 truncate = _doprnt_truncates;
451 case 'O':
452 base = 8;
453 goto print_unsigned;
454
455 case 'D': {
456 unsigned char *up;
457 char *q, *p;
458
459 up = (unsigned char *)va_arg(*argp, unsigned char *);
460 p = (char *)va_arg(*argp, char *);
461 if (length == -1)
462 length = 16;
463 while(length--) {
464 (*putc)(digs[(*up >> 4)], arg);
465 (*putc)(digs[(*up & 0x0f)], arg);
466 nprinted += 2;
467 up++;
468 if (length) {
469 for (q=p;*q;q++) {
470 (*putc)(*q, arg);
471 nprinted++;
472 }
473 }
474 }
475 break;
476 }
477
478 case 'd':
479 truncate = _doprnt_truncates;
480 base = 10;
481 goto print_signed;
482
483 case 'u':
484 truncate = _doprnt_truncates;
485 case 'U':
486 base = 10;
487 goto print_unsigned;
488
489 case 'p':
490 altfmt = TRUE;
491 case 'x':
492 truncate = _doprnt_truncates;
493 base = 16;
494 goto print_unsigned;
495
496 case 'X':
497 base = 16;
498 capitals=16; /* Print in upper case */
499 goto print_unsigned;
500
501 case 'z':
502 truncate = _doprnt_truncates;
503 base = 16;
504 goto print_signed;
505
506 case 'Z':
507 base = 16;
508 capitals=16; /* Print in upper case */
509 goto print_signed;
510
511 case 'r':
512 truncate = _doprnt_truncates;
513 case 'R':
514 base = radix;
515 goto print_signed;
516
517 case 'n':
518 truncate = _doprnt_truncates;
519 case 'N':
520 base = radix;
521 goto print_unsigned;
522
523 print_signed:
524 if (long_long) {
525 n = va_arg(*argp, long long);
526 } else {
527 n = va_arg(*argp, long);
528 }
529 if (n >= 0) {
530 u = n;
531 sign_char = plus_sign;
532 }
533 else {
534 u = -n;
535 sign_char = '-';
536 }
537 goto print_num;
538
539 print_unsigned:
540 if (long_long) {
541 u = va_arg(*argp, unsigned long long);
542 } else {
543 u = va_arg(*argp, unsigned long);
544 }
545 goto print_num;
546
547 print_num:
548 {
549 char buf[MAXBUF]; /* build number here */
550 register char * p = &buf[MAXBUF-1];
551 static char digits[] = "0123456789abcdef0123456789ABCDEF";
552 char *prefix = 0;
553
554 if (truncate) u = (long long)((int)(u));
555
556 if (u != 0 && altfmt) {
557 if (base == 8)
558 prefix = "0";
559 else if (base == 16)
560 prefix = "0x";
561 }
562
563 do {
564 /* Print in the correct case */
565 *p-- = digits[(u % base)+capitals];
566 u /= base;
567 } while (u != 0);
568
569 length -= (&buf[MAXBUF-1] - p);
570 if (sign_char)
571 length--;
572 if (prefix)
573 length -= strlen((const char *) prefix);
574
575 if (padc == ' ' && !ladjust) {
576 /* blank padding goes before prefix */
577 while (--length >= 0) {
578 (*putc)(' ', arg);
579 nprinted++;
580 }
581 }
582 if (sign_char) {
583 (*putc)(sign_char, arg);
584 nprinted++;
585 }
586 if (prefix) {
587 while (*prefix) {
588 (*putc)(*prefix++, arg);
589 nprinted++;
590 }
591 }
592 if (padc == '0') {
593 /* zero padding goes after sign and prefix */
594 while (--length >= 0) {
595 (*putc)('0', arg);
596 nprinted++;
597 }
598 }
599 while (++p != &buf[MAXBUF]) {
600 (*putc)(*p, arg);
601 nprinted++;
602 }
603
604 if (ladjust) {
605 while (--length >= 0) {
606 (*putc)(' ', arg);
607 nprinted++;
608 }
609 }
610 break;
611 }
612
613 case '\0':
614 fmt--;
615 break;
616
617 default:
618 (*putc)(c, arg);
619 nprinted++;
620 }
621 fmt++;
622 }
623
624 return nprinted;
625 }
626
627 static void
628 dummy_putc(int ch, void *arg)
629 {
630 void (*real_putc)(char) = arg;
631
632 real_putc(ch);
633 }
634
635 void
636 _doprnt(
637 register const char *fmt,
638 va_list *argp,
639 /* character output routine */
640 void (*putc)(char),
641 int radix) /* default radix - for '%r' */
642 {
643 __doprnt(fmt, argp, dummy_putc, putc, radix);
644 }
645
646 #if MP_PRINTF
647 boolean_t new_printf_cpu_number = FALSE;
648 #endif /* MP_PRINTF */
649
650
651 decl_simple_lock_data(,printf_lock)
652 decl_mutex_data(,sprintf_lock)
653
654 void
655 printf_init(void)
656 {
657 /*
658 * Lock is only really needed after the first thread is created.
659 */
660 simple_lock_init(&printf_lock, ETAP_MISC_PRINTF);
661 mutex_init(&sprintf_lock, ETAP_MISC_PRINTF);
662 }
663
664 /* derived from boot_gets */
665 void
666 safe_gets(
667 char *str,
668 int maxlen)
669 {
670 register char *lp;
671 register int c;
672 char *strmax = str + maxlen - 1; /* allow space for trailing 0 */
673
674 lp = str;
675 for (;;) {
676 c = cngetc();
677 switch (c) {
678 case '\n':
679 case '\r':
680 printf("\n");
681 *lp++ = 0;
682 return;
683
684 case '\b':
685 case '#':
686 case '\177':
687 if (lp > str) {
688 printf("\b \b");
689 lp--;
690 }
691 continue;
692
693 case '@':
694 case 'u'&037:
695 lp = str;
696 printf("\n\r");
697 continue;
698
699 default:
700 if (c >= ' ' && c < '\177') {
701 if (lp < strmax) {
702 *lp++ = c;
703 printf("%c", c);
704 }
705 else {
706 printf("%c", '\007'); /* beep */
707 }
708 }
709 }
710 }
711 }
712
713 void
714 conslog_putc(
715 char c)
716 {
717 extern unsigned int debug_mode, disableDebugOuput, disableConsoleOutput;
718
719 if ((debug_mode && !disableDebugOuput) || !disableConsoleOutput)
720 cnputc(c);
721
722 #ifdef MACH_BSD
723 log_putc(c);
724 #endif
725 }
726
727 void
728 dbugprintf(const char *fmt, ...)
729 {
730
731 #if MACH_KDB
732
733 extern void db_putchar(char c);
734 va_list listp;
735
736 va_start(listp, fmt);
737 _doprnt(fmt, &listp, db_putchar, 16);
738 va_end(listp);
739 #endif
740 return;
741 }
742
743 void
744 printf(const char *fmt, ...)
745 {
746 va_list listp;
747
748 disable_preemption();
749 va_start(listp, fmt);
750 _doprnt(fmt, &listp, conslog_putc, 16);
751 va_end(listp);
752 enable_preemption();
753 }
754
755 void
756 consdebug_putc(
757 char c)
758 {
759 extern unsigned int debug_mode, disableDebugOuput, disableConsoleOutput;
760
761 if ((debug_mode && !disableDebugOuput) || !disableConsoleOutput)
762 cnputc(c);
763
764 debug_putc(c);
765 }
766
767 void
768 kdb_printf(const char *fmt, ...)
769 {
770 va_list listp;
771
772 va_start(listp, fmt);
773 _doprnt(fmt, &listp, consdebug_putc, 16);
774 va_end(listp);
775 }
776
777 static char *copybyte_str;
778
779 static void
780 copybyte(
781 char byte)
782 {
783 *copybyte_str++ = byte;
784 *copybyte_str = '\0';
785 }
786
787 int
788 sprintf(char *buf, const char *fmt, ...)
789 {
790 va_list listp;
791
792 va_start(listp, fmt);
793 mutex_lock(&sprintf_lock);
794 copybyte_str = buf;
795 _doprnt(fmt, &listp, copybyte, 16);
796 mutex_unlock(&sprintf_lock);
797 va_end(listp);
798 return strlen(buf);
799 }