]>
Commit | Line | Data |
---|---|---|
2cb7cef9 BS |
1 | From: Roland McGrath <roland@redhat.com> |
2 | Date: Sun Apr 20 14:35:12 2008 -0700 | |
3 | Subject: x86 tracehook | |
4 | References: FATE#304321 | |
5 | Patch-mainline: no | |
6 | ||
7 | Apply the changes from x86-utrace branch of | |
8 | git://git.kernel.org/pub/scm/linux/kernel/git/frob/linux-2.6-utrace | |
9 | plus later cleanups. | |
10 | ||
11 | Signed-off-by: Roland McGrath <roland@redhat.com> | |
12 | Signed-off-by: Petr Tesarik <ptesarik@suse.cz> | |
13 | ||
14 | --- | |
15 | arch/x86/Kconfig | 1 | |
16 | arch/x86/kernel/ptrace.c | 34 +----- | |
17 | arch/x86/kernel/signal_32.c | 11 +- | |
18 | arch/x86/kernel/signal_64.c | 49 ++------- | |
19 | include/asm-x86/ptrace.h | 5 | |
20 | include/asm-x86/syscall.h | 213 ++++++++++++++++++++++++++++++++++++++++++ | |
21 | include/asm-x86/thread_info.h | 4 | |
22 | 7 files changed, 251 insertions(+), 66 deletions(-) | |
23 | ||
24 | --- linux-2.6.27.orig/arch/x86/Kconfig 2008-10-20 11:46:16.000000000 +0200 | |
25 | +++ linux-2.6.27/arch/x86/Kconfig 2008-10-20 17:24:26.000000000 +0200 | |
26 | @@ -29,6 +29,7 @@ config X86 | |
27 | select HAVE_FTRACE | |
28 | select HAVE_KVM if ((X86_32 && !X86_VOYAGER && !X86_VISWS && !X86_NUMAQ) || X86_64) | |
29 | select HAVE_ARCH_KGDB if !X86_VOYAGER | |
30 | + select HAVE_ARCH_TRACEHOOK | |
31 | select HAVE_GENERIC_DMA_COHERENT if X86_32 | |
32 | select HAVE_EFFICIENT_UNALIGNED_ACCESS | |
33 | ||
34 | --- linux-2.6.27.orig/arch/x86/kernel/ptrace.c 2008-10-20 11:46:16.000000000 +0200 | |
35 | +++ linux-2.6.27/arch/x86/kernel/ptrace.c 2008-10-20 11:46:16.000000000 +0200 | |
36 | @@ -14,6 +14,7 @@ | |
37 | #include <linux/errno.h> | |
38 | #include <linux/ptrace.h> | |
39 | #include <linux/regset.h> | |
40 | +#include <linux/tracehook.h> | |
41 | #include <linux/user.h> | |
42 | #include <linux/elf.h> | |
43 | #include <linux/security.h> | |
44 | @@ -1375,30 +1376,6 @@ void send_sigtrap(struct task_struct *ts | |
45 | force_sig_info(SIGTRAP, &info, tsk); | |
46 | } | |
47 | ||
48 | -static void syscall_trace(struct pt_regs *regs) | |
49 | -{ | |
50 | - if (!(current->ptrace & PT_PTRACED)) | |
51 | - return; | |
52 | - | |
53 | -#if 0 | |
54 | - printk("trace %s ip %lx sp %lx ax %d origrax %d caller %lx tiflags %x ptrace %x\n", | |
55 | - current->comm, | |
56 | - regs->ip, regs->sp, regs->ax, regs->orig_ax, __builtin_return_address(0), | |
57 | - current_thread_info()->flags, current->ptrace); | |
58 | -#endif | |
59 | - | |
60 | - ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) | |
61 | - ? 0x80 : 0)); | |
62 | - /* | |
63 | - * this isn't the same as continuing with a signal, but it will do | |
64 | - * for normal use. strace only continues with a signal if the | |
65 | - * stopping signal is not SIGTRAP. -brl | |
66 | - */ | |
67 | - if (current->exit_code) { | |
68 | - send_sig(current->exit_code, current, 1); | |
69 | - current->exit_code = 0; | |
70 | - } | |
71 | -} | |
72 | ||
73 | #ifdef CONFIG_X86_32 | |
74 | # define IS_IA32 1 | |
75 | @@ -1443,8 +1420,9 @@ asmregparm long syscall_trace_enter(stru | |
76 | if (unlikely(test_thread_flag(TIF_SYSCALL_EMU))) | |
77 | ret = -1L; | |
78 | ||
79 | - if (ret || test_thread_flag(TIF_SYSCALL_TRACE)) | |
80 | - syscall_trace(regs); | |
81 | + if ((ret || test_thread_flag(TIF_SYSCALL_TRACE)) && | |
82 | + tracehook_report_syscall_entry(regs)) | |
83 | + ret = -1L; | |
84 | ||
85 | if (unlikely(current->audit_context)) { | |
86 | if (IS_IA32) | |
87 | @@ -1473,7 +1451,7 @@ asmregparm void syscall_trace_leave(stru | |
88 | audit_syscall_exit(AUDITSC_RESULT(regs->ax), regs->ax); | |
89 | ||
90 | if (test_thread_flag(TIF_SYSCALL_TRACE)) | |
91 | - syscall_trace(regs); | |
92 | + tracehook_report_syscall_exit(regs, 0); | |
93 | ||
94 | /* | |
95 | * If TIF_SYSCALL_EMU is set, we only get here because of | |
96 | @@ -1489,6 +1467,6 @@ asmregparm void syscall_trace_leave(stru | |
97 | * system call instruction. | |
98 | */ | |
99 | if (test_thread_flag(TIF_SINGLESTEP) && | |
100 | - (current->ptrace & PT_PTRACED)) | |
101 | + tracehook_consider_fatal_signal(current, SIGTRAP, SIG_DFL)) | |
102 | send_sigtrap(current, regs, 0); | |
103 | } | |
104 | --- linux-2.6.27.orig/arch/x86/kernel/signal_32.c 2008-10-20 11:46:16.000000000 +0200 | |
105 | +++ linux-2.6.27/arch/x86/kernel/signal_32.c 2008-10-20 11:46:16.000000000 +0200 | |
106 | @@ -17,6 +17,7 @@ | |
107 | #include <linux/errno.h> | |
108 | #include <linux/sched.h> | |
109 | #include <linux/wait.h> | |
110 | +#include <linux/tracehook.h> | |
111 | #include <linux/elf.h> | |
112 | #include <linux/smp.h> | |
113 | #include <linux/mm.h> | |
114 | @@ -558,8 +559,6 @@ handle_signal(unsigned long sig, siginfo | |
115 | * handler too. | |
116 | */ | |
117 | regs->flags &= ~X86_EFLAGS_TF; | |
118 | - if (test_thread_flag(TIF_SINGLESTEP)) | |
119 | - ptrace_notify(SIGTRAP); | |
120 | ||
121 | spin_lock_irq(¤t->sighand->siglock); | |
122 | sigorsets(¤t->blocked, ¤t->blocked, &ka->sa.sa_mask); | |
123 | @@ -573,6 +572,9 @@ handle_signal(unsigned long sig, siginfo | |
124 | current->instrumentation &= ~PTS_SELF; | |
125 | } | |
126 | ||
127 | + tracehook_signal_handler(sig, info, ka, regs, | |
128 | + test_thread_flag(TIF_SINGLESTEP)); | |
129 | + | |
130 | return 0; | |
131 | } | |
132 | ||
133 | @@ -666,5 +668,10 @@ do_notify_resume(struct pt_regs *regs, v | |
134 | if (thread_info_flags & _TIF_SIGPENDING) | |
135 | do_signal(regs); | |
136 | ||
137 | + if (thread_info_flags & _TIF_NOTIFY_RESUME) { | |
138 | + clear_thread_flag(TIF_NOTIFY_RESUME); | |
139 | + tracehook_notify_resume(regs); | |
140 | + } | |
141 | + | |
142 | clear_thread_flag(TIF_IRET); | |
143 | } | |
144 | --- linux-2.6.27.orig/arch/x86/kernel/signal_64.c 2008-10-20 11:46:16.000000000 +0200 | |
145 | +++ linux-2.6.27/arch/x86/kernel/signal_64.c 2008-10-20 11:46:16.000000000 +0200 | |
146 | @@ -15,6 +15,7 @@ | |
147 | #include <linux/errno.h> | |
148 | #include <linux/wait.h> | |
149 | #include <linux/ptrace.h> | |
150 | +#include <linux/tracehook.h> | |
151 | #include <linux/unistd.h> | |
152 | #include <linux/stddef.h> | |
153 | #include <linux/personality.h> | |
154 | @@ -26,6 +27,7 @@ | |
155 | #include <asm/proto.h> | |
156 | #include <asm/ia32_unistd.h> | |
157 | #include <asm/mce.h> | |
158 | +#include <asm/syscall.h> | |
159 | #include "sigframe.h" | |
160 | ||
161 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) | |
162 | @@ -355,35 +357,6 @@ give_sigsegv: | |
163 | } | |
164 | ||
165 | /* | |
166 | - * Return -1L or the syscall number that @regs is executing. | |
167 | - */ | |
168 | -static long current_syscall(struct pt_regs *regs) | |
169 | -{ | |
170 | - /* | |
171 | - * We always sign-extend a -1 value being set here, | |
172 | - * so this is always either -1L or a syscall number. | |
173 | - */ | |
174 | - return regs->orig_ax; | |
175 | -} | |
176 | - | |
177 | -/* | |
178 | - * Return a value that is -EFOO if the system call in @regs->orig_ax | |
179 | - * returned an error. This only works for @regs from @current. | |
180 | - */ | |
181 | -static long current_syscall_ret(struct pt_regs *regs) | |
182 | -{ | |
183 | -#ifdef CONFIG_IA32_EMULATION | |
184 | - if (test_thread_flag(TIF_IA32)) | |
185 | - /* | |
186 | - * Sign-extend the value so (int)-EFOO becomes (long)-EFOO | |
187 | - * and will match correctly in comparisons. | |
188 | - */ | |
189 | - return (int) regs->ax; | |
190 | -#endif | |
191 | - return regs->ax; | |
192 | -} | |
193 | - | |
194 | -/* | |
195 | * OK, we're invoking a handler | |
196 | */ | |
197 | ||
198 | @@ -394,9 +367,9 @@ handle_signal(unsigned long sig, siginfo | |
199 | int ret; | |
200 | ||
201 | /* Are we from a system call? */ | |
202 | - if (current_syscall(regs) >= 0) { | |
203 | + if (syscall_get_nr(current, regs) >= 0) { | |
204 | /* If so, check system call restarting.. */ | |
205 | - switch (current_syscall_ret(regs)) { | |
206 | + switch (syscall_get_error(current, regs)) { | |
207 | case -ERESTART_RESTARTBLOCK: | |
208 | case -ERESTARTNOHAND: | |
209 | regs->ax = -EINTR; | |
210 | @@ -453,8 +426,6 @@ handle_signal(unsigned long sig, siginfo | |
211 | * handler too. | |
212 | */ | |
213 | regs->flags &= ~X86_EFLAGS_TF; | |
214 | - if (test_thread_flag(TIF_SINGLESTEP)) | |
215 | - ptrace_notify(SIGTRAP); | |
216 | ||
217 | spin_lock_irq(¤t->sighand->siglock); | |
218 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); | |
219 | @@ -462,6 +433,9 @@ handle_signal(unsigned long sig, siginfo | |
220 | sigaddset(¤t->blocked,sig); | |
221 | recalc_sigpending(); | |
222 | spin_unlock_irq(¤t->sighand->siglock); | |
223 | + | |
224 | + tracehook_signal_handler(sig, info, ka, regs, | |
225 | + test_thread_flag(TIF_SINGLESTEP)); | |
226 | } | |
227 | ||
228 | if (current->instrumentation & PTS_SELF) { | |
229 | @@ -523,9 +497,9 @@ static void do_signal(struct pt_regs *re | |
230 | } | |
231 | ||
232 | /* Did we come from a system call? */ | |
233 | - if (current_syscall(regs) >= 0) { | |
234 | + if (syscall_get_nr(current, regs) >= 0) { | |
235 | /* Restart the system call - no handlers present */ | |
236 | - switch (current_syscall_ret(regs)) { | |
237 | + switch (syscall_get_error(current, regs)) { | |
238 | case -ERESTARTNOHAND: | |
239 | case -ERESTARTSYS: | |
240 | case -ERESTARTNOINTR: | |
241 | @@ -563,6 +537,11 @@ void do_notify_resume(struct pt_regs *re | |
242 | /* deal with pending signal delivery */ | |
243 | if (thread_info_flags & _TIF_SIGPENDING) | |
244 | do_signal(regs); | |
245 | + | |
246 | + if (thread_info_flags & _TIF_NOTIFY_RESUME) { | |
247 | + clear_thread_flag(TIF_NOTIFY_RESUME); | |
248 | + tracehook_notify_resume(regs); | |
249 | + } | |
250 | } | |
251 | ||
252 | void signal_fault(struct pt_regs *regs, void __user *frame, char *where) | |
253 | --- linux-2.6.27.orig/include/asm-x86/ptrace.h 2008-10-10 00:13:53.000000000 +0200 | |
254 | +++ linux-2.6.27/include/asm-x86/ptrace.h 2008-10-20 17:23:29.000000000 +0200 | |
255 | @@ -213,6 +213,11 @@ static inline unsigned long frame_pointe | |
256 | return regs->bp; | |
257 | } | |
258 | ||
259 | +static inline unsigned long user_stack_pointer(struct pt_regs *regs) | |
260 | +{ | |
261 | + return regs->sp; | |
262 | +} | |
263 | + | |
264 | /* | |
265 | * These are defined as per linux/ptrace.h, which see. | |
266 | */ | |
267 | --- /dev/null 1970-01-01 00:00:00.000000000 +0000 | |
268 | +++ linux-2.6.27/include/asm-x86/syscall.h 2008-10-20 17:32:17.000000000 +0200 | |
269 | @@ -0,0 +1,213 @@ | |
270 | +/* | |
271 | + * Access to user system call parameters and results | |
272 | + * | |
273 | + * Copyright (C) 2008 Red Hat, Inc. All rights reserved. | |
274 | + * | |
275 | + * This copyrighted material is made available to anyone wishing to use, | |
276 | + * modify, copy, or redistribute it subject to the terms and conditions | |
277 | + * of the GNU General Public License v.2. | |
278 | + * | |
279 | + * See asm-generic/syscall.h for descriptions of what we must do here. | |
280 | + */ | |
281 | + | |
282 | +#ifndef _ASM_SYSCALL_H | |
283 | +#define _ASM_SYSCALL_H 1 | |
284 | + | |
285 | +#include <linux/sched.h> | |
286 | +#include <linux/err.h> | |
287 | + | |
288 | +static inline long syscall_get_nr(struct task_struct *task, | |
289 | + struct pt_regs *regs) | |
290 | +{ | |
291 | + /* | |
292 | + * We always sign-extend a -1 value being set here, | |
293 | + * so this is always either -1L or a syscall number. | |
294 | + */ | |
295 | + return regs->orig_ax; | |
296 | +} | |
297 | + | |
298 | +static inline void syscall_rollback(struct task_struct *task, | |
299 | + struct pt_regs *regs) | |
300 | +{ | |
301 | + regs->ax = regs->orig_ax; | |
302 | +} | |
303 | + | |
304 | +static inline long syscall_get_error(struct task_struct *task, | |
305 | + struct pt_regs *regs) | |
306 | +{ | |
307 | + unsigned long error = regs->ax; | |
308 | +#ifdef CONFIG_IA32_EMULATION | |
309 | + /* | |
310 | + * TS_COMPAT is set for 32-bit syscall entries and then | |
311 | + * remains set until we return to user mode. | |
312 | + */ | |
313 | + if (task_thread_info(task)->status & TS_COMPAT) | |
314 | + /* | |
315 | + * Sign-extend the value so (int)-EFOO becomes (long)-EFOO | |
316 | + * and will match correctly in comparisons. | |
317 | + */ | |
318 | + error = (long) (int) error; | |
319 | +#endif | |
320 | + return IS_ERR_VALUE(error) ? error : 0; | |
321 | +} | |
322 | + | |
323 | +static inline long syscall_get_return_value(struct task_struct *task, | |
324 | + struct pt_regs *regs) | |
325 | +{ | |
326 | + return regs->ax; | |
327 | +} | |
328 | + | |
329 | +static inline void syscall_set_return_value(struct task_struct *task, | |
330 | + struct pt_regs *regs, | |
331 | + int error, long val) | |
332 | +{ | |
333 | + regs->ax = (long) error ?: val; | |
334 | +} | |
335 | + | |
336 | +#ifdef CONFIG_X86_32 | |
337 | + | |
338 | +static inline void syscall_get_arguments(struct task_struct *task, | |
339 | + struct pt_regs *regs, | |
340 | + unsigned int i, unsigned int n, | |
341 | + unsigned long *args) | |
342 | +{ | |
343 | + BUG_ON(i + n > 6); | |
344 | + memcpy(args, ®s->bx + i, n * sizeof(args[0])); | |
345 | +} | |
346 | + | |
347 | +static inline void syscall_set_arguments(struct task_struct *task, | |
348 | + struct pt_regs *regs, | |
349 | + unsigned int i, unsigned int n, | |
350 | + const unsigned long *args) | |
351 | +{ | |
352 | + BUG_ON(i + n > 6); | |
353 | + memcpy(®s->bx + i, args, n * sizeof(args[0])); | |
354 | +} | |
355 | + | |
356 | +#else /* CONFIG_X86_64 */ | |
357 | + | |
358 | +static inline void syscall_get_arguments(struct task_struct *task, | |
359 | + struct pt_regs *regs, | |
360 | + unsigned int i, unsigned int n, | |
361 | + unsigned long *args) | |
362 | +{ | |
363 | +# ifdef CONFIG_IA32_EMULATION | |
364 | + if (task_thread_info(task)->status & TS_COMPAT) | |
365 | + switch (i) { | |
366 | + case 0: | |
367 | + if (!n--) break; | |
368 | + *args++ = regs->bx; | |
369 | + case 1: | |
370 | + if (!n--) break; | |
371 | + *args++ = regs->cx; | |
372 | + case 2: | |
373 | + if (!n--) break; | |
374 | + *args++ = regs->dx; | |
375 | + case 3: | |
376 | + if (!n--) break; | |
377 | + *args++ = regs->si; | |
378 | + case 4: | |
379 | + if (!n--) break; | |
380 | + *args++ = regs->di; | |
381 | + case 5: | |
382 | + if (!n--) break; | |
383 | + *args++ = regs->bp; | |
384 | + case 6: | |
385 | + if (!n--) break; | |
386 | + default: | |
387 | + BUG(); | |
388 | + break; | |
389 | + } | |
390 | + else | |
391 | +# endif | |
392 | + switch (i) { | |
393 | + case 0: | |
394 | + if (!n--) break; | |
395 | + *args++ = regs->di; | |
396 | + case 1: | |
397 | + if (!n--) break; | |
398 | + *args++ = regs->si; | |
399 | + case 2: | |
400 | + if (!n--) break; | |
401 | + *args++ = regs->dx; | |
402 | + case 3: | |
403 | + if (!n--) break; | |
404 | + *args++ = regs->r10; | |
405 | + case 4: | |
406 | + if (!n--) break; | |
407 | + *args++ = regs->r8; | |
408 | + case 5: | |
409 | + if (!n--) break; | |
410 | + *args++ = regs->r9; | |
411 | + case 6: | |
412 | + if (!n--) break; | |
413 | + default: | |
414 | + BUG(); | |
415 | + break; | |
416 | + } | |
417 | +} | |
418 | + | |
419 | +static inline void syscall_set_arguments(struct task_struct *task, | |
420 | + struct pt_regs *regs, | |
421 | + unsigned int i, unsigned int n, | |
422 | + const unsigned long *args) | |
423 | +{ | |
424 | +# ifdef CONFIG_IA32_EMULATION | |
425 | + if (task_thread_info(task)->status & TS_COMPAT) | |
426 | + switch (i) { | |
427 | + case 0: | |
428 | + if (!n--) break; | |
429 | + regs->bx = *args++; | |
430 | + case 1: | |
431 | + if (!n--) break; | |
432 | + regs->cx = *args++; | |
433 | + case 2: | |
434 | + if (!n--) break; | |
435 | + regs->dx = *args++; | |
436 | + case 3: | |
437 | + if (!n--) break; | |
438 | + regs->si = *args++; | |
439 | + case 4: | |
440 | + if (!n--) break; | |
441 | + regs->di = *args++; | |
442 | + case 5: | |
443 | + if (!n--) break; | |
444 | + regs->bp = *args++; | |
445 | + case 6: | |
446 | + if (!n--) break; | |
447 | + default: | |
448 | + BUG(); | |
449 | + break; | |
450 | + } | |
451 | + else | |
452 | +# endif | |
453 | + switch (i) { | |
454 | + case 0: | |
455 | + if (!n--) break; | |
456 | + regs->di = *args++; | |
457 | + case 1: | |
458 | + if (!n--) break; | |
459 | + regs->si = *args++; | |
460 | + case 2: | |
461 | + if (!n--) break; | |
462 | + regs->dx = *args++; | |
463 | + case 3: | |
464 | + if (!n--) break; | |
465 | + regs->r10 = *args++; | |
466 | + case 4: | |
467 | + if (!n--) break; | |
468 | + regs->r8 = *args++; | |
469 | + case 5: | |
470 | + if (!n--) break; | |
471 | + regs->r9 = *args++; | |
472 | + case 6: | |
473 | + if (!n--) break; | |
474 | + default: | |
475 | + BUG(); | |
476 | + break; | |
477 | + } | |
478 | +} | |
479 | + | |
480 | +#endif /* CONFIG_X86_32 */ | |
481 | + | |
482 | +#endif /* _ASM_SYSCALL_H */ | |
483 | --- linux-2.6.27.orig/include/asm-x86/thread_info.h 2008-10-10 00:13:53.000000000 +0200 | |
484 | +++ linux-2.6.27/include/asm-x86/thread_info.h 2008-10-20 17:23:10.000000000 +0200 | |
485 | @@ -71,6 +71,7 @@ struct thread_info { | |
486 | * Warning: layout of LSW is hardcoded in entry.S | |
487 | */ | |
488 | #define TIF_SYSCALL_TRACE 0 /* syscall trace active */ | |
489 | +#define TIF_NOTIFY_RESUME 1 /* callback before returning to user */ | |
490 | #define TIF_SIGPENDING 2 /* signal pending */ | |
491 | #define TIF_NEED_RESCHED 3 /* rescheduling necessary */ | |
492 | #define TIF_SINGLESTEP 4 /* reenable singlestep on user return*/ | |
493 | @@ -93,6 +94,7 @@ struct thread_info { | |
494 | #define TIF_BTS_TRACE_TS 27 /* record scheduling event timestamps */ | |
495 | ||
496 | #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) | |
497 | +#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) | |
498 | #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) | |
499 | #define _TIF_SINGLESTEP (1 << TIF_SINGLESTEP) | |
500 | #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) | |
501 | @@ -133,7 +135,7 @@ struct thread_info { | |
502 | ||
503 | /* Only used for 64 bit */ | |
504 | #define _TIF_DO_NOTIFY_MASK \ | |
505 | - (_TIF_SIGPENDING|_TIF_MCE_NOTIFY) | |
506 | + (_TIF_SIGPENDING|_TIF_MCE_NOTIFY|_TIF_NOTIFY_RESUME) | |
507 | ||
508 | /* flags to check in __switch_to() */ | |
509 | #define _TIF_WORK_CTXSW \ |