From: Brendan Hansen Date: Wed, 14 Dec 2022 16:59:46 +0000 (-0600) Subject: fixed `stopOnEntry` logic to be more correct; fixed multi-threaded breakpoints X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=85a77fcd5b8cdbc24fc60d2f4f392a3b7eb49755;p=onyx.git fixed `stopOnEntry` logic to be more correct; fixed multi-threaded breakpoints --- diff --git a/compiler/src/polymorph.h b/compiler/src/polymorph.h index 0c0583b3..8fee9c84 100644 --- a/compiler/src/polymorph.h +++ b/compiler/src/polymorph.h @@ -481,9 +481,10 @@ static AstTyped* try_lookup_based_on_partial_function_type(AstFunction *pp, AstF AstTyped *result = (AstTyped *) polymorphic_proc_lookup(pp, PPLM_By_Function_Type, ft->partial_function_type, pp->token); // If the result is not ready (NULL, yield flag, no type, or `type_auto_return` as return type), wait. - if (result - && result->type == NULL - || (result->type->kind == Type_Kind_Function && result->type->Function.return_type == &type_auto_return)) { + if (result && ( + result->type == NULL + || (result->type->kind == Type_Kind_Function && result->type->Function.return_type == &type_auto_return))) + { doing_nested_polymorph_lookup = 1; result = NULL; } diff --git a/interpreter/include/ovm_debug.h b/interpreter/include/ovm_debug.h index a2c08670..2b8a70a4 100644 --- a/interpreter/include/ovm_debug.h +++ b/interpreter/include/ovm_debug.h @@ -172,6 +172,7 @@ bool debug_info_lookup_location(debug_info_t *info, u32 instruction, debug_loc_i bool debug_info_lookup_file(debug_info_t *info, u32 file_id, debug_file_info_t *out); bool debug_info_lookup_file_by_name(debug_info_t *info, char *name, debug_file_info_t *out); bool debug_info_lookup_func(debug_info_t *info, u32 func_id, debug_func_info_t *out); +i32 debug_info_lookup_instr_by_file_line(debug_info_t *info, char *filename, u32 line); // // This builder is used in conjunction with code builder to output @@ -231,6 +232,13 @@ typedef struct debug_thread_state_t { debug_exec_state_t state; struct ovm_state_t *ovm_state; + // This flag signals if the thread has done + // ANY execution. When a thread first starts + // the thread signals a `paused` event, with + // an `entry` reason. When the thread pauses + // later on, it should be a `step` reason. + b32 started; + i32 run_count; sem_t wait_semaphore; @@ -239,7 +247,6 @@ typedef struct debug_thread_state_t { i32 extra_frames_since_last_pause; debug_pause_reason_t pause_reason; - bh_arr(debug_breakpoint_t) breakpoints; u32 last_breakpoint_hit; u32 state_change_write_fd; @@ -262,6 +269,7 @@ typedef struct debug_state_t { u32 next_thread_id; u32 next_breakpoint_id; + bh_arr(debug_breakpoint_t) breakpoints; pthread_t debug_thread; bool debug_thread_running; diff --git a/interpreter/src/debug/debug_host.c b/interpreter/src/debug/debug_host.c index 8ae0ce19..82b0c877 100644 --- a/interpreter/src/debug/debug_host.c +++ b/interpreter/src/debug/debug_host.c @@ -44,9 +44,6 @@ u32 debug_host_register_thread(debug_state_t *debug, ovm_state_t *ovm_state) { new_thread->run_count = 0; // Start threads in stopped state. sem_init(&new_thread->wait_semaphore, 0, 0); - new_thread->breakpoints = NULL; - bh_arr_new(debug->alloc, new_thread->breakpoints, 8); - u32 id = debug->next_thread_id++; new_thread->id = id; diff --git a/interpreter/src/debug/debug_info.c b/interpreter/src/debug/debug_info.c index 6f100037..e9fc60d9 100644 --- a/interpreter/src/debug/debug_info.c +++ b/interpreter/src/debug/debug_info.c @@ -211,6 +211,31 @@ bool debug_info_lookup_file(debug_info_t *info, u32 file_id, debug_file_info_t * return true; } +i32 debug_info_lookup_instr_by_file_line(debug_info_t *info, char *filename, u32 line) { + if (!info || !info->has_debug_info) return 0; + + debug_file_info_t file_info; + bool file_found = debug_info_lookup_file_by_name(info, filename, &file_info); + if (!file_found) { + return -1; + } + + if (line > file_info.line_count) { + return -1; + } + + u32 instr; + while ((instr = info->line_to_instruction[file_info.line_buffer_offset + line]) == 0) { + line += 1; + + if (line > file_info.line_count) { + return -1; + } + } + + return instr; +} + // // For now, this is going to compare the strings exactly. In the future, it might be a good // to do a levenschtein distance or something, so the full path isn't needed. diff --git a/interpreter/src/debug/debug_thread.c b/interpreter/src/debug/debug_thread.c index b87843b9..d613fdd9 100644 --- a/interpreter/src/debug/debug_thread.c +++ b/interpreter/src/debug/debug_thread.c @@ -163,41 +163,24 @@ static void process_command(debug_state_t *debug, struct msg_parse_ctx_t *ctx) { char *filename = parse_string(debug, ctx); unsigned int line = parse_int(debug, ctx); - // - // TODO: This translation logic will have to be abstracted - debug_file_info_t file_info; - bool file_found = debug_info_lookup_file_by_name(debug->info, filename, &file_info); - if (!file_found) { - goto brk_send_error; - } - - if (line > file_info.line_count) { - goto brk_send_error; - } - - u32 instr; - while ((instr = debug->info->line_to_instruction[file_info.line_buffer_offset + line]) == 0) { - line += 1; - - if (line > file_info.line_count) { - goto brk_send_error; - } - } + i32 instr = debug_info_lookup_instr_by_file_line(debug->info, filename, line); + if (instr < 0) goto brk_send_error; printf("[INFO ] Setting breakpoint at %s:%d (%x)\n", filename, line, instr); + + debug_file_info_t file_info; + debug_info_lookup_file_by_name(debug->info, filename, &file_info); debug_breakpoint_t bp; bp.id = debug->next_breakpoint_id++; bp.instr = instr; bp.file_id = file_info.file_id; bp.line = line; - bh_arr_each(debug_thread_state_t *, thread, debug->threads) { - bh_arr_push((*thread)->breakpoints, bp); - } + bh_arr_push(debug->breakpoints, bp); send_response_header(debug, msg_id); send_bool(debug, true); - send_int(debug, bp.id); // TODO: This should be a unique breakpoint ID + send_int(debug, bp.id); send_int(debug, line); break; @@ -220,14 +203,12 @@ static void process_command(debug_state_t *debug, struct msg_parse_ctx_t *ctx) { goto clr_brk_send_error; } - bh_arr_each(debug_thread_state_t *, thread, debug->threads) { - bh_arr_each(debug_breakpoint_t, bp, (*thread)->breakpoints) { - if (bp->file_id == file_info.file_id) { - // This is kind of hacky but it does successfully delete - // a single element from the array and move the iterator. - bh_arr_fastdelete((*thread)->breakpoints, bp - (*thread)->breakpoints); - bp--; - } + bh_arr_each(debug_breakpoint_t, bp, debug->breakpoints) { + if (bp->file_id == file_info.file_id) { + // This is kind of hacky but it does successfully delete + // a single element from the array and move the iterator. + bh_arr_fastdelete(debug->breakpoints, bp - debug->breakpoints); + bp--; } } @@ -554,7 +535,7 @@ void *__debug_thread_entry(void * data) { (*thread)->state = debug_state_paused; i32 instr = -1, bp_id = (*thread)->last_breakpoint_hit; - bh_arr_each(debug_breakpoint_t, bp, (*thread)->breakpoints) { + bh_arr_each(debug_breakpoint_t, bp, debug->breakpoints) { if (bp->id == bp_id) { instr = bp->instr; break; diff --git a/interpreter/src/vm/vm.c b/interpreter/src/vm/vm.c index 9080e0f4..ca036621 100644 --- a/interpreter/src/vm/vm.c +++ b/interpreter/src/vm/vm.c @@ -696,7 +696,14 @@ ovm_value_t ovm_run_code(ovm_engine_t *engine, ovm_state_t *state, ovm_program_t if (state->debug) { if (state->debug->run_count == 0) { state->debug->state = debug_state_pausing; - state->debug->pause_reason = debug_pause_entry; // This is not always due to entry... + + if (state->debug->started) { + state->debug->pause_reason = debug_pause_step; + } else { + state->debug->pause_reason = debug_pause_entry; + state->debug->started = 1; + } + goto should_wait; } @@ -716,7 +723,8 @@ ovm_value_t ovm_run_code(ovm_engine_t *engine, ovm_state_t *state, ovm_program_t } } - bh_arr_each(debug_breakpoint_t, bp, state->debug->breakpoints) { + ovm_assert(engine->debug); + bh_arr_each(debug_breakpoint_t, bp, engine->debug->breakpoints) { if (bp->instr == (u32) state->pc) { state->debug->state = debug_state_hit_breakpoint; state->debug->last_breakpoint_hit = bp->id; diff --git a/misc/vscode/out/ovmDebug.js b/misc/vscode/out/ovmDebug.js index 58653c23..f6edc2cf 100644 --- a/misc/vscode/out/ovmDebug.js +++ b/misc/vscode/out/ovmDebug.js @@ -31,6 +31,13 @@ class OVMDebugSession extends debugadapter_1.LoggingDebugSession { this.sendEvent(new debugadapter_1.StoppedEvent("breakpoint", ev.threadId)); }); this.debugger.on("paused", (ev) => { + if (ev.reason == "entry") { + this.sendEvent(new debugadapter_1.ThreadEvent("started", ev.thread_id)); + if (!this.stopOnEntry) { + this.debugger.resume(ev.thread_id); + return; + } + } this.sendEvent(new debugadapter_1.StoppedEvent(ev.reason, ev.threadId)); }); this.debugger.on("terminated", () => { @@ -219,16 +226,14 @@ class OVMDebugSession extends debugadapter_1.LoggingDebugSession { }); } attachRequest(response, args, request) { + var _a; return __awaiter(this, void 0, void 0, function* () { yield this._configurationDone.wait(1000); yield this.debugger.connect(args.socketPath); this._clientConnected = true; this._clientConnectedNotifier.notify(); + this.stopOnEntry = (_a = args.stopOnEntry) !== null && _a !== void 0 ? _a : false; this.sendResponse(response); - this.sendEvent(new debugadapter_1.ThreadEvent("started", 1)); - if (!args.stopOnEntry) { - this.debugger.resume(); - } }); } pauseRequest(response, args, request) { diff --git a/misc/vscode/ovmDebug.ts b/misc/vscode/ovmDebug.ts index 35ce3d53..00c8c252 100644 --- a/misc/vscode/ovmDebug.ts +++ b/misc/vscode/ovmDebug.ts @@ -52,6 +52,8 @@ export class OVMDebugSession extends LoggingDebugSession { private _variableReferences = new Handles(); private _frameReferences = new Handles(); + private stopOnEntry: boolean; + public constructor() { super("ovm-debug-log.txt"); @@ -68,6 +70,15 @@ export class OVMDebugSession extends LoggingDebugSession { }); this.debugger.on("paused", (ev) => { + if (ev.reason == "entry") { + this.sendEvent(new ThreadEvent("started", ev.thread_id)); + + if (!this.stopOnEntry) { + this.debugger.resume(ev.thread_id); + return; + } + } + this.sendEvent(new StoppedEvent(ev.reason, ev.threadId)); }); @@ -315,12 +326,10 @@ export class OVMDebugSession extends LoggingDebugSession { this._clientConnected = true; this._clientConnectedNotifier.notify(); - this.sendResponse(response); - this.sendEvent(new ThreadEvent("started", 1)); + this.stopOnEntry = args.stopOnEntry ?? false; - if (!args.stopOnEntry) { - this.debugger.resume(); - } + this.sendResponse(response); + // this.sendEvent(new ThreadEvent("started", 1)); } protected pauseRequest(response: DebugProtocol.PauseResponse, args: DebugProtocol.PauseArguments, request?: DebugProtocol.Request): void { diff --git a/shared/lib/linux_x86_64/lib/libovmwasm.so b/shared/lib/linux_x86_64/lib/libovmwasm.so index 38a91eaf..1ff06037 100755 Binary files a/shared/lib/linux_x86_64/lib/libovmwasm.so and b/shared/lib/linux_x86_64/lib/libovmwasm.so differ