svn commit: r275800 - in head: lib/libc/sys sys/compat/freebsd32 sys/conf sys/kern sys/sys

Konstantin Belousov kib at FreeBSD.org
Mon Dec 15 12:01:45 UTC 2014


Author: kib
Date: Mon Dec 15 12:01:42 2014
New Revision: 275800
URL: https://svnweb.freebsd.org/changeset/base/275800

Log:
  Add a facility for non-init process to declare itself the reaper of
  the orphaned descendants.  Base of the API is modelled after the same
  feature from the DragonFlyBSD.
  
  Requested by:	bapt
  Reviewed by:	jilles (previous version)
  Tested by:	pho
  Sponsored by:	The FreeBSD Foundation
  MFC after:	3 weeks

Added:
  head/sys/kern/kern_procctl.c
     - copied, changed from r275798, head/sys/kern/sys_process.c
Modified:
  head/lib/libc/sys/procctl.2
  head/sys/compat/freebsd32/freebsd32.h
  head/sys/compat/freebsd32/freebsd32_misc.c
  head/sys/conf/files
  head/sys/kern/init_main.c
  head/sys/kern/kern_exit.c
  head/sys/kern/kern_fork.c
  head/sys/kern/sys_process.c
  head/sys/sys/proc.h
  head/sys/sys/procctl.h

Modified: head/lib/libc/sys/procctl.2
==============================================================================
--- head/lib/libc/sys/procctl.2	Mon Dec 15 11:57:39 2014	(r275799)
+++ head/lib/libc/sys/procctl.2	Mon Dec 15 12:01:42 2014	(r275800)
@@ -2,6 +2,10 @@
 .\" Written by: John H. Baldwin <jhb at FreeBSD.org>
 .\" All rights reserved.
 .\"
+.\" Copyright (c) 2014 The FreeBSD Foundation
+.\" Portions of this documentation were written by Konstantin Belousov
+.\" under sponsorship from the FreeBSD Foundation.
+.\"
 .\" Redistribution and use in source and binary forms, with or without
 .\" modification, are permitted provided that the following conditions
 .\" are met:
@@ -25,7 +29,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd September 19, 2013
+.Dd December 15, 2014
 .Dt PROCCTL 2
 .Os
 .Sh NAME
@@ -67,7 +71,7 @@ The control request to perform is specif
 .Fa cmd
 argument.
 The following commands are supported:
-.Bl -tag -width "Dv PROC_SPROTECT"
+.Bl -tag -width "Dv PROC_REAP_GETPIDS"
 .It Dv PROC_SPROTECT
 Set process protection state.
 This is used to mark a process as protected from being killed if the system
@@ -95,6 +99,174 @@ When used with
 mark all future child processes of each selected process as protected.
 Future child processes will also mark all of their future child processes.
 .El
