Index: sys/arch/arm/arm/process_machdep.c =================================================================== RCS file: /cvsroot/src/sys/arch/arm/arm/process_machdep.c,v retrieving revision 1.31 diff -u -p -r1.31 process_machdep.c --- sys/arch/arm/arm/process_machdep.c 21 Feb 2017 07:40:28 -0000 1.31 +++ sys/arch/arm/arm/process_machdep.c 4 Mar 2017 10:42:20 -0000 @@ -143,9 +143,12 @@ __KERNEL_RCSID(0, "$NetBSD: process_mach #include #include +#include #include #include +int process_clear_sstep(struct lwp *); + int process_read_regs(struct lwp *l, struct reg *regs) { @@ -250,3 +253,286 @@ process_set_pc(struct lwp *l, void *addr return 0; } + +static int +ptrace_read_int(struct lwp *l, vaddr_t addr, uint32_t *v) +{ + + return proc_readmem(curlwp, l, addr, v, sizeof(*v)); +} + +static int +ptrace_write_int(struct lwp *l, vaddr_t addr, uint32_t v) +{ + + return proc_writemem(curlwp, l, addr, &v, sizeof(v)); +} + +static u_int +ptrace_get_usr_reg(void *cookie, int reg) +{ + struct lwp * const l = cookie; + struct trapframe * const tf = lwp_trapframe(l); + int ret; + + KASSERTMSG(reg >= 0 && reg <= ARM_REG_NUM_PC, + "reg (%d) is outside range", reg); + + switch(reg) { + case ARM_REG_NUM_PC: + ret = tf->tf_pc; + break; + case ARM_REG_NUM_LR: + ret = tf->tf_usr_lr; + break; + case ARM_REG_NUM_SP: + ret = tf->tf_usr_sp; + break; + default: + ret = *((register_t*)&tf->tf_r0 + reg); + break; + } + + return ret; +} + +static u_int +ptrace_get_usr_int(void *cookie, vaddr_t offset, u_int *val) +{ + struct lwp * const l = cookie; + + return ptrace_read_int(l, offset, val); +} + +/** + * This function parses current instruction opcode and decodes + * any possible jump (change in PC) which might occur after + * the instruction is executed. + * + * @param l LWP structure of analysed thread + * @param cur_instr Currently executed instruction + * @param alt_next_address Pointer to the variable where + * the destination address of the + * jump instruction shall be stored. + * + * @return <0> when jump is possible + * otherwise + */ +static int +ptrace_get_alternative_next(struct lwp *l, uint32_t cur_instr, + uint32_t *alt_next_address) +{ + int error; + + if (inst_branch(cur_instr) || inst_call(cur_instr) || + inst_return(cur_instr)) { + struct trapframe * const tf = lwp_trapframe(l); + error = arm_predict_branch(l, cur_instr, tf->tf_pc, + alt_next_address, ptrace_get_usr_reg, ptrace_get_usr_int); + + return error; + } + + return EINVAL; +} + +int +process_sstep(struct lwp *l, int sstep) +{ + struct trapframe * const tf = lwp_trapframe(l); + int error, error_alt = 0; + uint32_t cur_instr, alt_next = 0; + + /* TODO: This needs to be updated for Thumb-2 */ + if ((tf->tf_spsr & PSR_T_bit) != 0) + return EINVAL; + + /* We're continuing... */ + if (sstep == 0) { + /* clear ??? */; + return 0; + } + + KASSERTMSG(l->l_md.md_ptrace_instr == 0, + "Didn't clear single step"); + KASSERTMSG(l->l_md.md_ptrace_instr_alt == 0, + "Didn't clear alternative single step"); + + error = ptrace_read_int(l, tf->tf_pc, &cur_instr); + if (error) + goto out; + + error = ptrace_read_int(l, tf->tf_pc + INSN_SIZE, + &l->l_md.md_ptrace_instr); + if (error == 0) { + error = ptrace_write_int(l, tf->tf_pc + INSN_SIZE, + PTRACE_BREAKPOINT_INSN); + if (error) { + l->l_md.md_ptrace_instr = 0; + } else { + l->l_md.md_ptrace_addr = tf->tf_pc + INSN_SIZE; + } + } + + error_alt = ptrace_get_alternative_next(l, cur_instr, &alt_next); + if (error_alt == 0) { + error_alt = ptrace_read_int(l, alt_next, + &l->l_md.md_ptrace_instr_alt); + if (error_alt) { + l->l_md.md_ptrace_instr_alt = 0; + } else { + error_alt = ptrace_write_int(l, alt_next, + PTRACE_BREAKPOINT_INSN); + if (error_alt) + l->l_md.md_ptrace_instr_alt = 0; + else + l->l_md.md_ptrace_addr_alt = alt_next; + } + } +out: + if (error) + return error; + if (error_alt) + return error_alt; + return 0; +} + +int +process_clear_sstep(struct lwp *l) +{ + struct trapframe * const tf = lwp_trapframe(l); + + /* TODO: This needs to be updated for Thumb-2 */ + if ((tf->tf_spsr & PSR_T_bit) != 0) + return EINVAL; + + if (l->l_md.md_ptrace_instr != 0) { + ptrace_write_int(l, l->l_md.md_ptrace_addr, + l->l_md.md_ptrace_instr); + l->l_md.md_ptrace_instr = 0; + } + + if (l->l_md.md_ptrace_instr_alt != 0) { + ptrace_write_int(l, l->l_md.md_ptrace_addr_alt, + l->l_md.md_ptrace_instr_alt); + l->l_md.md_ptrace_instr_alt = 0; + } + + return 0; +} + + + +int +arm_predict_branch(void *cookie, u_int insn, register_t pc, register_t *new_pc, + u_int (*fetch_reg)(void *, int), u_int (*read_int)(void *, vaddr_t, u_int*)) +{ + u_int addr, nregs, offset = 0; + int error = 0; + + switch ((insn >> 24) & 0xf) { + case 0x2: /* add pc, reg1, #value */ + case 0x0: /* add pc, reg1, reg2, lsl #offset */ + + /* Data-processin and miscellaneous A5-196 */ + addr = fetch_reg(cookie, (insn >> 16) & 0xf); + if (((insn >> 16) & 0xf) == 15) + addr += 8; + if (insn & 0x0200000) { + offset = (insn >> 7) & 0x1e; + offset = (insn & 0xff) << (32 - offset) | + (insn & 0xff) >> offset; + } else { + + offset = fetch_reg(cookie, insn & 0x0f); + if ((insn & 0x0000ff0) != 0x00000000) { + if (insn & 0x10) + nregs = fetch_reg(cookie, + (insn >> 8) & 0xf); + else + nregs = (insn >> 7) & 0x1f; + switch ((insn >> 5) & 3) { + case 0: + /* lsl */ + offset = offset << nregs; + break; + case 1: + /* lsr */ + offset = offset >> nregs; + break; + default: + break; /* XXX */ + } + + } + *new_pc = addr + offset; + return 0; + + } + + case 0xa: /* b ... */ + case 0xb: /* bl ... */ + addr = ((insn << 2) & 0x03ffffff); + if (addr & 0x02000000) + addr |= 0xfc000000; + *new_pc = (pc + 8 + addr); + return 0; + case 0x7: /* ldr pc, [pc, reg, lsl #2] */ + + /* Load/store A5-208 */ + /* XXX op1 = 0x11, op (bit 4) = 0 */ + + addr = fetch_reg(cookie, insn & 0xf); + addr = pc + 8 + (addr << 2); + error = read_int(cookie, addr, &addr); + *new_pc = addr; + return error; + case 0x1: /* mov pc, reg */ + /* Data-processing and miscellaneous A5-196 */ + + *new_pc = fetch_reg(cookie, insn & 0xf); + return 0; + case 0x4: + case 0x5: /* ldr pc, [reg] */ + addr = fetch_reg(cookie, (insn >> 16) & 0xf); + /* ldr pc, [reg, #offset] */ + if (insn & (1 << 24)) + offset = insn & 0xfff; + if (insn & 0x00800000) + addr += offset; + else + addr -= offset; + error = read_int(cookie, addr, &addr); + *new_pc = addr; + + return error; + case 0x8: /* ldmxx reg, {..., pc} */ + case 0x9: + addr = fetch_reg(cookie, (insn >> 16) & 0xf); + nregs = (insn & 0x5555) + ((insn >> 1) & 0x5555); + nregs = (nregs & 0x3333) + ((nregs >> 2) & 0x3333); + nregs = (nregs + (nregs >> 4)) & 0x0f0f; + nregs = (nregs + (nregs >> 8)) & 0x001f; + switch ((insn >> 23) & 0x3) { + case 0x0: /* ldmda */ + addr = addr - 0; + break; + case 0x1: /* ldmia */ + addr = addr + 0 + ((nregs - 1) << 2); + break; + case 0x2: /* ldmdb */ + addr = addr - 4; + break; + case 0x3: /* ldmib */ + addr = addr + 4 + ((nregs - 1) << 2); + break; + } + error = read_int(cookie, addr, &addr); + *new_pc = addr; + + return error; + default: + return EINVAL; + } +} + Index: sys/arch/arm/arm/undefined.c =================================================================== RCS file: /cvsroot/src/sys/arch/arm/arm/undefined.c,v retrieving revision 1.58 diff -u -p -r1.58 undefined.c --- sys/arch/arm/arm/undefined.c 27 Feb 2017 06:46:59 -0000 1.58 +++ sys/arch/arm/arm/undefined.c 4 Mar 2017 10:42:21 -0000 @@ -47,8 +47,9 @@ #define FAST_FPE #include "opt_ddb.h" -#include "opt_kgdb.h" #include "opt_dtrace.h" +#include "opt_kgdb.h" +#include "opt_ptrace.h" #include #ifdef KGDB @@ -85,6 +86,10 @@ __KERNEL_RCSID(0, "$NetBSD: undefined.c, #include #endif +#ifdef PTRACE +#include +#endif + #ifdef acorn26 #include #endif @@ -379,7 +384,13 @@ undefinedinstruction(trapframe_t *tf) */ fault_instruction = read_insn(fault_pc, user); } - + if ((fault_instruction & 0x0f000010) == 0x0e000000) { + } else if ((fault_instruction & 0x0e000000) == 0x0c000000) { + } else if ((fault_instruction & 0x0f000010) == 0x0e000010) { + } else { + printf("Undefined instruction %08x @ %" PRIxVADDR " %d.%d\n", fault_instruction, fault_pc, curproc->p_pid, curlwp->l_lid); + disassemble(fault_pc); + } /* Update vmmeter statistics */ curcpu()->ci_data.cpu_ntrap++; @@ -430,6 +441,40 @@ undefinedinstruction(trapframe_t *tf) fault_code) == 0) break; +#ifdef PTRACE + + /* XXX only if uh == NULL??? */ + if (fault_code & FAULT_USER) { + if ((fault_instruction & 0x0f000010) == 0x0e000000) { + } else if ((fault_instruction & 0x0e000000) == 0x0c000000) { + } else if ((fault_instruction & 0x0f000010) == 0x0e000010) { + } else if ((fault_instruction & ~INSN_COND_MASK) + != (KERNEL_BREAKPOINT & ~INSN_COND_MASK)) { + printf("Undefined instruction %08x\n", fault_instruction); + disassemble(fault_pc); + } + /* TODO: No support for ptrace from Thumb-2 */ + if ((tf->tf_spsr & PSR_T_bit) == 0 && + fault_instruction == PTRACE_BREAKPOINT_INSN) { + extern int process_clear_sstep(struct lwp *); + + int error = process_clear_sstep(l); +printf("%s(%p:%d.%d): TRAP\n", __func__, curlwp, curproc->p_pid, curlwp->l_lid); + if (error == 0) { + ksiginfo_t ksi; + + KSI_INIT_TRAP(&ksi); + ksi.ksi_signo = TRAP_BRKPT; + ksi.ksi_code = SIGTRAP; + ksi.ksi_addr = (uint32_t *)fault_pc; + ksi.ksi_trap = fault_instruction; + trapsignal(l, &ksi); + } + return; + } + } +#endif + if (uh == NULL) { /* Fault has not been handled */ ksiginfo_t ksi; Index: sys/arch/arm/arm32/db_interface.c =================================================================== RCS file: /cvsroot/src/sys/arch/arm/arm32/db_interface.c,v retrieving revision 1.54 diff -u -p -r1.54 db_interface.c --- sys/arch/arm/arm32/db_interface.c 29 Oct 2014 14:14:14 -0000 1.54 +++ sys/arch/arm/arm32/db_interface.c 4 Mar 2017 10:42:21 -0000 @@ -51,6 +51,7 @@ __KERNEL_RCSID(0, "$NetBSD: db_interface #include +#include #include #include #include @@ -462,54 +463,38 @@ db_fetch_reg(int reg, db_regs_t *regs) } } +static u_int +db_branch_taken_read_int(void *cookie __unused, vaddr_t va, u_int *val) +{ + u_int ret; + + db_read_bytes(va, sizeof(ret), (char *)&ret); + *val = ret; + + return 0; +} + +static u_int +db_branch_taken_fetch_reg(void *cookie, int reg) +{ + db_regs_t *regs = cookie; + + return db_fetch_reg(reg, regs); +} + u_int branch_taken(u_int insn, u_int pc, db_regs_t *regs) { - u_int addr, nregs; + register_t new_pc; + int ret; - switch ((insn >> 24) & 0xf) { - case 0xa: /* b ... */ - case 0xb: /* bl ... */ - addr = ((insn << 2) & 0x03ffffff); - if (addr & 0x02000000) - addr |= 0xfc000000; - return (pc + 8 + addr); - case 0x7: /* ldr pc, [pc, reg, lsl #2] */ - addr = db_fetch_reg(insn & 0xf, regs); - addr = pc + 8 + (addr << 2); - db_read_bytes(addr, 4, (char *)&addr); - return (addr); - case 0x5: /* ldr pc, [reg] */ - addr = db_fetch_reg((insn >> 16) & 0xf, regs); - db_read_bytes(addr, 4, (char *)&addr); - return (addr); - case 0x1: /* mov pc, reg */ - addr = db_fetch_reg(insn & 0xf, regs); - return (addr); - case 0x8: /* ldmxx reg, {..., pc} */ - case 0x9: - addr = db_fetch_reg((insn >> 16) & 0xf, regs); - nregs = (insn & 0x5555) + ((insn >> 1) & 0x5555); - nregs = (nregs & 0x3333) + ((nregs >> 2) & 0x3333); - nregs = (nregs + (nregs >> 4)) & 0x0f0f; - nregs = (nregs + (nregs >> 8)) & 0x001f; - switch ((insn >> 23) & 0x3) { - case 0x0: /* ldmda */ - addr = addr - 0; - break; - case 0x1: /* ldmia */ - addr = addr + 0 + ((nregs - 1) << 2); - break; - case 0x2: /* ldmdb */ - addr = addr - 4; - break; - case 0x3: /* ldmib */ - addr = addr + 4 + ((nregs - 1) << 2); - break; - } - db_read_bytes(addr, 4, (char *)&addr); - return (addr); - default: - panic("branch_taken: botch"); + ret = arm_predict_branch(regs, insn, pc, &new_pc, + db_branch_taken_fetch_reg, db_branch_taken_read_int); + + if (ret != 0) { + panic("what now"); + //kdb_reenter(); } + + return new_pc; } Index: sys/arch/arm/include/cpu.h =================================================================== RCS file: /cvsroot/src/sys/arch/arm/include/cpu.h,v retrieving revision 1.90 diff -u -p -r1.90 cpu.h --- sys/arch/arm/include/cpu.h 15 Apr 2015 21:26:47 -0000 1.90 +++ sys/arch/arm/include/cpu.h 4 Mar 2017 10:42:21 -0000 @@ -104,7 +104,7 @@ extern int cpu_fpu_present; ((curcpu()->ci_intr_depth > 1) || \ ((cf)->cf_tf.tf_spsr & PSR_MODE) == PSR_UND32_MODE) #else -#define CLKF_INTR(cf) ((void)(cf), curcpu()->ci_intr_depth > 1) +#define CLKF_INTR(cf) ((void)(cf), curcpu()->ci_intr_depth > 1) #endif /* @@ -202,7 +202,7 @@ _curlwp_set(struct lwp *l) armreg_tpidrprw_write((uintptr_t)l); } -// Also in but also here if this was included before +// Also in but also here if this was included before static inline struct cpu_info *lwp_getcpu(struct lwp *); #define curlwp _curlwp() @@ -237,7 +237,7 @@ void cpu_boot_secondary_processors(void) #define CPU_IS_PRIMARY(ci) ((ci)->ci_index == 0) #define CPU_INFO_FOREACH(cii, ci) \ cii = 0, ci = cpu_info[0]; cii < ncpu && (ci = cpu_info[cii]) != NULL; cii++ -#else +#else #define cpu_number() 0 #define CPU_IS_PRIMARY(ci) true @@ -307,11 +307,14 @@ void cpu_proc_fork(struct proc *, struct void cpu_set_curpri(int); /* - * We've already preallocated the stack for the idlelwps for additional CPUs. + * We've already preallocated the stack for the idlelwps for additional CPUs. * This hook allows to return them. */ vaddr_t cpu_uarea_alloc_idlelwp(struct cpu_info *); +int arm_predict_branch(void *, u_int, register_t, register_t *, + u_int (*)(void *, int), u_int (*)(void *, vaddr_t, u_int *)); + #ifndef acorn26 /* * cpu device glue (belongs in cpuvar.h) Index: sys/arch/arm/include/db_machdep.h =================================================================== RCS file: /cvsroot/src/sys/arch/arm/include/db_machdep.h,v retrieving revision 1.24 diff -u -p -r1.24 db_machdep.h --- sys/arch/arm/include/db_machdep.h 20 Feb 2017 17:27:32 -0000 1.24 +++ sys/arch/arm/include/db_machdep.h 4 Mar 2017 10:42:21 -0000 @@ -91,7 +91,8 @@ extern db_regs_t *ddb_regp; /* mov pc, reg 0000000f register */ #define inst_return(ins) (((ins) & 0x0e108000) == 0x08108000 || \ - ((ins) & 0x0ff0fff0) == 0x01a0f000) + ((ins) & 0x0ff0fff0) == 0x01a0f000 || \ + ((ins) & 0x0ffffff0) == 0x012fff10) /* bx */ /* bl ... 00ffffff offset>>2 */ #define inst_call(ins) (((ins) & 0x0f000000) == 0x0b000000) @@ -99,9 +100,13 @@ extern db_regs_t *ddb_regp; 00ffffff offset>>2 */ /* ldr pc, [pc, reg, lsl #2] 0000000f register */ + #define inst_branch(ins) (((ins) & 0x0f000000) == 0x0a000000 || \ ((ins) & 0x0fdffff0) == 0x079ff100 || \ - ((ins) & 0x0ff0f000) == 0x0590f000) + ((ins) & 0x0cd0f000) == 0x0490f000 || \ + ((ins) & 0x0ffffff0) == 0x012fff30 || /* blx */ \ + ((ins) & 0x0de0f000) == 0x0080f000) + #define inst_load(ins) (0) #define inst_store(ins) (0) #define inst_unconditional_flow_transfer(ins) \ Index: sys/arch/arm/include/proc.h =================================================================== RCS file: /cvsroot/src/sys/arch/arm/include/proc.h,v retrieving revision 1.17 diff -u -p -r1.17 proc.h --- sys/arch/arm/include/proc.h 24 Feb 2014 16:57:57 -0000 1.17 +++ sys/arch/arm/include/proc.h 4 Mar 2017 10:42:21 -0000 @@ -44,7 +44,11 @@ struct lwp; struct mdlwp { struct trapframe *md_tf; - int md_flags; + int md_flags; + int md_ptrace_instr; + int md_ptrace_addr; + int md_ptrace_instr_alt; + int md_ptrace_addr_alt; }; /* Flags setttings for md_flags */ Index: sys/arch/arm/include/ptrace.h =================================================================== RCS file: /cvsroot/src/sys/arch/arm/include/ptrace.h,v retrieving revision 1.9 diff -u -p -r1.9 ptrace.h --- sys/arch/arm/include/ptrace.h 25 Nov 2016 02:19:19 -0000 1.9 +++ sys/arch/arm/include/ptrace.h 4 Mar 2017 10:42:21 -0000 @@ -34,9 +34,7 @@ /* * arm-dependent ptrace definitions */ -#ifndef _KERNEL -#define PT_STEP (PT_FIRSTMACH + 0) /* Not implemented */ -#endif +#define PT_STEP (PT_FIRSTMACH + 0) #define PT_GETREGS (PT_FIRSTMACH + 1) #define PT_SETREGS (PT_FIRSTMACH + 2) /* 3 and 4 are for FPE registers */ @@ -58,5 +56,7 @@ #define PTRACE_REG_SP(_r) (_r)->r_sp #define PTRACE_REG_INTRV(_r) (_r)->r[0] -#define PTRACE_BREAKPOINT ((const uint8_t[]) { 0xe7, 0xff, 0xff, 0xff }) +#define PTRACE_BREAKPOINT ((const uint8_t[]) { 0xe7, 0xff, 0xff, 0xfe }) #define PTRACE_BREAKPOINT_SIZE 4 + +#define PTRACE_BREAKPOINT_INSN 0xe7fffffe Index: sys/kern/sys_process.c =================================================================== RCS file: /cvsroot/src/sys/kern/sys_process.c,v retrieving revision 1.175 diff -u -p -r1.175 sys_process.c --- sys/kern/sys_process.c 2 Nov 2016 00:11:59 -0000 1.175 +++ sys/kern/sys_process.c 4 Mar 2017 10:42:21 -0000 @@ -145,6 +145,42 @@ __KERNEL_RCSID(0, "$NetBSD: sys_process. #include #if defined(KTRACE) || defined(PTRACE_HOOKS) + +static int +proc_iop(struct lwp *curl, struct lwp *l, vaddr_t va, void *buf, + size_t len, enum uio_rw rw) +{ + struct uio uio; + struct iovec iov; + + iov.iov_base = buf; + iov.iov_len = len; + uio.uio_iov = &iov; + uio.uio_iovcnt = 1; + uio.uio_offset = va; + uio.uio_resid = len; + uio.uio_rw = rw; + UIO_SETUP_SYSSPACE(&uio); + + return (process_domem(curl, l, &uio)); +} + +int +proc_readmem(struct lwp *curl, struct lwp *l, vaddr_t va, void *buf, + size_t len) +{ + + return (proc_iop(curl, l, va, buf, len, UIO_READ)); +} + +int +proc_writemem(struct lwp *curl, struct lwp *l, vaddr_t va, void *buf, + size_t len) +{ + + return (proc_iop(curl, l, va, buf, len, UIO_WRITE)); +} + int process_domem(struct lwp *curl /*tracer*/, struct lwp *l /*traced*/, Index: sys/sys/ptrace.h =================================================================== RCS file: /cvsroot/src/sys/sys/ptrace.h,v retrieving revision 1.58 diff -u -p -r1.58 ptrace.h --- sys/sys/ptrace.h 23 Feb 2017 03:34:23 -0000 1.58 +++ sys/sys/ptrace.h 4 Mar 2017 10:42:21 -0000 @@ -213,6 +213,8 @@ void process_stoptrace(void); void proc_reparent(struct proc *, struct proc *); void proc_changeparent(struct proc *, struct proc *); +int proc_readmem(struct lwp *, struct lwp *, vaddr_t, void *, size_t); +int proc_writemem(struct lwp *, struct lwp *, vaddr_t, void *, size_t); int do_ptrace(struct ptrace_methods *, struct lwp *, int, pid_t, void *, int, register_t *);