[qwaq] Implement execute-to-cursor

Support for finding the first address associated with a source line was
added to the engine, returning 0 if not found.

A temporary breakpoint is set and the progs allowed to run free.
However, better handling of temporary breakpoitns is needed as currently
a "permanent" breakpoint will be cleared without clearing the temporary
breakpoing if the permanent breakpoing is hit while execut-to-cursor is
running.
This commit is contained in:
Bill Currie 2021-06-08 16:54:04 +09:00
parent c818a2abf9
commit d23c9582f1
8 changed files with 152 additions and 7 deletions

View file

@ -1742,6 +1742,7 @@ pr_auxfunction_t *PR_Get_Lineno_Func (progs_t *pr, pr_lineno_t *lineno) __attrib
pr_uint_t PR_Get_Lineno_Addr (progs_t *pr, pr_lineno_t *lineno) __attribute__((pure)); pr_uint_t PR_Get_Lineno_Addr (progs_t *pr, pr_lineno_t *lineno) __attribute__((pure));
pr_uint_t PR_Get_Lineno_Line (progs_t *pr, pr_lineno_t *lineno) __attribute__((pure)); pr_uint_t PR_Get_Lineno_Line (progs_t *pr, pr_lineno_t *lineno) __attribute__((pure));
pr_lineno_t *PR_Find_Lineno (progs_t *pr, pr_uint_t addr) __attribute__((pure)); pr_lineno_t *PR_Find_Lineno (progs_t *pr, pr_uint_t addr) __attribute__((pure));
pr_uint_t PR_FindSourceLineAddr (progs_t *pr, const char *file, pr_uint_t line) __attribute__((pure));
const char *PR_Get_Source_File (progs_t *pr, pr_lineno_t *lineno) __attribute__((pure)); const char *PR_Get_Source_File (progs_t *pr, pr_lineno_t *lineno) __attribute__((pure));
const char *PR_Get_Source_Line (progs_t *pr, pr_uint_t addr); const char *PR_Get_Source_Line (progs_t *pr, pr_uint_t addr);
pr_def_t *PR_Get_Param_Def (progs_t *pr, dfunction_t *func, unsigned parm) __attribute__((pure)); pr_def_t *PR_Get_Param_Def (progs_t *pr, dfunction_t *func, unsigned parm) __attribute__((pure));

View file

