summaryrefslogtreecommitdiff
path: root/sys/uvm
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2009-03-05 19:52:25 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2009-03-05 19:52:25 +0000
commit94b35ac8ba6c670755f5c398f89709d960544622 (patch)
tree0c62a6bd55e1b1b55e3b7f5f166d8d94a0c07777 /sys/uvm
parent4939771421161444c79853f0ec2588d8aac2627e (diff)
Make ELF platforms generate ELF core dumps. Somewhat based on code from
NetBSD. ok kurt@, drahn@, miod@
Diffstat (limited to 'sys/uvm')
-rw-r--r--sys/uvm/uvm_extern.h20
-rw-r--r--sys/uvm/uvm_unix.c75
2 files changed, 93 insertions, 2 deletions
diff --git a/sys/uvm/uvm_extern.h b/sys/uvm/uvm_extern.h
index 2ec3f3431da..2e97ced5933 100644
--- a/sys/uvm/uvm_extern.h
+++ b/sys/uvm/uvm_extern.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: uvm_extern.h,v 1.73 2009/02/11 11:09:36 mikeb Exp $ */
+/* $OpenBSD: uvm_extern.h,v 1.74 2009/03/05 19:52:24 kettenis Exp $ */
/* $NetBSD: uvm_extern.h,v 1.57 2001/03/09 01:02:12 chs Exp $ */
/*
@@ -406,6 +406,20 @@ struct vmspace {
#ifdef _KERNEL
/*
+ * used to keep state while iterating over the map for a core dump.
+ */
+struct uvm_coredump_state {
+ void *cookie; /* opaque for the caller */
+ vaddr_t start; /* start of region */
+ vaddr_t realend; /* real end of region */
+ vaddr_t end; /* virtual end of region */
+ vm_prot_t prot; /* protection of region */
+ int flags; /* flags; see below */
+};
+
+#define UVM_COREDUMP_STACK 0x01 /* region is user stack */
+
+/*
* the various kernel maps, owned by MD code
*/
extern struct vm_map *exec_map;
@@ -574,6 +588,10 @@ void uvm_swap_init(void);
/* uvm_unix.c */
int uvm_coredump(struct proc *, struct vnode *,
struct ucred *, struct core *);
+int uvm_coredump_walkmap(struct proc *,
+ void *,
+ int (*)(struct proc *, void *,
+ struct uvm_coredump_state *), void *);
void uvm_grow(struct proc *, vaddr_t);
/* uvm_user.c */
diff --git a/sys/uvm/uvm_unix.c b/sys/uvm/uvm_unix.c
index 88601d6a810..118072ea12e 100644
--- a/sys/uvm/uvm_unix.c
+++ b/sys/uvm/uvm_unix.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uvm_unix.c,v 1.34 2008/03/02 20:29:20 kettenis Exp $ */
+/* $OpenBSD: uvm_unix.c,v 1.35 2009/03/05 19:52:24 kettenis Exp $ */
/* $NetBSD: uvm_unix.c,v 1.18 2000/09/13 15:00:25 thorpej Exp $ */
/*
@@ -255,3 +255,76 @@ uvm_coredump(p, vp, cred, chdr)
return (error);
}
+int
+uvm_coredump_walkmap(struct proc *p, void *iocookie,
+ int (*func)(struct proc *, void *, struct uvm_coredump_state *),
+ void *cookie)
+{
+ struct uvm_coredump_state state;
+ struct vmspace *vm = p->p_vmspace;
+ struct vm_map *map = &vm->vm_map;
+ struct vm_map_entry *entry;
+ vaddr_t top;
+ int error;
+
+ for (entry = map->header.next; entry != &map->header;
+ entry = entry->next) {
+
+ state.cookie = cookie;
+ state.prot = entry->protection;
+ state.flags = 0;
+
+ /* should never happen for a user process */
+ if (UVM_ET_ISSUBMAP(entry)) {
+ panic("uvm_coredump: user process with submap?");
+ }
+
+ if (!(entry->protection & VM_PROT_WRITE) &&
+ entry->start != p->p_sigcode)
+ continue;
+
+ /*
+ * Don't dump mmaped devices.
+ */
+ if (entry->object.uvm_obj != NULL &&
+ UVM_OBJ_IS_DEVICE(entry->object.uvm_obj))
+ continue;
+
+ state.start = entry->start;
+ state.realend = entry->end;
+ state.end = entry->end;
+
+ if (state.start >= VM_MAXUSER_ADDRESS)
+ continue;
+
+ if (state.end > VM_MAXUSER_ADDRESS)
+ state.end = VM_MAXUSER_ADDRESS;
+
+#ifdef MACHINE_STACK_GROWS_UP
+ if (USRSTACK <= state.start &&
+ state.start < (USRSTACK + MAXSSIZ)) {
+ top = round_page(USRSTACK + ptoa(vm->vm_ssize));
+ if (state.end > top)
+ state.end = top;
+
+ if (state.start >= state.end)
+ continue;
+#else
+ if (state.start >= (vaddr_t)vm->vm_maxsaddr) {
+ top = trunc_page(USRSTACK - ptoa(vm->vm_ssize));
+ if (state.start < top)
+ state.start = top;
+
+ if (state.start >= state.end)
+ continue;
+#endif
+ state.flags |= UVM_COREDUMP_STACK;
+ }
+
+ error = (*func)(p, iocookie, &state);
+ if (error)
+ return (error);
+ }
+
+ return (0);
+}