Commit c25f215b authored by Linus Torvalds's avatar Linus Torvalds

x86: common send_sigtrap helper for debug event SIGTRAP's,

and use that for system call single-step events.

This one also gets the user mode test right, and makes sure
the siginfo is not leaking any stack contents.
parent b7d88a5e
...@@ -553,6 +553,24 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) ...@@ -553,6 +553,24 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
return ret; return ret;
} }
void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, int error_code)
{
struct siginfo info;
tsk->thread.trap_no = 1;
tsk->thread.error_code = error_code;
memset(&info, 0, sizeof(info));
info.si_signo = SIGTRAP;
info.si_code = TRAP_BRKPT;
/* User-mode eip? */
info.si_addr = user_mode(regs) ? (void __user *) regs->eip : NULL;
/* Send us the fakey SIGTRAP */
force_sig_info(SIGTRAP, &info, tsk);
}
/* notification of system call entry/exit /* notification of system call entry/exit
* - triggered by current->work.syscall_trace * - triggered by current->work.syscall_trace
*/ */
...@@ -568,15 +586,19 @@ void do_syscall_trace(struct pt_regs *regs, int entryexit) ...@@ -568,15 +586,19 @@ void do_syscall_trace(struct pt_regs *regs, int entryexit)
audit_syscall_exit(current, regs->eax); audit_syscall_exit(current, regs->eax);
} }
if (!test_thread_flag(TIF_SYSCALL_TRACE) &&
!test_thread_flag(TIF_SINGLESTEP))
return;
if (!(current->ptrace & PT_PTRACED)) if (!(current->ptrace & PT_PTRACED))
return; return;
/* Fake a debug trap */
if (test_thread_flag(TIF_SINGLESTEP))
send_sigtrap(current, regs, 0);
if (!test_thread_flag(TIF_SYSCALL_TRACE))
return;
/* the 0x80 provides a way for the tracing parent to distinguish /* the 0x80 provides a way for the tracing parent to distinguish
between a syscall stop and SIGTRAP delivery */ between a syscall stop and SIGTRAP delivery */
ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) && ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ? 0x80 : 0));
!test_thread_flag(TIF_SINGLESTEP) ? 0x80 : 0));
/* /*
* this isn't the same as continuing with a signal, but it will do * this isn't the same as continuing with a signal, but it will do
......
...@@ -682,7 +682,6 @@ fastcall void do_debug(struct pt_regs * regs, long error_code) ...@@ -682,7 +682,6 @@ fastcall void do_debug(struct pt_regs * regs, long error_code)
{ {
unsigned int condition; unsigned int condition;
struct task_struct *tsk = current; struct task_struct *tsk = current;
siginfo_t info;
__asm__ __volatile__("movl %%db6,%0" : "=r" (condition)); __asm__ __volatile__("movl %%db6,%0" : "=r" (condition));
...@@ -723,18 +722,7 @@ fastcall void do_debug(struct pt_regs * regs, long error_code) ...@@ -723,18 +722,7 @@ fastcall void do_debug(struct pt_regs * regs, long error_code)
} }
/* Ok, finally something we can handle */ /* Ok, finally something we can handle */
tsk->thread.trap_no = 1; send_sigtrap(tsk, regs, error_code);
tsk->thread.error_code = error_code;
info.si_signo = SIGTRAP;
info.si_errno = 0;
info.si_code = TRAP_BRKPT;
/* If this is a kernel mode trap, save the user PC on entry to
* the kernel, that's what the debugger can make sense of.
*/
info.si_addr = ((regs->xcs & 3) == 0) ? (void __user *)tsk->thread.eip
: (void __user *)regs->eip;
force_sig_info(SIGTRAP, &info, tsk);
/* Disable additional traps. They'll be re-enabled when /* Disable additional traps. They'll be re-enabled when
* the signal is delivered. * the signal is delivered.
......
...@@ -55,6 +55,8 @@ struct pt_regs { ...@@ -55,6 +55,8 @@ struct pt_regs {
#define PTRACE_SET_THREAD_AREA 26 #define PTRACE_SET_THREAD_AREA 26
#ifdef __KERNEL__ #ifdef __KERNEL__
struct task_struct;
extern void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, int error_code);
#define user_mode(regs) ((VM_MASK & (regs)->eflags) || (3 & (regs)->xcs)) #define user_mode(regs) ((VM_MASK & (regs)->eflags) || (3 & (regs)->xcs))
#define instruction_pointer(regs) ((regs)->eip) #define instruction_pointer(regs) ((regs)->eip)
#if defined(CONFIG_SMP) && defined(CONFIG_FRAME_POINTER) #if defined(CONFIG_SMP) && defined(CONFIG_FRAME_POINTER)
......
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