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/ia32.h>
#include <asm/offsets.h>
#include <asm/signal.h>
#include <asm/thread_info.h>
......@@ -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
......@@ -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
......
......@@ -42,6 +42,7 @@
#include <asm/asmmacro.h>
#include <asm/break.h>
#include <asm/ia32.h>
#include <asm/kregs.h>
#include <asm/offsets.h>
#include <asm/pgtable.h>
......@@ -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
......
......@@ -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))
......
......@@ -6,7 +6,11 @@
#include <asm/ptrace.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_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 */
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