xref: /netbsd-src/sys/uvm/uvm_coredump.c (revision d2a0ebb67a049a5c019aba780e67b6c65954d3db)
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