diff options
author | Justus Winter <4winter@informatik.uni-hamburg.de> | 2014-09-18 18:38:04 +0200 |
---|---|---|
committer | Justus Winter <4winter@informatik.uni-hamburg.de> | 2014-09-29 12:38:36 +0200 |
commit | e9b7aa85c98750b6c8f54f3eb0013c359841f4d4 (patch) | |
tree | e14be692493efd0f6387188bf61f0d6bad10a135 /procfs/process.c | |
parent | db9ad21d272a4dce53c35095b97ca0a597b45004 (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/process.c')
-rw-r--r-- | procfs/process.c | 104 |
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, |