xref: /netbsd-src/usr.bin/kdump/setemul.c (revision ba0aa175c4da9ccc83d06676ced52fbcbd994030)
1*ba0aa175Smaxv /*	$NetBSD: setemul.c,v 1.32 2019/03/25 19:24:31 maxv Exp $	*/
2470e7fc5Sjdolecek 
3470e7fc5Sjdolecek /*-
4470e7fc5Sjdolecek  * Copyright (c) 2000 The NetBSD Foundation, Inc.
5470e7fc5Sjdolecek  * All rights reserved.
6470e7fc5Sjdolecek  *
7470e7fc5Sjdolecek  * Redistribution and use in source and binary forms, with or without
8470e7fc5Sjdolecek  * modification, are permitted provided that the following conditions
9470e7fc5Sjdolecek  * are met:
10470e7fc5Sjdolecek  * 1. Redistributions of source code must retain the above copyright
11470e7fc5Sjdolecek  *    notice, this list of conditions and the following disclaimer.
12470e7fc5Sjdolecek  * 2. Redistributions in binary form must reproduce the above copyright
13470e7fc5Sjdolecek  *    notice, this list of conditions and the following disclaimer in the
14470e7fc5Sjdolecek  *    documentation and/or other materials provided with the distribution.
15470e7fc5Sjdolecek  *
16470e7fc5Sjdolecek  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17470e7fc5Sjdolecek  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18470e7fc5Sjdolecek  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19470e7fc5Sjdolecek  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20470e7fc5Sjdolecek  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21470e7fc5Sjdolecek  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22470e7fc5Sjdolecek  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23470e7fc5Sjdolecek  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24470e7fc5Sjdolecek  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25470e7fc5Sjdolecek  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26470e7fc5Sjdolecek  * POSSIBILITY OF SUCH DAMAGE.
27470e7fc5Sjdolecek  */
28470e7fc5Sjdolecek 
29470e7fc5Sjdolecek /*
30470e7fc5Sjdolecek  * Copyright (c) 1988, 1993
31470e7fc5Sjdolecek  *	The Regents of the University of California.  All rights reserved.
32470e7fc5Sjdolecek  * (c) UNIX System Laboratories, Inc.
33470e7fc5Sjdolecek  * All or some portions of this file are derived from material licensed
34470e7fc5Sjdolecek  * to the University of California by American Telephone and Telegraph
35470e7fc5Sjdolecek  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
36470e7fc5Sjdolecek  * the permission of UNIX System Laboratories, Inc.
37470e7fc5Sjdolecek  *
38470e7fc5Sjdolecek  * Redistribution and use in source and binary forms, with or without
39470e7fc5Sjdolecek  * modification, are permitted provided that the following conditions
40470e7fc5Sjdolecek  * are met:
41470e7fc5Sjdolecek  * 1. Redistributions of source code must retain the above copyright
42470e7fc5Sjdolecek  *    notice, this list of conditions and the following disclaimer.
43470e7fc5Sjdolecek  * 2. Redistributions in binary form must reproduce the above copyright
44470e7fc5Sjdolecek  *    notice, this list of conditions and the following disclaimer in the
45470e7fc5Sjdolecek  *    documentation and/or other materials provided with the distribution.
4689aaa1bbSagc  * 3. Neither the name of the University nor the names of its contributors
47470e7fc5Sjdolecek  *    may be used to endorse or promote products derived from this software
48470e7fc5Sjdolecek  *    without specific prior written permission.
49470e7fc5Sjdolecek  *
50470e7fc5Sjdolecek  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
51470e7fc5Sjdolecek  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52470e7fc5Sjdolecek  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
53470e7fc5Sjdolecek  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
54470e7fc5Sjdolecek  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
55470e7fc5Sjdolecek  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
56470e7fc5Sjdolecek  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
57470e7fc5Sjdolecek  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
58470e7fc5Sjdolecek  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
59470e7fc5Sjdolecek  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
60470e7fc5Sjdolecek  * SUCH DAMAGE.
61470e7fc5Sjdolecek  */
62470e7fc5Sjdolecek 
63470e7fc5Sjdolecek #include <sys/cdefs.h>
64470e7fc5Sjdolecek #ifndef lint
65*ba0aa175Smaxv __RCSID("$NetBSD: setemul.c,v 1.32 2019/03/25 19:24:31 maxv Exp $");
66470e7fc5Sjdolecek #endif /* not lint */
67470e7fc5Sjdolecek 
68470e7fc5Sjdolecek #include <sys/param.h>
69470e7fc5Sjdolecek #include <sys/errno.h>
70470e7fc5Sjdolecek #include <sys/time.h>
7104fa39a4Sjdolecek #include <sys/queue.h>
72470e7fc5Sjdolecek 
73470e7fc5Sjdolecek #include <err.h>
74470e7fc5Sjdolecek #include <stdio.h>
75470e7fc5Sjdolecek #include <stdlib.h>
76470e7fc5Sjdolecek #include <string.h>
77470e7fc5Sjdolecek #include <unistd.h>
78470e7fc5Sjdolecek #include <vis.h>
79470e7fc5Sjdolecek 
80470e7fc5Sjdolecek #include "setemul.h"
81470e7fc5Sjdolecek 
82470e7fc5Sjdolecek #include <sys/syscall.h>
83470e7fc5Sjdolecek 
84470e7fc5Sjdolecek #include "../../sys/compat/netbsd32/netbsd32_syscall.h"
85470e7fc5Sjdolecek #include "../../sys/compat/freebsd/freebsd_syscall.h"
86470e7fc5Sjdolecek #include "../../sys/compat/linux/linux_syscall.h"
87ee0c5b44Smanu #include "../../sys/compat/linux32/linux32_syscall.h"
8805ebb290Smrg #include "../../sys/compat/sunos32/sunos32_syscall.h"
89470e7fc5Sjdolecek #include "../../sys/compat/sunos/sunos_syscall.h"
90470e7fc5Sjdolecek #include "../../sys/compat/ultrix/ultrix_syscall.h"
91394f070aSchristos #ifdef __m68k__
92394f070aSchristos #include "../../sys/compat/aoutm68k/aoutm68k_syscall.h"
93394f070aSchristos #endif
94470e7fc5Sjdolecek 
95470e7fc5Sjdolecek #define KTRACE
96470e7fc5Sjdolecek #include "../../sys/kern/syscalls.c"
97470e7fc5Sjdolecek 
98470e7fc5Sjdolecek #include "../../sys/compat/netbsd32/netbsd32_syscalls.c"
99470e7fc5Sjdolecek #include "../../sys/compat/freebsd/freebsd_syscalls.c"
100470e7fc5Sjdolecek #include "../../sys/compat/linux/linux_syscalls.c"
101ee0c5b44Smanu #include "../../sys/compat/linux32/linux32_syscalls.c"
102470e7fc5Sjdolecek #include "../../sys/compat/sunos/sunos_syscalls.c"
10305ebb290Smrg #include "../../sys/compat/sunos32/sunos32_syscalls.c"
104470e7fc5Sjdolecek #include "../../sys/compat/ultrix/ultrix_syscalls.c"
105394f070aSchristos #ifdef __m68k__
106394f070aSchristos #include "../../sys/compat/aoutm68k/aoutm68k_syscalls.c"
107394f070aSchristos #endif
108470e7fc5Sjdolecek 
109470e7fc5Sjdolecek #include "../../sys/compat/linux/common/linux_errno.c"
110470e7fc5Sjdolecek #undef KTRACE
111470e7fc5Sjdolecek 
112f600368bSchristos #define SIGRTMIN	33	/* XXX */
113f600368bSchristos #include "../../sys/compat/linux/common/linux_signo.c"
114f600368bSchristos 
115470e7fc5Sjdolecek #define NELEM(a) (sizeof(a) / sizeof(a[0]))
116470e7fc5Sjdolecek 
117bcffe04bSmanu /* static */
118bcffe04bSmanu const struct emulation emulations[] = {
119470e7fc5Sjdolecek 	{ "netbsd",	syscallnames,		SYS_MAXSYSCALL,
120f600368bSchristos 	  NULL,				0,
1212ccd4840Smrg 	  NULL,				0,	0 },
122f600368bSchristos 
123470e7fc5Sjdolecek 	{ "netbsd32",	netbsd32_syscallnames,	SYS_MAXSYSCALL,
124f600368bSchristos 	  NULL,				0,
1252ccd4840Smrg 	  NULL,				0,	EMUL_FLAG_NETBSD32 },
126f600368bSchristos 
127470e7fc5Sjdolecek 	{ "freebsd",	freebsd_syscallnames,	FREEBSD_SYS_MAXSYSCALL,
128f600368bSchristos 	  NULL,				0,
1292ccd4840Smrg 	  NULL,				0,	0 },
130f600368bSchristos 
131470e7fc5Sjdolecek 	{ "linux",	linux_syscallnames,	LINUX_SYS_MAXSYSCALL,
132f600368bSchristos 	  native_to_linux_errno,	NELEM(native_to_linux_errno),
1332ccd4840Smrg 	  linux_to_native_signo,	NSIG,	0 },
134f600368bSchristos 
135ee0c5b44Smanu 	{ "linux32",	linux32_syscallnames,	LINUX32_SYS_MAXSYSCALL,
136ee0c5b44Smanu 	  native_to_linux_errno,	NELEM(native_to_linux_errno),
137e7544f93Snjoly 	  linux_to_native_signo,	NSIG,	EMUL_FLAG_NETBSD32 },
138ee0c5b44Smanu 
13905ebb290Smrg 	{ "sunos32",	sunos32_syscallnames,	SUNOS32_SYS_MAXSYSCALL,
140f600368bSchristos 	  NULL,				0,
1412ccd4840Smrg 	  NULL,				0,	EMUL_FLAG_NETBSD32 },
142f600368bSchristos 
143470e7fc5Sjdolecek 	{ "sunos",	sunos_syscallnames,	SUNOS_SYS_MAXSYSCALL,
144f600368bSchristos 	  NULL,				0,
1452ccd4840Smrg 	  NULL,				0,	0 },
146f600368bSchristos 
147470e7fc5Sjdolecek 	{ "ultrix",	ultrix_syscallnames,	ULTRIX_SYS_MAXSYSCALL,
148f600368bSchristos 	  NULL,				0,
1492ccd4840Smrg 	  NULL,				0,	0 },
150f600368bSchristos 
151394f070aSchristos #ifdef __m68k__
152394f070aSchristos 	{ "aoutm68k",	aoutm68k_syscallnames,	AOUTM68K_SYS_MAXSYSCALL,
153394f070aSchristos 	  NULL,				0,
154394f070aSchristos 	  NULL,				0,	0 },
155394f070aSchristos #endif
156394f070aSchristos 
157470e7fc5Sjdolecek 	{ NULL,		NULL,			0,
158f600368bSchristos 	  NULL,				0,
1592ccd4840Smrg 	  NULL,				0,	0 }
160470e7fc5Sjdolecek };
161470e7fc5Sjdolecek 
162470e7fc5Sjdolecek struct emulation_ctx {
163470e7fc5Sjdolecek 	pid_t	pid;
164862d4684Sjdolecek 	const struct emulation *emulation;
16504fa39a4Sjdolecek 	LIST_ENTRY(emulation_ctx) ctx_link;
166470e7fc5Sjdolecek };
167470e7fc5Sjdolecek 
1683433691eSdsl const struct emulation *cur_emul;
1693433691eSdsl const struct emulation *prev_emul;
170470e7fc5Sjdolecek 
1713433691eSdsl static const struct emulation *default_emul = &emulations[0];
172470e7fc5Sjdolecek 
173470e7fc5Sjdolecek struct emulation_ctx *current_ctx;
17404fa39a4Sjdolecek static LIST_HEAD(, emulation_ctx) emul_ctx =
17504fa39a4Sjdolecek 	LIST_HEAD_INITIALIZER(emul_ctx);
176470e7fc5Sjdolecek 
17787b62b5aSchristos static struct emulation_ctx *ectx_find(pid_t);
17887b62b5aSchristos static void	ectx_update(pid_t, const struct emulation *);
179470e7fc5Sjdolecek 
180470e7fc5Sjdolecek void
setemul(const char * name,pid_t pid,int update_ectx)18187b62b5aSchristos setemul(const char *name, pid_t pid, int update_ectx)
182470e7fc5Sjdolecek {
183470e7fc5Sjdolecek 	int i;
184862d4684Sjdolecek 	const struct emulation *match = NULL;
185470e7fc5Sjdolecek 
186470e7fc5Sjdolecek 	for (i = 0; emulations[i].name != NULL; i++) {
187470e7fc5Sjdolecek 		if (strcmp(emulations[i].name, name) == 0) {
188470e7fc5Sjdolecek 			match = &emulations[i];
189470e7fc5Sjdolecek 			break;
190470e7fc5Sjdolecek 		}
191470e7fc5Sjdolecek 	}
192470e7fc5Sjdolecek 
193470e7fc5Sjdolecek 	if (!match) {
194470e7fc5Sjdolecek 		warnx("Emulation `%s' unknown", name);
195470e7fc5Sjdolecek 		return;
196470e7fc5Sjdolecek 	}
197470e7fc5Sjdolecek 
198470e7fc5Sjdolecek 	if (update_ectx)
199470e7fc5Sjdolecek 		ectx_update(pid, match);
2003433691eSdsl 	else
201470e7fc5Sjdolecek 		default_emul = match;
202470e7fc5Sjdolecek 
2033433691eSdsl 	if (cur_emul != NULL)
2043433691eSdsl 		prev_emul = cur_emul;
2051a6f0143Smanu 	else
2063433691eSdsl 		prev_emul = match;
2071a6f0143Smanu 
2083433691eSdsl 	cur_emul = match;
209470e7fc5Sjdolecek }
210470e7fc5Sjdolecek 
211470e7fc5Sjdolecek /*
212470e7fc5Sjdolecek  * Emulation context list is very simple chained list, not even hashed.
213470e7fc5Sjdolecek  * We expect the number of separate traced contexts/processes to be
214470e7fc5Sjdolecek  * fairly low, so it's not worth it to optimize this.
2153433691eSdsl  * MMMmmmm not when I use it, it is only bounded PID_MAX!
2163433691eSdsl  * Requeue looked up item at start of list to cache result since the
2173433691eSdsl  * trace file tendes to have a burst of calls for a single process.
218470e7fc5Sjdolecek  */
219470e7fc5Sjdolecek 
220470e7fc5Sjdolecek /*
221470e7fc5Sjdolecek  * Find an emulation context appropriate for the given pid.
222470e7fc5Sjdolecek  */
223470e7fc5Sjdolecek static struct emulation_ctx *
ectx_find(pid_t pid)22487b62b5aSchristos ectx_find(pid_t pid)
225470e7fc5Sjdolecek {
22604fa39a4Sjdolecek 	struct emulation_ctx *ctx;
227470e7fc5Sjdolecek 
22804fa39a4Sjdolecek 	/* Find an existing entry */
22904fa39a4Sjdolecek 	LIST_FOREACH(ctx, &emul_ctx, ctx_link) {
23004fa39a4Sjdolecek 		if (ctx->pid == pid)
23104fa39a4Sjdolecek 			break;
23204fa39a4Sjdolecek 	}
2333433691eSdsl 
2343433691eSdsl 	if (ctx == NULL) {
2353433691eSdsl 		/* create entry with default emulation */
2363433691eSdsl 		ctx = malloc(sizeof *ctx);
2373433691eSdsl 		if (ctx == NULL)
2383433691eSdsl 			err(1, "malloc emul context");
2393433691eSdsl 		ctx->pid = pid;
2403433691eSdsl 		ctx->emulation = default_emul;
24104fa39a4Sjdolecek 
24204fa39a4Sjdolecek 		/* chain into the list */
24304fa39a4Sjdolecek 		LIST_INSERT_HEAD(&emul_ctx, ctx, ctx_link);
24404fa39a4Sjdolecek 	} else {
24504fa39a4Sjdolecek 		/* move entry to head to optimize lookup for syscall bursts */
24604fa39a4Sjdolecek 		LIST_REMOVE(ctx, ctx_link);
24704fa39a4Sjdolecek 		LIST_INSERT_HEAD(&emul_ctx, ctx, ctx_link);
248470e7fc5Sjdolecek 	}
24904fa39a4Sjdolecek 
2503433691eSdsl 	return ctx;
251470e7fc5Sjdolecek }
252470e7fc5Sjdolecek 
253470e7fc5Sjdolecek /*
254470e7fc5Sjdolecek  * Update emulation context for given pid, or create new if no context
255470e7fc5Sjdolecek  * for this pid exists.
256470e7fc5Sjdolecek  */
257470e7fc5Sjdolecek static void
ectx_update(pid_t pid,const struct emulation * emul)25887b62b5aSchristos ectx_update(pid_t pid, const struct emulation *emul)
259470e7fc5Sjdolecek {
260470e7fc5Sjdolecek 	struct emulation_ctx *ctx;
261470e7fc5Sjdolecek 
2623433691eSdsl 	ctx = ectx_find(pid);
263470e7fc5Sjdolecek 	ctx->emulation = emul;
264470e7fc5Sjdolecek }
265470e7fc5Sjdolecek 
266470e7fc5Sjdolecek /*
267470e7fc5Sjdolecek  * Ensure current emulation context is correct for given pid.
268470e7fc5Sjdolecek  */
269470e7fc5Sjdolecek void
ectx_sanify(pid_t pid)27087b62b5aSchristos ectx_sanify(pid_t pid)
271470e7fc5Sjdolecek {
272470e7fc5Sjdolecek 	struct emulation_ctx *ctx;
273470e7fc5Sjdolecek 
2743433691eSdsl 	ctx = ectx_find(pid);
2753433691eSdsl 	cur_emul = ctx->emulation;
2763433691eSdsl }
2773433691eSdsl 
2783433691eSdsl /*
2793433691eSdsl  * Delete emulation context for current pid.
2803433691eSdsl  * (eg when tracing exit())
2813433691eSdsl  * Defer delete just in case we've cached a pointer...
2823433691eSdsl  */
2833433691eSdsl void
ectx_delete(void)2843433691eSdsl ectx_delete(void)
2853433691eSdsl {
28604fa39a4Sjdolecek 	static struct emulation_ctx *ctx = NULL;
2873433691eSdsl 
2883433691eSdsl 	if (ctx != NULL)
2893433691eSdsl 		free(ctx);
2903433691eSdsl 
29104fa39a4Sjdolecek 	/*
29204fa39a4Sjdolecek 	 * The emulation for current syscall entry is always on HEAD, due
29304fa39a4Sjdolecek 	 * to code in ectx_find().
29404fa39a4Sjdolecek 	 */
29504fa39a4Sjdolecek 	ctx = LIST_FIRST(&emul_ctx);
29604fa39a4Sjdolecek 
29704fa39a4Sjdolecek 	if (ctx)
29804fa39a4Sjdolecek 		LIST_REMOVE(ctx, ctx_link);
299470e7fc5Sjdolecek }
300