[PATCH 3/5] Remove scno retrieval code in get_scno_on_sysexit
Denys Vlasenko
dvlasenk at redhat.com
Mon Aug 22 10:27:23 UTC 2011
On Mon, 2011-08-22 at 12:21 +0200, Denys Vlasenko wrote:
> 3. Remove scno retrieval code in get_scno_on_sysexit, since we don't
> save it anyway. This is the first real logic change which should make
> strace faster: for example, on x64 ORIG_EAX is no longer read in each
> syscall exit.
diff -d -urpN strace.2/syscall.c strace.3/syscall.c
--- strace.2/syscall.c 2011-08-22 03:37:30.726824167 +0200
+++ strace.3/syscall.c 2011-08-22 03:37:40.306072274 +0200
@@ -1298,124 +1298,18 @@ get_scno_on_sysenter(struct tcb *tcp)
static int
get_scno_on_sysexit(struct tcb *tcp)
{
- long scno = 0;
-
#ifdef LINUX
# if defined(S390) || defined(S390X)
- if (tcp->flags & TCB_WAITEXECVE) {
- /*
- * When the execve system call completes successfully, the
- * new process still has -ENOSYS (old style) or __NR_execve
- * (new style) in gpr2. We cannot recover the scno again
- * by disassembly, because the image that executed the
- * syscall is gone now. Fortunately, we don't want it. We
- * leave the flag set so that syscall_fixup can fake the
- * result.
- */
- return 1;
- }
-
- if (upeek(tcp, PT_GPR2, &syscall_mode) < 0)
- return -1;
-
- if (syscall_mode != -ENOSYS) {
- /*
- * Since kernel version 2.5.44 the scno gets passed in gpr2.
- */
- scno = syscall_mode;
- } else {
- /*
- * Old style of "passing" the scno via the SVC instruction.
- */
-
- long opcode, offset_reg, tmp;
- void * svc_addr;
- static const int gpr_offset[16] = {
- PT_GPR0, PT_GPR1, PT_ORIGGPR2, PT_GPR3,
- PT_GPR4, PT_GPR5, PT_GPR6, PT_GPR7,
- PT_GPR8, PT_GPR9, PT_GPR10, PT_GPR11,
- PT_GPR12, PT_GPR13, PT_GPR14, PT_GPR15
- };
-
- if (upeek(tcp, PT_PSWADDR, &pc) < 0)
- return -1;
- errno = 0;
- opcode = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)(pc-sizeof(long)), 0);
- if (errno) {
- perror("peektext(pc-oneword)");
- return -1;
- }
-
- /*
- * We have to check if the SVC got executed directly or via an
- * EXECUTE instruction. In case of EXECUTE it is necessary to do
- * instruction decoding to derive the system call number.
- * Unfortunately the opcode sizes of EXECUTE and SVC are differently,
- * so that this doesn't work if a SVC opcode is part of an EXECUTE
- * opcode. Since there is no way to find out the opcode size this
- * is the best we can do...
- */
-
- if ((opcode & 0xff00) == 0x0a00) {
- /* SVC opcode */
- scno = opcode & 0xff;
- }
- else {
- /* SVC got executed by EXECUTE instruction */
-
- /*
- * Do instruction decoding of EXECUTE. If you really want to
- * understand this, read the Principles of Operations.
- */
- svc_addr = (void *) (opcode & 0xfff);
-
- tmp = 0;
- offset_reg = (opcode & 0x000f0000) >> 16;
- if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
- return -1;
- svc_addr += tmp;
-
- tmp = 0;
- offset_reg = (opcode & 0x0000f000) >> 12;
- if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
- return -1;
- svc_addr += tmp;
-
- scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, svc_addr, 0);
- if (errno)
- return -1;
-# if defined(S390X)
- scno >>= 48;
-# else
- scno >>= 16;
-# endif
- tmp = 0;
- offset_reg = (opcode & 0x00f00000) >> 20;
- if (offset_reg && (upeek(tcp, gpr_offset[offset_reg], &tmp) < 0))
- return -1;
-
- scno = (scno | tmp) & 0xff;
- }
- }
# elif defined (POWERPC)
- if (upeek(tcp, sizeof(unsigned long)*PT_R0, &scno) < 0)
- return -1;
# elif defined(AVR32)
/*
* Read complete register set in one go.
*/
if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, ®s) < 0)
return -1;
-
# elif defined(BFIN)
- if (upeek(tcp, PT_ORIG_P0, &scno))
- return -1;
# elif defined (I386)
- if (upeek(tcp, 4*ORIG_EAX, &scno) < 0)
- return -1;
# elif defined (X86_64)
- if (upeek(tcp, 8*ORIG_RAX, &scno) < 0)
- return -1;
# elif defined(IA64)
# define IA64_PSR_IS ((long)1 << 34)
if (upeek(tcp, PT_CR_IPSR, &psr) >= 0)
@@ -1430,71 +1324,7 @@ get_scno_on_sysexit(struct tcb *tcp)
*/
if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (void *)®s) == -1)
return -1;
-
- /*
- * We only need to grab the syscall number on syscall entry.
- */
- if (regs.ARM_ip == 0) {
- /*
- * Note: we only deal with only 32-bit CPUs here.
- */
- if (regs.ARM_cpsr & 0x20) {
- /*
- * Get the Thumb-mode system call number
- */
- scno = regs.ARM_r7;
- } else {
- /*
- * Get the ARM-mode system call number
- */
- errno = 0;
- scno = ptrace(PTRACE_PEEKTEXT, tcp->pid, (void *)(regs.ARM_pc - 4), NULL);
- if (errno)
- return -1;
-
- /* FIXME: bogus check? it is already done on entering before,
- * so we never can see it here?
- */
- if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
- tcp->flags &= ~TCB_WAITEXECVE;
- return 0;
- }
-
- /* Handle the EABI syscall convention. We do not
- bother converting structures between the two
- ABIs, but basic functionality should work even
- if strace and the traced program have different
- ABIs. */
- if (scno == 0xef000000) {
- scno = regs.ARM_r7;
- } else {
- if ((scno & 0x0ff00000) != 0x0f900000) {
- fprintf(stderr, "syscall: unknown syscall trap 0x%08lx\n",
- scno);
- return -1;
- }
-
- /*
- * Fixup the syscall number
- */
- scno &= 0x000fffff;
- }
- }
- if (scno & 0x0f0000) {
- /*
- * Handle ARM specific syscall
- */
- set_personality(1);
- scno &= 0x0000ffff;
- } else
- set_personality(0);
-
- fprintf(stderr, "pid %d stray syscall exit\n", tcp->pid);
- tcp->flags &= ~TCB_INSYSCALL;
- }
# elif defined (M68K)
- if (upeek(tcp, 4*PT_ORIG_D0, &scno) < 0)
- return -1;
# elif defined (LINUX_MIPSN32)
unsigned long long regs[38];
@@ -1517,47 +1347,15 @@ get_scno_on_sysexit(struct tcb *tcp)
if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)®s, 0) < 0)
return -1;
# elif defined(HPPA)
- if (upeek(tcp, PT_GR20, &scno) < 0)
- return -1;
# elif defined(SH)
- /*
- * In the new syscall ABI, the system call number is in R3.
- */
- if (upeek(tcp, 4*(REG_REG0+3), &scno) < 0)
- return -1;
-
- if (scno < 0) {
- /* Odd as it may seem, a glibc bug has been known to cause
- glibc to issue bogus negative syscall numbers. So for
- our purposes, make strace print what it *should* have been */
- long correct_scno = (scno & 0xff);
- if (debug)
- fprintf(stderr,
- "Detected glibc bug: bogus system call"
- " number = %ld, correcting to %ld\n",
- scno,
- correct_scno);
- scno = correct_scno;
- }
# elif defined(SH64)
- if (upeek(tcp, REG_SYSCALL, &scno) < 0)
- return -1;
- scno &= 0xFFFF;
# elif defined(CRISV10) || defined(CRISV32)
- if (upeek(tcp, 4*PT_R9, &scno) < 0)
- return -1;
# elif defined(TILE)
- if (upeek(tcp, PTREGS_OFFSET_REG(10), &scno) < 0)
- return -1;
# elif defined(MICROBLAZE)
- if (upeek(tcp, 0, &scno) < 0)
- return -1;
# endif
#endif /* LINUX */
#ifdef SUNOS4
- if (upeek(tcp, uoff(u_arg[7]), &scno) < 0)
- return -1;
#elif defined(SH)
/* new syscall ABI returns result in R0 */
if (upeek(tcp, 4*REG_REG0, (long *)&r0) < 0)
@@ -1569,25 +1367,12 @@ get_scno_on_sysexit(struct tcb *tcp)
#endif
#ifdef USE_PROCFS
-# ifdef HAVE_PR_SYSCALL
- scno = tcp->status.PR_SYSCALL;
-# else
-# ifndef FREEBSD
- scno = tcp->status.PR_WHAT;
-# else
+# ifndef HAVE_PR_SYSCALL
+# ifdef FREEBSD
if (pread(tcp->pfd_reg, ®s, sizeof(regs), 0) < 0) {
perror("pread");
return -1;
}
- switch (regs.r_eax) {
- case SYS_syscall:
- case SYS___syscall:
- pread(tcp->pfd, &scno, sizeof(scno), regs.r_esp + sizeof(int));
- break;
- default:
- scno = regs.r_eax;
- break;
- }
# endif /* FREEBSD */
# endif /* !HAVE_PR_SYSCALL */
#endif /* USE_PROCFS */
More information about the Strace-devel
mailing list