syscall.c revision 53b320f61f9c5f4278db227ed21db5a1937d58c3
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#ifdef SPARC 47# define fpq kernel_fpq 48# define fq kernel_fq 49# define fpu kernel_fpu 50#endif 51#include <asm/reg.h> 52#ifdef SPARC 53# undef fpq 54# undef fq 55# undef fpu 56#endif 57#endif 58 59#ifdef HAVE_SYS_REG_H 60#include <sys/reg.h> 61#ifndef PTRACE_PEEKUSR 62# define PTRACE_PEEKUSR PTRACE_PEEKUSER 63#endif 64#elif defined(HAVE_LINUX_PTRACE_H) 65#undef PTRACE_SYSCALL 66#include <linux/ptrace.h> 67#endif 68 69#if defined(LINUX) && defined(IA64) 70# include <asm/ptrace_offsets.h> 71# include <asm/rse.h> 72#endif 73 74#ifndef SYS_ERRLIST_DECLARED 75extern int sys_nerr; 76extern char *sys_errlist[]; 77#endif /* SYS_ERRLIST_DECLARED */ 78 79#define NR_SYSCALL_BASE 0 80#ifdef LINUX 81#ifndef ERESTARTSYS 82#define ERESTARTSYS 512 83#endif 84#ifndef ERESTARTNOINTR 85#define ERESTARTNOINTR 513 86#endif 87#ifndef ERESTARTNOHAND 88#define ERESTARTNOHAND 514 /* restart if no handler.. */ 89#endif 90#ifndef ENOIOCTLCMD 91#define ENOIOCTLCMD 515 /* No ioctl command */ 92#endif 93#ifndef NSIG 94#define NSIG 32 95#endif 96#ifdef ARM 97#undef NSIG 98#define NSIG 32 99#undef NR_SYSCALL_BASE 100#define NR_SYSCALL_BASE __NR_SYSCALL_BASE 101#endif 102#endif /* LINUX */ 103 104#include "syscall.h" 105 106/* Define these shorthand notations to simplify the syscallent files. */ 107#define TF TRACE_FILE 108#define TI TRACE_IPC 109#define TN TRACE_NETWORK 110#define TP TRACE_PROCESS 111#define TS TRACE_SIGNAL 112 113struct sysent sysent0[] = { 114#include "syscallent.h" 115}; 116int nsyscalls0 = sizeof sysent0 / sizeof sysent0[0]; 117 118#if SUPPORTED_PERSONALITIES >= 2 119struct sysent sysent1[] = { 120#include "syscallent1.h" 121}; 122int nsyscalls1 = sizeof sysent1 / sizeof sysent1[0]; 123#endif /* SUPPORTED_PERSONALITIES >= 2 */ 124 125#if SUPPORTED_PERSONALITIES >= 3 126struct sysent sysent2[] = { 127#include "syscallent2.h" 128}; 129int nsyscalls2 = sizeof sysent2 / sizeof sysent2[0]; 130#endif /* SUPPORTED_PERSONALITIES >= 3 */ 131 132struct sysent *sysent; 133int nsyscalls; 134 135/* Now undef them since short defines cause wicked namespace pollution. */ 136#undef TF 137#undef TI 138#undef TN 139#undef TP 140#undef TS 141 142char *errnoent0[] = { 143#include "errnoent.h" 144}; 145int nerrnos0 = sizeof errnoent0 / sizeof errnoent0[0]; 146 147#if SUPPORTED_PERSONALITIES >= 2 148char *errnoent1[] = { 149#include "errnoent1.h" 150}; 151int nerrnos1 = sizeof errnoent1 / sizeof errnoent1[0]; 152#endif /* SUPPORTED_PERSONALITIES >= 2 */ 153 154#if SUPPORTED_PERSONALITIES >= 3 155char *errnoent2[] = { 156#include "errnoent2.h" 157}; 158int nerrnos2 = sizeof errnoent2 / sizeof errnoent2[0]; 159#endif /* SUPPORTED_PERSONALITIES >= 3 */ 160 161char **errnoent; 162int nerrnos; 163 164int current_personality; 165 166int 167set_personality(personality) 168int personality; 169{ 170 switch (personality) { 171 case 0: 172 errnoent = errnoent0; 173 nerrnos = nerrnos0; 174 sysent = sysent0; 175 nsyscalls = nsyscalls0; 176 ioctlent = ioctlent0; 177 nioctlents = nioctlents0; 178 signalent = signalent0; 179 nsignals = nsignals0; 180 break; 181 182#if SUPPORTED_PERSONALITIES >= 2 183 case 1: 184 errnoent = errnoent1; 185 nerrnos = nerrnos1; 186 sysent = sysent1; 187 nsyscalls = nsyscalls1; 188 ioctlent = ioctlent1; 189 nioctlents = nioctlents1; 190 signalent = signalent1; 191 nsignals = nsignals1; 192 break; 193#endif /* SUPPORTED_PERSONALITIES >= 2 */ 194 195#if SUPPORTED_PERSONALITIES >= 3 196 case 2: 197 errnoent = errnoent2; 198 nerrnos = nerrnos2; 199 sysent = sysent2; 200 nsyscalls = nsyscalls2; 201 ioctlent = ioctlent2; 202 nioctlents = nioctlents2; 203 signalent = signalent2; 204 nsignals = nsignals2; 205 break; 206#endif /* SUPPORTED_PERSONALITIES >= 3 */ 207 208 default: 209 return -1; 210 } 211 212 current_personality = personality; 213 return 0; 214} 215 216int qual_flags[MAX_QUALS]; 217 218static int call_count[MAX_QUALS]; 219static int error_count[MAX_QUALS]; 220static struct timeval tv_count[MAX_QUALS]; 221static int sorted_count[MAX_QUALS]; 222 223static struct timeval shortest = { 1000000, 0 }; 224 225static int lookup_syscall(), lookup_signal(), lookup_fault(), lookup_desc(); 226 227static struct qual_options { 228 int bitflag; 229 char *option_name; 230 int (*lookup)(); 231 char *argument_name; 232} qual_options[] = { 233 { QUAL_TRACE, "trace", lookup_syscall, "system call" }, 234 { QUAL_TRACE, "t", lookup_syscall, "system call" }, 235 { QUAL_ABBREV, "abbrev", lookup_syscall, "system call" }, 236 { QUAL_ABBREV, "a", lookup_syscall, "system call" }, 237 { QUAL_VERBOSE, "verbose", lookup_syscall, "system call" }, 238 { QUAL_VERBOSE, "v", lookup_syscall, "system call" }, 239 { QUAL_RAW, "raw", lookup_syscall, "system call" }, 240 { QUAL_RAW, "x", lookup_syscall, "system call" }, 241 { QUAL_SIGNAL, "signal", lookup_signal, "signal" }, 242 { QUAL_SIGNAL, "signals", lookup_signal, "signal" }, 243 { QUAL_SIGNAL, "s", lookup_signal, "signal" }, 244 { QUAL_FAULT, "fault", lookup_fault, "fault" }, 245 { QUAL_FAULT, "faults", lookup_fault, "fault" }, 246 { QUAL_FAULT, "m", lookup_fault, "fault" }, 247 { QUAL_READ, "read", lookup_desc, "descriptor" }, 248 { QUAL_READ, "reads", lookup_desc, "descriptor" }, 249 { QUAL_READ, "r", lookup_desc, "descriptor" }, 250 { QUAL_WRITE, "write", lookup_desc, "descriptor" }, 251 { QUAL_WRITE, "writes", lookup_desc, "descriptor" }, 252 { QUAL_WRITE, "w", lookup_desc, "descriptor" }, 253 { 0, NULL, NULL, NULL }, 254}; 255 256static int 257lookup_syscall(s) 258char *s; 259{ 260 int i; 261 262 for (i = 0; i < nsyscalls; i++) { 263 if (strcmp(s, sysent[i].sys_name) == 0) 264 return i; 265 } 266 return -1; 267} 268 269static int 270lookup_signal(s) 271char *s; 272{ 273 int i; 274 char buf[32]; 275 276 if (s && *s && isdigit((unsigned char)*s)) 277 return atoi(s); 278 strcpy(buf, s); 279 s = buf; 280 for (i = 0; s[i]; i++) 281 s[i] = toupper((unsigned char)(s[i])); 282 if (strncmp(s, "SIG", 3) == 0) 283 s += 3; 284 for (i = 0; i <= NSIG; i++) { 285 if (strcmp(s, signame(i) + 3) == 0) 286 return i; 287 } 288 return -1; 289} 290 291static int 292lookup_fault(s) 293char *s; 294{ 295 return -1; 296} 297 298static int 299lookup_desc(s) 300char *s; 301{ 302 if (s && *s && isdigit((unsigned char)*s)) 303 return atoi(s); 304 return -1; 305} 306 307static int 308lookup_class(s) 309char *s; 310{ 311 if (strcmp(s, "file") == 0) 312 return TRACE_FILE; 313 if (strcmp(s, "ipc") == 0) 314 return TRACE_IPC; 315 if (strcmp(s, "network") == 0) 316 return TRACE_NETWORK; 317 if (strcmp(s, "process") == 0) 318 return TRACE_PROCESS; 319 if (strcmp(s, "signal") == 0) 320 return TRACE_SIGNAL; 321 return -1; 322} 323 324void 325qualify(s) 326char *s; 327{ 328 struct qual_options *opt; 329 int not; 330 char *p; 331 int i, n; 332 333 opt = &qual_options[0]; 334 for (i = 0; (p = qual_options[i].option_name); i++) { 335 n = strlen(p); 336 if (strncmp(s, p, n) == 0 && s[n] == '=') { 337 opt = &qual_options[i]; 338 s += n + 1; 339 break; 340 } 341 } 342 not = 0; 343 if (*s == '!') { 344 not = 1; 345 s++; 346 } 347 if (strcmp(s, "none") == 0) { 348 not = 1 - not; 349 s = "all"; 350 } 351 if (strcmp(s, "all") == 0) { 352 for (i = 0; i < MAX_QUALS; i++) { 353 if (not) 354 qual_flags[i] &= ~opt->bitflag; 355 else 356 qual_flags[i] |= opt->bitflag; 357 } 358 return; 359 } 360 for (i = 0; i < MAX_QUALS; i++) { 361 if (not) 362 qual_flags[i] |= opt->bitflag; 363 else 364 qual_flags[i] &= ~opt->bitflag; 365 } 366 for (p = strtok(s, ","); p; p = strtok(NULL, ",")) { 367 if (opt->bitflag == QUAL_TRACE && (n = lookup_class(p)) > 0) { 368 for (i = 0; i < MAX_QUALS; i++) { 369 if (sysent[i].sys_flags & n) { 370 if (not) 371 qual_flags[i] &= ~opt->bitflag; 372 else 373 qual_flags[i] |= opt->bitflag; 374 } 375 } 376 continue; 377 } 378 if ((n = (*opt->lookup)(p)) < 0) { 379 fprintf(stderr, "strace: invalid %s `%s'\n", 380 opt->argument_name, p); 381 exit(1); 382 } 383 if (not) 384 qual_flags[n] &= ~opt->bitflag; 385 else 386 qual_flags[n] |= opt->bitflag; 387 } 388 return; 389} 390 391static void 392dumpio(tcp) 393struct tcb *tcp; 394{ 395 if (syserror(tcp)) 396 return; 397 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= MAX_QUALS) 398 return; 399 switch (tcp->scno + NR_SYSCALL_BASE) { 400 case SYS_read: 401#ifdef SYS_recv 402 case SYS_recv: 403#endif 404#ifdef SYS_recvfrom 405 case SYS_recvfrom: 406#endif 407 if (qual_flags[tcp->u_arg[0]] & QUAL_READ) 408 dumpstr(tcp, tcp->u_arg[1], tcp->u_rval); 409 break; 410 case SYS_write: 411#ifdef SYS_send 412 case SYS_send: 413#endif 414#ifdef SYS_sendto 415 case SYS_sendto: 416#endif 417 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE) 418 dumpstr(tcp, tcp->u_arg[1], tcp->u_arg[2]); 419 break; 420#ifdef SYS_readv 421 case SYS_readv: 422 if (qual_flags[tcp->u_arg[0]] & QUAL_READ) 423 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]); 424 break; 425#endif 426#ifdef SYS_writev 427 case SYS_writev: 428 429 if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE) 430 dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]); 431 break; 432#endif 433 } 434} 435 436#ifndef FREEBSD 437enum subcall_style { shift_style, deref_style, mask_style, door_style }; 438#else /* FREEBSD */ 439enum subcall_style { shift_style, deref_style, mask_style, door_style, table_style }; 440 441struct subcall { 442 int call; 443 int nsubcalls; 444 int subcalls[5]; 445}; 446 447const struct subcall subcalls_table[] = { 448 { SYS_shmsys, 5, { SYS_shmat, SYS_shmctl, SYS_shmdt, SYS_shmget, SYS_shmctl } }, 449#ifdef SYS_semconfig 450 { SYS_semsys, 4, { SYS___semctl, SYS_semget, SYS_semop, SYS_semconfig } }, 451#else 452 { SYS_semsys, 3, { SYS___semctl, SYS_semget, SYS_semop } }, 453#endif 454 { SYS_msgsys, 4, { SYS_msgctl, SYS_msgget, SYS_msgsnd, SYS_msgrcv } }, 455}; 456#endif /* FREEBSD */ 457 458#if !(defined(LINUX) && ( defined(ALPHA) || defined(MIPS) )) 459 460const int socket_map [] = { 461 /* SYS_SOCKET */ 97, 462 /* SYS_BIND */ 104, 463 /* SYS_CONNECT */ 98, 464 /* SYS_LISTEN */ 106, 465 /* SYS_ACCEPT */ 99, 466 /* SYS_GETSOCKNAME */ 150, 467 /* SYS_GETPEERNAME */ 141, 468 /* SYS_SOCKETPAIR */ 135, 469 /* SYS_SEND */ 101, 470 /* SYS_RECV */ 102, 471 /* SYS_SENDTO */ 133, 472 /* SYS_RECVFROM */ 125, 473 /* SYS_SHUTDOWN */ 134, 474 /* SYS_SETSOCKOPT */ 105, 475 /* SYS_GETSOCKOPT */ 118, 476 /* SYS_SENDMSG */ 114, 477 /* SYS_RECVMSG */ 113 478}; 479 480void 481sparc_socket_decode (tcp) 482struct tcb *tcp; 483{ 484 volatile long addr; 485 volatile int i, n; 486 487 if (tcp->u_arg [0] < 1 || tcp->u_arg [0] > sizeof(socket_map)/sizeof(int)+1){ 488 return; 489 } 490 tcp->scno = socket_map [tcp->u_arg [0]-1]; 491 n = tcp->u_nargs = sysent [tcp->scno].nargs; 492 addr = tcp->u_arg [1]; 493 for (i = 0; i < n; i++){ 494 int arg; 495 if (umoven (tcp, addr, sizeof (arg), (void *) &arg) < 0) 496 arg = 0; 497 tcp->u_arg [i] = arg; 498 addr += sizeof (arg); 499 } 500} 501 502static void 503decode_subcall(tcp, subcall, nsubcalls, style) 504struct tcb *tcp; 505int subcall; 506int nsubcalls; 507enum subcall_style style; 508{ 509 int i, addr, mask, arg; 510 511 switch (style) { 512 case shift_style: 513 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls) 514 return; 515 tcp->scno = subcall + tcp->u_arg[0]; 516 if (sysent[tcp->scno].nargs != -1) 517 tcp->u_nargs = sysent[tcp->scno].nargs; 518 else 519 tcp->u_nargs--; 520 for (i = 0; i < tcp->u_nargs; i++) 521 tcp->u_arg[i] = tcp->u_arg[i + 1]; 522 break; 523 case deref_style: 524 if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls) 525 return; 526 tcp->scno = subcall + tcp->u_arg[0]; 527 addr = tcp->u_arg[1]; 528 for (i = 0; i < sysent[tcp->scno].nargs; i++) { 529 if (umove(tcp, addr, &arg) < 0) 530 arg = 0; 531 tcp->u_arg[i] = arg; 532 addr += sizeof(arg); 533 } 534 tcp->u_nargs = sysent[tcp->scno].nargs; 535 break; 536 case mask_style: 537 mask = (tcp->u_arg[0] >> 8) & 0xff; 538 for (i = 0; mask; i++) 539 mask >>= 1; 540 if (i >= nsubcalls) 541 return; 542 tcp->u_arg[0] &= 0xff; 543 tcp->scno = subcall + i; 544 if (sysent[tcp->scno].nargs != -1) 545 tcp->u_nargs = sysent[tcp->scno].nargs; 546 break; 547 case door_style: 548 /* 549 * Oh, yuck. The call code is the *sixth* argument. 550 * (don't you mean the *last* argument? - JH) 551 */ 552 if (tcp->u_arg[5] < 0 || tcp->u_arg[5] >= nsubcalls) 553 return; 554 tcp->scno = subcall + tcp->u_arg[5]; 555 if (sysent[tcp->scno].nargs != -1) 556 tcp->u_nargs = sysent[tcp->scno].nargs; 557 else 558 tcp->u_nargs--; 559 break; 560#ifdef FREEBSD 561 case table_style: 562 for (i = 0; i < sizeof(subcalls_table) / sizeof(struct subcall); i++) 563 if (subcalls_table[i].call == tcp->scno) break; 564 if (i < sizeof(subcalls_table) / sizeof(struct subcall) && 565 tcp->u_arg[0] >= 0 && tcp->u_arg[0] < subcalls_table[i].nsubcalls) { 566 tcp->scno = subcalls_table[i].subcalls[tcp->u_arg[0]]; 567 for (i = 0; i < tcp->u_nargs; i++) 568 tcp->u_arg[i] = tcp->u_arg[i + 1]; 569 } 570 break; 571#endif /* FREEBSD */ 572 } 573} 574#endif 575 576struct tcb *tcp_last = NULL; 577 578static int 579internal_syscall(tcp) 580struct tcb *tcp; 581{ 582 /* 583 * We must always trace a few critical system calls in order to 584 * correctly support following forks in the presence of tracing 585 * qualifiers. 586 */ 587 switch (tcp->scno + NR_SYSCALL_BASE) { 588#ifdef SYS_fork 589 case SYS_fork: 590#endif 591#ifdef SYS_vfork 592 case SYS_vfork: 593#endif 594#ifdef SYS_fork1 595 case SYS_fork1: 596#endif 597#ifdef SYS_forkall 598 case SYS_forkall: 599#endif 600#ifdef SYS_rfork1 601 case SYS_rfork1: 602#endif 603#ifdef SYS_rforkall 604 case SYS_rforkall: 605#endif 606 internal_fork(tcp); 607 break; 608#ifdef SYS_clone 609 case SYS_clone: 610 internal_clone(tcp); 611 break; 612#endif 613#ifdef SYS_clone2 614 case SYS_clone2: 615 internal_clone(tcp); 616 break; 617#endif 618#ifdef SYS_execv 619 case SYS_execv: 620#endif 621#ifdef SYS_execve 622 case SYS_execve: 623#endif 624#ifdef SYS_rexecve 625 case SYS_rexecve: 626#endif 627 internal_exec(tcp); 628 break; 629 630#ifdef SYS_wait 631 case SYS_wait: 632#endif 633#ifdef SYS_wait4 634 case SYS_wait4: 635#endif 636#ifdef SYS32_wait4 637 case SYS32_wait4: 638#endif 639#ifdef SYS_waitpid 640 case SYS_waitpid: 641#endif 642#ifdef SYS_waitsys 643 case SYS_waitsys: 644#endif 645 internal_wait(tcp); 646 break; 647 648#ifdef SYS_exit 649 case SYS_exit: 650#endif 651#ifdef SYS32_exit 652 case SYS32_exit: 653#endif 654 internal_exit(tcp); 655 break; 656 } 657 return 0; 658} 659 660 661#ifdef LINUX 662#if defined (I386) 663 static long eax; 664#elif defined (IA64) 665 long r8, r10, psr; 666 long ia32 = 0; 667#elif defined (POWERPC) 668 static long result,flags; 669#elif defined (M68K) 670 static int d0; 671#elif defined (ARM) 672 static int r0; 673#elif defined (ALPHA) 674 static long r0; 675 static long a3; 676#elif defined (SPARC) 677 static struct regs regs; 678 static unsigned long trap; 679#elif defined(MIPS) 680 static long a3; 681 static long r2; 682#elif defined(S390) 683 static long gpr2; 684 static long pc; 685#elif defined(HPPA) 686 static long r28; 687#elif defined(SH) 688 static long r0; 689 690#endif 691#endif /* LINUX */ 692#ifdef FREEBSD 693 struct reg regs; 694#endif /* FREEBSD */ 695 696int 697get_scno(tcp) 698struct tcb *tcp; 699{ 700 long scno = 0; 701#ifndef USE_PROCFS 702 int pid = tcp->pid; 703#endif /* !PROCFS */ 704 705#ifdef LINUX 706#if defined(S390) 707 if (upeek(tcp->pid,PT_PSWADDR,&pc) < 0) 708 return -1; 709 scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)(pc-4),0); 710 if (errno) 711 return -1; 712 scno&=0xFF; 713#elif defined (POWERPC) 714 if (upeek(pid, 4*PT_R0, &scno) < 0) 715 return -1; 716 if (!(tcp->flags & TCB_INSYSCALL)) { 717 /* Check if we return from execve. */ 718 if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) { 719 tcp->flags &= ~TCB_WAITEXECVE; 720 return 0; 721 } 722 } 723#elif defined (I386) 724 if (upeek(pid, 4*ORIG_EAX, &scno) < 0) 725 return -1; 726#elif defined(IA64) 727# define IA64_PSR_IS ((long)1 << 34) 728 if (upeek (pid, PT_CR_IPSR, &psr) >= 0) 729 ia32 = (psr & IA64_PSR_IS) != 0; 730 if (!(tcp->flags & TCB_INSYSCALL)) { 731 if (ia32) { 732 if (upeek(pid, PT_R1, &scno) < 0) /* orig eax */ 733 return -1; 734 /* Check if we return from execve. */ 735 } else { 736 if (upeek (pid, PT_R15, &scno) < 0) 737 return -1; 738 } 739 } else { 740 /* syscall in progress */ 741 if (upeek (pid, PT_R8, &r8) < 0) 742 return -1; 743 if (upeek (pid, PT_R10, &r10) < 0) 744 return -1; 745 } 746 if (tcp->flags & TCB_WAITEXECVE) { 747 tcp->flags &= ~TCB_WAITEXECVE; 748 return 0; 749 } 750 751#elif defined (ARM) 752 { 753 long pc; 754 upeek(pid, 4*15, &pc); 755 umoven(tcp, pc-4, 4, (char *)&scno); 756 scno &= 0x000fffff; 757 } 758#elif defined (M68K) 759 if (upeek(pid, 4*PT_ORIG_D0, &scno) < 0) 760 return -1; 761#elif defined (MIPS) 762 if (upeek(pid, REG_A3, &a3) < 0) 763 return -1; 764 765 if(!(tcp->flags & TCB_INSYSCALL)) { 766 if (upeek(pid, REG_V0, &scno) < 0) 767 return -1; 768 769 if (scno < 0 || scno > nsyscalls) { 770 if(a3 == 0 || a3 == -1) { 771 if(debug) 772 fprintf (stderr, "stray syscall exit: v0 = %ld\n", scno); 773 return 0; 774 } 775 } 776 } else { 777 if (upeek(pid, REG_V0, &r2) < 0) 778 return -1; 779 } 780#elif defined (ALPHA) 781 if (upeek(pid, REG_A3, &a3) < 0) 782 return -1; 783 784 if (!(tcp->flags & TCB_INSYSCALL)) { 785 if (upeek(pid, REG_R0, &scno) < 0) 786 return -1; 787 788 /* Check if we return from execve. */ 789 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) { 790 tcp->flags &= ~TCB_WAITEXECVE; 791 return 0; 792 } 793 794 /* 795 * Do some sanity checks to figure out if it's 796 * really a syscall entry 797 */ 798 if (scno < 0 || scno > nsyscalls) { 799 if (a3 == 0 || a3 == -1) { 800 if (debug) 801 fprintf (stderr, "stray syscall exit: r0 = %ld\n", scno); 802 return 0; 803 } 804 } 805 } 806 else { 807 if (upeek(pid, REG_R0, &r0) < 0) 808 return -1; 809 } 810#elif defined (SPARC) 811 /* Everything we need is in the current register set. */ 812 if (ptrace(PTRACE_GETREGS,pid,(char *)®s,0) < 0) 813 return -1; 814 815 /* If we are entering, then disassemble the syscall trap. */ 816 if (!(tcp->flags & TCB_INSYSCALL)) { 817 /* Retrieve the syscall trap instruction. */ 818 errno = 0; 819 trap = ptrace(PTRACE_PEEKTEXT,pid,(char *)regs.r_pc,0); 820 if (errno) 821 return -1; 822 823 /* Disassemble the trap to see what personality to use. */ 824 switch (trap) { 825 case 0x91d02010: 826 /* Linux/SPARC syscall trap. */ 827 set_personality(0); 828 break; 829 case 0x91d0206d: 830 /* Linux/SPARC64 syscall trap. */ 831 fprintf(stderr,"syscall: Linux/SPARC64 not supported yet\n"); 832 return -1; 833 case 0x91d02000: 834 /* SunOS syscall trap. (pers 1) */ 835 fprintf(stderr,"syscall: SunOS no support\n"); 836 return -1; 837 case 0x91d02008: 838 /* Solaris 2.x syscall trap. (per 2) */ 839 set_personality(1); 840 break; 841 case 0x91d02009: 842 /* NetBSD/FreeBSD syscall trap. */ 843 fprintf(stderr,"syscall: NetBSD/FreeBSD not supported\n"); 844 return -1; 845 case 0x91d02027: 846 /* Solaris 2.x gettimeofday */ 847 set_personality(1); 848 break; 849 default: 850 /* Unknown syscall trap. */ 851 if(tcp->flags & TCB_WAITEXECVE) { 852 tcp->flags &= ~TCB_WAITEXECVE; 853 return 0; 854 } 855 fprintf(stderr,"syscall: unknown syscall trap %08x %08x\n", trap, regs.r_pc); 856 return -1; 857 } 858 859 /* Extract the system call number from the registers. */ 860 if (trap == 0x91d02027) 861 scno = 156; 862 else 863 scno = regs.r_g1; 864 if (scno == 0) { 865 scno = regs.r_o0; 866 memmove (®s.r_o0, ®s.r_o1, 7*sizeof(regs.r_o0)); 867 } 868 } 869#elif defined(HPPA) 870 if (upeek(pid, PT_GR20, &scno) < 0) 871 return -1; 872 if (!(tcp->flags & TCB_INSYSCALL)) { 873 /* Check if we return from execve. */ 874 if ((tcp->flags & TCB_WAITEXECVE)) { 875 tcp->flags &= ~TCB_WAITEXECVE; 876 return 0; 877 } 878 } 879#elif defined(SH) 880 /* 881 * In the new syscall ABI, the system call number is in R3. 882 */ 883 if (upeek(pid, 4*(REG_REG0+3), &scno) < 0) 884 return -1; 885 886 if (scno < 0) { 887 /* Odd as it may seem, a glibc bug has been known to cause 888 glibc to issue bogus negative syscall numbers. So for 889 our purposes, make strace print what it *should* have been */ 890 long correct_scno = (scno & 0xff); 891 if (debug) 892 fprintf(stderr, 893 "Detected glibc bug: bogus system call number = %ld, " 894 "correcting to %ld\n", 895 scno, 896 correct_scno); 897 scno = correct_scno; 898 } 899 900 901 if (!(tcp->flags & TCB_INSYSCALL)) { 902 /* Check if we return from execve. */ 903 if (scno == 0 && tcp->flags & TCB_WAITEXECVE) { 904 tcp->flags &= ~TCB_WAITEXECVE; 905 return 0; 906 } 907 } 908#endif /* SH */ 909#endif /* LINUX */ 910#ifdef SUNOS4 911 if (upeek(pid, uoff(u_arg[7]), &scno) < 0) 912 return -1; 913#elif defined(SH) 914 /* new syscall ABI returns result in R0 */ 915 if (upeek(pid, 4*REG_REG0, (long *)&r0) < 0) 916 return -1; 917#endif 918#ifdef USE_PROCFS 919#ifdef HAVE_PR_SYSCALL 920 scno = tcp->status.PR_SYSCALL; 921#else /* !HAVE_PR_SYSCALL */ 922#ifndef FREEBSD 923 scno = tcp->status.PR_WHAT; 924#else /* FREEBSD */ 925 if (pread(tcp->pfd_reg, ®s, sizeof(regs), 0) < 0) { 926 perror("pread"); 927 return -1; 928 } 929 switch (regs.r_eax) { 930 case SYS_syscall: 931 case SYS___syscall: 932 pread(tcp->pfd, &scno, sizeof(scno), regs.r_esp + sizeof(int)); 933 break; 934 default: 935 scno = regs.r_eax; 936 break; 937 } 938#endif /* FREEBSD */ 939#endif /* !HAVE_PR_SYSCALL */ 940#endif /* USE_PROCFS */ 941 if (!(tcp->flags & TCB_INSYSCALL)) 942 tcp->scno = scno; 943 return 1; 944} 945 946 947int 948syscall_fixup(tcp) 949struct tcb *tcp; 950{ 951#ifndef USE_PROCFS 952 int pid = tcp->pid; 953#else /* USE_PROCFS */ 954 int scno = tcp->scno; 955 956 if (!(tcp->flags & TCB_INSYSCALL)) { 957 if (tcp->status.PR_WHY != PR_SYSENTRY) { 958 if ( 959 scno == SYS_fork 960#ifdef SYS_vfork 961 || scno == SYS_vfork 962#endif /* SYS_vfork */ 963#ifdef SYS_fork1 964 || scno == SYS_fork1 965#endif /* SYS_fork1 */ 966#ifdef SYS_forkall 967 || scno == SYS_forkall 968#endif /* SYS_forkall */ 969#ifdef SYS_rfork1 970 || scno == SYS_rfork1 971#endif /* SYS_fork1 */ 972#ifdef SYS_rforkall 973 || scno == SYS_rforkall 974#endif /* SYS_rforkall */ 975 ) { 976 /* We are returning in the child, fake it. */ 977 tcp->status.PR_WHY = PR_SYSENTRY; 978 trace_syscall(tcp); 979 tcp->status.PR_WHY = PR_SYSEXIT; 980 } 981 else { 982 fprintf(stderr, "syscall: missing entry\n"); 983 tcp->flags |= TCB_INSYSCALL; 984 } 985 } 986 } 987 else { 988 if (tcp->status.PR_WHY != PR_SYSEXIT) { 989 fprintf(stderr, "syscall: missing exit\n"); 990 tcp->flags &= ~TCB_INSYSCALL; 991 } 992 } 993#endif /* USE_PROCFS */ 994#ifdef SUNOS4 995 if (!(tcp->flags & TCB_INSYSCALL)) { 996 if (scno == 0) { 997 fprintf(stderr, "syscall: missing entry\n"); 998 tcp->flags |= TCB_INSYSCALL; 999 } 1000 } 1001 else { 1002 if (scno != 0) { 1003 if (debug) { 1004 /* 1005 * This happens when a signal handler 1006 * for a signal which interrupted a 1007 * a system call makes another system call. 1008 */ 1009 fprintf(stderr, "syscall: missing exit\n"); 1010 } 1011 tcp->flags &= ~TCB_INSYSCALL; 1012 } 1013 } 1014#endif /* SUNOS4 */ 1015#ifdef LINUX 1016#if defined (I386) 1017 if (upeek(pid, 4*EAX, &eax) < 0) 1018 return -1; 1019 if (eax != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) { 1020 if (debug) 1021 fprintf(stderr, "stray syscall exit: eax = %ld\n", eax); 1022 return 0; 1023 } 1024#elif defined (S390) 1025 if (upeek(pid, PT_GPR2, &gpr2) < 0) 1026 return -1; 1027 if (gpr2 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) { 1028 if (debug) 1029 fprintf(stderr, "stray syscall exit: gpr2 = %ld\n", gpr2); 1030 return 0; 1031 } 1032#elif defined (POWERPC) 1033# define SO_MASK 0x10000000 1034 if (upeek(pid, 4*PT_CCR, &flags) < 0) 1035 return -1; 1036 if (upeek(pid, 4*PT_R3, &result) < 0) 1037 return -1; 1038 if (flags & SO_MASK) 1039 result = -result; 1040#elif defined (M68K) 1041 if (upeek(pid, 4*PT_D0, &d0) < 0) 1042 return -1; 1043 if (d0 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) { 1044 if (debug) 1045 fprintf(stderr, "stray syscall exit: d0 = %ld\n", d0); 1046 return 0; 1047 } 1048#elif defined (ARM) 1049 if (upeek(pid, 4*0, (long *)&r0) < 0) 1050 return -1; 1051 if ( 0 && r0 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) { 1052 if (debug) 1053 fprintf(stderr, "stray syscall exit: d0 = %ld\n", r0); 1054 return 0; 1055 } 1056#elif defined (HPPA) 1057 if (upeek(pid, PT_GR28, &r28) < 0) 1058 return -1; 1059#elif defined(IA64) 1060 if (upeek(pid, PT_R10, &r10) < 0) 1061 return -1; 1062 if (upeek(pid, PT_R8, &r8) < 0) 1063 return -1; 1064 if (ia32 && r8 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) { 1065 if (debug) 1066 fprintf(stderr, "stray syscall exit: r8 = %ld\n", r8); 1067 return 0; 1068 } 1069#endif 1070#endif /* LINUX */ 1071 return 1; 1072} 1073 1074int 1075get_error(tcp) 1076struct tcb *tcp; 1077{ 1078 int u_error = 0; 1079#ifdef LINUX 1080#ifdef S390 1081 if (gpr2 && (unsigned) -gpr2 < nerrnos) { 1082 tcp->u_rval = -1; 1083 u_error = -gpr2; 1084 } 1085 else { 1086 tcp->u_rval = gpr2; 1087 u_error = 0; 1088 } 1089#else /* !S390 */ 1090#ifdef I386 1091 if (eax < 0 && -eax < nerrnos) { 1092 tcp->u_rval = -1; 1093 u_error = -eax; 1094 } 1095 else { 1096 tcp->u_rval = eax; 1097 u_error = 0; 1098 } 1099#else /* !I386 */ 1100#ifdef IA64 1101 if (ia32) { 1102 int err; 1103 1104 err = (int)r8; 1105 if (err < 0 && -err < nerrnos) { 1106 tcp->u_rval = -1; 1107 u_error = -err; 1108 } 1109 else { 1110 tcp->u_rval = err; 1111 u_error = 0; 1112 } 1113 } else { 1114 if (r10) { 1115 tcp->u_rval = -1; 1116 u_error = r8; 1117 } else { 1118 tcp->u_rval = r8; 1119 u_error = 0; 1120 } 1121 } 1122#else /* !IA64 */ 1123#ifdef MIPS 1124 if (a3) { 1125 tcp->u_rval = -1; 1126 u_error = r2; 1127 } else { 1128 tcp->u_rval = r2; 1129 u_error = 0; 1130 } 1131#else 1132#ifdef POWERPC 1133 if (result && (unsigned) -result < nerrnos) { 1134 tcp->u_rval = -1; 1135 u_error = -result; 1136 } 1137 else { 1138 tcp->u_rval = result; 1139 u_error = 0; 1140 } 1141#else /* !POWERPC */ 1142#ifdef M68K 1143 if (d0 && (unsigned) -d0 < nerrnos) { 1144 tcp->u_rval = -1; 1145 u_error = -d0; 1146 } 1147 else { 1148 tcp->u_rval = d0; 1149 u_error = 0; 1150 } 1151#else /* !M68K */ 1152#ifdef ARM 1153 if (r0 && (unsigned) -r0 < nerrnos) { 1154 tcp->u_rval = -1; 1155 u_error = -r0; 1156 } 1157 else { 1158 tcp->u_rval = r0; 1159 u_error = 0; 1160 } 1161#else /* !ARM */ 1162#ifdef ALPHA 1163 if (a3) { 1164 tcp->u_rval = -1; 1165 u_error = r0; 1166 } 1167 else { 1168 tcp->u_rval = r0; 1169 u_error = 0; 1170 } 1171#else /* !ALPHA */ 1172#ifdef SPARC 1173 if (regs.r_psr & PSR_C) { 1174 tcp->u_rval = -1; 1175 u_error = regs.r_o0; 1176 } 1177 else { 1178 tcp->u_rval = regs.r_o0; 1179 u_error = 0; 1180 } 1181#else /* !SPARC */ 1182#ifdef HPPA 1183 if (r28 && (unsigned) -r28 < nerrnos) { 1184 tcp->u_rval = -1; 1185 u_error = -r28; 1186 } 1187 else { 1188 tcp->u_rval = r28; 1189 u_error = 0; 1190 } 1191#else 1192#ifdef SH 1193 /* interpret R0 as return value or error number */ 1194 if (r0 && (unsigned) -r0 < nerrnos) { 1195 tcp->u_rval = -1; 1196 u_error = -r0; 1197 } 1198 else { 1199 tcp->u_rval = r0; 1200 u_error = 0; 1201 } 1202#endif /* SH */ 1203#endif /* HPPA */ 1204#endif /* SPARC */ 1205#endif /* ALPHA */ 1206#endif /* ARM */ 1207#endif /* M68K */ 1208#endif /* POWERPC */ 1209#endif /* MIPS */ 1210#endif /* IA64 */ 1211#endif /* I386 */ 1212#endif /* S390 */ 1213#endif /* LINUX */ 1214#ifdef SUNOS4 1215 /* get error code from user struct */ 1216 if (upeek(pid, uoff(u_error), &u_error) < 0) 1217 return -1; 1218 u_error >>= 24; /* u_error is a char */ 1219 1220 /* get system call return value */ 1221 if (upeek(pid, uoff(u_rval1), &tcp->u_rval) < 0) 1222 return -1; 1223#endif /* SUNOS4 */ 1224#ifdef SVR4 1225#ifdef SPARC 1226 /* Judicious guessing goes a long way. */ 1227 if (tcp->status.pr_reg[R_PSR] & 0x100000) { 1228 tcp->u_rval = -1; 1229 u_error = tcp->status.pr_reg[R_O0]; 1230 } 1231 else { 1232 tcp->u_rval = tcp->status.pr_reg[R_O0]; 1233 u_error = 0; 1234 } 1235#endif /* SPARC */ 1236#ifdef I386 1237 /* Wanna know how to kill an hour single-stepping? */ 1238 if (tcp->status.PR_REG[EFL] & 0x1) { 1239 tcp->u_rval = -1; 1240 u_error = tcp->status.PR_REG[EAX]; 1241 } 1242 else { 1243 tcp->u_rval = tcp->status.PR_REG[EAX]; 1244#ifdef HAVE_LONG_LONG 1245 tcp->u_lrval = 1246 ((unsigned long long) tcp->status.PR_REG[EDX] << 32) + 1247 tcp->status.PR_REG[EAX]; 1248#endif 1249 u_error = 0; 1250 } 1251#endif /* I386 */ 1252#ifdef MIPS 1253 if (tcp->status.pr_reg[CTX_A3]) { 1254 tcp->u_rval = -1; 1255 u_error = tcp->status.pr_reg[CTX_V0]; 1256 } 1257 else { 1258 tcp->u_rval = tcp->status.pr_reg[CTX_V0]; 1259 u_error = 0; 1260 } 1261#endif /* MIPS */ 1262#endif /* SVR4 */ 1263#ifdef FREEBSD 1264 if (regs.r_eflags & PSL_C) { 1265 tcp->u_rval = -1; 1266 u_error = regs.r_eax; 1267 } else { 1268 tcp->u_rval = regs.r_eax; 1269 tcp->u_lrval = 1270 ((unsigned long long) regs.r_edx << 32) + regs.r_eax; 1271 u_error = 0; 1272 } 1273#endif /* FREEBSD */ 1274 tcp->u_error = u_error; 1275 return 1; 1276} 1277 1278int syscall_enter(tcp) 1279struct tcb *tcp; 1280{ 1281#ifndef USE_PROCFS 1282 int pid = tcp->pid; 1283#endif /* !USE_PROCFS */ 1284#ifdef LINUX 1285#if defined(S390) 1286 { 1287 int i; 1288 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1) 1289 tcp->u_nargs = sysent[tcp->scno].nargs; 1290 else 1291 tcp->u_nargs = MAX_ARGS; 1292 for (i = 0; i < tcp->u_nargs; i++) { 1293 if (upeek(pid,i==0 ? PT_ORIGGPR2:PT_GPR2+(i<<2), &tcp->u_arg[i]) < 0) 1294 return -1; 1295 } 1296 } 1297#elif defined (ALPHA) 1298 { 1299 int i; 1300 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1) 1301 tcp->u_nargs = sysent[tcp->scno].nargs; 1302 else 1303 tcp->u_nargs = MAX_ARGS; 1304 for (i = 0; i < tcp->u_nargs; i++) { 1305 /* WTA: if scno is out-of-bounds this will bomb. Add range-check 1306 * for scno somewhere above here! 1307 */ 1308 if (upeek(pid, REG_A0+i, &tcp->u_arg[i]) < 0) 1309 return -1; 1310 } 1311 } 1312#elif defined (IA64) 1313 { 1314 if (!ia32) { 1315 unsigned long *out0, *rbs_end, cfm, sof, sol, i; 1316 /* be backwards compatible with kernel < 2.4.4... */ 1317# ifndef PT_RBS_END 1318# define PT_RBS_END PT_AR_BSP 1319# endif 1320 1321 if (upeek(pid, PT_RBS_END, (long *) &rbs_end) < 0) 1322 return -1; 1323 if (upeek(pid, PT_CFM, (long *) &cfm) < 0) 1324 return -1; 1325 1326 sof = (cfm >> 0) & 0x7f; 1327 sol = (cfm >> 7) & 0x7f; 1328 out0 = ia64_rse_skip_regs(rbs_end, -sof + sol); 1329 1330 if (tcp->scno >= 0 && tcp->scno < nsyscalls 1331 && sysent[tcp->scno].nargs != -1) 1332 tcp->u_nargs = sysent[tcp->scno].nargs; 1333 else 1334 tcp->u_nargs = MAX_ARGS; 1335 for (i = 0; i < tcp->u_nargs; ++i) { 1336 if (umoven(tcp, (unsigned long) ia64_rse_skip_regs(out0, i), 1337 sizeof(long), (char *) &tcp->u_arg[i]) < 0) 1338 return -1; 1339 } 1340 } else { 1341 int i; 1342 1343 if (/* EBX = out0 */ 1344 upeek(pid, PT_R11, (long *) &tcp->u_arg[0]) < 0 1345 /* ECX = out1 */ 1346 || upeek(pid, PT_R9, (long *) &tcp->u_arg[1]) < 0 1347 /* EDX = out2 */ 1348 || upeek(pid, PT_R10, (long *) &tcp->u_arg[2]) < 0 1349 /* ESI = out3 */ 1350 || upeek(pid, PT_R14, (long *) &tcp->u_arg[3]) < 0 1351 /* EDI = out4 */ 1352 || upeek(pid, PT_R15, (long *) &tcp->u_arg[4]) < 0 1353 /* EBP = out5 */ 1354 || upeek(pid, PT_R13, (long *) &tcp->u_arg[5]) < 0) 1355 return -1; 1356 1357 for (i = 0; i < 6; ++i) 1358 /* truncate away IVE sign-extension */ 1359 tcp->u_arg[i] &= 0xffffffff; 1360 1361 if (tcp->scno >= 0 && tcp->scno < nsyscalls 1362 && sysent[tcp->scno].nargs != -1) 1363 tcp->u_nargs = sysent[tcp->scno].nargs; 1364 else 1365 tcp->u_nargs = 5; 1366 } 1367 } 1368#elif defined (MIPS) 1369 { 1370 long sp; 1371 int i, nargs; 1372 1373 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1) 1374 nargs = tcp->u_nargs = sysent[tcp->scno].nargs; 1375 else 1376 nargs = tcp->u_nargs = MAX_ARGS; 1377 if(nargs > 4) { 1378 if(upeek(pid, REG_SP, &sp) < 0) 1379 return -1; 1380 for(i = 0; i < 4; i++) { 1381 if (upeek(pid, REG_A0 + i, &tcp->u_arg[i])<0) 1382 return -1; 1383 } 1384 umoven(tcp, sp+16, (nargs-4) * sizeof(tcp->u_arg[0]), 1385 (char *)(tcp->u_arg + 4)); 1386 } else { 1387 for(i = 0; i < nargs; i++) { 1388 if (upeek(pid, REG_A0 + i, &tcp->u_arg[i]) < 0) 1389 return -1; 1390 } 1391 } 1392 } 1393#elif defined (POWERPC) 1394 { 1395 int i; 1396 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1) 1397 tcp->u_nargs = sysent[tcp->scno].nargs; 1398 else 1399 tcp->u_nargs = MAX_ARGS; 1400 for (i = 0; i < tcp->u_nargs; i++) { 1401 if (upeek(pid, (i==0) ? (4*PT_ORIG_R3) : ((i+PT_R3)*4), &tcp->u_arg[i]) < 0) 1402 return -1; 1403 } 1404 } 1405#elif defined (SPARC) 1406 { 1407 int i; 1408 1409 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1) 1410 tcp->u_nargs = sysent[tcp->scno].nargs; 1411 else 1412 tcp->u_nargs = MAX_ARGS; 1413 for (i = 0; i < tcp->u_nargs; i++) 1414 tcp->u_arg[i] = *((®s.r_o0) + i); 1415 } 1416#elif defined (HPPA) 1417 { 1418 int i; 1419 1420 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1) 1421 tcp->u_nargs = sysent[tcp->scno].nargs; 1422 else 1423 tcp->u_nargs = MAX_ARGS; 1424 for (i = 0; i < tcp->u_nargs; i++) { 1425 if (upeek(pid, PT_GR26-4*i, &tcp->u_arg[i]) < 0) 1426 return -1; 1427 } 1428 } 1429#elif defined(SH) 1430 { 1431 int i; 1432 static int syscall_regs[] = { 1433 REG_REG0+4, REG_REG0+5, REG_REG0+6, REG_REG0+7, 1434 REG_REG0, REG_REG0+1, REG_REG0+2 1435 }; 1436 1437 tcp->u_nargs = sysent[tcp->scno].nargs; 1438 for (i = 0; i < tcp->u_nargs; i++) { 1439 if (upeek(pid, 4*syscall_regs[i], &tcp->u_arg[i]) < 0) 1440 return -1; 1441 } 1442 } 1443#else /* Other architecture (like i386) (32bits specific) */ 1444 { 1445 int i; 1446 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1) 1447 tcp->u_nargs = sysent[tcp->scno].nargs; 1448 else 1449 tcp->u_nargs = MAX_ARGS; 1450 for (i = 0; i < tcp->u_nargs; i++) { 1451 if (upeek(pid, i*4, &tcp->u_arg[i]) < 0) 1452 return -1; 1453 } 1454 } 1455#endif 1456#endif /* LINUX */ 1457#ifdef SUNOS4 1458 { 1459 int i; 1460 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1) 1461 tcp->u_nargs = sysent[tcp->scno].nargs; 1462 else 1463 tcp->u_nargs = MAX_ARGS; 1464 for (i = 0; i < tcp->u_nargs; i++) { 1465 struct user *u; 1466 1467 if (upeek(pid, uoff(u_arg[0]) + 1468 (i*sizeof(u->u_arg[0])), &tcp->u_arg[i]) < 0) 1469 return -1; 1470 } 1471 } 1472#endif /* SUNOS4 */ 1473#ifdef SVR4 1474#ifdef MIPS 1475 /* 1476 * SGI is broken: even though it has pr_sysarg, it doesn't 1477 * set them on system call entry. Get a clue. 1478 */ 1479 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1) 1480 tcp->u_nargs = sysent[tcp->scno].nargs; 1481 else 1482 tcp->u_nargs = tcp->status.pr_nsysarg; 1483 if (tcp->u_nargs > 4) { 1484 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0], 1485 4*sizeof(tcp->u_arg[0])); 1486 umoven(tcp, tcp->status.pr_reg[CTX_SP] + 16, 1487 (tcp->u_nargs - 4)*sizeof(tcp->u_arg[0]), (char *) (tcp->u_arg + 4)); 1488 } 1489 else { 1490 memcpy(tcp->u_arg, &tcp->status.pr_reg[CTX_A0], 1491 tcp->u_nargs*sizeof(tcp->u_arg[0])); 1492 } 1493#elif UNIXWARE >= 2 1494 /* 1495 * Like SGI, UnixWare doesn't set pr_sysarg until system call exit 1496 */ 1497 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1) 1498 tcp->u_nargs = sysent[tcp->scno].nargs; 1499 else 1500 tcp->u_nargs = tcp->status.pr_lwp.pr_nsysarg; 1501 umoven(tcp, tcp->status.PR_REG[UESP] + 4, 1502 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg); 1503#elif defined (HAVE_PR_SYSCALL) 1504 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1) 1505 tcp->u_nargs = sysent[tcp->scno].nargs; 1506 else 1507 tcp->u_nargs = tcp->status.pr_nsysarg; 1508 { 1509 int i; 1510 for (i = 0; i < tcp->u_nargs; i++) 1511 tcp->u_arg[i] = tcp->status.pr_sysarg[i]; 1512 } 1513#elif defined (I386) 1514 if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1) 1515 tcp->u_nargs = sysent[tcp->scno].nargs; 1516 else 1517 tcp->u_nargs = 5; 1518 umoven(tcp, tcp->status.PR_REG[UESP] + 4, 1519 tcp->u_nargs*sizeof(tcp->u_arg[0]), (char *) tcp->u_arg); 1520#else 1521 I DONT KNOW WHAT TO DO 1522#endif /* !HAVE_PR_SYSCALL */ 1523#endif /* SVR4 */ 1524#ifdef FREEBSD 1525 if (tcp->scno >= 0 && tcp->scno < nsyscalls && 1526 sysent[tcp->scno].nargs > tcp->status.val) 1527 tcp->u_nargs = sysent[tcp->scno].nargs; 1528 else 1529 tcp->u_nargs = tcp->status.val; 1530 if (tcp->u_nargs < 0) 1531 tcp->u_nargs = 0; 1532 if (tcp->u_nargs > MAX_ARGS) 1533 tcp->u_nargs = MAX_ARGS; 1534 switch(regs.r_eax) { 1535 case SYS___syscall: 1536 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long), 1537 regs.r_esp + sizeof(int) + sizeof(quad_t)); 1538 break; 1539 case SYS_syscall: 1540 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long), 1541 regs.r_esp + 2 * sizeof(int)); 1542 break; 1543 default: 1544 pread(tcp->pfd, &tcp->u_arg, tcp->u_nargs * sizeof(unsigned long), 1545 regs.r_esp + sizeof(int)); 1546 break; 1547 } 1548#endif /* FREEBSD */ 1549 return 1; 1550} 1551 1552int 1553trace_syscall(tcp) 1554struct tcb *tcp; 1555{ 1556 int sys_res; 1557 struct timeval tv; 1558 int res; 1559 1560 /* Measure the exit time as early as possible to avoid errors. */ 1561 if (dtime && (tcp->flags & TCB_INSYSCALL)) 1562 gettimeofday(&tv, NULL); 1563 1564 res = get_scno(tcp); 1565 if (res != 1) 1566 return res; 1567 1568 res = syscall_fixup(tcp); 1569 if (res != 1) 1570 return res; 1571 1572 if (tcp->flags & TCB_INSYSCALL) { 1573 long u_error; 1574 res = get_error(tcp); 1575 if (res != 1) 1576 return res; 1577 u_error = tcp->u_error; 1578 1579 1580 internal_syscall(tcp); 1581 if (tcp->scno >= 0 && tcp->scno < nsyscalls && 1582 !(qual_flags[tcp->scno] & QUAL_TRACE)) { 1583 tcp->flags &= ~TCB_INSYSCALL; 1584 return 0; 1585 } 1586 1587 if (tcp->flags & TCB_REPRINT) { 1588 printleader(tcp); 1589 tprintf("<... "); 1590 if (tcp->scno >= nsyscalls || tcp->scno < 0) 1591 tprintf("syscall_%lu", tcp->scno); 1592 else 1593 tprintf("%s", sysent[tcp->scno].sys_name); 1594 tprintf(" resumed> "); 1595 } 1596 1597 if (cflag && tcp->scno < nsyscalls && tcp->scno >= 0) { 1598 call_count[tcp->scno]++; 1599 if (tcp->u_error) 1600 error_count[tcp->scno]++; 1601 tv_sub(&tv, &tv, &tcp->etime); 1602#ifdef LINUX 1603 if (tv_cmp(&tv, &tcp->dtime) > 0) { 1604 static struct timeval one_tick = 1605 { 0, 1000000 / HZ }; 1606 1607 if (tv_nz(&tcp->dtime)) 1608 tv = tcp->dtime; 1609 else if (tv_cmp(&tv, &one_tick) > 0) { 1610 if (tv_cmp(&shortest, &one_tick) < 0) 1611 tv = shortest; 1612 else 1613 tv = one_tick; 1614 } 1615 } 1616#endif /* LINUX */ 1617 if (tv_cmp(&tv, &shortest) < 0) 1618 shortest = tv; 1619 tv_add(&tv_count[tcp->scno], 1620 &tv_count[tcp->scno], &tv); 1621 tcp->flags &= ~TCB_INSYSCALL; 1622 return 0; 1623 } 1624 1625 if (tcp->scno >= nsyscalls || tcp->scno < 0 1626 || (qual_flags[tcp->scno] & QUAL_RAW)) 1627 sys_res = printargs(tcp); 1628 else 1629 sys_res = (*sysent[tcp->scno].sys_func)(tcp); 1630 u_error = tcp->u_error; 1631 tprintf(") "); 1632 tabto(acolumn); 1633 if (tcp->scno >= nsyscalls || tcp->scno < 0 || 1634 qual_flags[tcp->scno] & QUAL_RAW) { 1635 if (u_error) 1636 tprintf("= -1 (errno %ld)", u_error); 1637 else 1638 tprintf("= %#lx", tcp->u_rval); 1639 } 1640 else if (!(sys_res & RVAL_NONE) && u_error) { 1641 switch (u_error) { 1642#ifdef LINUX 1643 case ERESTARTSYS: 1644 tprintf("= ? ERESTARTSYS (To be restarted)"); 1645 break; 1646 case ERESTARTNOINTR: 1647 tprintf("= ? ERESTARTNOINTR (To be restarted)"); 1648 break; 1649 case ERESTARTNOHAND: 1650 tprintf("= ? ERESTARTNOHAND (To be restarted)"); 1651 break; 1652#endif /* LINUX */ 1653 default: 1654 tprintf("= -1 "); 1655 if (u_error < 0) 1656 tprintf("E??? (errno %ld)", u_error); 1657 else if (u_error < nerrnos && u_error < sys_nerr) 1658 tprintf("%s (%s)", errnoent[u_error], 1659 sys_errlist[u_error]); 1660 else if (u_error < nerrnos) 1661 tprintf("%s (errno %ld)", 1662 errnoent[u_error], u_error); 1663 else if (u_error < sys_nerr) 1664 tprintf("ERRNO_%ld (%s)", u_error, 1665 sys_errlist[u_error]); 1666 else 1667 tprintf("E??? (errno %ld)", u_error); 1668 break; 1669 } 1670 } 1671 else { 1672 if (sys_res & RVAL_NONE) 1673 tprintf("= ?"); 1674 else { 1675 switch (sys_res & RVAL_MASK) { 1676 case RVAL_HEX: 1677 tprintf("= %#lx", tcp->u_rval); 1678 break; 1679 case RVAL_OCTAL: 1680 tprintf("= %#lo", tcp->u_rval); 1681 break; 1682 case RVAL_UDECIMAL: 1683 tprintf("= %lu", tcp->u_rval); 1684 break; 1685 case RVAL_DECIMAL: 1686 tprintf("= %ld", tcp->u_rval); 1687 break; 1688#ifdef HAVE_LONG_LONG 1689 case RVAL_LHEX: 1690 tprintf("= %#llx", tcp->u_lrval); 1691 break; 1692 case RVAL_LOCTAL: 1693 tprintf("= %#llo", tcp->u_lrval); 1694 break; 1695 case RVAL_LUDECIMAL: 1696 tprintf("= %llu", tcp->u_lrval); 1697 break; 1698 case RVAL_LDECIMAL: 1699 tprintf("= %lld", tcp->u_lrval); 1700 break; 1701#endif 1702 default: 1703 fprintf(stderr, 1704 "invalid rval format\n"); 1705 break; 1706 } 1707 } 1708 if ((sys_res & RVAL_STR) && tcp->auxstr) 1709 tprintf(" (%s)", tcp->auxstr); 1710 } 1711 if (dtime) { 1712 tv_sub(&tv, &tv, &tcp->etime); 1713 tprintf(" <%ld.%06ld>", 1714 (long) tv.tv_sec, (long) tv.tv_usec); 1715 } 1716 printtrailer(tcp); 1717 1718 dumpio(tcp); 1719 if (fflush(tcp->outf) == EOF) 1720 return -1; 1721 tcp->flags &= ~TCB_INSYSCALL; 1722 return 0; 1723 } 1724 1725 /* Entering system call */ 1726 res = syscall_enter(tcp); 1727 if (res != 1) 1728 return res; 1729 1730 switch (tcp->scno + NR_SYSCALL_BASE) { 1731#ifdef LINUX 1732#if !defined (ALPHA) && !defined(SPARC) && !defined(MIPS) && !defined(HPPA) 1733 case SYS_socketcall: 1734 decode_subcall(tcp, SYS_socket_subcall, 1735 SYS_socket_nsubcalls, deref_style); 1736 break; 1737 case SYS_ipc: 1738 decode_subcall(tcp, SYS_ipc_subcall, 1739 SYS_ipc_nsubcalls, shift_style); 1740 break; 1741#endif /* !ALPHA && !MIPS && !SPARC */ 1742#ifdef SPARC 1743 case SYS_socketcall: 1744 sparc_socket_decode (tcp); 1745 break; 1746#endif 1747#endif /* LINUX */ 1748#ifdef SVR4 1749#ifdef SYS_pgrpsys_subcall 1750 case SYS_pgrpsys: 1751 decode_subcall(tcp, SYS_pgrpsys_subcall, 1752 SYS_pgrpsys_nsubcalls, shift_style); 1753 break; 1754#endif /* SYS_pgrpsys_subcall */ 1755#ifdef SYS_sigcall_subcall 1756 case SYS_sigcall: 1757 decode_subcall(tcp, SYS_sigcall_subcall, 1758 SYS_sigcall_nsubcalls, mask_style); 1759 break; 1760#endif /* SYS_sigcall_subcall */ 1761 case SYS_msgsys: 1762 decode_subcall(tcp, SYS_msgsys_subcall, 1763 SYS_msgsys_nsubcalls, shift_style); 1764 break; 1765 case SYS_shmsys: 1766 decode_subcall(tcp, SYS_shmsys_subcall, 1767 SYS_shmsys_nsubcalls, shift_style); 1768 break; 1769 case SYS_semsys: 1770 decode_subcall(tcp, SYS_semsys_subcall, 1771 SYS_semsys_nsubcalls, shift_style); 1772 break; 1773#if 0 /* broken */ 1774 case SYS_utssys: 1775 decode_subcall(tcp, SYS_utssys_subcall, 1776 SYS_utssys_nsubcalls, shift_style); 1777 break; 1778#endif 1779 case SYS_sysfs: 1780 decode_subcall(tcp, SYS_sysfs_subcall, 1781 SYS_sysfs_nsubcalls, shift_style); 1782 break; 1783 case SYS_spcall: 1784 decode_subcall(tcp, SYS_spcall_subcall, 1785 SYS_spcall_nsubcalls, shift_style); 1786 break; 1787#ifdef SYS_context_subcall 1788 case SYS_context: 1789 decode_subcall(tcp, SYS_context_subcall, 1790 SYS_context_nsubcalls, shift_style); 1791 break; 1792#endif /* SYS_context_subcall */ 1793#ifdef SYS_door_subcall 1794 case SYS_door: 1795 decode_subcall(tcp, SYS_door_subcall, 1796 SYS_door_nsubcalls, door_style); 1797 break; 1798#endif /* SYS_door_subcall */ 1799#ifdef SYS_kaio_subcall 1800 case SYS_kaio: 1801 decode_subcall(tcp, SYS_kaio_subcall, 1802 SYS_kaio_nsubcalls, shift_style); 1803 break; 1804#endif 1805#endif /* SVR4 */ 1806#ifdef FREEBSD 1807 case SYS_msgsys: 1808 case SYS_shmsys: 1809 case SYS_semsys: 1810 decode_subcall(tcp, 0, 0, table_style); 1811 break; 1812#endif 1813#ifdef SUNOS4 1814 case SYS_semsys: 1815 decode_subcall(tcp, SYS_semsys_subcall, 1816 SYS_semsys_nsubcalls, shift_style); 1817 break; 1818 case SYS_msgsys: 1819 decode_subcall(tcp, SYS_msgsys_subcall, 1820 SYS_msgsys_nsubcalls, shift_style); 1821 break; 1822 case SYS_shmsys: 1823 decode_subcall(tcp, SYS_shmsys_subcall, 1824 SYS_shmsys_nsubcalls, shift_style); 1825 break; 1826#endif 1827 } 1828 1829 internal_syscall(tcp); 1830 if (tcp->scno >=0 && tcp->scno < nsyscalls && !(qual_flags[tcp->scno] & QUAL_TRACE)) { 1831 tcp->flags |= TCB_INSYSCALL; 1832 return 0; 1833 } 1834 1835 if (cflag) { 1836 gettimeofday(&tcp->etime, NULL); 1837 tcp->flags |= TCB_INSYSCALL; 1838 return 0; 1839 } 1840 1841 printleader(tcp); 1842 tcp->flags &= ~TCB_REPRINT; 1843 tcp_last = tcp; 1844 if (tcp->scno >= nsyscalls || tcp->scno < 0) 1845 tprintf("syscall_%lu(", tcp->scno); 1846 else 1847 tprintf("%s(", sysent[tcp->scno].sys_name); 1848 if (tcp->scno >= nsyscalls || tcp->scno < 0 || 1849 ((qual_flags[tcp->scno] & QUAL_RAW) && tcp->scno != SYS_exit)) 1850 sys_res = printargs(tcp); 1851 else 1852 sys_res = (*sysent[tcp->scno].sys_func)(tcp); 1853 if (fflush(tcp->outf) == EOF) 1854 return -1; 1855 tcp->flags |= TCB_INSYSCALL; 1856 /* Measure the entrance time as late as possible to avoid errors. */ 1857 if (dtime) 1858 gettimeofday(&tcp->etime, NULL); 1859 return sys_res; 1860} 1861 1862int 1863printargs(tcp) 1864struct tcb *tcp; 1865{ 1866 if (entering(tcp)) { 1867 int i; 1868 1869 for (i = 0; i < tcp->u_nargs; i++) 1870 tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]); 1871 } 1872 return 0; 1873} 1874 1875long 1876getrval2(tcp) 1877struct tcb *tcp; 1878{ 1879 long val = -1; 1880 1881#ifdef LINUX 1882#ifdef SPARC 1883 struct regs regs; 1884 if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)®s,0) < 0) 1885 return -1; 1886 val = regs.r_o1; 1887#endif /* SPARC */ 1888#endif /* LINUX */ 1889 1890#ifdef SUNOS4 1891 if (upeek(tcp->pid, uoff(u_rval2), &val) < 0) 1892 return -1; 1893#endif /* SUNOS4 */ 1894 1895#ifdef SVR4 1896#ifdef SPARC 1897 val = tcp->status.PR_REG[R_O1]; 1898#endif /* SPARC */ 1899#ifdef I386 1900 val = tcp->status.PR_REG[EDX]; 1901#endif /* I386 */ 1902#ifdef MIPS 1903 val = tcp->status.PR_REG[CTX_V1]; 1904#endif /* MIPS */ 1905#endif /* SVR4 */ 1906#ifdef FREEBSD 1907 struct reg regs; 1908 pread(tcp->pfd_reg, ®s, sizeof(regs), 0); 1909 val = regs.r_edx; 1910#endif 1911 return val; 1912} 1913 1914/* 1915 * Apparently, indirect system calls have already be converted by ptrace(2), 1916 * so if you see "indir" this program has gone astray. 1917 */ 1918int 1919sys_indir(tcp) 1920struct tcb *tcp; 1921{ 1922 int i, scno, nargs; 1923 1924 if (entering(tcp)) { 1925 if ((scno = tcp->u_arg[0]) > nsyscalls) { 1926 fprintf(stderr, "Bogus syscall: %u\n", scno); 1927 return 0; 1928 } 1929 nargs = sysent[scno].nargs; 1930 tprintf("%s", sysent[scno].sys_name); 1931 for (i = 0; i < nargs; i++) 1932 tprintf(", %#lx", tcp->u_arg[i+1]); 1933 } 1934 return 0; 1935} 1936 1937static int 1938time_cmp(a, b) 1939void *a; 1940void *b; 1941{ 1942 return -tv_cmp(&tv_count[*((int *) a)], &tv_count[*((int *) b)]); 1943} 1944 1945static int 1946syscall_cmp(a, b) 1947void *a; 1948void *b; 1949{ 1950 return strcmp(sysent[*((int *) a)].sys_name, 1951 sysent[*((int *) b)].sys_name); 1952} 1953 1954static int 1955count_cmp(a, b) 1956void *a; 1957void *b; 1958{ 1959 int m = call_count[*((int *) a)], n = call_count[*((int *) b)]; 1960 1961 return (m < n) ? 1 : (m > n) ? -1 : 0; 1962} 1963 1964static int (*sortfun)(); 1965static struct timeval overhead = { -1, -1 }; 1966 1967void 1968set_sortby(sortby) 1969char *sortby; 1970{ 1971 if (strcmp(sortby, "time") == 0) 1972 sortfun = time_cmp; 1973 else if (strcmp(sortby, "calls") == 0) 1974 sortfun = count_cmp; 1975 else if (strcmp(sortby, "name") == 0) 1976 sortfun = syscall_cmp; 1977 else if (strcmp(sortby, "nothing") == 0) 1978 sortfun = NULL; 1979 else { 1980 fprintf(stderr, "invalid sortby: `%s'\n", sortby); 1981 exit(1); 1982 } 1983} 1984 1985void set_overhead(n) 1986int n; 1987{ 1988 overhead.tv_sec = n / 1000000; 1989 overhead.tv_usec = n % 1000000; 1990} 1991 1992void 1993call_summary(outf) 1994FILE *outf; 1995{ 1996 int i, j; 1997 int call_cum, error_cum; 1998 struct timeval tv_cum, dtv; 1999 double percent; 2000 char *dashes = "-------------------------"; 2001 char error_str[16]; 2002 2003 call_cum = error_cum = tv_cum.tv_sec = tv_cum.tv_usec = 0; 2004 if (overhead.tv_sec == -1) { 2005 tv_mul(&overhead, &shortest, 8); 2006 tv_div(&overhead, &overhead, 10); 2007 } 2008 for (i = 0; i < nsyscalls; i++) { 2009 sorted_count[i] = i; 2010 if (call_count[i] == 0) 2011 continue; 2012 tv_mul(&dtv, &overhead, call_count[i]); 2013 tv_sub(&tv_count[i], &tv_count[i], &dtv); 2014 call_cum += call_count[i]; 2015 error_cum += error_count[i]; 2016 tv_add(&tv_cum, &tv_cum, &tv_count[i]); 2017 } 2018 if (sortfun) 2019 qsort((void *) sorted_count, nsyscalls, sizeof(int), sortfun); 2020 fprintf(outf, "%6.6s %11.11s %11.11s %9.9s %9.9s %s\n", 2021 "% time", "seconds", "usecs/call", 2022 "calls", "errors", "syscall"); 2023 fprintf(outf, "%6.6s %11.11s %11.11s %9.9s %9.9s %-16.16s\n", 2024 dashes, dashes, dashes, dashes, dashes, dashes); 2025 for (i = 0; i < nsyscalls; i++) { 2026 j = sorted_count[i]; 2027 if (call_count[j] == 0) 2028 continue; 2029 tv_div(&dtv, &tv_count[j], call_count[j]); 2030 if (error_count[j]) 2031 sprintf(error_str, "%d", error_count[j]); 2032 else 2033 error_str[0] = '\0'; 2034 percent = 100.0*tv_float(&tv_count[j])/tv_float(&tv_cum); 2035 fprintf(outf, "%6.2f %4ld.%06ld %11ld %9d %9.9s %s\n", 2036 percent, (long) tv_count[j].tv_sec, 2037 (long) tv_count[j].tv_usec, 2038 (long) 1000000 * dtv.tv_sec + dtv.tv_usec, 2039 call_count[j], error_str, sysent[j].sys_name); 2040 } 2041 fprintf(outf, "%6.6s %11.11s %11.11s %9.9s %9.9s %-16.16s\n", 2042 dashes, dashes, dashes, dashes, dashes, dashes); 2043 if (error_cum) 2044 sprintf(error_str, "%d", error_cum); 2045 else 2046 error_str[0] = '\0'; 2047 fprintf(outf, "%6.6s %4ld.%06ld %11.11s %9d %9.9s %s\n", 2048 "100.00", (long) tv_cum.tv_sec, (long) tv_cum.tv_usec, "", 2049 call_cum, error_str, "total"); 2050} 2051