syscall.c revision d8ae7e332a15c12a488efa40136fa07f7dafa34b
1/* 2 * Copyright (c) 1991, 1992 Paul Kranenburg <pk@cs.few.eur.nl> 3 * Copyright (c) 1993 Branko Lankester <branko@hacktic.nl> 4 * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs@world.std.com> 5 * Copyright (c) 1996-1999 Wichert Akkerman <wichert@cistron.nl> 6 * Copyright (c) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation 7 * Linux for s390 port by D.J. Barrow 8 * <barrow_dj@mail.yahoo.com,djbarrow@de.ibm.com> 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. The name of the author may not be used to endorse or promote products 20 * derived from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 * 33 * $Id$ 34 */ 35 36#include "defs.h" 37 38#include <signal.h> 39#include <time.h> 40#include <errno.h> 41#include <sys/user.h> 42#include <sys/syscall.h> 43#include <sys/param.h> 44 45#if HAVE_ASM_REG_H 46#include <asm/reg.h> 47#endif 48 49#if HAVE_LINUX_PTRACE_H 50#undef PTRACE_SYSCALL 51#include <linux/ptrace.h> 52#endif 53 54#ifdef HAVE_SYS_REG_H 55#include <sys/reg.h> 56#ifndef PTRACE_PEEKUSR 57# define PTRACE_PEEKUSR PTRACE_PEEKUSER 58#endif 59#endif 60 61#ifndef SYS_ERRLIST_DECLARED 62extern int sys_nerr; 63extern char *sys_errlist[]; 64#endif /* SYS_ERRLIST_DECLARED */ 65 66#define NR_SYSCALL_BASE 0 67#ifdef LINUX 68#ifndef ERESTARTSYS 69#define ERESTARTSYS 512 70#endif 71#ifndef ERESTARTNOINTR 72#define ERESTARTNOINTR 513 73#endif 74#ifndef ERESTARTNOHAND 75#define ERESTARTNOHAND 514 /* restart if no handler.. */ 76#endif 77#ifndef ENOIOCTLCMD 78#define ENOIOCTLCMD 515 /* No ioctl command */ 79#endif 80#ifndef NSIG 81#define NSIG 32 82#endif 83#ifdef ARM 84#undef NSIG 85#define NSIG 32 86#undef NR_SYSCALL_BASE 87#define NR_SYSCALL_BASE __NR_SYSCALL_BASE 88#endif 89#endif /* LINUX */ 90 91#include "syscall.h" 92 93/* Define these shorthand notations to simplify the syscallent files. */ 94#define TF TRACE_FILE 95#define TI TRACE_IPC 96#define TN TRACE_NETWORK 97#define TP TRACE_PROCESS 98#define TS TRACE_SIGNAL 99 100struct sysent sysent0[] = { 101#include "syscallent.h" 102}; 103int nsyscalls0 = sizeof sysent0 / sizeof sysent0[0]; 104 105#if SUPPORTED_PERSONALITIES >= 2 106struct sysent sysent1[] = { 107#include "syscallent1.h" 108}; 109int nsyscalls1 = sizeof sysent1 / sizeof sysent1[0]; 110#endif /* SUPPORTED_PERSONALITIES >= 2 */ 111 112#if SUPPORTED_PERSONALITIES >= 3 113struct sysent sysent2[] = { 114#include "syscallent2.h" 115}; 116int nsyscalls2 = sizeof sysent2 / sizeof sysent2[0]; 117#endif /* SUPPORTED_PERSONALITIES >= 3 */ 118 119struct sysent *sysent; 120int nsyscalls; 121 122/* Now undef them since short defines cause wicked namespace pollution. */ 123#undef TF 124#undef TI 125#undef TN 126#undef TP 127#undef TS 128 129char *errnoent0[] = { 130#include "errnoent.h" 131}; 132int nerrnos0 = sizeof errnoent0 / sizeof errnoent0[0]; 133 134#if SUPPORTED_PERSONALITIES >= 2 135char *errnoent1[] = { 136#include "errnoent1.h" 137}; 138int nerrnos1 = sizeof errnoent1 / sizeof errnoent1[0]; 139#endif /* SUPPORTED_PERSONALITIES >= 2 */ 140 141#if SUPPORTED_PERSONALITIES >= 3 142char *errnoent2[] = { 143#include "errnoent2.h" 144}; 145int nerrnos2 = sizeof errnoent2 / sizeof errnoent2[0]; 146#endif /* SUPPORTED_PERSONALITIES >= 3 */ 147 148char **errnoent; 149int nerrnos; 150 151int current_personality; 152 153int 154set_personality(personality) 155int personality; 156{ 157 switch (personality) { 158 case 0: 159 errnoent = errnoent0; 160 nerrnos = nerrnos0; 161 sysent = sysent0; 162 nsyscalls = nsyscalls0; 163 ioctlent = ioctlent0; 164 nioctlents = nioctlents0; 165 signalent = signalent0; 166 nsignals = nsignals0; 167 break; 168 169#if SUPPORTED_PERSONALITIES >= 2 170 case 1: 171 errnoent = errnoent1; 172 nerrnos = nerrnos1; 173 sysent = sysent1; 174 nsyscalls = nsyscalls1; 175 ioctlent = ioctlent1; 176 nioctlents = nioctlents1; 177 signalent = signalent1; 178 nsignals = nsignals1; 179 break; 180#endif /* SUPPORTED_PERSONALITIES >= 2 */ 181 182#if SUPPORTED_PERSONALITIES >= 3 183 case 2: 184 errnoent = errnoent2; 185 nerrnos = nerrnos2; 186 sysent = sysent2; 187 nsyscalls = nsyscalls2; 188 ioctlent = ioctlent2; 189 nioctlents = nioctlents2; 190 signalent = signalent2; 191 nsignals = nsignals2; 192 break; 193#endif /* SUPPORTED_PERSONALITIES >= 3 */ 194 195 default: 196 return -1; 197 } 198 199 current_personality = personality; 200 return 0; 201} 202 203int qual_flags[MAX_QUALS]; 204 205static int call_count[MAX_QUALS]; 206static int error_count[MAX_QUALS]; 207static struct timeval tv_count[MAX_QUALS]; 208static int sorted_count[MAX_QUALS]; 209 210static struct timeval shortest = { 1000000, 0 }; 211 212static int lookup_syscall(), lookup_signal(), lookup_fault(), lookup_desc(); 213 214static struct qual_options { 215 int bitflag; 216 char *option_name; 217 int (*lookup)(); 218 char *argument_name; 219} qual_options[] = { 220 { QUAL_TRACE, "trace", lookup_syscall, "system call" }, 221 { QUAL_TRACE, "t", lookup_syscall, "system call" }, 222 { QUAL_ABBREV, "abbrev", lookup_syscall, "system call" }, 223 { QUAL_ABBREV, "a", lookup_syscall, "system call" }, 224 { QUAL_VERBOSE, "verbose", lookup_syscall, "system call" }, 225 { QUAL_VERBOSE, "v", lookup_syscall, "system call" }, 226 { QUAL_RAW, "raw", lookup_syscall, "system call" }, 227 { QUAL_RAW, "x", lookup_syscall, "system call" }, 228 { QUAL_SIGNAL, "signal", lookup_signal, "signal" }, 229 { QUAL_SIGNAL, "signals", lookup_signal, "signal" }, 230 { QUAL_SIGNAL, "s", lookup_signal, "signal" }, 231 { QUAL_FAULT, "fault", lookup_fault, "fault" }, 232 { QUAL_FAULT, "faults", lookup_fault, "fault" }, 233 { QUAL_FAULT, "m", lookup_fault, "fault" }, 234 { QUAL_READ, "read", lookup_desc, "descriptor" }, 235 { QUAL_READ, "reads", lookup_desc, "descriptor" }, 236 { QUAL_READ, "r", lookup_desc, "descriptor" }, 237 { QUAL_WRITE, "write", lookup_desc, "descriptor" }, 238 { QUAL_WRITE, "writes", lookup_desc, "descriptor" }, 239 { QUAL_WRITE, "w", lookup_desc, "descriptor" }, 240 { 0, NULL, NULL, NULL }, 241}; 242 243static int 244lookup_syscall(s) 245char *s; 246{ 247 int i; 248 249 for (i = 0; i < nsyscalls; i++) { 250 if (strcmp(s, sysent[i].sys_name) == 0) 251 return i; 252 } 253 return -1; 254} 255 256static int 257lookup_signal(s) 258char *s; 259{ 260 int i; 261 char buf[32]; 262 263 if (s && *s && isdigit(*s)) 264 return atoi(s); 265 strcpy(buf, s); 266 s = buf; 267 for (i = 0; s[i]; i++) 268 s[i] = toupper(s[i]); 269 if (strncmp(s, "SIG", 3) == 0) 270 s += 3; 271 for (i = 0; i <= NSIG; i++) { 272 if (strcmp(s, signame(i) + 3) == 0) 273 return i; 274 } 275 return -1; 276} 277 278static int 279lookup_fault(s) 280char *s; 281{ 282 return -1; 283} 284 285static int 286lookup_desc(s) 287char *s; 288{ 289 if (s && *s && isdigit(*s)) 290 return atoi(s); 291 return -1; 292} 293 294static int 295lookup_class(s) 296char *s; 297{ 298 if (strcmp(s, "file") == 0) 299 return TRACE_FILE; 300 if (strcmp(s, "ipc") == 0) 301 return TRACE_IPC; 302 if (strcmp(s, "network") == 0) 303 return TRACE_NETWORK; 304 if (strcmp(s, "process") == 0) 305 return TRACE_PROCESS; 306 if (strcmp(s, "signal") == 0) 307 return TRACE_SIGNAL; 308 return -1; 309} 310 311void 312qualify(s) 313char *s; 314{ 315 struct qual_options *opt; 316 int not; 317 char *p; 318 int i, n; 319 320 opt = &qual_options[0]; 321 for (i = 0; (p = qual_options[i].option_name); i++) { 322 n = strlen(p); 323 if (strncmp(s, p, n) == 0 && s[n] == '=') { 324 opt = &qual_options[i]; 325 s += n + 1; 326 break; 327 } 328 } 329 not = 0; 330 if (*s == '!') { 331 not = 1; 332 s++; 333 } 334 if (strcmp(s, "none") == 0) { 335 not = 1 - not; 336 s = "all"; 337 } 338 if (strcmp(s, "all") == 0) { 339 for (i = 0; i < MAX_QUALS; i++) { 340 if (not) 341 qual_flags[i] &= ~opt->bitflag; 342 else 343 qual_flags[i] |= opt->bitflag; 344 } 345 return; 346 } 347 for (i = 0; i < MAX_QUALS; i++) { 348 if (not) 349 qual_flags[i] |= opt->bitflag; 350 else 351 qual_flags[i] &= ~opt->bitflag; 352 } 353 for (p = strtok(s, ","); p; p = strtok(NULL, ",")) { 354 if (opt->bitflag == QUAL_TRACE && (n = lookup_class(p)) > 0) { 355 for (i = 0; i < MAX_QUALS; i++) { 356 if (sysent[i].sys_flags & n) { 357 if (not) 358 qual_flags[i] &= ~opt->bitflag; 359 else 360 qual_flags[i] |= opt->bitflag; 361 } 362 } 363 continue; 364 } 365 if ((n = (*opt->lookup)(p)) < 0) { 366 fprintf(stderr, "strace: invalid %s `%s'\n", 367 opt->argument_name, p); 368 exit(1); 369 } 370 if (not) 371 qual_flags[n] &= ~opt->bitflag; 372 else 373 qual_flags[n] |= opt->bitflag; 374 } 375 return; 376} 377 378static void 379dumpio(tcp) 380struct tcb *tcp; 381{ 382 if (syserror(tcp)) 383 return; 384 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= MAX_QUALS) 385 return; 386 switch (tcp->scno + NR_SYSCALL_BASE) { 387 case SYS_read: 388#ifdef SYS_recv 389 case SYS_recv: 390#endif 391#ifdef SYS_recvfrom 392 case SYS_recvfrom: 393#endif 394 if (qual_flags[tcp->u_arg[0]] & QUAL_READ) 395 dumpstr(tcp, tcp->u_arg[1], tcp->u_rval); 396 break; 397 case SYS_write: 398#ifdef SYS_send 399 case SYS_send: 400#endif 401#ifdef SYS_sendto 402 case SYS_sendto: 403#endif 404 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE) 405 dumpstr(tcp, tcp->u_arg[1], tcp->u_arg[2]); 406 break; 407 } 408} 409 410enum subcall_style { shift_style, deref_style, mask_style, door_style }; 411 412#if !(defined(LINUX) && ( defined(ALPHA) || defined(MIPS) )) 413 414const int socket_map [] = { 415 /* SYS_SOCKET */ 97, 416 /* SYS_BIND */ 104, 417 /* SYS_CONNECT */ 98, 418 /* SYS_LISTEN */ 106, 419 /* SYS_ACCEPT */ 99, 420 /* SYS_GETSOCKNAME */ 150, 421 /* SYS_GETPEERNAME */ 141, 422 /* SYS_SOCKETPAIR */ 135, 423 /* SYS_SEND */ 101, 424 /* SYS_RECV */ 102, 425 /* SYS_SENDTO */ 133, 426 /* SYS_RECVFROM */ 125, 427 /* SYS_SHUTDOWN */ 134, 428 /* SYS_SETSOCKOPT */ 105, 429 /* SYS_GETSOCKOPT */ 118, 430 /* SYS_SENDMSG */ 114, 431 /* SYS_RECVMSG */ 113 432}; 433 434void 435sparc_socket_decode (tcp) 436struct tcb *tcp; 437{ 438 volatile long addr; 439 volatile int i, n; 440 441 if (tcp->u_arg [0] < 1 || tcp->u_arg [0] > sizeof(socket_map)/sizeof(int)+1){ 442 return; 443 } 444 tcp->scno = socket_map [tcp->u_arg [0]-1]; 445 n = tcp->u_nargs = sysent [tcp->scno].nargs; 446 addr = tcp->u_arg [1]; 447 for (i = 0; i < n; i++){ 448 int arg; 449 if (umoven (tcp, addr, sizeof (arg), (void *) &arg) < 0) 450 arg = 0; 451 tcp->u_arg [i] = arg; 452 addr += sizeof (arg); 453 } 454} 455 456static void 457decode_subcall(tcp, subcall, nsubcalls, style) 458struct tcb *tcp; 459int subcall; 460int nsubcalls; 461enum subcall_style style; 462{ 463 int i, addr, mask, arg; 464 465 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls) 466 return; 467 switch (style) { 468 case shift_style: 469 tcp->scno = subcall + tcp->u_arg[0]; 470 if (sysent[tcp->scno].nargs != -1) 471 tcp->u_nargs = sysent[tcp->scno].nargs; 472 else 473 tcp->u_nargs--; 474 for (i = 0; i < tcp->u_nargs; i++) 475 tcp->u_arg[i] = tcp->u_arg[i + 1]; 476 break; 477 case deref_style: 478 tcp->scno = subcall + tcp->u_arg[0]; 479 addr = tcp->u_arg[1]; 480 for (i = 0; i < sysent[tcp->scno].nargs; i++) { 481 if (umove(tcp, addr, &arg) < 0) 482 arg = 0; 483 tcp->u_arg[i] = arg; 484 addr += sizeof(arg); 485 } 486 tcp->u_nargs = sysent[tcp->scno].nargs; 487 break; 488 case mask_style: 489 mask = (tcp->u_arg[0] >> 8) & 0xff; 490 tcp->u_arg[0] &= 0xff; 491 for (i = 0; mask; i++) 492 mask >>= 1; 493 tcp->scno = subcall + i; 494 if (sysent[tcp->scno].nargs != -1) 495 tcp->u_nargs = sysent[tcp->scno].nargs; 496 break; 497 case door_style: 498 /* 499 * Oh, yuck. The call code is the *sixth* argument. 500 */ 501 tcp->scno = subcall + tcp->u_arg[5]; 502 if (sysent[tcp->scno].nargs != -1) 503 tcp->u_nargs = sysent[tcp->scno].nargs; 504 else 505 tcp->u_nargs--; 506 break; 507 } 508} 509#endif 510 511struct tcb *tcp_last = NULL; 512 513static int 514internal_syscall(tcp) 515struct tcb *tcp; 516{ 517 /* 518 * We must always trace a few critical system calls in order to 519 * correctly support following forks in the presence of tracing 520 * qualifiers. 521 */ 522 switch (tcp->scno + NR_SYSCALL_BASE) { 523#ifdef SYS_fork 524 case SYS_fork: 525#endif 526#ifdef SYS_vfork 527 case SYS_vfork: 528#endif 529 internal_fork(tcp); 530 break; 531#ifdef SYS_clone 532 case SYS_clone: 533 internal_clone(tcp); 534 break; 535#endif 536#ifdef SYS_execv 537 case SYS_execv: 538#endif 539#ifdef SYS_execve 540 case SYS_execve: 541#endif 542 internal_exec(tcp); 543 break; 544 545#ifdef SYS_wait 546 case SYS_wait: 547#endif 548#ifdef SYS_wait4 549 case SYS_wait4: 550#endif 551#ifdef SYS_waitpid 552 case SYS_waitpid: 553#endif 554#ifdef SYS_waitsys 555 case SYS_waitsys: 556#endif 557 internal_wait(tcp); 558 break; 559 560#ifdef SYS_exit 561 case SYS_exit: 562#endif 563 internal_exit(tcp); 564 break; 565 } 566 return 0; 567} 568 569int 570trace_syscall(tcp) 571struct tcb *tcp; 572{ 573 int sys_res; 574 struct timeval tv; 575 long scno = 0; 576#ifdef LINUX 577#if defined (I386) 578 long eax; 579#elif defined (POWERPC) 580 long result,flags; 581#elif defined (M68K) 582 int d0; 583#elif defined (ARM) 584 int r0; 585#elif defined (ALPHA) 586 long r0; 587 long a3; 588#elif defined(MIPS) 589 long r2,a3; 590#elif defined (SPARC) 591 struct regs regs; 592 unsigned long trap; 593#elif defined(S390) 594 long gpr2; 595 long pc; 596#endif 597#endif /* LINUX */ 598 599#ifndef SVR4 600 int pid = tcp->pid; 601#endif /* !SVR4 */ 602 603 /* Measure the exit time as early as possible to avoid errors. */ 604 if (dtime && (tcp->flags & TCB_INSYSCALL)) 605 gettimeofday(&tv, NULL); 606#ifdef LINUX 607#if defined(S390) 608 if (upeek(tcp->pid,PT_PSWADDR,&pc) < 0) 609 return -1; 610 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)(pc-4),0); 611 if (errno) 612 return -1; 613 scno&=0xFF; 614#elif defined (POWERPC) 615 if (upeek(pid, 4*PT_R0, &scno) < 0) 616 return -1; 617 if (!(tcp->flags & TCB_INSYSCALL)) { 618 /* Check if we return from execve. */ 619 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) { 620 tcp->flags &= ~TCB_WAITEXECVE; 621 return 0; 622 } 623 } 624#elif defined (I386) 625 if (upeek(pid, 4*ORIG_EAX, &scno) < 0) 626 return -1; 627#elif defined (ARM) 628 { 629 long pc; 630 upeek(pid, 4*15, &pc); 631 umoven(tcp, pc-4, 4, (char *)&scno); 632 scno &= 0x000fffff; 633 } 634#elif defined (M68K) 635 if (upeek(pid, 4*PT_ORIG_D0, &scno) < 0) 636 return -1; 637#elif defined (MIPS) 638 if (upeek(pid, REG_A3, &a3) < 0) 639 return -1; 640 641 if(!(tcp->flags & TCB_INSYSCALL)) { 642 if (upeek(pid, REG_V0, &scno) < 0) 643 return -1; 644 645 if (scno < 0 || scno > nsyscalls) { 646 if(a3 == 0 || a3 == -1) { 647 if(debug) 648 fprintf (stderr, "stray syscall exit: v0 = %ld\n", scno); 649 return 0; 650 } 651 } 652 } else { 653 if (upeek(pid, REG_V0, &r2) < 0) 654 return -1; 655 } 656#elif defined (ALPHA) 657 if (upeek(pid, REG_A3, &a3) < 0) 658 return -1; 659 660 if (!(tcp->flags & TCB_INSYSCALL)) { 661 if (upeek(pid, REG_R0, &scno) < 0) 662 return -1; 663 664 /* Check if we return from execve. */ 665 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) { 666 tcp->flags &= ~TCB_WAITEXECVE; 667 return 0; 668 } 669 670 /* 671 * Do some sanity checks to figure out if it's 672 * really a syscall entry 673 */ 674 if (scno < 0 || scno > nsyscalls) { 675 if (a3 == 0 || a3 == -1) { 676 if (debug) 677 fprintf (stderr, "stray syscall exit: r0 = %ld\n", scno); 678 return 0; 679 } 680 } 681 } 682 else { 683 if (upeek(pid, REG_R0, &r0) < 0) 684 return -1; 685 } 686#elif defined (SPARC) 687 /* Everything we need is in the current register set. */ 688 if (ptrace(PTRACE_GETREGS,pid,(char *)®s,0) < 0) 689 return -1; 690 691 /* If we are entering, then disassemble the syscall trap. */ 692 if (!(tcp->flags & TCB_INSYSCALL)) { 693 /* Retrieve the syscall trap instruction. */ 694 errno = 0; 695 trap = ptrace(PTRACE_PEEKTEXT,pid,(char *)regs.r_pc,0); 696 if (errno) 697 return -1; 698 699 /* Disassemble the trap to see what personality to use. */ 700 switch (trap) { 701 case 0x91d02010: 702 /* Linux/SPARC syscall trap. */ 703 set_personality(0); 704 break; 705 case 0x91d0206d: 706 /* Linux/SPARC64 syscall trap. */ 707 fprintf(stderr,"syscall: Linux/SPARC64 not supported yet\n"); 708 return -1; 709 case 0x91d02000: 710 /* SunOS syscall trap. (pers 1) */ 711 fprintf(stderr,"syscall: SunOS no support\n"); 712 return -1; 713 case 0x91d02008: 714 /* Solaris 2.x syscall trap. (per 2) */ 715 set_personality(1); 716 break; 717 case 0x91d02009: 718 /* NetBSD/FreeBSD syscall trap. */ 719 fprintf(stderr,"syscall: NetBSD/FreeBSD not supported\n"); 720 return -1; 721 case 0x91d02027: 722 /* Solaris 2.x gettimeofday */ 723 set_personality(1); 724 break; 725 default: 726 /* Unknown syscall trap. */ 727 if(tcp->flags & TCB_WAITEXECVE) { 728 tcp->flags &= ~TCB_WAITEXECVE; 729 return 0; 730 } 731 fprintf(stderr,"syscall: unknown syscall trap %08x %08x\n", trap, regs.r_pc); 732 return -1; 733 } 734 735 /* Extract the system call number from the registers. */ 736 if (trap == 0x91d02027) 737 scno = 156; 738 else 739 scno = regs.r_g1; 740 if (scno == 0) { 741 scno = regs.r_o0; 742 memmove (®s.r_o0, ®s.r_o1, 7*sizeof(regs.r_o0)); 743 } 744 } 745#endif 746#endif /* LINUX */ 747#ifdef SUNOS4 748 if (upeek(pid, uoff(u_arg[7]), &scno) < 0) 749 return -1; 750#endif 751#ifdef SVR4 752#ifdef HAVE_PR_SYSCALL 753 scno = tcp->status.pr_syscall; 754#else /* !HAVE_PR_SYSCALL */ 755 scno = tcp->status.PR_WHAT; 756#endif /* !HAVE_PR_SYSCALL */ 757 if (!(tcp->flags & TCB_INSYSCALL)) { 758 if (tcp->status.PR_WHY != PR_SYSENTRY) { 759 if ( 760 scno == SYS_fork 761#ifdef SYS_vfork 762 || scno == SYS_vfork 763#endif /* SYS_vfork */ 764 ) { 765 /* We are returning in the child, fake it. */ 766 tcp->status.PR_WHY = PR_SYSENTRY; 767 trace_syscall(tcp); 768 tcp->status.PR_WHY = PR_SYSEXIT; 769 } 770 else { 771 fprintf(stderr, "syscall: missing entry\n"); 772 tcp->flags |= TCB_INSYSCALL; 773 } 774 } 775 } 776 else { 777 if (tcp->status.PR_WHY != PR_SYSEXIT) { 778 fprintf(stderr, "syscall: missing exit\n"); 779 tcp->flags &= ~TCB_INSYSCALL; 780 } 781 } 782#endif /* SVR4 */ 783#ifdef SUNOS4 784 if (!(tcp->flags & TCB_INSYSCALL)) { 785 if (scno == 0) { 786 fprintf(stderr, "syscall: missing entry\n"); 787 tcp->flags |= TCB_INSYSCALL; 788 } 789 } 790 else { 791 if (scno != 0) { 792 if (debug) { 793 /* 794 * This happens when a signal handler 795 * for a signal which interrupted a 796 * a system call makes another system call. 797 */ 798 fprintf(stderr, "syscall: missing exit\n"); 799 } 800 tcp->flags &= ~TCB_INSYSCALL; 801 } 802 } 803#endif /* SUNOS4 */ 804#ifdef LINUX 805#if defined (I386) 806 if (upeek(pid, 4*EAX, &eax) < 0) 807 return -1; 808 if (eax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) { 809 if (debug) 810 fprintf(stderr, "stray syscall exit: eax = %ld\n", eax); 811 return 0; 812 } 813#elif defined (POWERPC) 814# define SO_MASK 0x10000000 815 if (upeek(pid, 4*PT_CCR, &flags) < 0) 816 return -1; 817 if (upeek(pid, 4*PT_R3, &result) < 0) 818 return -1; 819 if (flags & SO_MASK) 820 result = -result; 821#elif defined (M68K) 822 if (upeek(pid, 4*PT_D0, &d0) < 0) 823 return -1; 824 if (d0 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) { 825 if (debug) 826 fprintf(stderr, "stray syscall exit: d0 = %ld\n", d0); 827 return 0; 828 } 829#elif defined (ARM) 830 if (upeek(pid, 4*0, (long *)&r0) < 0) 831 return -1; 832 if ( 0 && r0 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) { 833 if (debug) 834 fprintf(stderr, "stray syscall exit: d0 = %ld\n", r0); 835 return 0; 836 } 837#else 838#endif 839#endif /* LINUX */ 840 841 if (tcp->flags & TCB_INSYSCALL) { 842 long u_error; 843 844#ifdef LINUX 845#ifdef I386 846 if (eax < 0 && -eax < nerrnos) { 847 tcp->u_rval = -1; 848 u_error = -eax; 849 } 850 else { 851 tcp->u_rval = eax; 852 u_error = 0; 853 } 854#else /* !I386 */ 855#ifdef MIPS 856 if (a3) { 857 tcp->u_rval = -1; 858 u_error = r2; 859 } else { 860 tcp->u_rval = r2; 861 u_error = 0; 862 } 863#else 864#ifdef POWERPC 865 if (result && (unsigned) -result < nerrnos) { 866 tcp->u_rval = -1; 867 u_error = -result; 868 } 869 else { 870 tcp->u_rval = result; 871 u_error = 0; 872 } 873#else /* !POWERPC */ 874#ifdef M68K 875 if (d0 && (unsigned) -d0 < nerrnos) { 876 tcp->u_rval = -1; 877 u_error = -d0; 878 } 879 else { 880 tcp->u_rval = d0; 881 u_error = 0; 882 } 883#else /* !M68K */ 884#ifdef ARM 885 if (r0 && (unsigned) -r0 < nerrnos) { 886 tcp->u_rval = -1; 887 u_error = -r0; 888 } 889 else { 890 tcp->u_rval = r0; 891 u_error = 0; 892 } 893#else /* !ARM */ 894#ifdef ALPHA 895 if (a3) { 896 tcp->u_rval = -1; 897 u_error = r0; 898 } 899 else { 900 tcp->u_rval = r0; 901 u_error = 0; 902 } 903#else /* !ALPHA */ 904#ifdef SPARC 905 if (regs.r_psr & PSR_C) { 906 tcp->u_rval = -1; 907 u_error = regs.r_o0; 908 } 909 else { 910 tcp->u_rval = regs.r_o0; 911 u_error = 0; 912 } 913#endif /* SPARC */ 914#endif /* ALPHA */ 915#endif /* ARM */ 916#endif /* M68K */ 917#endif /* POWERPC */ 918#endif /* MIPS */ 919#endif /* I386 */ 920#endif /* LINUX */ 921#ifdef SUNOS4 922 /* get error code from user struct */ 923 if (upeek(pid, uoff(u_error), &u_error) < 0) 924 return -1; 925 u_error >>= 24; /* u_error is a char */ 926 927 /* get system call return value */ 928 if (upeek(pid, uoff(u_rval1), &tcp->u_rval) < 0) 929 return -1; 930#endif /* SUNOS4 */ 931#ifdef SVR4 932#ifdef SPARC 933 /* Judicious guessing goes a long way. */ 934 if (tcp->status.pr_reg[R_PSR] & 0x100000) { 935 tcp->u_rval = -1; 936 u_error = tcp->status.pr_reg[R_O0]; 937 } 938 else { 939 tcp->u_rval = tcp->status.pr_reg[R_O0]; 940 u_error = 0; 941 } 942#endif /* SPARC */ 943#ifdef I386 944 /* Wanna know how to kill an hour single-stepping? */ 945 if (tcp->status.PR_REG[EFL] & 0x1) { 946 tcp->u_rval = -1; 947 u_error = tcp->status.PR_REG[EAX]; 948 } 949 else { 950 tcp->u_rval = tcp->status.PR_REG[EAX]; 951 u_error = 0; 952 } 953#endif /* I386 */ 954#ifdef MIPS 955 if (tcp->status.pr_reg[CTX_A3]) { 956 tcp->u_rval = -1; 957 u_error = tcp->status.pr_reg[CTX_V0]; 958 } 959 else { 960 tcp->u_rval = tcp->status.pr_reg[CTX_V0]; 961 u_error = 0; 962 } 963#endif /* MIPS */ 964#endif /* SVR4 */ 965 tcp->u_error = u_error; 966 967 internal_syscall(tcp); 968 if (!(qual_flags[tcp->scno] & QUAL_TRACE)) { 969 tcp->flags &= ~TCB_INSYSCALL; 970 return 0; 971 } 972 973 if (tcp->flags & TCB_REPRINT) { 974 printleader(tcp); 975 tprintf("<... "); 976 if (tcp->scno >= nsyscalls) 977 tprintf("syscall_%lu", tcp->scno); 978 else 979 tprintf("%s", sysent[tcp->scno].sys_name); 980 tprintf(" resumed> "); 981 } 982 983 if (cflag) { 984 call_count[tcp->scno]++; 985 if (u_error) 986 error_count[tcp->scno]++; 987 tv_sub(&tv, &tv, &tcp->etime); 988#ifdef LINUX 989 if (tv_cmp(&tv, &tcp->dtime) > 0) { 990 static struct timeval one_tick = 991 { 0, 1000000 / HZ }; 992 993 if (tv_nz(&tcp->dtime)) 994 tv = tcp->dtime; 995 else if (tv_cmp(&tv, &one_tick) > 0) { 996 if (tv_cmp(&shortest, &one_tick) < 0) 997 tv = shortest; 998 else 999 tv = one_tick; 1000 } 1001 } 1002#endif /* LINUX */ 1003 if (tv_cmp(&tv, &shortest) < 0) 1004 shortest = tv; 1005 tv_add(&tv_count[tcp->scno], 1006 &tv_count[tcp->scno], &tv); 1007 tcp->flags &= ~TCB_INSYSCALL; 1008 return 0; 1009 } 1010 1011 if (tcp->scno >= nsyscalls 1012 || (qual_flags[tcp->scno] & QUAL_RAW)) 1013 sys_res = printargs(tcp); 1014 else 1015 sys_res = (*sysent[tcp->scno].sys_func)(tcp); 1016 u_error = tcp->u_error; 1017 tprintf(") "); 1018 tabto(acolumn); 1019 if (qual_flags[tcp->scno] & QUAL_RAW) { 1020 if (u_error) 1021 tprintf("= -1 (errno %ld)", u_error); 1022 else 1023 tprintf("= %#lx", tcp->u_rval); 1024 } 1025 else if (!(sys_res & RVAL_NONE) && u_error) { 1026#ifdef LINUX 1027 switch (u_error) { 1028 case ERESTARTSYS: 1029 tprintf("= ? ERESTARTSYS (To be restarted)"); 1030 break; 1031 case ERESTARTNOINTR: 1032 tprintf("= ? ERESTARTNOINTR (To be restarted)"); 1033 break; 1034 case ERESTARTNOHAND: 1035 tprintf("= ? ERESTARTNOHAND (To be restarted)"); 1036 break; 1037 default: 1038#endif /* LINUX */ 1039 tprintf("= -1 "); 1040 if (u_error < nerrnos && u_error < sys_nerr) 1041 tprintf("%s (%s)", errnoent[u_error], 1042 sys_errlist[u_error]); 1043 else if (u_error < nerrnos) 1044 tprintf("%s (errno %ld)", 1045 errnoent[u_error], u_error); 1046 else if (u_error < sys_nerr) 1047 tprintf("ERRNO_%ld (%s)", u_error, 1048 sys_errlist[u_error]); 1049 else 1050 tprintf("E??? (errno %ld)", u_error); 1051#ifdef LINUX 1052 break; 1053 } 1054#endif /* LINUX */ 1055 } 1056 else { 1057 if (sys_res & RVAL_NONE) 1058 tprintf("= ?"); 1059 else { 1060 switch (sys_res & RVAL_MASK) { 1061 case RVAL_HEX: 1062 tprintf("= %#lx", tcp->u_rval); 1063 break; 1064 case RVAL_OCTAL: 1065 tprintf("= %#lo", tcp->u_rval); 1066 break; 1067 case RVAL_UDECIMAL: 1068 tprintf("= %lu", tcp->u_rval); 1069 break; 1070 case RVAL_DECIMAL: 1071 tprintf("= %ld", tcp->u_rval); 1072 break; 1073 default: 1074 fprintf(stderr, 1075 "invalid rval format\n"); 1076 break; 1077 } 1078 } 1079 if ((sys_res & RVAL_STR) && tcp->auxstr) 1080 tprintf(" (%s)", tcp->auxstr); 1081 } 1082 if (dtime) { 1083 tv_sub(&tv, &tv, &tcp->etime); 1084 tprintf(" <%ld.%06ld>", 1085 (long) tv.tv_sec, (long) tv.tv_usec); 1086 } 1087 printtrailer(tcp); 1088 1089 dumpio(tcp); 1090 if (fflush(tcp->outf) == EOF) 1091 return -1; 1092 tcp->flags &= ~TCB_INSYSCALL; 1093 return 0; 1094 } 1095 1096 /* Entering system call */ 1097 tcp->scno = scno; 1098#ifdef LINUX 1099#if defined(S390) 1100 { 1101 int i; 1102 tcp->u_nargs = sysent[tcp->scno].nargs; 1103 for (i = 0; i < tcp->u_nargs; i++) { 1104 if (upeek(pid,i==0 ? PT_ORIGGPR2:PT_GPR2+(i<<2), &tcp->u_arg[i]) < 0) 1105 return -1; 1106 } 1107 } 1108#elif defined (ALPHA) 1109 { 1110 int i; 1111 tcp->u_nargs = sysent[tcp->scno].nargs; 1112 for (i = 0; i < tcp->u_nargs; i++) { 1113 /* WTA: if scno is out-of-bounds this will bomb. Add range-check 1114 * for scno somewhere above here! 1115 */ 1116 if (upeek(pid, REG_A0+i, &tcp->u_arg[i]) < 0) 1117 return -1; 1118 } 1119 } 1120#elif defined (MIPS) 1121 { 1122 long sp; 1123 int i, nargs; 1124 1125 nargs = tcp->u_nargs = sysent[tcp->scno].nargs; 1126 if(nargs > 4) { 1127 if(upeek(pid, REG_SP, &sp) < 0) 1128 return -1; 1129 for(i = 0; i < 4; i++) { 1130 if (upeek(pid, REG_A0 + i, &tcp->u_arg[i])<0) 1131 return -1; 1132 } 1133 umoven(tcp, sp+16, (nargs-4) * sizeof(tcp->u_arg[0]), 1134 (char *)(tcp->u_arg + 4)); 1135 } else { 1136 for(i = 0; i < nargs; i++) { 1137 if (upeek(pid, REG_A0 + i, &tcp->u_arg[i]) < 0) 1138 return -1; 1139 } 1140 } 1141 } 1142#elif defined (POWERPC) 1143 { 1144 int i; 1145 tcp->u_nargs = sysent[tcp->scno].nargs; 1146 for (i = 0; i < tcp->u_nargs; i++) { 1147 if (upeek(pid, (i==0) ? (4*PT_ORIG_R3) : ((i+PT_R3)*4), &tcp->u_arg[i]) < 0) 1148 return -1; 1149 } 1150 } 1151#elif defined (SPARC) 1152 { 1153 int i; 1154 1155 tcp->u_nargs = sysent[tcp->scno].nargs; 1156 for (i = 0; i < tcp->u_nargs; i++) 1157 tcp->u_arg[i] = *((®s.r_o0) + i); 1158 } 1159#else 1160 { 1161 int i; 1162 tcp->u_nargs = sysent[tcp->scno].nargs; 1163 for (i = 0; i < tcp->u_nargs; i++) { 1164 if (upeek(pid, i*4, &tcp->u_arg[i]) < 0) 1165 return -1; 1166 } 1167 } 1168#endif 1169#endif /* LINUX */ 1170#ifdef SUNOS4 1171 { 1172 int i; 1173 tcp->u_nargs = sysent[tcp->scno].nargs; 1174 for (i = 0; i < tcp->u_nargs; i++) { 1175 struct user *u; 1176 1177 if (upeek(pid, uoff(u_arg[0]) + 1178 (i*sizeof(u->u_arg[0])), &tcp->u_arg[i]) < 0) 1179 return -1; 1180 } 1181 } 1182#endif /* SUNOS4 */ 1183#ifdef SVR4 1184#ifdef MIPS 1185 /* 1186 * SGI is broken: even though it has pr_sysarg, it doesn't 1187 * set them on system call entry. Get a clue. 1188 */ 1189 if (sysent[tcp->scno].nargs != -1) 1190 tcp->u_nargs = sysent[tcp->scno].nargs; 1191 else 1192 tcp->u_nargs = tcp->status.pr_nsysarg; 1193 if (tcp->u_nargs > 4) { 1194 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0], 1195 4*sizeof(tcp->u_arg[0])); 1196 umoven(tcp, tcp->status.pr_reg[CTX_SP] + 16, 1197 (tcp->u_nargs - 4)*sizeof(tcp->u_arg[0]), (char *) (tcp->u_arg + 4)); 1198 } 1199 else { 1200 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0], 1201 tcp->u_nargs*sizeof(tcp->u_arg[0])); 1202 } 1203#else /* !MIPS */ 1204#ifdef HAVE_PR_SYSCALL 1205 if (sysent[tcp->scno].nargs != -1) 1206 tcp->u_nargs = sysent[tcp->scno].nargs; 1207 else 1208 tcp->u_nargs = tcp->status.pr_nsysarg; 1209 { 1210 int i; 1211 for (i = 0; i < tcp->u_nargs; i++) 1212 tcp->u_arg[i] = tcp->status.pr_sysarg[i]; 1213 } 1214#else /* !HAVE_PR_SYSCALL */ 1215#ifdef I386 1216 if (sysent[tcp->scno].nargs != -1) 1217 tcp->u_nargs = sysent[tcp->scno].nargs; 1218 else 1219#if UNIXWARE >= 2 1220 tcp->u_nargs = tcp->status.pr_lwp.pr_nsysarg; 1221#else 1222 tcp->u_nargs = 5; 1223#endif 1224 umoven(tcp, tcp->status.PR_REG[UESP] + 4, 1225 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg); 1226#endif /* I386 */ 1227#endif /* !HAVE_PR_SYSCALL */ 1228#endif /* !MIPS */ 1229#endif /* SVR4 */ 1230 switch (tcp->scno + NR_SYSCALL_BASE) { 1231#ifdef LINUX 1232#if !defined (ALPHA) && !defined(SPARC) && !defined(MIPS) 1233 case SYS_socketcall: 1234 decode_subcall(tcp, SYS_socket_subcall, 1235 SYS_socket_nsubcalls, deref_style); 1236 break; 1237 case SYS_ipc: 1238 decode_subcall(tcp, SYS_ipc_subcall, 1239 SYS_ipc_nsubcalls, shift_style); 1240 break; 1241#endif /* !ALPHA && !SPARC */ 1242#ifdef SPARC 1243 case SYS_socketcall: 1244 sparc_socket_decode (tcp); 1245 break; 1246#endif 1247#endif /* LINUX */ 1248#ifdef SVR4 1249#ifdef SYS_pgrpsys_subcall 1250 case SYS_pgrpsys: 1251 decode_subcall(tcp, SYS_pgrpsys_subcall, 1252 SYS_pgrpsys_nsubcalls, shift_style); 1253 break; 1254#endif /* SYS_pgrpsys_subcall */ 1255#ifdef SYS_sigcall_subcall 1256 case SYS_sigcall: 1257 decode_subcall(tcp, SYS_sigcall_subcall, 1258 SYS_sigcall_nsubcalls, mask_style); 1259 break; 1260#endif /* SYS_sigcall_subcall */ 1261 case SYS_msgsys: 1262 decode_subcall(tcp, SYS_msgsys_subcall, 1263 SYS_msgsys_nsubcalls, shift_style); 1264 break; 1265 case SYS_shmsys: 1266 decode_subcall(tcp, SYS_shmsys_subcall, 1267 SYS_shmsys_nsubcalls, shift_style); 1268 break; 1269 case SYS_semsys: 1270 decode_subcall(tcp, SYS_semsys_subcall, 1271 SYS_semsys_nsubcalls, shift_style); 1272 break; 1273#if 0 /* broken */ 1274 case SYS_utssys: 1275 decode_subcall(tcp, SYS_utssys_subcall, 1276 SYS_utssys_nsubcalls, shift_style); 1277 break; 1278#endif 1279 case SYS_sysfs: 1280 decode_subcall(tcp, SYS_sysfs_subcall, 1281 SYS_sysfs_nsubcalls, shift_style); 1282 break; 1283 case SYS_spcall: 1284 decode_subcall(tcp, SYS_spcall_subcall, 1285 SYS_spcall_nsubcalls, shift_style); 1286 break; 1287#ifdef SYS_context_subcall 1288 case SYS_context: 1289 decode_subcall(tcp, SYS_context_subcall, 1290 SYS_context_nsubcalls, shift_style); 1291 break; 1292#endif /* SYS_context_subcall */ 1293#ifdef SYS_door_subcall 1294 case SYS_door: 1295 decode_subcall(tcp, SYS_door_subcall, 1296 SYS_door_nsubcalls, door_style); 1297 break; 1298#endif /* SYS_door_subcall */ 1299#endif /* SVR4 */ 1300#ifdef SUNOS4 1301 case SYS_semsys: 1302 decode_subcall(tcp, SYS_semsys_subcall, 1303 SYS_semsys_nsubcalls, shift_style); 1304 break; 1305 case SYS_msgsys: 1306 decode_subcall(tcp, SYS_msgsys_subcall, 1307 SYS_msgsys_nsubcalls, shift_style); 1308 break; 1309 case SYS_shmsys: 1310 decode_subcall(tcp, SYS_shmsys_subcall, 1311 SYS_shmsys_nsubcalls, shift_style); 1312 break; 1313#endif 1314 } 1315 1316 internal_syscall(tcp); 1317 if (!(qual_flags[tcp->scno] & QUAL_TRACE)) { 1318 tcp->flags |= TCB_INSYSCALL; 1319 return 0; 1320 } 1321 1322 if (cflag) { 1323 gettimeofday(&tcp->etime, NULL); 1324 tcp->flags |= TCB_INSYSCALL; 1325 return 0; 1326 } 1327 1328 printleader(tcp); 1329 tcp->flags &= ~TCB_REPRINT; 1330 tcp_last = tcp; 1331 if (tcp->scno >= nsyscalls) 1332 tprintf("syscall_%lu(", tcp->scno); 1333 else 1334 tprintf("%s(", sysent[tcp->scno].sys_name); 1335 if (tcp->scno >= nsyscalls || 1336 ((qual_flags[tcp->scno] & QUAL_RAW) && tcp->scno != SYS_exit)) 1337 sys_res = printargs(tcp); 1338 else 1339 sys_res = (*sysent[tcp->scno].sys_func)(tcp); 1340 if (fflush(tcp->outf) == EOF) 1341 return -1; 1342 tcp->flags |= TCB_INSYSCALL; 1343 /* Measure the entrance time as late as possible to avoid errors. */ 1344 if (dtime) 1345 gettimeofday(&tcp->etime, NULL); 1346 return sys_res; 1347} 1348 1349int 1350printargs(tcp) 1351struct tcb *tcp; 1352{ 1353 if (entering(tcp)) { 1354 int i; 1355 1356 for (i = 0; i < tcp->u_nargs; i++) 1357 tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]); 1358 } 1359 return 0; 1360} 1361 1362long 1363getrval2(tcp) 1364struct tcb *tcp; 1365{ 1366 long val = -1; 1367 1368#ifdef LINUX 1369#ifdef SPARC 1370 struct regs regs; 1371 if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)®s,0) < 0) 1372 return -1; 1373 val = regs.r_o1; 1374#endif /* SPARC */ 1375#endif /* LINUX */ 1376 1377#ifdef SUNOS4 1378 if (upeek(tcp->pid, uoff(u_rval2), &val) < 0) 1379 return -1; 1380#endif /* SUNOS4 */ 1381 1382#ifdef SVR4 1383#ifdef SPARC 1384 val = tcp->status.PR_REG[R_O1]; 1385#endif /* SPARC */ 1386#ifdef I386 1387 val = tcp->status.PR_REG[EDX]; 1388#endif /* I386 */ 1389#ifdef MIPS 1390 val = tcp->status.PR_REG[CTX_V1]; 1391#endif /* MIPS */ 1392#endif /* SVR4 */ 1393 1394 return val; 1395} 1396 1397/* 1398 * Apparently, indirect system calls have already be converted by ptrace(2), 1399 * so if you see "indir" this program has gone astray. 1400 */ 1401int 1402sys_indir(tcp) 1403struct tcb *tcp; 1404{ 1405 int i, scno, nargs; 1406 1407 if (entering(tcp)) { 1408 if ((scno = tcp->u_arg[0]) > nsyscalls) { 1409 fprintf(stderr, "Bogus syscall: %u\n", scno); 1410 return 0; 1411 } 1412 nargs = sysent[scno].nargs; 1413 tprintf("%s", sysent[scno].sys_name); 1414 for (i = 0; i < nargs; i++) 1415 tprintf(", %#lx", tcp->u_arg[i+1]); 1416 } 1417 return 0; 1418} 1419 1420static int 1421time_cmp(a, b) 1422void *a; 1423void *b; 1424{ 1425 return -tv_cmp(&tv_count[*((int *) a)], &tv_count[*((int *) b)]); 1426} 1427 1428static int 1429syscall_cmp(a, b) 1430void *a; 1431void *b; 1432{ 1433 return strcmp(sysent[*((int *) a)].sys_name, 1434 sysent[*((int *) b)].sys_name); 1435} 1436 1437static int 1438count_cmp(a, b) 1439void *a; 1440void *b; 1441{ 1442 int m = call_count[*((int *) a)], n = call_count[*((int *) b)]; 1443 1444 return (m < n) ? 1 : (m > n) ? -1 : 0; 1445} 1446 1447static int (*sortfun)(); 1448static struct timeval overhead = { -1, -1 }; 1449 1450void 1451set_sortby(sortby) 1452char *sortby; 1453{ 1454 if (strcmp(sortby, "time") == 0) 1455 sortfun = time_cmp; 1456 else if (strcmp(sortby, "calls") == 0) 1457 sortfun = count_cmp; 1458 else if (strcmp(sortby, "name") == 0) 1459 sortfun = syscall_cmp; 1460 else if (strcmp(sortby, "nothing") == 0) 1461 sortfun = NULL; 1462 else { 1463 fprintf(stderr, "invalid sortby: `%s'\n", sortby); 1464 exit(1); 1465 } 1466} 1467 1468void set_overhead(n) 1469int n; 1470{ 1471 overhead.tv_sec = n / 1000000; 1472 overhead.tv_usec = n % 1000000; 1473} 1474 1475void 1476call_summary(outf) 1477FILE *outf; 1478{ 1479 int i, j; 1480 int call_cum, error_cum; 1481 struct timeval tv_cum, dtv; 1482 double percent; 1483 char *dashes = "-------------------------"; 1484 char error_str[16]; 1485 1486 call_cum = error_cum = tv_cum.tv_sec = tv_cum.tv_usec = 0; 1487 if (overhead.tv_sec == -1) { 1488 tv_mul(&overhead, &shortest, 8); 1489 tv_div(&overhead, &overhead, 10); 1490 } 1491 for (i = 0; i < nsyscalls; i++) { 1492 sorted_count[i] = i; 1493 if (call_count[i] == 0) 1494 continue; 1495 tv_mul(&dtv, &overhead, call_count[i]); 1496 tv_sub(&tv_count[i], &tv_count[i], &dtv); 1497 call_cum += call_count[i]; 1498 error_cum += error_count[i]; 1499 tv_add(&tv_cum, &tv_cum, &tv_count[i]); 1500 } 1501 if (sortfun) 1502 qsort((void *) sorted_count, nsyscalls, sizeof(int), sortfun); 1503 fprintf(outf, "%6.6s %11.11s %11.11s %9.9s %9.9s %s\n", 1504 "% time", "seconds", "usecs/call", 1505 "calls", "errors", "syscall"); 1506 fprintf(outf, "%6.6s %11.11s %11.11s %9.9s %9.9s %-16.16s\n", 1507 dashes, dashes, dashes, dashes, dashes, dashes); 1508 for (i = 0; i < nsyscalls; i++) { 1509 j = sorted_count[i]; 1510 if (call_count[j] == 0) 1511 continue; 1512 tv_div(&dtv, &tv_count[j], call_count[j]); 1513 if (error_count[j]) 1514 sprintf(error_str, "%d", error_count[j]); 1515 else 1516 error_str[0] = '\0'; 1517 percent = 100.0*tv_float(&tv_count[j])/tv_float(&tv_cum); 1518 fprintf(outf, "%6.2f %4ld.%06ld %11ld %9d %9.9s %s\n", 1519 percent, (long) tv_count[j].tv_sec, 1520 (long) tv_count[j].tv_usec, 1521 (long) 1000000 * dtv.tv_sec + dtv.tv_usec, 1522 call_count[j], error_str, sysent[j].sys_name); 1523 } 1524 fprintf(outf, "%6.6s %11.11s %11.11s %9.9s %9.9s %-16.16s\n", 1525 dashes, dashes, dashes, dashes, dashes, dashes); 1526 if (error_cum) 1527 sprintf(error_str, "%d", error_cum); 1528 else 1529 error_str[0] = '\0'; 1530 fprintf(outf, "%6.6s %4ld.%06ld %11.11s %9d %9.9s %s\n", 1531 "100.00", (long) tv_cum.tv_sec, (long) tv_cum.tv_usec, "", 1532 call_cum, error_str, "total"); 1533} 1534