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)
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
* - triggered by current->work.syscall_trace
*/
......@@ -568,15 +586,19 @@ void do_syscall_trace(struct pt_regs *regs, int entryexit)
audit_syscall_exit(current, regs->eax);
}
if (!test_thread_flag(TIF_SYSCALL_TRACE) &&
!test_thread_flag(TIF_SINGLESTEP))
return;
if (!(current->ptrace & PT_PTRACED))
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
between a syscall stop and SIGTRAP delivery */
ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) &&
!test_thread_flag(TIF_SINGLESTEP) ? 0x80 : 0));
ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ? 0x80 : 0));
/*
* 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)
{
unsigned int condition;
struct task_struct *tsk = current;
siginfo_t info;
__asm__ __volatile__("movl %%db6,%0" : "=r" (condition));
......@@ -723,18 +722,7 @@ fastcall void do_debug(struct pt_regs * regs, long error_code)
}
/* Ok, finally something we can handle */
tsk->thread.trap_no = 1;
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);
send_sigtrap(tsk, regs, error_code);
/* Disable additional traps. They'll be re-enabled when
* the signal is delivered.
......
......@@ -55,6 +55,8 @@ struct pt_regs {
#define PTRACE_SET_THREAD_AREA 26
#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 instruction_pointer(regs) ((regs)->eip)
#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