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 */
160const 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
254struct emulation_ctx {
255	pid_t	pid;
256	const struct emulation *emulation;
257	LIST_ENTRY(emulation_ctx) ctx_link;
258};
259
260const struct emulation *cur_emul;
261const struct emulation *prev_emul;
262/* Mach emulation require extra emulation contexts */
263static const struct emulation *mach;
264static const struct emulation *mach_ppccalls;
265static const struct emulation *mach_fasttraps;
266
267static const struct emulation *default_emul = &emulations[0];
268
269struct emulation_ctx *current_ctx;
270static LIST_HEAD(, emulation_ctx) emul_ctx =
271	LIST_HEAD_INITIALIZER(emul_ctx);
272
273static struct emulation_ctx *ectx_find(pid_t);
274static void	ectx_update(pid_t, const struct emulation *);
275
276void
277setemul(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 */
319static struct emulation_ctx *
320ectx_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 */
353static void
354ectx_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 */
365void
366ectx_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 */
379void
380ectx_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
404int
405mach_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 */
431void
432mach_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 */
454const char *
455mach_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