1 /* $NetBSD: setemul.c,v 1.32 2019/03/25 19:24:31 maxv 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.32 2019/03/25 19:24:31 maxv 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/sunos32/sunos32_syscall.h"
89 #include "../../sys/compat/sunos/sunos_syscall.h"
90 #include "../../sys/compat/ultrix/ultrix_syscall.h"
91 #ifdef __m68k__
92 #include "../../sys/compat/aoutm68k/aoutm68k_syscall.h"
93 #endif
94
95 #define KTRACE
96 #include "../../sys/kern/syscalls.c"
97
98 #include "../../sys/compat/netbsd32/netbsd32_syscalls.c"
99 #include "../../sys/compat/freebsd/freebsd_syscalls.c"
100 #include "../../sys/compat/linux/linux_syscalls.c"
101 #include "../../sys/compat/linux32/linux32_syscalls.c"
102 #include "../../sys/compat/sunos/sunos_syscalls.c"
103 #include "../../sys/compat/sunos32/sunos32_syscalls.c"
104 #include "../../sys/compat/ultrix/ultrix_syscalls.c"
105 #ifdef __m68k__
106 #include "../../sys/compat/aoutm68k/aoutm68k_syscalls.c"
107 #endif
108
109 #include "../../sys/compat/linux/common/linux_errno.c"
110 #undef KTRACE
111
112 #define SIGRTMIN 33 /* XXX */
113 #include "../../sys/compat/linux/common/linux_signo.c"
114
115 #define NELEM(a) (sizeof(a) / sizeof(a[0]))
116
117 /* static */
118 const struct emulation emulations[] = {
119 { "netbsd", syscallnames, SYS_MAXSYSCALL,
120 NULL, 0,
121 NULL, 0, 0 },
122
123 { "netbsd32", netbsd32_syscallnames, SYS_MAXSYSCALL,
124 NULL, 0,
125 NULL, 0, EMUL_FLAG_NETBSD32 },
126
127 { "freebsd", freebsd_syscallnames, FREEBSD_SYS_MAXSYSCALL,
128 NULL, 0,
129 NULL, 0, 0 },
130
131 { "linux", linux_syscallnames, LINUX_SYS_MAXSYSCALL,
132 native_to_linux_errno, NELEM(native_to_linux_errno),
133 linux_to_native_signo, NSIG, 0 },
134
135 { "linux32", linux32_syscallnames, LINUX32_SYS_MAXSYSCALL,
136 native_to_linux_errno, NELEM(native_to_linux_errno),
137 linux_to_native_signo, NSIG, EMUL_FLAG_NETBSD32 },
138
139 { "sunos32", sunos32_syscallnames, SUNOS32_SYS_MAXSYSCALL,
140 NULL, 0,
141 NULL, 0, EMUL_FLAG_NETBSD32 },
142
143 { "sunos", sunos_syscallnames, SUNOS_SYS_MAXSYSCALL,
144 NULL, 0,
145 NULL, 0, 0 },
146
147 { "ultrix", ultrix_syscallnames, ULTRIX_SYS_MAXSYSCALL,
148 NULL, 0,
149 NULL, 0, 0 },
150
151 #ifdef __m68k__
152 { "aoutm68k", aoutm68k_syscallnames, AOUTM68K_SYS_MAXSYSCALL,
153 NULL, 0,
154 NULL, 0, 0 },
155 #endif
156
157 { NULL, NULL, 0,
158 NULL, 0,
159 NULL, 0, 0 }
160 };
161
162 struct emulation_ctx {
163 pid_t pid;
164 const struct emulation *emulation;
165 LIST_ENTRY(emulation_ctx) ctx_link;
166 };
167
168 const struct emulation *cur_emul;
169 const struct emulation *prev_emul;
170
171 static const struct emulation *default_emul = &emulations[0];
172
173 struct emulation_ctx *current_ctx;
174 static LIST_HEAD(, emulation_ctx) emul_ctx =
175 LIST_HEAD_INITIALIZER(emul_ctx);
176
177 static struct emulation_ctx *ectx_find(pid_t);
178 static void ectx_update(pid_t, const struct emulation *);
179
180 void
setemul(const char * name,pid_t pid,int update_ectx)181 setemul(const char *name, pid_t pid, int update_ectx)
182 {
183 int i;
184 const struct emulation *match = NULL;
185
186 for (i = 0; emulations[i].name != NULL; i++) {
187 if (strcmp(emulations[i].name, name) == 0) {
188 match = &emulations[i];
189 break;
190 }
191 }
192
193 if (!match) {
194 warnx("Emulation `%s' unknown", name);
195 return;
196 }
197
198 if (update_ectx)
199 ectx_update(pid, match);
200 else
201 default_emul = match;
202
203 if (cur_emul != NULL)
204 prev_emul = cur_emul;
205 else
206 prev_emul = match;
207
208 cur_emul = match;
209 }
210
211 /*
212 * Emulation context list is very simple chained list, not even hashed.
213 * We expect the number of separate traced contexts/processes to be
214 * fairly low, so it's not worth it to optimize this.
215 * MMMmmmm not when I use it, it is only bounded PID_MAX!
216 * Requeue looked up item at start of list to cache result since the
217 * trace file tendes to have a burst of calls for a single process.
218 */
219
220 /*
221 * Find an emulation context appropriate for the given pid.
222 */
223 static struct emulation_ctx *
ectx_find(pid_t pid)224 ectx_find(pid_t pid)
225 {
226 struct emulation_ctx *ctx;
227
228 /* Find an existing entry */
229 LIST_FOREACH(ctx, &emul_ctx, ctx_link) {
230 if (ctx->pid == pid)
231 break;
232 }
233
234 if (ctx == NULL) {
235 /* create entry with default emulation */
236 ctx = malloc(sizeof *ctx);
237 if (ctx == NULL)
238 err(1, "malloc emul context");
239 ctx->pid = pid;
240 ctx->emulation = default_emul;
241
242 /* chain into the list */
243 LIST_INSERT_HEAD(&emul_ctx, ctx, ctx_link);
244 } else {
245 /* move entry to head to optimize lookup for syscall bursts */
246 LIST_REMOVE(ctx, ctx_link);
247 LIST_INSERT_HEAD(&emul_ctx, ctx, ctx_link);
248 }
249
250 return ctx;
251 }
252
253 /*
254 * Update emulation context for given pid, or create new if no context
255 * for this pid exists.
256 */
257 static void
ectx_update(pid_t pid,const struct emulation * emul)258 ectx_update(pid_t pid, const struct emulation *emul)
259 {
260 struct emulation_ctx *ctx;
261
262 ctx = ectx_find(pid);
263 ctx->emulation = emul;
264 }
265
266 /*
267 * Ensure current emulation context is correct for given pid.
268 */
269 void
ectx_sanify(pid_t pid)270 ectx_sanify(pid_t pid)
271 {
272 struct emulation_ctx *ctx;
273
274 ctx = ectx_find(pid);
275 cur_emul = ctx->emulation;
276 }
277
278 /*
279 * Delete emulation context for current pid.
280 * (eg when tracing exit())
281 * Defer delete just in case we've cached a pointer...
282 */
283 void
ectx_delete(void)284 ectx_delete(void)
285 {
286 static struct emulation_ctx *ctx = NULL;
287
288 if (ctx != NULL)
289 free(ctx);
290
291 /*
292 * The emulation for current syscall entry is always on HEAD, due
293 * to code in ectx_find().
294 */
295 ctx = LIST_FIRST(&emul_ctx);
296
297 if (ctx)
298 LIST_REMOVE(ctx, ctx_link);
299 }
300