MFC revs 203696, 203708, 203783 and 203788:

Add PT_VM_TIMESTAMP and PT_VM_ENTRY so that the tracing process can
obtain the memory map of the traced process.

Requested by: kib@
This commit is contained in:
Marcel Moolenaar 2010-03-07 00:05:44 +00:00
parent d3fe3690fb
commit d5f57f7e08
2 changed files with 197 additions and 0 deletions

View file

@ -72,6 +72,20 @@ struct ptrace_io_desc32 {
u_int32_t piod_addr;
u_int32_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;
};
#endif
/*
@ -339,6 +353,148 @@ 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)
{
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, vfslocked;
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_LOCK(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_LOCK(tobj);
if (lobj != obj)
VM_OBJECT_UNLOCK(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_UNLOCK(lobj);
VM_OBJECT_UNLOCK(obj);
if (vp != NULL) {
freepath = NULL;
fullpath = NULL;
vn_fullpath(td, vp, &fullpath, &freepath);
vfslocked = VFS_LOCK_GIANT(vp->v_mount);
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);
VFS_UNLOCK_GIANT(vfslocked);
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_IA32
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);
}
#endif /* COMPAT_IA32 */
/*
* Process debugging system call.
*/
@ -382,6 +538,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;
@ -390,6 +547,7 @@ ptrace(struct thread *td, struct ptrace_args *uap)
struct fpreg32 fpreg32;
struct reg32 reg32;
struct ptrace_io_desc32 piod32;
struct ptrace_vm_entry32 pve32;
#endif
} r;
void *addr;
@ -422,6 +580,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;
@ -434,6 +595,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;
@ -970,6 +1134,21 @@ 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);
#ifdef COMPAT_IA32
if (wrap32)
error = ptrace_vm_entry32(td, p, addr);
else
#endif
error = ptrace_vm_entry(td, p, addr);
PROC_LOCK(p);
break;
default:
#ifdef __HAVE_PTRACE_MACHDEP
if (req >= PT_FIRSTMACH) {

View file

@ -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,20 @@ struct ptrace_lwpinfo {
sigset_t pl_siglist; /* LWP pending signal */
};
/* Argument structure for PT_VM_ENTRY. */
struct ptrace_vm_entry {
int pve_entry; /* Entry number used for iteration. */
int pve_timestamp; /* Generation number of VM map. */
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. */
long pve_fileid; /* File ID. */
uint32_t pve_fsid; /* File system ID. */
char *pve_path; /* Path name of object. */
};
#ifdef _KERNEL
#define PTRACESTOP_SC(p, td, flag) \