diff options
author | Jasper Lievisse Adriaanse <jasper@humppa.nl> | 2012-04-04 19:23:07 +0200 |
---|---|---|
committer | Jasper Lievisse Adriaanse <jasper@humppa.nl> | 2012-04-04 19:23:07 +0200 |
commit | b0f4bee85e3ef974ca9fde04abd1769a8b84a544 (patch) | |
tree | c73d2a5380ff70ba61c0ce203e5625e6872ac36b /sysdeps/openbsd | |
parent | 1d1d3fb90791deb60635506d095c09377ac2b8c8 (diff) | |
download | libgtop-b0f4bee85e3ef974ca9fde04abd1769a8b84a544.tar.gz |
sync with openbsd to use the new vmmap memory allocator
Diffstat (limited to 'sysdeps/openbsd')
-rw-r--r-- | sysdeps/openbsd/procmap.c | 160 |
1 files changed, 127 insertions, 33 deletions
diff --git a/sysdeps/openbsd/procmap.c b/sysdeps/openbsd/procmap.c index 49048193..b915dae2 100644 --- a/sysdeps/openbsd/procmap.c +++ b/sysdeps/openbsd/procmap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: procmap.c,v 1.6 2011/06/06 17:12:12 jasper Exp $ */ +/* $OpenBSD: patch-sysdeps_openbsd_procmap_c,v 1.7 2012/03/11 08:45:24 ajacoutot Exp $ */ /* Copyright (C) 1998 Joshua Sled This file is part of LibGTop 1.0. @@ -29,6 +29,7 @@ #include <glibtop_suid.h> #include <kvm.h> +#include <stdlib.h> #include <sys/param.h> #include <sys/proc.h> #include <sys/resource.h> @@ -56,6 +57,12 @@ static const unsigned long _glibtop_sysdeps_map_entry = (1L << GLIBTOP_MAP_ENTRY_OFFSET) + (1L << GLIBTOP_MAP_ENTRY_PERM) + (1L << GLIBTOP_MAP_ENTRY_INODE) + (1L << GLIBTOP_MAP_ENTRY_DEVICE); +/* Local helper functions. */ + +ssize_t load_vmmap_entries(glibtop*, unsigned long, struct vm_map_entry**, + struct vm_map_entry*); +void unload_vmmap_entries(struct vm_map_entry *); + /* Init function. */ void @@ -65,9 +72,89 @@ _glibtop_init_proc_map_p (glibtop *server) } /* + * Download vmmap_entries from the kernel into our address space. + * We fix up the addr tree while downloading. + * + * Returns: the size of the tree on succes, or -1 on failure. + * On failure, *rptr needs to be passed to unload_vmmap_entries to free + * the lot. + */ +ssize_t +load_vmmap_entries(glibtop *server, unsigned long kptr, + struct vm_map_entry **rptr, struct vm_map_entry *parent) +{ + struct vm_map_entry *entry; + unsigned long left_kptr, right_kptr; + ssize_t left_sz; + ssize_t right_sz; + + if (kptr == 0) + return 0; + + /* Need space. */ + entry = malloc(sizeof(*entry)); + if (entry == NULL) + return -1; + + /* Download entry at kptr. */ + if (kvm_read (server->machine.kd, kptr, + (char *)entry, sizeof(*entry)) != sizeof(*entry)) { + free(entry); + return -1; + } + + /* + * Update addr pointers to have sane values in this address space. + * We save the kernel pointers in {left,right}_kptr, so we have them + * available to download children. + */ + left_kptr = (unsigned long) RB_LEFT(entry, daddrs.addr_entry); + right_kptr = (unsigned long) RB_RIGHT(entry, daddrs.addr_entry); + RB_LEFT(entry, daddrs.addr_entry) = + RB_RIGHT(entry, daddrs.addr_entry) = NULL; + /* Fill in parent pointer. */ + RB_PARENT(entry, daddrs.addr_entry) = parent; + + /* + * Consistent state reached, fill in *rptr. + */ + *rptr = entry; + + /* + * Download left, right. + * On failure, our map is in a state that can be handled by + * unload_vmmap_entries. + */ + left_sz = load_vmmap_entries(server, left_kptr, + &RB_LEFT(entry, daddrs.addr_entry), entry); + if (left_sz == -1) + return -1; + right_sz = load_vmmap_entries(server, right_kptr, + &RB_RIGHT(entry, daddrs.addr_entry), entry); + if (right_sz == -1) + return -1; + + return 1 + left_sz + right_sz; +} + +/* + * Free the vmmap entries in the given tree. + */ +void +unload_vmmap_entries(struct vm_map_entry *entry) +{ + if (entry == NULL) + return; + + unload_vmmap_entries(RB_LEFT(entry, daddrs.addr_entry)); + unload_vmmap_entries(RB_RIGHT(entry, daddrs.addr_entry)); + free(entry); +} + +/* * Provides detailed information about a process. * Due to the fact we are only requested info about one process, it's possible - * the process has been reaped before we get to kvm_getproc2. Tough luck. + * the process has been reaped before we get to kvm_getprocs. Tough luck. */ glibtop_map_entry * @@ -75,15 +162,16 @@ glibtop_get_proc_map_p (glibtop *server, glibtop_proc_map *buf, pid_t pid) { struct kinfo_proc *pinfo; - struct vm_map_entry entry, *first; + struct vm_map_entry *entry; + struct uvm_map_addr root; struct vmspace vmspace; struct vnode vnode; struct inode inode; + ssize_t nentries; GArray *maps = g_array_sized_new(FALSE, FALSE, sizeof(glibtop_map_entry), 100); - int count, i = 0; - int update = 0; + int count = 0; glibtop_init_p (server, (1L << GLIBTOP_SYSDEPS_PROC_MAP), 0); @@ -95,7 +183,7 @@ glibtop_get_proc_map_p (glibtop *server, glibtop_proc_map *buf, glibtop_suid_enter (server); /* Get the process data */ - pinfo = kvm_getprocs (server->machine.kd, KERN_PROC_PID, pid, sizeof(struct kinfo_proc2), &count); + pinfo = kvm_getprocs (server->machine.kd, KERN_PROC_PID, pid, sizeof(struct kinfo_proc), &count); if ((pinfo == NULL) || (count < 1)) { glibtop_warn_io_r (server, "kvm_getprocs (%d)", pid); return (glibtop_map_entry*) g_array_free(maps, TRUE); @@ -108,16 +196,18 @@ glibtop_get_proc_map_p (glibtop *server, glibtop_proc_map *buf, (char *) &vmspace, sizeof (vmspace)) != sizeof (vmspace)) glibtop_error_io_r (server, "kvm_read (vmspace)"); - first = vmspace.vm_map.header.next; - - if (kvm_read (server->machine.kd, - (unsigned long) vmspace.vm_map.header.next, - (char *) &entry, sizeof (entry)) != sizeof (entry)) + RB_INIT(&root); + nentries = load_vmmap_entries(server, + (unsigned long) RB_ROOT(&vmspace.vm_map.addr), + &RB_ROOT(&root), NULL); + if (nentries == -1) { + unload_vmmap_entries(RB_ROOT(&root)); glibtop_error_io_r (server, "kvm_read (entry)"); + } /* Allocate space. */ - buf->number = vmspace.vm_map.nentries; + buf->number = nentries; buf->size = sizeof (glibtop_map_entry); buf->total = buf->number * buf->size; @@ -131,32 +221,23 @@ glibtop_get_proc_map_p (glibtop *server, glibtop_proc_map *buf, * to OBJT_DEFAULT so it seems this really works. */ - do { + RB_FOREACH(entry, uvm_map_addr, &root) { glibtop_map_entry *mentry; unsigned long inum, dev; guint len; - if (update) { - if (kvm_read (server->machine.kd, - (unsigned long) entry.next, - &entry, sizeof (entry)) != sizeof (entry)) - glibtop_error_io_r (server, "kvm_read (entry)"); - } else { - update = 1; - } - - if (UVM_ET_ISSUBMAP (&entry)) + if (UVM_ET_ISSUBMAP(entry)) continue; - - if (!entry.object.uvm_obj) + if (!entry->object.uvm_obj) continue; /* We're only interested in vnodes */ if (kvm_read (server->machine.kd, - (unsigned long) entry.object.uvm_obj, + (unsigned long) entry->object.uvm_obj, &vnode, sizeof (vnode)) != sizeof (vnode)) { glibtop_warn_io_r (server, "kvm_read (vnode)"); + unload_vmmap_entries(RB_ROOT(&root)); return (glibtop_map_entry*) g_array_free(maps, TRUE); } @@ -181,21 +262,21 @@ glibtop_get_proc_map_p (glibtop *server, glibtop_proc_map *buf, mentry->flags = _glibtop_sysdeps_map_entry; - mentry->start = (guint64) entry.start; - mentry->end = (guint64) entry.end; - mentry->offset = (guint64) entry.offset; + mentry->start = (guint64) entry->start; + mentry->end = (guint64) entry->end; + mentry->offset = (guint64) entry->offset; mentry->device = (guint64) dev; mentry->inode = (guint64) inum; mentry->perm = (guint64) 0; - if (entry.protection & VM_PROT_READ) + if (entry->protection & VM_PROT_READ) mentry->perm |= GLIBTOP_MAP_PERM_READ; - if (entry.protection & VM_PROT_WRITE) + if (entry->protection & VM_PROT_WRITE) mentry->perm |= GLIBTOP_MAP_PERM_WRITE; - if (entry.protection & VM_PROT_EXECUTE) + if (entry->protection & VM_PROT_EXECUTE) mentry->perm |= GLIBTOP_MAP_PERM_EXECUTE; - } while (entry.next != first); + } buf->flags = _glibtop_sysdeps_proc_map; @@ -203,5 +284,18 @@ glibtop_get_proc_map_p (glibtop *server, glibtop_proc_map *buf, buf->size = sizeof (glibtop_map_entry); buf->total = buf->number * buf->size; + unload_vmmap_entries(RB_ROOT(&root)); return (glibtop_map_entry*) g_array_free(maps, FALSE); } + +/* + * Don't implement address comparison. + */ +static __inline int +no_impl(void *p, void *q) +{ + abort(); /* Should not be called. */ + return 0; +} + +RB_GENERATE(uvm_map_addr, vm_map_entry, daddrs.addr_entry, no_impl); |