]> git.saurik.com Git - apple/xnu.git/blame - libsyscall/wrappers/kdebug_trace.c
xnu-7195.101.1.tar.gz
[apple/xnu.git] / libsyscall / wrappers / kdebug_trace.c
CommitLineData
a1c7dba1
A
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>
39037602 25#include <stdbool.h>
3e170ce0 26#include <stdlib.h>
39037602 27#include <stdatomic.h>
a1c7dba1
A
28#include <machine/cpu_capabilities.h>
29#include <sys/kdebug.h>
39037602 30#include <sys/kdebug_signpost.h>
a1c7dba1 31#include <sys/errno.h>
39037602
A
32#include <sys/param.h>
33#include <sys/sysctl.h>
34#include <mach/mach.h>
35#include <mach/mach_vm.h>
a1c7dba1 36
39037602 37extern int __kdebug_typefilter(void** addr, size_t* size);
3e170ce0 38extern int __kdebug_trace64(uint32_t code, uint64_t arg1, uint64_t arg2,
0a7de745 39 uint64_t arg3, uint64_t arg4);
3e170ce0 40extern uint64_t __kdebug_trace_string(uint32_t debugid, uint64_t str_id,
0a7de745 41 const char *str);
a1c7dba1 42
39037602 43static int kdebug_signpost_internal(uint32_t debugid, uintptr_t arg1,
0a7de745 44 uintptr_t arg2, uintptr_t arg3, uintptr_t arg4);
3e170ce0 45
39037602
A
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
62void *
63kdebug_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 }
3e170ce0 79 }
a1c7dba1 80
39037602 81 return typefilter;
3e170ce0 82}
a1c7dba1 83
39037602
A
84bool
85kdebug_is_enabled(uint32_t debugid)
a1c7dba1 86{
c3c9b80d 87 uint32_t state = COMM_PAGE_READ(uint32_t, KDEBUG_ENABLE);
39037602
A
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),
0a7de745 98 * debugids are allowed.
39037602
A
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 }
a1c7dba1
A
114 }
115
39037602 116 return TRUE;
3e170ce0
A
117}
118
cb323159
A
119bool
120kdebug_using_continuous_time(void)
121{
c3c9b80d 122 uint32_t state = COMM_PAGE_READ(uint32_t, KDEBUG_ENABLE);
cb323159
A
123 return state & KDEBUG_ENABLE_CONT_TIME;
124}
125
3e170ce0
A
126int
127kdebug_trace(uint32_t debugid, uint64_t arg1, uint64_t arg2, uint64_t arg3,
0a7de745 128 uint64_t arg4)
3e170ce0 129{
39037602 130 if (!kdebug_is_enabled(debugid)) {
a1c7dba1
A
131 return 0;
132 }
3e170ce0 133
3e170ce0
A
134 return __kdebug_trace64(debugid, arg1, arg2, arg3, arg4);
135}
136
137uint64_t
138kdebug_trace_string(uint32_t debugid, uint64_t str_id, const char *str)
139{
39037602 140 if (!kdebug_is_enabled(debugid)) {
3e170ce0
A
141 return 0;
142 }
143
144 if ((int64_t)str_id == -1) {
145 errno = EINVAL;
146 return (uint64_t)-1;
147 }
148
149 if (str_id == 0 && str == NULL) {
150 errno = EINVAL;
151 return (uint64_t)-1;
152 }
153
39037602
A
154 return __kdebug_trace_string(debugid, str_id, str);
155}
156
157static int
158kdebug_signpost_internal(uint32_t debugid, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t arg4)
159{
160 if (KDBG_EXTRACT_CSC(debugid) != 0) {
161 errno = EINVAL;
162 return -1;
3e170ce0
A
163 }
164
39037602
A
165 debugid |= APPSDBG_CODE(DBG_APP_SIGNPOST, 0);
166
167 return kdebug_trace(debugid, arg1, arg2, arg3, arg4);
168}
169
170int
171kdebug_signpost(uint32_t code, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t arg4)
172{
173 return kdebug_signpost_internal(code << KDBG_CODE_OFFSET, arg1, arg2, arg3, arg4);
174}
175
176int
177kdebug_signpost_start(uint32_t code, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t arg4)
178{
179 return kdebug_signpost_internal((code << KDBG_CODE_OFFSET) | DBG_FUNC_START, arg1, arg2, arg3, arg4);
180}
181
182int
183kdebug_signpost_end(uint32_t code, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t arg4)
184{
185 return kdebug_signpost_internal((code << KDBG_CODE_OFFSET) | DBG_FUNC_END, arg1, arg2, arg3, arg4);
a1c7dba1 186}