Subject: Re: PT_MEMMAP
To: Love <lha@stacken.kth.se>
From: Gregory McGarry <g.mcgarry@ieee.org>
List: tech-kern
Date: 08/04/2002 14:57:50
Love wrote:
> Gregory McGarry <g.mcgarry@ieee.org> writes:
>
> > > : lha@nutcracker ; ./pmap 303
> > > start: 08048000 end: 0804c000 r-x rwx COW NC obj 0 1 0 /usr/bin/od
> > > start: 0804c000 end: 0804d000 rw- rwx COW NNC anon 0 1 0
> > > start: 0804d000 end: 0805f000 rwx rwx COW NNC anon 0 1 0
> [...]
> >
> > I like it!
> >
> > > http://www.e.kth.se/~lha/patches/netbsd/gdb-core/ptrace-patch2
> >
> > Check out ktrsyscall()/ktrwrite() for a clean way to do the uiomove
> > stuff.
>
> You mean by a header or something else ? I have to use two uiomove's since
> as far I know there there isn't a uiomove-version that takes two uio's as
> argument.
--- sys_process.c.orig Sun Aug 4 14:29:39 2002
+++ sys_process.c Sun Aug 4 14:50:22 2002
@@ -64,6 +64,7 @@
#include <sys/proc.h>
#include <sys/errno.h>
#include <sys/ptrace.h>
+#include <sys/malloc.h>
#include <sys/uio.h>
#include <sys/user.h>
@@ -71,9 +72,13 @@
#include <sys/syscallargs.h>
#include <uvm/uvm_extern.h>
+#include <uvm/uvm.h>
#include <machine/reg.h>
+int proc_vnode_to_path(struct vnode *, char *, int,
+ struct proc *, struct proc *);
+
/* Macros to clear/set/test flags. */
#define SET(t, f) (t) |= (f)
#define CLR(t, f) (t) &= ~(f)
@@ -174,6 +179,7 @@
case PT_IO:
case PT_KILL:
case PT_DETACH:
+ case PT_MEMMAP:
#ifdef PT_STEP
case PT_STEP:
#endif
@@ -436,6 +442,114 @@
return (process_dofpregs(p, t, &uio));
}
#endif
+
+ case PT_MEMMAP:
+ {
+ struct ptrace_mem_map_desc *desc;
+ struct vm_map *map = &t->p_vmspace->vm_map;
+ struct vm_map_entry *entry;
+ char *path;
+ int len;
+
+ desc = malloc(sizeof(*desc) + MAXPATHLEN * 4,
+ M_TEMP, M_WAITOK);
+ if (desc == NULL)
+ return ENOMEM;
+ path = (char *)(desc + sizeof(*desc));
+ *path = 0;
+
+ if (map == &curproc->p_vmspace->vm_map) {
+ free(path, M_TEMP);
+ return EDEADLK;
+ }
+
+ vm_map_lock_read(map);
+
+ iov.iov_base = SCARG(uap, addr);
+ iov.iov_len = SCARG(uap, data);
+ uio.uio_iovcnt = 1;
+ uio.uio_iov = &iov;
+ uio.uio_iovcnt = 1;
+ uio.uio_offset = 0;
+ uio.uio_resid = SCARG(uap, data);
+ uio.uio_segflg = UIO_USERSPACE;
+ uio.uio_rw = UIO_READ;
+ uio.uio_procp = p;
+
+ for (entry = map->header.next;
+ entry != &map->header;
+ entry = entry->next) {
+
+ memset(desc, 0, sizeof(*desc));
+
+ desc->pmmd_start = (void *)entry->start;
+ desc->pmmd_end = (void *)entry->end;
+
+ if (entry->protection & VM_PROT_READ)
+ desc->pmmd_flags |= PMMD_PROT_READ;
+ if (entry->protection & VM_PROT_WRITE)
+ desc->pmmd_flags |= PMMD_PROT_WRITE;
+ if (entry->protection & VM_PROT_EXECUTE)
+ desc->pmmd_flags |= PMMD_PROT_EXEC;
+
+ if (entry->max_protection & VM_PROT_READ)
+ desc->pmmd_flags |= PMMD_PROT_MAX_READ;
+ if (entry->max_protection & VM_PROT_WRITE)
+ desc->pmmd_flags |= PMMD_PROT_MAX_WRITE;
+ if (entry->max_protection & VM_PROT_EXECUTE)
+ desc->pmmd_flags |= PMMD_PROT_MAX_EXEC;
+
+ if (entry->etype & UVM_ET_COPYONWRITE)
+ desc->pmmd_flags |= PMMD_COW;
+ if (entry->etype & UVM_ET_NEEDSCOPY)
+ desc->pmmd_flags |= PMMD_NEEDCOPY;
+
+ desc->pmmd_wiredcount = entry->wired_count;
+ desc->pmmd_inheritance = entry->inheritance;
+ desc->pmmd_advice = entry->advice;
+
+ /* is this the last entry */
+ if (entry->next == &map->header)
+ desc->pmmd_flags |= PMMD_LAST_ENTRY;
+
+ if (UVM_ET_ISOBJ(entry) &&
+ UVM_OBJ_IS_VNODE(entry->object.uvm_obj)) {
+ struct vnode *vp;
+
+ vp = (struct vnode *)
+ entry->object.uvm_obj;
+
+ desc->pmmd_flags |= PMMD_OBJECT;
+ error = proc_vnode_to_path(vp, path,
+ MAXPATHLEN * 4, curproc, t);
+ if (error == 0) {
+ len = strlen(path);
+ memset(path + len, 0,
+ MIN(MAXPATHLEN * 4 - len,
+ ALIGNBYTES + 1));
+ len = ALIGN(len + 1);
+ } else {
+ len = ALIGN(1);
+ memset(path, 0, len);
+ }
+ } else
+ len = 0;
+
+ if (sizeof(*desc) + len > uio.uio_resid) {
+ error = ENOMEM;
+ break;
+ }
+
+ error = uiomove(desc,
+ sizeof(*desc) + len, &uio);
+ if (error)
+ break;
+ }
+ vm_map_unlock_read(map);
+ free(desc, M_TEMP);
+
+ return (error);
+ }
#ifdef __HAVE_PTRACE_MACHDEP
PTRACE_MACHDEP_REQUEST_CASES
> > I'm not sure whether the use of getcwd_common() isn't a horrible hack.
> > It doesn't seem like the right thing to do.
>
> I don't really feel responsible that proc_vnode_to_path() does to get the
> results. I think that getcwd_common() is somewhat missname (although I
> can't find another better name for it).
>
> Still, pmap wont be that useful info if NAMECACHE_ENTER_REVERSE isn't
> turned on. Should it be ? If it isn't I think that the interface should
> include the dev_t and inode number of the file and let the user find the
> info with find(1).
I guess there wasn't really a reason to have it enabled before now.
Nobody has complained violently to the suggestion.
-- Gregory McGarry <g.mcgarry@ieee.org>