1 /* $NetBSD: setemul.c,v 1.26 2008/04/28 20:24:13 martin 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.26 2008/04/28 20:24:13 martin 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/irix/irix_syscall.h" 88 #include "../../sys/compat/linux/linux_syscall.h" 89 #include "../../sys/compat/linux32/linux32_syscall.h" 90 #include "../../sys/compat/mach/mach_syscall.h" 91 #include "../../sys/compat/darwin/darwin_syscall.h" 92 #include "../../sys/compat/mach/arch/powerpc/ppccalls/mach_ppccalls_syscall.h" 93 #include "../../sys/compat/mach/arch/powerpc/fasttraps/mach_fasttraps_syscall.h" 94 #include "../../sys/compat/osf1/osf1_syscall.h" 95 #include "../../sys/compat/sunos32/sunos32_syscall.h" 96 #include "../../sys/compat/sunos/sunos_syscall.h" 97 #include "../../sys/compat/svr4/svr4_syscall.h" 98 #include "../../sys/compat/svr4_32/svr4_32_syscall.h" 99 #include "../../sys/compat/ultrix/ultrix_syscall.h" 100 #ifdef __m68k__ 101 #include "../../sys/compat/aoutm68k/aoutm68k_syscall.h" 102 #endif 103 104 #define KTRACE 105 #include "../../sys/kern/syscalls.c" 106 107 #include "../../sys/compat/netbsd32/netbsd32_syscalls.c" 108 #include "../../sys/compat/freebsd/freebsd_syscalls.c" 109 #include "../../sys/compat/ibcs2/ibcs2_syscalls.c" 110 #include "../../sys/compat/irix/irix_syscalls.c" 111 #include "../../sys/compat/linux/linux_syscalls.c" 112 #include "../../sys/compat/linux32/linux32_syscalls.c" 113 #include "../../sys/compat/darwin/darwin_syscalls.c" 114 #include "../../sys/compat/mach/mach_syscalls.c" 115 #include "../../sys/compat/mach/arch/powerpc/ppccalls/mach_ppccalls_syscalls.c" 116 #include "../../sys/compat/mach/arch/powerpc/fasttraps/mach_fasttraps_syscalls.c" 117 #include "../../sys/compat/osf1/osf1_syscalls.c" 118 #include "../../sys/compat/sunos/sunos_syscalls.c" 119 #include "../../sys/compat/sunos32/sunos32_syscalls.c" 120 #include "../../sys/compat/svr4/svr4_syscalls.c" 121 #include "../../sys/compat/svr4_32/svr4_32_syscalls.c" 122 #include "../../sys/compat/ultrix/ultrix_syscalls.c" 123 #ifdef __m68k__ 124 #include "../../sys/compat/aoutm68k/aoutm68k_syscalls.c" 125 #endif 126 127 #include "../../sys/compat/svr4/svr4_errno.c" 128 #include "../../sys/compat/ibcs2/ibcs2_errno.c" 129 #include "../../sys/compat/irix/irix_errno.c" 130 #include "../../sys/compat/osf1/osf1_errno.c" 131 #include "../../sys/compat/linux/common/linux_errno.c" 132 #undef KTRACE 133 134 #define SIGRTMIN 33 /* XXX */ 135 #include "../../sys/compat/svr4/svr4_signo.c" 136 #include "../../sys/compat/ibcs2/ibcs2_signo.c" 137 /* irix uses svr4 */ 138 #include "../../sys/compat/osf1/osf1_signo.c" 139 #include "../../sys/compat/linux/common/linux_signo.c" 140 141 /* For Mach services names in MMSG traces */ 142 #ifndef LETS_GET_SMALL 143 #include "../../sys/compat/mach/mach_services_names.c" 144 #endif 145 146 #define NELEM(a) (sizeof(a) / sizeof(a[0])) 147 148 /* static */ 149 const struct emulation emulations[] = { 150 { "netbsd", syscallnames, SYS_MAXSYSCALL, 151 NULL, 0, 152 NULL, 0, 0 }, 153 154 { "netbsd32", netbsd32_syscallnames, SYS_MAXSYSCALL, 155 NULL, 0, 156 NULL, 0, EMUL_FLAG_NETBSD32 }, 157 158 { "freebsd", freebsd_syscallnames, FREEBSD_SYS_MAXSYSCALL, 159 NULL, 0, 160 NULL, 0, 0 }, 161 162 { "ibcs2", ibcs2_syscallnames, IBCS2_SYS_MAXSYSCALL, 163 native_to_ibcs2_errno, NELEM(native_to_ibcs2_errno), 164 ibcs2_to_native_signo, NSIG, 0 }, 165 166 { "irix o32", irix_syscallnames, IRIX_SYS_MAXSYSCALL, 167 native_to_irix_errno, NELEM(native_to_irix_errno), 168 svr4_to_native_signo, NSIG, 0 }, 169 170 { "irix n32", irix_syscallnames, IRIX_SYS_MAXSYSCALL, 171 native_to_irix_errno, NELEM(native_to_irix_errno), 172 svr4_to_native_signo, NSIG, 0 }, 173 174 { "linux", linux_syscallnames, LINUX_SYS_MAXSYSCALL, 175 native_to_linux_errno, NELEM(native_to_linux_errno), 176 linux_to_native_signo, NSIG, 0 }, 177 178 { "linux32", linux32_syscallnames, LINUX32_SYS_MAXSYSCALL, 179 native_to_linux_errno, NELEM(native_to_linux_errno), 180 linux_to_native_signo, NSIG, EMUL_FLAG_NETBSD32 }, 181 182 { "darwin", darwin_syscallnames, DARWIN_SYS_MAXSYSCALL, 183 NULL, 0, 184 NULL, 0, 0 }, 185 186 { "mach", mach_syscallnames, MACH_SYS_MAXSYSCALL, 187 NULL, 0, 188 NULL, 0, 0 }, 189 190 { "mach ppccalls", mach_ppccalls_syscallnames, 191 MACH_PPCCALLS_SYS_MAXSYSCALL, 192 NULL, 0, 193 NULL, 0, 0 }, 194 195 { "mach fasttraps", mach_fasttraps_syscallnames, 196 MACH_FASTTRAPS_SYS_MAXSYSCALL, 197 NULL, 0, 198 NULL, 0, 0 }, 199 200 { "osf1", osf1_syscallnames, OSF1_SYS_MAXSYSCALL, 201 native_to_osf1_errno, NELEM(native_to_osf1_errno), 202 osf1_to_native_signo, NSIG, 0 }, 203 204 { "sunos32", sunos32_syscallnames, SUNOS32_SYS_MAXSYSCALL, 205 NULL, 0, 206 NULL, 0, EMUL_FLAG_NETBSD32 }, 207 208 { "sunos", sunos_syscallnames, SUNOS_SYS_MAXSYSCALL, 209 NULL, 0, 210 NULL, 0, 0 }, 211 212 { "svr4", svr4_syscallnames, SVR4_SYS_MAXSYSCALL, 213 native_to_svr4_errno, NELEM(native_to_svr4_errno), 214 svr4_to_native_signo, NSIG, 0 }, 215 216 { "svr4_32", svr4_syscallnames, SVR4_SYS_MAXSYSCALL, 217 native_to_svr4_errno, NELEM(native_to_svr4_errno), 218 svr4_to_native_signo, NSIG, EMUL_FLAG_NETBSD32 }, 219 220 { "ultrix", ultrix_syscallnames, ULTRIX_SYS_MAXSYSCALL, 221 NULL, 0, 222 NULL, 0, 0 }, 223 224 { "pecoff", syscallnames, SYS_MAXSYSCALL, 225 NULL, 0, 226 NULL, 0, 0 }, 227 228 #ifdef __m68k__ 229 { "aoutm68k", aoutm68k_syscallnames, AOUTM68K_SYS_MAXSYSCALL, 230 NULL, 0, 231 NULL, 0, 0 }, 232 #endif 233 234 { NULL, NULL, 0, 235 NULL, 0, 236 NULL, 0, 0 } 237 }; 238 239 struct emulation_ctx { 240 pid_t pid; 241 const struct emulation *emulation; 242 LIST_ENTRY(emulation_ctx) ctx_link; 243 }; 244 245 const struct emulation *cur_emul; 246 const struct emulation *prev_emul; 247 /* Mach emulation require extra emulation contexts */ 248 static const struct emulation *mach; 249 static const struct emulation *mach_ppccalls; 250 static const struct emulation *mach_fasttraps; 251 252 static const struct emulation *default_emul = &emulations[0]; 253 254 struct emulation_ctx *current_ctx; 255 static LIST_HEAD(, emulation_ctx) emul_ctx = 256 LIST_HEAD_INITIALIZER(emul_ctx); 257 258 static struct emulation_ctx *ectx_find(pid_t); 259 static void ectx_update(pid_t, const struct emulation *); 260 261 void 262 setemul(const char *name, pid_t pid, int update_ectx) 263 { 264 int i; 265 const struct emulation *match = NULL; 266 267 for (i = 0; emulations[i].name != NULL; i++) { 268 if (strcmp(emulations[i].name, name) == 0) { 269 match = &emulations[i]; 270 break; 271 } 272 } 273 274 if (!match) { 275 warnx("Emulation `%s' unknown", name); 276 return; 277 } 278 279 if (update_ectx) 280 ectx_update(pid, match); 281 else 282 default_emul = match; 283 284 if (cur_emul != NULL) 285 prev_emul = cur_emul; 286 else 287 prev_emul = match; 288 289 cur_emul = match; 290 } 291 292 /* 293 * Emulation context list is very simple chained list, not even hashed. 294 * We expect the number of separate traced contexts/processes to be 295 * fairly low, so it's not worth it to optimize this. 296 * MMMmmmm not when I use it, it is only bounded PID_MAX! 297 * Requeue looked up item at start of list to cache result since the 298 * trace file tendes to have a burst of calls for a single process. 299 */ 300 301 /* 302 * Find an emulation context appropriate for the given pid. 303 */ 304 static struct emulation_ctx * 305 ectx_find(pid_t pid) 306 { 307 struct emulation_ctx *ctx; 308 309 /* Find an existing entry */ 310 LIST_FOREACH(ctx, &emul_ctx, ctx_link) { 311 if (ctx->pid == pid) 312 break; 313 } 314 315 if (ctx == NULL) { 316 /* create entry with default emulation */ 317 ctx = malloc(sizeof *ctx); 318 if (ctx == NULL) 319 err(1, "malloc emul context"); 320 ctx->pid = pid; 321 ctx->emulation = default_emul; 322 323 /* chain into the list */ 324 LIST_INSERT_HEAD(&emul_ctx, ctx, ctx_link); 325 } else { 326 /* move entry to head to optimize lookup for syscall bursts */ 327 LIST_REMOVE(ctx, ctx_link); 328 LIST_INSERT_HEAD(&emul_ctx, ctx, ctx_link); 329 } 330 331 return ctx; 332 } 333 334 /* 335 * Update emulation context for given pid, or create new if no context 336 * for this pid exists. 337 */ 338 static void 339 ectx_update(pid_t pid, const struct emulation *emul) 340 { 341 struct emulation_ctx *ctx; 342 343 ctx = ectx_find(pid); 344 ctx->emulation = emul; 345 } 346 347 /* 348 * Ensure current emulation context is correct for given pid. 349 */ 350 void 351 ectx_sanify(pid_t pid) 352 { 353 struct emulation_ctx *ctx; 354 355 ctx = ectx_find(pid); 356 cur_emul = ctx->emulation; 357 } 358 359 /* 360 * Delete emulation context for current pid. 361 * (eg when tracing exit()) 362 * Defer delete just in case we've cached a pointer... 363 */ 364 void 365 ectx_delete(void) 366 { 367 static struct emulation_ctx *ctx = NULL; 368 369 if (ctx != NULL) 370 free(ctx); 371 372 /* 373 * The emulation for current syscall entry is always on HEAD, due 374 * to code in ectx_find(). 375 */ 376 ctx = LIST_FIRST(&emul_ctx); 377 378 if (ctx) 379 LIST_REMOVE(ctx, ctx_link); 380 } 381 382 /* 383 * Temporarily modify code and emulations to handle Mach traps 384 * XXX The define are duplicated from sys/arch/powerpc/include/mach_syscall.c 385 */ 386 #define MACH_FASTTRAPS 0x00007ff0 387 #define MACH_PPCCALLS 0x00006000 388 #define MACH_ODD_SYSCALL_MASK 0x0000fff0 389 int 390 mach_traps_dispatch(int *code, const struct emulation **emul) 391 { 392 switch (*code & MACH_ODD_SYSCALL_MASK) { 393 case MACH_FASTTRAPS: 394 *emul = mach_fasttraps; 395 *code -= MACH_FASTTRAPS; 396 return 1; 397 398 case MACH_PPCCALLS: 399 *emul = mach_ppccalls; 400 *code -= MACH_PPCCALLS; 401 return 1; 402 403 default: 404 if (*code < 0 && *code > -MACH_SYS_MAXSYSCALL) { 405 *emul = mach; 406 *code = -*code; 407 return 1; 408 } 409 return 0; 410 } 411 } 412 413 /* 414 * Lookup Machs emulations 415 */ 416 void 417 mach_lookup_emul(void) 418 { 419 const struct emulation *emul_idx; 420 421 for (emul_idx = emulations; emul_idx->name; emul_idx++) { 422 if (strcmp("mach", emul_idx->name) == 0) 423 mach = emul_idx; 424 if (strcmp("mach fasttraps", emul_idx->name) == 0) 425 mach_fasttraps = emul_idx; 426 if (strcmp("mach ppccalls", emul_idx->name) == 0) 427 mach_ppccalls = emul_idx; 428 } 429 if (mach == NULL || mach_fasttraps == NULL || mach_ppccalls == NULL) { 430 errx(1, "Cannot load mach emulations"); 431 exit(1); 432 } 433 return; 434 } 435 436 /* 437 * Find the name of the Mach service responsible to a given message Id 438 */ 439 const char * 440 mach_service_name(id) 441 int id; 442 { 443 const char *retval = NULL; 444 #ifndef LETS_GET_SMALL 445 struct mach_service_name *srv; 446 447 for (srv = mach_services_names; srv->srv_id; srv++) 448 if (srv->srv_id == id) 449 break; 450 retval = srv->srv_name; 451 #endif /* LETS_GET_SMALL */ 452 453 return retval; 454 } 455