summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordfr <dfr@FreeBSD.org>2001-09-15 11:06:07 +0000
committerdfr <dfr@FreeBSD.org>2001-09-15 11:06:07 +0000
commit01ee11f4089db73bd35056711623d696d285dc94 (patch)
tree436c5cb5980e2a98d7b1f21477fbda20cf5f27ed
parent5330a2f5be549ed9795bcd65dfa6b7a02d8e59ee (diff)
downloadFreeBSD-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.
-rw-r--r--sys/amd64/include/db_machdep.h2
-rw-r--r--sys/ddb/db_break.c51
-rw-r--r--sys/ddb/db_break.h6
-rw-r--r--sys/ddb/db_run.c4
-rw-r--r--sys/i386/include/db_machdep.h2
-rw-r--r--sys/ia64/ia64/db_disasm.c25
-rw-r--r--sys/ia64/ia64/db_interface.c81
-rw-r--r--sys/ia64/ia64/trap.c34
-rw-r--r--sys/ia64/include/db_machdep.h25
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
*/
OpenPOWER on IntegriCloud