Skip to content

Commit

Permalink
sh: ptrace single stepping cleanups.
Browse files Browse the repository at this point in the history
This converts the single stepping done by sh/sh64 ptrace implementations
to use the generic user_enable/disable_single_step(), and subsequently
rips out a lot of ptrace request cases that are now handled generically.

Signed-off-by: Paul Mundt <lethal@linux-sh.org>
  • Loading branch information
Paul Mundt committed Aug 1, 2008
1 parent c4637d4 commit c459dbf
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 140 deletions.
9 changes: 9 additions & 0 deletions arch/sh/include/asm/ptrace.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,15 @@ struct pt_dspregs {

extern void show_regs(struct pt_regs *);

/*
* These are defined as per linux/ptrace.h.
*/
struct task_struct;

#define arch_has_single_step() (1)
extern void user_enable_single_step(struct task_struct *);
extern void user_disable_single_step(struct task_struct *);

#ifdef CONFIG_SH_DSP
#define task_pt_regs(task) \
((struct pt_regs *) (task_stack_page(task) + THREAD_SIZE \
Expand Down
93 changes: 18 additions & 75 deletions arch/sh/kernel/ptrace_32.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,23 @@ static inline int put_stack_long(struct task_struct *task, int offset,
return 0;
}

static void ptrace_disable_singlestep(struct task_struct *child)
void user_enable_single_step(struct task_struct *child)
{
struct pt_regs *regs = task_pt_regs(child);
long pc;

pc = get_stack_long(child, (long)&regs->pc);

/* Next scheduling will set up UBC */
if (child->thread.ubc_pc == 0)
ubc_usercnt += 1;

child->thread.ubc_pc = pc;

set_tsk_thread_flag(child, TIF_SINGLESTEP);
}

void user_disable_single_step(struct task_struct *child)
{
clear_tsk_thread_flag(child, TIF_SINGLESTEP);

Expand All @@ -82,7 +98,7 @@ static void ptrace_disable_singlestep(struct task_struct *child)
*/
void ptrace_disable(struct task_struct *child)
{
ptrace_disable_singlestep(child);
user_disable_single_step(child);
}

long arch_ptrace(struct task_struct *child, long request, long addr, long data)
Expand All @@ -91,12 +107,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
int ret;

switch (request) {
/* when I and D space are separate, these will need to be fixed. */
case PTRACE_PEEKTEXT: /* read word at location addr. */
case PTRACE_PEEKDATA:
ret = generic_ptrace_peekdata(child, addr, data);
break;

/* read the word at location addr in the USER area. */
case PTRACE_PEEKUSR: {
unsigned long tmp;
Expand Down Expand Up @@ -126,12 +136,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
break;
}

/* when I and D space are separate, this will have to be fixed. */
case PTRACE_POKETEXT: /* write the word at location addr. */
case PTRACE_POKEDATA:
ret = generic_ptrace_pokedata(child, addr, data);
break;

case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
ret = -EIO;
if ((addr & 3) || addr < 0 ||
Expand All @@ -152,67 +156,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
}
break;

case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
case PTRACE_CONT: { /* restart after signal. */
ret = -EIO;
if (!valid_signal(data))
break;
if (request == PTRACE_SYSCALL)
set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
else
clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);

ptrace_disable_singlestep(child);

child->exit_code = data;
wake_up_process(child);
ret = 0;
break;
}

/*
* make the child exit. Best I can do is send it a sigkill.
* perhaps it should be put in the status that it wants to
* exit.
*/
case PTRACE_KILL: {
ret = 0;
if (child->exit_state == EXIT_ZOMBIE) /* already dead */
break;
ptrace_disable_singlestep(child);
child->exit_code = SIGKILL;
wake_up_process(child);
break;
}

case PTRACE_SINGLESTEP: { /* set the trap flag. */
long pc;
struct pt_regs *regs = NULL;

ret = -EIO;
if (!valid_signal(data))
break;
clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
if ((child->ptrace & PT_DTRACE) == 0) {
/* Spurious delayed TF traps may occur */
child->ptrace |= PT_DTRACE;
}

pc = get_stack_long(child, (long)&regs->pc);

/* Next scheduling will set up UBC */
if (child->thread.ubc_pc == 0)
ubc_usercnt += 1;
child->thread.ubc_pc = pc;

set_tsk_thread_flag(child, TIF_SINGLESTEP);
child->exit_code = data;
/* give it a chance to run. */
wake_up_process(child);
ret = 0;
break;
}

#ifdef CONFIG_SH_DSP
case PTRACE_GETDSPREGS: {
unsigned long dp;
Expand Down
77 changes: 12 additions & 65 deletions arch/sh/kernel/ptrace_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -121,18 +121,23 @@ put_fpu_long(struct task_struct *task, unsigned long addr, unsigned long data)
return 0;
}

void user_enable_single_step(struct task_struct *child)
{
struct pt_regs *regs = child->thread.uregs;

regs->sr |= SR_SSTEP; /* auto-resetting upon exception */
}

void user_disable_single_step(struct task_struct *child)
{
regs->sr &= ~SR_SSTEP;
}

long arch_ptrace(struct task_struct *child, long request, long addr, long data)
{
int ret;

switch (request) {
/* when I and D space are separate, these will need to be fixed. */
case PTRACE_PEEKTEXT: /* read word at location addr. */
case PTRACE_PEEKDATA:
ret = generic_ptrace_peekdata(child, addr, data);
break;

/* read the word at location addr in the USER area. */
case PTRACE_PEEKUSR: {
unsigned long tmp;
Expand All @@ -155,12 +160,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
break;
}

/* when I and D space are separate, this will have to be fixed. */
case PTRACE_POKETEXT: /* write the word at location addr. */
case PTRACE_POKEDATA:
ret = generic_ptrace_pokedata(child, addr, data);
break;

case PTRACE_POKEUSR:
/* write the word at location addr in the USER area. We must
disallow any changes to certain SR bits or u_fpvalid, since
Expand Down Expand Up @@ -192,58 +191,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
}
break;

case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
case PTRACE_CONT: { /* restart after signal. */
ret = -EIO;
if (!valid_signal(data))
break;
if (request == PTRACE_SYSCALL)
set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
else
clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
child->exit_code = data;
wake_up_process(child);
ret = 0;
break;
}

/*
* make the child exit. Best I can do is send it a sigkill.
* perhaps it should be put in the status that it wants to
* exit.
*/
case PTRACE_KILL: {
ret = 0;
if (child->exit_state == EXIT_ZOMBIE) /* already dead */
break;
child->exit_code = SIGKILL;
wake_up_process(child);
break;
}

case PTRACE_SINGLESTEP: { /* set the trap flag. */
struct pt_regs *regs;

ret = -EIO;
if (!valid_signal(data))
break;
clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
if ((child->ptrace & PT_DTRACE) == 0) {
/* Spurious delayed TF traps may occur */
child->ptrace |= PT_DTRACE;
}

regs = child->thread.uregs;

regs->sr |= SR_SSTEP; /* auto-resetting upon exception */

child->exit_code = data;
/* give it a chance to run. */
wake_up_process(child);
ret = 0;
break;
}

default:
ret = ptrace_request(child, request, addr, data);
break;
Expand Down Expand Up @@ -341,5 +288,5 @@ asmlinkage void do_software_break_point(unsigned long long vec,
*/
void ptrace_disable(struct task_struct *child)
{
/* nothing to do.. */
user_disable_single_step(child);
}

0 comments on commit c459dbf

Please sign in to comment.