From 8a77aa804e1464313b01ae9dc908efefb8cf5ae6 Mon Sep 17 00:00:00 2001 From: Brendan Hansen Date: Mon, 8 Aug 2022 22:41:06 -0500 Subject: [PATCH] expanding debugger functionality --- build.sh | 3 +- include/ovm_debug.h | 5 +++ src/debug/debug_info.c | 6 +++ src/debug/debug_thread.c | 86 +++++++++++++++++++++++++++++++--------- src/vm/vm.c | 13 ++++-- 5 files changed, 91 insertions(+), 22 deletions(-) diff --git a/build.sh b/build.sh index 05f7bdf..57309ed 100755 --- a/build.sh +++ b/build.sh @@ -2,12 +2,13 @@ CC="gcc" WARNINGS='-Wimplicit -Wmisleading-indentation -Wparentheses -Wsequence-point -Wreturn-type -Wshift-negative-value -Wunused-but-set-parameter -Wunused-but-set-variable -Wunused-function -Wunused-label -Wmaybe-uninitialized -Wsign-compare -Wstrict-overflow -Wduplicated-branches -Wduplicated-cond -Wtrigraphs -Waddress -Wlogical-op' +# FLAGS="-g3" # FLAGS="-g3 -DOVM_VERBOSE=1" FLAGS="-Ofast" LIBS="-pthread" INCLUDES="-I include" TARGET="libovmwasm.so" -C_FILES="src/wasm.c src/vm/*.c src/wasm/*.c" +C_FILES="src/wasm.c src/vm/*.c src/wasm/*.c src/debug/*.c" $CC $FLAGS $INCLUDES -shared -fPIC -o $TARGET $C_FILES $LIBS $WARNINGS diff --git a/include/ovm_debug.h b/include/ovm_debug.h index c4de4cf..453e2f6 100644 --- a/include/ovm_debug.h +++ b/include/ovm_debug.h @@ -90,6 +90,9 @@ typedef enum debug_exec_state_t { debug_state_ready, debug_state_running, debug_state_paused, + + debug_state_pausing, + debug_state_hit_breakpoint, } debug_exec_state_t; typedef struct debug_thread_state_t { @@ -101,7 +104,9 @@ typedef struct debug_thread_state_t { i32 run_count; sem_t wait_semaphore; + // :BreakpointID bh_arr(u32) breakpoints; + u32 last_breakpoint_hit; } debug_thread_state_t; // diff --git a/src/debug/debug_info.c b/src/debug/debug_info.c index 0341563..5dbc047 100644 --- a/src/debug/debug_info.c +++ b/src/debug/debug_info.c @@ -79,12 +79,16 @@ void debug_info_import_func_info(debug_info_t *info, u8 *data, u32 len) { } bool debug_info_lookup_location(debug_info_t *info, u32 instruction, debug_loc_info_t *out) { + if (!info) return false; + if (instruction > (u32) bh_arr_length(info->instruction_reducer)) return false; *out = info->line_info[info->instruction_reducer[instruction]]; return true; } bool debug_info_lookup_file(debug_info_t *info, u32 file_id, debug_file_info_t *out) { + if (!info) return false; + if (file_id > (u32) bh_arr_length(info->files)) return false; *out = info->files[file_id]; return true; @@ -94,6 +98,8 @@ bool debug_info_lookup_file(debug_info_t *info, u32 file_id, debug_file_info_t * // 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. bool debug_info_lookup_file_by_name(debug_info_t *info, char *name, debug_file_info_t *out) { + if (!info) return false; + bh_arr_each(debug_file_info_t, file, info->files) { if (!strcmp(file->name, name)) { *out = *file; diff --git a/src/debug/debug_thread.c b/src/debug/debug_thread.c index 4748c8e..beab3c1 100644 --- a/src/debug/debug_thread.c +++ b/src/debug/debug_thread.c @@ -87,15 +87,23 @@ static void process_command(debug_state_t *debug, struct msg_parse_ctx_t *ctx) { case CMD_RES: { // Returns: nothing - // Release the threads + u32 thread_id = parse_int(debug, ctx); + + bool resumed_a_thread = false; + + // Release the thread(s) bh_arr_each(debug_thread_state_t *, thread, debug->threads) { - // This logic for "how to resume a thread" should be moved - // elsewhere, but now its fine here. - (*thread)->run_count = -1; - sem_post(&(*thread)->wait_semaphore); + if (thread_id == 0xffffffff || (*thread)->id == thread_id) { + // This logic for "how to resume a thread" should be moved + // elsewhere, but now its fine here. + (*thread)->run_count = -1; + sem_post(&(*thread)->wait_semaphore); + resumed_a_thread = true; + } } send_response_header(debug, msg_id); + send_bool(debug, resumed_a_thread); break; } @@ -111,13 +119,19 @@ static void process_command(debug_state_t *debug, struct msg_parse_ctx_t *ctx) { debug_file_info_t file_info; bool file_found = debug_info_lookup_file_by_name(debug->info, filename, &file_info); if (!file_found) { - send_response_header(debug, msg_id); - send_bool(debug, false); - send_int(debug, -1); - return; + goto send_error; + } + + if (line > file_info.line_count) { + goto send_error; } u32 instr = debug->info->line_to_instruction[file_info.line_buffer_offset + line]; + if (instr == 0) { + // Technically, this condition is not right as it is possible for the first + // instruction to have index 0. + goto send_error; + } printf("[INFO ] Setting breakpoint at %s:%d (%xd)\n", filename, line, instr); @@ -127,15 +141,18 @@ static void process_command(debug_state_t *debug, struct msg_parse_ctx_t *ctx) { send_response_header(debug, msg_id); send_bool(debug, true); - send_int(debug, 0); + send_int(debug, 0); // TODO: This should be a unique breakpoint ID + break; + + send_error: + send_response_header(debug, msg_id); + send_bool(debug, false); + send_int(debug, -1); break; } } } -static void process_response(debug_state_t *debug, struct msg_parse_ctx_t *ctx) { -} - static void process_message(debug_state_t *debug, char *msg, unsigned int bytes_read) { struct msg_parse_ctx_t ctx; ctx.data = msg; @@ -144,12 +161,9 @@ static void process_message(debug_state_t *debug, char *msg, unsigned int bytes_ while (ctx.offset < ctx.bytes_read) { u32 msg_id = *(u32 *) &ctx.data[ctx.offset]; + assert(msg_id != 0xffffffff); - if (msg_id != 0xffffffff) { - process_command(debug, &ctx); - } else { - process_response(debug, &ctx); - } + process_command(debug, &ctx); } } @@ -215,6 +229,42 @@ void *__debug_thread_entry(void * data) { // // Check the state of the running program and report any changes. + bh_arr_each(debug_thread_state_t *, thread, debug->threads) { + if ((*thread)->state == debug_state_hit_breakpoint) { + (*thread)->state = debug_state_paused; + + u32 bp_id = (*thread)->last_breakpoint_hit; // :BreakpointID + u32 instr = (*thread)->breakpoints[bp_id]; + + debug_loc_info_t loc_info; + debug_info_lookup_location(debug->info, instr, &loc_info); + + debug_file_info_t file_info; + debug_info_lookup_file(debug->info, loc_info.file_id, &file_info); + + send_int(debug, 1); + send_int(debug, bp_id); + send_int(debug, (*thread)->id); + send_string(debug, file_info.name); + send_int(debug, loc_info.line); + } + + if ((*thread)->state == debug_state_pausing) { + (*thread)->state = debug_state_paused; + + debug_loc_info_t loc_info; + debug_info_lookup_location(debug->info, (*thread)->ovm_state->pc, &loc_info); + + debug_file_info_t file_info; + debug_info_lookup_file(debug->info, loc_info.file_id, &file_info); + + send_int(debug, 2); + send_int(debug, (*thread)->id); + send_string(debug, file_info.name); + send_int(debug, loc_info.line); + } + } + bh_arena_clear(&debug->tmp_arena); } diff --git a/src/vm/vm.c b/src/vm/vm.c index 6eb5800..37d03bd 100644 --- a/src/vm/vm.c +++ b/src/vm/vm.c @@ -684,16 +684,23 @@ ovm_value_t ovm_run_code(ovm_engine_t *engine, ovm_state_t *state, ovm_program_t // Check if breakpoints are hit if (state->debug) { - if (state->debug->run_count == 0) goto should_wait; + if (state->debug->run_count == 0) { + state->debug->state = debug_state_pausing; + goto should_wait; + } bh_arr_each(u32, bp, state->debug->breakpoints) { - if (*bp == (u32) state->pc) goto should_wait; + if (*bp == (u32) state->pc) { + // :BreakpointID + state->debug->state = debug_state_hit_breakpoint; + state->debug->last_breakpoint_hit = bp - state->debug->breakpoints; + goto should_wait; + } } goto shouldnt_wait; should_wait: - state->debug->state = debug_state_paused; sem_wait(&state->debug->wait_semaphore); state->debug->state = debug_state_running; -- 2.25.1