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