2 * Copyright (c) 2014 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
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>
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
,
43 static int kdebug_signpost_internal(uint32_t debugid
, uintptr_t arg1
,
44 uintptr_t arg2
, uintptr_t arg3
, uintptr_t arg4
);
47 * GENERAL API DESIGN NOTE!
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
53 * Trace invocations via wrapper and syscall must have the same behavior.
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
63 kdebug_typefilter(void)
65 static void* typefilter
;
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.
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
);
85 kdebug_is_enabled(uint32_t debugid
)
87 uint32_t state
= COMM_PAGE_READ(uint32_t, KDEBUG_ENABLE
);
93 if ((state
& KDEBUG_COMMPAGE_ENABLE_TYPEFILTER
) > 0) {
97 * If no typefilter is available (even if due to error),
98 * debugids are allowed.
100 * The typefilter will always allow DBG_TRACE; this is a kernel
101 * invariant. There is no need for an explicit check here.
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
110 uint8_t* typefilter
= kdebug_typefilter();
111 if (typefilter
&& isset(typefilter
, KDBG_EXTRACT_CSC(debugid
)) == 0) {
120 kdebug_using_continuous_time(void)
122 uint32_t state
= COMM_PAGE_READ(uint32_t, KDEBUG_ENABLE
);
123 return state
& KDEBUG_ENABLE_CONT_TIME
;
127 kdebug_trace(uint32_t debugid
, uint64_t arg1
, uint64_t arg2
, uint64_t arg3
,
130 if (!kdebug_is_enabled(debugid
)) {
134 return __kdebug_trace64(debugid
, arg1
, arg2
, arg3
, arg4
);
138 kdebug_trace_string(uint32_t debugid
, uint64_t str_id
, const char *str
)
140 if (!kdebug_is_enabled(debugid
)) {
144 if ((int64_t)str_id
== -1) {
149 if (str_id
== 0 && str
== NULL
) {
154 return __kdebug_trace_string(debugid
, str_id
, str
);
158 kdebug_signpost_internal(uint32_t debugid
, uintptr_t arg1
, uintptr_t arg2
, uintptr_t arg3
, uintptr_t arg4
)
160 if (KDBG_EXTRACT_CSC(debugid
) != 0) {
165 debugid
|= APPSDBG_CODE(DBG_APP_SIGNPOST
, 0);
167 return kdebug_trace(debugid
, arg1
, arg2
, arg3
, arg4
);
171 kdebug_signpost(uint32_t code
, uintptr_t arg1
, uintptr_t arg2
, uintptr_t arg3
, uintptr_t arg4
)
173 return kdebug_signpost_internal(code
<< KDBG_CODE_OFFSET
, arg1
, arg2
, arg3
, arg4
);
177 kdebug_signpost_start(uint32_t code
, uintptr_t arg1
, uintptr_t arg2
, uintptr_t arg3
, uintptr_t arg4
)
179 return kdebug_signpost_internal((code
<< KDBG_CODE_OFFSET
) | DBG_FUNC_START
, arg1
, arg2
, arg3
, arg4
);
183 kdebug_signpost_end(uint32_t code
, uintptr_t arg1
, uintptr_t arg2
, uintptr_t arg3
, uintptr_t arg4
)
185 return kdebug_signpost_internal((code
<< KDBG_CODE_OFFSET
) | DBG_FUNC_END
, arg1
, arg2
, arg3
, arg4
);