From 01ee11f4089db73bd35056711623d696d285dc94 Mon Sep 17 00:00:00 2001 From: dfr Date: Sat, 15 Sep 2001 11:06:07 +0000 Subject: 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. --- sys/amd64/include/db_machdep.h | 2 ++ sys/ddb/db_break.c | 51 ++++++++++++++------------ sys/ddb/db_break.h | 6 +++- sys/ddb/db_run.c | 4 +-- sys/i386/include/db_machdep.h | 2 ++ sys/ia64/ia64/db_disasm.c | 25 ++----------- sys/ia64/ia64/db_interface.c | 81 ++++++++++++++++++++++++++++++++++++++++-- sys/ia64/ia64/trap.c | 34 ++++++++++++++++-- sys/ia64/include/db_machdep.h | 25 +++++++++---- 9 files changed, 171 insertions(+), 59 deletions(-) diff --git a/sys/amd64/include/db_machdep.h b/sys/amd64/include/db_machdep.h index f37d2e8..ba84fc6 100644 --- a/sys/amd64/include/db_machdep.h +++ b/sys/amd64/include/db_machdep.h @@ -48,6 +48,8 @@ extern db_regs_t ddb_regs; /* register state */ #define BKPT_SIZE (1) /* size of breakpoint inst */ #define BKPT_SET(inst) (BKPT_INST) +#define BKPT_SKIP ddb_regs.tf_eip += 1 + #define FIXUP_PC_AFTER_BREAK ddb_regs.tf_eip -= 1; #define db_clear_single_step(regs) ((regs)->tf_eflags &= ~PSL_T) diff --git a/sys/ddb/db_break.c b/sys/ddb/db_break.c index 9ac0001..d62d8c3 100644 --- a/sys/ddb/db_break.c +++ b/sys/ddb/db_break.c @@ -165,6 +165,19 @@ db_find_breakpoint_here(addr) static boolean_t db_breakpoints_inserted = TRUE; +#ifndef BKPT_WRITE +#define BKPT_WRITE(addr, storage) \ +do { \ + *storage = db_get_value(addr, BKPT_SIZE, FALSE); \ + db_put_value(addr, BKPT_SIZE, BKPT_SET(*storage)); \ +} while (0) +#endif + +#ifndef BKPT_CLEAR +#define BKPT_CLEAR(addr, storage) \ + db_put_value(addr, BKPT_SIZE, *storage) +#endif + void db_set_breakpoints() { @@ -172,18 +185,13 @@ db_set_breakpoints() if (!db_breakpoints_inserted) { - for (bkpt = db_breakpoint_list; - bkpt != 0; - bkpt = bkpt->link) - if (db_map_current(bkpt->map)) { - bkpt->bkpt_inst = db_get_value(bkpt->address, - BKPT_SIZE, - FALSE); - db_put_value(bkpt->address, - BKPT_SIZE, - BKPT_SET(bkpt->bkpt_inst)); - } - db_breakpoints_inserted = TRUE; + for (bkpt = db_breakpoint_list; + bkpt != 0; + bkpt = bkpt->link) + if (db_map_current(bkpt->map)) { + BKPT_WRITE(bkpt->address, &bkpt->bkpt_inst); + } + db_breakpoints_inserted = TRUE; } } @@ -194,13 +202,13 @@ db_clear_breakpoints() if (db_breakpoints_inserted) { - for (bkpt = db_breakpoint_list; - bkpt != 0; - bkpt = bkpt->link) - if (db_map_current(bkpt->map)) { - db_put_value(bkpt->address, BKPT_SIZE, bkpt->bkpt_inst); - } - db_breakpoints_inserted = FALSE; + for (bkpt = db_breakpoint_list; + bkpt != 0; + bkpt = bkpt->link) + if (db_map_current(bkpt->map)) { + BKPT_CLEAR(bkpt->address, &bkpt->bkpt_inst); + } + db_breakpoints_inserted = FALSE; } } @@ -228,8 +236,7 @@ db_set_temp_breakpoint(addr) bkpt->init_count = 1; bkpt->count = 1; - bkpt->bkpt_inst = db_get_value(bkpt->address, BKPT_SIZE, FALSE); - db_put_value(bkpt->address, BKPT_SIZE, BKPT_SET(bkpt->bkpt_inst)); + BKPT_WRITE(bkpt->address, &bkpt->bkpt_inst); return bkpt; } @@ -237,7 +244,7 @@ void db_delete_temp_breakpoint(bkpt) db_breakpoint_t bkpt; { - db_put_value(bkpt->address, BKPT_SIZE, bkpt->bkpt_inst); + BKPT_CLEAR(bkpt->address, &bkpt->bkpt_inst); db_breakpoint_free(bkpt); } #endif /* SOFTWARE_SSTEP */ diff --git a/sys/ddb/db_break.h b/sys/ddb/db_break.h index 008acab..88520da 100644 --- a/sys/ddb/db_break.h +++ b/sys/ddb/db_break.h @@ -37,6 +37,10 @@ * Breakpoint. */ +#ifndef BKPT_INST_TYPE +#define BKPT_INST_TYPE int +#endif + struct db_breakpoint { vm_map_t map; /* in this map */ db_addr_t address; /* set here */ @@ -45,7 +49,7 @@ struct db_breakpoint { int flags; /* flags: */ #define BKPT_SINGLE_STEP 0x2 /* to simulate single step */ #define BKPT_TEMP 0x4 /* temporary */ - int bkpt_inst; /* saved instruction at bkpt */ + BKPT_INST_TYPE bkpt_inst; /* saved instruction at bkpt */ struct db_breakpoint *link; /* link in in-use or free chain */ }; typedef struct db_breakpoint *db_breakpoint_t; diff --git a/sys/ddb/db_run.c b/sys/ddb/db_run.c index 2459eed..c17d0a4 100644 --- a/sys/ddb/db_run.c +++ b/sys/ddb/db_run.c @@ -104,8 +104,8 @@ db_stop_at_pc(is_breakpoint) return (TRUE); /* stop here */ } } else if (*is_breakpoint) { -#ifdef __i386__ /* XXx */ - ddb_regs.tf_eip += 1; +#ifdef BKPT_SKIP + BKPT_SKIP; #endif } diff --git a/sys/i386/include/db_machdep.h b/sys/i386/include/db_machdep.h index f37d2e8..ba84fc6 100644 --- a/sys/i386/include/db_machdep.h +++ b/sys/i386/include/db_machdep.h @@ -48,6 +48,8 @@ extern db_regs_t ddb_regs; /* register state */ #define BKPT_SIZE (1) /* size of breakpoint inst */ #define BKPT_SET(inst) (BKPT_INST) +#define BKPT_SKIP ddb_regs.tf_eip += 1 + #define FIXUP_PC_AFTER_BREAK ddb_regs.tf_eip -= 1; #define db_clear_single_step(regs) ((regs)->tf_eflags &= ~PSL_T) 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 */ -- cgit v1.1