diff --git a/src/debugger.c b/src/debugger.c index 0c7e920..8a1cafa 100644 --- a/src/debugger.c +++ b/src/debugger.c @@ -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) { diff --git a/src/debugger.h b/src/debugger.h index 7c42e79..3cb3a00 100644 --- a/src/debugger.h +++ b/src/debugger.h @@ -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 diff --git a/src/debugger_cui.c b/src/debugger_cui.c index 0507045..f79cc78 100644 --- a/src/debugger_cui.c +++ b/src/debugger_cui.c @@ -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 = { diff --git a/src/debugger_dap.c b/src/debugger_dap.c index 101d44b..9170489 100644 --- a/src/debugger_dap.c +++ b/src/debugger_dap.c @@ -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 = { diff --git a/src/debugger_private.h b/src/debugger_private.h index 22569ca..a7fcfd0 100644 --- a/src/debugger_private.h +++ b/src/debugger_private.h @@ -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); diff --git a/src/nact.c b/src/nact.c index 00239b1..6811ef7 100644 --- a/src/nact.c +++ b/src/nact.c @@ -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++;