mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-10 15:22:04 +00:00
[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:
parent
c818a2abf9
commit
d23c9582f1
8 changed files with 152 additions and 7 deletions
|
@ -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));
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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},
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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));
|
||||||
|
|
Loading…
Reference in a new issue