+.It Dv PROC_REAP_ACQUIRE
+Acquires the reaper status for the current process.
+The status means that orphaned children by the reaper descendants,
+forked after the acquisition of the status, are reparented to the
+reaper.
+After the system initialization,
+.Xr init 8
+is the default reaper.
+.Pp
+.It Dv PROC_REAP_RELEASE
+Releases the reaper state fpr the current process.
+The reaper of the current process becomes the new reaper of the
+current process descendants.
+.It Dv PROC_REAP_STATUS
+Provides the information about the reaper of the specified process,
+or the process itself, in case it is a reaper.
+The
+.Fa data
+argument must point to the
+.Vt "struct procctl_reaper_status" ,
+which if filled by the syscall on successfull return.
+.Bd -literal
+struct procctl_reaper_status {
+	u_int	rs_flags;
+	u_int	rs_children;
+	u_int	rs_descendants;
+	pid_t	rs_reaper;
+	pid_t	rs_pid;
+};
+.Ed
+The
+.Fa rs_flags
+may have the following flags returned:
+.Bl -tag -width "Dv REAPER_STATUS_REALINIT"
+.It Dv REAPER_STATUS_OWNED
+The specified process has acquired the reaper status and did not
+released it.
+When the flag is returned, the
+.Fa id
+pid identifies reaper, otherwise the
+.Fa rs_reaper
+field of the structure is the pid of the reaper for passed process id.
+.It Dv REAPER_STATUS_REALINIT
+The specified process is the root of the reaper tree, i.e.
+.Xr init 8.
+.El
+The
+.Fa rs_children
+returns the number of the children of the reaper.
+The
+.Fa rs_descendants
+returns the total number of descendants of the reaper,
+not counting descendants of the reapers in the subtree.
+The
+.Fa rs_reaper
+returns the reaper pid.
+The
+.Fa rs_pid
+returns pid of some reaper child if there is any descendant.
+.It Dv PROC_REAP_GETPIDS
+Queries the list of descendants of the reaper of the specified process.
+The request takes the pointer to
+.Vt "struct procctl_reaper_pids"
+as
+.Fa data .
+.Bd -literal
+struct procctl_reaper_pids {
+	u_int	rp_count;
+	struct procctl_reaper_pidinfo *rp_pids;
+};
+.Ed
+On call, the
+.Fa rp_pids
+must point to the array of
+.Vt procctl_reaper_pidinfo
+structures, to be filled on return,
+and the
+.Fa rp_count
+must specify the size of the array,
+no more than rp_count elements is filled by kernel.
+.Pp
+The
+.Vt "struct procctl_reaper_pidinfo"
+structure provides some information about one reaper' descendant.
+Note that for the descendant which is not child, it is the subject
+of usual race with process exiting and pid reuse.
+.Bd -literal
+struct procctl_reaper_pidinfo {
+	pid_t	pi_pid;
+	pid_t	pi_subtree;
+	u_int	pi_flags;
+};
+.Ed
+The
+.Fa pi_pid
+is the process id of the descendant.
+The
+.Fa pi_subtree
+provides the pid of the child of the reaper, which is (grand-)parent
+of the process.
+The
+.Fa pi_flags
+returns the following flags, further describing the descendant:
+.Bl -tag -width "Dv REAPER_PIDINFO_VALID"
+.It Dv REAPER_PIDINFO_VALID
+Set for the
+.Vt procctl_reaper_pidinfo
+structure, which was filled by kernel.
+Zero-filling the
+.Fa rp_pids
+array and testing the flag allows the caller to detect the end
+of returned array.
+.It Dv REAPER_PIDINFO_CHILD
+The
+.Fa pi_pid
+is the direct child of the reaper.
+.El
+.It Dv PROC_REAP_KILL
+Request to deliver a signal to some subset of descendants of the reaper.
+The
+.Fa data
+must point to
+.Vt procctl_reaper_kill
+structure, which is used both for parameters and status return.
+.Bd -literal
+struct procctl_reaper_kill {
+	int	rk_sig;
+	u_int	rk_flags;
+	pid_t	rk_subtree;
+	u_int	rk_killed;
+	pid_t	rk_fpid;
+};
+.Ed
+The
+.Fa rk_sig
+specifies the signal to be delivered.
+Zero is not a valid signal number, unlike
+.Xr kill 2 .
+The
+.Fa rk_flags
+further directs the operation.
+It is or-ed from the following flags:
+.Bl -tag -width "Dv REAPER_KILL_CHILDREN"
+.It Dv REAPER_KILL_CHILDREN
+Deliver the specified signal only to direct children of the reaper.
+.It Dv REAPER_KILL_SUBTREE
+Deliver the specified signal only to descendants which were forked by
+the direct child with pid specified in
+.Fa rk_subtree .
+.El
+If no
+.Dv REAPER_KILL_CHILDREN
+and
+.Dv REAPER_KILL_SUBTREE
+flags are specified, all current descendants of the reaper are signalled.
+.Pp
+If signal was delivered to any process, the return value from the request
+is zero.
+In this case,
+.Fa rk_killed
+field is filled with the count of processes signalled.
+The
+.Fa rk_fpid
+field is set to the pid of the first process for which signal
+delivery failed, e.g. due to the permission problems.
+If no such process exist, the
+.Fa rk_fpid
+is set to -1.
 .El
 .Sh RETURN VALUES
 If an error occurs, a value of -1 is returned and
@@ -132,11 +304,48 @@ An invalid operation or flag was passed 
 for a
 .Dv PROC_SPROTECT
 command.
+.It Bq Er EPERM
+The
+.Fa idtype
+argument is not equal to
+.Dv P_PID ,
+or
+.Fa id
+is not equal to the pid of the calling process, for
+.Dv PROC_REAP_ACQUIRE
+or
+.Dv PROC_REAP_RELEASE
+requests.
+.It Bq Er EINVAL
+Invalid or undefined flags were passed to
+.Dv PROC_REAP_KILL
+request.
+.It Bq Er EINVAL
+Invalid or zero signal number was requested for
+.Dv PROC_REAP_KILL
+request.
+.It Bq Er EINVAL
+The
+.Dv PROC_REAP_RELEASE
+request was issued by the
+.Xr init 8
+process.
+.It Bq Er EBUSY
+The
+.Dv PROC_REAP_ACQUIRE
+request was issued by the process which already acquired reaper status
+and did not released it.
 .El
 .Sh SEE ALSO
