Index: head/sys/mips/mips/db_trace.c =================================================================== --- head/sys/mips/mips/db_trace.c (revision 310036) +++ head/sys/mips/mips/db_trace.c (revision 310037) @@ -1,479 +1,475 @@ /*- * Copyright (c) 2004-2005, Juniper Networks, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * JNPR: db_trace.c,v 1.8 2007/08/09 11:23:32 katta */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include extern char _locore[]; extern char _locoreEnd[]; extern char edata[]; /* * A function using a stack frame has the following instruction as the first * one: [d]addiu sp,sp,- * * We make use of this to detect starting address of a function. This works * better than using 'j ra' instruction to signify end of the previous * function (for e.g. functions like boot() or panic() do not actually * emit a 'j ra' instruction). * * XXX the abi does not require that the addiu instruction be the first one. */ #define MIPS_START_OF_FUNCTION(ins) ((((ins) & 0xffff8000) == 0x27bd8000) \ || (((ins) & 0xffff8000) == 0x67bd8000)) /* * MIPS ABI 3.0 requires that all functions return using the 'j ra' instruction * * XXX gcc doesn't do this for functions with __noreturn__ attribute. */ #define MIPS_END_OF_FUNCTION(ins) ((ins) == 0x03e00008) #if defined(__mips_n64) # define MIPS_IS_VALID_KERNELADDR(reg) ((((reg) & 3) == 0) && \ ((vm_offset_t)(reg) >= MIPS_XKPHYS_START)) #else # define MIPS_IS_VALID_KERNELADDR(reg) ((((reg) & 3) == 0) && \ ((vm_offset_t)(reg) >= MIPS_KSEG0_START)) #endif /* * Functions ``special'' enough to print by name */ #ifdef __STDC__ #define Name(_fn) { (void*)_fn, # _fn } #else #define Name(_fn) { _fn, "_fn"} #endif static struct { void *addr; char *name; } names[] = { Name(trap), Name(MipsKernGenException), Name(MipsUserGenException), Name(MipsKernIntr), Name(MipsUserIntr), Name(cpu_switch), { 0, 0 } }; /* * Map a function address to a string name, if known; or a hex string. */ static char * fn_name(uintptr_t addr) { static char buf[17]; int i = 0; db_expr_t diff; c_db_sym_t sym; char *symname; diff = 0; symname = NULL; sym = db_search_symbol((db_addr_t)addr, DB_STGY_ANY, &diff); db_symbol_values(sym, (const char **)&symname, (db_expr_t *)0); if (symname && diff == 0) return (symname); for (i = 0; names[i].name; i++) if (names[i].addr == (void *)addr) return (names[i].name); sprintf(buf, "%jx", (uintmax_t)addr); return (buf); } void stacktrace_subr(register_t pc, register_t sp, register_t ra, int (*printfn) (const char *,...)) { InstFmt i; /* * Arrays for a0..a3 registers and flags if content * of these registers is valid, e.g. obtained from the stack */ int valid_args[4]; register_t args[4]; register_t va, subr; unsigned instr, mask; unsigned int frames = 0; int more, stksize, j; register_t next_ra; /* Jump here when done with a frame, to start a new one */ loop: /* * Invalidate arguments values */ valid_args[0] = 0; valid_args[1] = 0; valid_args[2] = 0; valid_args[3] = 0; next_ra = 0; /* Jump here after a nonstandard (interrupt handler) frame */ stksize = 0; subr = 0; if (frames++ > 100) { (*printfn) ("\nstackframe count exceeded\n"); /* return breaks stackframe-size heuristics with gcc -O2 */ goto finish; /* XXX */ } /* check for bad SP: could foul up next frame */ /*XXX MIPS64 bad: this hard-coded SP is lame */ if (!MIPS_IS_VALID_KERNELADDR(sp)) { (*printfn) ("SP 0x%jx: not in kernel\n", sp); ra = 0; subr = 0; goto done; } #define Between(x, y, z) \ ( ((x) <= (y)) && ((y) < (z)) ) #define pcBetween(a,b) \ Between((uintptr_t)a, pc, (uintptr_t)b) /* * Check for current PC in exception handler code that don't have a * preceding "j ra" at the tail of the preceding function. Depends * on relative ordering of functions in exception.S, swtch.S. */ if (pcBetween(MipsKernGenException, MipsUserGenException)) subr = (uintptr_t)MipsKernGenException; else if (pcBetween(MipsUserGenException, MipsKernIntr)) subr = (uintptr_t)MipsUserGenException; else if (pcBetween(MipsKernIntr, MipsUserIntr)) subr = (uintptr_t)MipsKernIntr; else if (pcBetween(MipsUserIntr, MipsTLBInvalidException)) subr = (uintptr_t)MipsUserIntr; else if (pcBetween(MipsTLBInvalidException, MipsTLBMissException)) subr = (uintptr_t)MipsTLBInvalidException; else if (pcBetween(fork_trampoline, savectx)) subr = (uintptr_t)fork_trampoline; else if (pcBetween(savectx, cpu_throw)) subr = (uintptr_t)savectx; else if (pcBetween(cpu_throw, cpu_switch)) subr = (uintptr_t)cpu_throw; else if (pcBetween(cpu_switch, MipsSwitchFPState)) subr = (uintptr_t)cpu_switch; else if (pcBetween(_locore, _locoreEnd)) { subr = (uintptr_t)_locore; ra = 0; goto done; } /* check for bad PC */ /*XXX MIPS64 bad: These hard coded constants are lame */ if (!MIPS_IS_VALID_KERNELADDR(pc)) { (*printfn) ("PC 0x%jx: not in kernel\n", pc); ra = 0; goto done; } /* * Find the beginning of the current subroutine by scanning * backwards from the current PC for the end of the previous * subroutine. */ if (!subr) { va = pc - sizeof(int); while (1) { instr = kdbpeek((int *)va); if (MIPS_START_OF_FUNCTION(instr)) break; if (MIPS_END_OF_FUNCTION(instr)) { /* skip over branch-delay slot instruction */ va += 2 * sizeof(int); break; } va -= sizeof(int); } /* skip over nulls which might separate .o files */ while ((instr = kdbpeek((int *)va)) == 0) va += sizeof(int); subr = va; } /* scan forwards to find stack size and any saved registers */ stksize = 0; more = 3; mask = 0; for (va = subr; more; va += sizeof(int), more = (more == 3) ? 3 : more - 1) { /* stop if hit our current position */ if (va >= pc) break; instr = kdbpeek((int *)va); i.word = instr; switch (i.JType.op) { case OP_SPECIAL: switch (i.RType.func) { case OP_JR: case OP_JALR: more = 2; /* stop after next instruction */ break; case OP_SYSCALL: case OP_BREAK: more = 1; /* stop now */ } break; case OP_BCOND: case OP_J: case OP_JAL: case OP_BEQ: case OP_BNE: case OP_BLEZ: case OP_BGTZ: more = 2; /* stop after next instruction */ break; case OP_COP0: case OP_COP1: case OP_COP2: case OP_COP3: switch (i.RType.rs) { case OP_BCx: case OP_BCy: more = 2; /* stop after next instruction */ } break; case OP_SW: /* look for saved registers on the stack */ if (i.IType.rs != 29) break; /* * only restore the first one except RA for * MipsKernGenException case */ if (mask & (1 << i.IType.rt)) { if (subr == (uintptr_t)MipsKernGenException && i.IType.rt == 31) next_ra = kdbpeek((int *)(sp + (short)i.IType.imm)); break; } mask |= (1 << i.IType.rt); switch (i.IType.rt) { case 4:/* a0 */ args[0] = kdbpeek((int *)(sp + (short)i.IType.imm)); valid_args[0] = 1; break; case 5:/* a1 */ args[1] = kdbpeek((int *)(sp + (short)i.IType.imm)); valid_args[1] = 1; break; case 6:/* a2 */ args[2] = kdbpeek((int *)(sp + (short)i.IType.imm)); valid_args[2] = 1; break; case 7:/* a3 */ args[3] = kdbpeek((int *)(sp + (short)i.IType.imm)); valid_args[3] = 1; break; case 31: /* ra */ ra = kdbpeek((int *)(sp + (short)i.IType.imm)); } break; case OP_SD: /* look for saved registers on the stack */ if (i.IType.rs != 29) break; /* only restore the first one */ if (mask & (1 << i.IType.rt)) break; mask |= (1 << i.IType.rt); switch (i.IType.rt) { case 4:/* a0 */ args[0] = kdbpeekd((int *)(sp + (short)i.IType.imm)); valid_args[0] = 1; break; case 5:/* a1 */ args[1] = kdbpeekd((int *)(sp + (short)i.IType.imm)); valid_args[1] = 1; break; case 6:/* a2 */ args[2] = kdbpeekd((int *)(sp + (short)i.IType.imm)); valid_args[2] = 1; break; case 7:/* a3 */ args[3] = kdbpeekd((int *)(sp + (short)i.IType.imm)); valid_args[3] = 1; break; case 31: /* ra */ ra = kdbpeekd((int *)(sp + (short)i.IType.imm)); } break; case OP_ADDI: case OP_ADDIU: case OP_DADDI: case OP_DADDIU: /* look for stack pointer adjustment */ if (i.IType.rs != 29 || i.IType.rt != 29) break; stksize = -((short)i.IType.imm); } } done: (*printfn) ("%s+%x (", fn_name(subr), pc - subr); for (j = 0; j < 4; j ++) { if (j > 0) (*printfn)(","); if (valid_args[j]) (*printfn)("%jx", (uintmax_t)(u_register_t)args[j]); else (*printfn)("?"); } (*printfn) (") ra %jx sp %jx sz %d\n", (uintmax_t)(u_register_t) ra, (uintmax_t)(u_register_t) sp, stksize); if (ra) { if (pc == ra && stksize == 0) (*printfn) ("stacktrace: loop!\n"); else { pc = ra; sp += stksize; ra = next_ra; goto loop; } } else { finish: if (curproc) (*printfn) ("pid %d\n", curproc->p_pid); else (*printfn) ("curproc NULL\n"); } } int db_md_set_watchpoint(db_expr_t addr, db_expr_t size) { return(0); } int db_md_clr_watchpoint(db_expr_t addr, db_expr_t size) { return(0); } void db_md_list_watchpoints() { } void db_trace_self(void) { - db_trace_thread (curthread, -1); + register_t pc, ra, sp; + + sp = (register_t)(intptr_t)__builtin_frame_address(0); + ra = (register_t)(intptr_t)__builtin_return_address(0); + + __asm __volatile( + "jal 99f\n" + "nop\n" + "99:\n" + "move %0, $31\n" /* get ra */ + "move $31, %1\n" /* restore ra */ + : "=r" (pc) + : "r" (ra)); + stacktrace_subr(pc, sp, ra, db_printf); return; } int db_trace_thread(struct thread *thr, int count) { register_t pc, ra, sp; struct pcb *ctx; - if (thr == curthread) { - sp = (register_t)(intptr_t)__builtin_frame_address(0); - ra = (register_t)(intptr_t)__builtin_return_address(0); - - __asm __volatile( - "jal 99f\n" - "nop\n" - "99:\n" - "move %0, $31\n" /* get ra */ - "move $31, %1\n" /* restore ra */ - : "=r" (pc) - : "r" (ra)); - - } else { - ctx = kdb_thr_ctx(thr); - sp = (register_t)ctx->pcb_context[PCB_REG_SP]; - pc = (register_t)ctx->pcb_context[PCB_REG_PC]; - ra = (register_t)ctx->pcb_context[PCB_REG_RA]; - } - - stacktrace_subr(pc, sp, ra, - (int (*) (const char *, ...))db_printf); + ctx = kdb_thr_ctx(thr); + sp = (register_t)ctx->pcb_context[PCB_REG_SP]; + pc = (register_t)ctx->pcb_context[PCB_REG_PC]; + ra = (register_t)ctx->pcb_context[PCB_REG_RA]; + stacktrace_subr(pc, sp, ra, db_printf); return (0); } void db_show_mdpcpu(struct pcpu *pc) { db_printf("ipis = 0x%x\n", pc->pc_pending_ipis); db_printf("next ASID = %d\n", pc->pc_next_asid); db_printf("GENID = %d\n", pc->pc_asid_generation); return; } Index: head/sys/mips/mips/pm_machdep.c =================================================================== --- head/sys/mips/mips/pm_machdep.c (revision 310036) +++ head/sys/mips/mips/pm_machdep.c (revision 310037) @@ -1,500 +1,500 @@ /*- * Copyright (c) 1992 Terrence R. Lambert. * Copyright (c) 1982, 1987, 1990 The Regents of the University of California. * All rights reserved. * * This code is derived from software contributed to Berkeley by * William Jolitz. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * from: @(#)machdep.c 7.4 (Berkeley) 6/3/91 * from: src/sys/i386/i386/machdep.c,v 1.385.2.3 2000/05/10 02:04:46 obrien * JNPR: pm_machdep.c,v 1.9.2.1 2007/08/16 15:59:10 girish */ #include __FBSDID("$FreeBSD$"); #include "opt_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define UCONTEXT_MAGIC 0xACEDBADE /* * Send an interrupt to process. * * Stack is set up to allow sigcode stored * at top to call routine, followed by kcall * to sigreturn routine below. After sigreturn * resets the signal mask, the stack, and the * frame pointer, it returns to the user * specified pc, psl. */ void sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) { struct proc *p; struct thread *td; struct trapframe *regs; struct sigacts *psp; struct sigframe sf, *sfp; int sig; int oonstack; td = curthread; p = td->td_proc; PROC_LOCK_ASSERT(p, MA_OWNED); sig = ksi->ksi_signo; psp = p->p_sigacts; mtx_assert(&psp->ps_mtx, MA_OWNED); regs = td->td_frame; oonstack = sigonstack(regs->sp); /* save user context */ bzero(&sf, sizeof(struct sigframe)); sf.sf_uc.uc_sigmask = *mask; sf.sf_uc.uc_stack = td->td_sigstk; sf.sf_uc.uc_mcontext.mc_onstack = (oonstack) ? 1 : 0; sf.sf_uc.uc_mcontext.mc_pc = regs->pc; sf.sf_uc.uc_mcontext.mullo = regs->mullo; sf.sf_uc.uc_mcontext.mulhi = regs->mulhi; sf.sf_uc.uc_mcontext.mc_tls = td->td_md.md_tls; sf.sf_uc.uc_mcontext.mc_regs[0] = UCONTEXT_MAGIC; /* magic number */ bcopy((void *)®s->ast, (void *)&sf.sf_uc.uc_mcontext.mc_regs[1], sizeof(sf.sf_uc.uc_mcontext.mc_regs) - sizeof(register_t)); sf.sf_uc.uc_mcontext.mc_fpused = td->td_md.md_flags & MDTD_FPUSED; if (sf.sf_uc.uc_mcontext.mc_fpused) { /* if FPU has current state, save it first */ if (td == PCPU_GET(fpcurthread)) MipsSaveCurFPState(td); bcopy((void *)&td->td_frame->f0, (void *)sf.sf_uc.uc_mcontext.mc_fpregs, sizeof(sf.sf_uc.uc_mcontext.mc_fpregs)); } /* Allocate and validate space for the signal handler context. */ if ((td->td_pflags & TDP_ALTSTACK) != 0 && !oonstack && SIGISMEMBER(psp->ps_sigonstack, sig)) { sfp = (struct sigframe *)(((uintptr_t)td->td_sigstk.ss_sp + td->td_sigstk.ss_size - sizeof(struct sigframe)) & ~(sizeof(__int64_t) - 1)); } else sfp = (struct sigframe *)((vm_offset_t)(regs->sp - sizeof(struct sigframe)) & ~(sizeof(__int64_t) - 1)); /* Build the argument list for the signal handler. */ regs->a0 = sig; regs->a2 = (register_t)(intptr_t)&sfp->sf_uc; if (SIGISMEMBER(psp->ps_siginfo, sig)) { /* Signal handler installed with SA_SIGINFO. */ regs->a1 = (register_t)(intptr_t)&sfp->sf_si; /* sf.sf_ahu.sf_action = (__siginfohandler_t *)catcher; */ /* fill siginfo structure */ sf.sf_si = ksi->ksi_info; sf.sf_si.si_signo = sig; sf.sf_si.si_code = ksi->ksi_code; sf.sf_si.si_addr = (void*)(intptr_t)regs->badvaddr; } else { /* Old FreeBSD-style arguments. */ regs->a1 = ksi->ksi_code; regs->a3 = regs->badvaddr; /* sf.sf_ahu.sf_handler = catcher; */ } mtx_unlock(&psp->ps_mtx); PROC_UNLOCK(p); /* * Copy the sigframe out to the user's stack. */ if (copyout(&sf, sfp, sizeof(struct sigframe)) != 0) { /* * Something is wrong with the stack pointer. * ...Kill the process. */ PROC_LOCK(p); sigexit(td, SIGILL); } regs->pc = (register_t)(intptr_t)catcher; regs->t9 = (register_t)(intptr_t)catcher; regs->sp = (register_t)(intptr_t)sfp; /* * Signal trampoline code is at base of user stack. */ regs->ra = (register_t)(intptr_t)PS_STRINGS - *(p->p_sysent->sv_szsigcode); PROC_LOCK(p); mtx_lock(&psp->ps_mtx); } /* * System call to cleanup state after a signal * has been taken. Reset signal mask and * stack state from context left by sendsig (above). * Return to previous pc as specified by * context left by sendsig. */ int sys_sigreturn(struct thread *td, struct sigreturn_args *uap) { ucontext_t uc; int error; error = copyin(uap->sigcntxp, &uc, sizeof(uc)); if (error != 0) return (error); error = set_mcontext(td, &uc.uc_mcontext); if (error != 0) return (error); kern_sigprocmask(td, SIG_SETMASK, &uc.uc_sigmask, NULL, 0); return (EJUSTRETURN); } int ptrace_set_pc(struct thread *td, unsigned long addr) { td->td_frame->pc = (register_t) addr; return 0; } static int ptrace_read_int(struct thread *td, off_t addr, int *v) { if (proc_readmem(td, td->td_proc, addr, v, sizeof(*v)) != sizeof(*v)) return (ENOMEM); return (0); } static int ptrace_write_int(struct thread *td, off_t addr, int v) { if (proc_writemem(td, td->td_proc, addr, &v, sizeof(v)) != sizeof(v)) return (ENOMEM); return (0); } int ptrace_single_step(struct thread *td) { unsigned va; struct trapframe *locr0 = td->td_frame; int i; int bpinstr = MIPS_BREAK_SSTEP; int curinstr; struct proc *p; p = td->td_proc; PROC_UNLOCK(p); /* * Fetch what's at the current location. */ ptrace_read_int(td, (off_t)locr0->pc, &curinstr); /* compute next address after current location */ if(curinstr != 0) { 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", p->p_comm, p->p_pid, td->td_md.md_ss_addr, va); /* XXX */ return (EFAULT); } 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); /* * Store breakpoint instruction at the "next" location now. */ i = ptrace_write_int (td, va, bpinstr); /* * The sync'ing of I & D caches is done by procfs_domem() * through procfs_rwmem(). */ 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); } void makectx(struct trapframe *tf, struct pcb *pcb) { - pcb->pcb_regs.ra = tf->ra; - pcb->pcb_regs.pc = tf->pc; - pcb->pcb_regs.sp = tf->sp; + pcb->pcb_context[PCB_REG_RA] = tf->ra; + pcb->pcb_context[PCB_REG_PC] = tf->pc; + pcb->pcb_context[PCB_REG_SP] = tf->sp; } int fill_regs(struct thread *td, struct reg *regs) { memcpy(regs, td->td_frame, sizeof(struct reg)); return (0); } int set_regs(struct thread *td, struct reg *regs) { struct trapframe *f; register_t sr; f = (struct trapframe *) td->td_frame; /* * Don't allow the user to change SR */ sr = f->sr; memcpy(td->td_frame, regs, sizeof(struct reg)); f->sr = sr; return (0); } int get_mcontext(struct thread *td, mcontext_t *mcp, int flags) { struct trapframe *tp; tp = td->td_frame; PROC_LOCK(curthread->td_proc); mcp->mc_onstack = sigonstack(tp->sp); PROC_UNLOCK(curthread->td_proc); bcopy((void *)&td->td_frame->zero, (void *)&mcp->mc_regs, sizeof(mcp->mc_regs)); mcp->mc_fpused = td->td_md.md_flags & MDTD_FPUSED; if (mcp->mc_fpused) { bcopy((void *)&td->td_frame->f0, (void *)&mcp->mc_fpregs, sizeof(mcp->mc_fpregs)); } if (flags & GET_MC_CLEAR_RET) { mcp->mc_regs[V0] = 0; mcp->mc_regs[V1] = 0; mcp->mc_regs[A3] = 0; } mcp->mc_pc = td->td_frame->pc; mcp->mullo = td->td_frame->mullo; mcp->mulhi = td->td_frame->mulhi; mcp->mc_tls = td->td_md.md_tls; return (0); } int set_mcontext(struct thread *td, mcontext_t *mcp) { struct trapframe *tp; tp = td->td_frame; bcopy((void *)&mcp->mc_regs, (void *)&td->td_frame->zero, sizeof(mcp->mc_regs)); td->td_md.md_flags = mcp->mc_fpused & MDTD_FPUSED; if (mcp->mc_fpused) { bcopy((void *)&mcp->mc_fpregs, (void *)&td->td_frame->f0, sizeof(mcp->mc_fpregs)); } td->td_frame->pc = mcp->mc_pc; td->td_frame->mullo = mcp->mullo; td->td_frame->mulhi = mcp->mulhi; td->td_md.md_tls = mcp->mc_tls; /* Dont let user to set any bits in status and cause registers. */ return (0); } int fill_fpregs(struct thread *td, struct fpreg *fpregs) { if (td == PCPU_GET(fpcurthread)) MipsSaveCurFPState(td); memcpy(fpregs, &td->td_frame->f0, sizeof(struct fpreg)); return 0; } int set_fpregs(struct thread *td, struct fpreg *fpregs) { if (PCPU_GET(fpcurthread) == td) PCPU_SET(fpcurthread, (struct thread *)0); memcpy(&td->td_frame->f0, fpregs, sizeof(struct fpreg)); return 0; } /* * Clear registers on exec * $sp is set to the stack pointer passed in. $pc is set to the entry * point given by the exec_package passed in, as is $t9 (used for PIC * code by the MIPS elf abi). */ void exec_setregs(struct thread *td, struct image_params *imgp, u_long stack) { bzero((caddr_t)td->td_frame, sizeof(struct trapframe)); /* * The stack pointer has to be aligned to accommodate the largest * datatype at minimum. This probably means it should be 16-byte * aligned, but for now we're 8-byte aligning it. */ td->td_frame->sp = ((register_t) stack) & ~(sizeof(__int64_t) - 1); /* * If we're running o32 or n32 programs but have 64-bit registers, * GCC may use stack-relative addressing near the top of user * address space that, due to sign extension, will yield an * invalid address. For instance, if sp is 0x7fffff00 then GCC * might do something like this to load a word from 0x7ffffff0: * * addu sp, sp, 32768 * lw t0, -32528(sp) * * On systems with 64-bit registers, sp is sign-extended to * 0xffffffff80007f00 and the load is instead done from * 0xffffffff7ffffff0. * * To prevent this, we subtract 64K from the stack pointer here. * * For consistency, we should just always do this unless we're * running n64 programs. For now, since we don't support * COMPAT_FREEBSD32 on n64 kernels, we just do it unless we're * running n64 kernels. */ #if !defined(__mips_n64) td->td_frame->sp -= 65536; #endif td->td_frame->pc = imgp->entry_addr & ~3; td->td_frame->t9 = imgp->entry_addr & ~3; /* abicall req */ td->td_frame->sr = MIPS_SR_KSU_USER | MIPS_SR_EXL | MIPS_SR_INT_IE | (mips_rd_status() & MIPS_SR_INT_MASK); #if defined(__mips_n32) td->td_frame->sr |= MIPS_SR_PX; #elif defined(__mips_n64) td->td_frame->sr |= MIPS_SR_PX | MIPS_SR_UX | MIPS_SR_KX; #endif /* * FREEBSD_DEVELOPERS_FIXME: * Setup any other CPU-Specific registers (Not MIPS Standard) * and/or bits in other standard MIPS registers (if CPU-Specific) * that are needed. */ /* * Set up arguments for the rtld-capable crt0: * a0 stack pointer * a1 rtld cleanup (filled in by dynamic loader) * a2 rtld object (filled in by dynamic loader) * a3 ps_strings */ td->td_frame->a0 = (register_t) stack; td->td_frame->a1 = 0; td->td_frame->a2 = 0; td->td_frame->a3 = (register_t)imgp->ps_strings; td->td_md.md_flags &= ~MDTD_FPUSED; if (PCPU_GET(fpcurthread) == td) PCPU_SET(fpcurthread, (struct thread *)0); td->td_md.md_ss_addr = 0; td->td_md.md_tls_tcb_offset = TLS_TP_OFFSET + TLS_TCB_SIZE; } int ptrace_clear_single_step(struct thread *td) { int i; struct proc *p; p = td->td_proc; PROC_LOCK_ASSERT(p, MA_OWNED); if (!td->td_md.md_ss_addr) return EINVAL; /* * Restore original instruction and clear BP */ i = ptrace_write_int (td, td->td_md.md_ss_addr, td->td_md.md_ss_instr); /* The sync'ing of I & D caches is done by procfs_domem(). */ if (i < 0) { log(LOG_ERR, "SS %s %d: can't restore instruction at %x: %x\n", p->p_comm, p->p_pid, td->td_md.md_ss_addr, td->td_md.md_ss_instr); } td->td_md.md_ss_addr = 0; return 0; }