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