Index: lib/libc/sys/ptrace.2 =================================================================== --- lib/libc/sys/ptrace.2 +++ lib/libc/sys/ptrace.2 @@ -2,7 +2,7 @@ .\" $NetBSD: ptrace.2,v 1.2 1995/02/27 12:35:37 cgd Exp $ .\" .\" This file is in the public domain. -.Dd July 15, 2019 +.Dd April 10, 2021 .Dt PTRACE 2 .Os .Sh NAME @@ -807,6 +807,20 @@ The .Fa data argument is ignored. +.It Dv PT_COREDUMP +This request creates a coredump for the stopped program. +.Fa addr +argument specifies a pointer to a +.Vt "struct ptrace_coredump" , +which is defined as follows: +.Bd -literal +struct ptrace_coredump { + TODO; +}; +.Ed +.Pp +The size of the structmust be passed in +.Fa data . .El .Sh ARM MACHINE-SPECIFIC REQUESTS .Bl -tag -width "Dv PT_SETVFPREGS" Index: sys/kern/subr_trap.c =================================================================== --- sys/kern/subr_trap.c +++ sys/kern/subr_trap.c @@ -193,6 +193,41 @@ #endif } +void ptrace_coredump(struct proc *p); +/*static*/ +void +ptrace_coredump(struct proc *p) +{ + struct thread *td; + /* TODO: do something about the error */ + int error; + + td = curthread; + + if ((p->p_flag2 & P2_COREDUMP) == 0) + return; + if (p->p_sysent->sv_coredump == NULL) { + error = ENOSYS; + return; + } + + if (thread_single(p, SINGLE_BOUNDARY) != 0) { + error = EBUSY; + return; + } + +#if 0 + struct vnode *vp = p->p_coredump_vn; + PROC_UNLOCK(p); + error = p->p_sysent->sv_coredump(td, vp, OFF_MAX, 0); + PROC_LOCK(p); +#endif + thread_single_end(p, SINGLE_BOUNDARY); + + p->p_flag2 &= ~P2_COREDUMP; + wakeup(p); +} + /* * Process an asynchronous software trap. * This is relatively easy. @@ -355,6 +390,12 @@ kern_sigprocmask(td, SIG_SETMASK, &td->td_oldsigmask, NULL, 0); } + if ((p->p_flag2 & P2_COREDUMP) != 0) { + PROC_LOCK(p); + ptrace_coredump(p); + PROC_UNLOCK(p); + } + #ifdef RACCT if (__predict_false(racct_enable && p->p_throttled != 0)) racct_proc_throttled(p); Index: sys/kern/sys_process.c =================================================================== --- sys/kern/sys_process.c +++ sys/kern/sys_process.c @@ -51,6 +51,8 @@ #include #include #include +#include +#include #include @@ -469,6 +471,7 @@ struct ptrace_io_desc piod; struct ptrace_lwpinfo pl; struct ptrace_vm_entry pve; + struct ptrace_coredump pc; struct dbreg dbreg; struct fpreg fpreg; struct reg reg; @@ -519,6 +522,12 @@ case PT_VM_ENTRY: error = copyin(uap->addr, &r.pve, sizeof(r.pve)); break; + case PT_COREDUMP: + if (uap->data != sizeof(r.pc)) + error = EINVAL; + else + error = copyin(uap->addr, &r.pc, uap->data); + break; default: addr = uap->addr; break; @@ -611,6 +620,7 @@ struct ptrace_io_desc *piod = NULL; struct ptrace_lwpinfo *pl; struct ptrace_sc_ret *psr; + struct file *fp; int error, num, tmp; int proctree_locked = 0; lwpid_t tid = 0, *buf; @@ -635,6 +645,7 @@ case PT_SET_EVENT_MASK: case PT_DETACH: case PT_GET_SC_ARGS: + case PT_COREDUMP: sx_xlock(&proctree_lock); proctree_locked = 1; break; @@ -950,6 +961,11 @@ case PT_TO_SCX: case PT_SYSCALL: case PT_DETACH: + case PT_COREDUMP: + /* PT_COREDUMP does not pass signal in data. */ + if (req == PT_COREDUMP) + data = 0; + /* Zero means do not send any signal */ if (data < 0 || data > _SIG_MAXSIG) { error = EINVAL; @@ -1003,6 +1019,26 @@ break; } break; + case PT_COREDUMP: + { + struct ptrace_coredump *pc = addr; + CTR2(KTR_PTRACE, + "PT_COREDUMP: pid %d, fd = %d", + p->p_pid, pc->pc_fd); + + error = getvnode(td, pc->pc_fd, &cap_write_rights, &fp); + if (error != 0) + break; + + /* Do not try writing to non-regular files. */ + if (fp->f_vnode->v_type != VREG) { + error = EFAULT; + break; + } + + p->p_coredump_vn = fp->f_vnode; + break; + } case PT_DETACH: /* * Clear P_TRACED before reparenting @@ -1052,12 +1088,20 @@ break; } + if (error != 0) + break; + sx_xunlock(&proctree_lock); proctree_locked = 0; sendsig: MPASS(proctree_locked == 0); + if ((p->p_flag2 & P2_COREDUMP) != 0) { + /* XXXKIB do something reasonable */ + } + p->p_flag2 |= P2_COREDUMP; + /* * Clear the pending event for the thread that just * reported its event (p_xthread). This may not be @@ -1313,6 +1357,13 @@ } out: + if (req == PT_COREDUMP) { + while ((p->p_flag2 & P2_COREDUMP) != 0) + msleep(p, &p->p_mtx, PPAUSE, "crdmp", 0); + /* get the results etc */ + fdrop(fp, td); + } + /* Drop our hold on this process now that the request has completed. */ _PRELE(p); fail: Index: sys/sys/proc.h =================================================================== --- sys/sys/proc.h +++ sys/sys/proc.h @@ -720,6 +720,7 @@ uint64_t p_prev_runtime; /* (c) Resource usage accounting. */ struct racct *p_racct; /* (b) Resource accounting. */ int p_throttled; /* (c) Flag for racct pcpu throttling */ + struct vnode *p_coredump_vn; /* vnode to write coredump to. */ /* * An orphan is the child that has been re-parented to the * debugger as a result of attaching to it. Need to keep @@ -829,6 +830,7 @@ #define P2_STKGAP_DISABLE_EXEC 0x00001000 /* Stack gap disabled after exec */ #define P2_ITSTOPPED 0x00002000 +#define P2_COREDUMP 0x00004000 /* Coredump request */ /* Flags protected by proctree_lock, kept in p_treeflags. */ #define P_TREE_ORPHANED 0x00000001 /* Reparented, on orphan list */ Index: sys/sys/ptrace.h =================================================================== --- sys/sys/ptrace.h +++ sys/sys/ptrace.h @@ -74,6 +74,8 @@ #define PT_GET_SC_ARGS 27 /* fetch syscall args */ #define PT_GET_SC_RET 28 /* fetch syscall results */ +#define PT_COREDUMP 29 /* create a coredump */ + #define PT_GETREGS 33 /* get general-purpose registers */ #define PT_SETREGS 34 /* set general-purpose registers */ #define PT_GETFPREGS 35 /* get floating-point registers */ @@ -176,6 +178,11 @@ char *pve_path; /* Path name of object. */ }; +/* Argument structure for PT_COREDUMP. */ +struct ptrace_coredump { + int pc_fd; /* File descriptor to write dump to. */ +}; + #ifdef _KERNEL int ptrace_set_pc(struct thread *_td, unsigned long _addr);