diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2009-03-05 19:52:25 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2009-03-05 19:52:25 +0000 |
commit | 94b35ac8ba6c670755f5c398f89709d960544622 (patch) | |
tree | 0c62a6bd55e1b1b55e3b7f5f166d8d94a0c07777 /sys/uvm | |
parent | 4939771421161444c79853f0ec2588d8aac2627e (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.h | 20 | ||||
-rw-r--r-- | sys/uvm/uvm_unix.c | 75 |
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); +} |