]> git.saurik.com Git - apple/xnu.git/blob - libsyscall/wrappers/kdebug_trace.c
xnu-4903.241.1.tar.gz
[apple/xnu.git] / libsyscall / wrappers / kdebug_trace.c
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 }