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,15 @@ The .Fa data argument is ignored. +.It Dv PT_DUMPCORE +This request creates a coredump for the stopped program. +.Fa addr +must point to a buffer containing a null-terminated path where coredump +should be created. The path may use the formats described in +.Xr core 5 . +.Fa data +specifies the size of the buffer. Upon success, the actual file path +(with formats expanded) is written back into the buffer. .El .Sh ARM MACHINE-SPECIFIC REQUESTS .Bl -tag -width "Dv PT_SETVFPREGS" Index: sys/kern/kern_sig.c =================================================================== --- sys/kern/kern_sig.c +++ sys/kern/kern_sig.c @@ -103,7 +103,7 @@ SDT_PROBE_DEFINE3(proc, , , signal__discard, "struct thread *", "struct proc *", "int"); -static int coredump(struct thread *); +int coredump(struct thread *, const char *, char *); static int killpg1(struct thread *td, int sig, int pgid, int all, ksiginfo_t *ksi); static int issignal(struct thread *td); @@ -3268,6 +3268,30 @@ kern_psignal(p, SIGKILL); } +/* + * Protect the access to corefilename[] by allproc_lock. + */ +#define corefilename_lock allproc_lock + +static char corefilename[MAXPATHLEN] = {"%N.core"}; +TUNABLE_STR("kern.corefile", corefilename, sizeof(corefilename)); + +static int +sysctl_kern_corefile(SYSCTL_HANDLER_ARGS) +{ + int error; + + sx_xlock(&corefilename_lock); + error = sysctl_handle_string(oidp, corefilename, sizeof(corefilename), + req); + sx_xunlock(&corefilename_lock); + + return (error); +} +SYSCTL_PROC(_kern, OID_AUTO, corefile, CTLTYPE_STRING | CTLFLAG_RW | + CTLFLAG_MPSAFE, 0, 0, sysctl_kern_corefile, "A", + "Process corefile name format string"); + /* * Force the current process to exit with the specified signal, dumping core * if appropriate. We bypass the normal tests for masked and caught signals, @@ -3302,7 +3326,7 @@ * XXX : Todo, as well as euid, write out ruid too * Note that coredump() drops proc lock. */ - if (coredump(td) == 0) + if (coredump(td, corefilename, NULL) == 0) sig |= WCOREFLAG; if (kern_logsigexit) log(LOG_INFO, @@ -3461,30 +3485,6 @@ &compress_user_cores_level, 0, "Corefile compression level"); -/* - * Protect the access to corefilename[] by allproc_lock. - */ -#define corefilename_lock allproc_lock - -static char corefilename[MAXPATHLEN] = {"%N.core"}; -TUNABLE_STR("kern.corefile", corefilename, sizeof(corefilename)); - -static int -sysctl_kern_corefile(SYSCTL_HANDLER_ARGS) -{ - int error; - - sx_xlock(&corefilename_lock); - error = sysctl_handle_string(oidp, corefilename, sizeof(corefilename), - req); - sx_xunlock(&corefilename_lock); - - return (error); -} -SYSCTL_PROC(_kern, OID_AUTO, corefile, CTLTYPE_STRING | CTLFLAG_RW | - CTLFLAG_MPSAFE, 0, 0, sysctl_kern_corefile, "A", - "Process corefile name format string"); - static void vnode_close_locked(struct thread *td, struct vnode *vp) { @@ -3586,10 +3586,10 @@ } /* - * corefile_open(comm, uid, pid, td, compress, vpp, namep) - * Expand the name described in corefilename, using name, uid, and pid + * corefile_open(comm, uid, pid, td, compress, vpp, namep, format) + * Expand the name described in format, using name, uid, and pid * and open/create core file. - * corefilename is a printf-like string, with three format specifiers: + * format is a printf-like string, with three format specifiers: * %N name of process ("name") * %P process id (pid) * %U user id (uid) @@ -3599,16 +3599,15 @@ */ static int corefile_open(const char *comm, uid_t uid, pid_t pid, struct thread *td, - int compress, int signum, struct vnode **vpp, char **namep) + int compress, int signum, struct vnode **vpp, char **namep, + const char *format) { struct sbuf sb; struct nameidata nd; - const char *format; char *hostname, *name; int cmode, error, flags, i, indexpos, indexlen, oflags, ncores; hostname = NULL; - format = corefilename; name = malloc(MAXPATHLEN, M_TEMP, M_WAITOK | M_ZERO); indexlen = 0; indexpos = -1; @@ -3720,15 +3719,17 @@ } /* - * Dump a process' core. The main routine does some - * policy checking, and creates the name of the coredump; - * then it passes on a vnode and a size limit to the process-specific - * coredump routine if there is one; if there _is not_ one, it returns - * ENOSYS; otherwise it returns the error from the process-specific routine. + * Dump a process' core. The main routine does some policy checking, + * and creates the name of the coredump using specified format; then it passes + * on a vnode and a size limit to the process-specific coredump routine if + * there is one; if there _is not_ one, it returns ENOSYS; otherwise it returns + * the error from the process-specific routine. Finally, if it were successful + * and outpath is not NULL, it copies the core dump path into it (up + * to MAXPATHLEN). */ -static int -coredump(struct thread *td) +int +coredump(struct thread *td, const char *format, char *outpath) { struct proc *p = td->td_proc; struct ucred *cred = td->td_ucred; @@ -3768,7 +3769,7 @@ PROC_UNLOCK(p); error = corefile_open(p->p_comm, cred->cr_uid, p->p_pid, td, - compress_user_cores, p->p_sig, &vp, &name); + compress_user_cores, p->p_sig, &vp, &name, format); if (error != 0) return (error); @@ -3861,6 +3862,8 @@ #ifdef AUDIT audit_proc_coredump(td, name, error); #endif + if (outpath) + strcpy(outpath, name); free(name, M_TEMP); return (error); } Index: sys/kern/sys_process.c =================================================================== --- sys/kern/sys_process.c +++ sys/kern/sys_process.c @@ -69,6 +69,8 @@ #include #endif +int coredump(struct thread *, const char *, char *); + /* * Functions implemented using PROC_ACTION(): * @@ -475,6 +477,7 @@ char args[sizeof(td->td_sa.args)]; struct ptrace_sc_ret psr; int ptevents; + char path[MAXPATHLEN]; } r; void *addr; int error = 0; @@ -519,6 +522,9 @@ case PT_VM_ENTRY: error = copyin(uap->addr, &r.pve, sizeof(r.pve)); break; + case PT_DUMPCORE: + error = copyin(uap->addr, &r.path, uap->data); + break; default: addr = uap->addr; break; @@ -562,6 +568,9 @@ error = copyout(&r.psr, uap->addr, MIN(uap->data, sizeof(r.psr))); break; + case PT_DUMPCORE: + error = copyout(&r.path, uap->addr, uap->data); + break; } return (error); @@ -1300,6 +1309,13 @@ PROC_LOCK(p); break; + case PT_DUMPCORE: + PROC_UNLOCK(p); + PROC_LOCK(td->td_proc); + error = coredump(td, addr, addr); + PROC_LOCK(p); + break; + default: #ifdef __HAVE_PTRACE_MACHDEP if (req >= PT_FIRSTMACH) { 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_DUMPCORE 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 */