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