summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/libc/sys/ptrace.277
-rw-r--r--sys/kern/sys_process.c103
-rw-r--r--sys/sys/ptrace.h15
3 files changed, 194 insertions, 1 deletions
diff --git a/lib/libc/sys/ptrace.2 b/lib/libc/sys/ptrace.2
index 9d8f550..ab51ee3 100644
--- a/lib/libc/sys/ptrace.2
+++ b/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 March 27, 2009
+.Dd February 8, 2010
.Dt PTRACE 2
.Os
.Sh NAME
@@ -327,6 +327,61 @@ This request will trace the specified process on each system call exit.
.It PT_SYSCALL
This request will trace the specified process
on each system call entry and exit.
+.It PT_VM_TIMESTAMP
+This request returns the generation number or timestamp of the memory map of
+the traced process as the return value from
+.Fn ptrace .
+This provides a low-cost way for the tracing process to determine if the
+VM map changed since the last time this request was made.
+.It PT_VM_ENTRY
+This request is used to iterate over the entries of the VM map of the traced
+process.
+The
+.Fa addr
+argument specifies a pointer to a
+.Vt "struct ptrace_vm_entry" ,
+which is defined as follows:
+.Bd -literal
+struct ptrace_vm_entry {
+ void *pve_cookie;
+ u_long pve_start;
+ u_long pve_end;
+ u_long pve_offset;
+ u_int pve_prot;
+ u_int pve_pathlen;
+ char *pve_path;
+};
+.Ed
+.Pp
+The first entry is returned by setting
+.Va pve_cookie
+to
+.Dv NULL .
+Subsequent entries are returned by leaving
+.Va pve_cookie
+unmodified from the value returned by previous requests.
+By setting
+.Va pve_pathlen
+to a non-zero value on entry, the pathname of the backing object is returned
+in the buffer pointed to by
+.Va pve_path ,
+provided the entry is backed by a vnode.
+The
+.Va pve_pathlen
+field is updated with the actual length of the pathname (including the
+terminating null character).
+The
+.Va pve_offset
+field is the offset within the backing object at which the range starts.
+The range is located in the VM space at
+.Va pve_start
+and extends up to
+.Va pve_end
+(inclusive).
+.Pp
+The
+.Fa data
+argument is ignored.
.El
.Pp
Additionally, machine-specific requests can exist.
@@ -376,6 +431,10 @@ or
.Dv PT_SETDBREGS
was attempted on a process with no valid register set.
(This is normally true only of system processes.)
+.It
+.Dv PT_VM_ENTRY
+was given an invalid value for
+.Fa pve_cookie .
.El
.It Bq Er EBUSY
.Bl -bullet -compact
@@ -405,6 +464,22 @@ on a process in violation of the requirements listed under
.Dv PT_ATTACH
above.
.El
+.It Bq Er ENOENT
+.Bl -bullet -compact
+.It
+.Dv PT_VM_ENTRY
+previously returned the last entry of the memory map.
+No more entries exist.
+.El
+.It Bq Er ENAMETOOLONG
+.Bl -bullet -compact
+.It
+.Dv PT_VM_ENTRY
+cannot return the pathname of the backing object because the buffer is not big
+enough.
+.Fa pve_pathlen
+holds the minimum buffer size required on return.
+.El
.El
.Sh SEE ALSO
.Xr execve 2 ,
diff --git a/sys/kern/sys_process.c b/sys/kern/sys_process.c
index 3c6394c..77734a4 100644
--- a/sys/kern/sys_process.c
+++ b/sys/kern/sys_process.c
@@ -346,6 +346,92 @@ proc_rwmem(struct proc *p, struct uio *uio)
return (error);
}
+static int
+ptrace_vm_entry(struct thread *td, struct proc *p, struct ptrace_vm_entry *pve)
+{
+ vm_map_t map;
+ vm_map_entry_t entry;
+ vm_object_t obj, tobj, lobj;
+ struct vnode *vp;
+ char *freepath, *fullpath;
+ u_int pathlen;
+ int error, vfslocked;
+
+ map = &p->p_vmspace->vm_map;
+ entry = map->header.next;
+ if (pve->pve_cookie != NULL) {
+ while (entry != &map->header && entry != pve->pve_cookie)
+ entry = entry->next;
+ if (entry != pve->pve_cookie)
+ return (EINVAL);
+ entry = entry->next;
+ }
+ while (entry != &map->header && (entry->eflags & MAP_ENTRY_IS_SUB_MAP))
+ entry = entry->next;
+ if (entry == &map->header)
+ return (ENOENT);
+
+ /* We got an entry. */
+ pve->pve_cookie = entry;
+ 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)
+ return (0);
+
+ pathlen = pve->pve_pathlen;
+ pve->pve_pathlen = 0;
+
+ obj = entry->object.vm_object;
+ if (obj == NULL)
+ return (0);
+
+ VM_OBJECT_LOCK(obj);
+ for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) {
+ if (tobj != obj)
+ VM_OBJECT_LOCK(tobj);
+ if (lobj != obj)
+ VM_OBJECT_UNLOCK(lobj);
+ lobj = tobj;
+ pve->pve_offset += tobj->backing_object_offset;
+ }
+ if (lobj != NULL) {
+ vp = (lobj->type == OBJT_VNODE) ? lobj->handle : NULL;
+ if (vp != NULL)
+ vref(vp);
+ if (lobj != obj)
+ VM_OBJECT_UNLOCK(lobj);
+ VM_OBJECT_UNLOCK(obj);
+ } else
+ vp = NULL;
+
+ if (vp == NULL)
+ return (0);
+
+ freepath = NULL;
+ fullpath = NULL;
+ vn_fullpath(td, vp, &fullpath, &freepath);
+ vfslocked = VFS_LOCK_GIANT(vp->v_mount);
+ vrele(vp);
+ VFS_UNLOCK_GIANT(vfslocked);
+
+ error = 0;
+ 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);
+}
+
/*
* Process debugging system call.
*/
@@ -389,6 +475,7 @@ ptrace(struct thread *td, struct ptrace_args *uap)
union {
struct ptrace_io_desc piod;
struct ptrace_lwpinfo pl;
+ struct ptrace_vm_entry pve;
struct dbreg dbreg;
struct fpreg fpreg;
struct reg reg;
@@ -429,6 +516,9 @@ ptrace(struct thread *td, struct ptrace_args *uap)
case PT_IO:
error = COPYIN(uap->addr, &r.piod, sizeof r.piod);
break;
+ case PT_VM_ENTRY:
+ error = COPYIN(uap->addr, &r.pve, sizeof r.pve);
+ break;
default:
addr = uap->addr;
break;
@@ -441,6 +531,9 @@ ptrace(struct thread *td, struct ptrace_args *uap)
return (error);
switch (uap->req) {
+ case PT_VM_ENTRY:
+ error = COPYOUT(&r.pve, uap->addr, sizeof r.pve);
+ break;
case PT_IO:
error = COPYOUT(&r.piod, uap->addr, sizeof r.piod);
break;
@@ -977,6 +1070,16 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
PROC_LOCK(p);
break;
+ case PT_VM_TIMESTAMP:
+ td->td_retval[0] = p->p_vmspace->vm_map.timestamp;
+ break;
+
+ case PT_VM_ENTRY:
+ PROC_UNLOCK(p);
+ error = ptrace_vm_entry(td, p, addr);
+ PROC_LOCK(p);
+ break;
+
default:
#ifdef __HAVE_PTRACE_MACHDEP
if (req >= PT_FIRSTMACH) {
diff --git a/sys/sys/ptrace.h b/sys/sys/ptrace.h
index 8fd52cb..0d35cac 100644
--- a/sys/sys/ptrace.h
+++ b/sys/sys/ptrace.h
@@ -67,6 +67,10 @@
#define PT_SETFPREGS 36 /* set floating-point registers */
#define PT_GETDBREGS 37 /* get debugging registers */
#define PT_SETDBREGS 38 /* set debugging registers */
+
+#define PT_VM_TIMESTAMP 40 /* Get VM version (timestamp) */
+#define PT_VM_ENTRY 41 /* Get VM map (entry) */
+
#define PT_FIRSTMACH 64 /* for machine-specific requests */
#include <machine/ptrace.h> /* machine-specific requests, if any */
@@ -98,6 +102,17 @@ struct ptrace_lwpinfo {
sigset_t pl_siglist; /* LWP pending signal */
};
+/* Argument structure for PT_VM_ENTRY. */
+struct ptrace_vm_entry {
+ void *pve_cookie; /* Token used to iterate. */
+ u_long pve_start; /* Start VA of range. */
+ u_long pve_end; /* End VA of range (incl). */
+ u_long pve_offset; /* Offset in backing object. */
+ u_int pve_prot; /* Protection of memory range. */
+ u_int pve_pathlen; /* Size of path. */
+ char *pve_path; /* Path name of object. */
+};
+
#ifdef _KERNEL
#define PTRACESTOP_SC(p, td, flag) \
OpenPOWER on IntegriCloud