setemul.c revision 1.22 1 /* $NetBSD: setemul.c,v 1.22 2006/05/04 18:06:29 christos 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 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the NetBSD
18 * Foundation, Inc. and its contributors.
19 * 4. Neither the name of The NetBSD Foundation nor the names of its
20 * contributors may be used to endorse or promote products derived
21 * from this software without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
24 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
25 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
27 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 */
35
36 /*
37 * Copyright (c) 1988, 1993
38 * The Regents of the University of California. All rights reserved.
39 * (c) UNIX System Laboratories, Inc.
40 * All or some portions of this file are derived from material licensed
41 * to the University of California by American Telephone and Telegraph
42 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
43 * the permission of UNIX System Laboratories, Inc.
44 *
45 * Redistribution and use in source and binary forms, with or without
46 * modification, are permitted provided that the following conditions
47 * are met:
48 * 1. Redistributions of source code must retain the above copyright
49 * notice, this list of conditions and the following disclaimer.
50 * 2. Redistributions in binary form must reproduce the above copyright
51 * notice, this list of conditions and the following disclaimer in the
52 * documentation and/or other materials provided with the distribution.
53 * 3. Neither the name of the University nor the names of its contributors
54 * may be used to endorse or promote products derived from this software
55 * without specific prior written permission.
56 *
57 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
58 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
59 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
60 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
61 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
62 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
63 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
64 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
65 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
66 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
67 * SUCH DAMAGE.
68 */
69
70 #include <sys/cdefs.h>
71 #ifndef lint
72 __RCSID("$NetBSD: setemul.c,v 1.22 2006/05/04 18:06:29 christos Exp $");
73 #endif /* not lint */
74
75 #include <sys/param.h>
76 #include <sys/errno.h>
77 #include <sys/time.h>
78 #include <sys/queue.h>
79
80 #include <err.h>
81 #include <stdio.h>
82 #include <stdlib.h>
83 #include <string.h>
84 #include <unistd.h>
85 #include <vis.h>
86
87 #include "setemul.h"
88
89 #include <sys/syscall.h>
90
91 #include "../../sys/compat/netbsd32/netbsd32_syscall.h"
92 #include "../../sys/compat/freebsd/freebsd_syscall.h"
93 #include "../../sys/compat/hpux/hpux_syscall.h"
94 #include "../../sys/compat/ibcs2/ibcs2_syscall.h"
95 #include "../../sys/compat/irix/irix_syscall.h"
96 #include "../../sys/compat/linux/linux_syscall.h"
97 #include "../../sys/compat/linux32/linux32_syscall.h"
98 #include "../../sys/compat/mach/mach_syscall.h"
99 #include "../../sys/compat/darwin/darwin_syscall.h"
100 #include "../../sys/compat/mach/arch/powerpc/ppccalls/mach_ppccalls_syscall.h"
101 #include "../../sys/compat/mach/arch/powerpc/fasttraps/mach_fasttraps_syscall.h"
102 #include "../../sys/compat/osf1/osf1_syscall.h"
103 #include "../../sys/compat/sunos32/sunos32_syscall.h"
104 #include "../../sys/compat/sunos/sunos_syscall.h"
105 #include "../../sys/compat/svr4/svr4_syscall.h"
106 #include "../../sys/compat/svr4_32/svr4_32_syscall.h"
107 #include "../../sys/compat/ultrix/ultrix_syscall.h"
108 #ifdef __m68k__
109 #include "../../sys/compat/aoutm68k/aoutm68k_syscall.h"
110 #endif
111
112 #define KTRACE
113 #include "../../sys/kern/syscalls.c"
114
115 #include "../../sys/compat/netbsd32/netbsd32_syscalls.c"
116 #include "../../sys/compat/freebsd/freebsd_syscalls.c"
117 #include "../../sys/compat/hpux/hpux_syscalls.c"
118 #include "../../sys/compat/ibcs2/ibcs2_syscalls.c"
119 #include "../../sys/compat/irix/irix_syscalls.c"
120 #include "../../sys/compat/linux/linux_syscalls.c"
121 #include "../../sys/compat/linux32/linux32_syscalls.c"
122 #include "../../sys/compat/darwin/darwin_syscalls.c"
123 #include "../../sys/compat/mach/mach_syscalls.c"
124 #include "../../sys/compat/mach/arch/powerpc/ppccalls/mach_ppccalls_syscalls.c"
125 #include "../../sys/compat/mach/arch/powerpc/fasttraps/mach_fasttraps_syscalls.c"
126 #include "../../sys/compat/osf1/osf1_syscalls.c"
127 #include "../../sys/compat/sunos/sunos_syscalls.c"
128 #include "../../sys/compat/sunos32/sunos32_syscalls.c"
129 #include "../../sys/compat/svr4/svr4_syscalls.c"
130 #include "../../sys/compat/svr4_32/svr4_32_syscalls.c"
131 #include "../../sys/compat/ultrix/ultrix_syscalls.c"
132 #ifdef __m68k__
133 #include "../../sys/compat/aoutm68k/aoutm68k_syscalls.c"
134 #endif
135
136 #include "../../sys/compat/hpux/hpux_errno.c"
137 #include "../../sys/compat/svr4/svr4_errno.c"
138 #include "../../sys/compat/ibcs2/ibcs2_errno.c"
139 #include "../../sys/compat/irix/irix_errno.c"
140 #include "../../sys/compat/osf1/osf1_errno.c"
141 #include "../../sys/compat/linux/common/linux_errno.c"
142 #undef KTRACE
143
144 #define SIGRTMIN 33 /* XXX */
145 #include "../../sys/compat/hpux/hpux_signo.c"
146 #include "../../sys/compat/svr4/svr4_signo.c"
147 #include "../../sys/compat/ibcs2/ibcs2_signo.c"
148 /* irix uses svr4 */
149 #include "../../sys/compat/osf1/osf1_signo.c"
150 #include "../../sys/compat/linux/common/linux_signo.c"
151
152 /* For Mach services names in MMSG traces */
153 #ifndef LETS_GET_SMALL
154 #include "../../sys/compat/mach/mach_services_names.c"
155 #endif
156
157 #define NELEM(a) (sizeof(a) / sizeof(a[0]))
158
159 /* static */
160 const struct emulation emulations[] = {
161 { "netbsd", syscallnames, SYS_MAXSYSCALL,
162 NULL, 0,
163 NULL, 0, 0 },
164
165 { "netbsd32", netbsd32_syscallnames, SYS_MAXSYSCALL,
166 NULL, 0,
167 NULL, 0, EMUL_FLAG_NETBSD32 },
168
169 { "freebsd", freebsd_syscallnames, FREEBSD_SYS_MAXSYSCALL,
170 NULL, 0,
171 NULL, 0, 0 },
172
173 { "hpux", hpux_syscallnames, HPUX_SYS_MAXSYSCALL,
174 native_to_hpux_errno, NELEM(native_to_hpux_errno),
175 hpux_to_native_signo, NSIG, 0 },
176
177 { "ibcs2", ibcs2_syscallnames, IBCS2_SYS_MAXSYSCALL,
178 native_to_ibcs2_errno, NELEM(native_to_ibcs2_errno),
179 ibcs2_to_native_signo, NSIG, 0 },
180
181 { "irix o32", irix_syscallnames, IRIX_SYS_MAXSYSCALL,
182 native_to_irix_errno, NELEM(native_to_irix_errno),
183 svr4_to_native_signo, NSIG, 0 },
184
185 { "irix n32", irix_syscallnames, IRIX_SYS_MAXSYSCALL,
186 native_to_irix_errno, NELEM(native_to_irix_errno),
187 svr4_to_native_signo, NSIG, 0 },
188
189 { "linux", linux_syscallnames, LINUX_SYS_MAXSYSCALL,
190 native_to_linux_errno, NELEM(native_to_linux_errno),
191 linux_to_native_signo, NSIG, 0 },
192
193 { "linux32", linux32_syscallnames, LINUX32_SYS_MAXSYSCALL,
194 native_to_linux_errno, NELEM(native_to_linux_errno),
195 linux_to_native_signo, NSIG, 0 },
196
197 { "darwin", darwin_syscallnames, DARWIN_SYS_MAXSYSCALL,
198 NULL, 0,
199 NULL, 0, 0 },
200
201 { "mach", mach_syscallnames, MACH_SYS_MAXSYSCALL,
202 NULL, 0,
203 NULL, 0, 0 },
204
205 { "mach ppccalls", mach_ppccalls_syscallnames,
206 MACH_PPCCALLS_SYS_MAXSYSCALL,
207 NULL, 0,
208 NULL, 0, 0 },
209
210 { "mach fasttraps", mach_fasttraps_syscallnames,
211 MACH_FASTTRAPS_SYS_MAXSYSCALL,
212 NULL, 0,
213 NULL, 0, 0 },
214
215 { "osf1", osf1_syscallnames, OSF1_SYS_MAXSYSCALL,
216 native_to_osf1_errno, NELEM(native_to_osf1_errno),
217 osf1_to_native_signo, NSIG, 0 },
218
219 { "sunos32", sunos32_syscallnames, SUNOS32_SYS_MAXSYSCALL,
220 NULL, 0,
221 NULL, 0, EMUL_FLAG_NETBSD32 },
222
223 { "sunos", sunos_syscallnames, SUNOS_SYS_MAXSYSCALL,
224 NULL, 0,
225 NULL, 0, 0 },
226
227 { "svr4", svr4_syscallnames, SVR4_SYS_MAXSYSCALL,
228 native_to_svr4_errno, NELEM(native_to_svr4_errno),
229 svr4_to_native_signo, NSIG, 0 },
230
231 { "svr4_32", svr4_syscallnames, SVR4_SYS_MAXSYSCALL,
232 native_to_svr4_errno, NELEM(native_to_svr4_errno),
233 svr4_to_native_signo, NSIG, EMUL_FLAG_NETBSD32 },
234
235 { "ultrix", ultrix_syscallnames, ULTRIX_SYS_MAXSYSCALL,
236 NULL, 0,
237 NULL, 0, 0 },
238
239 { "pecoff", syscallnames, SYS_MAXSYSCALL,
240 NULL, 0,
241 NULL, 0, 0 },
242
243 #ifdef __m68k__
244 { "aoutm68k", aoutm68k_syscallnames, AOUTM68K_SYS_MAXSYSCALL,
245 NULL, 0,
246 NULL, 0, 0 },
247 #endif
248
249 { NULL, NULL, 0,
250 NULL, 0,
251 NULL, 0, 0 }
252 };
253
254 struct emulation_ctx {
255 pid_t pid;
256 const struct emulation *emulation;
257 LIST_ENTRY(emulation_ctx) ctx_link;
258 };
259
260 const struct emulation *cur_emul;
261 const struct emulation *prev_emul;
262 /* Mach emulation require extra emulation contexts */
263 static const struct emulation *mach;
264 static const struct emulation *mach_ppccalls;
265 static const struct emulation *mach_fasttraps;
266
267 static const struct emulation *default_emul = &emulations[0];
268
269 struct emulation_ctx *current_ctx;
270 static LIST_HEAD(, emulation_ctx) emul_ctx =
271 LIST_HEAD_INITIALIZER(emul_ctx);
272
273 static struct emulation_ctx *ectx_find(pid_t);
274 static void ectx_update(pid_t, const struct emulation *);
275
276 void
277 setemul(const char *name, pid_t pid, int update_ectx)
278 {
279 int i;
280 const struct emulation *match = NULL;
281
282 for (i = 0; emulations[i].name != NULL; i++) {
283 if (strcmp(emulations[i].name, name) == 0) {
284 match = &emulations[i];
285 break;
286 }
287 }
288
289 if (!match) {
290 warnx("Emulation `%s' unknown", name);
291 return;
292 }
293
294 if (update_ectx)
295 ectx_update(pid, match);
296 else
297 default_emul = match;
298
299 if (cur_emul != NULL)
300 prev_emul = cur_emul;
301 else
302 prev_emul = match;
303
304 cur_emul = match;
305 }
306
307 /*
308 * Emulation context list is very simple chained list, not even hashed.
309 * We expect the number of separate traced contexts/processes to be
310 * fairly low, so it's not worth it to optimize this.
311 * MMMmmmm not when I use it, it is only bounded PID_MAX!
312 * Requeue looked up item at start of list to cache result since the
313 * trace file tendes to have a burst of calls for a single process.
314 */
315
316 /*
317 * Find an emulation context appropriate for the given pid.
318 */
319 static struct emulation_ctx *
320 ectx_find(pid_t pid)
321 {
322 struct emulation_ctx *ctx;
323
324 /* Find an existing entry */
325 LIST_FOREACH(ctx, &emul_ctx, ctx_link) {
326 if (ctx->pid == pid)
327 break;
328 }
329
330 if (ctx == NULL) {
331 /* create entry with default emulation */
332 ctx = malloc(sizeof *ctx);
333 if (ctx == NULL)
334 err(1, "malloc emul context");
335 ctx->pid = pid;
336 ctx->emulation = default_emul;
337
338 /* chain into the list */
339 LIST_INSERT_HEAD(&emul_ctx, ctx, ctx_link);
340 } else {
341 /* move entry to head to optimize lookup for syscall bursts */
342 LIST_REMOVE(ctx, ctx_link);
343 LIST_INSERT_HEAD(&emul_ctx, ctx, ctx_link);
344 }
345
346 return ctx;
347 }
348
349 /*
350 * Update emulation context for given pid, or create new if no context
351 * for this pid exists.
352 */
353 static void
354 ectx_update(pid_t pid, const struct emulation *emul)
355 {
356 struct emulation_ctx *ctx;
357
358 ctx = ectx_find(pid);
359 ctx->emulation = emul;
360 }
361
362 /*
363 * Ensure current emulation context is correct for given pid.
364 */
365 void
366 ectx_sanify(pid_t pid)
367 {
368 struct emulation_ctx *ctx;
369
370 ctx = ectx_find(pid);
371 cur_emul = ctx->emulation;
372 }
373
374 /*
375 * Delete emulation context for current pid.
376 * (eg when tracing exit())
377 * Defer delete just in case we've cached a pointer...
378 */
379 void
380 ectx_delete(void)
381 {
382 static struct emulation_ctx *ctx = NULL;
383
384 if (ctx != NULL)
385 free(ctx);
386
387 /*
388 * The emulation for current syscall entry is always on HEAD, due
389 * to code in ectx_find().
390 */
391 ctx = LIST_FIRST(&emul_ctx);
392
393 if (ctx)
394 LIST_REMOVE(ctx, ctx_link);
395 }
396
397 /*
398 * Temporarily modify code and emulations to handle Mach traps
399 * XXX The define are duplicated from sys/arch/powerpc/include/mach_syscall.c
400 */
401 #define MACH_FASTTRAPS 0x00007ff0
402 #define MACH_PPCCALLS 0x00006000
403 #define MACH_ODD_SYSCALL_MASK 0x0000fff0
404 int
405 mach_traps_dispatch(int *code, const struct emulation **emul)
406 {
407 switch (*code & MACH_ODD_SYSCALL_MASK) {
408 case MACH_FASTTRAPS:
409 *emul = mach_fasttraps;
410 *code -= MACH_FASTTRAPS;
411 return 1;
412
413 case MACH_PPCCALLS:
414 *emul = mach_ppccalls;
415 *code -= MACH_PPCCALLS;
416 return 1;
417
418 default:
419 if (*code < 0) {
420 *emul = mach;
421 *code = -*code;
422 return 1;
423 }
424 return 0;
425 }
426 }
427
428 /*
429 * Lookup Machs emulations
430 */
431 void
432 mach_lookup_emul(void)
433 {
434 const struct emulation *emul_idx;
435
436 for (emul_idx = emulations; emul_idx->name; emul_idx++) {
437 if (strcmp("mach", emul_idx->name) == 0)
438 mach = emul_idx;
439 if (strcmp("mach fasttraps", emul_idx->name) == 0)
440 mach_fasttraps = emul_idx;
441 if (strcmp("mach ppccalls", emul_idx->name) == 0)
442 mach_ppccalls = emul_idx;
443 }
444 if (mach == NULL || mach_fasttraps == NULL || mach_ppccalls == NULL) {
445 errx(1, "Cannot load mach emulations");
446 exit(1);
447 }
448 return;
449 }
450
451 /*
452 * Find the name of the Mach service responsible to a given message Id
453 */
454 const char *
455 mach_service_name(id)
456 int id;
457 {
458 const char *retval = NULL;
459 #ifndef LETS_GET_SMALL
460 struct mach_service_name *srv;
461
462 for (srv = mach_services_names; srv->srv_id; srv++)
463 if (srv->srv_id == id)
464 break;
465 retval = srv->srv_name;
466 #endif /* LETS_GET_SMALL */
467
468 return retval;
469 }
470