1*d2a0ebb6Sad /* $NetBSD: uvm_coredump.c,v 1.8 2020/02/23 15:46:43 ad Exp $ */
292ce8c6aSad
392ce8c6aSad /*
492ce8c6aSad * Copyright (c) 1997 Charles D. Cranor and Washington University.
592ce8c6aSad * Copyright (c) 1991, 1993, The Regents of the University of California.
692ce8c6aSad *
792ce8c6aSad * All rights reserved.
892ce8c6aSad *
992ce8c6aSad * This code is derived from software contributed to Berkeley by
1092ce8c6aSad * The Mach Operating System project at Carnegie-Mellon University.
1192ce8c6aSad *
1292ce8c6aSad * Redistribution and use in source and binary forms, with or without
1392ce8c6aSad * modification, are permitted provided that the following conditions
1492ce8c6aSad * are met:
1592ce8c6aSad * 1. Redistributions of source code must retain the above copyright
1692ce8c6aSad * notice, this list of conditions and the following disclaimer.
1792ce8c6aSad * 2. Redistributions in binary form must reproduce the above copyright
1892ce8c6aSad * notice, this list of conditions and the following disclaimer in the
1992ce8c6aSad * documentation and/or other materials provided with the distribution.
2040ec801aSchuck * 3. Neither the name of the University nor the names of its contributors
2192ce8c6aSad * may be used to endorse or promote products derived from this software
2292ce8c6aSad * without specific prior written permission.
2392ce8c6aSad *
2492ce8c6aSad * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2592ce8c6aSad * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2692ce8c6aSad * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2792ce8c6aSad * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2892ce8c6aSad * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2992ce8c6aSad * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3092ce8c6aSad * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3192ce8c6aSad * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3292ce8c6aSad * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3392ce8c6aSad * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3492ce8c6aSad * SUCH DAMAGE.
3592ce8c6aSad *
3692ce8c6aSad * @(#)vm_glue.c 8.6 (Berkeley) 1/5/94
3792ce8c6aSad * from: Id: uvm_glue.c,v 1.1.2.8 1998/02/07 01:16:54 chs Exp
3892ce8c6aSad *
3992ce8c6aSad *
4092ce8c6aSad * Copyright (c) 1987, 1990 Carnegie-Mellon University.
4192ce8c6aSad * All rights reserved.
4292ce8c6aSad *
4392ce8c6aSad * Permission to use, copy, modify and distribute this software and
4492ce8c6aSad * its documentation is hereby granted, provided that both the copyright
4592ce8c6aSad * notice and this permission notice appear in all copies of the
4692ce8c6aSad * software, derivative works or modified versions, and any portions
4792ce8c6aSad * thereof, and that both notices appear in supporting documentation.
4892ce8c6aSad *
4992ce8c6aSad * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
5092ce8c6aSad * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
5192ce8c6aSad * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
5292ce8c6aSad *
5392ce8c6aSad * Carnegie Mellon requests users of this software to return to
5492ce8c6aSad *
5592ce8c6aSad * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
5692ce8c6aSad * School of Computer Science
5792ce8c6aSad * Carnegie Mellon University
5892ce8c6aSad * Pittsburgh PA 15213-3890
5992ce8c6aSad *
6092ce8c6aSad * any improvements or extensions that they make and grant Carnegie the
6192ce8c6aSad * rights to redistribute these changes.
6292ce8c6aSad */
6392ce8c6aSad
6492ce8c6aSad #include <sys/cdefs.h>
65*d2a0ebb6Sad __KERNEL_RCSID(0, "$NetBSD: uvm_coredump.c,v 1.8 2020/02/23 15:46:43 ad Exp $");
6692ce8c6aSad
6792ce8c6aSad /*
6892ce8c6aSad * uvm_coredump.c: glue functions for coredump
6992ce8c6aSad */
7092ce8c6aSad
7192ce8c6aSad #include <sys/param.h>
7292ce8c6aSad #include <sys/systm.h>
7392ce8c6aSad #include <sys/proc.h>
7492ce8c6aSad
7592ce8c6aSad #include <uvm/uvm.h>
7692ce8c6aSad
7792ce8c6aSad /*
7892ce8c6aSad * uvm_coredump_walkmap: walk a process's map for the purpose of dumping
7992ce8c6aSad * a core file.
807a743f3dSdsl * XXX: I'm not entirely sure the locking is this function is in anyway
817a743f3dSdsl * correct. If the process isn't actually stopped then the data passed
827a743f3dSdsl * to func() is at best stale, and horrid things might happen if the
837a743f3dSdsl * entry being processed is deleted (dsl).
8492ce8c6aSad */
8592ce8c6aSad
8692ce8c6aSad int
uvm_coredump_walkmap(struct proc * p,int (* func)(struct uvm_coredump_state *),void * cookie)87825d1920Sdsl uvm_coredump_walkmap(struct proc *p, int (*func)(struct uvm_coredump_state *),
88825d1920Sdsl void *cookie)
8992ce8c6aSad {
9092ce8c6aSad struct uvm_coredump_state state;
9192ce8c6aSad struct vmspace *vm = p->p_vmspace;
9292ce8c6aSad struct vm_map *map = &vm->vm_map;
9392ce8c6aSad struct vm_map_entry *entry;
9492ce8c6aSad int error;
9592ce8c6aSad
9692ce8c6aSad entry = NULL;
9792ce8c6aSad vm_map_lock_read(map);
9892ce8c6aSad state.end = 0;
9992ce8c6aSad for (;;) {
10092ce8c6aSad if (entry == NULL)
10192ce8c6aSad entry = map->header.next;
10292ce8c6aSad else if (!uvm_map_lookup_entry(map, state.end, &entry))
10392ce8c6aSad entry = entry->next;
10492ce8c6aSad if (entry == &map->header)
10592ce8c6aSad break;
10692ce8c6aSad
10792ce8c6aSad state.cookie = cookie;
10892ce8c6aSad if (state.end > entry->start) {
10992ce8c6aSad state.start = state.end;
11092ce8c6aSad } else {
11192ce8c6aSad state.start = entry->start;
11292ce8c6aSad }
11392ce8c6aSad state.realend = entry->end;
11492ce8c6aSad state.end = entry->end;
11592ce8c6aSad state.prot = entry->protection;
11692ce8c6aSad state.flags = 0;
11792ce8c6aSad
11892ce8c6aSad /*
11992ce8c6aSad * Dump the region unless one of the following is true:
12092ce8c6aSad *
12192ce8c6aSad * (1) the region has neither object nor amap behind it
12292ce8c6aSad * (ie. it has never been accessed).
12392ce8c6aSad *
12492ce8c6aSad * (2) the region has no amap and is read-only
12592ce8c6aSad * (eg. an executable text section).
12692ce8c6aSad *
12792ce8c6aSad * (3) the region's object is a device.
12892ce8c6aSad *
12992ce8c6aSad * (4) the region is unreadable by the process.
13092ce8c6aSad */
13192ce8c6aSad
13292ce8c6aSad KASSERT(!UVM_ET_ISSUBMAP(entry));
133514df72fSrin #ifdef VM_MAXUSER_ADDRESS
13492ce8c6aSad KASSERT(state.start < VM_MAXUSER_ADDRESS);
13592ce8c6aSad KASSERT(state.end <= VM_MAXUSER_ADDRESS);
136514df72fSrin #endif
13792ce8c6aSad if (entry->object.uvm_obj == NULL &&
13892ce8c6aSad entry->aref.ar_amap == NULL) {
13992ce8c6aSad state.realend = state.start;
14092ce8c6aSad } else if ((entry->protection & VM_PROT_WRITE) == 0 &&
14192ce8c6aSad entry->aref.ar_amap == NULL) {
14292ce8c6aSad state.realend = state.start;
14392ce8c6aSad } else if (entry->object.uvm_obj != NULL &&
14492ce8c6aSad UVM_OBJ_IS_DEVICE(entry->object.uvm_obj)) {
14592ce8c6aSad state.realend = state.start;
14692ce8c6aSad } else if ((entry->protection & VM_PROT_READ) == 0) {
14792ce8c6aSad state.realend = state.start;
14892ce8c6aSad } else {
14992ce8c6aSad if (state.start >= (vaddr_t)vm->vm_maxsaddr)
15092ce8c6aSad state.flags |= UVM_COREDUMP_STACK;
15192ce8c6aSad
15292ce8c6aSad /*
15392ce8c6aSad * If this an anonymous entry, only dump instantiated
15492ce8c6aSad * pages.
15592ce8c6aSad */
15692ce8c6aSad if (entry->object.uvm_obj == NULL) {
15792ce8c6aSad vaddr_t end;
15892ce8c6aSad
159*d2a0ebb6Sad amap_lock(entry->aref.ar_amap, RW_READER);
16092ce8c6aSad for (end = state.start;
16192ce8c6aSad end < state.end; end += PAGE_SIZE) {
16292ce8c6aSad struct vm_anon *anon;
16392ce8c6aSad anon = amap_lookup(&entry->aref,
16492ce8c6aSad end - entry->start);
16592ce8c6aSad /*
16692ce8c6aSad * If we have already encountered an
16792ce8c6aSad * uninstantiated page, stop at the
16892ce8c6aSad * first instantied page.
16992ce8c6aSad */
17092ce8c6aSad if (anon != NULL &&
17192ce8c6aSad state.realend != state.end) {
17292ce8c6aSad state.end = end;
17392ce8c6aSad break;
17492ce8c6aSad }
17592ce8c6aSad
17692ce8c6aSad /*
17792ce8c6aSad * If this page is the first
17892ce8c6aSad * uninstantiated page, mark this as
17992ce8c6aSad * the real ending point. Continue to
18092ce8c6aSad * counting uninstantiated pages.
18192ce8c6aSad */
18292ce8c6aSad if (anon == NULL &&
18392ce8c6aSad state.realend == state.end) {
18492ce8c6aSad state.realend = end;
18592ce8c6aSad }
18692ce8c6aSad }
18792ce8c6aSad amap_unlock(entry->aref.ar_amap);
18892ce8c6aSad }
18992ce8c6aSad }
19092ce8c6aSad
19192ce8c6aSad vm_map_unlock_read(map);
192825d1920Sdsl error = (*func)(&state);
19392ce8c6aSad if (error)
19492ce8c6aSad return (error);
19592ce8c6aSad vm_map_lock_read(map);
19692ce8c6aSad }
19792ce8c6aSad vm_map_unlock_read(map);
19892ce8c6aSad
19992ce8c6aSad return (0);
20092ce8c6aSad }
2017a743f3dSdsl
2027a743f3dSdsl static int
count_segs(struct uvm_coredump_state * s)203825d1920Sdsl count_segs(struct uvm_coredump_state *s)
2047a743f3dSdsl {
2057a743f3dSdsl (*(int *)s->cookie)++;
2067a743f3dSdsl
2077a743f3dSdsl return 0;
2087a743f3dSdsl }
2097a743f3dSdsl
2107a743f3dSdsl int
uvm_coredump_count_segs(struct proc * p)2117a743f3dSdsl uvm_coredump_count_segs(struct proc *p)
2127a743f3dSdsl {
2137a743f3dSdsl int count = 0;
2147a743f3dSdsl
2157a743f3dSdsl uvm_coredump_walkmap(p, count_segs, &count);
2167a743f3dSdsl return count;
2177a743f3dSdsl }
218