svn commit: r332951 - in head/sys/mips: include mips
John Baldwin
jhb at FreeBSD.org
Tue Apr 24 17:53:17 UTC 2018
Author: jhb
Date: Tue Apr 24 17:53:16 2018
New Revision: 332951
URL: https://svnweb.freebsd.org/changeset/base/332951
Log:
Fix PT_STEP single-stepping for mips.
Note that GDB at least implements single stepping for MIPS using software
breakpoints explicitly rather than using PT_STEP, so this has only been
tested via tests in ptrace_test which now pass rather than fail.
- Fix several places to use uintptr_t instead of int for virtual addresses.
- Check for errors from ptrace_read_int() when setting a breakpoint for a
step.
- Properly check for errors from ptrace_write_int() as it returns non-zero,
not negative values on failure.
- Change the error returns for ptrace_read_int() and ptrace_write_int() from
ENOMEM to EFAULT.
- Clear a single step breakpoint when it traps rather than waiting for it
to be cleared from ptrace(). This matches the behavior of the arm port
and in general seems a bit more reliable than waiting for ptrace() to
clear it via FIX_SSTEP.
- Drop the PROC_LOCK around ptrace_write_int() in ptrace_clear_single_step()
since it can sleep.
- Reorder the breakpoint handler in trap() to only read the instruction if
the address matches the current thread's breakpoint address.
- Replace various #if 0'd debugging printfs with KTR_PTRACE traces.
Tested on: mips64
Modified:
head/sys/mips/include/proc.h
head/sys/mips/mips/pm_machdep.c
head/sys/mips/mips/trap.c
Modified: head/sys/mips/include/proc.h
==============================================================================
--- head/sys/mips/include/proc.h Tue Apr 24 17:46:33 2018 (r332950)
+++ head/sys/mips/include/proc.h Tue Apr 24 17:53:16 2018 (r332951)
@@ -55,7 +55,7 @@ struct mdthread {
#else
int md_upte[KSTACK_PAGES];
#endif
- int md_ss_addr; /* single step address for ptrace */
+ uintptr_t md_ss_addr; /* single step address for ptrace */
int md_ss_instr; /* single step instruction for ptrace */
register_t md_saved_intr;
u_int md_spinlock_count;
Modified: head/sys/mips/mips/pm_machdep.c
==============================================================================
--- head/sys/mips/mips/pm_machdep.c Tue Apr 24 17:46:33 2018 (r332950)
+++ head/sys/mips/mips/pm_machdep.c Tue Apr 24 17:53:16 2018 (r332951)
@@ -216,29 +216,29 @@ ptrace_set_pc(struct thread *td, unsigned long addr)
}
static int
-ptrace_read_int(struct thread *td, off_t addr, int *v)
+ptrace_read_int(struct thread *td, uintptr_t addr, int *v)
{
if (proc_readmem(td, td->td_proc, addr, v, sizeof(*v)) != sizeof(*v))
- return (ENOMEM);
+ return (EFAULT);
return (0);
}
static int
-ptrace_write_int(struct thread *td, off_t addr, int v)
+ptrace_write_int(struct thread *td, uintptr_t addr, int v)
{
if (proc_writemem(td, td->td_proc, addr, &v, sizeof(v)) != sizeof(v))
- return (ENOMEM);
+ return (EFAULT);
return (0);
}
int
ptrace_single_step(struct thread *td)
{
- unsigned va;
+ uintptr_t va;
struct trapframe *locr0 = td->td_frame;
- int i;
+ int error;
int bpinstr = MIPS_BREAK_SSTEP;
int curinstr;
struct proc *p;
@@ -248,46 +248,52 @@ ptrace_single_step(struct thread *td)
/*
* Fetch what's at the current location.
*/
- ptrace_read_int(td, (off_t)locr0->pc, &curinstr);
+ error = ptrace_read_int(td, locr0->pc, &curinstr);
+ if (error)
+ goto out;
+ CTR3(KTR_PTRACE,
+ "ptrace_single_step: tid %d, current instr at %#lx: %#08x",
+ td->td_tid, locr0->pc, curinstr);
+
/* compute next address after current location */
- if(curinstr != 0) {
+ if (locr0->cause & MIPS_CR_BR_DELAY) {
va = MipsEmulateBranch(locr0, locr0->pc, locr0->fsr,
(uintptr_t)&curinstr);
} else {
va = locr0->pc + 4;
}
if (td->td_md.md_ss_addr) {
- printf("SS %s (%d): breakpoint already set at %x (va %x)\n",
+ printf("SS %s (%d): breakpoint already set at %lx (va %lx)\n",
p->p_comm, p->p_pid, td->td_md.md_ss_addr, va); /* XXX */
- PROC_LOCK(p);
- return (EFAULT);
+ error = EFAULT;
+ goto out;
}
td->td_md.md_ss_addr = va;
/*
* Fetch what's at the current location.
*/
- ptrace_read_int(td, (off_t)va, &td->td_md.md_ss_instr);
+ error = ptrace_read_int(td, (off_t)va, &td->td_md.md_ss_instr);
+ if (error)
+ goto out;
/*
* Store breakpoint instruction at the "next" location now.
*/
- i = ptrace_write_int (td, va, bpinstr);
+ error = ptrace_write_int(td, va, bpinstr);
/*
- * The sync'ing of I & D caches is done by procfs_domem()
- * through procfs_rwmem().
+ * The sync'ing of I & D caches is done by proc_rwmem()
+ * through proc_writemem().
*/
+out:
PROC_LOCK(p);
- if (i < 0)
- return (EFAULT);
-#if 0
- printf("SS %s (%d): breakpoint set at %x: %x (pc %x) br %x\n",
- p->p_comm, p->p_pid, p->p_md.md_ss_addr,
- p->p_md.md_ss_instr, locr0->pc, curinstr); /* XXX */
-#endif
- return (0);
+ if (error == 0)
+ CTR3(KTR_PTRACE,
+ "ptrace_single_step: tid %d, break set at %#lx: (%#08x)",
+ td->td_tid, va, td->td_md.md_ss_instr);
+ return (error);
}
@@ -471,8 +477,8 @@ exec_setregs(struct thread *td, struct image_params *i
int
ptrace_clear_single_step(struct thread *td)
{
- int i;
struct proc *p;
+ int error;
p = td->td_proc;
PROC_LOCK_ASSERT(p, MA_OWNED);
@@ -482,12 +488,19 @@ ptrace_clear_single_step(struct thread *td)
/*
* Restore original instruction and clear BP
*/
- i = ptrace_write_int (td, td->td_md.md_ss_addr, td->td_md.md_ss_instr);
+ PROC_UNLOCK(p);
+ CTR3(KTR_PTRACE,
+ "ptrace_clear_single_step: tid %d, restore instr at %#lx: %#08x",
+ td->td_tid, td->td_md.md_ss_addr, td->td_md.md_ss_instr);
+ error = ptrace_write_int(td, td->td_md.md_ss_addr,
+ td->td_md.md_ss_instr);
+ PROC_LOCK(p);
- /* The sync'ing of I & D caches is done by procfs_domem(). */
+ /* The sync'ing of I & D caches is done by proc_rwmem(). */
- if (i < 0) {
- log(LOG_ERR, "SS %s %d: can't restore instruction at %x: %x\n",
+ if (error != 0) {
+ log(LOG_ERR,
+ "SS %s %d: can't restore instruction at %lx: %x\n",
p->p_comm, p->p_pid, td->td_md.md_ss_addr,
td->td_md.md_ss_instr);
}
Modified: head/sys/mips/mips/trap.c
==============================================================================
--- head/sys/mips/mips/trap.c Tue Apr 24 17:46:33 2018 (r332950)
+++ head/sys/mips/mips/trap.c Tue Apr 24 17:53:16 2018 (r332951)
@@ -526,7 +526,7 @@ trap(struct trapframe *trapframe)
char *msg = NULL;
intptr_t addr = 0;
register_t pc;
- int cop;
+ int cop, error;
register_t *frame_regs;
trapdebug_enter(trapframe, 0);
@@ -825,34 +825,34 @@ dofault:
intptr_t va;
uint32_t instr;
+ i = SIGTRAP;
+ ucode = TRAP_BRKPT;
+ addr = trapframe->pc;
+
/* compute address of break instruction */
va = trapframe->pc;
if (DELAYBRANCH(trapframe->cause))
va += sizeof(int);
+ if (td->td_md.md_ss_addr != va)
+ break;
+
/* read break instruction */
instr = fuword32((caddr_t)va);
-#if 0
- printf("trap: %s (%d) breakpoint %x at %x: (adr %x ins %x)\n",
- p->p_comm, p->p_pid, instr, trapframe->pc,
- p->p_md.md_ss_addr, p->p_md.md_ss_instr); /* XXX */
-#endif
- if (td->td_md.md_ss_addr != va ||
- instr != MIPS_BREAK_SSTEP) {
- i = SIGTRAP;
- ucode = TRAP_BRKPT;
- addr = trapframe->pc;
+
+ if (instr != MIPS_BREAK_SSTEP)
break;
- }
- /*
- * The restoration of the original instruction and
- * the clearing of the breakpoint will be done later
- * by the call to ptrace_clear_single_step() in
- * issignal() when SIGTRAP is processed.
- */
- addr = trapframe->pc;
- i = SIGTRAP;
- ucode = TRAP_TRACE;
+
+ CTR3(KTR_PTRACE,
+ "trap: tid %d, single step at %#lx: %#08x",
+ td->td_tid, va, instr);
+ PROC_LOCK(p);
+ _PHOLD(p);
+ error = ptrace_clear_single_step(td);
+ _PRELE(p);
+ PROC_UNLOCK(p);
+ if (error == 0)
+ ucode = TRAP_TRACE;
break;
}
More information about the svn-src-head
mailing list