aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/Kconfig1
-rw-r--r--arch/x86/kernel/ptrace.c34
-rw-r--r--arch/x86/kernel/signal_32.c11
-rw-r--r--arch/x86/kernel/signal_64.c49
-rw-r--r--include/asm-x86/ptrace.h5
-rw-r--r--include/asm-x86/syscall.h211
-rw-r--r--include/asm-x86/thread_info.h4
7 files changed, 249 insertions, 66 deletions
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index ed92864d1325..ebfd7ff82ade 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -29,6 +29,7 @@ config X86
29 select HAVE_FTRACE 29 select HAVE_FTRACE
30 select HAVE_KVM if ((X86_32 && !X86_VOYAGER && !X86_VISWS && !X86_NUMAQ) || X86_64) 30 select HAVE_KVM if ((X86_32 && !X86_VOYAGER && !X86_VISWS && !X86_NUMAQ) || X86_64)
31 select HAVE_ARCH_KGDB if !X86_VOYAGER 31 select HAVE_ARCH_KGDB if !X86_VOYAGER
32 select HAVE_ARCH_TRACEHOOK
32 select HAVE_GENERIC_DMA_COHERENT if X86_32 33 select HAVE_GENERIC_DMA_COHERENT if X86_32
33 select HAVE_EFFICIENT_UNALIGNED_ACCESS 34 select HAVE_EFFICIENT_UNALIGNED_ACCESS
34 35
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index d00e756c05af..e375b658efc3 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -14,6 +14,7 @@
14#include <linux/errno.h> 14#include <linux/errno.h>
15#include <linux/ptrace.h> 15#include <linux/ptrace.h>
16#include <linux/regset.h> 16#include <linux/regset.h>
17#include <linux/tracehook.h>
17#include <linux/user.h> 18#include <linux/user.h>
18#include <linux/elf.h> 19#include <linux/elf.h>
19#include <linux/security.h> 20#include <linux/security.h>
@@ -1469,30 +1470,6 @@ void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, int error_code)
1469 force_sig_info(SIGTRAP, &info, tsk); 1470 force_sig_info(SIGTRAP, &info, tsk);
1470} 1471}
1471 1472
1472static void syscall_trace(struct pt_regs *regs)
1473{
1474 if (!(current->ptrace & PT_PTRACED))
1475 return;
1476
1477#if 0
1478 printk("trace %s ip %lx sp %lx ax %d origrax %d caller %lx tiflags %x ptrace %x\n",
1479 current->comm,
1480 regs->ip, regs->sp, regs->ax, regs->orig_ax, __builtin_return_address(0),
1481 current_thread_info()->flags, current->ptrace);
1482#endif
1483
1484 ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
1485 ? 0x80 : 0));
1486 /*
1487 * this isn't the same as continuing with a signal, but it will do
1488 * for normal use. strace only continues with a signal if the
1489 * stopping signal is not SIGTRAP. -brl
1490 */
1491 if (current->exit_code) {
1492 send_sig(current->exit_code, current, 1);
1493 current->exit_code = 0;
1494 }
1495}
1496 1473
1497#ifdef CONFIG_X86_32 1474#ifdef CONFIG_X86_32
1498# define IS_IA32 1 1475# define IS_IA32 1
@@ -1526,8 +1503,9 @@ asmregparm long syscall_trace_enter(struct pt_regs *regs)
1526 if (unlikely(test_thread_flag(TIF_SYSCALL_EMU))) 1503 if (unlikely(test_thread_flag(TIF_SYSCALL_EMU)))
1527 ret = -1L; 1504 ret = -1L;
1528 1505
1529 if (ret || test_thread_flag(TIF_SYSCALL_TRACE)) 1506 if ((ret || test_thread_flag(TIF_SYSCALL_TRACE)) &&
1530 syscall_trace(regs); 1507 tracehook_report_syscall_entry(regs))
1508 ret = -1L;
1531 1509
1532 if (unlikely(current->audit_context)) { 1510 if (unlikely(current->audit_context)) {
1533 if (IS_IA32) 1511 if (IS_IA32)
@@ -1553,7 +1531,7 @@ asmregparm void syscall_trace_leave(struct pt_regs *regs)
1553 audit_syscall_exit(AUDITSC_RESULT(regs->ax), regs->ax); 1531 audit_syscall_exit(AUDITSC_RESULT(regs->ax), regs->ax);
1554 1532
1555 if (test_thread_flag(TIF_SYSCALL_TRACE)) 1533 if (test_thread_flag(TIF_SYSCALL_TRACE))
1556 syscall_trace(regs); 1534 tracehook_report_syscall_exit(regs, 0);
1557 1535
1558 /* 1536 /*
1559 * If TIF_SYSCALL_EMU is set, we only get here because of 1537 * 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)
1569 * system call instruction. 1547 * system call instruction.
1570 */ 1548 */
1571 if (test_thread_flag(TIF_SINGLESTEP) && 1549 if (test_thread_flag(TIF_SINGLESTEP) &&
1572 (current->ptrace & PT_PTRACED)) 1550 tracehook_consider_fatal_signal(current, SIGTRAP, SIG_DFL))
1573 send_sigtrap(current, regs, 0); 1551 send_sigtrap(current, regs, 0);
1574} 1552}
diff --git a/arch/x86/kernel/signal_32.c b/arch/x86/kernel/signal_32.c
index 0c727f64e79b..2a2435d3037d 100644
--- a/arch/x86/kernel/signal_32.c
+++ b/arch/x86/kernel/signal_32.c
@@ -17,6 +17,7 @@
17#include <linux/errno.h> 17#include <linux/errno.h>
18#include <linux/sched.h> 18#include <linux/sched.h>
19#include <linux/wait.h> 19#include <linux/wait.h>
20#include <linux/tracehook.h>
20#include <linux/elf.h> 21#include <linux/elf.h>
21#include <linux/smp.h> 22#include <linux/smp.h>
22#include <linux/mm.h> 23#include <linux/mm.h>
@@ -559,8 +560,6 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
559 * handler too. 560 * handler too.
560 */ 561 */
561 regs->flags &= ~X86_EFLAGS_TF; 562 regs->flags &= ~X86_EFLAGS_TF;
562 if (test_thread_flag(TIF_SINGLESTEP))
563 ptrace_notify(SIGTRAP);
564 563
565 spin_lock_irq(&current->sighand->siglock); 564 spin_lock_irq(&current->sighand->siglock);
566 sigorsets(&current->blocked, &current->blocked, &ka->sa.sa_mask); 565 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,
569 recalc_sigpending(); 568 recalc_sigpending();
570 spin_unlock_irq(&current->sighand->siglock); 569 spin_unlock_irq(&current->sighand->siglock);
571 570
571 tracehook_signal_handler(sig, info, ka, regs,
572 test_thread_flag(TIF_SINGLESTEP));
573
572 return 0; 574 return 0;
573} 575}
574 576
@@ -662,5 +664,10 @@ do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
662 if (thread_info_flags & _TIF_SIGPENDING) 664 if (thread_info_flags & _TIF_SIGPENDING)
663 do_signal(regs); 665 do_signal(regs);
664 666
667 if (thread_info_flags & _TIF_NOTIFY_RESUME) {
668 clear_thread_flag(TIF_NOTIFY_RESUME);
669 tracehook_notify_resume(regs);
670 }
671
665 clear_thread_flag(TIF_IRET); 672 clear_thread_flag(TIF_IRET);
666} 673}
diff --git a/arch/x86/kernel/signal_64.c b/arch/x86/kernel/signal_64.c
index 2f1464050059..4d32487805ef 100644
--- a/arch/x86/kernel/signal_64.c
+++ b/arch/x86/kernel/signal_64.c
@@ -15,6 +15,7 @@
15#include <linux/errno.h> 15#include <linux/errno.h>
16#include <linux/wait.h> 16#include <linux/wait.h>
17#include <linux/ptrace.h> 17#include <linux/ptrace.h>
18#include <linux/tracehook.h>
18#include <linux/unistd.h> 19#include <linux/unistd.h>
19#include <linux/stddef.h> 20#include <linux/stddef.h>
20#include <linux/personality.h> 21#include <linux/personality.h>
@@ -26,6 +27,7 @@
26#include <asm/proto.h> 27#include <asm/proto.h>
27#include <asm/ia32_unistd.h> 28#include <asm/ia32_unistd.h>
28#include <asm/mce.h> 29#include <asm/mce.h>
30#include <asm/syscall.h>
29#include <asm/syscalls.h> 31#include <asm/syscalls.h>
30#include "sigframe.h" 32#include "sigframe.h"
31 33
@@ -356,35 +358,6 @@ give_sigsegv:
356} 358}
357 359
358/* 360/*
359 * Return -1L or the syscall number that @regs is executing.
360 */
361static long current_syscall(struct pt_regs *regs)
362{
363 /*
364 * We always sign-extend a -1 value being set here,
365 * so this is always either -1L or a syscall number.
366 */
367 return regs->orig_ax;
368}
369
370/*
371 * Return a value that is -EFOO if the system call in @regs->orig_ax
372 * returned an error. This only works for @regs from @current.
373 */
374static long current_syscall_ret(struct pt_regs *regs)
375{
376#ifdef CONFIG_IA32_EMULATION
377 if (test_thread_flag(TIF_IA32))
378 /*
379 * Sign-extend the value so (int)-EFOO becomes (long)-EFOO
380 * and will match correctly in comparisons.
381 */
382 return (int) regs->ax;
383#endif
384 return regs->ax;
385}
386
387/*
388 * OK, we're invoking a handler 361 * OK, we're invoking a handler
389 */ 362 */
390 363
@@ -395,9 +368,9 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
395 int ret; 368 int ret;
396 369
397 /* Are we from a system call? */ 370 /* Are we from a system call? */
398 if (current_syscall(regs) >= 0) { 371 if (syscall_get_nr(current, regs) >= 0) {
399 /* If so, check system call restarting.. */ 372 /* If so, check system call restarting.. */
400 switch (current_syscall_ret(regs)) { 373 switch (syscall_get_error(current, regs)) {
401 case -ERESTART_RESTARTBLOCK: 374 case -ERESTART_RESTARTBLOCK:
402 case -ERESTARTNOHAND: 375 case -ERESTARTNOHAND:
403 regs->ax = -EINTR; 376 regs->ax = -EINTR;
@@ -454,8 +427,6 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
454 * handler too. 427 * handler too.
455 */ 428 */
456 regs->flags &= ~X86_EFLAGS_TF; 429 regs->flags &= ~X86_EFLAGS_TF;
457 if (test_thread_flag(TIF_SINGLESTEP))
458 ptrace_notify(SIGTRAP);
459 430
460 spin_lock_irq(&current->sighand->siglock); 431 spin_lock_irq(&current->sighand->siglock);
461 sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask); 432 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,
463 sigaddset(&current->blocked,sig); 434 sigaddset(&current->blocked,sig);
464 recalc_sigpending(); 435 recalc_sigpending();
465 spin_unlock_irq(&current->sighand->siglock); 436 spin_unlock_irq(&current->sighand->siglock);
437
438 tracehook_signal_handler(sig, info, ka, regs,
439 test_thread_flag(TIF_SINGLESTEP));
466 } 440 }
467 441
468 return ret; 442 return ret;
@@ -519,9 +493,9 @@ static void do_signal(struct pt_regs *regs)
519 } 493 }
520 494
521 /* Did we come from a system call? */ 495 /* Did we come from a system call? */
522 if (current_syscall(regs) >= 0) { 496 if (syscall_get_nr(current, regs) >= 0) {
523 /* Restart the system call - no handlers present */ 497 /* Restart the system call - no handlers present */
524 switch (current_syscall_ret(regs)) { 498 switch (syscall_get_error(current, regs)) {
525 case -ERESTARTNOHAND: 499 case -ERESTARTNOHAND:
526 case -ERESTARTSYS: 500 case -ERESTARTSYS:
527 case -ERESTARTNOINTR: 501 case -ERESTARTNOINTR:
@@ -559,6 +533,11 @@ void do_notify_resume(struct pt_regs *regs, void *unused,
559 /* deal with pending signal delivery */ 533 /* deal with pending signal delivery */
560 if (thread_info_flags & _TIF_SIGPENDING) 534 if (thread_info_flags & _TIF_SIGPENDING)
561 do_signal(regs); 535 do_signal(regs);
536
537 if (thread_info_flags & _TIF_NOTIFY_RESUME) {
538 clear_thread_flag(TIF_NOTIFY_RESUME);
539 tracehook_notify_resume(regs);
540 }
562} 541}
563 542
564void signal_fault(struct pt_regs *regs, void __user *frame, char *where) 543void signal_fault(struct pt_regs *regs, void __user *frame, char *where)
diff --git a/include/asm-x86/ptrace.h b/include/asm-x86/ptrace.h
index 33a034be8b5c..d64a61097165 100644
--- a/include/asm-x86/ptrace.h
+++ b/include/asm-x86/ptrace.h
@@ -250,6 +250,11 @@ static inline unsigned long frame_pointer(struct pt_regs *regs)
250 return regs->bp; 250 return regs->bp;
251} 251}
252 252
253static inline unsigned long user_stack_pointer(struct pt_regs *regs)
254{
255 return regs->sp;
256}
257
253/* 258/*
254 * These are defined as per linux/ptrace.h, which see. 259 * These are defined as per linux/ptrace.h, which see.
255 */ 260 */
diff --git a/include/asm-x86/syscall.h b/include/asm-x86/syscall.h
new file mode 100644
index 000000000000..04c47dc5597c
--- /dev/null
+++ b/include/asm-x86/syscall.h
@@ -0,0 +1,211 @@
1/*
2 * Access to user system call parameters and results
3 *
4 * Copyright (C) 2008 Red Hat, Inc. All rights reserved.
5 *
6 * This copyrighted material is made available to anyone wishing to use,
7 * modify, copy, or redistribute it subject to the terms and conditions
8 * of the GNU General Public License v.2.
9 *
10 * See asm-generic/syscall.h for descriptions of what we must do here.
11 */
12
13#ifndef _ASM_SYSCALL_H
14#define _ASM_SYSCALL_H 1
15
16#include <linux/sched.h>
17#include <linux/err.h>
18
19static inline long syscall_get_nr(struct task_struct *task,
20 struct pt_regs *regs)
21{
22 /*
23 * We always sign-extend a -1 value being set here,
24 * so this is always either -1L or a syscall number.
25 */
26 return regs->orig_ax;
27}
28
29static inline void syscall_rollback(struct task_struct *task,
30 struct pt_regs *regs)
31{
32 regs->ax = regs->orig_ax;
33}
34
35static inline long syscall_get_error(struct task_struct *task,
36 struct pt_regs *regs)
37{
38 unsigned long error = regs->ax;
39#ifdef CONFIG_IA32_EMULATION
40 /*
41 * TS_COMPAT is set for 32-bit syscall entries and then
42 * remains set until we return to user mode.
43 */
44 if (task_thread_info(task)->status & TS_COMPAT)
45 /*
46 * Sign-extend the value so (int)-EFOO becomes (long)-EFOO
47 * and will match correctly in comparisons.
48 */
49 error = (long) (int) error;
50#endif
51 return IS_ERR_VALUE(error) ? error : 0;
52}
53
54static inline long syscall_get_return_value(struct task_struct *task,
55 struct pt_regs *regs)
56{
57 return regs->ax;
58}
59
60static inline void syscall_set_return_value(struct task_struct *task,
61 struct pt_regs *regs,
62 int error, long val)
63{
64 regs->ax = (long) error ?: val;
65}
66
67#ifdef CONFIG_X86_32
68
69static inline void syscall_get_arguments(struct task_struct *task,
70 struct pt_regs *regs,
71 unsigned int i, unsigned int n,
72 unsigned long *args)
73{
74 BUG_ON(i + n > 6);
75 memcpy(args, &regs->bx + i, n * sizeof(args[0]));
76}
77
78static inline void syscall_set_arguments(struct task_struct *task,
79 struct pt_regs *regs,
80 unsigned int i, unsigned int n,
81 const unsigned long *args)
82{
83 BUG_ON(i + n > 6);
84 memcpy(&regs->bx + i, args, n * sizeof(args[0]));
85}
86
87#else /* CONFIG_X86_64 */
88
89static inline void syscall_get_arguments(struct task_struct *task,
90 struct pt_regs *regs,
91 unsigned int i, unsigned int n,
92 unsigned long *args)
93{
94# ifdef CONFIG_IA32_EMULATION
95 if (task_thread_info(task)->status & TS_COMPAT)
96 switch (i + n) {
97 case 6:
98 if (!n--) break;
99 *args++ = regs->bp;
100 case 5:
101 if (!n--) break;
102 *args++ = regs->di;
103 case 4:
104 if (!n--) break;
105 *args++ = regs->si;
106 case 3:
107 if (!n--) break;
108 *args++ = regs->dx;
109 case 2:
110 if (!n--) break;
111 *args++ = regs->cx;
112 case 1:
113 if (!n--) break;
114 *args++ = regs->bx;
115 case 0:
116 if (!n--) break;
117 default:
118 BUG();
119 break;
120 }
121 else
122# endif
123 switch (i + n) {
124 case 6:
125 if (!n--) break;
126 *args++ = regs->r9;
127 case 5:
128 if (!n--) break;
129 *args++ = regs->r8;
130 case 4:
131 if (!n--) break;
132 *args++ = regs->r10;
133 case 3:
134 if (!n--) break;
135 *args++ = regs->dx;
136 case 2:
137 if (!n--) break;
138 *args++ = regs->si;
139 case 1:
140 if (!n--) break;
141 *args++ = regs->di;
142 case 0:
143 if (!n--) break;
144 default:
145 BUG();
146 break;
147 }
148}
149
150static inline void syscall_set_arguments(struct task_struct *task,
151 struct pt_regs *regs,
152 unsigned int i, unsigned int n,
153 const unsigned long *args)
154{
155# ifdef CONFIG_IA32_EMULATION
156 if (task_thread_info(task)->status & TS_COMPAT)
157 switch (i + n) {
158 case 6:
159 if (!n--) break;
160 regs->bp = *args++;
161 case 5:
162 if (!n--) break;
163 regs->di = *args++;
164 case 4:
165 if (!n--) break;
166 regs->si = *args++;
167 case 3:
168 if (!n--) break;
169 regs->dx = *args++;
170 case 2:
171 if (!n--) break;
172 regs->cx = *args++;
173 case 1:
174 if (!n--) break;
175 regs->bx = *args++;
176 case 0:
177 if (!n--) break;
178 default:
179 BUG();
180 }
181 else
182# endif
183 switch (i + n) {
184 case 6:
185 if (!n--) break;
186 regs->r9 = *args++;
187 case 5:
188 if (!n--) break;
189 regs->r8 = *args++;
190 case 4:
191 if (!n--) break;
192 regs->r10 = *args++;
193 case 3:
194 if (!n--) break;
195 regs->dx = *args++;
196 case 2:
197 if (!n--) break;
198 regs->si = *args++;
199 case 1:
200 if (!n--) break;
201 regs->di = *args++;
202 case 0:
203 if (!n--) break;
204 default:
205 BUG();
206 }
207}
208
209#endif /* CONFIG_X86_32 */
210
211#endif /* _ASM_SYSCALL_H */
diff --git a/include/asm-x86/thread_info.h b/include/asm-x86/thread_info.h
index e64be8863b76..4db0066a3a35 100644
--- a/include/asm-x86/thread_info.h
+++ b/include/asm-x86/thread_info.h
@@ -71,6 +71,7 @@ struct thread_info {
71 * Warning: layout of LSW is hardcoded in entry.S 71 * Warning: layout of LSW is hardcoded in entry.S
72 */ 72 */
73#define TIF_SYSCALL_TRACE 0 /* syscall trace active */ 73#define TIF_SYSCALL_TRACE 0 /* syscall trace active */
74#define TIF_NOTIFY_RESUME 1 /* callback before returning to user */
74#define TIF_SIGPENDING 2 /* signal pending */ 75#define TIF_SIGPENDING 2 /* signal pending */
75#define TIF_NEED_RESCHED 3 /* rescheduling necessary */ 76#define TIF_NEED_RESCHED 3 /* rescheduling necessary */
76#define TIF_SINGLESTEP 4 /* reenable singlestep on user return*/ 77#define TIF_SINGLESTEP 4 /* reenable singlestep on user return*/
@@ -93,6 +94,7 @@ struct thread_info {
93#define TIF_BTS_TRACE_TS 27 /* record scheduling event timestamps */ 94#define TIF_BTS_TRACE_TS 27 /* record scheduling event timestamps */
94 95
95#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) 96#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE)
97#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME)
96#define _TIF_SIGPENDING (1 << TIF_SIGPENDING) 98#define _TIF_SIGPENDING (1 << TIF_SIGPENDING)
97#define _TIF_SINGLESTEP (1 << TIF_SINGLESTEP) 99#define _TIF_SINGLESTEP (1 << TIF_SINGLESTEP)
98#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) 100#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)
@@ -133,7 +135,7 @@ struct thread_info {
133 135
134/* Only used for 64 bit */ 136/* Only used for 64 bit */
135#define _TIF_DO_NOTIFY_MASK \ 137#define _TIF_DO_NOTIFY_MASK \
136 (_TIF_SIGPENDING|_TIF_MCE_NOTIFY) 138 (_TIF_SIGPENDING|_TIF_MCE_NOTIFY|_TIF_NOTIFY_RESUME)
137 139
138/* flags to check in __switch_to() */ 140/* flags to check in __switch_to() */
139#define _TIF_WORK_CTXSW \ 141#define _TIF_WORK_CTXSW \