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.h210
-rw-r--r--include/asm-x86/thread_info.h4
7 files changed, 248 insertions, 66 deletions
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index b6fa2877b173..f463a8a3b21f 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -30,6 +30,7 @@ config X86
30 select HAVE_FTRACE 30 select HAVE_FTRACE
31 select HAVE_KVM if ((X86_32 && !X86_VOYAGER && !X86_VISWS && !X86_NUMAQ) || X86_64) 31 select HAVE_KVM if ((X86_32 && !X86_VOYAGER && !X86_VISWS && !X86_NUMAQ) || X86_64)
32 select HAVE_ARCH_KGDB if !X86_VOYAGER 32 select HAVE_ARCH_KGDB if !X86_VOYAGER
33 select HAVE_ARCH_TRACEHOOK
33 select HAVE_EFFICIENT_UNALIGNED_ACCESS 34 select HAVE_EFFICIENT_UNALIGNED_ACCESS
34 35
35config ARCH_DEFCONFIG 36config ARCH_DEFCONFIG
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index e37dccce85db..19a7d2c40560 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>
@@ -1375,30 +1376,6 @@ void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, int error_code)
1375 force_sig_info(SIGTRAP, &info, tsk); 1376 force_sig_info(SIGTRAP, &info, tsk);
1376} 1377}
1377 1378
1378static void syscall_trace(struct pt_regs *regs)
1379{
1380 if (!(current->ptrace & PT_PTRACED))
1381 return;
1382
1383#if 0
1384 printk("trace %s ip %lx sp %lx ax %d origrax %d caller %lx tiflags %x ptrace %x\n",
1385 current->comm,
1386 regs->ip, regs->sp, regs->ax, regs->orig_ax, __builtin_return_address(0),
1387 current_thread_info()->flags, current->ptrace);
1388#endif
1389
1390 ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
1391 ? 0x80 : 0));
1392 /*
1393 * this isn't the same as continuing with a signal, but it will do
1394 * for normal use. strace only continues with a signal if the
1395 * stopping signal is not SIGTRAP. -brl
1396 */
1397 if (current->exit_code) {
1398 send_sig(current->exit_code, current, 1);
1399 current->exit_code = 0;
1400 }
1401}
1402 1379
1403#ifdef CONFIG_X86_32 1380#ifdef CONFIG_X86_32
1404# define IS_IA32 1 1381# define IS_IA32 1
@@ -1432,8 +1409,9 @@ asmregparm long syscall_trace_enter(struct pt_regs *regs)
1432 if (unlikely(test_thread_flag(TIF_SYSCALL_EMU))) 1409 if (unlikely(test_thread_flag(TIF_SYSCALL_EMU)))
1433 ret = -1L; 1410 ret = -1L;
1434 1411
1435 if (ret || test_thread_flag(TIF_SYSCALL_TRACE)) 1412 if ((ret || test_thread_flag(TIF_SYSCALL_TRACE)) &&
1436 syscall_trace(regs); 1413 tracehook_report_syscall_entry(regs))
1414 ret = -1L;
1437 1415
1438 if (unlikely(current->audit_context)) { 1416 if (unlikely(current->audit_context)) {
1439 if (IS_IA32) 1417 if (IS_IA32)
@@ -1459,7 +1437,7 @@ asmregparm void syscall_trace_leave(struct pt_regs *regs)
1459 audit_syscall_exit(AUDITSC_RESULT(regs->ax), regs->ax); 1437 audit_syscall_exit(AUDITSC_RESULT(regs->ax), regs->ax);
1460 1438
1461 if (test_thread_flag(TIF_SYSCALL_TRACE)) 1439 if (test_thread_flag(TIF_SYSCALL_TRACE))
1462 syscall_trace(regs); 1440 tracehook_report_syscall_exit(regs, 0);
1463 1441
1464 /* 1442 /*
1465 * If TIF_SYSCALL_EMU is set, we only get here because of 1443 * If TIF_SYSCALL_EMU is set, we only get here because of
@@ -1475,6 +1453,6 @@ asmregparm void syscall_trace_leave(struct pt_regs *regs)
1475 * system call instruction. 1453 * system call instruction.
1476 */ 1454 */
1477 if (test_thread_flag(TIF_SINGLESTEP) && 1455 if (test_thread_flag(TIF_SINGLESTEP) &&
1478 (current->ptrace & PT_PTRACED)) 1456 tracehook_consider_fatal_signal(current, SIGTRAP, SIG_DFL))
1479 send_sigtrap(current, regs, 0); 1457 send_sigtrap(current, regs, 0);
1480} 1458}
diff --git a/arch/x86/kernel/signal_32.c b/arch/x86/kernel/signal_32.c
index 6fb5bcdd8933..4445d26efd47 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>
@@ -558,8 +559,6 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
558 * handler too. 559 * handler too.
559 */ 560 */
560 regs->flags &= ~X86_EFLAGS_TF; 561 regs->flags &= ~X86_EFLAGS_TF;
561 if (test_thread_flag(TIF_SINGLESTEP))
562 ptrace_notify(SIGTRAP);
563 562
564 spin_lock_irq(&current->sighand->siglock); 563 spin_lock_irq(&current->sighand->siglock);
565 sigorsets(&current->blocked, &current->blocked, &ka->sa.sa_mask); 564 sigorsets(&current->blocked, &current->blocked, &ka->sa.sa_mask);
@@ -568,6 +567,9 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
568 recalc_sigpending(); 567 recalc_sigpending();
569 spin_unlock_irq(&current->sighand->siglock); 568 spin_unlock_irq(&current->sighand->siglock);
570 569
570 tracehook_signal_handler(sig, info, ka, regs,
571 test_thread_flag(TIF_SINGLESTEP));
572
571 return 0; 573 return 0;
572} 574}
573 575
@@ -661,5 +663,10 @@ do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
661 if (thread_info_flags & _TIF_SIGPENDING) 663 if (thread_info_flags & _TIF_SIGPENDING)
662 do_signal(regs); 664 do_signal(regs);
663 665
666 if (thread_info_flags & _TIF_NOTIFY_RESUME) {
667 clear_thread_flag(TIF_NOTIFY_RESUME);
668 tracehook_notify_resume(regs);
669 }
670
664 clear_thread_flag(TIF_IRET); 671 clear_thread_flag(TIF_IRET);
665} 672}
diff --git a/arch/x86/kernel/signal_64.c b/arch/x86/kernel/signal_64.c
index b45ef8ddd651..d01e3f6ef26d 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 "sigframe.h" 31#include "sigframe.h"
30 32
31#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) 33#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
@@ -346,35 +348,6 @@ give_sigsegv:
346} 348}
347 349
348/* 350/*
349 * Return -1L or the syscall number that @regs is executing.
350 */
351static long current_syscall(struct pt_regs *regs)
352{
353 /*
354 * We always sign-extend a -1 value being set here,
355 * so this is always either -1L or a syscall number.
356 */
357 return regs->orig_ax;
358}
359
360/*
361 * Return a value that is -EFOO if the system call in @regs->orig_ax
362 * returned an error. This only works for @regs from @current.
363 */
364static long current_syscall_ret(struct pt_regs *regs)
365{
366#ifdef CONFIG_IA32_EMULATION
367 if (test_thread_flag(TIF_IA32))
368 /*
369 * Sign-extend the value so (int)-EFOO becomes (long)-EFOO
370 * and will match correctly in comparisons.
371 */
372 return (int) regs->ax;
373#endif
374 return regs->ax;
375}
376
377/*
378 * OK, we're invoking a handler 351 * OK, we're invoking a handler
379 */ 352 */
380 353
@@ -385,9 +358,9 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
385 int ret; 358 int ret;
386 359
387 /* Are we from a system call? */ 360 /* Are we from a system call? */
388 if (current_syscall(regs) >= 0) { 361 if (syscall_get_nr(current, regs) >= 0) {
389 /* If so, check system call restarting.. */ 362 /* If so, check system call restarting.. */
390 switch (current_syscall_ret(regs)) { 363 switch (syscall_get_error(current, regs)) {
391 case -ERESTART_RESTARTBLOCK: 364 case -ERESTART_RESTARTBLOCK:
392 case -ERESTARTNOHAND: 365 case -ERESTARTNOHAND:
393 regs->ax = -EINTR; 366 regs->ax = -EINTR;
@@ -444,8 +417,6 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
444 * handler too. 417 * handler too.
445 */ 418 */
446 regs->flags &= ~X86_EFLAGS_TF; 419 regs->flags &= ~X86_EFLAGS_TF;
447 if (test_thread_flag(TIF_SINGLESTEP))
448 ptrace_notify(SIGTRAP);
449 420
450 spin_lock_irq(&current->sighand->siglock); 421 spin_lock_irq(&current->sighand->siglock);
451 sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask); 422 sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
@@ -453,6 +424,9 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
453 sigaddset(&current->blocked,sig); 424 sigaddset(&current->blocked,sig);
454 recalc_sigpending(); 425 recalc_sigpending();
455 spin_unlock_irq(&current->sighand->siglock); 426 spin_unlock_irq(&current->sighand->siglock);
427
428 tracehook_signal_handler(sig, info, ka, regs,
429 test_thread_flag(TIF_SINGLESTEP));
456 } 430 }
457 431
458 return ret; 432 return ret;
@@ -509,9 +483,9 @@ static void do_signal(struct pt_regs *regs)
509 } 483 }
510 484
511 /* Did we come from a system call? */ 485 /* Did we come from a system call? */
512 if (current_syscall(regs) >= 0) { 486 if (syscall_get_nr(current, regs) >= 0) {
513 /* Restart the system call - no handlers present */ 487 /* Restart the system call - no handlers present */
514 switch (current_syscall_ret(regs)) { 488 switch (syscall_get_error(current, regs)) {
515 case -ERESTARTNOHAND: 489 case -ERESTARTNOHAND:
516 case -ERESTARTSYS: 490 case -ERESTARTSYS:
517 case -ERESTARTNOINTR: 491 case -ERESTARTNOINTR:
@@ -549,6 +523,11 @@ void do_notify_resume(struct pt_regs *regs, void *unused,
549 /* deal with pending signal delivery */ 523 /* deal with pending signal delivery */
550 if (thread_info_flags & _TIF_SIGPENDING) 524 if (thread_info_flags & _TIF_SIGPENDING)
551 do_signal(regs); 525 do_signal(regs);
526
527 if (thread_info_flags & _TIF_NOTIFY_RESUME) {
528 clear_thread_flag(TIF_NOTIFY_RESUME);
529 tracehook_notify_resume(regs);
530 }
552} 531}
553 532
554void signal_fault(struct pt_regs *regs, void __user *frame, char *where) 533void 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 8a71db803da6..91a77f5c4678 100644
--- a/include/asm-x86/ptrace.h
+++ b/include/asm-x86/ptrace.h
@@ -213,6 +213,11 @@ static inline unsigned long frame_pointer(struct pt_regs *regs)
213 return regs->bp; 213 return regs->bp;
214} 214}
215 215
216static inline unsigned long user_stack_pointer(struct pt_regs *regs)
217{
218 return regs->sp;
219}
220
216/* 221/*
217 * These are defined as per linux/ptrace.h, which see. 222 * These are defined as per linux/ptrace.h, which see.
218 */ 223 */
diff --git a/include/asm-x86/syscall.h b/include/asm-x86/syscall.h
new file mode 100644
index 000000000000..6f293892895a
--- /dev/null
+++ b/include/asm-x86/syscall.h
@@ -0,0 +1,210 @@
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
18static inline long syscall_get_nr(struct task_struct *task,
19 struct pt_regs *regs)
20{
21 /*
22 * We always sign-extend a -1 value being set here,
23 * so this is always either -1L or a syscall number.
24 */
25 return regs->orig_ax;
26}
27
28static inline void syscall_rollback(struct task_struct *task,
29 struct pt_regs *regs)
30{
31 regs->ax = regs->orig_ax;
32}
33
34static inline long syscall_get_error(struct task_struct *task,
35 struct pt_regs *regs)
36{
37 unsigned long error = regs->ax;
38#ifdef CONFIG_IA32_EMULATION
39 /*
40 * TS_COMPAT is set for 32-bit syscall entries and then
41 * remains set until we return to user mode.
42 */
43 if (task_thread_info(task)->status & TS_COMPAT)
44 /*
45 * Sign-extend the value so (int)-EFOO becomes (long)-EFOO
46 * and will match correctly in comparisons.
47 */
48 error = (long) (int) error;
49#endif
50 return error >= -4095L ? error : 0;
51}
52
53static inline long syscall_get_return_value(struct task_struct *task,
54 struct pt_regs *regs)
55{
56 return regs->ax;
57}
58
59static inline void syscall_set_return_value(struct task_struct *task,
60 struct pt_regs *regs,
61 int error, long val)
62{
63 regs->ax = (long) error ?: val;
64}
65
66#ifdef CONFIG_X86_32
67
68static inline void syscall_get_arguments(struct task_struct *task,
69 struct pt_regs *regs,
70 unsigned int i, unsigned int n,
71 unsigned long *args)
72{
73 BUG_ON(i + n > 6);
74 memcpy(args, &regs->bx + i, n * sizeof(args[0]));
75}
76
77static inline void syscall_set_arguments(struct task_struct *task,
78 struct pt_regs *regs,
79 unsigned int i, unsigned int n,
80 const unsigned long *args)
81{
82 BUG_ON(i + n > 6);
83 memcpy(&regs->bx + i, args, n * sizeof(args[0]));
84}
85
86#else /* CONFIG_X86_64 */
87
88static inline void syscall_get_arguments(struct task_struct *task,
89 struct pt_regs *regs,
90 unsigned int i, unsigned int n,
91 unsigned long *args)
92{
93# ifdef CONFIG_IA32_EMULATION
94 if (task_thread_info(task)->status & TS_COMPAT)
95 switch (i + n) {
96 case 6:
97 if (!n--) break;
98 *args++ = regs->bp;
99 case 5:
100 if (!n--) break;
101 *args++ = regs->di;
102 case 4:
103 if (!n--) break;
104 *args++ = regs->si;
105 case 3:
106 if (!n--) break;
107 *args++ = regs->dx;
108 case 2:
109 if (!n--) break;
110 *args++ = regs->cx;
111 case 1:
112 if (!n--) break;
113 *args++ = regs->bx;
114 case 0:
115 if (!n--) break;
116 default:
117 BUG();
118 break;
119 }
120 else
121# endif
122 switch (i + n) {
123 case 6:
124 if (!n--) break;
125 *args++ = regs->r9;
126 case 5:
127 if (!n--) break;
128 *args++ = regs->r8;
129 case 4:
130 if (!n--) break;
131 *args++ = regs->r10;
132 case 3:
133 if (!n--) break;
134 *args++ = regs->dx;
135 case 2:
136 if (!n--) break;
137 *args++ = regs->si;
138 case 1:
139 if (!n--) break;
140 *args++ = regs->di;
141 case 0:
142 if (!n--) break;
143 default:
144 BUG();
145 break;
146 }
147}
148
149static inline void syscall_set_arguments(struct task_struct *task,
150 struct pt_regs *regs,
151 unsigned int i, unsigned int n,
152 const unsigned long *args)
153{
154# ifdef CONFIG_IA32_EMULATION
155 if (task_thread_info(task)->status & TS_COMPAT)
156 switch (i + n) {
157 case 6:
158 if (!n--) break;
159 regs->bp = *args++;
160 case 5:
161 if (!n--) break;
162 regs->di = *args++;
163 case 4:
164 if (!n--) break;
165 regs->si = *args++;
166 case 3:
167 if (!n--) break;
168 regs->dx = *args++;
169 case 2:
170 if (!n--) break;
171 regs->cx = *args++;
172 case 1:
173 if (!n--) break;
174 regs->bx = *args++;
175 case 0:
176 if (!n--) break;
177 default:
178 BUG();
179 }
180 else
181# endif
182 switch (i + n) {
183 case 6:
184 if (!n--) break;
185 regs->r9 = *args++;
186 case 5:
187 if (!n--) break;
188 regs->r8 = *args++;
189 case 4:
190 if (!n--) break;
191 regs->r10 = *args++;
192 case 3:
193 if (!n--) break;
194 regs->dx = *args++;
195 case 2:
196 if (!n--) break;
197 regs->si = *args++;
198 case 1:
199 if (!n--) break;
200 regs->di = *args++;
201 case 0:
202 if (!n--) break;
203 default:
204 BUG();
205 }
206}
207
208#endif /* CONFIG_X86_32 */
209
210#endif /* _ASM_SYSCALL_H */
diff --git a/include/asm-x86/thread_info.h b/include/asm-x86/thread_info.h
index da0a675adf94..4cd5b7bdc8cc 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 \