From aca8b603ee5e39f4e55ada964ec03564ddc33017 Mon Sep 17 00:00:00 2001 From: David Mosberger Date: Wed, 31 Dec 2003 07:18:59 -0800 Subject: [PATCH] ia64: Allow system-call number to be changed during system-call tracing (both for native and x86 system call tracing). This is needed by recent versions of strace and UML likes to do that, too. --- arch/ia64/ia32/ia32_entry.S | 31 ++++++++++++--------- arch/ia64/kernel/entry.S | 54 +++++++++++++++++-------------------- arch/ia64/kernel/ivt.S | 10 ++++--- arch/ia64/kernel/ptrace.c | 4 ++- include/asm-ia64/ia32.h | 10 +++++-- 5 files changed, 59 insertions(+), 50 deletions(-) diff --git a/arch/ia64/ia32/ia32_entry.S b/arch/ia64/ia32/ia32_entry.S index 1230fd2b479fa..f8b22ce60ff2c 100644 --- a/arch/ia64/ia32/ia32_entry.S +++ b/arch/ia64/ia32/ia32_entry.S @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -141,27 +142,35 @@ GLOBAL_ENTRY(ia32_trace_syscall) adds r2=IA64_PT_REGS_R8_OFFSET+16,sp ;; st8 [r2]=r3 // initialize return code to -ENOSYS - br.call.sptk.few rp=invoke_syscall_trace // give parent a chance to catch syscall args - // Need to reload arguments (they may be changed by the tracing process) - adds r2=IA64_PT_REGS_R9_OFFSET+16,sp // r2 = &pt_regs.r9 + br.call.sptk.few rp=syscall_trace // give parent a chance to catch syscall args +.ret2: // Need to reload arguments (they may be changed by the tracing process) + adds r2=IA64_PT_REGS_R1_OFFSET+16,sp // r2 = &pt_regs.r1 adds r3=IA64_PT_REGS_R13_OFFSET+16,sp // r3 = &pt_regs.r13 + mov r15=IA32_NR_syscalls + ;; + ld4 r8=[r2],IA64_PT_REGS_R9_OFFSET-IA64_PT_REGS_R1_OFFSET + movl r16=ia32_syscall_table ;; ld4 r33=[r2],8 // r9 == ecx ld4 r37=[r3],16 // r13 == ebp + cmp.ltu.unc p6,p7=r8,r15 ;; ld4 r34=[r2],8 // r10 == edx ld4 r36=[r3],8 // r15 == edi +(p6) shladd r16=r8,3,r16 // force ni_syscall if not valid syscall number + ;; + ld8 r16=[r16] ;; ld4 r32=[r2],8 // r11 == ebx + mov b6=r16 ld4 r35=[r3],8 // r14 == esi - ;; -.ret2: br.call.sptk.few rp=b6 // do the syscall + br.call.sptk.few rp=b6 // do the syscall .ia32_strace_check_retval: cmp.lt p6,p0=r8,r0 // syscall failed? adds r2=IA64_PT_REGS_R8_OFFSET+16,sp // r2 = &pt_regs.r8 ;; st8.spill [r2]=r8 // store return value in slot for r8 - br.call.sptk.few rp=invoke_syscall_trace // give parent a chance to catch return value + br.call.sptk.few rp=syscall_trace // give parent a chance to catch return value .ret4: alloc r2=ar.pfs,0,0,0,0 // drop the syscall argument frame br.cond.sptk.many ia64_leave_kernel END(ia32_trace_syscall) @@ -469,10 +478,6 @@ ia32_syscall_table: data8 sys_ni_syscall data8 sys_statfs64 data8 sys_fstatfs64 - data8 sys_ni_syscall - - /* - * CAUTION: If any system calls are added beyond this point - * then the check in `arch/ia64/kernel/ivt.S' will have - * to be modified also. You've been warned. - */ + + // guard against failures to increase IA32_NR_syscalls + .org ia32_syscall_table + 8*IA32_NR_syscalls diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S index b189495af5d2d..27943979a9c14 100644 --- a/arch/ia64/kernel/entry.S +++ b/arch/ia64/kernel/entry.S @@ -483,34 +483,11 @@ GLOBAL_ENTRY(clone) br.ret.sptk.many rp END(clone) - /* - * We invoke syscall_trace through this intermediate function to - * ensure that the syscall input arguments are not clobbered. We - * also use it to preserve b6, which contains the syscall entry point. - */ -GLOBAL_ENTRY(invoke_syscall_trace) - .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8) - alloc loc1=ar.pfs,8,3,0,0 - mov loc0=rp - .body - mov loc2=b6 - ;; - br.call.sptk.many rp=syscall_trace -.ret3: mov rp=loc0 - mov ar.pfs=loc1 - mov b6=loc2 - br.ret.sptk.many rp -END(invoke_syscall_trace) - /* * Invoke a system call, but do some tracing before and after the call. * We MUST preserve the current register frame throughout this routine * because some system calls (such as ia64_execve) directly * manipulate ar.pfs. - * - * Input: - * r15 = syscall number - * b6 = syscall entry point */ .global ia64_strace_leave_kernel @@ -522,21 +499,38 @@ GLOBAL_ENTRY(ia64_trace_syscall) */ nop.m 0 nop.i 0 - br.call.sptk.many rp=invoke_syscall_trace // give parent a chance to catch syscall args + br.call.sptk.many rp=syscall_trace // give parent a chance to catch syscall args } -.ret6: br.call.sptk.many rp=b6 // do the syscall -strace_check_retval: + // the syscall number may have changed, so re-load it and re-calculate the + // syscall entry-point: + adds r15=PT(R15)+16,sp // r15 = &pt_regs.r15 (syscall #) + ;; + ld8 r15=[r15] + mov r3=NR_syscalls - 1 + ;; + adds r15=-1024,r15 + movl r16=sys_call_table + ;; + shladd r20=r15,3,r16 // r20 = sys_call_table + 8*(syscall-1024) + cmp.leu p6,p7=r15,r3 + ;; +(p6) ld8 r20=[r20] // load address of syscall entry point +(p7) movl r20=sys_ni_syscall + ;; + mov b6=r20 + br.call.sptk.many rp=b6 // do the syscall +.strace_check_retval: cmp.lt p6,p0=r8,r0 // syscall failed? adds r2=PT(R8)+16,sp // r2 = &pt_regs.r8 adds r3=PT(R10)+16,sp // r3 = &pt_regs.r10 mov r10=0 (p6) br.cond.sptk strace_error // syscall failed -> ;; // avoid RAW on r10 -strace_save_retval: +.strace_save_retval: .mem.offset 0,0; st8.spill [r2]=r8 // store return value in slot for r8 .mem.offset 8,0; st8.spill [r3]=r10 // clear error indication in slot for r10 ia64_strace_leave_kernel: - br.call.sptk.many rp=invoke_syscall_trace // give parent a chance to catch return value + br.call.sptk.many rp=syscall_trace // give parent a chance to catch return value .rety: br.cond.sptk ia64_leave_syscall strace_error: @@ -548,7 +542,7 @@ strace_error: ;; (p6) mov r10=-1 (p6) mov r8=r9 - br.cond.sptk strace_save_retval + br.cond.sptk .strace_save_retval END(ia64_trace_syscall) GLOBAL_ENTRY(ia64_ret_from_clone) @@ -573,7 +567,7 @@ GLOBAL_ENTRY(ia64_ret_from_clone) ;; mov r8=0 tbit.nz p6,p0=r2,TIF_SYSCALL_TRACE -(p6) br.cond.spnt strace_check_retval +(p6) br.cond.spnt .strace_check_retval ;; // added stop bits to prevent r8 dependency END(ia64_ret_from_clone) // fall through diff --git a/arch/ia64/kernel/ivt.S b/arch/ia64/kernel/ivt.S index 6a32b97b9e60f..8aed612cb284f 100644 --- a/arch/ia64/kernel/ivt.S +++ b/arch/ia64/kernel/ivt.S @@ -42,6 +42,7 @@ #include #include +#include #include #include #include @@ -705,13 +706,14 @@ ENTRY(break_fault) movl r2=ia64_ret_from_syscall ;; shladd r20=r15,3,r16 // r20 = sys_call_table + 8*(syscall-1024) - cmp.geu p0,p7=r3,r15 // (syscall > 0 && syscall < 1024 + NR_syscalls) ? + cmp.leu p6,p7=r15,r3 // (syscall > 0 && syscall < 1024 + NR_syscalls) ? mov rp=r2 // set the real return addr ;; -(p7) add r20=(__NR_ni_syscall-1024)*8,r16 // force __NR_ni_syscall +(p6) ld8 r20=[r20] // load address of syscall entry point +(p7) movl r20=sys_ni_syscall + add r2=TI_FLAGS+IA64_TASK_SIZE,r13 ;; - ld8 r20=[r20] // load address of syscall entry point ld4 r2=[r2] // r2 = current_thread_info()->flags ;; tbit.z p8,p0=r2,TIF_SYSCALL_TRACE @@ -1513,7 +1515,7 @@ ENTRY(dispatch_to_ia32_handler) alloc r15=ar.pfs,0,0,6,0 // must first in an insn group ;; ld4 r8=[r14],8 // r8 == eax (syscall number) - mov r15=270 // number of entries in ia32 system call table + mov r15=IA32_NR_syscalls ;; cmp.ltu.unc p6,p7=r8,r15 ld4 out1=[r14],8 // r9 == ecx diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c index 427bc87ae6089..cbcb2b24fe8fc 100644 --- a/arch/ia64/kernel/ptrace.c +++ b/arch/ia64/kernel/ptrace.c @@ -1421,7 +1421,9 @@ sys_ptrace (long request, pid_t pid, unsigned long addr, unsigned long data, return ret; } -void +/* "asmlinkage" so the input arguments are preserved... */ + +asmlinkage void syscall_trace (void) { if (!test_thread_flag(TIF_SYSCALL_TRACE)) diff --git a/include/asm-ia64/ia32.h b/include/asm-ia64/ia32.h index 4c8fd32b8b78f..da5a1f22c5662 100644 --- a/include/asm-ia64/ia32.h +++ b/include/asm-ia64/ia32.h @@ -6,7 +6,11 @@ #include #include -#ifdef CONFIG_IA32_SUPPORT +#define IA32_NR_syscalls 270 /* length of syscall table */ + +#ifndef __ASSEMBLY__ + +# ifdef CONFIG_IA32_SUPPORT extern void ia32_cpu_init (void); extern void ia32_boot_gdt_init (void); @@ -15,10 +19,12 @@ extern int ia32_exception (struct pt_regs *regs, unsigned long isr); extern int ia32_intercept (struct pt_regs *regs, unsigned long isr); extern int ia32_clone_tls (struct task_struct *child, struct pt_regs *childregs); -#endif /* !CONFIG_IA32_SUPPORT */ +# endif /* !CONFIG_IA32_SUPPORT */ /* Declare this unconditionally, so we don't get warnings for unreachable code. */ extern int ia32_setup_frame1 (int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set, struct pt_regs *regs); +#endif /* !__ASSEMBLY__ */ + #endif /* _ASM_IA64_IA32_H */ -- 2.53.0