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