[PATCH 1c] utrace: tracehook for s390 This patch does the initial tracehook conversion for s390. Signed-off-by: Roland McGrath Signed-off-by: David Wilder --- include/asm-s390/tracehook.h | 46 ++++++++++++++++++++++++++++ arch/s390/kernel/compat_signal.c | 5 ++- arch/s390/kernel/signal.c | 3 ++ arch/s390/kernel/traps.c | 6 ++-- arch/s390/kernel/ptrace.c | 62 +++++++++++++++++++++----------------- 5 files changed, 90 insertions(+), 32 deletions(-) create include/asm-s390/tracehook.h --- linux-2.6/include/asm-s390/tracehook.h +++ linux-2.6/include/asm-s390/tracehook.h @@ -0,0 +1,46 @@ +/* + * Tracing hooks, s390/s390x support. + * + * Copyright (C) 2006, 2007 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License v.2. + * + * Red Hat Author: Roland McGrath. + */ + +#ifndef _ASM_TRACEHOOK_H +#define _ASM_TRACEHOOK_H 1 + +#include +#include + +/* + * See linux/tracehook.h for the descriptions of what these need to do. + */ + +#define ARCH_HAS_SINGLE_STEP (1) + +/* These three are defined in arch/s390/kernel/ptrace.c. */ +void tracehook_enable_single_step(struct task_struct *tsk); +void tracehook_disable_single_step(struct task_struct *tsk); +int tracehook_single_step_enabled(struct task_struct *tsk); + + +static inline void tracehook_enable_syscall_trace(struct task_struct *tsk) +{ + set_tsk_thread_flag(tsk, TIF_SYSCALL_TRACE); +} + +static inline void tracehook_disable_syscall_trace(struct task_struct *tsk) +{ + clear_tsk_thread_flag(tsk, TIF_SYSCALL_TRACE); +} + +static inline void tracehook_abort_syscall(struct pt_regs *regs) +{ + regs->gprs[2] = -1L; +} + +#endif --- linux-2.6/arch/s390/kernel/compat_signal.c +++ linux-2.6/arch/s390/kernel/compat_signal.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "compat_linux.h" #include "compat_ptrace.h" @@ -579,7 +580,9 @@ handle_signal32(unsigned long sig, struc sigaddset(¤t->blocked,sig); recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); + + tracehook_report_handle_signal(sig, ka, oldset, regs); } + return ret; } - --- linux-2.6/arch/s390/kernel/signal.c +++ linux-2.6/arch/s390/kernel/signal.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -395,6 +396,8 @@ handle_signal(unsigned long sig, struct sigaddset(¤t->blocked,sig); recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); + + tracehook_report_handle_signal(sig, ka, oldset, regs); } return ret; --- linux-2.6/arch/s390/kernel/traps.c +++ linux-2.6/arch/s390/kernel/traps.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include #include @@ -360,7 +360,7 @@ void __kprobes do_single_step(struct pt_ SIGTRAP) == NOTIFY_STOP){ return; } - if ((current->ptrace & PT_PTRACED) != 0) + if (tracehook_consider_fatal_signal(current, SIGTRAP)) force_sig(SIGTRAP, current); } @@ -461,7 +461,7 @@ static void illegal_op(struct pt_regs * if (get_user(*((__u16 *) opcode), (__u16 __user *) location)) return; if (*((__u16 *) opcode) == S390_BREAKPOINT_U16) { - if (current->ptrace & PT_PTRACED) + if (tracehook_consider_fatal_signal(current, SIGTRAP)) force_sig(SIGTRAP, current); else signal = SIGILL; --- linux-2.6/arch/s390/kernel/ptrace.c +++ linux-2.6/arch/s390/kernel/ptrace.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -84,18 +85,35 @@ FixPerRegisters(struct task_struct *task per_info->control_regs.bits.storage_alt_space_ctl = 1; else per_info->control_regs.bits.storage_alt_space_ctl = 0; + + if (task == current) + /* + * These registers are loaded in __switch_to on + * context switch. We must load them now if + * touching the current thread. + */ + __ctl_load(per_info->control_regs.words.cr, 9, 11); } -static void set_single_step(struct task_struct *task) +void +tracehook_enable_single_step(struct task_struct *task) { task->thread.per_info.single_step = 1; FixPerRegisters(task); } -static void clear_single_step(struct task_struct *task) +void +tracehook_disable_single_step(struct task_struct *task) { task->thread.per_info.single_step = 0; FixPerRegisters(task); + clear_tsk_thread_flag(task, TIF_SINGLE_STEP); +} + +int +tracehook_single_step_enabled(struct task_struct *task) +{ + return task->thread.per_info.single_step; } /* @@ -107,7 +125,7 @@ void ptrace_disable(struct task_struct *child) { /* make sure the single step bit is not set. */ - clear_single_step(child); + tracehook_disable_single_step(child); } #ifndef CONFIG_64BIT @@ -593,6 +611,7 @@ do_ptrace_emu31(struct task_struct *chil copied += sizeof(unsigned int); } return 0; +#if 0 /* XXX */ case PTRACE_GETEVENTMSG: return put_user((__u32) child->ptrace_message, (unsigned int __force __user *) data); @@ -658,7 +677,7 @@ do_ptrace(struct task_struct *child, lon clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); child->exit_code = data; /* make sure the single step bit is not set. */ - clear_single_step(child); + tracehook_disable_single_step(child); wake_up_process(child); return 0; @@ -672,7 +691,7 @@ do_ptrace(struct task_struct *child, lon return 0; child->exit_code = SIGKILL; /* make sure the single step bit is not set. */ - clear_single_step(child); + tracehook_disable_single_step(child); wake_up_process(child); return 0; @@ -685,7 +704,7 @@ do_ptrace(struct task_struct *child, lon if (data) set_tsk_thread_flag(child, TIF_SINGLE_STEP); else - set_single_step(child); + tracehook_enable_single_step(child); /* give it a chance to run. */ wake_up_process(child); return 0; @@ -738,30 +757,17 @@ syscall_trace(struct pt_regs *regs, int if (unlikely(current->audit_context) && entryexit) audit_syscall_exit(AUDITSC_RESULT(regs->gprs[2]), regs->gprs[2]); - if (!test_thread_flag(TIF_SYSCALL_TRACE)) - goto out; - if (!(current->ptrace & PT_PTRACED)) - goto out; - ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) - ? 0x80 : 0)); - - /* - * If the debuffer has set an invalid system call number, - * we prepare to skip the system call restart handling. - */ - if (!entryexit && regs->gprs[2] >= NR_syscalls) - regs->trap = -1; + if (test_thread_flag(TIF_SYSCALL_TRACE)) { + tracehook_report_syscall(regs, entryexit); - /* - * 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; + /* + * If the debugger has set an invalid system call number, + * we prepare to skip the system call restart handling. + */ + if (!entryexit && regs->gprs[2] >= NR_syscalls) + regs->trap = -1; } - out: + if (unlikely(current->audit_context) && !entryexit) audit_syscall_entry(test_thread_flag(TIF_31BIT)?AUDIT_ARCH_S390:AUDIT_ARCH_S390X, regs->gprs[2], regs->orig_gpr2, regs->gprs[3],