+
+/*
+ * This routine is called by procxmt() to single step one instruction.
+ * We do this by storing a break instruction after the current instruction,
+ * resuming execution, and then restoring the old instruction.
+ */
+cpu_singlestep(p)
+ register struct proc *p;
+{
+ register unsigned va;
+ register int *locr0 = p->p_regs;
+ int i;
+
+ /* compute next address after current location */
+ va = MachEmulateBranch(locr0, locr0[PC], 0, 1);
+ if (p->p_md.md_ss_addr || p->p_md.md_ss_addr == va ||
+ !useracc((caddr_t)va, 4, B_READ)) {
+ printf("SS %s (%d): breakpoint already set at %x (va %x)\n",
+ p->p_comm, p->p_pid, p->p_md.md_ss_addr, va); /* XXX */
+ return (EFAULT);
+ }
+ p->p_md.md_ss_addr = va;
+ p->p_md.md_ss_instr = fuiword(va);
+ i = suiword((caddr_t)va, MACH_BREAK_SSTEP);
+ if (i < 0) {
+ vm_offset_t sa, ea;
+ int rv;
+
+ sa = trunc_page((vm_offset_t)va);
+ ea = round_page((vm_offset_t)va+sizeof(int)-1);
+ rv = vm_map_protect(&p->p_vmspace->vm_map, sa, ea,
+ VM_PROT_DEFAULT, FALSE);
+ if (rv == KERN_SUCCESS) {
+ i = suiword((caddr_t)va, MACH_BREAK_SSTEP);
+ (void) vm_map_protect(&p->p_vmspace->vm_map,
+ sa, ea, VM_PROT_READ|VM_PROT_EXECUTE, FALSE);
+ }
+ }
+ if (i < 0)
+ return (EFAULT);
+ printf("SS %s (%d): breakpoint set at %x: %x (pc %x)\n",
+ p->p_comm, p->p_pid, p->p_md.md_ss_addr,
+ p->p_md.md_ss_instr, locr0[PC]); /* XXX */
+ return (0);
+}