+
+void
+start_kern_tracing(unsigned int new_nkdbufs, boolean_t need_map)
+{
+
+ if (!new_nkdbufs)
+ return;
+ nkdbufs = kdbg_set_nkdbufs(new_nkdbufs);
+ kdbg_lock_init();
+
+ kernel_debug_string("start_kern_tracing");
+
+ if (0 == kdbg_reinit(TRUE)) {
+
+ if (need_map == TRUE) {
+ uint32_t old1, old2;
+
+ kdbg_thrmap_init();
+
+ disable_wrap(&old1, &old2);
+ }
+
+ /* Hold off interrupts until the early traces are cut */
+ boolean_t s = ml_set_interrupts_enabled(FALSE);
+
+ kdbg_set_tracing_enabled(
+ TRUE,
+ kdebug_serial ?
+ (KDEBUG_ENABLE_TRACE | KDEBUG_ENABLE_SERIAL) :
+ KDEBUG_ENABLE_TRACE);
+
+ /*
+ * Transfer all very early events from the static buffer
+ * into the real buffers.
+ */
+ kernel_debug_early_end();
+
+ ml_set_interrupts_enabled(s);
+
+ printf("kernel tracing started\n");
+#if KDEBUG_MOJO_TRACE
+ if (kdebug_serial) {
+ printf("serial output enabled with %lu named events\n",
+ sizeof(kd_events)/sizeof(kd_event_t));
+ }
+#endif
+ } else {
+ printf("error from kdbg_reinit, kernel tracing not started\n");
+ }
+}
+
+void
+start_kern_tracing_with_typefilter(unsigned int new_nkdbufs,
+ boolean_t need_map,
+ unsigned int typefilter)
+{
+ /* startup tracing */
+ start_kern_tracing(new_nkdbufs, need_map);
+
+ /* check that tracing was actually enabled */
+ if (!(kdebug_enable & KDEBUG_ENABLE_TRACE))
+ return;
+
+ /* setup the typefiltering */
+ if (0 == kdbg_enable_typefilter())
+ setbit(type_filter_bitmap, typefilter & (CSC_MASK >> CSC_OFFSET));
+}
+
+void
+kdbg_dump_trace_to_file(const char *filename)
+{
+ vfs_context_t ctx;
+ vnode_t vp;
+ int error;
+ size_t number;
+
+
+ if ( !(kdebug_enable & KDEBUG_ENABLE_TRACE))
+ return;
+
+ if (global_state_pid != -1) {
+ if ((proc_find(global_state_pid)) != NULL) {
+ /*
+ * The global pid exists, we're running
+ * due to fs_usage, latency, etc...
+ * don't cut the panic/shutdown trace file
+ * Disable tracing from this point to avoid
+ * perturbing state.
+ */
+ kdebug_enable = 0;
+ kd_ctrl_page.enabled = 0;
+ commpage_update_kdebug_enable();
+ return;
+ }
+ }
+ KERNEL_DEBUG_CONSTANT(TRACE_PANIC | DBG_FUNC_NONE, 0, 0, 0, 0, 0);
+
+ kdebug_enable = 0;
+ kd_ctrl_page.enabled = 0;
+ commpage_update_kdebug_enable();
+
+ ctx = vfs_context_kernel();
+
+ if ((error = vnode_open(filename, (O_CREAT | FWRITE | O_NOFOLLOW), 0600, 0, &vp, ctx)))
+ return;
+
+ number = kd_mapcount * sizeof(kd_threadmap);
+ kdbg_readthrmap(0, &number, vp, ctx);
+
+ number = nkdbufs*sizeof(kd_buf);
+ kdbg_read(0, &number, vp, ctx);
+
+ vnode_close(vp, FWRITE, ctx);
+
+ sync(current_proc(), (void *)NULL, (int *)NULL);
+}
+
+/* Helper function for filling in the BSD name for an address space
+ * Defined here because the machine bindings know only Mach threads
+ * and nothing about BSD processes.
+ *
+ * FIXME: need to grab a lock during this?
+ */
+void kdbg_get_task_name(char* name_buf, int len, task_t task)
+{
+ proc_t proc;
+
+ /* Note: we can't use thread->task (and functions that rely on it) here
+ * because it hasn't been initialized yet when this function is called.
+ * We use the explicitly-passed task parameter instead.
+ */
+ proc = get_bsdtask_info(task);
+ if (proc != PROC_NULL)
+ snprintf(name_buf, len, "%s/%d", proc->p_comm, proc->p_pid);
+ else
+ snprintf(name_buf, len, "%p [!bsd]", task);
+}
+
+#if KDEBUG_MOJO_TRACE
+static kd_event_t *
+binary_search(uint32_t id)
+{
+ int low, high, mid;
+
+ low = 0;
+ high = sizeof(kd_events)/sizeof(kd_event_t) - 1;
+
+ while (TRUE)
+ {
+ mid = (low + high) / 2;
+
+ if (low > high)
+ return NULL; /* failed */
+ else if ( low + 1 >= high) {
+ /* We have a match */
+ if (kd_events[high].id == id)
+ return &kd_events[high];
+ else if (kd_events[low].id == id)
+ return &kd_events[low];
+ else
+ return NULL; /* search failed */
+ }
+ else if (id < kd_events[mid].id)
+ high = mid;
+ else
+ low = mid;
+ }
+}
+
+/*
+ * Look up event id to get name string.
+ * Using a per-cpu cache of a single entry
+ * before resorting to a binary search of the full table.
+ */
+#define NCACHE 1
+static kd_event_t *last_hit[MAX_CPUS];
+static kd_event_t *
+event_lookup_cache(uint32_t cpu, uint32_t id)
+{
+ if (last_hit[cpu] == NULL || last_hit[cpu]->id != id)
+ last_hit[cpu] = binary_search(id);
+ return last_hit[cpu];
+}
+
+static uint64_t kd_last_timstamp;
+
+static void
+kdebug_serial_print(
+ uint32_t cpunum,
+ uint32_t debugid,
+ uint64_t timestamp,
+ uintptr_t arg1,
+ uintptr_t arg2,
+ uintptr_t arg3,
+ uintptr_t arg4,
+ uintptr_t threadid
+ )
+{
+ char kprintf_line[192];
+ char event[40];
+ uint64_t us = timestamp / NSEC_PER_USEC;
+ uint64_t us_tenth = (timestamp % NSEC_PER_USEC) / 100;
+ uint64_t delta = timestamp - kd_last_timstamp;
+ uint64_t delta_us = delta / NSEC_PER_USEC;
+ uint64_t delta_us_tenth = (delta % NSEC_PER_USEC) / 100;
+ uint32_t event_id = debugid & DBG_FUNC_MASK;
+ const char *command;
+ const char *bra;
+ const char *ket;
+ kd_event_t *ep;
+
+ /* event time and delta from last */
+ snprintf(kprintf_line, sizeof(kprintf_line),
+ "%11llu.%1llu %8llu.%1llu ",
+ us, us_tenth, delta_us, delta_us_tenth);
+
+
+ /* event (id or name) - start prefixed by "[", end postfixed by "]" */
+ bra = (debugid & DBG_FUNC_START) ? "[" : " ";
+ ket = (debugid & DBG_FUNC_END) ? "]" : " ";
+ ep = event_lookup_cache(cpunum, event_id);
+ if (ep) {
+ if (strlen(ep->name) < sizeof(event) - 3)
+ snprintf(event, sizeof(event), "%s%s%s",
+ bra, ep->name, ket);
+ else
+ snprintf(event, sizeof(event), "%s%x(name too long)%s",
+ bra, event_id, ket);
+ } else {
+ snprintf(event, sizeof(event), "%s%x%s",
+ bra, event_id, ket);
+ }
+ snprintf(kprintf_line + strlen(kprintf_line),
+ sizeof(kprintf_line) - strlen(kprintf_line),
+ "%-40s ", event);
+
+ /* arg1 .. arg4 with special cases for strings */
+ switch (event_id) {
+ case VFS_LOOKUP:
+ case VFS_LOOKUP_DONE:
+ if (debugid & DBG_FUNC_START) {
+ /* arg1 hex then arg2..arg4 chars */
+ snprintf(kprintf_line + strlen(kprintf_line),
+ sizeof(kprintf_line) - strlen(kprintf_line),
+ "%-16lx %-8s%-8s%-8s ",
+ arg1, (char*)&arg2, (char*)&arg3, (char*)&arg4);
+ break;
+ }
+ /* else fall through for arg1..arg4 chars */
+ case TRACE_STRING_EXEC:
+ case TRACE_STRING_NEWTHREAD:
+ case TRACE_INFO_STRING:
+ snprintf(kprintf_line + strlen(kprintf_line),
+ sizeof(kprintf_line) - strlen(kprintf_line),
+ "%-8s%-8s%-8s%-8s ",
+ (char*)&arg1, (char*)&arg2, (char*)&arg3, (char*)&arg4);
+ break;
+ default:
+ snprintf(kprintf_line + strlen(kprintf_line),
+ sizeof(kprintf_line) - strlen(kprintf_line),
+ "%-16lx %-16lx %-16lx %-16lx",
+ arg1, arg2, arg3, arg4);
+ }
+
+ /* threadid, cpu and command name */
+ if (threadid == (uintptr_t)thread_tid(current_thread()) &&
+ current_proc() &&
+ current_proc()->p_comm)
+ command = current_proc()->p_comm;
+ else
+ command = "-";
+ snprintf(kprintf_line + strlen(kprintf_line),
+ sizeof(kprintf_line) - strlen(kprintf_line),
+ " %-16lx %-2d %s\n",
+ threadid, cpunum, command);
+
+ kprintf("%s", kprintf_line);
+ kd_last_timstamp = timestamp;
+}
+#endif