+ if (!os_atomic_load(&kdbg_typefilter, acquire)) {
+ return EINVAL;
+ }
+
+ assert(kdbg_typefilter_memory_entry);
+
+ mach_vm_offset_t user_addr = 0;
+ vm_map_t user_map = current_map();
+
+ ret = mach_to_bsd_errno(
+ mach_vm_map_kernel(user_map, // target map
+ &user_addr, // [in, out] target address
+ TYPEFILTER_ALLOC_SIZE, // initial size
+ 0, // mask (alignment?)
+ VM_FLAGS_ANYWHERE, // flags
+ VM_MAP_KERNEL_FLAGS_NONE,
+ VM_KERN_MEMORY_NONE,
+ kdbg_typefilter_memory_entry, // port (memory entry!)
+ 0, // offset (in memory entry)
+ false, // should copy
+ VM_PROT_READ, // cur_prot
+ VM_PROT_READ, // max_prot
+ VM_INHERIT_SHARE)); // inherit behavior on fork
+
+ if (ret == KERN_SUCCESS) {
+ vm_size_t user_ptr_size = vm_map_is_64bit(user_map) ? 8 : 4;
+ ret = copyout(CAST_DOWN(void *, &user_addr), uap->addr, user_ptr_size );
+
+ if (ret != KERN_SUCCESS) {
+ mach_vm_deallocate(user_map, user_addr, TYPEFILTER_ALLOC_SIZE);
+ }
+ }
+
+ return ret;
+}
+
+/*
+ * Support syscall SYS_kdebug_trace. U64->K32 args may get truncated in kdebug_trace64
+ */
+int
+kdebug_trace(struct proc *p, struct kdebug_trace_args *uap, int32_t *retval)
+{
+ struct kdebug_trace64_args uap64;
+
+ uap64.code = uap->code;
+ uap64.arg1 = uap->arg1;
+ uap64.arg2 = uap->arg2;
+ uap64.arg3 = uap->arg3;
+ uap64.arg4 = uap->arg4;
+
+ return kdebug_trace64(p, &uap64, retval);
+}
+
+/*
+ * Support syscall SYS_kdebug_trace64. 64-bit args on K32 will get truncated
+ * to fit in 32-bit record format.
+ *
+ * It is intentional that error conditions are not checked until kdebug is
+ * enabled. This is to match the userspace wrapper behavior, which is optimizing
+ * for non-error case performance.
+ */
+int
+kdebug_trace64(__unused struct proc *p, struct kdebug_trace64_args *uap, __unused int32_t *retval)
+{
+ int err;
+
+ if (__probable(kdebug_enable == 0)) {
+ return 0;
+ }
+
+ if ((err = kdebug_validate_debugid(uap->code)) != 0) {
+ return err;
+ }
+
+ kernel_debug_internal(uap->code, (uintptr_t)uap->arg1,
+ (uintptr_t)uap->arg2, (uintptr_t)uap->arg3, (uintptr_t)uap->arg4,
+ (uintptr_t)thread_tid(current_thread()), 0);
+
+ return 0;
+}
+
+/*
+ * Adding enough padding to contain a full tracepoint for the last
+ * portion of the string greatly simplifies the logic of splitting the
+ * string between tracepoints. Full tracepoints can be generated using
+ * the buffer itself, without having to manually add zeros to pad the
+ * arguments.
+ */
+
+/* 2 string args in first tracepoint and 9 string data tracepoints */
+#define STR_BUF_ARGS (2 + (9 * 4))
+/* times the size of each arg on K64 */
+#define MAX_STR_LEN (STR_BUF_ARGS * sizeof(uint64_t))
+/* on K32, ending straddles a tracepoint, so reserve blanks */
+#define STR_BUF_SIZE (MAX_STR_LEN + (2 * sizeof(uint32_t)))
+
+/*
+ * This function does no error checking and assumes that it is called with
+ * the correct arguments, including that the buffer pointed to by str is at
+ * least STR_BUF_SIZE bytes. However, str must be aligned to word-size and
+ * be NUL-terminated. In cases where a string can fit evenly into a final
+ * tracepoint without its NUL-terminator, this function will not end those
+ * strings with a NUL in trace. It's up to clients to look at the function
+ * qualifier for DBG_FUNC_END in this case, to end the string.
+ */
+static uint64_t
+kernel_debug_string_internal(uint32_t debugid, uint64_t str_id, void *vstr,
+ size_t str_len)
+{
+ /* str must be word-aligned */
+ uintptr_t *str = vstr;
+ size_t written = 0;
+ uintptr_t thread_id;
+ int i;
+ uint32_t trace_debugid = TRACEDBG_CODE(DBG_TRACE_STRING,
+ TRACE_STRING_GLOBAL);
+
+ thread_id = (uintptr_t)thread_tid(current_thread());
+
+ /* if the ID is being invalidated, just emit that */
+ if (str_id != 0 && str_len == 0) {
+ kernel_debug_internal(trace_debugid | DBG_FUNC_START | DBG_FUNC_END,
+ (uintptr_t)debugid, (uintptr_t)str_id, 0, 0, thread_id, 0);
+ return str_id;
+ }
+
+ /* generate an ID, if necessary */
+ if (str_id == 0) {
+ str_id = OSIncrementAtomic64((SInt64 *)&g_curr_str_id);
+ str_id = (str_id & STR_ID_MASK) | g_str_id_signature;
+ }
+
+ trace_debugid |= DBG_FUNC_START;
+ /* string can fit in a single tracepoint */
+ if (str_len <= (2 * sizeof(uintptr_t))) {
+ trace_debugid |= DBG_FUNC_END;
+ }
+
+ kernel_debug_internal(trace_debugid, (uintptr_t)debugid, (uintptr_t)str_id,
+ str[0], str[1], thread_id, 0);
+
+ trace_debugid &= KDBG_EVENTID_MASK;
+ i = 2;
+ written += 2 * sizeof(uintptr_t);
+
+ for (; written < str_len; i += 4, written += 4 * sizeof(uintptr_t)) {
+ if ((written + (4 * sizeof(uintptr_t))) >= str_len) {
+ trace_debugid |= DBG_FUNC_END;
+ }
+ kernel_debug_internal(trace_debugid, str[i],
+ str[i + 1],
+ str[i + 2],
+ str[i + 3], thread_id, 0);
+ }
+
+ return str_id;
+}
+
+/*
+ * Returns true if the current process can emit events, and false otherwise.
+ * Trace system and scheduling events circumvent this check, as do events
+ * emitted in interrupt context.
+ */
+static bool
+kdebug_current_proc_enabled(uint32_t debugid)
+{
+ /* can't determine current process in interrupt context */
+ if (ml_at_interrupt_context()) {
+ return true;
+ }