-.Xr ptrace 2
+.Xr kill 2 ,
+.Xr ptrace 2 ,
+.Xr wait 2 ,
+.Xr init 8
 .Sh HISTORY
 The
 .Fn procctl
 function appeared in
 .Fx 10.0 .
+Reaper facility was created based on the similar feature of Linux and
+DragonflyBSD, and first appeared in
+.Fx 10.2 .

Modified: head/sys/compat/freebsd32/freebsd32.h
==============================================================================
--- head/sys/compat/freebsd32/freebsd32.h	Mon Dec 15 11:57:39 2014	(r275799)
+++ head/sys/compat/freebsd32/freebsd32.h	Mon Dec 15 12:01:42 2014	(r275800)
@@ -390,4 +390,10 @@ struct kld32_file_stat {
 	char	pathname[MAXPATHLEN];
 };
 
+struct procctl_reaper_pids32 {
+	u_int	rp_count;
+	u_int	rp_pad0[15];
+	uint32_t rp_pids;
+};
+
 #endif /* !_COMPAT_FREEBSD32_FREEBSD32_H_ */

Modified: head/sys/compat/freebsd32/freebsd32_misc.c
==============================================================================
--- head/sys/compat/freebsd32/freebsd32_misc.c	Mon Dec 15 11:57:39 2014	(r275799)
+++ head/sys/compat/freebsd32/freebsd32_misc.c	Mon Dec 15 12:01:42 2014	(r275800)
@@ -2957,20 +2957,63 @@ int
 freebsd32_procctl(struct thread *td, struct freebsd32_procctl_args *uap)
 {
 	void *data;
-	int error, flags;
+	union {
+		struct procctl_reaper_status rs;
+		struct procctl_reaper_pids rp;
+		struct procctl_reaper_kill rk;
+	} x;
+	union {
+		struct procctl_reaper_pids32 rp;
+	} x32;
+	int error, error1, flags;
 
 	switch (uap->com) {
 	case PROC_SPROTECT:
 		error = copyin(PTRIN(uap->data), &flags, sizeof(flags));
-		if (error)
+		if (error != 0)
 			return (error);
 		data = &flags;
 		break;
+	case PROC_REAP_ACQUIRE:
+	case PROC_REAP_RELEASE:
+		if (uap->data != NULL)
+			return (EINVAL);
+		data = NULL;
+		break;
+	case PROC_REAP_STATUS:
+		data = &x.rs;
+		break;
+	case PROC_REAP_GETPIDS:
+		error = copyin(uap->data, &x32.rp, sizeof(x32.rp));
+		if (error != 0)
+			return (error);
+		CP(x32.rp, x.rp, rp_count);
+		PTRIN_CP(x32.rp, x.rp, rp_pids);
+		data = &x.rp;
+		break;
+	case PROC_REAP_KILL:
+		error = copyin(uap->data, &x.rk, sizeof(x.rk));
+		if (error != 0)
+			return (error);
+		data = &x.rk;
+		break;
 	default:
 		return (EINVAL);
 	}
-	return (kern_procctl(td, uap->idtype, PAIR32TO64(id_t, uap->id),
-	    uap->com, data));
+	error = kern_procctl(td, uap->idtype, PAIR32TO64(id_t, uap->id),
+	    uap->com, data);
+	switch (uap->com) {
+	case PROC_REAP_STATUS:
+		if (error == 0)
+			error = copyout(&x.rs, uap->data, sizeof(x.rs));
+		break;
+	case PROC_REAP_KILL:
+		error1 = copyout(&x.rk, uap->data, sizeof(x.rk));
+		if (error == 0)
+			error = error1;
+		break;
+	}
+	return (error);
 }
 
 int

Modified: head/sys/conf/files
==============================================================================
--- head/sys/conf/files	Mon Dec 15 11:57:39 2014	(r275799)
+++ head/sys/conf/files	Mon Dec 15 12:01:42 2014	(r275800)
@@ -2987,6 +2987,7 @@ kern/kern_pmc.c			standard
 kern/kern_poll.c		optional device_polling
 kern/kern_priv.c		standard
 kern/kern_proc.c		standard
+kern/kern_procctl.c		standard
 kern/kern_prot.c		standard
 kern/kern_racct.c		standard
 kern/kern_rangelock.c		standard

Modified: head/sys/kern/init_main.c
==============================================================================
--- head/sys/kern/init_main.c	Mon Dec 15 11:57:39 2014	(r275799)
+++ head/sys/kern/init_main.c	Mon Dec 15 12:01:42 2014	(r275800)
@@ -496,7 +496,8 @@ proc0_init(void *dummy __unused)
 	prison0.pr_cpuset = cpuset_ref(td->td_cpuset);
 	p->p_peers = 0;
 	p->p_leader = p;
