+ /* always emit trace system and scheduling events */
+ if ((KDBG_EXTRACT_CLASS(debugid) == DBG_TRACE ||
+ (debugid & KDBG_CSC_MASK) == MACHDBG_CODE(DBG_MACH_SCHED, 0)))
+ {
+ return TRUE;
+ }
+
+ if (kd_ctrl_page.kdebug_flags & KDBG_PIDCHECK) {
+ proc_t cur_proc = current_proc();
+
+ /* only the process with the kdebug bit set is allowed */
+ if (cur_proc && !(cur_proc->p_kdebug)) {
+ return FALSE;
+ }
+ } else if (kd_ctrl_page.kdebug_flags & KDBG_PIDEXCLUDE) {
+ proc_t cur_proc = current_proc();
+
+ /* every process except the one with the kdebug bit set is allowed */
+ if (cur_proc && cur_proc->p_kdebug) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+/*
+ * Returns true if the debugid is disabled by filters, and false if the
+ * debugid is allowed to be traced. A debugid may not be traced if the
+ * typefilter disables its class and subclass, it's outside a range
+ * check, or if it's not an allowed debugid in a value check. Trace
+ * system events bypass this check.
+ */
+static boolean_t
+kdebug_debugid_enabled(uint32_t debugid)
+{
+ boolean_t is_enabled = TRUE;
+
+ /* if no filtering is enabled */
+ if (!kd_ctrl_page.kdebug_slowcheck) {
+ return TRUE;
+ }
+
+ if (KDBG_EXTRACT_CLASS(debugid) == DBG_TRACE) {
+ return TRUE;
+ }
+
+ if (kd_ctrl_page.kdebug_flags & KDBG_TYPEFILTER_CHECK) {
+ disable_preemption();
+
+ /*
+ * Recheck if typefilter is still being used. If tracing is being
+ * disabled, there's a 100ms sleep on the other end to keep the
+ * bitmap around for this check.
+ */
+ if (kd_ctrl_page.kdebug_flags & KDBG_TYPEFILTER_CHECK) {
+ if (!(isset(type_filter_bitmap, KDBG_EXTRACT_CSC(debugid)))) {
+ is_enabled = FALSE;
+ }
+ }
+
+ enable_preemption();
+ } else if (kd_ctrl_page.kdebug_flags & KDBG_RANGECHECK) {
+ if (debugid < kdlog_beg || debugid > kdlog_end) {
+ is_enabled = FALSE;
+ }
+ } else if (kd_ctrl_page.kdebug_flags & KDBG_VALCHECK) {
+ if ((debugid & KDBG_EVENTID_MASK) != kdlog_value1 &&
+ (debugid & KDBG_EVENTID_MASK) != kdlog_value2 &&
+ (debugid & KDBG_EVENTID_MASK) != kdlog_value3 &&
+ (debugid & KDBG_EVENTID_MASK) != kdlog_value4)
+ {
+ is_enabled = FALSE;
+ }
+ }
+
+ return is_enabled;
+}
+
+/*
+ * Returns 0 if a string can be traced with these arguments. Returns errno
+ * value if error occurred.
+ */
+static errno_t
+kdebug_check_trace_string(uint32_t debugid, uint64_t str_id)
+{
+ /* if there are function qualifiers on the debugid */
+ if (debugid & ~KDBG_EVENTID_MASK) {
+ return EINVAL;
+ }
+
+ if (kdebug_validate_debugid(debugid)) {
+ return EPERM;
+ }
+
+ if (str_id != 0 && (str_id & STR_ID_SIG_MASK) != g_str_id_signature) {
+ return EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+ * Implementation of KPI kernel_debug_string.
+ */
+int
+kernel_debug_string(uint32_t debugid, uint64_t *str_id, const char *str)
+{
+ /* arguments to tracepoints must be word-aligned */
+ __attribute__((aligned(sizeof(uintptr_t)))) char str_buf[STR_BUF_SIZE];
+ assert_static(sizeof(str_buf) > MAX_STR_LEN);
+ vm_size_t len_copied;
+ int err;
+
+ assert(str_id);
+
+ if (__probable(kdebug_enable == 0)) {
+ return 0;
+ }
+
+ if (!kdebug_current_proc_enabled(debugid)) {
+ return 0;
+ }
+
+ if (!kdebug_debugid_enabled(debugid)) {
+ return 0;
+ }
+
+ if ((err = kdebug_check_trace_string(debugid, *str_id)) != 0) {
+ return err;
+ }
+
+ if (str == NULL) {
+ if (str_id == 0) {
+ return EINVAL;
+ }
+
+ *str_id = kernel_debug_string_internal(debugid, *str_id, NULL, 0);
+ return 0;
+ }
+
+ memset(str_buf, 0, sizeof(str_buf));
+ len_copied = strlcpy(str_buf, str, MAX_STR_LEN + 1);
+ *str_id = kernel_debug_string_internal(debugid, *str_id, str_buf,
+ len_copied);
+ return 0;
+}
+
+/*
+ * Support syscall kdebug_trace_string.
+ */
+int
+kdebug_trace_string(__unused struct proc *p,
+ struct kdebug_trace_string_args *uap,
+ uint64_t *retval)
+{
+ __attribute__((aligned(sizeof(uintptr_t)))) char str_buf[STR_BUF_SIZE];
+ assert_static(sizeof(str_buf) > MAX_STR_LEN);
+ size_t len_copied;
+ int err;
+
+ if (__probable(kdebug_enable == 0)) {
+ return 0;
+ }
+
+ if (!kdebug_current_proc_enabled(uap->debugid)) {
+ return 0;
+ }
+
+ if (!kdebug_debugid_enabled(uap->debugid)) {
+ return 0;
+ }
+
+ if ((err = kdebug_check_trace_string(uap->debugid, uap->str_id)) != 0) {
+ return err;
+ }
+
+ if (uap->str == USER_ADDR_NULL) {
+ if (uap->str_id == 0) {
+ return EINVAL;
+ }
+
+ *retval = kernel_debug_string_internal(uap->debugid, uap->str_id,
+ NULL, 0);
+ return 0;
+ }
+
+ memset(str_buf, 0, sizeof(str_buf));
+ err = copyinstr(uap->str, str_buf, MAX_STR_LEN + 1, &len_copied);
+
+ /* it's alright to truncate the string, so allow ENAMETOOLONG */
+ if (err == ENAMETOOLONG) {
+ str_buf[MAX_STR_LEN] = '\0';
+ } else if (err) {
+ return err;
+ }
+
+ if (len_copied <= 1) {
+ return EINVAL;
+ }
+
+ /* convert back to a length */
+ len_copied--;
+
+ *retval = kernel_debug_string_internal(uap->debugid, uap->str_id, str_buf,
+ len_copied);
+ return 0;
+}
+
+static void
+kdbg_lock_init(void)
+{
+ if (kd_ctrl_page.kdebug_flags & KDBG_LOCKINIT)
+ return;
+
+ /*
+ * allocate lock group attribute and group
+ */
+ kd_trace_mtx_sysctl_grp_attr = lck_grp_attr_alloc_init();
+ kd_trace_mtx_sysctl_grp = lck_grp_alloc_init("kdebug", kd_trace_mtx_sysctl_grp_attr);
+
+ /*
+ * allocate the lock attribute
+ */
+ kd_trace_mtx_sysctl_attr = lck_attr_alloc_init();
+
+
+ /*
+ * allocate and initialize mutex's
+ */
+ kd_trace_mtx_sysctl = lck_mtx_alloc_init(kd_trace_mtx_sysctl_grp, kd_trace_mtx_sysctl_attr);
+ kds_spin_lock = lck_spin_alloc_init(kd_trace_mtx_sysctl_grp, kd_trace_mtx_sysctl_attr);
+ kdw_spin_lock = lck_spin_alloc_init(kd_trace_mtx_sysctl_grp, kd_trace_mtx_sysctl_attr);
+
+ kd_ctrl_page.kdebug_flags |= KDBG_LOCKINIT;
+}
+
+
+int
+kdbg_bootstrap(boolean_t early_trace)
+{
+ kd_ctrl_page.kdebug_flags &= ~KDBG_WRAPPED;
+
+ return (create_buffers(early_trace));
+}
+
+int
+kdbg_reinit(boolean_t early_trace)
+{
+ int ret = 0;
+
+ /*
+ * Disable trace collecting
+ * First make sure we're not in
+ * the middle of cutting a trace
+ */
+ kdbg_set_tracing_enabled(FALSE, KDEBUG_ENABLE_TRACE);
+
+ /*
+ * make sure the SLOW_NOLOG is seen
+ * by everyone that might be trying
+ * to cut a trace..
+ */
+ IOSleep(100);
+
+ delete_buffers();
+
+ if ((kd_ctrl_page.kdebug_flags & KDBG_MAPINIT) && kd_mapsize && kd_mapptr) {
+ kmem_free(kernel_map, (vm_offset_t)kd_mapptr, kd_mapsize);
+ kd_ctrl_page.kdebug_flags &= ~KDBG_MAPINIT;
+ kd_mapsize = 0;
+ kd_mapptr = NULL;
+ kd_mapcount = 0;
+ }
+ ret = kdbg_bootstrap(early_trace);
+
+ RAW_file_offset = 0;
+ RAW_file_written = 0;
+
+ return(ret);
+}
+
+void
+kdbg_trace_data(struct proc *proc, long *arg_pid)
+{
+ if (!proc)
+ *arg_pid = 0;
+ else
+ *arg_pid = proc->p_pid;
+}
+
+
+void
+kdbg_trace_string(struct proc *proc, long *arg1, long *arg2, long *arg3, long *arg4)
+{
+ char *dbg_nameptr;
+ int dbg_namelen;
+ long dbg_parms[4];
+
+ if (!proc) {
+ *arg1 = 0;
+ *arg2 = 0;
+ *arg3 = 0;
+ *arg4 = 0;
+ return;
+ }
+ /*
+ * Collect the pathname for tracing
+ */
+ dbg_nameptr = proc->p_comm;
+ dbg_namelen = (int)strlen(proc->p_comm);
+ dbg_parms[0]=0L;
+ dbg_parms[1]=0L;
+ dbg_parms[2]=0L;
+ dbg_parms[3]=0L;
+
+ if(dbg_namelen > (int)sizeof(dbg_parms))
+ dbg_namelen = (int)sizeof(dbg_parms);
+
+ strncpy((char *)dbg_parms, dbg_nameptr, dbg_namelen);
+
+ *arg1=dbg_parms[0];
+ *arg2=dbg_parms[1];
+ *arg3=dbg_parms[2];
+ *arg4=dbg_parms[3];
+}
+
+static void
+kdbg_resolve_map(thread_t th_act, void *opaque)
+{
+ kd_threadmap *mapptr;
+ krt_t *t = (krt_t *)opaque;
+
+ if (t->count < t->maxcount) {
+ mapptr = &t->map[t->count];
+ mapptr->thread = (uintptr_t)thread_tid(th_act);