setemul.c revision 1.31
1/*	$NetBSD: setemul.c,v 1.31 2018/12/29 18:09:32 martin Exp $	*/
2
3/*-
4 * Copyright (c) 2000 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/*
30 * Copyright (c) 1988, 1993
31 *	The Regents of the University of California.  All rights reserved.
32 * (c) UNIX System Laboratories, Inc.
33 * All or some portions of this file are derived from material licensed
34 * to the University of California by American Telephone and Telegraph
35 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
36 * the permission of UNIX System Laboratories, Inc.
37 *
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions
40 * are met:
41 * 1. Redistributions of source code must retain the above copyright
42 *    notice, this list of conditions and the following disclaimer.
43 * 2. Redistributions in binary form must reproduce the above copyright
44 *    notice, this list of conditions and the following disclaimer in the
45 *    documentation and/or other materials provided with the distribution.
46 * 3. Neither the name of the University nor the names of its contributors
47 *    may be used to endorse or promote products derived from this software
48 *    without specific prior written permission.
49 *
50 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
51 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
53 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
54 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
55 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
56 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
57 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
58 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
59 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
60 * SUCH DAMAGE.
61 */
62
63#include <sys/cdefs.h>
64#ifndef lint
65__RCSID("$NetBSD: setemul.c,v 1.31 2018/12/29 18:09:32 martin Exp $");
66#endif /* not lint */
67
68#include <sys/param.h>
69#include <sys/errno.h>
70#include <sys/time.h>
71#include <sys/queue.h>
72
73#include <err.h>
74#include <stdio.h>
75#include <stdlib.h>
76#include <string.h>
77#include <unistd.h>
78#include <vis.h>
79
80#include "setemul.h"
81
82#include <sys/syscall.h>
83
84#include "../../sys/compat/netbsd32/netbsd32_syscall.h"
85#include "../../sys/compat/freebsd/freebsd_syscall.h"
86#include "../../sys/compat/linux/linux_syscall.h"
87#include "../../sys/compat/linux32/linux32_syscall.h"
88#include "../../sys/compat/osf1/osf1_syscall.h"
89#include "../../sys/compat/sunos32/sunos32_syscall.h"
90#include "../../sys/compat/sunos/sunos_syscall.h"
91#include "../../sys/compat/ultrix/ultrix_syscall.h"
92#ifdef __m68k__
93#include "../../sys/compat/aoutm68k/aoutm68k_syscall.h"
94#endif
95
96#define KTRACE
97#include "../../sys/kern/syscalls.c"
98
99#include "../../sys/compat/netbsd32/netbsd32_syscalls.c"
100#include "../../sys/compat/freebsd/freebsd_syscalls.c"
101#include "../../sys/compat/linux/linux_syscalls.c"
102#include "../../sys/compat/linux32/linux32_syscalls.c"
103#include "../../sys/compat/osf1/osf1_syscalls.c"
104#include "../../sys/compat/sunos/sunos_syscalls.c"
105#include "../../sys/compat/sunos32/sunos32_syscalls.c"
106#include "../../sys/compat/ultrix/ultrix_syscalls.c"
107#ifdef __m68k__
108#include "../../sys/compat/aoutm68k/aoutm68k_syscalls.c"
109#endif
110
111#include "../../sys/compat/osf1/osf1_errno.c"
112#include "../../sys/compat/linux/common/linux_errno.c"
113#undef KTRACE
114
115#define SIGRTMIN	33	/* XXX */
116#include "../../sys/compat/osf1/osf1_signo.c"
117#include "../../sys/compat/linux/common/linux_signo.c"
118
119#define NELEM(a) (sizeof(a) / sizeof(a[0]))
120
121/* static */
122const struct emulation emulations[] = {
123	{ "netbsd",	syscallnames,		SYS_MAXSYSCALL,
124	  NULL,				0,
125	  NULL,				0,	0 },
126
127	{ "netbsd32",	netbsd32_syscallnames,	SYS_MAXSYSCALL,
128	  NULL,				0,
129	  NULL,				0,	EMUL_FLAG_NETBSD32 },
130
131	{ "freebsd",	freebsd_syscallnames,	FREEBSD_SYS_MAXSYSCALL,
132	  NULL,				0,
133	  NULL,				0,	0 },
134
135	{ "linux",	linux_syscallnames,	LINUX_SYS_MAXSYSCALL,
136	  native_to_linux_errno,	NELEM(native_to_linux_errno),
137	  linux_to_native_signo,	NSIG,	0 },
138
139	{ "linux32",	linux32_syscallnames,	LINUX32_SYS_MAXSYSCALL,
140	  native_to_linux_errno,	NELEM(native_to_linux_errno),
141	  linux_to_native_signo,	NSIG,	EMUL_FLAG_NETBSD32 },
142
143	{ "osf1",	osf1_syscallnames,	OSF1_SYS_MAXSYSCALL,
144	  native_to_osf1_errno,		NELEM(native_to_osf1_errno),
145	  osf1_to_native_signo,		NSIG,	0 },
146
147	{ "sunos32",	sunos32_syscallnames,	SUNOS32_SYS_MAXSYSCALL,
148	  NULL,				0,
149	  NULL,				0,	EMUL_FLAG_NETBSD32 },
150
151	{ "sunos",	sunos_syscallnames,	SUNOS_SYS_MAXSYSCALL,
152	  NULL,				0,
153	  NULL,				0,	0 },
154
155	{ "ultrix",	ultrix_syscallnames,	ULTRIX_SYS_MAXSYSCALL,
156	  NULL,				0,
157	  NULL,				0,	0 },
158
159#ifdef __m68k__
160	{ "aoutm68k",	aoutm68k_syscallnames,	AOUTM68K_SYS_MAXSYSCALL,
161	  NULL,				0,
162	  NULL,				0,	0 },
163#endif
164
165	{ NULL,		NULL,			0,
166	  NULL,				0,
167	  NULL,				0,	0 }
168};
169
170struct emulation_ctx {
171	pid_t	pid;
172	const struct emulation *emulation;
173	LIST_ENTRY(emulation_ctx) ctx_link;
174};
175
176const struct emulation *cur_emul;
177const struct emulation *prev_emul;
178
179static const struct emulation *default_emul = &emulations[0];
180
181struct emulation_ctx *current_ctx;
182static LIST_HEAD(, emulation_ctx) emul_ctx =
183	LIST_HEAD_INITIALIZER(emul_ctx);
184
185static struct emulation_ctx *ectx_find(pid_t);
186static void	ectx_update(pid_t, const struct emulation *);
187
188void
189setemul(const char *name, pid_t pid, int update_ectx)
190{
191	int i;
192	const struct emulation *match = NULL;
193
194	for (i = 0; emulations[i].name != NULL; i++) {
195		if (strcmp(emulations[i].name, name) == 0) {
196			match = &emulations[i];
197			break;
198		}
199	}
200
201	if (!match) {
202		warnx("Emulation `%s' unknown", name);
203		return;
204	}
205
206	if (update_ectx)
207		ectx_update(pid, match);
208	else
209		default_emul = match;
210
211	if (cur_emul != NULL)
212		prev_emul = cur_emul;
213	else
214		prev_emul = match;
215
216	cur_emul = match;
217}
218
219/*
220 * Emulation context list is very simple chained list, not even hashed.
221 * We expect the number of separate traced contexts/processes to be
222 * fairly low, so it's not worth it to optimize this.
223 * MMMmmmm not when I use it, it is only bounded PID_MAX!
224 * Requeue looked up item at start of list to cache result since the
225 * trace file tendes to have a burst of calls for a single process.
226 */
227
228/*
229 * Find an emulation context appropriate for the given pid.
230 */
231static struct emulation_ctx *
232ectx_find(pid_t pid)
233{
234	struct emulation_ctx *ctx;
235
236	/* Find an existing entry */
237	LIST_FOREACH(ctx, &emul_ctx, ctx_link) {
238		if (ctx->pid == pid)
239			break;
240	}
241
242	if (ctx == NULL) {
243		/* create entry with default emulation */
244		ctx = malloc(sizeof *ctx);
245		if (ctx == NULL)
246			err(1, "malloc emul context");
247		ctx->pid = pid;
248		ctx->emulation = default_emul;
249
250		/* chain into the list */
251		LIST_INSERT_HEAD(&emul_ctx, ctx, ctx_link);
252	} else {
253		/* move entry to head to optimize lookup for syscall bursts */
254		LIST_REMOVE(ctx, ctx_link);
255		LIST_INSERT_HEAD(&emul_ctx, ctx, ctx_link);
256	}
257
258	return ctx;
259}
260
261/*
262 * Update emulation context for given pid, or create new if no context
263 * for this pid exists.
264 */
265static void
266ectx_update(pid_t pid, const struct emulation *emul)
267{
268	struct emulation_ctx *ctx;
269
270	ctx = ectx_find(pid);
271	ctx->emulation = emul;
272}
273
274/*
275 * Ensure current emulation context is correct for given pid.
276 */
277void
278ectx_sanify(pid_t pid)
279{
280	struct emulation_ctx *ctx;
281
282	ctx = ectx_find(pid);
283	cur_emul = ctx->emulation;
284}
285
286/*
287 * Delete emulation context for current pid.
288 * (eg when tracing exit())
289 * Defer delete just in case we've cached a pointer...
290 */
291void
292ectx_delete(void)
293{
294	static struct emulation_ctx *ctx = NULL;
295
296	if (ctx != NULL)
297		free(ctx);
298
299	/*
300	 * The emulation for current syscall entry is always on HEAD, due
301	 * to code in ectx_find().
302	 */
303	ctx = LIST_FIRST(&emul_ctx);
304
305	if (ctx)
306		LIST_REMOVE(ctx, ctx_link);
307}
308