-
+	p->p_reaper = p;
+	LIST_INIT(&p->p_reaplist);
 
 	strncpy(p->p_comm, "kernel", sizeof (p->p_comm));
 	strncpy(td->td_name, "swapper", sizeof (td->td_name));
@@ -821,8 +822,11 @@ create_init(const void *udata __unused)
 	KASSERT(initproc->p_pid == 1, ("create_init: initproc->p_pid != 1"));
 	/* divorce init's credentials from the kernel's */
 	newcred = crget();
+	sx_xlock(&proctree_lock);
 	PROC_LOCK(initproc);
 	initproc->p_flag |= P_SYSTEM | P_INMEM;
+	initproc->p_treeflag |= P_TREE_REAPER;
+	LIST_INSERT_HEAD(&initproc->p_reaplist, &proc0, p_reapsibling);
 	oldcred = initproc->p_ucred;
 	crcopy(newcred, oldcred);
 #ifdef MAC
@@ -833,6 +837,7 @@ create_init(const void *udata __unused)
 #endif
 	initproc->p_ucred = newcred;
 	PROC_UNLOCK(initproc);
+	sx_xunlock(&proctree_lock);
 	crfree(oldcred);
 	cred_update_thread(FIRST_THREAD_IN_PROC(initproc));
 	cpu_set_fork_handler(FIRST_THREAD_IN_PROC(initproc), start_init, NULL);

Modified: head/sys/kern/kern_exit.c
==============================================================================
--- head/sys/kern/kern_exit.c	Mon Dec 15 11:57:39 2014	(r275799)
+++ head/sys/kern/kern_exit.c	Mon Dec 15 12:01:42 2014	(r275800)
@@ -123,6 +123,31 @@ proc_realparent(struct proc *child)
 	return (parent);
 }
 
