mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-12 13:55:32 +00:00
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:
commit
b159d7a989
7 changed files with 249 additions and 66 deletions
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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(¤t->sighand->siglock);
|
||||
sigorsets(¤t->blocked, ¤t->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(¤t->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);
|
||||
}
|
||||
|
|
|
@ -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(¤t->sighand->siglock);
|
||||
sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask);
|
||||
|
@ -463,6 +434,9 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
|
|||
sigaddset(¤t->blocked,sig);
|
||||
recalc_sigpending();
|
||||
spin_unlock_irq(¤t->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)
|
||||
|
|
|
@ -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
211
include/asm-x86/syscall.h
Normal 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, ®s->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(®s->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 */
|
|
@ -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 \
|
||||
|
|
Loading…
Reference in a new issue