+}
+
+static int
+copyoutsiginfo(user_siginfo_t *native, boolean_t is64, user_addr_t uaddr)
+{
+ if (is64) {
+ user64_siginfo_t sinfo64;
+
+ bzero(&sinfo64, sizeof (sinfo64));
+ siginfo_user_to_user64(native, &sinfo64);
+ return (copyout(&sinfo64, uaddr, sizeof (sinfo64)));
+ } else {
+ user32_siginfo_t sinfo32;
+
+ bzero(&sinfo32, sizeof (sinfo32));
+ siginfo_user_to_user32(native, &sinfo32);
+ return (copyout(&sinfo32, uaddr, sizeof (sinfo32)));
+ }
+}
+
+static void populate_corpse_crashinfo(proc_t p, void *crash_info_ptr, struct rusage_superset *rup, mach_exception_data_type_t code, mach_exception_data_type_t subcode)
+{
+ mach_vm_address_t uaddr = 0;
+ mach_exception_data_type_t exc_codes[EXCEPTION_CODE_MAX];
+ exc_codes[0] = code;
+ exc_codes[1] = subcode;
+ cpu_type_t cputype;
+ struct proc_uniqidentifierinfo p_uniqidinfo;
+ struct proc_workqueueinfo pwqinfo;
+ int retval = 0;
+ uint64_t crashed_threadid = thread_tid(current_thread());
+ unsigned int pflags = 0;
+
+#if CONFIG_MEMORYSTATUS
+ int memstat_dirty_flags = 0;
+#endif
+
+ if (KERN_SUCCESS == kcdata_get_memory_addr(crash_info_ptr, TASK_CRASHINFO_EXCEPTION_CODES, sizeof(exc_codes), &uaddr)) {
+ copyout(exc_codes, uaddr, sizeof(exc_codes));
+ }
+
+ if (KERN_SUCCESS == kcdata_get_memory_addr(crash_info_ptr, TASK_CRASHINFO_PID, sizeof(p->p_pid), &uaddr)) {
+ copyout(&p->p_pid, uaddr, sizeof(p->p_pid));
+ }
+
+ if (KERN_SUCCESS == kcdata_get_memory_addr(crash_info_ptr, TASK_CRASHINFO_PPID, sizeof(p->p_ppid), &uaddr)) {
+ copyout(&p->p_ppid, uaddr, sizeof(p->p_ppid));
+ }
+
+ if (KERN_SUCCESS == kcdata_get_memory_addr(crash_info_ptr, TASK_CRASHINFO_CRASHED_THREADID, sizeof(uint64_t), &uaddr)) {
+ copyout(&crashed_threadid, uaddr, sizeof(uint64_t));
+ }
+
+ if (KERN_SUCCESS == kcdata_get_memory_addr(crash_info_ptr, TASK_CRASHINFO_RUSAGE, sizeof(struct rusage), &uaddr)) {
+ copyout(&rup->ru, uaddr, sizeof(struct rusage));
+ }
+
+ if (KERN_SUCCESS ==
+ kcdata_get_memory_addr(crash_info_ptr, TASK_CRASHINFO_BSDINFOWITHUNIQID, sizeof(struct proc_uniqidentifierinfo), &uaddr)) {
+ proc_piduniqidentifierinfo(p, &p_uniqidinfo);
+ copyout(&p_uniqidinfo, uaddr, sizeof(struct proc_uniqidentifierinfo));
+ }
+
+ if (KERN_SUCCESS == kcdata_get_memory_addr(crash_info_ptr, TASK_CRASHINFO_RUSAGE_INFO, sizeof(rusage_info_current), &uaddr)) {
+ copyout(&rup->ri, uaddr, sizeof(rusage_info_current));
+ }
+
+ if (KERN_SUCCESS == kcdata_get_memory_addr(crash_info_ptr, TASK_CRASHINFO_PROC_CSFLAGS, sizeof(p->p_csflags), &uaddr)) {
+ copyout(&p->p_csflags, uaddr, sizeof(p->p_csflags));
+ }
+
+ if (KERN_SUCCESS == kcdata_get_memory_addr(crash_info_ptr, TASK_CRASHINFO_PROC_NAME, sizeof(p->p_comm), &uaddr)) {
+ copyout(&p->p_comm, uaddr, sizeof(p->p_comm));
+ }
+
+ if (KERN_SUCCESS == kcdata_get_memory_addr(crash_info_ptr, TASK_CRASHINFO_PROC_STARTTIME, sizeof(p->p_start), &uaddr)) {
+ struct timeval64 t64;
+ t64.tv_sec = (int64_t)p->p_start.tv_sec;
+ t64.tv_usec = (int64_t)p->p_start.tv_usec;
+ copyout(&t64, uaddr, sizeof(t64));
+ }
+
+ if (KERN_SUCCESS == kcdata_get_memory_addr(crash_info_ptr, TASK_CRASHINFO_USERSTACK, sizeof(p->user_stack), &uaddr)) {
+ copyout(&p->user_stack, uaddr, sizeof(p->user_stack));
+ }
+
+ if (KERN_SUCCESS == kcdata_get_memory_addr(crash_info_ptr, TASK_CRASHINFO_ARGSLEN, sizeof(p->p_argslen), &uaddr)) {
+ copyout(&p->p_argslen, uaddr, sizeof(p->p_argslen));
+ }
+
+ if (KERN_SUCCESS == kcdata_get_memory_addr(crash_info_ptr, TASK_CRASHINFO_PROC_ARGC, sizeof(p->p_argc), &uaddr)) {
+ copyout(&p->p_argc, uaddr, sizeof(p->p_argc));
+ }
+
+ if (KERN_SUCCESS == kcdata_get_memory_addr(crash_info_ptr, TASK_CRASHINFO_PROC_PATH, MAXPATHLEN, &uaddr)) {
+ proc_pidpathinfo(p, 0, uaddr, MAXPATHLEN, &retval);
+ }
+
+ pflags = p->p_flag & (P_LP64 | P_SUGID);
+ if (KERN_SUCCESS == kcdata_get_memory_addr(crash_info_ptr, TASK_CRASHINFO_PROC_FLAGS, sizeof(pflags), &uaddr)) {
+ copyout(&pflags, uaddr, sizeof(pflags));
+ }
+
+ if (KERN_SUCCESS == kcdata_get_memory_addr(crash_info_ptr, TASK_CRASHINFO_UID, sizeof(p->p_uid), &uaddr)) {
+ copyout(&p->p_uid, uaddr, sizeof(p->p_uid));
+ }
+
+ if (KERN_SUCCESS == kcdata_get_memory_addr(crash_info_ptr, TASK_CRASHINFO_GID, sizeof(p->p_gid), &uaddr)) {
+ copyout(&p->p_gid, uaddr, sizeof(p->p_gid));
+ }
+
+ cputype = cpu_type() & ~CPU_ARCH_MASK;
+ if (IS_64BIT_PROCESS(p))
+ cputype |= CPU_ARCH_ABI64;
+
+ if (KERN_SUCCESS == kcdata_get_memory_addr(crash_info_ptr, TASK_CRASHINFO_CPUTYPE, sizeof(cpu_type_t), &uaddr)) {
+ copyout(&cputype, uaddr, sizeof(cpu_type_t));
+ }
+
+ bzero(&pwqinfo, sizeof(struct proc_workqueueinfo));
+ retval = fill_procworkqueue(p, &pwqinfo);
+ if (retval == 0) {
+ if (KERN_SUCCESS == kcdata_get_memory_addr(crash_info_ptr, TASK_CRASHINFO_WORKQUEUEINFO, sizeof(struct proc_workqueueinfo), &uaddr)) {
+ copyout(&pwqinfo, uaddr, sizeof(struct proc_workqueueinfo));
+ }
+ }
+
+ if (KERN_SUCCESS == kcdata_get_memory_addr(crash_info_ptr, TASK_CRASHINFO_RESPONSIBLE_PID, sizeof(p->p_responsible_pid), &uaddr)) {
+ copyout(&p->p_responsible_pid, uaddr, sizeof(p->p_responsible_pid));
+ }
+
+#if CONFIG_MEMORYSTATUS
+ memstat_dirty_flags = memorystatus_dirty_get(p);
+ if (KERN_SUCCESS == kcdata_get_memory_addr(crash_info_ptr, TASK_CRASHINFO_DIRTY_FLAGS, sizeof(memstat_dirty_flags), &uaddr)) {
+ copyout(&memstat_dirty_flags, uaddr, sizeof(memstat_dirty_flags));
+ }
+#endif
+
+}
+
+static __attribute__((noinline)) void
+launchd_crashed_panic(proc_t p, int rv)
+{
+ printf("pid 1 exited (signal %d, exit %d)\n",
+ WTERMSIG(rv), WEXITSTATUS(rv));
+
+#if (DEVELOPMENT || DEBUG)
+ /*
+ * For debugging purposes, generate a core file of initproc before
+ * panicking. Leave at least 300 MB free on the root volume, and ignore
+ * the process's corefile ulimit. fsync() the file to ensure it lands on disk
+ * before the panic hits.
+ */
+
+ int err;
+ uint64_t coredump_start = mach_absolute_time();
+ uint64_t coredump_end;
+ clock_sec_t tv_sec;
+ clock_usec_t tv_usec;
+ uint32_t tv_msec;
+
+ err = coredump(p, 300, COREDUMP_IGNORE_ULIMIT | COREDUMP_FULLFSYNC);
+
+ coredump_end = mach_absolute_time();
+
+ absolutetime_to_microtime(coredump_end - coredump_start, &tv_sec, &tv_usec);
+
+ tv_msec = tv_usec / 1000;
+
+ if (err != 0) {
+ printf("Failed to generate initproc core file: error %d, took %d.%03d seconds\n",
+ err, (uint32_t)tv_sec, tv_msec);
+ } else {
+ printf("Generated initproc core file in %d.%03d seconds\n",
+ (uint32_t)tv_sec, tv_msec);
+ }
+#endif
+
+ sync(p, (void *)NULL, (int *)NULL);
+
+ panic_plain("%s exited (signal %d, exit status %d %s)", (p->p_name[0] != '\0' ? p->p_name : "initproc"), WTERMSIG(rv),
+ WEXITSTATUS(rv), ((p->p_csflags & CS_KILLED) ? "CS_KILLED" : ""));