+void
+reaper_abandon_children(struct proc *p, bool exiting)
+{
+	struct proc *p1, *p2, *ptmp;
+
+	sx_assert(&proctree_lock, SX_LOCKED);
+	KASSERT(p != initproc, ("reaper_abandon_children for initproc"));
+	if ((p->p_treeflag & P_TREE_REAPER) == 0)
+		return;
+	p1 = p->p_reaper;
+	LIST_FOREACH_SAFE(p2, &p->p_reaplist, p_reapsibling, ptmp) {
+		LIST_REMOVE(p2, p_reapsibling);
+		p2->p_reaper = p1;
+		p2->p_reapsubtree = p->p_reapsubtree;
+		LIST_INSERT_HEAD(&p1->p_reaplist, p2, p_reapsibling);
+		if (exiting && p2->p_pptr == p) {
+			PROC_LOCK(p2);
+			proc_reparent(p2, p1);
+			PROC_UNLOCK(p2);
+		}
+	}
+	KASSERT(LIST_EMPTY(&p->p_reaplist), ("p_reaplist not empty"));
+	p->p_treeflag &= ~P_TREE_REAPER;
+}
+
 static void
 clear_orphan(struct proc *p)
 {
@@ -458,14 +483,14 @@ exit1(struct thread *td, int rv)
 	sx_xlock(&proctree_lock);
 	q = LIST_FIRST(&p->p_children);
 	if (q != NULL)		/* only need this if any child is S_ZOMB */
-		wakeup(initproc);
+		wakeup(q->p_reaper);
 	for (; q != NULL; q = nq) {
 		nq = LIST_NEXT(q, p_sibling);
 		PROC_LOCK(q);
 		q->p_sigparent = SIGCHLD;
 
 		if (!(q->p_flag & P_TRACED)) {
-			proc_reparent(q, initproc);
+			proc_reparent(q, q->p_reaper);
 		} else {
 			/*
 			 * Traced processes are killed since their existence
@@ -473,7 +498,7 @@ exit1(struct thread *td, int rv)
 			 */
 			t = proc_realparent(q);
 			if (t == p) {
-				proc_reparent(q, initproc);
+				proc_reparent(q, q->p_reaper);
 			} else {
 				PROC_LOCK(t);
 				proc_reparent(q, t);
@@ -562,7 +587,7 @@ exit1(struct thread *td, int rv)
 			mtx_unlock(&p->p_pptr->p_sigacts->ps_mtx);
 			pp = p->p_pptr;
 			PROC_UNLOCK(pp);
-			proc_reparent(p, initproc);
+			proc_reparent(p, p->p_reaper);
 			p->p_sigparent = SIGCHLD;
 			PROC_LOCK(p->p_pptr);
 
@@ -575,8 +600,8 @@ exit1(struct thread *td, int rv)
 		} else
 			mtx_unlock(&p->p_pptr->p_sigacts->ps_mtx);
 
-		if (p->p_pptr == initproc)
-			kern_psignal(p->p_pptr, SIGCHLD);
+		if (p->p_pptr == p->p_reaper || p->p_pptr == initproc)
+			childproc_exited(p);
 		else if (p->p_sigparent != 0) {
 			if (p->p_sigparent == SIGCHLD)
 				childproc_exited(p);
@@ -849,6 +874,8 @@ proc_reap(struct thread *td, struct proc
 	LIST_REMOVE(p, p_list);	/* off zombproc */
 	sx_xunlock(&allproc_lock);
 	LIST_REMOVE(p, p_sibling);
+	reaper_abandon_children(p, true);
+	LIST_REMOVE(p, p_reapsibling);
 	PROC_LOCK(p);
 	clear_orphan(p);
 	PROC_UNLOCK(p);

Modified: head/sys/kern/kern_fork.c
==============================================================================
--- head/sys/kern/kern_fork.c	Mon Dec 15 11:57:39 2014	(r275799)
+++ head/sys/kern/kern_fork.c	Mon Dec 15 12:01:42 2014	(r275800)
@@ -261,11 +261,21 @@ retry:
 		 * Scan the active and zombie procs to check whether this pid
 		 * is in use.  Remember the lowest pid that's greater
 		 * than trypid, so we can avoid checking for a while.
+		 *
+		 * Avoid reuse of the process group id, session id or
+		 * the reaper subtree id.  Note that for process group
+		 * and sessions, the amount of reserved pids is
+		 * limited by process limit.  For the subtree ids, the
+		 * id is kept reserved only while there is a
+		 * non-reaped process in the subtree, so amount of
+		 * reserved pids is limited by process limit times
+		 * two.
 		 */
 		p = LIST_FIRST(&allproc);
 again:
 		for (; p != NULL; p = LIST_NEXT(p, p_list)) {
 			while (p->p_pid == trypid ||
+			    p->p_reapsubtree == trypid ||
 			    (p->p_pgrp != NULL &&
 			    (p->p_pgrp->pg_id == trypid ||
 			    (p->p_session != NULL &&
@@ -611,12 +621,20 @@ do_fork(struct thread *td, int flags, st
 	 * of init.  This effectively disassociates the child from the
 	 * parent.
 	 */
-	if (flags & RFNOWAIT)
-		pptr = initproc;
-	else
+	if ((flags & RFNOWAIT) != 0) {
+		pptr = p1->p_reaper;
+		p2->p_reaper = pptr;
+	} else {
+		p2->p_reaper = (p1->p_treeflag & P_TREE_REAPER) != 0 ?
+		    p1 : p1->p_reaper;
 		pptr = p1;
+	}
 	p2->p_pptr = pptr;
 	LIST_INSERT_HEAD(&pptr->p_children, p2, p_sibling);
+	LIST_INIT(&p2->p_reaplist);
+	LIST_INSERT_HEAD(&p2->p_reaper->p_reaplist, p2, p_reapsibling);
+	if (p2->p_reaper == p1)
+		p2->p_reapsubtree = p2->p_pid;
 	sx_xunlock(&proctree_lock);
 
 	/* Inform accounting that we have forked. */

Copied and modified: head/sys/kern/kern_procctl.c (from r275798, head/sys/kern/sys_process.c)
==============================================================================
--- head/sys/kern/sys_process.c	Mon Dec 15 11:05:53 2014	(r275798, copy source)
+++ head/sys/kern/kern_procctl.c	Mon Dec 15 12:01:42 2014	(r275800)
@@ -1,6 +1,9 @@
 /*-
- * Copyright (c) 1994, Sean Eric Fagan
- * All rights reserved.
+ * Copyright (c) 2014 John Baldwin
+ * Copyright (c) 2014 The FreeBSD Foundation
+ *
+ * Portions of this software were developed by Konstantin Belousov
+ * under sponsorship from the FreeBSD Foundation.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -10,11 +13,6 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *	This product includes software developed by Sean Eric Fagan.
- * 4. The name of the author may not be used to endorse or promote products
- *    derived from this software without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -32,1208 +30,18 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
-#include "opt_compat.h"
-
 #include <sys/param.h>
 #include <sys/systm.h>
+#include <sys/capsicum.h>
 #include <sys/lock.h>
 #include <sys/mutex.h>
-#include <sys/syscallsubr.h>
-#include <sys/sysent.h>
-#include <sys/sysproto.h>
 #include <sys/priv.h>
 #include <sys/proc.h>
 #include <sys/procctl.h>
-#include <sys/vnode.h>
-#include <sys/ptrace.h>
-#include <sys/rwlock.h>
 #include <sys/sx.h>
-#include <sys/malloc.h>
-#include <sys/signalvar.h>
-
-#include <machine/reg.h>
-
-#include <security/audit/audit.h>
-
-#include <vm/vm.h>
-#include <vm/pmap.h>
-#include <vm/vm_extern.h>
-#include <vm/vm_map.h>
-#include <vm/vm_kern.h>
-#include <vm/vm_object.h>
-#include <vm/vm_page.h>
-#include <vm/vm_param.h>
-
-#ifdef COMPAT_FREEBSD32
-#include <sys/procfs.h>
-#include <compat/freebsd32/freebsd32_signal.h>
-
-struct ptrace_io_desc32 {
-	int		piod_op;
-	uint32_t	piod_offs;
-	uint32_t	piod_addr;
-	uint32_t	piod_len;
-};
-
-struct ptrace_vm_entry32 {
-	int		pve_entry;
-	int		pve_timestamp;
-	uint32_t	pve_start;
-	uint32_t	pve_end;
-	uint32_t	pve_offset;
-	u_int		pve_prot;
-	u_int		pve_pathlen;
-	int32_t		pve_fileid;
-	u_int		pve_fsid;
-	uint32_t	pve_path;
-};
-
-struct ptrace_lwpinfo32 {
-	lwpid_t	pl_lwpid;	/* LWP described. */
-	int	pl_event;	/* Event that stopped the LWP. */
-	int	pl_flags;	/* LWP flags. */
-	sigset_t	pl_sigmask;	/* LWP signal mask */
-	sigset_t	pl_siglist;	/* LWP pending signal */
-	struct siginfo32 pl_siginfo;	/* siginfo for signal */
-	char	pl_tdname[MAXCOMLEN + 1];	/* LWP name. */
-	int	pl_child_pid;		/* New child pid */
-};
-
-#endif
-
-/*
- * Functions implemented using PROC_ACTION():
- *
- * proc_read_regs(proc, regs)
- *	Get the current user-visible register set from the process
- *	and copy it into the regs structure (<machine/reg.h>).
- *	The process is stopped at the time read_regs is called.
- *
- * proc_write_regs(proc, regs)
- *	Update the current register set from the passed in regs
- *	structure.  Take care to avoid clobbering special CPU
- *	registers or privileged bits in the PSL.
- *	Depending on the architecture this may have fix-up work to do,
- *	especially if the IAR or PCW are modified.
- *	The process is stopped at the time write_regs is called.
- *
- * proc_read_fpregs, proc_write_fpregs
- *	deal with the floating point register set, otherwise as above.
- *
- * proc_read_dbregs, proc_write_dbregs
- *	deal with the processor debug register set, otherwise as above.
- *
- * proc_sstep(proc)
- *	Arrange for the process to trap after executing a single instruction.
- */
-
-#define	PROC_ACTION(action) do {					\
-	int error;							\
-									\
-	PROC_LOCK_ASSERT(td->td_proc, MA_OWNED);			\
-	if ((td->td_proc->p_flag & P_INMEM) == 0)			\
-		error = EIO;						\
-	else								\
-		error = (action);					\
-	return (error);							\
-} while(0)
-
-int
-proc_read_regs(struct thread *td, struct reg *regs)
-{
-
-	PROC_ACTION(fill_regs(td, regs));
-}
-
-int
-proc_write_regs(struct thread *td, struct reg *regs)
-{
-
-	PROC_ACTION(set_regs(td, regs));
-}
-
-int
-proc_read_dbregs(struct thread *td, struct dbreg *dbregs)
-{
-
-	PROC_ACTION(fill_dbregs(td, dbregs));
-}
-
-int
-proc_write_dbregs(struct thread *td, struct dbreg *dbregs)
-{
-
-	PROC_ACTION(set_dbregs(td, dbregs));
-}
-
-/*
- * Ptrace doesn't support fpregs at all, and there are no security holes
- * or translations for fpregs, so we can just copy them.
- */
-int
-proc_read_fpregs(struct thread *td, struct fpreg *fpregs)
-{
-
-	PROC_ACTION(fill_fpregs(td, fpregs));
-}
-
-int
-proc_write_fpregs(struct thread *td, struct fpreg *fpregs)
-{
-
-	PROC_ACTION(set_fpregs(td, fpregs));
-}
-
-#ifdef COMPAT_FREEBSD32
-/* For 32 bit binaries, we need to expose the 32 bit regs layouts. */
-int
-proc_read_regs32(struct thread *td, struct reg32 *regs32)
-{
-
-	PROC_ACTION(fill_regs32(td, regs32));
-}
-
-int
-proc_write_regs32(struct thread *td, struct reg32 *regs32)
-{
-
-	PROC_ACTION(set_regs32(td, regs32));
-}
-
-int
-proc_read_dbregs32(struct thread *td, struct dbreg32 *dbregs32)
-{
-
-	PROC_ACTION(fill_dbregs32(td, dbregs32));
-}
-
-int
-proc_write_dbregs32(struct thread *td, struct dbreg32 *dbregs32)
-{
-
-	PROC_ACTION(set_dbregs32(td, dbregs32));
-}
-
-int
-proc_read_fpregs32(struct thread *td, struct fpreg32 *fpregs32)
-{
-
-	PROC_ACTION(fill_fpregs32(td, fpregs32));
-}
-
-int
-proc_write_fpregs32(struct thread *td, struct fpreg32 *fpregs32)
-{
-
-	PROC_ACTION(set_fpregs32(td, fpregs32));
-}
-#endif
-
-int
-proc_sstep(struct thread *td)
-{
-
-	PROC_ACTION(ptrace_single_step(td));
-}
-
-int
-proc_rwmem(struct proc *p, struct uio *uio)
-{
-	vm_map_t map;
-	vm_offset_t pageno;		/* page number */
-	vm_prot_t reqprot;
-	int error, fault_flags, page_offset, writing;
-
-	/*
-	 * Assert that someone has locked this vmspace.  (Should be
-	 * curthread but we can't assert that.)  This keeps the process
-	 * from exiting out from under us until this operation completes.
-	 */
-	KASSERT(p->p_lock >= 1, ("%s: process %p (pid %d) not held", __func__,
-	    p, p->p_pid));
-
-	/*
-	 * The map we want...
-	 */
-	map = &p->p_vmspace->vm_map;
-
-	/*
-	 * If we are writing, then we request vm_fault() to create a private
-	 * copy of each page.  Since these copies will not be writeable by the
-	 * process, we must explicity request that they be dirtied.
-	 */
-	writing = uio->uio_rw == UIO_WRITE;
-	reqprot = writing ? VM_PROT_COPY | VM_PROT_READ : VM_PROT_READ;
-	fault_flags = writing ? VM_FAULT_DIRTY : VM_FAULT_NORMAL;
-
-	/*
-	 * Only map in one page at a time.  We don't have to, but it
-	 * makes things easier.  This way is trivial - right?
-	 */
-	do {
-		vm_offset_t uva;
-		u_int len;
-		vm_page_t m;
-
-		uva = (vm_offset_t)uio->uio_offset;
-
-		/*
-		 * Get the page number of this segment.
-		 */
-		pageno = trunc_page(uva);
-		page_offset = uva - pageno;
-
-		/*
-		 * How many bytes to copy
-		 */
-		len = min(PAGE_SIZE - page_offset, uio->uio_resid);
-
-		/*
-		 * Fault and hold the page on behalf of the process.
-		 */
-		error = vm_fault_hold(map, pageno, reqprot, fault_flags, &m);
-		if (error != KERN_SUCCESS) {
-			if (error == KERN_RESOURCE_SHORTAGE)
-				error = ENOMEM;
-			else
-				error = EFAULT;
-			break;
-		}
-
-		/*
-		 * Now do the i/o move.
-		 */
-		error = uiomove_fromphys(&m, page_offset, len, uio);
-
-		/* Make the I-cache coherent for breakpoints. */
-		if (writing && error == 0) {
-			vm_map_lock_read(map);
-			if (vm_map_check_protection(map, pageno, pageno +
-			    PAGE_SIZE, VM_PROT_EXECUTE))
-				vm_sync_icache(map, uva, len);
-			vm_map_unlock_read(map);
-		}
-
-		/*
-		 * Release the page.
-		 */
-		vm_page_lock(m);
-		vm_page_unhold(m);
-		vm_page_unlock(m);
-
-	} while (error == 0 && uio->uio_resid > 0);
-
-	return (error);
-}
-
-static int
-ptrace_vm_entry(struct thread *td, struct proc *p, struct ptrace_vm_entry *pve)
-{
-	struct vattr vattr;
-	vm_map_t map;
-	vm_map_entry_t entry;
-	vm_object_t obj, tobj, lobj;
-	struct vmspace *vm;
-	struct vnode *vp;
-	char *freepath, *fullpath;
-	u_int pathlen;
-	int error, index;
-
-	error = 0;
-	obj = NULL;
-
-	vm = vmspace_acquire_ref(p);
-	map = &vm->vm_map;
-	vm_map_lock_read(map);
-
-	do {
-		entry = map->header.next;
-		index = 0;
-		while (index < pve->pve_entry && entry != &map->header) {
-			entry = entry->next;
-			index++;
-		}
-		if (index != pve->pve_entry) {
-			error = EINVAL;
-			break;
-		}
-		while (entry != &map->header &&
-		    (entry->eflags & MAP_ENTRY_IS_SUB_MAP) != 0) {
-			entry = entry->next;
-			index++;
-		}
-		if (entry == &map->header) {
-			error = ENOENT;
-			break;
-		}
-
-		/* We got an entry. */
-		pve->pve_entry = index + 1;
-		pve->pve_timestamp = map->timestamp;
-		pve->pve_start = entry->start;
-		pve->pve_end = entry->end - 1;
-		pve->pve_offset = entry->offset;
-		pve->pve_prot = entry->protection;
-
-		/* Backing object's path needed? */
-		if (pve->pve_pathlen == 0)
-			break;
-
-		pathlen = pve->pve_pathlen;
-		pve->pve_pathlen = 0;
-
-		obj = entry->object.vm_object;
-		if (obj != NULL)
-			VM_OBJECT_RLOCK(obj);
-	} while (0);
-
-	vm_map_unlock_read(map);
-	vmspace_free(vm);
-
-	pve->pve_fsid = VNOVAL;
-	pve->pve_fileid = VNOVAL;
-
-	if (error == 0 && obj != NULL) {
-		lobj = obj;
-		for (tobj = obj; tobj != NULL; tobj = tobj->backing_object) {
-			if (tobj != obj)
-				VM_OBJECT_RLOCK(tobj);
-			if (lobj != obj)
-				VM_OBJECT_RUNLOCK(lobj);
-			lobj = tobj;
-			pve->pve_offset += tobj->backing_object_offset;
-		}
-		vp = (lobj->type == OBJT_VNODE) ? lobj->handle : NULL;
-		if (vp != NULL)
-			vref(vp);
-		if (lobj != obj)
-			VM_OBJECT_RUNLOCK(lobj);
-		VM_OBJECT_RUNLOCK(obj);
-
-		if (vp != NULL) {
-			freepath = NULL;
-			fullpath = NULL;
-			vn_fullpath(td, vp, &fullpath, &freepath);
-			vn_lock(vp, LK_SHARED | LK_RETRY);
-			if (VOP_GETATTR(vp, &vattr, td->td_ucred) == 0) {
-				pve->pve_fileid = vattr.va_fileid;
-				pve->pve_fsid = vattr.va_fsid;
-			}
-			vput(vp);
-
-			if (fullpath != NULL) {
-				pve->pve_pathlen = strlen(fullpath) + 1;
-				if (pve->pve_pathlen <= pathlen) {
-					error = copyout(fullpath, pve->pve_path,
-					    pve->pve_pathlen);
-				} else
-					error = ENAMETOOLONG;
-			}
-			if (freepath != NULL)
-				free(freepath, M_TEMP);
-		}
-	}
-
-	return (error);
-}
-
-#ifdef COMPAT_FREEBSD32
-static int      
-ptrace_vm_entry32(struct thread *td, struct proc *p,
-    struct ptrace_vm_entry32 *pve32)
-{
-	struct ptrace_vm_entry pve;
-	int error;
-
-	pve.pve_entry = pve32->pve_entry;
-	pve.pve_pathlen = pve32->pve_pathlen;
-	pve.pve_path = (void *)(uintptr_t)pve32->pve_path;
-
-	error = ptrace_vm_entry(td, p, &pve);
-	if (error == 0) {
-		pve32->pve_entry = pve.pve_entry;
-		pve32->pve_timestamp = pve.pve_timestamp;
-		pve32->pve_start = pve.pve_start;
-		pve32->pve_end = pve.pve_end;
-		pve32->pve_offset = pve.pve_offset;
-		pve32->pve_prot = pve.pve_prot;
-		pve32->pve_fileid = pve.pve_fileid;
-		pve32->pve_fsid = pve.pve_fsid;
-	}
-
-	pve32->pve_pathlen = pve.pve_pathlen;
-	return (error);
-}
-
-static void
-ptrace_lwpinfo_to32(const struct ptrace_lwpinfo *pl,
-    struct ptrace_lwpinfo32 *pl32)
-{
-
-	pl32->pl_lwpid = pl->pl_lwpid;
-	pl32->pl_event = pl->pl_event;
-	pl32->pl_flags = pl->pl_flags;
-	pl32->pl_sigmask = pl->pl_sigmask;
-	pl32->pl_siglist = pl->pl_siglist;
-	siginfo_to_siginfo32(&pl->pl_siginfo, &pl32->pl_siginfo);
-	strcpy(pl32->pl_tdname, pl->pl_tdname);
-	pl32->pl_child_pid = pl->pl_child_pid;
-}
-#endif /* COMPAT_FREEBSD32 */
-
-/*
- * Process debugging system call.

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-all mailing list