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