📄 syscall.c
字号:
/* * Copyright (c) 1991, 1992 Paul Kranenburg <pk@cs.few.eur.nl> * Copyright (c) 1993 Branko Lankester <branko@hacktic.nl> * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs@world.std.com> * Copyright (c) 1996-1999 Wichert Akkerman <wichert@cistron.nl> * Copyright (c) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation * Linux for s390 port by D.J. Barrow * <barrow_dj@mail.yahoo.com,djbarrow@de.ibm.com> * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $Id: syscall.c,v 1.30 2001/03/28 20:29:17 wichert Exp $ */#include "defs.h"#include <signal.h>#include <time.h>#include <errno.h>#include <sys/user.h>#include <sys/syscall.h>#include <sys/param.h>#if HAVE_ASM_REG_H#ifdef SPARC# define fpq kernel_fpq# define fq kernel_fq# define fpu kernel_fpu#endif#include <asm/reg.h>#ifdef SPARC# undef fpq# undef fq# undef fpu #endif#endif#ifdef HAVE_SYS_REG_H#include <sys/reg.h>#ifndef PTRACE_PEEKUSR# define PTRACE_PEEKUSR PTRACE_PEEKUSER#endif#elif defined(HAVE_LINUX_PTRACE_H)#undef PTRACE_SYSCALL#include <linux/ptrace.h>#endif#if defined(LINUX) && defined(IA64)# include <asm/ptrace_offsets.h># include <asm/rse.h>#endif#ifndef SYS_ERRLIST_DECLAREDextern int sys_nerr;extern char *sys_errlist[];#endif /* SYS_ERRLIST_DECLARED */#define NR_SYSCALL_BASE 0#ifdef LINUX#ifndef ERESTARTSYS#define ERESTARTSYS 512#endif#ifndef ERESTARTNOINTR#define ERESTARTNOINTR 513#endif#ifndef ERESTARTNOHAND#define ERESTARTNOHAND 514 /* restart if no handler.. */#endif#ifndef ENOIOCTLCMD#define ENOIOCTLCMD 515 /* No ioctl command */#endif#ifndef NSIG#define NSIG 32#endif#ifdef ARM#undef NSIG#define NSIG 32#undef NR_SYSCALL_BASE#define NR_SYSCALL_BASE __NR_SYSCALL_BASE#endif#endif /* LINUX */#include "syscall.h"/* Define these shorthand notations to simplify the syscallent files. */#define TF TRACE_FILE#define TI TRACE_IPC#define TN TRACE_NETWORK#define TP TRACE_PROCESS#define TS TRACE_SIGNALstruct sysent sysent0[] = {#include "syscallent.h"};int nsyscalls0 = sizeof sysent0 / sizeof sysent0[0];#if SUPPORTED_PERSONALITIES >= 2struct sysent sysent1[] = {#include "syscallent1.h"};int nsyscalls1 = sizeof sysent1 / sizeof sysent1[0];#endif /* SUPPORTED_PERSONALITIES >= 2 */#if SUPPORTED_PERSONALITIES >= 3struct sysent sysent2[] = {#include "syscallent2.h"};int nsyscalls2 = sizeof sysent2 / sizeof sysent2[0];#endif /* SUPPORTED_PERSONALITIES >= 3 */struct sysent *sysent;int nsyscalls;/* Now undef them since short defines cause wicked namespace pollution. */#undef TF#undef TI#undef TN#undef TP#undef TSchar *errnoent0[] = {#include "errnoent.h"};int nerrnos0 = sizeof errnoent0 / sizeof errnoent0[0];#if SUPPORTED_PERSONALITIES >= 2char *errnoent1[] = {#include "errnoent1.h"};int nerrnos1 = sizeof errnoent1 / sizeof errnoent1[0];#endif /* SUPPORTED_PERSONALITIES >= 2 */#if SUPPORTED_PERSONALITIES >= 3char *errnoent2[] = {#include "errnoent2.h"};int nerrnos2 = sizeof errnoent2 / sizeof errnoent2[0];#endif /* SUPPORTED_PERSONALITIES >= 3 */char **errnoent;int nerrnos;int current_personality;intset_personality(personality)int personality;{ switch (personality) { case 0: errnoent = errnoent0; nerrnos = nerrnos0; sysent = sysent0; nsyscalls = nsyscalls0; ioctlent = ioctlent0; nioctlents = nioctlents0; signalent = signalent0; nsignals = nsignals0; break;#if SUPPORTED_PERSONALITIES >= 2 case 1: errnoent = errnoent1; nerrnos = nerrnos1; sysent = sysent1; nsyscalls = nsyscalls1; ioctlent = ioctlent1; nioctlents = nioctlents1; signalent = signalent1; nsignals = nsignals1; break;#endif /* SUPPORTED_PERSONALITIES >= 2 */#if SUPPORTED_PERSONALITIES >= 3 case 2: errnoent = errnoent2; nerrnos = nerrnos2; sysent = sysent2; nsyscalls = nsyscalls2; ioctlent = ioctlent2; nioctlents = nioctlents2; signalent = signalent2; nsignals = nsignals2; break;#endif /* SUPPORTED_PERSONALITIES >= 3 */ default: return -1; } current_personality = personality; return 0;}int qual_flags[MAX_QUALS];static int call_count[MAX_QUALS];static int error_count[MAX_QUALS];static struct timeval tv_count[MAX_QUALS];static int sorted_count[MAX_QUALS];static struct timeval shortest = { 1000000, 0 };static int lookup_syscall(), lookup_signal(), lookup_fault(), lookup_desc();static struct qual_options { int bitflag; char *option_name; int (*lookup)(); char *argument_name;} qual_options[] = { { QUAL_TRACE, "trace", lookup_syscall, "system call" }, { QUAL_TRACE, "t", lookup_syscall, "system call" }, { QUAL_ABBREV, "abbrev", lookup_syscall, "system call" }, { QUAL_ABBREV, "a", lookup_syscall, "system call" }, { QUAL_VERBOSE, "verbose", lookup_syscall, "system call" }, { QUAL_VERBOSE, "v", lookup_syscall, "system call" }, { QUAL_RAW, "raw", lookup_syscall, "system call" }, { QUAL_RAW, "x", lookup_syscall, "system call" }, { QUAL_SIGNAL, "signal", lookup_signal, "signal" }, { QUAL_SIGNAL, "signals", lookup_signal, "signal" }, { QUAL_SIGNAL, "s", lookup_signal, "signal" }, { QUAL_FAULT, "fault", lookup_fault, "fault" }, { QUAL_FAULT, "faults", lookup_fault, "fault" }, { QUAL_FAULT, "m", lookup_fault, "fault" }, { QUAL_READ, "read", lookup_desc, "descriptor" }, { QUAL_READ, "reads", lookup_desc, "descriptor" }, { QUAL_READ, "r", lookup_desc, "descriptor" }, { QUAL_WRITE, "write", lookup_desc, "descriptor" }, { QUAL_WRITE, "writes", lookup_desc, "descriptor" }, { QUAL_WRITE, "w", lookup_desc, "descriptor" }, { 0, NULL, NULL, NULL },};static intlookup_syscall(s)char *s;{ int i; for (i = 0; i < nsyscalls; i++) { if (strcmp(s, sysent[i].sys_name) == 0) return i; } return -1;}static intlookup_signal(s)char *s;{ int i; char buf[32]; if (s && *s && isdigit((unsigned char)*s)) return atoi(s); strcpy(buf, s); s = buf; for (i = 0; s[i]; i++) s[i] = toupper((unsigned char)(s[i])); if (strncmp(s, "SIG", 3) == 0) s += 3; for (i = 0; i <= NSIG; i++) { if (strcmp(s, signame(i) + 3) == 0) return i; } return -1;}static intlookup_fault(s)char *s;{ return -1;}static intlookup_desc(s)char *s;{ if (s && *s && isdigit((unsigned char)*s)) return atoi(s); return -1;}static intlookup_class(s)char *s;{ if (strcmp(s, "file") == 0) return TRACE_FILE; if (strcmp(s, "ipc") == 0) return TRACE_IPC; if (strcmp(s, "network") == 0) return TRACE_NETWORK; if (strcmp(s, "process") == 0) return TRACE_PROCESS; if (strcmp(s, "signal") == 0) return TRACE_SIGNAL; return -1;}voidqualify(s)char *s;{ struct qual_options *opt; int not; char *p; int i, n; opt = &qual_options[0]; for (i = 0; (p = qual_options[i].option_name); i++) { n = strlen(p); if (strncmp(s, p, n) == 0 && s[n] == '=') { opt = &qual_options[i]; s += n + 1; break; } } not = 0; if (*s == '!') { not = 1; s++; } if (strcmp(s, "none") == 0) { not = 1 - not; s = "all"; } if (strcmp(s, "all") == 0) { for (i = 0; i < MAX_QUALS; i++) { if (not) qual_flags[i] &= ~opt->bitflag; else qual_flags[i] |= opt->bitflag; } return; } for (i = 0; i < MAX_QUALS; i++) { if (not) qual_flags[i] |= opt->bitflag; else qual_flags[i] &= ~opt->bitflag; } for (p = strtok(s, ","); p; p = strtok(NULL, ",")) { if (opt->bitflag == QUAL_TRACE && (n = lookup_class(p)) > 0) { for (i = 0; i < MAX_QUALS; i++) { if (sysent[i].sys_flags & n) { if (not) qual_flags[i] &= ~opt->bitflag; else qual_flags[i] |= opt->bitflag; } } continue; } if ((n = (*opt->lookup)(p)) < 0) { fprintf(stderr, "strace: invalid %s `%s'\n", opt->argument_name, p); exit(1); } if (not) qual_flags[n] &= ~opt->bitflag; else qual_flags[n] |= opt->bitflag; } return;}static voiddumpio(tcp)struct tcb *tcp;{ if (syserror(tcp)) return; if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= MAX_QUALS) return; switch (tcp->scno + NR_SYSCALL_BASE) { case SYS_read:#ifdef SYS_recv case SYS_recv:#endif#ifdef SYS_recvfrom case SYS_recvfrom:#endif if (qual_flags[tcp->u_arg[0]] & QUAL_READ) dumpstr(tcp, tcp->u_arg[1], tcp->u_rval); break; case SYS_write:#ifdef SYS_send case SYS_send:#endif#ifdef SYS_sendto case SYS_sendto:#endif if (qual_flags[tcp->u_arg[0]] & QUAL_WRITE) dumpstr(tcp, tcp->u_arg[1], tcp->u_arg[2]); break; }}#ifndef FREEBSDenum subcall_style { shift_style, deref_style, mask_style, door_style };#else /* FREEBSD */enum subcall_style { shift_style, deref_style, mask_style, door_style, table_style };struct subcall { int call; int nsubcalls; int subcalls[5];};const struct subcall subcalls_table[] = { { SYS_shmsys, 5, { SYS_shmat, SYS_shmctl, SYS_shmdt, SYS_shmget, SYS_shmctl } },#ifdef SYS_semconfig { SYS_semsys, 4, { SYS___semctl, SYS_semget, SYS_semop, SYS_semconfig } },#else { SYS_semsys, 3, { SYS___semctl, SYS_semget, SYS_semop } },#endif { SYS_msgsys, 4, { SYS_msgctl, SYS_msgget, SYS_msgsnd, SYS_msgrcv } },};#endif /* FREEBSD */#if !(defined(LINUX) && ( defined(ALPHA) || defined(IA64) || defined(MIPS) ))const int socket_map [] = { /* SYS_SOCKET */ 97, /* SYS_BIND */ 104, /* SYS_CONNECT */ 98, /* SYS_LISTEN */ 106, /* SYS_ACCEPT */ 99, /* SYS_GETSOCKNAME */ 150, /* SYS_GETPEERNAME */ 141, /* SYS_SOCKETPAIR */ 135, /* SYS_SEND */ 101, /* SYS_RECV */ 102, /* SYS_SENDTO */ 133, /* SYS_RECVFROM */ 125, /* SYS_SHUTDOWN */ 134, /* SYS_SETSOCKOPT */ 105, /* SYS_GETSOCKOPT */ 118, /* SYS_SENDMSG */ 114, /* SYS_RECVMSG */ 113};voidsparc_socket_decode (tcp)struct tcb *tcp;{ volatile long addr; volatile int i, n; if (tcp->u_arg [0] < 1 || tcp->u_arg [0] > sizeof(socket_map)/sizeof(int)+1){ return; } tcp->scno = socket_map [tcp->u_arg [0]-1]; n = tcp->u_nargs = sysent [tcp->scno].nargs; addr = tcp->u_arg [1]; for (i = 0; i < n; i++){ int arg; if (umoven (tcp, addr, sizeof (arg), (void *) &arg) < 0) arg = 0; tcp->u_arg [i] = arg; addr += sizeof (arg); }}static voiddecode_subcall(tcp, subcall, nsubcalls, style)struct tcb *tcp;int subcall;int nsubcalls;enum subcall_style style;{ int i, addr, mask, arg; switch (style) { case shift_style: if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls) return; tcp->scno = subcall + tcp->u_arg[0]; if (sysent[tcp->scno].nargs != -1) tcp->u_nargs = sysent[tcp->scno].nargs; else tcp->u_nargs--; for (i = 0; i < tcp->u_nargs; i++) tcp->u_arg[i] = tcp->u_arg[i + 1]; break; case deref_style: if (tcp->u_arg[0] < 0 || tcp->u_arg[0] >= nsubcalls) return; tcp->scno = subcall + tcp->u_arg[0]; addr = tcp->u_arg[1]; for (i = 0; i < sysent[tcp->scno].nargs; i++) { if (umove(tcp, addr, &arg) < 0) arg = 0; tcp->u_arg[i] = arg; addr += sizeof(arg); } tcp->u_nargs = sysent[tcp->scno].nargs; break; case mask_style: mask = (tcp->u_arg[0] >> 8) & 0xff; for (i = 0; mask; i++) mask >>= 1; if (i >= nsubcalls) return; tcp->u_arg[0] &= 0xff; tcp->scno = subcall + i; if (sysent[tcp->scno].nargs != -1) tcp->u_nargs = sysent[tcp->scno].nargs; break; case door_style: /* * Oh, yuck. The call code is the *sixth* argument. * (don't you mean the *last* argument? - JH) */ if (tcp->u_arg[5] < 0 || tcp->u_arg[5] >= nsubcalls) return; tcp->scno = subcall + tcp->u_arg[5]; if (sysent[tcp->scno].nargs != -1) tcp->u_nargs = sysent[tcp->scno].nargs; else tcp->u_nargs--; break;#ifdef FREEBSD case table_style: for (i = 0; i < sizeof(subcalls_table) / sizeof(struct subcall); i++) if (subcalls_table[i].call == tcp->scno) break; if (i < sizeof(subcalls_table) / sizeof(struct subcall) && tcp->u_arg[0] >= 0 && tcp->u_arg[0] < subcalls_table[i].nsubcalls) { tcp->scno = subcalls_table[i].subcalls[tcp->u_arg[0]]; for (i = 0; i < tcp->u_nargs; i++) tcp->u_arg[i] = tcp->u_arg[i + 1]; } break;#endif /* FREEBSD */ }}#endifstruct tcb *tcp_last = NULL;static intinternal_syscall(tcp)struct tcb *tcp;{ /* * We must always trace a few critical system calls in order to * correctly support following forks in the presence of tracing * qualifiers. */ switch (tcp->scno + NR_SYSCALL_BASE) {#ifdef SYS_fork case SYS_fork:#endif#ifdef SYS_vfork case SYS_vfork:#endif internal_fork(tcp); break;#ifdef SYS_clone case SYS_clone: internal_clone(tcp); break;#endif#ifdef SYS_execv case SYS_execv:#endif#ifdef SYS_execve case SYS_execve:#endif internal_exec(tcp); break;#ifdef SYS_wait case SYS_wait:#endif#ifdef SYS_wait4 case SYS_wait4:#endif#ifdef SYS_waitpid case SYS_waitpid:#endif#ifdef SYS_waitsys case SYS_waitsys:#endif internal_wait(tcp); break;#ifdef SYS_exit case SYS_exit:#endif internal_exit(tcp); break; } return 0;}#ifdef LINUX#if defined (I386) static long eax;#elif defined (IA64) long r8, r10, psr; long ia32 = 0;#elif defined (POWERPC) static long result,flags;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -