Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 9 Feb 2010 05:52:35 +0000 (UTC)
From:      Marcel Moolenaar <marcel@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r203696 - in head: lib/libc/sys sys/kern sys/sys
Message-ID:  <201002090552.o195qZcD074581@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: marcel
Date: Tue Feb  9 05:52:35 2010
New Revision: 203696
URL: http://svn.freebsd.org/changeset/base/203696

Log:
  Add PT_VM_TIMESTAMP and PT_VM_ENTRY so that the tracing process can
  obtain the memory map of the traced process. PT_VM_TIMESTAMP can be
  used to check if the memory map changed since the last time to avoid
  iterating over all the VM entries unnecesarily.
  
  MFC after:	1 month

Modified:
  head/lib/libc/sys/ptrace.2
  head/sys/kern/sys_process.c
  head/sys/sys/ptrace.h

Modified: head/lib/libc/sys/ptrace.2
==============================================================================
--- head/lib/libc/sys/ptrace.2	Tue Feb  9 04:07:39 2010	(r203695)
+++ head/lib/libc/sys/ptrace.2	Tue Feb  9 05:52:35 2010	(r203696)
@@ -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 pr
 .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 require
 .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 ,

Modified: head/sys/kern/sys_process.c
==============================================================================
--- head/sys/kern/sys_process.c	Tue Feb  9 04:07:39 2010	(r203695)
+++ head/sys/kern/sys_process.c	Tue Feb  9 05:52:35 2010	(r203696)
@@ -346,6 +346,92 @@ proc_rwmem(struct proc *p, struct uio *u
 	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_
 	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_
 	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_
 		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, 
 		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) {

Modified: head/sys/sys/ptrace.h
==============================================================================
--- head/sys/sys/ptrace.h	Tue Feb  9 04:07:39 2010	(r203695)
+++ head/sys/sys/ptrace.h	Tue Feb  9 05:52:35 2010	(r203696)
@@ -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)				\



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201002090552.o195qZcD074581>