Home | History | Annotate | Line # | Download | only in kdump
      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
    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 *
    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
    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
    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
    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