Commit aca8b603 authored by David Mosberger's avatar David Mosberger

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.
parent 2c2c4c6e
#include <asm/asmmacro.h> #include <asm/asmmacro.h>
#include <asm/ia32.h>
#include <asm/offsets.h> #include <asm/offsets.h>
#include <asm/signal.h> #include <asm/signal.h>
#include <asm/thread_info.h> #include <asm/thread_info.h>
...@@ -141,27 +142,35 @@ GLOBAL_ENTRY(ia32_trace_syscall) ...@@ -141,27 +142,35 @@ GLOBAL_ENTRY(ia32_trace_syscall)
adds r2=IA64_PT_REGS_R8_OFFSET+16,sp adds r2=IA64_PT_REGS_R8_OFFSET+16,sp
;; ;;
st8 [r2]=r3 // initialize return code to -ENOSYS st8 [r2]=r3 // initialize return code to -ENOSYS
br.call.sptk.few rp=invoke_syscall_trace // give parent a chance to catch syscall args br.call.sptk.few rp=syscall_trace // give parent a chance to catch syscall args
// Need to reload arguments (they may be changed by the tracing process) .ret2: // 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 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 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 r33=[r2],8 // r9 == ecx
ld4 r37=[r3],16 // r13 == ebp ld4 r37=[r3],16 // r13 == ebp
cmp.ltu.unc p6,p7=r8,r15
;; ;;
ld4 r34=[r2],8 // r10 == edx ld4 r34=[r2],8 // r10 == edx
ld4 r36=[r3],8 // r15 == edi 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 ld4 r32=[r2],8 // r11 == ebx
mov b6=r16
ld4 r35=[r3],8 // r14 == esi ld4 r35=[r3],8 // r14 == esi
;; br.call.sptk.few rp=b6 // do the syscall
.ret2: br.call.sptk.few rp=b6 // do the syscall
.ia32_strace_check_retval: .ia32_strace_check_retval:
cmp.lt p6,p0=r8,r0 // syscall failed? cmp.lt p6,p0=r8,r0 // syscall failed?
adds r2=IA64_PT_REGS_R8_OFFSET+16,sp // r2 = &pt_regs.r8 adds r2=IA64_PT_REGS_R8_OFFSET+16,sp // r2 = &pt_regs.r8
;; ;;
st8.spill [r2]=r8 // store return value in slot for 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 .ret4: alloc r2=ar.pfs,0,0,0,0 // drop the syscall argument frame
br.cond.sptk.many ia64_leave_kernel br.cond.sptk.many ia64_leave_kernel
END(ia32_trace_syscall) END(ia32_trace_syscall)
...@@ -469,10 +478,6 @@ ia32_syscall_table: ...@@ -469,10 +478,6 @@ ia32_syscall_table:
data8 sys_ni_syscall data8 sys_ni_syscall
data8 sys_statfs64 data8 sys_statfs64
data8 sys_fstatfs64 data8 sys_fstatfs64
data8 sys_ni_syscall
// guard against failures to increase IA32_NR_syscalls
/* .org ia32_syscall_table + 8*IA32_NR_syscalls
* 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.
*/
...@@ -483,34 +483,11 @@ GLOBAL_ENTRY(clone) ...@@ -483,34 +483,11 @@ GLOBAL_ENTRY(clone)
br.ret.sptk.many rp br.ret.sptk.many rp
END(clone) 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. * Invoke a system call, but do some tracing before and after the call.
* We MUST preserve the current register frame throughout this routine * We MUST preserve the current register frame throughout this routine
* because some system calls (such as ia64_execve) directly * because some system calls (such as ia64_execve) directly
* manipulate ar.pfs. * manipulate ar.pfs.
*
* Input:
* r15 = syscall number
* b6 = syscall entry point
*/ */
.global ia64_strace_leave_kernel .global ia64_strace_leave_kernel
...@@ -522,21 +499,38 @@ GLOBAL_ENTRY(ia64_trace_syscall) ...@@ -522,21 +499,38 @@ GLOBAL_ENTRY(ia64_trace_syscall)
*/ */
nop.m 0 nop.m 0
nop.i 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 // the syscall number may have changed, so re-load it and re-calculate the
strace_check_retval: // 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? cmp.lt p6,p0=r8,r0 // syscall failed?
adds r2=PT(R8)+16,sp // r2 = &pt_regs.r8 adds r2=PT(R8)+16,sp // r2 = &pt_regs.r8
adds r3=PT(R10)+16,sp // r3 = &pt_regs.r10 adds r3=PT(R10)+16,sp // r3 = &pt_regs.r10
mov r10=0 mov r10=0
(p6) br.cond.sptk strace_error // syscall failed -> (p6) br.cond.sptk strace_error // syscall failed ->
;; // avoid RAW on r10 ;; // 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 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 .mem.offset 8,0; st8.spill [r3]=r10 // clear error indication in slot for r10
ia64_strace_leave_kernel: 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 .rety: br.cond.sptk ia64_leave_syscall
strace_error: strace_error:
...@@ -548,7 +542,7 @@ strace_error: ...@@ -548,7 +542,7 @@ strace_error:
;; ;;
(p6) mov r10=-1 (p6) mov r10=-1
(p6) mov r8=r9 (p6) mov r8=r9
br.cond.sptk strace_save_retval br.cond.sptk .strace_save_retval
END(ia64_trace_syscall) END(ia64_trace_syscall)
GLOBAL_ENTRY(ia64_ret_from_clone) GLOBAL_ENTRY(ia64_ret_from_clone)
...@@ -573,7 +567,7 @@ GLOBAL_ENTRY(ia64_ret_from_clone) ...@@ -573,7 +567,7 @@ GLOBAL_ENTRY(ia64_ret_from_clone)
;; ;;
mov r8=0 mov r8=0
tbit.nz p6,p0=r2,TIF_SYSCALL_TRACE 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 ;; // added stop bits to prevent r8 dependency
END(ia64_ret_from_clone) END(ia64_ret_from_clone)
// fall through // fall through
......
...@@ -42,6 +42,7 @@ ...@@ -42,6 +42,7 @@
#include <asm/asmmacro.h> #include <asm/asmmacro.h>
#include <asm/break.h> #include <asm/break.h>
#include <asm/ia32.h>
#include <asm/kregs.h> #include <asm/kregs.h>
#include <asm/offsets.h> #include <asm/offsets.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
...@@ -705,13 +706,14 @@ ENTRY(break_fault) ...@@ -705,13 +706,14 @@ ENTRY(break_fault)
movl r2=ia64_ret_from_syscall movl r2=ia64_ret_from_syscall
;; ;;
shladd r20=r15,3,r16 // r20 = sys_call_table + 8*(syscall-1024) 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 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 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 ld4 r2=[r2] // r2 = current_thread_info()->flags
;; ;;
tbit.z p8,p0=r2,TIF_SYSCALL_TRACE tbit.z p8,p0=r2,TIF_SYSCALL_TRACE
...@@ -1513,7 +1515,7 @@ ENTRY(dispatch_to_ia32_handler) ...@@ -1513,7 +1515,7 @@ ENTRY(dispatch_to_ia32_handler)
alloc r15=ar.pfs,0,0,6,0 // must first in an insn group alloc r15=ar.pfs,0,0,6,0 // must first in an insn group
;; ;;
ld4 r8=[r14],8 // r8 == eax (syscall number) 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 cmp.ltu.unc p6,p7=r8,r15
ld4 out1=[r14],8 // r9 == ecx ld4 out1=[r14],8 // r9 == ecx
......
...@@ -1421,7 +1421,9 @@ sys_ptrace (long request, pid_t pid, unsigned long addr, unsigned long data, ...@@ -1421,7 +1421,9 @@ sys_ptrace (long request, pid_t pid, unsigned long addr, unsigned long data,
return ret; return ret;
} }
void /* "asmlinkage" so the input arguments are preserved... */
asmlinkage void
syscall_trace (void) syscall_trace (void)
{ {
if (!test_thread_flag(TIF_SYSCALL_TRACE)) if (!test_thread_flag(TIF_SYSCALL_TRACE))
......
...@@ -6,7 +6,11 @@ ...@@ -6,7 +6,11 @@
#include <asm/ptrace.h> #include <asm/ptrace.h>
#include <asm/signal.h> #include <asm/signal.h>
#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_cpu_init (void);
extern void ia32_boot_gdt_init (void); extern void ia32_boot_gdt_init (void);
...@@ -15,10 +19,12 @@ extern int ia32_exception (struct pt_regs *regs, unsigned long isr); ...@@ -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_intercept (struct pt_regs *regs, unsigned long isr);
extern int ia32_clone_tls (struct task_struct *child, struct pt_regs *childregs); 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. */ /* 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, extern int ia32_setup_frame1 (int sig, struct k_sigaction *ka, siginfo_t *info,
sigset_t *set, struct pt_regs *regs); sigset_t *set, struct pt_regs *regs);
#endif /* !__ASSEMBLY__ */
#endif /* _ASM_IA64_IA32_H */ #endif /* _ASM_IA64_IA32_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment