+
+ *sp_val = *(uintptr_t *)sp;
+ return KERN_SUCCESS;
+}
+
+#else /* defined(__arm__) */
+#error "interrupted_kernel_{sp,lr}: unsupported architecture"
+#endif /* !defined(__arm__) */
+
+
+static void
+callstack_fixup_interrupted(struct callstack *cs)
+{
+ uintptr_t fixup_val = 0;
+ assert(cs->nframes < MAX_CALLSTACK_FRAMES);
+
+ /*
+ * Only provide arbitrary data on development or debug kernels.
+ */
+#if DEVELOPMENT || DEBUG
+#if defined(__x86_64__)
+ (void)interrupted_kernel_sp_value(&fixup_val);
+#endif /* defined(__x86_64__) */
+#endif /* DEVELOPMENT || DEBUG */
+
+ cs->frames[cs->nframes++] = fixup_val ?
+ VM_KERNEL_UNSLIDE_OR_PERM(fixup_val) : 0;
+}
+
+void
+kperf_continuation_sample(struct callstack *cs, struct kperf_context *context)
+{
+ thread_t thread;
+
+ assert(cs != NULL);
+ assert(context != NULL);
+
+ thread = context->cur_thread;
+ assert(thread != NULL);
+ assert(thread->continuation != NULL);
+
+ cs->flags = CALLSTACK_CONTINUATION | CALLSTACK_VALID | CALLSTACK_KERNEL;
+#ifdef __LP64__
+ cs->flags |= CALLSTACK_64BIT;
+#endif
+
+ cs->nframes = 1;
+ cs->frames[0] = VM_KERNEL_UNSLIDE(thread->continuation);
+}
+
+void
+kperf_backtrace_sample(struct callstack *cs, struct kperf_context *context)
+{
+ assert(cs != NULL);
+ assert(context != NULL);
+ assert(context->cur_thread == current_thread());
+
+ cs->flags = CALLSTACK_KERNEL | CALLSTACK_KERNEL_WORDS;
+#ifdef __LP64__
+ cs->flags |= CALLSTACK_64BIT;
+#endif
+
+ BUF_VERB(PERF_CS_BACKTRACE | DBG_FUNC_START, 1);
+
+ cs->nframes = backtrace_frame((uintptr_t *)&(cs->frames), cs->nframes - 1,
+ context->starting_fp);
+ if (cs->nframes > 0) {