diff --git a/include/QF/progs.h b/include/QF/progs.h index fd36c0c62..7ccb962d2 100644 --- a/include/QF/progs.h +++ b/include/QF/progs.h @@ -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_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_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_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)); diff --git a/libs/gamecode/pr_debug.c b/libs/gamecode/pr_debug.c index 3ef208442..906ec185f 100644 --- a/libs/gamecode/pr_debug.c +++ b/libs/gamecode/pr_debug.c @@ -31,6 +31,8 @@ # include "config.h" #endif +#define _GNU_SOURCE // for qsort_r + #ifdef HAVE_STRING_H # include #endif @@ -41,6 +43,7 @@ #include #include +#include "QF/fbsearch.h" #include "QF/cvar.h" #include "QF/dstring.h" #include "QF/hash.h" @@ -75,6 +78,11 @@ typedef struct compunit_s { pr_compunit_t *unit; } compunit_t; +typedef struct { + const char *file; + pr_uint_t line; +} func_key_t; + typedef struct prdeb_resources_s { progs_t *pr; dstring_t *string; @@ -85,6 +93,7 @@ typedef struct prdeb_resources_s { pr_debug_header_t *debug; pr_auxfunction_t *auxfunctions; pr_auxfunction_t **auxfunction_map; + func_t *sorted_functions; pr_lineno_t *linenos; pr_def_t *local_defs; pr_def_t *type_encodings_def; @@ -379,6 +388,9 @@ pr_debug_clear (progs_t *pr, void *data) if (res->auxfunction_map) pr->free_progs_mem (pr, res->auxfunction_map); res->auxfunction_map = 0; + if (res->sorted_functions) + pr->free_progs_mem (pr, res->sorted_functions); + res->sorted_functions = 0; res->linenos = 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 PR_LoadDebug (progs_t *pr) { @@ -562,8 +611,12 @@ PR_LoadDebug (progs_t *pr) i = pr->progs->numfunctions * sizeof (pr_auxfunction_t *); 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->sorted_functions[i] = i; + } res->type_encodings_def = PR_FindGlobal (pr, ".type_encodings"); 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].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++) { byteswap_def (&res->local_defs[i]); if (type_encodings) { @@ -752,6 +807,43 @@ PR_Find_Lineno (progs_t *pr, pr_uint_t addr) 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 * PR_Get_Source_File (progs_t *pr, pr_lineno_t *lineno) { diff --git a/ruamoko/qwaq/builtins/debug.c b/ruamoko/qwaq/builtins/debug.c index fe6796b46..5d6c598ed 100644 --- a/ruamoko/qwaq/builtins/debug.c +++ b/ruamoko/qwaq/builtins/debug.c @@ -225,8 +225,9 @@ qdb_set_breakpoint (progs_t *pr) R_INT (pr) = -1; return; } + int set = (tpr->pr_statements[staddr].op & OP_BREAK) != 0; tpr->pr_statements[staddr].op |= OP_BREAK; - R_INT (pr) = 0; + R_INT (pr) = set; } 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[] = { {"qdb_set_trace", qdb_set_trace, -1}, {"qdb_set_breakpoint", qdb_set_breakpoint, -1}, @@ -641,6 +655,7 @@ static builtin_t builtins[] = { {"qdb_find_auxfunction", qdb_find_auxfunction, -1}, {"qdb_get_auxfunction", qdb_get_auxfunction, -1}, {"qdb_get_local_defs", qdb_get_local_defs, -1}, + {"qdb_get_source_line_addr", qdb_get_source_line_addr, -1}, {} }; diff --git a/ruamoko/qwaq/debugger/debug.h b/ruamoko/qwaq/debugger/debug.h index f6f58f5ed..2e68de316 100644 --- a/ruamoko/qwaq/debugger/debug.h +++ b/ruamoko/qwaq/debugger/debug.h @@ -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_get_auxfunction (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 traceoff(); diff --git a/ruamoko/qwaq/debugger/debug.r b/ruamoko/qwaq/debugger/debug.r index feb8adbdd..70126f7a2 100644 --- a/ruamoko/qwaq/debugger/debug.r +++ b/ruamoko/qwaq/debugger/debug.r @@ -27,3 +27,5 @@ qdb_auxfunction_t *qdb_find_auxfunction (qdb_target_t target, qdb_auxfunction_t *qdb_get_auxfunction (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; diff --git a/ruamoko/qwaq/debugger/debugger.h b/ruamoko/qwaq/debugger/debugger.h index 8694d06c0..46c9cbeda 100644 --- a/ruamoko/qwaq/debugger/debugger.h +++ b/ruamoko/qwaq/debugger/debugger.h @@ -28,6 +28,7 @@ int onExit; } sub_cond; SEL traceHandler; + SEL breakHandler; int running; Window *source_window; diff --git a/ruamoko/qwaq/debugger/debugger.r b/ruamoko/qwaq/debugger/debugger.r index 3acf1707e..aabb06889 100644 --- a/ruamoko/qwaq/debugger/debugger.r +++ b/ruamoko/qwaq/debugger/debugger.r @@ -53,17 +53,17 @@ -(Editor *) find_file:(string) filename { Editor *file; - filename = qdb_get_file_path (target, filename); + string filepath = qdb_get_file_path (target, filename); for (int i = [files count]; i-- > 0; ) { file = [files objectAtIndex: i]; - if ([file filename] == filename) { + if ([file filepath] == filepath) { return file; } } Rect rect = {{1, 1}, [source_window size]}; rect.extent.width -= 2; rect.extent.height -= 2; - file = [Editor withRect:rect file:filename]; + file = [Editor withRect:rect file:filename path:filepath]; [files addObject: file]; return file; } @@ -154,6 +154,27 @@ proxy_event_stopped (Debugger *self, id proxy, qwaq_event_t *event) self.running = 1; qdb_continue (self.target); 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; @@ -236,6 +257,18 @@ is_new_line (qdb_state_t last_state, qdb_state_t state) return self; } +-breakKeep +{ + return self; +} + +-breakClear +{ + qdb_state_t state = qdb_get_state (target); + qdb_clear_breakpoint (target, state.staddr); + return self; +} + -handleDebugEvent { if (qdb_get_event (target, &event)) { @@ -247,6 +280,7 @@ is_new_line (qdb_state_t last_state, qdb_state_t state) break; case prd_breakpoint: case prd_watchpoint: + [self performSelector:breakHandler]; [self stop:event.what]; break; case prd_subenter: diff --git a/ruamoko/qwaq/gcd.r b/ruamoko/qwaq/gcd.r index bfa3a5e84..a01cce830 100644 --- a/ruamoko/qwaq/gcd.r +++ b/ruamoko/qwaq/gcd.r @@ -13,7 +13,6 @@ gcd (int a, int b) int main (int argc, string *argv) { - traceon (); x = 130; y = 120; printf ("%d\n", gcd (x, y));