Merge branch 'x86/tracehook' into x86-v28-for-linus-phase1

Conflicts:
	arch/x86/kernel/signal_64.c

Signed-off-by: Ingo Molnar <mingo@elte.hu>
This commit is contained in:
Ingo Molnar 2008-10-06 18:16:40 +02:00
commit b159d7a989
7 changed files with 249 additions and 66 deletions

View file

@ -29,6 +29,7 @@ config X86
select HAVE_FTRACE
select HAVE_KVM if ((X86_32 && !X86_VOYAGER && !X86_VISWS && !X86_NUMAQ) || X86_64)
select HAVE_ARCH_KGDB if !X86_VOYAGER
select HAVE_ARCH_TRACEHOOK
select HAVE_GENERIC_DMA_COHERENT if X86_32
select HAVE_EFFICIENT_UNALIGNED_ACCESS

View file

@ -14,6 +14,7 @@
#include <linux/errno.h>
#include <linux/ptrace.h>
#include <linux/regset.h>
#include <linux/tracehook.h>
#include <linux/user.h>
#include <linux/elf.h>
#include <linux/security.h>
@ -1469,30 +1470,6 @@ void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, int error_code)
force_sig_info(SIGTRAP, &info, tsk);
}
static void syscall_trace(struct pt_regs *regs)
{
if (!(current->ptrace & PT_PTRACED))
return;
#if 0
printk("trace %s ip %lx sp %lx ax %d origrax %d caller %lx tiflags %x ptrace %x\n",
current->comm,
regs->ip, regs->sp, regs->ax, regs->orig_ax, __builtin_return_address(0),
current_thread_info()->flags, current->ptrace);
#endif
ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
? 0x80 : 0));
/*
* this isn't the same as continuing with a signal, but it will do
* for normal use. strace only continues with a signal if the
* stopping signal is not SIGTRAP. -brl
*/
if (current->exit_code) {
send_sig(current->exit_code, current, 1);
current->exit_code = 0;
}
}
#ifdef CONFIG_X86_32
# define IS_IA32 1
@ -1526,8 +1503,9 @@ asmregparm long syscall_trace_enter(struct pt_regs *regs)
if (unlikely(test_thread_flag(TIF_SYSCALL_EMU)))
ret = -1L;
if (ret || test_thread_flag(TIF_SYSCALL_TRACE))
syscall_trace(regs);
if ((ret || test_thread_flag(TIF_SYSCALL_TRACE)) &&
tracehook_report_syscall_entry(regs))
ret = -1L;
if (unlikely(current->audit_context)) {
if (IS_IA32)
@ -1553,7 +1531,7 @@ asmregparm void syscall_trace_leave(struct pt_regs *regs)
audit_syscall_exit(AUDITSC_RESULT(regs->ax), regs->ax);
if (test_thread_flag(TIF_SYSCALL_TRACE))
syscall_trace(regs);
tracehook_report_syscall_exit(regs, 0);
/*
* If TIF_SYSCALL_EMU is set, we only get here because of
@ -1569,6 +1547,6 @@ asmregparm void syscall_trace_leave(struct pt_regs *regs)
* system call instruction.
*/
if (test_thread_flag(TIF_SINGLESTEP) &&
(current->ptrace & PT_PTRACED))
tracehook_consider_fatal_signal(current, SIGTRAP, SIG_DFL))
send_sigtrap(current, regs, 0);
}

View file

@ -17,6 +17,7 @@
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/tracehook.h>
#include <linux/elf.h>
#include <linux/smp.h>
#include <linux/mm.h>
@ -559,8 +560,6 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
* handler too.
*/
regs->flags &= ~X86_EFLAGS_TF;
if (test_thread_flag(TIF_SINGLESTEP))
ptrace_notify(SIGTRAP);
spin_lock_irq(&current->sighand->siglock);
sigorsets(&current->blocked, &current->blocked, &ka->sa.sa_mask);
@ -569,6 +568,9 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock);
tracehook_signal_handler(sig, info, ka, regs,
test_thread_flag(TIF_SINGLESTEP));
return 0;
}
@ -662,5 +664,10 @@ do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
if (thread_info_flags & _TIF_SIGPENDING)
do_signal(regs);
if (thread_info_flags & _TIF_NOTIFY_RESUME) {
clear_thread_flag(TIF_NOTIFY_RESUME);
tracehook_notify_resume(regs);
}
clear_thread_flag(TIF_IRET);
}

View file

