expanding debugger functionality
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Tue, 9 Aug 2022 03:41:06 +0000 (22:41 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Tue, 9 Aug 2022 03:41:06 +0000 (22:41 -0500)
build.sh
include/ovm_debug.h
src/debug/debug_info.c
src/debug/debug_thread.c
src/vm/vm.c

index 05f7bdfbf22b0c11e0fe42a1651893eb5d13c61b..57309edc7cd0ec91859394a10b15ca55b56ef4d7 100755 (executable)
--- 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
 
index c4de4cfab14bb8292c94b81c711a56ec7d9cbc2a..453e2f67ca36a019b008c00c318615ba7a67cac8 100644 (file)
@@ -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;
 
 //
index 0341563a94737275ff532c2fe4fe160018ee01f4..5dbc04785eb3302aeeda354e8091b7a8582af197 100644 (file)
@@ -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;
index 4748c8e7b30b1476c4a43970d6bd51df9ee9364a..beab3c106ecf9e53c4e75e313094af6f948aa9be 100644 (file)
@@ -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);
     }
index 6eb580068067d1db4e716c657b262a7bdc3265b6..37d03bd4944a5ee7d84e307fa6e5a9073a348516 100644 (file)
@@ -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;