xref: /netbsd-src/usr.bin/kdump/setemul.c (revision ba0aa175c4da9ccc83d06676ced52fbcbd994030)
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