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