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