Commit cae7c30a authored by Roland McGrath's avatar Roland McGrath Committed by Linus Torvalds

[PATCH] Fix x86-64 singlestep through sigreturn system call

This patch just directly clones Davide Libenzi's i386 code for x86-64 in
both 64-bit and 32-bit cases.  With this, the behavior of single-stepping
all system calls is consistent.  

The syscall exit tracing caused by TIF_SINGLESTEP is superfluous in the
case of sysret returns, but harmlessly so (since continuing afterward with
PTRACE_CONT will have cleared TF as well as TIF_SINGLESTEP).  I figured
that little bit of extra processing in the single-step case was better than
adding code to ignore the flag in the sysret case.
Signed-off-by: default avatarRoland McGrath <roland@redhat.com>
Cc: <ak@muc.de>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent b9cbc585
......@@ -297,7 +297,7 @@ int_very_careful:
sti
SAVE_REST
/* Check for syscall exit trace */
testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),%edx
testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP),%edx
jz int_signal
pushq %rdi
leaq 8(%rsp),%rdi # &ptregs -> arg1
......@@ -305,6 +305,7 @@ int_very_careful:
popq %rdi
btr $TIF_SYSCALL_TRACE,%edi
btr $TIF_SYSCALL_AUDIT,%edi
btr $TIF_SINGLESTEP,%edi
jmp int_restore_rest
int_signal:
......
......@@ -88,6 +88,7 @@ void ptrace_disable(struct task_struct *child)
{
long tmp;
clear_tsk_thread_flag(child, TIF_SINGLESTEP);
tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG;
put_stack_long(child, EFL_OFFSET, tmp);
}
......@@ -344,6 +345,7 @@ asmlinkage long sys_ptrace(long request, long pid, unsigned long addr, long data
set_tsk_thread_flag(child,TIF_SYSCALL_TRACE);
else
clear_tsk_thread_flag(child,TIF_SYSCALL_TRACE);
clear_tsk_thread_flag(child, TIF_SINGLESTEP);
child->exit_code = data;
/* make sure the single step bit is not set. */
tmp = get_stack_long(child, EFL_OFFSET);
......@@ -395,6 +397,7 @@ asmlinkage long sys_ptrace(long request, long pid, unsigned long addr, long data
ret = 0;
if (child->state == TASK_ZOMBIE) /* already dead */
break;
clear_tsk_thread_flag(child, TIF_SINGLESTEP);
child->exit_code = SIGKILL;
/* make sure the single step bit is not set. */
tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG;
......@@ -416,6 +419,7 @@ asmlinkage long sys_ptrace(long request, long pid, unsigned long addr, long data
}
tmp = get_stack_long(child, EFL_OFFSET) | TRAP_FLAG;
put_stack_long(child, EFL_OFFSET, tmp);
set_tsk_thread_flag(child, TIF_SINGLESTEP);
child->exit_code = data;
/* give it a chance to run. */
wake_up_process(child);
......@@ -528,7 +532,8 @@ asmlinkage void syscall_trace_leave(struct pt_regs *regs)
if (unlikely(current->audit_context))
audit_syscall_exit(current, regs->rax);
if (test_thread_flag(TIF_SYSCALL_TRACE)
if ((test_thread_flag(TIF_SYSCALL_TRACE)
|| test_thread_flag(TIF_SINGLESTEP))
&& (current->ptrace & PT_PTRACED))
syscall_trace(regs);
}
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