[quickjs] More debugger work

This commit is contained in:
John Doty 2023-09-24 11:24:28 -07:00
parent 0531387498
commit 743a1cc623
2 changed files with 56 additions and 13 deletions

View file

@ -1018,6 +1018,11 @@ typedef struct JSBreakpoint {
JS_BOOL enabled; JS_BOOL enabled;
} JSBreakpoint; } JSBreakpoint;
typedef struct JSDebugContext {
JSContext *ctx;
JSStackFrame *sf;
} JSDebugContext;
static int JS_InitAtoms(JSRuntime *rt); static int JS_InitAtoms(JSRuntime *rt);
static JSAtom __JS_NewAtomInit(JSRuntime *rt, const char *str, int len, static JSAtom __JS_NewAtomInit(JSRuntime *rt, const char *str, int len,
int atom_type); int atom_type);
@ -6503,6 +6508,7 @@ static void get_frame_debug_position(JSContext *ctx, JSStackFrame *sf,
*backtrace_barrier = FALSE; *backtrace_barrier = FALSE;
*function = get_func_name(ctx, sf->cur_func); *function = get_func_name(ctx, sf->cur_func);
p = JS_VALUE_GET_OBJ(sf->cur_func); p = JS_VALUE_GET_OBJ(sf->cur_func);
if (js_class_has_bytecode(p->class_id)) { if (js_class_has_bytecode(p->class_id)) {
JSFunctionBytecode *b; JSFunctionBytecode *b;
@ -6510,7 +6516,6 @@ static void get_frame_debug_position(JSContext *ctx, JSStackFrame *sf,
b = p->u.func.function_bytecode; b = p->u.func.function_bytecode;
*backtrace_barrier = b->backtrace_barrier; *backtrace_barrier = b->backtrace_barrier;
*function = JS_AtomToCString(ctx, b->func_name);
if (b->has_debug) { if (b->has_debug) {
line_num1 = find_line_num(ctx, b, sf->cur_pc - b->byte_code_buf - 1); line_num1 = find_line_num(ctx, b, sf->cur_pc - b->byte_code_buf - 1);
@ -33775,6 +33780,24 @@ static JSValue __JS_EvalInternal(JSContext *ctx, JSValueConst this_obj,
goto fail1; goto fail1;
fun_obj = JS_DupValue(ctx, JS_MKPTR(JS_TAG_MODULE, m)); fun_obj = JS_DupValue(ctx, JS_MKPTR(JS_TAG_MODULE, m));
} }
if (ctx->rt->debug_callback) {
JSDebugContext dctx;
dctx.ctx = ctx;
dctx.sf = sf;
JSDebugEvent evt;
evt.reason = JS_BREAK_CODE_LOADED;
evt.u.loaded.filename = filename;
/* TODO: Handle the step/resume/what-have-you. Step from here will
be complicated because the function we need to step into will be
the one we just parsed, kinda- unless it's a module? Even then
it's not clear where the break will go if we're loading a
module... yikes. */
/* resume = */ctx->rt->debug_callback(&dctx, &evt, ctx->rt->debug_opaque);
}
if (flags & JS_EVAL_FLAG_COMPILE_ONLY) { if (flags & JS_EVAL_FLAG_COMPILE_ONLY) {
ret_val = fun_obj; ret_val = fun_obj;
} else { } else {
@ -54147,6 +54170,12 @@ void JS_SetSourceMapFunc(JSRuntime *rt, JSMapSourceFunc *map_func, void *opaque)
/* Debugger */ /* Debugger */
void JS_SetDebugCallbackFunc(JSRuntime *rt, JSDebugCallbackFunc *func, void *opaque)
{
rt->debug_callback = func;
rt->debug_opaque = opaque;
}
static BOOL find_pc_offset(JSFunctionBytecode *b, int target_line, int *break_pc, int *actual_line) static BOOL find_pc_offset(JSFunctionBytecode *b, int target_line, int *break_pc, int *actual_line)
{ {
const uint8_t *p_end, *p; const uint8_t *p_end, *p;
@ -54199,7 +54228,8 @@ static BOOL find_pc_offset(JSFunctionBytecode *b, int target_line, int *break_pc
return FALSE; return FALSE;
} }
static JSBreakpoint *find_existing_breakpoint(JSContext *ctx, JSFunctionBytecode *func, int pc) { static JSBreakpoint *find_existing_breakpoint(JSContext *ctx, JSFunctionBytecode *func, int pc)
{
struct list_head *el; struct list_head *el;
list_for_each(el, &ctx->rt->breakpoint_list) { list_for_each(el, &ctx->rt->breakpoint_list) {
JSBreakpoint *bp = list_entry(el, JSBreakpoint, link); JSBreakpoint *bp = list_entry(el, JSBreakpoint, link);
@ -54210,12 +54240,8 @@ static JSBreakpoint *find_existing_breakpoint(JSContext *ctx, JSFunctionBytecode
return NULL; return NULL;
} }
typedef struct JSDebugContext { static int js_handle_breakpoint(JSContext *ctx, JSFunctionBytecode *b, int code_offset)
JSContext *ctx; {
JSStackFrame *sf;
} JSDebugContext;
static int js_handle_breakpoint(JSContext *ctx, JSFunctionBytecode *b, int code_offset) {
int next_op; int next_op;
/* JSResumeMode resume = JS_RESUME_MODE_CONTINUE; */ /* JSResumeMode resume = JS_RESUME_MODE_CONTINUE; */
JSRuntime *rt = ctx->rt; JSRuntime *rt = ctx->rt;
@ -54227,7 +54253,11 @@ static int js_handle_breakpoint(JSContext *ctx, JSFunctionBytecode *b, int code_
dctx.ctx = ctx; dctx.ctx = ctx;
dctx.sf = ctx->rt->current_stack_frame; dctx.sf = ctx->rt->current_stack_frame;
/* resume = */rt->debug_callback(&dctx, JS_BREAK_BREAKPOINT, bp, rt->debug_opaque); JSDebugEvent evt;
evt.reason = JS_BREAK_BREAKPOINT;
evt.u.breakpoint = bp;
/* resume = */rt->debug_callback(&dctx, &evt, rt->debug_opaque);
} }
} }
next_op = bp->replaced_byte; next_op = bp->replaced_byte;
@ -54242,7 +54272,10 @@ static int js_handle_breakpoint(JSContext *ctx, JSFunctionBytecode *b, int code_
dctx.ctx = ctx; dctx.ctx = ctx;
dctx.sf = ctx->rt->current_stack_frame; dctx.sf = ctx->rt->current_stack_frame;
/* resume = */rt->debug_callback(&dctx, JS_BREAK_STEP, NULL, rt->debug_opaque); JSDebugEvent evt;
evt.reason = JS_BREAK_STEP;
/* resume = */rt->debug_callback(&dctx, &evt, rt->debug_opaque);
} }
} }

View file

@ -1070,15 +1070,25 @@ typedef enum JSResumeMode {
} JSResumeMode; } JSResumeMode;
typedef enum JSBreakReason { typedef enum JSBreakReason {
JS_BREAK_CODE_LOADED,
JS_BREAK_BREAKPOINT, JS_BREAK_BREAKPOINT,
JS_BREAK_STEP, JS_BREAK_STEP,
} JSBreakReason; } JSBreakReason;
typedef struct JSBreakpoint JSBreakpoint; typedef struct JSBreakpoint JSBreakpoint;
typedef struct JSDebugEvent {
JSBreakReason reason;
union {
struct {
const char *filename;
} loaded;
JSBreakpoint *breakpoint;
} u;
} JSDebugEvent;
typedef JSResumeMode JSDebugCallbackFunc(JSDebugContext *ctx, typedef JSResumeMode JSDebugCallbackFunc(JSDebugContext *ctx,
JSBreakReason reason, JSDebugEvent *event,
JSBreakpoint *breakpoint,
void *opaque); void *opaque);
void JS_SetDebugCallbackFunc(JSRuntime *rt, JSDebugCallbackFunc *bp_func, void JS_SetDebugCallbackFunc(JSRuntime *rt, JSDebugCallbackFunc *bp_func,
void *opqaue); void *opqaue);