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 <j...@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 ***
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to