diff options
author | dfr <dfr@FreeBSD.org> | 2001-09-15 11:06:07 +0000 |
---|---|---|
committer | dfr <dfr@FreeBSD.org> | 2001-09-15 11:06:07 +0000 |
commit | 01ee11f4089db73bd35056711623d696d285dc94 (patch) | |
tree | 436c5cb5980e2a98d7b1f21477fbda20cf5f27ed /sys/ia64 | |
parent | 5330a2f5be549ed9795bcd65dfa6b7a02d8e59ee (diff) | |
download | FreeBSD-src-01ee11f4089db73bd35056711623d696d285dc94.zip FreeBSD-src-01ee11f4089db73bd35056711623d696d285dc94.tar.gz |
Fill out some gaps in ia64 DDB support. This involves generalising DDB's
breakpoint handling slightly to cope with the fact that ia64 instructions
are not located on byte boundaries.
Diffstat (limited to 'sys/ia64')
-rw-r--r-- | sys/ia64/ia64/db_disasm.c | 25 | ||||
-rw-r--r-- | sys/ia64/ia64/db_interface.c | 81 | ||||
-rw-r--r-- | sys/ia64/ia64/trap.c | 34 | ||||
-rw-r--r-- | sys/ia64/include/db_machdep.h | 25 |
4 files changed, 131 insertions, 34 deletions
diff --git a/sys/ia64/ia64/db_disasm.c b/sys/ia64/ia64/db_disasm.c index 174c0ae..42bae22 100644 --- a/sys/ia64/ia64/db_disasm.c +++ b/sys/ia64/ia64/db_disasm.c @@ -39,11 +39,6 @@ #define sign_extend(imm, w) (((int64_t)(imm) << (64 - (w))) >> (64 - (w))) -struct ia64_bundle { - u_int64_t slot[3]; - int template; -}; - typedef void (*ia64_print_slot)(db_addr_t loc, u_int64_t slot, boolean_t showregs); static void ia64_print_M(db_addr_t, u_int64_t, boolean_t); @@ -253,20 +248,6 @@ const char *control_names[] = { }; static void -ia64_fetch_bundle(db_addr_t loc, struct ia64_bundle *bp) -{ - u_int64_t low, high; - - db_read_bytes(loc, 8, (caddr_t) &low); - db_read_bytes(loc+8, 8, (caddr_t) &high); - - bp->template = low & 0x1f; - bp->slot[0] = (low >> 5) & ((1L<<41) - 1); - bp->slot[1] = (low >> 46) | ((high & ((1L<<23) - 1)) << 18); - bp->slot[2] = (high >> 23); -} - -static void ia64_print_ill(const char *name, u_int64_t ins, db_addr_t loc) { db_printf("%s %lx", name, ins); @@ -1640,7 +1621,7 @@ ia64_print_X1(const char *name, u_int64_t ins, db_addr_t loc) struct ia64_bundle b; union ia64_instruction u; u.ins = ins; - ia64_fetch_bundle(loc, &b); + db_read_bundle(loc, &b); db_printf("%s %lx", name, (b.slot[1] << 21) | (u.X1.i << 20) | u.X1.imm20a); @@ -1652,7 +1633,7 @@ ia64_print_X2(const char *name, u_int64_t ins, db_addr_t loc) struct ia64_bundle b; union ia64_instruction u; u.ins = ins; - ia64_fetch_bundle(loc, &b); + db_read_bundle(loc, &b); db_printf("%s %s=%lx", name, register_names[u.X2.r1], @@ -2848,7 +2829,7 @@ db_disasm(db_addr_t loc, boolean_t altfmt) */ slot = loc & 15; loc &= ~15; - ia64_fetch_bundle(loc, &b); + db_read_bundle(loc, &b); if (b.slot[slot] & 63) db_printf("(p%ld) ", b.slot[slot] & 63); diff --git a/sys/ia64/ia64/db_interface.c b/sys/ia64/ia64/db_interface.c index ead35f8..10d8ea5 100644 --- a/sys/ia64/ia64/db_interface.c +++ b/sys/ia64/ia64/db_interface.c @@ -75,11 +75,13 @@ extern int trap_types; int db_active; static u_int64_t zero; static int db_get_rse_reg(struct db_variable *vp, db_expr_t *valuep, int op); +static int db_get_pc_reg(struct db_variable *vp, db_expr_t *valuep, int op); struct db_variable db_regs[] = { /* Misc control/app registers */ -#define DB_MISC_REGS 14 /* make sure this is correct */ +#define DB_MISC_REGS 15 /* make sure this is correct */ + {"pc", (db_expr_t*) 0, db_get_pc_reg}, {"ip", (db_expr_t*) &ddb_regs.tf_cr_iip, FCN_NULL}, {"psr", (db_expr_t*) &ddb_regs.tf_cr_ipsr, FCN_NULL}, {"cr.isr", (db_expr_t*) &ddb_regs.tf_cr_isr, FCN_NULL}, @@ -295,6 +297,14 @@ db_get_rse_reg(struct db_variable *vp, db_expr_t *valuep, int op) return 0; } +static int +db_get_pc_reg(struct db_variable *vp, db_expr_t *valuep, int op) +{ + /* Read only */ + if (op == DB_VAR_GET) + *valuep = PC_REGS(DDB_REGS); +} + /* * Print trap reason. */ @@ -323,7 +333,8 @@ kdb_trap(int vector, struct trapframe *regs) * conditions exist, something Bad has happened. */ - if (vector != IA64_VEC_BREAK) { + if (vector != IA64_VEC_BREAK + && vector != IA64_VEC_SINGLE_STEP_TRAP) { #if 0 if (ddb_mode) { db_printf("ddbprinttrap from 0x%lx\n", /* XXX */ @@ -466,3 +477,69 @@ db_register_value(regs, regno) } } } + +void +db_read_bundle(db_addr_t addr, struct ia64_bundle *bp) +{ + u_int64_t low, high; + + db_read_bytes(addr, 8, (caddr_t) &low); + db_read_bytes(addr+8, 8, (caddr_t) &high); + + bp->template = low & 0x1f; + bp->slot[0] = (low >> 5) & ((1L<<41) - 1); + bp->slot[1] = (low >> 46) | ((high & ((1L<<23) - 1)) << 18); + bp->slot[2] = (high >> 23); +} + +void +db_write_bundle(db_addr_t addr, struct ia64_bundle *bp) +{ + u_int64_t low, high; + + low = bp->template | (bp->slot[0] << 5) | (bp->slot[1] << 46); + high = (bp->slot[1] >> 18) | (bp->slot[2] << 23); + + db_write_bytes(addr, 8, (caddr_t) &low); + db_write_bytes(addr+8, 8, (caddr_t) &high); +} + +void +db_write_breakpoint(vm_offset_t addr, u_int64_t *storage) +{ + struct ia64_bundle b; + int slot; + + slot = addr & 15; + addr &= ~15; + db_read_bundle(addr, &b); + *storage = b.slot[slot]; + b.slot[slot] = 0x80100 << 6; /* break.* 0x80100 */ + db_write_bundle(addr, &b); +} + +void +db_clear_breakpoint(vm_offset_t addr, u_int64_t *storage) +{ + struct ia64_bundle b; + int slot; + + slot = addr & 15; + addr &= ~15; + db_read_bundle(addr, &b); + b.slot[slot] = *storage; + db_write_bundle(addr, &b); +} + +void +db_skip_breakpoint(void) +{ + /* + * Skip past the break instruction. + */ + ddb_regs.tf_cr_ipsr += IA64_PSR_RI_1; + if ((ddb_regs.tf_cr_ipsr & IA64_PSR_RI) > IA64_PSR_RI_2) { + ddb_regs.tf_cr_ipsr &= ~IA64_PSR_RI; + ddb_regs.tf_cr_iip += 16; + } +} diff --git a/sys/ia64/ia64/trap.c b/sys/ia64/ia64/trap.c index c21cdf4..6018124 100644 --- a/sys/ia64/ia64/trap.c +++ b/sys/ia64/ia64/trap.c @@ -243,9 +243,6 @@ trap(int vector, int imm, struct trapframe *framep) /* Always fatal in kernel. Should never happen. */ goto dopanic; - case IA64_VEC_BREAK: - goto dopanic; - case IA64_VEC_DISABLED_FP: /* * on exit from the kernel, if thread == fpcurthread, @@ -394,6 +391,37 @@ trap(int vector, int imm, struct trapframe *framep) printtrap(vector, imm, framep, 1, user); #endif break; + + case IA64_VEC_SINGLE_STEP_TRAP: + /* + * Clear single-step bit. + */ + framep->tf_cr_ipsr &= IA64_PSR_SS; + /* FALLTHROUTH */ + + case IA64_VEC_DEBUG: + case IA64_VEC_TAKEN_BRANCH_TRAP: + case IA64_VEC_BREAK: + /* + * These are always fatal in kernel, and should never happen. + */ + if (!user) { +#ifdef DDB + /* + * ...unless, of course, DDB is configured. + */ + if (kdb_trap(vector, framep)) + return; + + /* + * If we get here, DDB did _not_ handle the + * trap, and we need to PANIC! + */ +#endif + goto dopanic; + } + i = SIGTRAP; + break; } default: diff --git a/sys/ia64/include/db_machdep.h b/sys/ia64/include/db_machdep.h index 3ac65d7..c419092 100644 --- a/sys/ia64/include/db_machdep.h +++ b/sys/ia64/include/db_machdep.h @@ -41,6 +41,11 @@ #define DB_NO_AOUT +struct ia64_bundle { + u_int64_t slot[3]; + int template; +}; + typedef vm_offset_t db_addr_t; /* address - unsigned */ typedef long db_expr_t; /* expression - signed */ typedef struct trapframe db_regs_t; @@ -50,16 +55,16 @@ db_regs_t ddb_regs; /* register state */ #define PC_REGS(regs) ((db_addr_t)(regs)->tf_cr_iip \ + (((regs)->tf_cr_ipsr >> 41) & 3)) -#define BKPT_INST 0x00000080 /* breakpoint instruction */ -#define BKPT_SIZE (4) /* size of breakpoint inst */ -#define BKPT_SET(inst) (BKPT_INST) +#define BKPT_WRITE(addr, storage) db_write_breakpoint(addr, storage) +#define BKPT_CLEAR(addr, storage) db_clear_breakpoint(addr, storage) +#define BKPT_INST_TYPE u_int64_t -#define FIXUP_PC_AFTER_BREAK +#define BKPT_SKIP db_skip_breakpoint() -#define db_clear_single_step(regs) 0 -#define db_set_single_step(regs) 0 +#define db_clear_single_step(regs) ddb_regs.tf_cr_ipsr &= ~IA64_PSR_SS +#define db_set_single_step(regs) ddb_regs.tf_cr_ipsr |= IA64_PSR_SS -#define IS_BREAKPOINT_TRAP(type, code) 0 +#define IS_BREAKPOINT_TRAP(type, code) (type == IA64_VEC_BREAK) #define IS_WATCHPOINT_TRAP(type, code) 0 #define inst_trap_return(ins) 0 @@ -86,6 +91,12 @@ u_int64_t *db_rse_current_frame(void); u_int64_t *db_rse_previous_frame(u_int64_t *bsp, int sof); u_int64_t *db_rse_register_address(u_int64_t *bsp, int regno); +void db_read_bundle(db_addr_t addr, struct ia64_bundle *bp); +void db_write_bundle(db_addr_t addr, struct ia64_bundle *bp); +void db_write_breakpoint(db_addr_t addr, u_int64_t *storage); +void db_clear_breakpoint(db_addr_t addr, u_int64_t *storage); +void db_skip_breakpoint(void); + /* * Pretty arbitrary */ |