microblaze: Support ptrace syscall tracing.
Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com> Signed-off-by: Michal Simek <monstr@monstr.eu>
This commit is contained in:
parent
f97b4f7de4
commit
235754834b
@ -308,38 +308,69 @@ C_ENTRY(_user_exception):
|
|||||||
swi r12, r1, PTO+PT_R0;
|
swi r12, r1, PTO+PT_R0;
|
||||||
tovirt(r1,r1)
|
tovirt(r1,r1)
|
||||||
|
|
||||||
la r15, r0, ret_from_trap-8
|
|
||||||
/* where the trap should return need -8 to adjust for rtsd r15, 8*/
|
/* where the trap should return need -8 to adjust for rtsd r15, 8*/
|
||||||
/* Jump to the appropriate function for the system call number in r12
|
/* Jump to the appropriate function for the system call number in r12
|
||||||
* (r12 is not preserved), or return an error if r12 is not valid. The LP
|
* (r12 is not preserved), or return an error if r12 is not valid. The LP
|
||||||
* register should point to the location where
|
* register should point to the location where
|
||||||
* the called function should return. [note that MAKE_SYS_CALL uses label 1] */
|
* the called function should return. [note that MAKE_SYS_CALL uses label 1] */
|
||||||
/* See if the system call number is valid. */
|
|
||||||
|
# Step into virtual mode.
|
||||||
|
set_vms;
|
||||||
|
addik r11, r0, 3f
|
||||||
|
rtid r11, 0
|
||||||
|
nop
|
||||||
|
3:
|
||||||
|
add r11, r0, CURRENT_TASK /* Get current task ptr into r11 */
|
||||||
|
lwi r11, r11, TS_THREAD_INFO /* get thread info */
|
||||||
|
lwi r11, r11, TI_FLAGS /* get flags in thread info */
|
||||||
|
andi r11, r11, _TIF_WORK_SYSCALL_MASK
|
||||||
|
beqi r11, 4f
|
||||||
|
|
||||||
|
addik r3, r0, -ENOSYS
|
||||||
|
swi r3, r1, PTO + PT_R3
|
||||||
|
brlid r15, do_syscall_trace_enter
|
||||||
|
addik r5, r1, PTO + PT_R0
|
||||||
|
|
||||||
|
# do_syscall_trace_enter returns the new syscall nr.
|
||||||
|
addk r12, r0, r3
|
||||||
|
lwi r5, r1, PTO+PT_R5;
|
||||||
|
lwi r6, r1, PTO+PT_R6;
|
||||||
|
lwi r7, r1, PTO+PT_R7;
|
||||||
|
lwi r8, r1, PTO+PT_R8;
|
||||||
|
lwi r9, r1, PTO+PT_R9;
|
||||||
|
lwi r10, r1, PTO+PT_R10;
|
||||||
|
4:
|
||||||
|
/* Jump to the appropriate function for the system call number in r12
|
||||||
|
* (r12 is not preserved), or return an error if r12 is not valid.
|
||||||
|
* The LP register should point to the location where the called function
|
||||||
|
* should return. [note that MAKE_SYS_CALL uses label 1] */
|
||||||
|
/* See if the system call number is valid */
|
||||||
addi r11, r12, -__NR_syscalls;
|
addi r11, r12, -__NR_syscalls;
|
||||||
bgei r11,1f;
|
bgei r11,5f;
|
||||||
/* Figure out which function to use for this system call. */
|
/* Figure out which function to use for this system call. */
|
||||||
/* Note Microblaze barrel shift is optional, so don't rely on it */
|
/* Note Microblaze barrel shift is optional, so don't rely on it */
|
||||||
add r12, r12, r12; /* convert num -> ptr */
|
add r12, r12, r12; /* convert num -> ptr */
|
||||||
add r12, r12, r12;
|
add r12, r12, r12;
|
||||||
|
|
||||||
/* Trac syscalls and stored them to r0_ram */
|
/* Trac syscalls and stored them to r0_ram */
|
||||||
lwi r3, r12, 0x400 + TOPHYS(r0_ram)
|
lwi r3, r12, 0x400 + r0_ram
|
||||||
addi r3, r3, 1
|
addi r3, r3, 1
|
||||||
swi r3, r12, 0x400 + TOPHYS(r0_ram)
|
swi r3, r12, 0x400 + r0_ram
|
||||||
|
|
||||||
|
# Find and jump into the syscall handler.
|
||||||
|
lwi r12, r12, sys_call_table
|
||||||
|
/* where the trap should return need -8 to adjust for rtsd r15, 8 */
|
||||||
|
la r15, r0, ret_from_trap-8
|
||||||
|
bra r12
|
||||||
|
|
||||||
lwi r12, r12, TOPHYS(sys_call_table); /* Function ptr */
|
|
||||||
/* Make the system call. to r12*/
|
|
||||||
set_vms;
|
|
||||||
rtid r12, 0;
|
|
||||||
nop;
|
|
||||||
/* The syscall number is invalid, return an error. */
|
/* The syscall number is invalid, return an error. */
|
||||||
1: VM_ON; /* RETURN() expects virtual mode*/
|
5:
|
||||||
addi r3, r0, -ENOSYS;
|
addi r3, r0, -ENOSYS;
|
||||||
rtsd r15,8; /* looks like a normal subroutine return */
|
rtsd r15,8; /* looks like a normal subroutine return */
|
||||||
or r0, r0, r0
|
or r0, r0, r0
|
||||||
|
|
||||||
|
|
||||||
/* Entry point used to return from a syscall/trap. */
|
/* Entry point used to return from a syscall/trap */
|
||||||
/* We re-enable BIP bit before state restore */
|
/* We re-enable BIP bit before state restore */
|
||||||
C_ENTRY(ret_from_trap):
|
C_ENTRY(ret_from_trap):
|
||||||
set_bip; /* Ints masked for state restore*/
|
set_bip; /* Ints masked for state restore*/
|
||||||
@ -347,6 +378,23 @@ C_ENTRY(ret_from_trap):
|
|||||||
/* See if returning to kernel mode, if so, skip resched &c. */
|
/* See if returning to kernel mode, if so, skip resched &c. */
|
||||||
bnei r11, 2f;
|
bnei r11, 2f;
|
||||||
|
|
||||||
|
/* We're returning to user mode, so check for various conditions that
|
||||||
|
* trigger rescheduling. */
|
||||||
|
# FIXME: Restructure all these flag checks.
|
||||||
|
add r11, r0, CURRENT_TASK; /* Get current task ptr into r11 */
|
||||||
|
lwi r11, r11, TS_THREAD_INFO; /* get thread info */
|
||||||
|
lwi r11, r11, TI_FLAGS; /* get flags in thread info */
|
||||||
|
andi r11, r11, _TIF_WORK_SYSCALL_MASK
|
||||||
|
beqi r11, 1f
|
||||||
|
|
||||||
|
swi r3, r1, PTO + PT_R3
|
||||||
|
swi r4, r1, PTO + PT_R4
|
||||||
|
brlid r15, do_syscall_trace_leave
|
||||||
|
addik r5, r1, PTO + PT_R0
|
||||||
|
lwi r3, r1, PTO + PT_R3
|
||||||
|
lwi r4, r1, PTO + PT_R4
|
||||||
|
1:
|
||||||
|
|
||||||
/* We're returning to user mode, so check for various conditions that
|
/* We're returning to user mode, so check for various conditions that
|
||||||
* trigger rescheduling. */
|
* trigger rescheduling. */
|
||||||
/* Get current task ptr into r11 */
|
/* Get current task ptr into r11 */
|
||||||
|
@ -29,6 +29,10 @@
|
|||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
#include <linux/ptrace.h>
|
#include <linux/ptrace.h>
|
||||||
#include <linux/signal.h>
|
#include <linux/signal.h>
|
||||||
|
#include <linux/elf.h>
|
||||||
|
#include <linux/audit.h>
|
||||||
|
#include <linux/seccomp.h>
|
||||||
|
#include <linux/tracehook.h>
|
||||||
|
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
#include <asm/processor.h>
|
#include <asm/processor.h>
|
||||||
@ -174,6 +178,64 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
|
|||||||
return rval;
|
return rval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
asmlinkage long do_syscall_trace_enter(struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
long ret = 0;
|
||||||
|
|
||||||
|
secure_computing(regs->r12);
|
||||||
|
|
||||||
|
if (test_thread_flag(TIF_SYSCALL_TRACE) &&
|
||||||
|
tracehook_report_syscall_entry(regs))
|
||||||
|
/*
|
||||||
|
* Tracing decided this syscall should not happen.
|
||||||
|
* We'll return a bogus call number to get an ENOSYS
|
||||||
|
* error, but leave the original number in regs->regs[0].
|
||||||
|
*/
|
||||||
|
ret = -1L;
|
||||||
|
|
||||||
|
if (unlikely(current->audit_context))
|
||||||
|
audit_syscall_entry(EM_XILINX_MICROBLAZE, regs->r12,
|
||||||
|
regs->r5, regs->r6,
|
||||||
|
regs->r7, regs->r8);
|
||||||
|
|
||||||
|
return ret ?: regs->r12;
|
||||||
|
}
|
||||||
|
|
||||||
|
asmlinkage void do_syscall_trace_leave(struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
int step;
|
||||||
|
|
||||||
|
if (unlikely(current->audit_context))
|
||||||
|
audit_syscall_exit(AUDITSC_RESULT(regs->r3), regs->r3);
|
||||||
|
|
||||||
|
step = test_thread_flag(TIF_SINGLESTEP);
|
||||||
|
if (step || test_thread_flag(TIF_SYSCALL_TRACE))
|
||||||
|
tracehook_report_syscall_exit(regs, step);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
static asmlinkage void syscall_trace(void)
|
||||||
|
{
|
||||||
|
if (!test_thread_flag(TIF_SYSCALL_TRACE))
|
||||||
|
return;
|
||||||
|
if (!(current->ptrace & PT_PTRACED))
|
||||||
|
return;
|
||||||
|
/* The 0x80 provides a way for the tracing parent to distinguish
|
||||||
|
between a syscall stop and SIGTRAP delivery */
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void ptrace_disable(struct task_struct *child)
|
void ptrace_disable(struct task_struct *child)
|
||||||
{
|
{
|
||||||
/* nothing to do */
|
/* nothing to do */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user