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 */ |
187 | static char digs[] = "0123456789abcdef" ; |
188 | |
189 | #if CONFIG_NO_PRINTF_STRINGS |
190 | /* Prevent CPP from breaking the definition below */ |
191 | #undef printf |
192 | #endif |
193 | |
194 | int _consume_printf_args(int a __unused, ...) |
195 | { |
196 | return 0; |
197 | } |
198 | void _consume_kprintf_args(int a __unused, ...) |
199 | { |
200 | } |
201 | |
202 | static int |
203 | printnum( |
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 | |
226 | boolean_t _doprnt_truncates = FALSE; |
227 | |
228 | #if (DEVELOPMENT || DEBUG) |
229 | boolean_t doprnt_hide_pointers = FALSE; |
230 | #else |
231 | boolean_t doprnt_hide_pointers = TRUE; |
232 | #endif |
233 | |
234 | int |
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 | |
671 | static void |
672 | dummy_putc(int ch, void *arg) |
673 | { |
674 | void (*real_putc)(char) = arg; |
675 | |
676 | real_putc(ch); |
677 | } |
678 | |
679 | void |
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 | |
690 | void |
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 |
702 | boolean_t new_printf_cpu_number = FALSE; |
703 | #endif /* MP_PRINTF */ |
704 | |
705 | decl_simple_lock_data(,printf_lock) |
706 | decl_simple_lock_data(,bsd_log_spinlock) |
707 | |
708 | /* |
709 | * Defined here to allow lock group to be statically allocated. |
710 | */ |
711 | static lck_grp_t oslog_stream_lock_grp; |
712 | decl_lck_spin_data(,oslog_stream_lock) |
713 | void oslog_lock_init(void); |
714 | |
715 | extern void bsd_log_init(void); |
716 | void bsd_log_lock(void); |
717 | void bsd_log_unlock(void); |
718 | |
719 | void |
720 | |
721 | printf_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 | |
731 | void |
732 | bsd_log_lock(void) |
733 | { |
734 | simple_lock(&bsd_log_spinlock); |
735 | } |
736 | |
737 | void |
738 | bsd_log_unlock(void) |
739 | { |
740 | simple_unlock(&bsd_log_spinlock); |
741 | } |
742 | |
743 | void |
744 | oslog_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 */ |
751 | void |
752 | safe_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 | |
799 | extern int disableConsoleOutput; |
800 | |
801 | void |
802 | conslog_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 | |
814 | void |
815 | cons_putc_locked( |
816 | char c) |
817 | { |
818 | if (!disableConsoleOutput) |
819 | cnputc(c); |
820 | } |
821 | |
822 | static int |
823 | vprintf_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)) |
854 | int |
855 | printf(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)) |
868 | int |
869 | vprintf(const char *fmt, va_list ap) |
870 | { |
871 | return vprintf_internal(fmt, ap, __builtin_return_address(0)); |
872 | } |
873 | |
874 | void |
875 | consdebug_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 | |
886 | void |
887 | consdebug_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 | |
898 | void |
899 | consdebug_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 | */ |
910 | int |
911 | paniclog_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 | |
922 | int |
923 | kdb_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 | |
938 | int |
939 | kdb_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 | |
954 | int |
955 | kdb_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 | |
972 | static void |
973 | copybyte(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 | */ |
990 | int |
991 | sprintf(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, ©byte_str, 16, FALSE); |
999 | va_end(listp); |
1000 | *copybyte_str = '\0'; |
1001 | return (int)strlen(buf); |
1002 | } |
1003 | #endif /* !CONFIG_EMBEDDED */ |
1004 | |