diff --git a/sys/ddb/db_break.c b/sys/ddb/db_break.c --- a/sys/ddb/db_break.c +++ b/sys/ddb/db_break.c @@ -35,10 +35,14 @@ */ #include +#include +#include #include #include +#include + #include #include #include @@ -61,6 +65,17 @@ .db_breakpoint_list = NULL, }; +#ifdef HAS_HW_BREAKPOINT +static struct db_breakpoint db_hbreak_table[NHBREAKPOINTS]; + +static struct db_breakpoint_type db_hbreakpoint = { + .db_next_free_breakpoint = &db_hbreak_table[0], + .db_breakpoint_limit = &db_hbreak_table[NHBREAKPOINTS], + .db_free_breakpoints = NULL, + .db_breakpoint_list = NULL, +}; +#endif + static db_breakpoint_t db_breakpoint_alloc( struct db_breakpoint_type *bkpt_type); static void db_breakpoint_free(struct db_breakpoint_type *bkpt_typ, @@ -70,7 +85,7 @@ static db_breakpoint_t db_find_breakpoint(struct db_breakpoint_type *bkpt_type, vm_map_t map, db_addr_t addr); static void db_list_breakpoints(void); -static void db_set_breakpoint(struct db_breakpoint_type *bkpt_type, +static bool db_set_breakpoint(struct db_breakpoint_type *bkpt_type, vm_map_t map, db_addr_t addr, int count); static db_breakpoint_t @@ -100,7 +115,7 @@ bkpt_type->db_free_breakpoints = bkpt; } -static void +static bool db_set_breakpoint(struct db_breakpoint_type *bkpt_type, vm_map_t map, db_addr_t addr, int count) { @@ -108,13 +123,13 @@ if (db_find_breakpoint(bkpt_type, map, addr)) { db_printf("Already set.\n"); - return; + return (false); } bkpt = db_breakpoint_alloc(bkpt_type); if (bkpt == 0) { db_printf("Too many breakpoints.\n"); - return; + return (false); } bkpt->map = map; @@ -125,6 +140,8 @@ bkpt->link = bkpt_type->db_breakpoint_list; bkpt_type->db_breakpoint_list = bkpt; + + return (true); } static void @@ -171,7 +188,16 @@ db_breakpoint_t db_find_breakpoint_here(db_addr_t addr) { - return db_find_breakpoint(&db_breakpoint, db_map_addr(addr), addr); + db_breakpoint_t bkpt; + + bkpt = db_find_breakpoint(&db_breakpoint, db_map_addr(addr), addr); +#ifdef HAS_HW_BREAKPOINT + if (bkpt == NULL) + bkpt = db_find_breakpoint(&db_hbreakpoint, db_map_addr(addr), + addr); +#endif + + return (bkpt); } static bool db_breakpoints_inserted = true; @@ -189,6 +215,9 @@ db_put_value(addr, BKPT_SIZE, *storage) #endif +/* + * Set software breakpoints. + */ void db_set_breakpoints(void) { @@ -205,6 +234,9 @@ } } +/* + * Clean software breakpoints. + */ void db_clear_breakpoints(void) { @@ -222,7 +254,7 @@ } /* - * List breakpoints. + * List software breakpoints. */ static void db_list_breakpoints(void) @@ -246,7 +278,9 @@ } } -/* Delete breakpoint */ +/* + * Delete software breakpoint + */ /*ARGSUSED*/ void db_delete_cmd(db_expr_t addr, bool have_addr, db_expr_t count, char *modif) @@ -255,7 +289,9 @@ (db_addr_t)addr); } -/* Set breakpoint with skip count */ +/* + * Set software breakpoint with skip count + */ /*ARGSUSED*/ void db_breakpoint_cmd(db_expr_t addr, bool have_addr, db_expr_t count, char *modif) @@ -267,11 +303,55 @@ count); } +#ifdef HAS_HW_BREAKPOINT +/* + * Delete hardware breakpoint + */ +void +db_deletehbreak_cmd(db_expr_t addr, bool have_addr, db_expr_t count, + char *modif) +{ + if (count == -1) + count = 1; + + if (kdb_cpu_clr_breakpoint(addr) != 0) { + db_printf("hardware breakpoint could not be delete\n"); + return; + } + + db_delete_breakpoint(&db_hbreakpoint, db_map_addr(addr), + (db_addr_t)addr); +} + +/* + * Set hardware breakpoint + */ +void +db_hbreakpoint_cmd(db_expr_t addr, bool have_addr, db_expr_t count, char *modif) +{ + if (count == -1) + count = 1; + + if (!db_set_breakpoint(&db_hbreakpoint, db_map_addr(addr), + (db_addr_t)addr, count)) + return; + + if (kdb_cpu_set_breakpoint(addr) != 0) { + db_printf("hardware breakpoint could not be set\n"); + db_delete_breakpoint(&db_hbreakpoint, db_map_addr(addr), + (db_addr_t)addr); + } +} +#endif + /* list breakpoints */ void db_listbreak_cmd(db_expr_t dummy1, bool dummy2, db_expr_t dummy3, char *dummy4) { db_list_breakpoints(); +#ifdef HAS_HW_BREAKPOINT + db_md_list_breakpoints(); +#endif } /* diff --git a/sys/ddb/db_command.c b/sys/ddb/db_command.c --- a/sys/ddb/db_command.c +++ b/sys/ddb/db_command.c @@ -126,6 +126,10 @@ DB_CMD("delete", db_delete_cmd, 0), DB_CMD("d", db_delete_cmd, 0), DB_CMD("dump", db_dump, DB_CMD_MEMSAFE), +#ifdef HAS_HW_BREAKPOINT + DB_CMD("dhbreak", db_deletehbreak_cmd, 0), + DB_CMD("hbreak", db_hbreakpoint_cmd, 0), +#endif DB_CMD("break", db_breakpoint_cmd, 0), DB_CMD("b", db_breakpoint_cmd, 0), DB_CMD("dwatch", db_deletewatch_cmd, 0), diff --git a/sys/ddb/ddb.h b/sys/ddb/ddb.h --- a/sys/ddb/ddb.h +++ b/sys/ddb/ddb.h @@ -299,6 +299,13 @@ db_cmdfcn_t db_write_cmd; db_cmdfcn_t db_pprint_cmd; +#ifdef HAS_HW_BREAKPOINT +void db_md_list_breakpoints(void); + +db_cmdfcn_t db_deletehbreak_cmd; +db_cmdfcn_t db_hbreakpoint_cmd; +#endif + /* * Interface between DDB and the DDB output capture facility. */