/* $OpenBSD: db_machdep.c,v 1.2 1998/09/15 10:50:13 pefo Exp $ */ /*- * Copyright (c) 1998 Per Fogelstrom, Opsycon AB * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed under OpenBSD by * Per Fogelstrom, Opsycon AB, Sweden. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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_interface.c,v 1.6.2.1 2007/08/29 12:24:49 girish */ #include __FBSDID("$FreeBSD$"); #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 static db_varfcn_t db_frame; #define DB_OFFSET(x) (db_expr_t *)offsetof(struct trapframe, x) struct db_variable db_regs[] = { { "at", DB_OFFSET(ast), db_frame }, { "v0", DB_OFFSET(v0), db_frame }, { "v1", DB_OFFSET(v1), db_frame }, { "a0", DB_OFFSET(a0), db_frame }, { "a1", DB_OFFSET(a1), db_frame }, { "a2", DB_OFFSET(a2), db_frame }, { "a3", DB_OFFSET(a3), db_frame }, #if defined(__mips_n32) || defined(__mips_n64) { "a4", DB_OFFSET(a4), db_frame }, { "a5", DB_OFFSET(a5), db_frame }, { "a6", DB_OFFSET(a6), db_frame }, { "a7", DB_OFFSET(a7), db_frame }, { "t0", DB_OFFSET(t0), db_frame }, { "t1", DB_OFFSET(t1), db_frame }, { "t2", DB_OFFSET(t2), db_frame }, { "t3", DB_OFFSET(t3), db_frame }, #else { "t0", DB_OFFSET(t0), db_frame }, { "t1", DB_OFFSET(t1), db_frame }, { "t2", DB_OFFSET(t2), db_frame }, { "t3", DB_OFFSET(t3), db_frame }, { "t4", DB_OFFSET(t4), db_frame }, { "t5", DB_OFFSET(t5), db_frame }, { "t6", DB_OFFSET(t6), db_frame }, { "t7", DB_OFFSET(t7), db_frame }, #endif { "s0", DB_OFFSET(s0), db_frame }, { "s1", DB_OFFSET(s1), db_frame }, { "s2", DB_OFFSET(s2), db_frame }, { "s3", DB_OFFSET(s3), db_frame }, { "s4", DB_OFFSET(s4), db_frame }, { "s5", DB_OFFSET(s5), db_frame }, { "s6", DB_OFFSET(s6), db_frame }, { "s7", DB_OFFSET(s7), db_frame }, { "t8", DB_OFFSET(t8), db_frame }, { "t9", DB_OFFSET(t9), db_frame }, { "k0", DB_OFFSET(k0), db_frame }, { "k1", DB_OFFSET(k1), db_frame }, { "gp", DB_OFFSET(gp), db_frame }, { "sp", DB_OFFSET(sp), db_frame }, { "s8", DB_OFFSET(s8), db_frame }, { "ra", DB_OFFSET(ra), db_frame }, { "sr", DB_OFFSET(sr), db_frame }, { "lo", DB_OFFSET(mullo), db_frame }, { "hi", DB_OFFSET(mulhi), db_frame }, { "bad", DB_OFFSET(badvaddr), db_frame }, { "cs", DB_OFFSET(cause), db_frame }, { "pc", DB_OFFSET(pc), db_frame }, }; struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]); int (*do_db_log_stack_trace_cmd)(char *); static int db_frame(struct db_variable *vp, db_expr_t *valuep, int op) { register_t *reg; if (kdb_frame == NULL) return (0); reg = (register_t *)((uintptr_t)kdb_frame + (size_t)(intptr_t)vp->valuep); if (op == DB_VAR_GET) *valuep = *reg; else *reg = *valuep; return (1); } int db_read_bytes(vm_offset_t addr, size_t size, char *data) { jmp_buf jb; void *prev_jb; int ret; prev_jb = kdb_jmpbuf(jb); ret = setjmp(jb); if (ret == 0) { /* * 'addr' could be a memory-mapped I/O address. Try to * do atomic load/store in unit of size requested. */ if ((size == 2 || size == 4 || size == 8) && ((addr & (size -1)) == 0) && (((vm_offset_t)data & (size -1)) == 0)) { switch (size) { case 2: *(uint16_t *)data = *(uint16_t *)addr; break; case 4: *(uint32_t *)data = *(uint32_t *)addr; break; case 8: atomic_load_64((volatile u_int64_t *)addr, (u_int64_t *)data); break; } } else { char *src; src = (char *)addr; while (size-- > 0) *data++ = *src++; } } (void)kdb_jmpbuf(prev_jb); return (ret); } int db_write_bytes(vm_offset_t addr, size_t size, char *data) { int ret; jmp_buf jb; void *prev_jb; prev_jb = kdb_jmpbuf(jb); ret = setjmp(jb); if (ret == 0) { /* * 'addr' could be a memory-mapped I/O address. Try to * do atomic load/store in unit of size requested. */ if ((size == 2 || size == 4 || size == 8) && ((addr & (size -1)) == 0) && (((vm_offset_t)data & (size -1)) == 0)) { switch (size) { case 2: *(uint16_t *)addr = *(uint16_t *)data; break; case 4: *(uint32_t *)addr = *(uint32_t *)data; break; case 8: atomic_store_64((volatile u_int64_t *)addr, (u_int64_t *)data); break; } } else { char *dst; size_t len = size; dst = (char *)addr; while (len-- > 0) *dst++ = *data++; } mips_icache_sync_range((db_addr_t) addr, size); mips_dcache_wbinv_range((db_addr_t) addr, size); } (void)kdb_jmpbuf(prev_jb); return (ret); } /* * To do a single step ddb needs to know the next address * that we will get to. It means that we need to find out * both the address for a branch taken and for not taken, NOT! :-) * MipsEmulateBranch will do the job to find out _exactly_ which * address we will end up at so the 'dual bp' method is not * requiered. */ db_addr_t next_instr_address(db_addr_t pc, boolean_t bd) { db_addr_t next; next = (db_addr_t)MipsEmulateBranch(kdb_frame, pc, 0, 0); return (next); } /* * Decode instruction and figure out type. */ int db_inst_type(int ins) { InstFmt inst; int ityp = 0; inst.word = ins; switch ((int)inst.JType.op) { case OP_SPECIAL: switch ((int)inst.RType.func) { case OP_JR: ityp = IT_BRANCH; break; case OP_JALR: case OP_SYSCALL: ityp = IT_CALL; break; } break; case OP_BCOND: switch ((int)inst.IType.rt) { case OP_BLTZ: case OP_BLTZL: case OP_BGEZ: case OP_BGEZL: ityp = IT_BRANCH; break; case OP_BLTZAL: case OP_BLTZALL: case OP_BGEZAL: case OP_BGEZALL: ityp = IT_CALL; break; } break; case OP_JAL: ityp = IT_CALL; break; case OP_J: case OP_BEQ: case OP_BEQL: case OP_BNE: case OP_BNEL: case OP_BLEZ: case OP_BLEZL: case OP_BGTZ: case OP_BGTZL: ityp = IT_BRANCH; break; case OP_COP1: switch (inst.RType.rs) { case OP_BCx: case OP_BCy: ityp = IT_BRANCH; break; } break; case OP_LB: case OP_LH: case OP_LW: case OP_LD: case OP_LBU: case OP_LHU: case OP_LWU: case OP_LWC1: ityp = IT_LOAD; break; case OP_SB: case OP_SH: case OP_SW: case OP_SD: case OP_SWC1: ityp = IT_STORE; break; } return (ityp); } /* * Return the next pc if the given branch is taken. * MachEmulateBranch() runs analysis for branch delay slot. */ db_addr_t branch_taken(int inst, db_addr_t pc) { db_addr_t ra; register_t fpucsr; /* TBD: when is fsr set */ fpucsr = (curthread) ? curthread->td_pcb->pcb_regs.fsr : 0; ra = (db_addr_t)MipsEmulateBranch(kdb_frame, pc, fpucsr, 0); return (ra); }