From owner-svn-src-all@FreeBSD.ORG Tue Feb 9 05:52:36 2010 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id EA783106566C; Tue, 9 Feb 2010 05:52:35 +0000 (UTC) (envelope-from marcel@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id D995B8FC18; Tue, 9 Feb 2010 05:52:35 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id o195qZLq074585; Tue, 9 Feb 2010 05:52:35 GMT (envelope-from marcel@svn.freebsd.org) Received: (from marcel@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id o195qZcD074581; Tue, 9 Feb 2010 05:52:35 GMT (envelope-from marcel@svn.freebsd.org) Message-Id: <201002090552.o195qZcD074581@svn.freebsd.org> From: Marcel Moolenaar Date: Tue, 9 Feb 2010 05:52:35 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r203696 - in head: lib/libc/sys sys/kern sys/sys X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 09 Feb 2010 05:52:36 -0000 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-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) \