+#define OS_REASON_IFLAG_USER_FAULT 0x1
+
+#define OS_REASON_TOTAL_USER_FAULTS_PER_PROC 5
+
+static int
+abort_with_payload_internal(proc_t p,
+ uint32_t reason_namespace, uint64_t reason_code,
+ user_addr_t payload, uint32_t payload_size,
+ user_addr_t reason_string, uint64_t reason_flags,
+ uint32_t internal_flags)
+{
+ os_reason_t exit_reason = OS_REASON_NULL;
+ kern_return_t kr = KERN_SUCCESS;
+
+ if (internal_flags & OS_REASON_IFLAG_USER_FAULT) {
+ uint32_t old_value = atomic_load_explicit(&p->p_user_faults,
+ memory_order_relaxed);
+ for (;;) {
+ if (old_value >= OS_REASON_TOTAL_USER_FAULTS_PER_PROC) {
+ return EQFULL;
+ }
+ // this reloads the value in old_value
+ if (atomic_compare_exchange_strong_explicit(&p->p_user_faults,
+ &old_value, old_value + 1, memory_order_relaxed,
+ memory_order_relaxed)) {
+ break;
+ }
+ }
+ }
+
+ KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_PROC, BSD_PROC_EXITREASON_CREATE) | DBG_FUNC_NONE,
+ p->p_pid, reason_namespace,
+ reason_code, 0, 0);
+
+ exit_reason = build_userspace_exit_reason(reason_namespace, reason_code,
+ payload, payload_size, reason_string, reason_flags);
+
+ if (internal_flags & OS_REASON_IFLAG_USER_FAULT) {
+ mach_exception_code_t code = 0;
+
+ EXC_GUARD_ENCODE_TYPE(code, GUARD_TYPE_USER); /* simulated EXC_GUARD */
+ EXC_GUARD_ENCODE_FLAVOR(code, 0);
+ EXC_GUARD_ENCODE_TARGET(code, reason_namespace);
+
+ if (exit_reason == OS_REASON_NULL) {
+ kr = KERN_RESOURCE_SHORTAGE;
+ } else {
+ kr = task_violated_guard(code, reason_code, exit_reason);
+ }
+ os_reason_free(exit_reason);
+ } else {
+ /*
+ * We use SIGABRT (rather than calling exit directly from here) so that
+ * the debugger can catch abort_with_{reason,payload} calls.
+ */
+ psignal_try_thread_with_reason(p, current_thread(), SIGABRT, exit_reason);
+ }
+
+ switch (kr) {
+ case KERN_SUCCESS:
+ return 0;
+ case KERN_NOT_SUPPORTED:
+ return ENOTSUP;
+ case KERN_INVALID_ARGUMENT:
+ return EINVAL;
+ case KERN_RESOURCE_SHORTAGE:
+ default:
+ return EBUSY;
+ }
+}
+
+int
+abort_with_payload(struct proc *cur_proc, struct abort_with_payload_args *args,
+ __unused void *retval)
+{
+ abort_with_payload_internal(cur_proc, args->reason_namespace,
+ args->reason_code, args->payload, args->payload_size,
+ args->reason_string, args->reason_flags, 0);
+
+ return 0;
+}
+
+int
+os_fault_with_payload(struct proc *cur_proc,
+ struct os_fault_with_payload_args *args, __unused int *retval)
+{
+ return abort_with_payload_internal(cur_proc, args->reason_namespace,
+ args->reason_code, args->payload, args->payload_size,
+ args->reason_string, args->reason_flags, OS_REASON_IFLAG_USER_FAULT);
+}
+
+