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