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>