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