diff options
author | Michal Simek <monstr@monstr.eu> | 2009-08-24 07:26:04 -0400 |
---|---|---|
committer | Michal Simek <monstr@monstr.eu> | 2009-09-22 04:00:45 -0400 |
commit | 235754834b6818e727d6b8e240c4ec7f79e2f457 (patch) | |
tree | a58160000a994c22f41abdbcb783dc076c9ae7a0 /arch/microblaze | |
parent | f97b4f7de4a4d92e578845d517660942e851ca4f (diff) |
microblaze: Support ptrace syscall tracing.
Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com>
Signed-off-by: Michal Simek <monstr@monstr.eu>
Diffstat (limited to 'arch/microblaze')
-rw-r--r-- | arch/microblaze/kernel/entry.S | 72 | ||||
-rw-r--r-- | arch/microblaze/kernel/ptrace.c | 62 |
2 files changed, 122 insertions, 12 deletions
diff --git a/arch/microblaze/kernel/entry.S b/arch/microblaze/kernel/entry.S index c7353e79f4a2..acc1f05d1e2c 100644 --- a/arch/microblaze/kernel/entry.S +++ b/arch/microblaze/kernel/entry.S | |||
@@ -308,38 +308,69 @@ C_ENTRY(_user_exception): | |||
308 | swi r12, r1, PTO+PT_R0; | 308 | swi r12, r1, PTO+PT_R0; |
309 | tovirt(r1,r1) | 309 | tovirt(r1,r1) |
310 | 310 | ||
311 | la r15, r0, ret_from_trap-8 | ||
312 | /* where the trap should return need -8 to adjust for rtsd r15, 8*/ | 311 | /* where the trap should return need -8 to adjust for rtsd r15, 8*/ |
313 | /* Jump to the appropriate function for the system call number in r12 | 312 | /* Jump to the appropriate function for the system call number in r12 |
314 | * (r12 is not preserved), or return an error if r12 is not valid. The LP | 313 | * (r12 is not preserved), or return an error if r12 is not valid. The LP |
315 | * register should point to the location where | 314 | * register should point to the location where |
316 | * the called function should return. [note that MAKE_SYS_CALL uses label 1] */ | 315 | * the called function should return. [note that MAKE_SYS_CALL uses label 1] */ |
317 | /* See if the system call number is valid. */ | 316 | |
317 | # Step into virtual mode. | ||
318 | set_vms; | ||
319 | addik r11, r0, 3f | ||
320 | rtid r11, 0 | ||
321 | nop | ||
322 | 3: | ||
323 | add r11, r0, CURRENT_TASK /* Get current task ptr into r11 */ | ||
324 | lwi r11, r11, TS_THREAD_INFO /* get thread info */ | ||
325 | lwi r11, r11, TI_FLAGS /* get flags in thread info */ | ||
326 | andi r11, r11, _TIF_WORK_SYSCALL_MASK | ||
327 | beqi r11, 4f | ||
328 | |||
329 | addik r3, r0, -ENOSYS | ||
330 | swi r3, r1, PTO + PT_R3 | ||
331 | brlid r15, do_syscall_trace_enter | ||
332 | addik r5, r1, PTO + PT_R0 | ||
333 | |||
334 | # do_syscall_trace_enter returns the new syscall nr. | ||
335 | addk r12, r0, r3 | ||
336 | lwi r5, r1, PTO+PT_R5; | ||
337 | lwi r6, r1, PTO+PT_R6; | ||
338 | lwi r7, r1, PTO+PT_R7; | ||
339 | lwi r8, r1, PTO+PT_R8; | ||
340 | lwi r9, r1, PTO+PT_R9; | ||
341 | lwi r10, r1, PTO+PT_R10; | ||
342 | 4: | ||
343 | /* Jump to the appropriate function for the system call number in r12 | ||
344 | * (r12 is not preserved), or return an error if r12 is not valid. | ||
345 | * The LP register should point to the location where the called function | ||
346 | * should return. [note that MAKE_SYS_CALL uses label 1] */ | ||
347 | /* See if the system call number is valid */ | ||
318 | addi r11, r12, -__NR_syscalls; | 348 | addi r11, r12, -__NR_syscalls; |
319 | bgei r11,1f; | 349 | bgei r11,5f; |
320 | /* Figure out which function to use for this system call. */ | 350 | /* Figure out which function to use for this system call. */ |
321 | /* Note Microblaze barrel shift is optional, so don't rely on it */ | 351 | /* Note Microblaze barrel shift is optional, so don't rely on it */ |
322 | add r12, r12, r12; /* convert num -> ptr */ | 352 | add r12, r12, r12; /* convert num -> ptr */ |
323 | add r12, r12, r12; | 353 | add r12, r12, r12; |
324 | 354 | ||
325 | /* Trac syscalls and stored them to r0_ram */ | 355 | /* Trac syscalls and stored them to r0_ram */ |
326 | lwi r3, r12, 0x400 + TOPHYS(r0_ram) | 356 | lwi r3, r12, 0x400 + r0_ram |
327 | addi r3, r3, 1 | 357 | addi r3, r3, 1 |
328 | swi r3, r12, 0x400 + TOPHYS(r0_ram) | 358 | swi r3, r12, 0x400 + r0_ram |
359 | |||
360 | # Find and jump into the syscall handler. | ||
361 | lwi r12, r12, sys_call_table | ||
362 | /* where the trap should return need -8 to adjust for rtsd r15, 8 */ | ||
363 | la r15, r0, ret_from_trap-8 | ||
364 | bra r12 | ||
329 | 365 | ||
330 | lwi r12, r12, TOPHYS(sys_call_table); /* Function ptr */ | ||
331 | /* Make the system call. to r12*/ | ||
332 | set_vms; | ||
333 | rtid r12, 0; | ||
334 | nop; | ||
335 | /* The syscall number is invalid, return an error. */ | 366 | /* The syscall number is invalid, return an error. */ |
336 | 1: VM_ON; /* RETURN() expects virtual mode*/ | 367 | 5: |
337 | addi r3, r0, -ENOSYS; | 368 | addi r3, r0, -ENOSYS; |
338 | rtsd r15,8; /* looks like a normal subroutine return */ | 369 | rtsd r15,8; /* looks like a normal subroutine return */ |
339 | or r0, r0, r0 | 370 | or r0, r0, r0 |
340 | 371 | ||
341 | 372 | ||
342 | /* Entry point used to return from a syscall/trap. */ | 373 | /* Entry point used to return from a syscall/trap */ |
343 | /* We re-enable BIP bit before state restore */ | 374 | /* We re-enable BIP bit before state restore */ |
344 | C_ENTRY(ret_from_trap): | 375 | C_ENTRY(ret_from_trap): |
345 | set_bip; /* Ints masked for state restore*/ | 376 | set_bip; /* Ints masked for state restore*/ |
@@ -349,6 +380,23 @@ C_ENTRY(ret_from_trap): | |||
349 | 380 | ||
350 | /* We're returning to user mode, so check for various conditions that | 381 | /* We're returning to user mode, so check for various conditions that |
351 | * trigger rescheduling. */ | 382 | * trigger rescheduling. */ |
383 | # FIXME: Restructure all these flag checks. | ||
384 | add r11, r0, CURRENT_TASK; /* Get current task ptr into r11 */ | ||
385 | lwi r11, r11, TS_THREAD_INFO; /* get thread info */ | ||
386 | lwi r11, r11, TI_FLAGS; /* get flags in thread info */ | ||
387 | andi r11, r11, _TIF_WORK_SYSCALL_MASK | ||
388 | beqi r11, 1f | ||
389 | |||
390 | swi r3, r1, PTO + PT_R3 | ||
391 | swi r4, r1, PTO + PT_R4 | ||
392 | brlid r15, do_syscall_trace_leave | ||
393 | addik r5, r1, PTO + PT_R0 | ||
394 | lwi r3, r1, PTO + PT_R3 | ||
395 | lwi r4, r1, PTO + PT_R4 | ||
396 | 1: | ||
397 | |||
398 | /* We're returning to user mode, so check for various conditions that | ||
399 | * trigger rescheduling. */ | ||
352 | /* Get current task ptr into r11 */ | 400 | /* Get current task ptr into r11 */ |
353 | add r11, r0, CURRENT_TASK; /* Get current task ptr into r11 */ | 401 | add r11, r0, CURRENT_TASK; /* Get current task ptr into r11 */ |
354 | lwi r11, r11, TS_THREAD_INFO; /* get thread info */ | 402 | lwi r11, r11, TS_THREAD_INFO; /* get thread info */ |
diff --git a/arch/microblaze/kernel/ptrace.c b/arch/microblaze/kernel/ptrace.c index 53ff39af6a5c..4b3ac32754de 100644 --- a/arch/microblaze/kernel/ptrace.c +++ b/arch/microblaze/kernel/ptrace.c | |||
@@ -29,6 +29,10 @@ | |||
29 | #include <linux/sched.h> | 29 | #include <linux/sched.h> |
30 | #include <linux/ptrace.h> | 30 | #include <linux/ptrace.h> |
31 | #include <linux/signal.h> | 31 | #include <linux/signal.h> |
32 | #include <linux/elf.h> | ||
33 | #include <linux/audit.h> | ||
34 | #include <linux/seccomp.h> | ||
35 | #include <linux/tracehook.h> | ||
32 | 36 | ||
33 | #include <linux/errno.h> | 37 | #include <linux/errno.h> |
34 | #include <asm/processor.h> | 38 | #include <asm/processor.h> |
@@ -174,6 +178,64 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
174 | return rval; | 178 | return rval; |
175 | } | 179 | } |
176 | 180 | ||
181 | asmlinkage long do_syscall_trace_enter(struct pt_regs *regs) | ||
182 | { | ||
183 | long ret = 0; | ||
184 | |||
185 | secure_computing(regs->r12); | ||
186 | |||
187 | if (test_thread_flag(TIF_SYSCALL_TRACE) && | ||
188 | tracehook_report_syscall_entry(regs)) | ||
189 | /* | ||
190 | * Tracing decided this syscall should not happen. | ||
191 | * We'll return a bogus call number to get an ENOSYS | ||
192 | * error, but leave the original number in regs->regs[0]. | ||
193 | */ | ||
194 | ret = -1L; | ||
195 | |||
196 | if (unlikely(current->audit_context)) | ||
197 | audit_syscall_entry(EM_XILINX_MICROBLAZE, regs->r12, | ||
198 | regs->r5, regs->r6, | ||
199 | regs->r7, regs->r8); | ||
200 | |||
201 | return ret ?: regs->r12; | ||
202 | } | ||
203 | |||
204 | asmlinkage void do_syscall_trace_leave(struct pt_regs *regs) | ||
205 | { | ||
206 | int step; | ||
207 | |||
208 | if (unlikely(current->audit_context)) | ||
209 | audit_syscall_exit(AUDITSC_RESULT(regs->r3), regs->r3); | ||
210 | |||
211 | step = test_thread_flag(TIF_SINGLESTEP); | ||
212 | if (step || test_thread_flag(TIF_SYSCALL_TRACE)) | ||
213 | tracehook_report_syscall_exit(regs, step); | ||
214 | } | ||
215 | |||
216 | #if 0 | ||
217 | static asmlinkage void syscall_trace(void) | ||
218 | { | ||
219 | if (!test_thread_flag(TIF_SYSCALL_TRACE)) | ||
220 | return; | ||
221 | if (!(current->ptrace & PT_PTRACED)) | ||
222 | return; | ||
223 | /* The 0x80 provides a way for the tracing parent to distinguish | ||
224 | between a syscall stop and SIGTRAP delivery */ | ||
225 | ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) | ||
226 | ? 0x80 : 0)); | ||
227 | /* | ||
228 | * this isn't the same as continuing with a signal, but it will do | ||
229 | * for normal use. strace only continues with a signal if the | ||
230 | * stopping signal is not SIGTRAP. -brl | ||
231 | */ | ||
232 | if (current->exit_code) { | ||
233 | send_sig(current->exit_code, current, 1); | ||
234 | current->exit_code = 0; | ||
235 | } | ||
236 | } | ||
237 | #endif | ||
238 | |||
177 | void ptrace_disable(struct task_struct *child) | 239 | void ptrace_disable(struct task_struct *child) |
178 | { | 240 | { |
179 | /* nothing to do */ | 241 | /* nothing to do */ |