o Add support for COMPAT_IA32.
o Incorporate review comments: - Properly reference and lock the map - Take into account that the VM map can change inbetween requests - Add the fileid and fsid attributes Credits: kib@ Reviewed by: kib@
This commit is contained in:
parent
f634c39527
commit
162110273c
@ -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 February 8, 2010
|
||||
.Dd February 11, 2010
|
||||
.Dt PTRACE 2
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -343,23 +343,30 @@ argument specifies a pointer to a
|
||||
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;
|
||||
int pve_entry;
|
||||
int pve_timestamp;
|
||||
u_long pve_start;
|
||||
u_long pve_end;
|
||||
u_long pve_offset;
|
||||
u_int pve_prot;
|
||||
u_int pve_pathlen;
|
||||
long pve_fileid;
|
||||
uint32_t pve_fsid;
|
||||
char *pve_path;
|
||||
};
|
||||
.Ed
|
||||
.Pp
|
||||
The first entry is returned by setting
|
||||
.Va pve_cookie
|
||||
to
|
||||
.Dv NULL .
|
||||
.Va pve_entry
|
||||
to zero.
|
||||
Subsequent entries are returned by leaving
|
||||
.Va pve_cookie
|
||||
.Va pve_entry
|
||||
unmodified from the value returned by previous requests.
|
||||
The
|
||||
.Va pve_timestamp
|
||||
field can be used to detect changes to the VM map while iterating over the
|
||||
entries.
|
||||
The tracing process can then take appropriate action, such as restarting.
|
||||
By setting
|
||||
.Va pve_pathlen
|
||||
to a non-zero value on entry, the pathname of the backing object is returned
|
||||
@ -434,7 +441,8 @@ was attempted on a process with no valid register set.
|
||||
.It
|
||||
.Dv PT_VM_ENTRY
|
||||
was given an invalid value for
|
||||
.Fa pve_cookie .
|
||||
.Fa pve_entry .
|
||||
This can also be caused by changes to the VM map of the process.
|
||||
.El
|
||||
.It Bq Er EBUSY
|
||||
.Bl -bullet -compact
|
||||
|
@ -75,12 +75,15 @@ struct ptrace_io_desc32 {
|
||||
};
|
||||
|
||||
struct ptrace_vm_entry32 {
|
||||
uint32_t pve_cookie;
|
||||
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;
|
||||
};
|
||||
|
||||
@ -360,89 +363,142 @@ proc_rwmem(struct proc *p, struct uio *uio)
|
||||
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, vfslocked;
|
||||
int error, index, vfslocked;
|
||||
|
||||
map = &p->p_vmspace->vm_map;
|
||||
entry = map->header.next;
|
||||
if (pve->pve_cookie != NULL) {
|
||||
while (entry != &map->header && entry != pve->pve_cookie)
|
||||
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;
|
||||
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);
|
||||
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_cookie = entry;
|
||||
pve->pve_start = entry->start;
|
||||
pve->pve_end = entry->end - 1;
|
||||
pve->pve_offset = entry->offset;
|
||||
pve->pve_prot = entry->protection;
|
||||
/* 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)
|
||||
return (0);
|
||||
/* Backing object's path needed? */
|
||||
if (pve->pve_pathlen == 0)
|
||||
break;
|
||||
|
||||
pathlen = pve->pve_pathlen;
|
||||
pve->pve_pathlen = 0;
|
||||
pathlen = pve->pve_pathlen;
|
||||
pve->pve_pathlen = 0;
|
||||
|
||||
obj = entry->object.vm_object;
|
||||
if (obj == NULL)
|
||||
return (0);
|
||||
obj = entry->object.vm_object;
|
||||
if (obj != NULL)
|
||||
VM_OBJECT_LOCK(obj);
|
||||
} while (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) {
|
||||
vm_map_unlock_read(map);
|
||||
vmspace_free(vm);
|
||||
|
||||
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);
|
||||
} else
|
||||
vp = NULL;
|
||||
|
||||
if (vp == NULL)
|
||||
return (0);
|
||||
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);
|
||||
|
||||
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 (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);
|
||||
}
|
||||
}
|
||||
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.
|
||||
*/
|
||||
@ -1087,14 +1143,12 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
|
||||
break;
|
||||
|
||||
case PT_VM_ENTRY:
|
||||
#ifdef COMPAT_IA32
|
||||
/* XXX to be implemented. */
|
||||
if (wrap32) {
|
||||
error = EDOOFUS;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
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;
|
||||
|
@ -104,13 +104,16 @@ struct ptrace_lwpinfo {
|
||||
|
||||
/* 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. */
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user