debugger - add n (next) command

similar to s/step but skips OVER jsr/jsl commands.
implemented via a new temporary breakpoint list.
This commit is contained in:
Kelvin Sherlock 2019-03-12 18:57:59 -04:00
parent dd3a00a734
commit 0e5f941cd5
3 changed files with 216 additions and 18 deletions

View File

@ -30,8 +30,8 @@ word32 g_mp_breakpoints[MAX_BREAK_POINTS];
int g_num_bp_breakpoints = 0;
word32 g_bp_breakpoints[MAX_BREAK_POINTS];
int g_num_tmp_bp_breakpoints = 0;
word32 g_tmp_bp_breakpoints[MAX_BREAK_POINTS];
int g_num_tp_breakpoints = 0;
word32 g_tp_breakpoints[MAX_BREAK_POINTS];
int g_dbg_shell = 0;
int g_stepping = 0;
@ -567,6 +567,159 @@ word32 do_list(word32 address, int lines) {
return address;
}
#if 0
word32 next_pc(void) {
/* return next pc, skipping subroutines,
accounting for inline calls, and branches
*/
word32 pc = engine.kpc;
enum {
C = 1 << 0,
Z = 1 << 1,
I = 1 << 2,
D = 1 << 3,
X = 1 << 4,
M = 1 << 5,
V = 1 << 6,
N = 1 << 7,
E = 1 << 8
};
unsigned opcode = get_memory_c(pc++, 0);
unsigned operand = 0;
unsigned dtype = disasm_types[opcode];
unsigned args = dtype >> 8;
switch (args) {
case 4:
args = engine.psr & M ? 1 : 2;
break;
case 5:
args = engine.psr & X ? 1 : 2;
break;
}
operand = 0;
switch(args) {
case 1:
operand = get_memory_c(pc, 0);
break;
case 2:
operand = get_memory16_c(pc, 0);
break;
case 3:
operand = get_memory24_c(pc, 0);
break;
}
pc += args;
switch (opcode) {
case 0x20:
if ((pc & 0xff0000) == 0 && operand == 0xbf00)
return pc + 3;
break;
case 0x22:
if (operand == 0xe100a8)
return pc + 6;
break;
case 0x82: /* brl */
operand += pc & 0xffff;
return (pc & 0xff0000) | operand;
break;
case 0x80: /* bra */
operand = (pc + (int8_t)operand) & 0xffff;
return (pc & 0xff0000) | operand;
break;
case 0x90: /* bcc */
operand = (pc + (int8_t)operand) & 0xffff;
if (~engine.psr & C)
return (pc & 0xff0000) | operand;
break;
case 0xb0: /* bcc */
operand = (pc + (int8_t)operand) & 0xffff;
if (engine.psr & C)
return (pc & 0xff0000) | operand;
break;
case 0x10: /* bpl */
operand = (pc + (int8_t)operand) & 0xffff;
if (~engine.psr & N)
return (pc & 0xff0000) | operand;
break;
case 0x30: /* bmi */
operand = (pc + (int8_t)operand) & 0xffff;
if (engine.psr & N)
return (pc & 0xff0000) | operand;
break;
case 0x50: /* bvc */
operand = (pc + (int8_t)operand) & 0xffff;
if (~engine.psr & V)
return (pc & 0xff0000) | operand;
break;
case 0x70: /* bvs */
operand = (pc + (int8_t)operand) & 0xffff;
if (engine.psr & V)
return (pc & 0xff0000) | operand;
break;
case 0xd0: /* bvc */
operand = (pc + (int8_t)operand) & 0xffff;
if (~engine.psr & Z)
return (pc & 0xff0000) | operand;
break;
case 0xf0: /* beq */
operand = (pc + (int8_t)operand) & 0xffff;
if (engine.psr & Z)
return (pc & 0xff0000) | operand;
break;
}
return 0;
}
#endif
/*
* todo --
* should use tmp breakpoint instead of g_stepping?
* don't want to step into an interrupt, for example.
* also, step should steps over gs/os, toolbox calls
* (gsbug has protected memory ranges)
*/
int next_pc(void) {
word32 pc = engine.kpc;
unsigned opcode = get_memory_c(pc++, 0);
unsigned operand = 0;
switch (opcode) {
case 0x20: /* jsr abs */
operand = get_memory16_c(pc, 0);
pc += 2;
if ((pc & 0xff0000) == 0 && operand == 0xbf00)
pc += 3;
return pc;
break;
case 0xfc: /* jsr (abs,x) */
return pc + 2;
break;
case 0x22: /* jsl */
operand = get_memory24_c(pc, 0);
pc += 3;
if (operand == 0xe100a8)
pc += 6;
return pc;
break;
}
return -1;
}
enum {
REG_A,
@ -796,6 +949,13 @@ void show_bp(int type) {
breakpoints = g_mp_breakpoints;
num_breakpoints = g_num_mp_breakpoints;
break;
case 'T':
breakpoints = g_tp_breakpoints;
num_breakpoints = g_num_tp_breakpoints;
break;
default:
fputs("Invalid breakpoint type\n", stderr);
return;
@ -808,7 +968,7 @@ void show_bp(int type) {
}
}
void set_bp(int type, word32 addr) {
int set_bp(int type, word32 addr) {
int i;
word32 *breakpoints;
@ -823,32 +983,40 @@ void set_bp(int type, word32 addr) {
breakpoints = g_mp_breakpoints;
num_breakpoints = g_num_mp_breakpoints;
break;
case 'T':
breakpoints = g_tp_breakpoints;
num_breakpoints = g_num_tp_breakpoints;
break;
default:
fputs("Invalid breakpoint type\n", stderr);
return;
return 0;
}
for (i = 0; i < num_breakpoints; ++i) {
if (breakpoints[i] == addr) break;
}
if (i < num_breakpoints) return; /* already set */
if (i < num_breakpoints) return 1; /* already set */
if (num_breakpoints == MAX_BREAK_POINTS) {
printf("Too many breakpoints.\n");
return;
return 0;
}
breakpoints[num_breakpoints++] = addr;
switch(type) {
case 'B': g_num_bp_breakpoints = num_breakpoints; break;
case 'M': g_num_mp_breakpoints = num_breakpoints; break;
case 'T': g_num_tp_breakpoints = num_breakpoints; break;
}
qsort(breakpoints, num_breakpoints, sizeof(word32), addr_cmp);
fixup_brks();
return 1;
}
void delete_bp(int type, word32 addr) {
/* returns 1 if address deleted */
int delete_bp(int type, word32 addr) {
int i;
word32 *breakpoints;
@ -863,26 +1031,33 @@ void delete_bp(int type, word32 addr) {
breakpoints = g_mp_breakpoints;
num_breakpoints = g_num_mp_breakpoints;
break;
case 'T':
breakpoints = g_tp_breakpoints;
num_breakpoints = g_num_tp_breakpoints;
break;
default:
fputs("Invalid breakpoint type\n", stderr);
return;
return 0;
}
for (i = 0; i < num_breakpoints; ++i) {
if (breakpoints[i] == addr) break;
}
if (i == num_breakpoints) return; /* not set */
if (i == num_breakpoints) return 0; /* not set */
breakpoints[i] = 0;
breakpoints[i] = breakpoints[--num_breakpoints];
switch(type) {
case 'B': g_num_bp_breakpoints = num_breakpoints; break;
case 'M': g_num_mp_breakpoints = num_breakpoints; break;
case 'T': g_num_tp_breakpoints = num_breakpoints; break;
}
qsort(breakpoints, num_breakpoints, sizeof(word32), addr_cmp);
fixup_brks();
return 1;
}
@ -1148,6 +1323,23 @@ command:
return 1;
}
"n" eol {
/* next. steps OVER jsr/jsl */
if (has_addr) {
engine.kpc = addr;
}
int tmp = next_pc();
if (tmp < 0) {
g_stepping = 1;
} else {
g_stepping = 0;
set_bp('T', tmp);
}
return 1;
}
";bp" [+-]? eol {
char plus = cp[3];
if (!has_addr && plus == 0) { show_bp('B'); return 0; }
@ -1211,8 +1403,12 @@ int debug_shell(int code) {
/* todo -- only clear IF exit pc == entry pc ? */
if (code == RET_BP) {
engine.flags |= FLAG_IGNORE_BP;
printf("Breakpoint hit:\n");
/* check for temp. breakpoint */
if (!delete_bp('T', engine.kpc)) {
engine.flags |= FLAG_IGNORE_BP;
printf("Breakpoint hit:\n");
}
}
if (code == RET_MP) {
engine.flags |= FLAG_IGNORE_MP;

View File

@ -400,8 +400,8 @@ extern word32 slow_mem_changed[];
extern int g_num_bp_breakpoints;
extern word32 g_bp_breakpoints[];
extern int g_num_tmp_bp_breakpoints;
extern word32 g_tmp_bp_breakpoints[];
extern int g_num_tp_breakpoints;
extern word32 g_tp_breakpoints[];
extern int g_num_mp_breakpoints;
extern word32 g_mp_breakpoints[];
@ -412,13 +412,15 @@ extern word32 g_abort_bytes;
int check_bp_breakpoints(word32 addr) {
int i;
for (i = 0; i < g_num_bp_breakpoints; ++i) {
if (g_bp_breakpoints[i] == addr) {
return 1;
}
}
for (i = 0; i < g_num_tmp_bp_breakpoints; ++i) {
if (g_tmp_bp_breakpoints[i] == addr) {
/* temp breakpoints */
for (i = 0; i < g_num_tp_breakpoints; ++i) {
if (g_tp_breakpoints[i] == addr) {
return 1;
}
}
@ -1043,7 +1045,7 @@ int enter_engine(Engine_reg *engine_ptr) {
word32 saved_psr = 0;
word32 abort_support = g_num_mp_breakpoints ? 1 : 0;
word32 kpc_support = g_num_bp_breakpoints + g_num_tmp_bp_breakpoints ? 1 : 0;
word32 kpc_support = g_num_bp_breakpoints + g_num_tp_breakpoints ? 1 : 0;
flags = engine_ptr->flags;
if (flags & FLAG_IGNORE_MP) abort_support = 0;

View File

@ -172,9 +172,9 @@ void do_debug_intfc(void);
word32 dis_get_memory_ptr(word32 addr);
void show_one_toolset(FILE *toolfile, int toolnum, word32 addr);
void show_toolset_tables(word32 a2bank, word32 addr);
void set_bp(int type, word32 addr);
int set_bp(int type, word32 addr);
void show_bp(int type);
void delete_bp(int type, word32 addr);
int delete_bp(int type, word32 addr);
void do_blank(void);
void do_go(void);
void do_go_debug(void); // socket debug ver