@ -31,6 +31,8 @@
# include "config.h" # include "config.h"
#endif #endif
#define _GNU_SOURCE // for qsort_r
#ifdef HAVE_STRING_H #ifdef HAVE_STRING_H
# include <string.h> # include <string.h>
#endif #endif
@ -41,6 +43,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <stdlib.h> #include <stdlib.h>
#include "QF/fbsearch.h"
#include "QF/cvar.h" #include "QF/cvar.h"
#include "QF/dstring.h" #include "QF/dstring.h"
#include "QF/hash.h" #include "QF/hash.h"
@ -75,6 +78,11 @@ typedef struct compunit_s {
pr_compunit_t *unit; pr_compunit_t *unit;
} compunit_t; } compunit_t;
typedef struct {
const char *file;
pr_uint_t line;
} func_key_t;
typedef struct prdeb_resources_s { typedef struct prdeb_resources_s {
progs_t *pr; progs_t *pr;
dstring_t *string; dstring_t *string;
@ -85,6 +93,7 @@ typedef struct prdeb_resources_s {
pr_debug_header_t *debug; pr_debug_header_t *debug;
pr_auxfunction_t *auxfunctions; pr_auxfunction_t *auxfunctions;
pr_auxfunction_t **auxfunction_map; pr_auxfunction_t **auxfunction_map;
func_t *sorted_functions;
pr_lineno_t *linenos; pr_lineno_t *linenos;
pr_def_t *local_defs; pr_def_t *local_defs;
pr_def_t *type_encodings_def; pr_def_t *type_encodings_def;
@ -379,6 +388,9 @@ pr_debug_clear (progs_t *pr, void *data)
if (res->auxfunction_map) if (res->auxfunction_map)
pr->free_progs_mem (pr, res->auxfunction_map); pr->free_progs_mem (pr, res->auxfunction_map);
res->auxfunction_map = 0; res->auxfunction_map = 0;
if (res->sorted_functions)
pr->free_progs_mem (pr, res->sorted_functions);
res->sorted_functions = 0;
res->linenos = 0; res->linenos = 0;
res->local_defs = 0; res->local_defs = 0;
@ -478,6 +490,43 @@ process_compunit (prdeb_resources_t *res, pr_def_t *def)
} }
} }
static int
func_compare_sort (const void *_fa, const void *_fb, void *_res)
{
prdeb_resources_t *res = _res;
progs_t *pr = res->pr;
func_t fa = *(const func_t *)_fa;
func_t fb = *(const func_t *)_fb;
const char *fa_file = PR_GetString (pr, pr->pr_functions[fa].s_file);
const char *fb_file = PR_GetString (pr, pr->pr_functions[fb].s_file);
int cmp = strcmp (fa_file, fb_file);
if (cmp) {
return cmp;
}
pr_auxfunction_t *fa_aux = res->auxfunction_map[fa];
pr_auxfunction_t *fb_aux = res->auxfunction_map[fb];
pr_uint_t fa_line = fa_aux ? fa_aux->source_line : 0;
pr_uint_t fb_line = fb_aux ? fb_aux->source_line : 0;
return fa_line - fb_line;
}
static int
func_compare_search (const void *_key, const void *_f, void *_res)
{
prdeb_resources_t *res = _res;
progs_t *pr = res->pr;
const func_key_t *key = _key;
func_t f = *(const func_t *)_f;
const char *f_file = PR_GetString (pr, pr->pr_functions[f].s_file);
int cmp = strcmp (key->file, f_file);
if (cmp) {
return cmp;
}
pr_auxfunction_t *f_aux = res->auxfunction_map[f];
pr_uint_t f_line = f_aux ? f_aux->source_line : 0;
return key->line - f_line;
}
VISIBLE int VISIBLE int
PR_LoadDebug (progs_t *pr) PR_LoadDebug (progs_t *pr)
{ {
@ -562,8 +611,12 @@ PR_LoadDebug (progs_t *pr)
i = pr->progs->numfunctions * sizeof (pr_auxfunction_t *); i = pr->progs->numfunctions * sizeof (pr_auxfunction_t *);
res->auxfunction_map = pr->allocate_progs_mem (pr, i); res->auxfunction_map = pr->allocate_progs_mem (pr, i);
for (i = 0; i < pr->progs->numfunctions; i++) i = pr->progs->numfunctions * sizeof (func_t);
res->sorted_functions = pr->allocate_progs_mem (pr, i);
for (i = 0; i < pr->progs->numfunctions; i++) {
res->auxfunction_map[i] = 0; res->auxfunction_map[i] = 0;
res->sorted_functions[i] = i;
}
res->type_encodings_def = PR_FindGlobal (pr, ".type_encodings"); res->type_encodings_def = PR_FindGlobal (pr, ".type_encodings");
if (res->type_encodings_def) { if (res->type_encodings_def) {
@ -593,6 +646,8 @@ PR_LoadDebug (progs_t *pr)
res->linenos[i].fa.func = LittleLong (res->linenos[i].fa.func); res->linenos[i].fa.func = LittleLong (res->linenos[i].fa.func);
res->linenos[i].line = LittleLong (res->linenos[i].line); res->linenos[i].line = LittleLong (res->linenos[i].line);
} }
qsort_r (res->sorted_functions, pr->progs->numfunctions, sizeof (func_t),
func_compare_sort, res);
for (i = 0; i < res->debug->num_locals; i++) { for (i = 0; i < res->debug->num_locals; i++) {
byteswap_def (&res->local_defs[i]); byteswap_def (&res->local_defs[i]);
if (type_encodings) { if (type_encodings) {
@ -752,6 +807,43 @@ PR_Find_Lineno (progs_t *pr, pr_uint_t addr)
return lineno; return lineno;
} }
pr_uint_t
PR_FindSourceLineAddr (progs_t *pr, const char *file, pr_uint_t line)
{
prdeb_resources_t *res = pr->pr_debug_resources;
func_key_t key = { file, line };
func_t *f = fbsearch_r (&key, res->sorted_functions,
pr->progs->numfunctions, sizeof (func_t),
func_compare_search, res);
if (!f) {
return 0;
}
dfunction_t *func = &pr->pr_functions[*f];
if (func->first_statement <= 0
|| strcmp (file, PR_GetString (pr, func->s_file)) != 0) {
return 0;
}
pr_auxfunction_t *aux = res->auxfunction_map[*f];
if (!aux) {
return 0;
}
pr_uint_t addr = func->first_statement;
line -= aux->source_line;
//FIXME put lineno count in sym file
for (pr_uint_t i = aux->line_info + 1; i < res->debug->num_linenos; i++) {
if (!res->linenos[i].line) {
break;
}
if (res->linenos[i].line <= line) {
addr = res->linenos[i].fa.addr;
} else {
break;
}
}
return addr;
}
const char * const char *
PR_Get_Source_File (progs_t *pr, pr_lineno_t *lineno) PR_Get_Source_File (progs_t *pr, pr_lineno_t *lineno)
{ {

View file

@ -225,8 +225,9 @@ qdb_set_breakpoint (progs_t *pr)
R_INT (pr) = -1; R_INT (pr) = -1;
return; return;
} }
int set = (tpr->pr_statements[staddr].op & OP_BREAK) != 0;
tpr->pr_statements[staddr].op |= OP_BREAK; tpr->pr_statements[staddr].op |= OP_BREAK;
R_INT (pr) = 0; R_INT (pr) = set;
} }
static void static void
@ -619,6 +620,19 @@ qdb_get_local_defs (progs_t *pr)
} }
} }
static void
qdb_get_source_line_addr (progs_t *pr)
{
__auto_type debug = PR_Resources_Find (pr, "qwaq-debug");
pointer_t handle = P_INT (pr, 0);
qwaq_target_t *target = get_target (debug, __FUNCTION__, handle);
progs_t *tpr = target->pr;
const char *file = P_GSTRING (pr, 1);
pr_uint_t line = P_UINT (pr, 2);
R_UINT (pr) = PR_FindSourceLineAddr (tpr, file, line);
}
static builtin_t builtins[] = { static builtin_t builtins[] = {
{"qdb_set_trace", qdb_set_trace, -1}, {"qdb_set_trace", qdb_set_trace, -1},
{"qdb_set_breakpoint", qdb_set_breakpoint, -1}, {"qdb_set_breakpoint", qdb_set_breakpoint, -1},
@ -641,6 +655,7 @@ static builtin_t builtins[] = {
{"qdb_find_auxfunction", qdb_find_auxfunction, -1}, {"qdb_find_auxfunction", qdb_find_auxfunction, -1},
{"qdb_get_auxfunction", qdb_get_auxfunction, -1}, {"qdb_get_auxfunction", qdb_get_auxfunction, -1},
{"qdb_get_local_defs", qdb_get_local_defs, -1}, {"qdb_get_local_defs", qdb_get_local_defs, -1},
{"qdb_get_source_line_addr", qdb_get_source_line_addr, -1},
{} {}
}; };

View file

@ -95,7 +95,8 @@ qdb_function_t *qdb_get_function (qdb_target_t target, unsigned fnum);
qdb_auxfunction_t *qdb_find_auxfunction (qdb_target_t target, string name); qdb_auxfunction_t *qdb_find_auxfunction (qdb_target_t target, string name);
qdb_auxfunction_t *qdb_get_auxfunction (qdb_target_t target, unsigned fnum); qdb_auxfunction_t *qdb_get_auxfunction (qdb_target_t target, unsigned fnum);
qdb_def_t *qdb_get_local_defs (qdb_target_t target, unsigned fnum); qdb_def_t *qdb_get_local_defs (qdb_target_t target, unsigned fnum);
unsigned qdb_get_source_line_addr(qdb_target_t target, string file,
unsigned line);
void traceon(); void traceon();
void traceoff(); void traceoff();

View file

@ -27,3 +27,5 @@ qdb_auxfunction_t *qdb_find_auxfunction (qdb_target_t target,
qdb_auxfunction_t *qdb_get_auxfunction (qdb_target_t target, qdb_auxfunction_t *qdb_get_auxfunction (qdb_target_t target,
unsigned fnum) = #0; unsigned fnum) = #0;
qdb_def_t *qdb_get_local_defs (qdb_target_t target, unsigned fnum) = #0; qdb_def_t *qdb_get_local_defs (qdb_target_t target, unsigned fnum) = #0;
unsigned qdb_get_source_line_addr(qdb_target_t target, string file,
unsigned line) = #0;

View file

@ -28,6 +28,7 @@
int onExit; int onExit;
} sub_cond; } sub_cond;
SEL traceHandler; SEL traceHandler;
SEL breakHandler;
int running; int running;
Window *source_window; Window *source_window;

View file

@ -53,17 +53,17 @@
-(Editor *) find_file:(string) filename -(Editor *) find_file:(string) filename
{ {
Editor *file; Editor *file;
filename = qdb_get_file_path (target, filename); string filepath = qdb_get_file_path (target, filename);
for (int i = [files count]; i-- > 0; ) { for (int i = [files count]; i-- > 0; ) {
file = [files objectAtIndex: i]; file = [files objectAtIndex: i];
if ([file filename] == filename) { if ([file filepath] == filepath) {
return file; return file;
} }
} }
Rect rect = {{1, 1}, [source_window size]}; Rect rect = {{1, 1}, [source_window size]};
rect.extent.width -= 2; rect.extent.width -= 2;
rect.extent.height -= 2; rect.extent.height -= 2;
file = [Editor withRect:rect file:filename]; file = [Editor withRect:rect file:filename path:filepath];
[files addObject: file]; [files addObject: file];
return file; return file;
} }
@ -154,6 +154,27 @@ proxy_event_stopped (Debugger *self, id proxy, qwaq_event_t *event)
self.running = 1; self.running = 1;
qdb_continue (self.target); qdb_continue (self.target);
return 1; return 1;
case QFK_F4:
string file = [self.current_file filename];
unsigned line = [self.current_file cursor].y + 1;
unsigned addr = qdb_get_source_line_addr (self.target,
file, line);
int set = -1;
if (addr) {
set = qdb_set_breakpoint (self.target, addr);
}
if (set >= 0) {
qdb_set_trace (self.target, 0);
if (set) {
self.breakHandler = @selector(breakKeep);
} else {
self.breakHandler = @selector(breakClear);
}
self.running = 1;
qdb_continue (self.target);
} else {
}
return 1;
} }
} }
return 0; return 0;
@ -236,6 +257,18 @@ is_new_line (qdb_state_t last_state, qdb_state_t state)
return self; return self;
} }
-breakKeep
{
return self;
}
-breakClear
{
qdb_state_t state = qdb_get_state (target);
qdb_clear_breakpoint (target, state.staddr);
return self;
}
-handleDebugEvent -handleDebugEvent
{ {
if (qdb_get_event (target, &event)) { if (qdb_get_event (target, &event)) {
@ -247,6 +280,7 @@ is_new_line (qdb_state_t last_state, qdb_state_t state)
break; break;
case prd_breakpoint: case prd_breakpoint:
case prd_watchpoint: case prd_watchpoint:
[self performSelector:breakHandler];
[self stop:event.what]; [self stop:event.what];
break; break;
case prd_subenter: case prd_subenter:

View file

@ -13,7 +13,6 @@ gcd (int a, int b)
int int
main (int argc, string *argv) main (int argc, string *argv)
{ {
traceon ();
x = 130; x = 130;
y = 120; y = 120;
printf ("%d\n", gcd (x, y)); printf ("%d\n", gcd (x, y));