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