unsigned long sp;
unsigned long pc;
-- - /* Hardware debugging registers */
-- - unsigned long ubc_pc;
- -
- - /* floating point info */
- - union sh_fpu_union fpu;
++ + /* Save middle states of ptrace breakpoints */
++ + struct perf_event *ptrace_bps[HBP_NUM];
- /* floating point info */
- union sh_fpu_union fpu;
-
#ifdef CONFIG_SH_DSP
/* Dsp status information */
struct sh_dsp_struct dsp_status;
#endif
- -};
+
- -/* Count of active tasks with UBC settings */
- -extern int ubc_usercnt;
+ ++ /* Extended processor state */
+ ++ union thread_xstate *xstate;
+ +};
- /* Count of active tasks with UBC settings */
- extern int ubc_usercnt;
-
#define INIT_THREAD { \
.sp = sizeof(init_stack) + (long) &init_stack, \
}
return 0;
}
-- -void user_enable_single_step(struct task_struct *child)
++ +void ptrace_triggered(struct perf_event *bp, int nmi,
++ + struct perf_sample_data *data, struct pt_regs *regs)
+ {
- - /* Next scheduling will set up UBC */
- - if (child->thread.ubc_pc == 0)
- - ubc_usercnt += 1;
++ + struct perf_event_attr attr;
++ +
++ + /*
++ + * Disable the breakpoint request here since ptrace has defined a
++ + * one-shot behaviour for breakpoint exceptions.
++ + */
++ + attr = bp->attr;
++ + attr.disabled = true;
++ + modify_user_hw_breakpoint(bp, &attr);
++ +}
++ +
++ +static int set_single_step(struct task_struct *tsk, unsigned long addr)
+ +{
- /* Next scheduling will set up UBC */
- if (child->thread.ubc_pc == 0)
- ubc_usercnt += 1;
++ + struct thread_struct *thread = &tsk->thread;
++ + struct perf_event *bp;
++ + struct perf_event_attr attr;
++ +
++ + bp = thread->ptrace_bps[0];
++ + if (!bp) {
++ + hw_breakpoint_init(&attr);
++ +
++ + attr.bp_addr = addr;
++ + attr.bp_len = HW_BREAKPOINT_LEN_2;
++ + attr.bp_type = HW_BREAKPOINT_R;
+ +
- child->thread.ubc_pc = get_stack_long(child,
- offsetof(struct pt_regs, pc));
++ + bp = register_user_hw_breakpoint(&attr, ptrace_triggered, tsk);
++ + if (IS_ERR(bp))
++ + return PTR_ERR(bp);
++ +
++ + thread->ptrace_bps[0] = bp;
++ + } else {
++ + int err;
++ +
++ + attr = bp->attr;
++ + attr.bp_addr = addr;
++ + err = modify_user_hw_breakpoint(bp, &attr);
++ + if (unlikely(err))
++ + return err;
++ + }
++ +
++ + return 0;
++ +}
+
- - child->thread.ubc_pc = get_stack_long(child,
- - offsetof(struct pt_regs, pc));
++ +void user_enable_single_step(struct task_struct *child)
++ +{
++ + unsigned long pc = get_stack_long(child, offsetof(struct pt_regs, pc));
set_tsk_thread_flag(child, TIF_SINGLESTEP);
++ +
++ + set_single_step(child, pc);
}
void user_disable_single_step(struct task_struct *child)