From 3ccae8efeea6f066fa49fdc4e90597758877949f Mon Sep 17 00:00:00 2001 From: Martin Baulig Date: Sat, 3 Apr 1999 22:54:00 +0000 Subject: [PATCH] Added LIBGTOP_PROC_MAPS: process memory maps. --- kernel/sysctl/libgtop.c | 142 +++++++++++++++++++++++++++++++++++++++- kernel/sysctl/libgtop.h | 41 +++++++++++- 2 files changed, 180 insertions(+), 3 deletions(-) diff --git a/kernel/sysctl/libgtop.c b/kernel/sysctl/libgtop.c index a2d5540f..aa99139e 100644 --- a/kernel/sysctl/libgtop.c +++ b/kernel/sysctl/libgtop.c @@ -43,8 +43,14 @@ static int proc_ctl_handler (ctl_table *table, int *name, int nlen, size_t newlen, void **context); static int proc_args_ctl_handler (ctl_table *table, int *name, int nlen, - void *oldval, size_t *oldlenp, void *newval, - size_t newlen, void **context); + void *oldval, size_t *oldlenp, + void *newval, size_t newlen, + void **context); + +static int proc_maps_ctl_handler (ctl_table *table, int *name, int nlen, + void *oldval, size_t *oldlenp, + void *newval, size_t newlen, + void **context); static int libgtop_sysctl_version = 1; static int libgtop_update_expensive = 5000; @@ -98,6 +104,8 @@ ctl_table libgtop_table[] = { sizeof (libgtop_proc_signal), 0444, NULL, NULL, &proc_ctl_handler}, {LIBGTOP_PROC_ARGS, NULL, NULL, 0, 0444, NULL, NULL, &proc_args_ctl_handler}, + {LIBGTOP_PROC_MAPS, NULL, NULL, 0, 0444, NULL, NULL, + &proc_maps_ctl_handler}, {0} }; @@ -1009,3 +1017,133 @@ proc_args_ctl_handler (ctl_table *table, int *name, int nlen, free_page (page); return -EFAULT; } + +static int +proc_maps_ctl_handler (ctl_table *table, int *name, int nlen, + void *oldval, size_t *oldlenp, void *newval, + size_t newlen, void **context) +{ + struct task_struct *p = NULL; + struct vm_area_struct * map, * next; + int i, len, len_name, retval = -EINVAL; + libgtop_proc_maps_t *proc_maps; + size_t count, wrote = 0; + loff_t lineno = 0; + int volatile_task; + + if (!oldlenp || get_user (len, oldlenp)) + return -EFAULT; + + if (!name || !nlen || get_user (len_name, name)) + return -EFAULT; + + if (nlen != 2) + return -EFAULT; + + read_lock (&tasklist_lock); + p = find_task_by_pid (name [1]); + /* FIXME!! This should be done after the last use */ + read_unlock (&tasklist_lock); + + if (!p || !p->mm) + return -ESRCH; + + if (len % sizeof (libgtop_proc_maps_t)) + return -EINVAL; + + count = len / sizeof (libgtop_proc_maps_t); + + if (!(proc_maps = kmalloc (sizeof (libgtop_proc_maps_t), GFP_KERNEL))) + return -ENOMEM; + + if (!p->mm || p->mm == &init_mm) + goto write_len_out; + + /* Check whether the mmaps could change if we sleep */ + volatile_task = (p != current || atomic_read (&p->mm->count) > 1); + + if (count == 0) { + /* Only get total count. */ + for (map = p->mm->mmap, i = 0; map; map = map->vm_next, i++) + continue; + wrote = i; + goto write_len_success; + } + + /* quickly go to line lineno */ + for (map = p->mm->mmap, i = 0; map && (i < lineno); + map = map->vm_next, i++) + continue; + + for ( ; map; map = next) { + memset (proc_maps, 0, sizeof (libgtop_proc_maps_t)); + + /* + * Get the next vma now (but it won't be used if we sleep). + */ + next = map->vm_next; + + proc_maps->header.start = map->vm_start; + proc_maps->header.end = map->vm_end; + proc_maps->header.offset = map->vm_offset; + + proc_maps->header.perm = map->vm_flags; + + if (map->vm_file != NULL) { + char *line = d_path (map->vm_file->f_dentry, proc_maps->filename, + LIBGTOP_MAP_PATH_LEN); + + proc_maps->filename [LIBGTOP_MAP_PATH_LEN-1] = '\0'; + proc_maps->header.filename_offset = line - proc_maps->filename; + + proc_maps->header.device = + map->vm_file->f_dentry->d_inode->i_dev; + proc_maps->header.inode = + map->vm_file->f_dentry->d_inode->i_ino; + } + + /* Copy current entry to user space. */ + if (copy_to_user (oldval, proc_maps, sizeof (*proc_maps))) { + retval = -EFAULT; + goto free_page_out; + } + + wrote += sizeof (*proc_maps); + + oldval += sizeof (*proc_maps); + len -= sizeof (*proc_maps); + count--; + + /* If there are no more entries, we don't have to worry about space. */ + if (next == NULL) + goto write_len_success; + + if (len < sizeof (*proc_maps)) { + retval = -EFAULT; + goto write_len_out; + } + + if (count == 0) { + retval = -E2BIG; + goto write_len_out; + } + } + + retval = -ENOSYS; + goto free_page_out; + + return retval; + + write_len_success: + retval = 1; + + write_len_out: + if (put_user (wrote, oldlenp)) { + retval = -EFAULT; + goto free_page_out; + } + + free_page_out: + kfree (proc_maps); + return retval; +} diff --git a/kernel/sysctl/libgtop.h b/kernel/sysctl/libgtop.h index 48da890d..7ebd2165 100644 --- a/kernel/sysctl/libgtop.h +++ b/kernel/sysctl/libgtop.h @@ -16,7 +16,8 @@ enum { LIBGTOP_PROC_SEGMENT, LIBGTOP_PROC_MEM, LIBGTOP_PROC_SIGNAL, - LIBGTOP_PROC_ARGS + LIBGTOP_PROC_ARGS, + LIBGTOP_PROC_MAPS }; enum { @@ -45,6 +46,27 @@ enum { #define LIBGTOP_TASK_STOPPED 16 #define LIBGTOP_TASK_SWAPPING 32 +#define LIBGTOP_VM_READ 0x0001 /* currently active flags */ +#define LIBGTOP_VM_WRITE 0x0002 +#define LIBGTOP_VM_EXEC 0x0004 +#define LIBGTOP_VM_SHARED 0x0008 + +#define LIBGTOP_VM_MAYREAD 0x0010 /* limits for mprotect() etc */ +#define LIBGTOP_VM_MAYWRITE 0x0020 +#define LIBGTOP_VM_MAYEXEC 0x0040 +#define LIBGTOP_VM_MAYSHARE 0x0080 + +#define LIBGTOP_VM_GROWSDOWN 0x0100 /* general info on the segment */ +#define LIBGTOP_VM_GROWSUP 0x0200 +#define LIBGTOP_VM_SHM 0x0400 /* shared memory area, don't swap out */ +#define LIBGTOP_VM_DENYWRITE 0x0800 /* ETXTBSY on write attempts.. */ + +#define LIBGTOP_VM_EXECUTABLE 0x1000 +#define LIBGTOP_VM_LOCKED 0x2000 +#define LIBGTOP_VM_IO 0x4000 /* Memory mapped I/O or similar */ + +#define LIBGTOP_MAP_PATH_LEN (PAGE_SIZE - sizeof (libgtop_proc_maps_header_t)) + #ifndef min #define min(a,b) ((a < b) ? a : b) #endif @@ -62,6 +84,9 @@ typedef struct libgtop_proc_segment libgtop_proc_segment_t; typedef struct libgtop_proc_mem libgtop_proc_mem_t; typedef struct libgtop_proc_signal libgtop_proc_signal_t; +typedef struct libgtop_proc_maps_header libgtop_proc_maps_header_t; +typedef struct libgtop_proc_maps libgtop_proc_maps_t; + struct libgtop_cpu { unsigned long total; /* Total CPU Time */ @@ -165,4 +190,18 @@ struct libgtop_proc_signal unsigned long catch [LIBGTOP_NSIG]; }; +struct libgtop_proc_maps_header +{ + unsigned long start, end, offset, perm; + off_t filename_offset; + ino_t inode; + dev_t device; +} __attribute__ ((aligned (64))); + +struct libgtop_proc_maps +{ + libgtop_proc_maps_header_t header; + char filename [LIBGTOP_MAP_PATH_LEN]; +}; + #endif