From de77e9e6b9518071a68a8580a90cda99eda962fe Mon Sep 17 00:00:00 2001 From: John Doty Date: Fri, 22 Sep 2023 22:11:47 -0500 Subject: [PATCH] [quickjs] More debugger work - Helpers for frame position stuff - Debug Frame manipulation --- oden-js-sys/quickjs/quickjs.c | 123 ++++++++++++++++++++++++---------- oden-js-sys/quickjs/quickjs.h | 16 ++++- 2 files changed, 100 insertions(+), 39 deletions(-) diff --git a/oden-js-sys/quickjs/quickjs.c b/oden-js-sys/quickjs/quickjs.c index 40624b9a..e8d8e6f6 100644 --- a/oden-js-sys/quickjs/quickjs.c +++ b/oden-js-sys/quickjs/quickjs.c @@ -6501,6 +6501,51 @@ static const char *get_func_name(JSContext *ctx, JSValueConst func) /* only taken into account if filename is provided */ #define JS_BACKTRACE_FLAG_SINGLE_LEVEL (1 << 1) +static void get_frame_debug_position(JSContext *ctx, JSStackFrame *sf, + const char **function, const char **file, + int *line, BOOL *backtrace_barrier) +{ + JSObject *p; + + *backtrace_barrier = FALSE; + *function = get_func_name(ctx, sf->cur_func); + p = JS_VALUE_GET_OBJ(sf->cur_func); + if (js_class_has_bytecode(p->class_id)) { + JSFunctionBytecode *b; + const char *atom_str; + int line_num1; + + b = p->u.func.function_bytecode; + *backtrace_barrier = b->backtrace_barrier; + *function = JS_AtomToCString(ctx, b->func_name); + if (b->has_debug) { + line_num1 = find_line_num(ctx, b, sf->cur_pc - b->byte_code_buf - 1); + + JSAtom fname = b->debug.filename; + if (ctx->rt->map_source_func) { + ctx->rt->map_source_func( + ctx, + ctx->rt->map_source_opaque, + fname, line_num1, + &fname, &line_num1); + } + + *file = JS_AtomToCString(ctx, fname); + *line = line_num1; + + if (ctx->rt->map_source_func) { + JS_FreeAtomRT(ctx->rt, fname); + } + } else { + *file = NULL; + *line = -1; + } + } else { + *file = js_strdup(ctx, "native"); + *line = -1; + } +} + /* if filename != NULL, an additional level is added with the filename and line number information (used for parse error). */ static void build_backtrace(JSContext *ctx, JSValueConst error_obj, @@ -6511,6 +6556,8 @@ static void build_backtrace(JSContext *ctx, JSValueConst error_obj, JSValue str; DynBuf dbuf; const char *func_name_str; + const char *file_name_str; + int line_num1; const char *str1; JSObject *p; BOOL backtrace_barrier; @@ -6534,7 +6581,9 @@ static void build_backtrace(JSContext *ctx, JSValueConst error_obj, backtrace_flags &= ~JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL; continue; } - func_name_str = get_func_name(ctx, sf->cur_func); + + get_frame_debug_position(ctx, sf, &func_name_str, &file_name_str, + &line_num1, &backtrace_barrier); if (!func_name_str || func_name_str[0] == '\0') str1 = ""; else @@ -6542,43 +6591,14 @@ static void build_backtrace(JSContext *ctx, JSValueConst error_obj, dbuf_printf(&dbuf, " at %s", str1); JS_FreeCString(ctx, func_name_str); - p = JS_VALUE_GET_OBJ(sf->cur_func); - backtrace_barrier = FALSE; - if (js_class_has_bytecode(p->class_id)) { - JSFunctionBytecode *b; - const char *atom_str; - int line_num1; - - b = p->u.func.function_bytecode; - backtrace_barrier = b->backtrace_barrier; - if (b->has_debug) { - line_num1 = find_line_num(ctx, b, - sf->cur_pc - b->byte_code_buf - 1); - - JSAtom file = b->debug.filename; - if (ctx->rt->map_source_func) { - ctx->rt->map_source_func( - ctx, - ctx->rt->map_source_opaque, - file, line_num1, - &file, &line_num1); - } - - atom_str = JS_AtomToCString(ctx, file); - dbuf_printf(&dbuf, " (%s", - atom_str ? atom_str : ""); - JS_FreeCString(ctx, atom_str); - if (line_num1 != -1) - dbuf_printf(&dbuf, ":%d", line_num1); - dbuf_putc(&dbuf, ')'); - - if (ctx->rt->map_source_func) { - JS_FreeAtomRT(ctx->rt, file); - } + if (file_name_str && file_name_str[0]) { + dbuf_printf(&dbuf, " (%s"); + if (line_num1 >= 0) { + dbuf_printf(&dbuf, ":%d", line_num1); } - } else { - dbuf_printf(&dbuf, " (native)"); + dbuf_putc(&dbuf, ')'); } + dbuf_putc(&dbuf, '\n'); /* stop backtrace if JS_EVAL_FLAG_BACKTRACE_BARRIER was used */ if (backtrace_barrier) @@ -54199,6 +54219,7 @@ static JSBreakpoint *find_existing_breakpoint(JSContext *ctx, JSFunctionBytecode typedef struct JSDebugContext { JSContext *ctx; + JSStackFrame *sf; } JSDebugContext; static int js_handle_breakpoint(JSContext *ctx, JSFunctionBytecode *b, int code_offset) { @@ -54211,6 +54232,7 @@ static int js_handle_breakpoint(JSContext *ctx, JSFunctionBytecode *b, int code_ if (rt->debug_callback) { JSDebugContext dctx; dctx.ctx = ctx; + dctx.sf = ctx->rt->current_stack_frame; resume = rt->debug_callback(&dctx, JS_BREAK_BREAKPOINT, bp, rt->debug_opaque); } @@ -54225,6 +54247,7 @@ static int js_handle_breakpoint(JSContext *ctx, JSFunctionBytecode *b, int code_ if (rt->debug_callback) { JSDebugContext dctx; dctx.ctx = ctx; + dctx.sf = ctx->rt->current_stack_frame; resume = rt->debug_callback(&dctx, JS_BREAK_STEP, NULL, rt->debug_opaque); } @@ -54233,6 +54256,33 @@ static int js_handle_breakpoint(JSContext *ctx, JSFunctionBytecode *b, int code_ return next_op; } +JSContext *JS_DebugGetContext(JSDebugContext *ctx) +{ + return ctx->ctx; +} + +JSDebugFrame *JS_DebugGetFrame(JSDebugContext *ctx) { + return (JSDebugFrame *)(ctx->sf); +} + +JSDebugFrame *JS_DebugGetPreviousFrame(JSDebugContext *ctx, JSDebugFrame *frame) { + JSStackFrame *sf = (JSStackFrame *)frame; + if (!sf) + return NULL; + return (JSDebugFrame *)(sf->prev_frame); +} + +void JS_DebugGetFrameSourcePosition(JSDebugContext *dctx, JSDebugFrame *frame, + const char **function, const char **file, + int *line) { + JSStackFrame *sf = (JSStackFrame *)frame; + JSContext *ctx = dctx->ctx; + BOOL backtrace_barrier; + + get_frame_debug_position(ctx, sf, function, file, line, &backtrace_barrier); +} + + JSBreakpoint *JS_SetBreakpoint(JSContext *ctx, JSAtom file, int line) { struct list_head *el; @@ -54309,4 +54359,3 @@ void JS_GetBreakpointLocation(JSBreakpoint *breakpoint, JSAtom *file, int *line) *line = breakpoint->line; } - diff --git a/oden-js-sys/quickjs/quickjs.h b/oden-js-sys/quickjs/quickjs.h index a5409d2f..6ca6cec7 100644 --- a/oden-js-sys/quickjs/quickjs.h +++ b/oden-js-sys/quickjs/quickjs.h @@ -1053,8 +1053,16 @@ void JS_SetSourceMapFunc(JSRuntime *rt, JSMapSourceFunc *map_func, void *opaque) /* Debugger support */ typedef struct JSDebugContext JSDebugContext; +typedef struct JSDebugFrame JSDebugFrame; + JSContext *JS_DebugGetContext(JSDebugContext *ctx); +JSDebugFrame *JS_DebugGetFrame(JSDebugContext *ctx); +JSDebugFrame *JS_DebugGetPreviousFrame(JSDebugContext *ctx, JSDebugFrame *frame); +void JS_DebugGetFrameSourcePosition(JSDebugContext *ctx, JSDebugFrame *frame, + const char **function, const char **file, + int *line); + typedef enum JSResumeMode { JS_RESUME_MODE_CONTINUE, JS_RESUME_MODE_STEP_OVER, @@ -1068,8 +1076,12 @@ typedef enum JSBreakReason { typedef struct JSBreakpoint JSBreakpoint; -typedef JSResumeMode JSDebugCallbackFunc(JSDebugContext *ctx, JSBreakReason reason, JSBreakpoint *breakpoint, void *opaque); -void JS_SetDebugCallbackFunc(JSRuntime *rt, JSDebugCallbackFunc *bp_func, void *opqaue); +typedef JSResumeMode JSDebugCallbackFunc(JSDebugContext *ctx, + JSBreakReason reason, + JSBreakpoint *breakpoint, + void *opaque); +void JS_SetDebugCallbackFunc(JSRuntime *rt, JSDebugCallbackFunc *bp_func, + void *opqaue); JSBreakpoint *JS_SetBreakpoint(JSContext *ctx, JSAtom file, int line); JSBreakpoint *JS_DupBreakpoint(JSBreakpoint *breakpoint);