Debugger: Allow setting multiple breakpoints at a single address

This prevents the internal breakpoint from conflicting with regular
breakpoints.
This commit is contained in:
kichikuou
2022-03-19 10:22:55 +09:00
parent f97259bc30
commit f1fb50841c
6 changed files with 62 additions and 47 deletions
+42 -24
View File
@@ -268,10 +268,10 @@ boolean dbg_evaluate(const char *expr, char *result, size_t result_size) {
}
}
Breakpoint *dbg_find_breakpoint(int page, int addr) {
static PhysicalBreakpoint *find_physical_breakpoint(int page, int addr) {
for (Breakpoint *bp = breakpoints; bp; bp = bp->next) {
if (bp->page == page && bp->addr == addr)
return bp;
if (bp->phys->page == page && bp->phys->addr == addr)
return bp->phys;
}
return NULL;
}
@@ -280,17 +280,29 @@ Breakpoint *dbg_set_breakpoint(int page, int addr, boolean is_internal) {
dridata *dfile = ald_getdata(DRIFILE_SCO, page);
if (!dfile)
return NULL;
if (addr < 0 || addr >= dfile->size || dfile->data[addr] == BREAKPOINT) {
if (addr < 0 || addr >= dfile->size) {
ald_freedata(dfile);
return NULL;
}
PhysicalBreakpoint *phys;
if (dfile->data[addr] == BREAKPOINT) {
phys = find_physical_breakpoint(page, addr);
if (!phys)
SYSERROR("Illegal BREAKPOINT instruction");
phys->refcnt++;
} else {
phys = calloc(1, sizeof(PhysicalBreakpoint));
phys->page = page;
phys->addr = addr;
phys->refcnt = 1;
phys->restore_op = dfile->data[addr];
}
Breakpoint *bp = calloc(1, sizeof(Breakpoint));
bp->no = is_internal ? INTERNAL_BREAKPOINT_NO : next_breakpoint_no++;
bp->page = page;
bp->addr = addr;
bp->phys = phys;
bp->dfile = dfile;
bp->restore_op = dfile->data[addr];
bp->next = breakpoints;
breakpoints = bp;
@@ -309,8 +321,12 @@ boolean dbg_set_breakpoint_condition(Breakpoint *bp, const char *condition, char
}
static Breakpoint *breakpoint_free(Breakpoint *bp) {
assert(bp->dfile->data[bp->addr] == BREAKPOINT);
bp->dfile->data[bp->addr] = bp->restore_op;
assert(bp->dfile->data[bp->phys->addr] == BREAKPOINT);
assert(bp->phys->refcnt > 0);
if (--bp->phys->refcnt == 0) {
bp->dfile->data[bp->phys->addr] = bp->phys->restore_op;
free(bp->phys);
}
if (bp->condition)
free(bp->condition);
ald_freedata(bp->dfile);
@@ -332,7 +348,7 @@ boolean dbg_delete_breakpoint(int no) {
void dbg_delete_breakpoints_in_page(int page) {
Breakpoint **p = &breakpoints;
while (*p) {
if ((*p)->page == page)
if ((*p)->phys->page == page)
*p = breakpoint_free(*p);
else
p = &(*p)->next;
@@ -340,19 +356,21 @@ void dbg_delete_breakpoints_in_page(int page) {
}
BYTE dbg_handle_breakpoint(int page, int addr) {
Breakpoint *bp = dbg_find_breakpoint(page, addr);
if (!bp)
SYSERROR("Illegal BREAKPOINT instruction");
for (Breakpoint *bp = breakpoints; bp; bp = bp->next) {
if (bp->phys->page != page || bp->phys->addr != addr)
continue;
if (bp->condition && !eval_condition(bp->condition))
continue;
if (bp->condition && !eval_condition(bp->condition))
return bp->restore_op;
dbg_state = bp->no == INTERNAL_BREAKPOINT_NO ?
DBG_STOPPED_NEXT : DBG_STOPPED_BREAKPOINT;
dbg_state = bp->no == INTERNAL_BREAKPOINT_NO ?
DBG_STOPPED_NEXT : DBG_STOPPED_BREAKPOINT;
BYTE restore_op = bp->restore_op;
dbg_main(); // this may destroy bp
return restore_op;
BYTE restore_op = bp->phys->restore_op;
dbg_main(bp->no); // this may destroy bp
return restore_op;
}
SYSERROR("Illegal BREAKPOINT instruction");
return BREAKPOINT;
}
static void set_stack_frame(StackFrame *frame, int page, int addr, boolean is_return_addr) {
@@ -449,7 +467,7 @@ static int get_retaddr_if_funcall(void) {
sl_jmpNear(nact->current_addr);
int c0 = sl_getc();
if (c0 == BREAKPOINT) {
Breakpoint *bp = dbg_find_breakpoint(nact->current_page, nact->current_addr);
PhysicalBreakpoint *bp = find_physical_breakpoint(nact->current_page, nact->current_addr);
if (bp)
c0 = bp->restore_op;
else
@@ -502,7 +520,7 @@ static boolean should_continue_next(void) {
return true;
}
void dbg_main(void) {
void dbg_main(int bp_no) {
if (internal_breakpoint) {
dbg_delete_breakpoint(INTERNAL_BREAKPOINT_NO);
internal_breakpoint = NULL;
@@ -520,7 +538,7 @@ void dbg_main(void) {
default:
break;
}
dbg_impl->repl();
dbg_impl->repl(bp_no);
}
void dbg_onsleep(void) {
+2 -2
View File
@@ -43,7 +43,7 @@ extern DebuggerState dbg_state;
#define dbg_trapped() (dbg_state != DBG_RUNNING)
void dbg_init(const char *symbols_path, boolean use_dap);
void dbg_quit(bool restart);
void dbg_main(void);
void dbg_main(int bp_no);
void dbg_onsleep(void);
BYTE dbg_handle_breakpoint(int page, int addr);
boolean dbg_console_vprintf(int lv, const char *format, va_list ap);
@@ -53,7 +53,7 @@ boolean dbg_console_vprintf(int lv, const char *format, va_list ap);
#define dbg_trapped() false
#define dbg_init(symbols_path, use_dap)
#define dbg_quit(restart)
#define dbg_main()
#define dbg_main(bp_no)
#define dbg_onsleep()
#define dbg_handle_breakpoint(page, addr) BREAKPOINT
#define dbg_console_vprintf(lv, format, ap) false
+6 -13
View File
@@ -148,11 +148,7 @@ static CommandResult cmd_break(void) {
}
Breakpoint *bp = dbg_set_breakpoint(page, addr, false);
if (!bp) {
Breakpoint *bp = dbg_find_breakpoint(page, addr);
if (bp)
printf("Breakpoint %d is already set at %d:0x%x.\n", bp->no, page, addr);
else
printf("Failed to set breakpoint at %d:0x%x: invalid address\n", page, addr);
printf("Failed to set breakpoint at %d:0x%x: invalid address\n", page, addr);
return CONTINUE_REPL;
}
@@ -170,7 +166,7 @@ static CommandResult cmd_break(void) {
}
}
printf("Breakpoint %d at %s\n", bp->no, format_address(bp->page, bp->addr));
printf("Breakpoint %d at %s\n", bp->no, format_address(bp->phys->page, bp->phys->addr));
return CONTINUE_REPL;
}
@@ -413,12 +409,9 @@ static CommandResult cmd_help(void) {
return CONTINUE_REPL;
}
static void dbg_cui_repl(void) {
if (dbg_state == DBG_STOPPED_BREAKPOINT) {
Breakpoint *bp = dbg_find_breakpoint(nact->current_page, nact->current_addr);
if (bp)
printf("Breakpoint %d\n", bp->no);
}
static void dbg_cui_repl(int bp_no) {
if (dbg_state == DBG_STOPPED_BREAKPOINT && bp_no)
printf("Breakpoint %d\n", bp_no);
if (!print_source_line(nact->current_page, nact->current_addr))
printf("Stopped at %s\n", format_address(nact->current_page, nact->current_addr));
dbg_state = DBG_RUNNING;
@@ -445,7 +438,7 @@ static void dbg_cui_repl(void) {
static void dbg_cui_onsleep(void) {
if (dbg_state == DBG_STOPPED_INTERRUPT)
dbg_main();
dbg_main(0);
}
DebuggerImpl dbg_cui_impl = {
+2 -2
View File
@@ -596,7 +596,7 @@ static void dbg_dap_quit(bool restart) {
exit(0); // The front end will restart xsystem35, so we can just exit.
}
static void dbg_dap_repl(void) {
static void dbg_dap_repl(int bp_no) {
emit_stopped_event();
dbg_state = DBG_RUNNING;
@@ -617,7 +617,7 @@ static void dbg_dap_onsleep(void) {
handle_message(msg);
}
if (dbg_state == DBG_STOPPED_INTERRUPT || dbg_state == DBG_STOPPED_EXCEPTION)
dbg_main();
dbg_main(0);
}
DebuggerImpl dbg_dap_impl = {
+9 -5
View File
@@ -25,12 +25,17 @@
extern struct debug_symbols *symbols;
typedef struct breakpoint {
struct breakpoint *next;
int no;
typedef struct {
int page;
int addr;
int refcnt;
BYTE restore_op;
} PhysicalBreakpoint;
typedef struct breakpoint {
struct breakpoint *next;
PhysicalBreakpoint *phys;
int no;
char *condition;
dridata *dfile; // keeps modified scenario page alive in the cache
} Breakpoint;
@@ -51,7 +56,7 @@ typedef struct {
typedef struct {
void (*init)(const char *symbols_path);
void (*quit)(bool restart);
void (*repl)(void);
void (*repl)(int bp_no);
void (*onsleep)(void);
void (*console_output)(int lv, const char *output);
} DebuggerImpl;
@@ -60,7 +65,6 @@ extern DebuggerImpl dbg_cui_impl;
extern DebuggerImpl dbg_dap_impl;
extern DebuggerImpl *dbg_impl;
Breakpoint *dbg_find_breakpoint(int page, int addr);
Breakpoint *dbg_set_breakpoint(int page, int addr, boolean is_internal);
boolean dbg_delete_breakpoint(int no);
void dbg_delete_breakpoints_in_page(int page);
+1 -1
View File
@@ -118,7 +118,7 @@ void nact_main() {
nact->current_page = sl_getPage();
nact->current_addr = sl_getIndex();
if (dbg_trapped())
dbg_main();
dbg_main(0);
exec_command();
nact->cmd_count++;