@ -15,6 +15,7 @@
#include <linux/errno.h>
#include <linux/wait.h>
#include <linux/ptrace.h>
#include <linux/tracehook.h>
#include <linux/unistd.h>
#include <linux/stddef.h>
#include <linux/personality.h>
@ -26,6 +27,7 @@
#include <asm/proto.h>
#include <asm/ia32_unistd.h>
#include <asm/mce.h>
#include <asm/syscall.h>
#include <asm/syscalls.h>
#include "sigframe.h"
@ -355,35 +357,6 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
return -EFAULT;
}
/*
* Return -1L or the syscall number that @regs is executing.
*/
static long current_syscall(struct pt_regs *regs)
{
/*
* We always sign-extend a -1 value being set here,
* so this is always either -1L or a syscall number.
*/
return regs->orig_ax;
}
/*
* Return a value that is -EFOO if the system call in @regs->orig_ax
* returned an error. This only works for @regs from @current.
*/
static long current_syscall_ret(struct pt_regs *regs)
{
#ifdef CONFIG_IA32_EMULATION
if (test_thread_flag(TIF_IA32))
/*
* Sign-extend the value so (int)-EFOO becomes (long)-EFOO
* and will match correctly in comparisons.
*/
return (int) regs->ax;
#endif
return regs->ax;
}
/*
* OK, we're invoking a handler
*/
@ -395,9 +368,9 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
int ret;
/* Are we from a system call? */
if (current_syscall(regs) >= 0) {
if (syscall_get_nr(current, regs) >= 0) {
/* If so, check system call restarting.. */
switch (current_syscall_ret(regs)) {
switch (syscall_get_error(current, regs)) {
case -ERESTART_RESTARTBLOCK:
case -ERESTARTNOHAND:
regs->ax = -EINTR;
@ -454,8 +427,6 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
* handler too.
*/
regs->flags &= ~X86_EFLAGS_TF;
if (test_thread_flag(TIF_SINGLESTEP))
ptrace_notify(SIGTRAP);
spin_lock_irq(&current->sighand->siglock);
sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
@ -463,6 +434,9 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
sigaddset(&current->blocked,sig);
recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock);
tracehook_signal_handler(sig, info, ka, regs,
test_thread_flag(TIF_SINGLESTEP));
}
return ret;
@ -519,9 +493,9 @@ static void do_signal(struct pt_regs *regs)
}
/* Did we come from a system call? */
if (current_syscall(regs) >= 0) {
if (syscall_get_nr(current, regs) >= 0) {
/* Restart the system call - no handlers present */
switch (current_syscall_ret(regs)) {
switch (syscall_get_error(current, regs)) {
case -ERESTARTNOHAND:
case -ERESTARTSYS:
case -ERESTARTNOINTR:
@ -559,6 +533,11 @@ void do_notify_resume(struct pt_regs *regs, void *unused,
/* deal with pending signal delivery */
if (thread_info_flags & _TIF_SIGPENDING)
do_signal(regs);
if (thread_info_flags & _TIF_NOTIFY_RESUME) {
clear_thread_flag(TIF_NOTIFY_RESUME);
tracehook_notify_resume(regs);
}
}
void signal_fault(struct pt_regs *regs, void __user *frame, char *where)

View file

@ -250,6 +250,11 @@ static inline unsigned long frame_pointer(struct pt_regs *regs)
return regs->bp;
}
static inline unsigned long user_stack_pointer(struct pt_regs *regs)
{
return regs->sp;
}
/*
* These are defined as per linux/ptrace.h, which see.
*/

211
include/asm-x86/syscall.h Normal file
View file

@ -0,0 +1,211 @@
/*
* Access to user system call parameters and results
*
* Copyright (C) 2008 Red Hat, Inc. All rights reserved.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU General Public License v.2.
*
* See asm-generic/syscall.h for descriptions of what we must do here.
*/
#ifndef _ASM_SYSCALL_H
#define _ASM_SYSCALL_H 1
#include <linux/sched.h>
#include <linux/err.h>
static inline long syscall_get_nr(struct task_struct *task,
struct pt_regs *regs)
{
/*
* We always sign-extend a -1 value being set here,
* so this is always either -1L or a syscall number.
*/
return regs->orig_ax;
}
static inline void syscall_rollback(struct task_struct *task,
struct pt_regs *regs)
{
regs->ax = regs->orig_ax;
}
static inline long syscall_get_error(struct task_struct *task,
struct pt_regs *regs)
{
unsigned long error = regs->ax;
#ifdef CONFIG_IA32_EMULATION
/*
* TS_COMPAT is set for 32-bit syscall entries and then
* remains set until we return to user mode.
*/
if (task_thread_info(task)->status & TS_COMPAT)
/*
* Sign-extend the value so (int)-EFOO becomes (long)-EFOO
* and will match correctly in comparisons.
*/
error = (long) (int) error;
#endif
return IS_ERR_VALUE(error) ? error : 0;
}
static inline long syscall_get_return_value(struct task_struct *task,
struct pt_regs *regs)
{
return regs->ax;
}
static inline void syscall_set_return_value(struct task_struct *task,
struct pt_regs *regs,
int error, long val)
{
regs->ax = (long) error ?: val;
}
#ifdef CONFIG_X86_32
static inline void syscall_get_arguments(struct task_struct *task,
struct pt_regs *regs,
unsigned int i, unsigned int n,
unsigned long *args)
{
BUG_ON(i + n > 6);
memcpy(args, &regs->bx + i, n * sizeof(args[0]));
}
static inline void syscall_set_arguments(struct task_struct *task,
struct pt_regs *regs,
unsigned int i, unsigned int n,
const unsigned long *args)
{
BUG_ON(i + n > 6);
memcpy(&regs->bx + i, args, n * sizeof(args[0]));
}
#else /* CONFIG_X86_64 */
static inline void syscall_get_arguments(struct task_struct *task,
struct pt_regs *regs,
unsigned int i, unsigned int n,
unsigned long *args)
{
# ifdef CONFIG_IA32_EMULATION
if (task_thread_info(task)->status & TS_COMPAT)
switch (i + n) {
case 6:
if (!n--) break;
*args++ = regs->bp;
case 5:
if (!n--) break;
*args++ = regs->di;
case 4:
if (!n--) break;
*args++ = regs->si;
case 3:
if (!n--) break;
*args++ = regs->dx;
case 2:
if (!n--) break;
*args++ = regs->cx;
case 1:
if (!n--) break;
*args++ = regs->bx;
case 0:
if (!n--) break;
default:
BUG();
break;
}
else
# endif
switch (i + n) {
case 6:
if (!n--) break;
*args++ = regs->r9;
case 5:
if (!n--) break;
*args++ = regs->r8;
case 4:
if (!n--) break;
*args++ = regs->r10;
case 3:
if (!n--) break;
*args++ = regs->dx;
case 2:
if (!n--) break;
*args++ = regs->si;
case 1:
if (!n--) break;
*args++ = regs->di;
case 0:
if (!n--) break;
default:
BUG();
break;
}
}
static inline void syscall_set_arguments(struct task_struct *task,
struct pt_regs *regs,
unsigned int i, unsigned int n,
const unsigned long *args)
{
# ifdef CONFIG_IA32_EMULATION
if (task_thread_info(task)->status & TS_COMPAT)
switch (i + n) {
case 6:
if (!n--) break;
regs->bp = *args++;
case 5:
if (!n--) break;
regs->di = *args++;
case 4:
if (!n--) break;
regs->si = *args++;
case 3:
if (!n--) break;
regs->dx = *args++;
case 2:
if (!n--) break;
regs->cx = *args++;
case 1:
if (!n--) break;
regs->bx = *args++;
case 0:
if (!n--) break;
default:
BUG();
}
else
# endif
switch (i + n) {
case 6:
if (!n--) break;
regs->r9 = *args++;
case 5:
if (!n--) break;
regs->r8 = *args++;
case 4:
if (!n--) break;
regs->r10 = *args++;
case 3:
if (!n--) break;
regs->dx = *args++;
case 2:
if (!n--) break;
regs->si = *args++;
case 1:
if (!n--) break;
regs->di = *args++;
case 0:
if (!n--) break;
default:
BUG();
}
}
#endif /* CONFIG_X86_32 */
#endif /* _ASM_SYSCALL_H */

View file

@ -71,6 +71,7 @@ struct thread_info {
* Warning: layout of LSW is hardcoded in entry.S
*/
#define TIF_SYSCALL_TRACE 0 /* syscall trace active */
#define TIF_NOTIFY_RESUME 1 /* callback before returning to user */
#define TIF_SIGPENDING 2 /* signal pending */
#define TIF_NEED_RESCHED 3 /* rescheduling necessary */
#define TIF_SINGLESTEP 4 /* reenable singlestep on user return*/
@ -93,6 +94,7 @@ struct thread_info {
#define TIF_BTS_TRACE_TS 27 /* record scheduling event timestamps */
#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE)
#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME)
#define _TIF_SIGPENDING (1 << TIF_SIGPENDING)
#define _TIF_SINGLESTEP (1 << TIF_SINGLESTEP)
#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)
@ -133,7 +135,7 @@ struct thread_info {
/* Only used for 64 bit */
#define _TIF_DO_NOTIFY_MASK \
(_TIF_SIGPENDING|_TIF_MCE_NOTIFY)
(_TIF_SIGPENDING|_TIF_MCE_NOTIFY|_TIF_NOTIFY_RESUME)
/* flags to check in __switch_to() */
#define _TIF_WORK_CTXSW \