mirror of
https://github.com/kichikuou/xsystem35-sdl2.git
synced 2026-10-05 13:18:08 +03:00
Debugger: Allow setting multiple breakpoints at a single address
This prevents the internal breakpoint from conflicting with regular breakpoints.
This commit is contained in:
+42
-24
@@ -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
@@ -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
@@ -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
@@ -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 = {
|
||||
|
||||
@@ -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
@@ -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++;
|
||||
|
||||
Reference in New Issue
Block a user