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; } _______________________________________________ svn-src-all@freebsd.org mailing list https://lists.freebsd.org/mailman/listinfo/svn-src-all To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"