]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * Copyright (c) 2014 Apple Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_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. Please obtain a copy of the License at | |
10 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
11 | * file. | |
12 | * | |
13 | * The Original Code and all software distributed under the License are | |
14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
18 | * Please see the License for the specific language governing rights and | |
19 | * limitations under the License. | |
20 | * | |
21 | * @APPLE_LICENSE_HEADER_END@ | |
22 | */ | |
23 | ||
24 | #include <stdint.h> | |
25 | #include <stdbool.h> | |
26 | #include <stdlib.h> | |
27 | #include <stdatomic.h> | |
28 | #include <machine/cpu_capabilities.h> | |
29 | #include <sys/kdebug.h> | |
30 | #include <sys/kdebug_signpost.h> | |
31 | #include <sys/errno.h> | |
32 | #include <sys/param.h> | |
33 | #include <sys/sysctl.h> | |
34 | #include <mach/mach.h> | |
35 | #include <mach/mach_vm.h> | |
36 | ||
37 | extern int __kdebug_typefilter(void** addr, size_t* size); | |
38 | extern int __kdebug_trace64(uint32_t code, uint64_t arg1, uint64_t arg2, | |
39 | uint64_t arg3, uint64_t arg4); | |
40 | extern uint64_t __kdebug_trace_string(uint32_t debugid, uint64_t str_id, | |
41 | const char *str); | |
42 | ||
43 | static int kdebug_signpost_internal(uint32_t debugid, uintptr_t arg1, | |
44 | uintptr_t arg2, uintptr_t arg3, uintptr_t arg4); | |
45 | ||
46 | /* | |
47 | * GENERAL API DESIGN NOTE! | |
48 | * | |
49 | * Trace API's are expected to avoid performing checks until tracing has | |
50 | * been enabled. This includes checks that might cause error codes to be | |
51 | * returned. | |
52 | * | |
53 | * Trace invocations via wrapper and syscall must have the same behavior. | |
54 | * | |
55 | * Note that the userspace API is chosing to optimize fastpath, non-error | |
56 | * performance by eliding validation of each debugid. This means that error | |
57 | * cases which could have been caught in userspace will make a syscall | |
58 | * before returning with the correct error code. This tradeoff in performance | |
59 | * is intentional. | |
60 | */ | |
61 | ||
62 | void * | |
63 | kdebug_typefilter(void) | |
64 | { | |
65 | static void* typefilter; | |
66 | ||
67 | /* We expect kdebug_typefilter_bitmap to be valid (the if is not executed) */ | |
68 | if (__builtin_expect(!typefilter, 0)) { | |
69 | // Map the typefilter if it can be mapped. | |
70 | void* ptr = NULL; | |
71 | size_t ptr_size = 0; | |
72 | ||
73 | if (__kdebug_typefilter(&ptr, &ptr_size) == 0) { | |
74 | void* old_value = NULL; | |
75 | if (ptr && !atomic_compare_exchange_strong((void* _Atomic volatile *)&typefilter, &old_value, ptr)) { | |
76 | mach_vm_deallocate(mach_task_self(), (mach_vm_offset_t)ptr, KDBG_TYPEFILTER_BITMAP_SIZE); | |
77 | } | |
78 | } | |
79 | } | |
80 | ||
81 | return typefilter; | |
82 | } | |
83 | ||
84 | bool | |
85 | kdebug_is_enabled(uint32_t debugid) | |
86 | { | |
87 | uint32_t state = *((volatile uint32_t *)(uintptr_t)(_COMM_PAGE_KDEBUG_ENABLE)); | |
88 | ||
89 | if (state == 0) { | |
90 | return FALSE; | |
91 | } | |
92 | ||
93 | if ((state & KDEBUG_COMMPAGE_ENABLE_TYPEFILTER) > 0) { | |
94 | /* | |
95 | * Typefilter rules... | |
96 | * | |
97 | * If no typefilter is available (even if due to error), | |
98 | * debugids are allowed. | |
99 | * | |
100 | * The typefilter will always allow DBG_TRACE; this is a kernel | |
101 | * invariant. There is no need for an explicit check here. | |
102 | * | |
103 | * NOTE: The typefilter will always allow DBG_TRACE, but | |
104 | * it is not legal to inject DBG_TRACE via kdebug_trace. | |
105 | * Attempts to do so will not be detected here, but will be | |
106 | * detected in the kernel, and an error will be returned. Per | |
107 | * the API design note at the top of this file, this is a | |
108 | * deliberate choice. | |
109 | */ | |
110 | uint8_t* typefilter = kdebug_typefilter(); | |
111 | if (typefilter && isset(typefilter, KDBG_EXTRACT_CSC(debugid)) == 0) { | |
112 | return FALSE; | |
113 | } | |
114 | } | |
115 | ||
116 | return TRUE; | |
117 | } | |
118 | ||
119 | int | |
120 | kdebug_trace(uint32_t debugid, uint64_t arg1, uint64_t arg2, uint64_t arg3, | |
121 | uint64_t arg4) | |
122 | { | |
123 | if (!kdebug_is_enabled(debugid)) { | |
124 | return 0; | |
125 | } | |
126 | ||
127 | return __kdebug_trace64(debugid, arg1, arg2, arg3, arg4); | |
128 | } | |
129 | ||
130 | uint64_t | |
131 | kdebug_trace_string(uint32_t debugid, uint64_t str_id, const char *str) | |
132 | { | |
133 | if (!kdebug_is_enabled(debugid)) { | |
134 | return 0; | |
135 | } | |
136 | ||
137 | if ((int64_t)str_id == -1) { | |
138 | errno = EINVAL; | |
139 | return (uint64_t)-1; | |
140 | } | |
141 | ||
142 | if (str_id == 0 && str == NULL) { | |
143 | errno = EINVAL; | |
144 | return (uint64_t)-1; | |
145 | } | |
146 | ||
147 | return __kdebug_trace_string(debugid, str_id, str); | |
148 | } | |
149 | ||
150 | static int | |
151 | kdebug_signpost_internal(uint32_t debugid, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t arg4) | |
152 | { | |
153 | if (KDBG_EXTRACT_CSC(debugid) != 0) { | |
154 | errno = EINVAL; | |
155 | return -1; | |
156 | } | |
157 | ||
158 | debugid |= APPSDBG_CODE(DBG_APP_SIGNPOST, 0); | |
159 | ||
160 | return kdebug_trace(debugid, arg1, arg2, arg3, arg4); | |
161 | } | |
162 | ||
163 | int | |
164 | kdebug_signpost(uint32_t code, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t arg4) | |
165 | { | |
166 | return kdebug_signpost_internal(code << KDBG_CODE_OFFSET, arg1, arg2, arg3, arg4); | |
167 | } | |
168 | ||
169 | int | |
170 | kdebug_signpost_start(uint32_t code, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t arg4) | |
171 | { | |
172 | return kdebug_signpost_internal((code << KDBG_CODE_OFFSET) | DBG_FUNC_START, arg1, arg2, arg3, arg4); | |
173 | } | |
174 | ||
175 | int | |
176 | kdebug_signpost_end(uint32_t code, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t arg4) | |
177 | { | |
178 | return kdebug_signpost_internal((code << KDBG_CODE_OFFSET) | DBG_FUNC_END, arg1, arg2, arg3, arg4); | |
179 | } |