summaryrefslogtreecommitdiff
path: root/procfs
diff options
context:
space:
mode:
authorJustus Winter <4winter@informatik.uni-hamburg.de>2014-09-18 18:38:04 +0200
committerJustus Winter <4winter@informatik.uni-hamburg.de>2014-09-29 12:38:36 +0200
commite9b7aa85c98750b6c8f54f3eb0013c359841f4d4 (patch)
treee14be692493efd0f6387188bf61f0d6bad10a135 /procfs
parentdb9ad21d272a4dce53c35095b97ca0a597b45004 (diff)
procfs: implement /proc/N/maps
Fixes https://savannah.gnu.org/bugs/?32770 . * procfs/process.c (process_file_gc_maps): New function. (entries): Use the new function to implement /proc/N/maps.
Diffstat (limited to 'procfs')
-rw-r--r--procfs/process.c104
1 files changed, 103 insertions, 1 deletions
diff --git a/procfs/process.c b/procfs/process.c
index 48541484..a9b1a597 100644
--- a/procfs/process.c
+++ b/procfs/process.c
@@ -1,5 +1,5 @@
/* Hurd /proc filesystem, implementation of process directories.
- Copyright (C) 2010 Free Software Foundation, Inc.
+ Copyright (C) 2010,14 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -109,6 +109,100 @@ process_file_gc_environ (struct proc_stat *ps, char **contents)
}
static ssize_t
+process_file_gc_maps (struct proc_stat *ps, char **contents)
+{
+ error_t err;
+ FILE *s;
+ size_t contents_len;
+ vm_offset_t addr = 0;
+ vm_size_t size;
+ vm_prot_t prot, max_prot;
+ mach_port_t obj;
+ vm_offset_t offs;
+ vm_inherit_t inh;
+ int shared;
+
+ /* Unfortunately we cannot resolve memory objects to their backing
+ file (yet), so we use the port name as identifier. To avoid the
+ same name from being used again and again, we defer the
+ deallocation until the end of the function. We use a simple
+ linked list for this purpose. */
+ struct mem_obj
+ {
+ mach_port_t port;
+ struct mem_obj *next;
+ };
+ struct mem_obj *objects = NULL;
+
+ s = open_memstream (contents, &contents_len);
+ if (s == NULL)
+ {
+ *contents = NULL;
+ return 0;
+ }
+
+ while (1)
+ {
+ err =
+ vm_region (ps->task, &addr, &size, &prot, &max_prot, &inh,
+ &shared, &obj, &offs);
+ if (err)
+ break;
+
+ fprintf (s, "%0*x-%0*x %c%c%c%c %0*x %s %d ",
+ /* Address range. */
+ 2*sizeof s, addr,
+ 2*sizeof s, addr + size,
+ /* Permissions. */
+ prot & VM_PROT_READ? 'r': '-',
+ prot & VM_PROT_WRITE? 'w': '-',
+ prot & VM_PROT_EXECUTE? 'x': '-',
+ shared? 's': 'p',
+ /* Offset. */
+ 2*sizeof s, offs,
+ /* Device. */
+ "00:00",
+ /* Inode. */
+ 0);
+
+ /* Pathname. */
+ if (MACH_PORT_VALID (obj))
+ {
+ struct mem_obj *o = malloc (sizeof *o);
+ if (o)
+ {
+ o->port = obj;
+ o->next = objects;
+ objects = o;
+ }
+ else
+ mach_port_deallocate (mach_task_self (), obj);
+
+ fprintf (s, "[mem_obj=%d]\n", obj);
+ }
+ else
+ fprintf (s, "\n");
+
+ addr += size;
+ }
+
+ while (objects)
+ {
+ struct mem_obj *o = objects;
+ mach_port_deallocate (mach_task_self (), o->port);
+ objects = o->next;
+ free (o);
+ }
+
+ /* This is a bit awkward, fortunately vm_region should not fail. */
+ if (err != KERN_NO_SPACE)
+ fprintf (s, "%s\n", strerror (err));
+
+ fclose (s);
+ return contents_len;
+}
+
+static ssize_t
process_file_gc_stat (struct proc_stat *ps, char **contents)
{
struct procinfo *pi = proc_stat_proc_info (ps);
@@ -348,6 +442,14 @@ static struct procfs_dir_entry entries[] = {
},
},
{
+ .name = "maps",
+ .hook = & (struct process_file_desc) {
+ .get_contents = process_file_gc_maps,
+ .needs = PSTAT_TASK,
+ .mode = 0400,
+ },
+ },
+ {
.name = "stat",
.hook = & (struct process_file_desc) {
.get_contents = process_file_gc_stat,