added memory read/write to debugger
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Tue, 3 Jan 2023 03:02:28 +0000 (21:02 -0600)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Tue, 3 Jan 2023 03:02:28 +0000 (21:02 -0600)
interpreter/include/ovm_debug.h
interpreter/src/debug/debug_runtime_values.c
interpreter/src/debug/debug_thread.c
misc/vscode/out/ovmDebug.js
misc/vscode/ovmDebug.ts

index 07501a54751e4e1ed4d4892be68982f6d0e7900f..4302d086605e78f59e193c00d3bc8dd3ad3cb55c 100644 (file)
@@ -343,7 +343,6 @@ typedef struct debug_runtime_value_builder_t {
     u32 it_type;
     char *it_name;
     bool it_has_children; 
-
 } debug_runtime_value_builder_t;
 
 void debug_runtime_value_build_init(debug_runtime_value_builder_t *builder, bh_allocator alloc);
@@ -351,6 +350,7 @@ void debug_runtime_value_build_set_location(debug_runtime_value_builder_t *build
 void debug_runtime_value_build_descend(debug_runtime_value_builder_t *builder, u32 index);
 bool debug_runtime_value_build_step(debug_runtime_value_builder_t *builder);
 void debug_runtime_value_build_string(debug_runtime_value_builder_t *builder);
+u32  debug_runtime_value_get_it_addr(debug_runtime_value_builder_t *builder);
 void debug_runtime_value_build_clear(debug_runtime_value_builder_t *builder);
 void debug_runtime_value_build_free(debug_runtime_value_builder_t *builder);
 
index a11abcd291570ae3cdfacf7885ed3cf40c5529ce..bed7fb85aaeaea262f6ef042105b1346fda30f1b 100644 (file)
@@ -735,6 +735,36 @@ bool debug_runtime_value_build_step(debug_runtime_value_builder_t *builder) {
     return true;
 }
 
+u32 debug_runtime_value_get_it_addr(debug_runtime_value_builder_t *builder) {
+    if (builder->it_loc_kind == debug_sym_loc_register) {
+        debug_type_info_t *type = &builder->info->types[builder->it_type];
+
+        if (type->kind == debug_type_kind_slice) {
+            ovm_value_t value;
+            if (lookup_register_in_frame(builder->ovm_state, builder->ovm_frame, builder->it_loc, &value)) {
+                return value.u32;
+            }
+        }
+
+        return 0;
+    }
+
+    if (builder->it_loc_kind == debug_sym_loc_stack) {
+        u32 stack_ptr;
+        if (!lookup_stack_pointer(builder, &stack_ptr)) {
+            return 0;
+        }
+
+        return builder->it_loc + stack_ptr;
+    }
+
+    if (builder->it_loc_kind == debug_sym_loc_global) {
+        return builder->it_loc;
+    }
+
+    return 0;
+}
+
 void debug_runtime_value_build_string(debug_runtime_value_builder_t *builder) {
     if (builder->it_loc_kind == debug_sym_loc_register) {
         append_value_from_register(builder, builder->it_loc, builder->it_type);
index 176956475ec8d7a9eef99f7709fe6b5d479da2b5..52e8d948bf37c1f97586a66a739f0c607984716b 100644 (file)
@@ -18,6 +18,8 @@
 #define CMD_TRACE 6
 #define CMD_THREADS 7
 #define CMD_VARS 8
+#define CMD_MEM_R 9
+#define CMD_MEM_W 10
 
 #define EVT_NOP 0
 #define EVT_BRK_HIT 1
@@ -67,12 +69,12 @@ static int parse_int(debug_state_t *debug, struct msg_parse_ctx_t *ctx) {
     return i;
 }
 
-static char *parse_bytes(debug_state_t *debug, struct msg_parse_ctx_t *ctx) {
-    int len = parse_int(debug, ctx);
+static char *parse_bytes(debug_state_t *debug, struct msg_parse_ctx_t *ctx, u32 *len) {
+    *len = parse_int(debug, ctx);
 
-    char *buf = bh_alloc_array(debug->tmp_alloc, char, len);
-    memcpy(buf, &ctx->data[ctx->offset], len);
-    ctx->offset += len;
+    char *buf = bh_alloc_array(debug->tmp_alloc, char, *len);
+    memcpy(buf, &ctx->data[ctx->offset], *len);
+    ctx->offset += *len;
 
     return buf;
 }
@@ -114,330 +116,378 @@ static void get_stack_frame_location(debug_state_t *debug,
     assert(debug_info_lookup_file(debug->info, loc_info->file_id, file_info));
 }
 
-static void process_command(debug_state_t *debug, struct msg_parse_ctx_t *ctx) {
+
+
+//
+// Command handling
+//
+
+#define DEBUG_COMMAND_HANDLER(name) \
+    void name(debug_state_t *debug, struct msg_parse_ctx_t *ctx, u32 msg_id)
+
+typedef DEBUG_COMMAND_HANDLER((* debug_command_handler_t));
+
 #define ON_THREAD(tid) \
     bh_arr_each(debug_thread_state_t *, thread, debug->threads) \
         if ((*thread)->id == tid)
 
-    u32 msg_id     = parse_int(debug, ctx);
-    u32 command_id = parse_int(debug, ctx);
 
-    // printf("[INFO ] Recv command: %d\n", command_id);
+static DEBUG_COMMAND_HANDLER(debug_command_nop) {
+    send_response_header(debug, msg_id);
+}
 
-    switch (command_id) {
-        case CMD_NOP: {
-            send_response_header(debug, msg_id);
-            break;
+static DEBUG_COMMAND_HANDLER(debug_command_res) {
+    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) {
+        if (thread_id == 0xffffffff || (*thread)->id == thread_id) {
+            resume_thread(*thread);
+            resumed_a_thread = true;
         }
+    }
 
-        case CMD_RES: {
-            u32 thread_id = parse_int(debug, ctx);
+    send_response_header(debug, msg_id);
+    send_bool(debug, resumed_a_thread);
+}
 
-            bool resumed_a_thread = false;
+static DEBUG_COMMAND_HANDLER(debug_command_pause) {
+    u32 thread_id = parse_int(debug, ctx);
 
-            // Release the thread(s)
-            bh_arr_each(debug_thread_state_t *, thread, debug->threads) {
-                if (thread_id == 0xffffffff || (*thread)->id == thread_id) {
-                    resume_thread(*thread);
-                    resumed_a_thread = true;
-                }
-            }
+    ON_THREAD(thread_id) {
+        (*thread)->run_count = 0;
+    }
 
-            send_response_header(debug, msg_id);
-            send_bool(debug, resumed_a_thread);
-            break;
-        }
+    send_response_header(debug, msg_id);
+}
 
-        case CMD_PAUSE: {
-            u32 thread_id = parse_int(debug, ctx);
+static DEBUG_COMMAND_HANDLER(debug_command_brk) {
+    char    *filename = parse_string(debug, ctx);
+    unsigned int line = parse_int(debug, ctx);
 
-            ON_THREAD(thread_id) {
-                (*thread)->run_count = 0;
-            }
+    i32 instr = debug_info_lookup_instr_by_file_line(debug->info, filename, line);
+    if (instr < 0) goto brk_send_error;
 
-            send_response_header(debug, msg_id);
-            break;
-        }
+    printf("[INFO ] Setting breakpoint at %s:%d (%x)\n", filename, line, instr);
 
-        case CMD_BRK: {
-            char    *filename = parse_string(debug, ctx);
-            unsigned int line = parse_int(debug, ctx);
-
-            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_push(debug->breakpoints, bp);
-
-            send_response_header(debug, msg_id);
-            send_bool(debug, true);
-            send_int(debug, bp.id);
-            send_int(debug, line);
-            break;
+    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_push(debug->breakpoints, bp);
+
+    send_response_header(debug, msg_id);
+    send_bool(debug, true);
+    send_int(debug, bp.id);
+    send_int(debug, line);
+    return;
+
+  brk_send_error:
+    printf("[WARN ] Failed to set breakpoint at %s:%d (%x)\n", filename, line, instr);
+
+    send_response_header(debug, msg_id);
+    send_bool(debug, false);
+    send_int(debug, -1);
+    send_int(debug, 0);
+}
 
-          brk_send_error:
-            printf("[WARN ] Failed to set breakpoint at %s:%d (%x)\n", filename, line, instr);
+static DEBUG_COMMAND_HANDLER(debug_command_clr_brk) {
+    char *filename = parse_string(debug, ctx);
 
-            send_response_header(debug, msg_id);
-            send_bool(debug, false);
-            send_int(debug, -1);
-            send_int(debug, 0);
-            break;
-        }
+    debug_file_info_t file_info;
+    bool file_found = debug_info_lookup_file_by_name(debug->info, filename, &file_info);
+    if (!file_found) {
+        goto clr_brk_send_error;
+    }
 
-        case CMD_CLR_BRK: {
-            char *filename = parse_string(debug, ctx);
+    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--;
+        }
+    }
 
-            debug_file_info_t file_info;
-            bool file_found = debug_info_lookup_file_by_name(debug->info, filename, &file_info);
-            if (!file_found) {
-                goto clr_brk_send_error;
-            }
+    send_response_header(debug, msg_id);
+    send_bool(debug, true);
+    return;
 
-            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--;
-                }
-            }
+  clr_brk_send_error:
+    send_response_header(debug, msg_id);
+    send_bool(debug, false);
+}
 
-            send_response_header(debug, msg_id);
-            send_bool(debug, true);
-            break;
+static DEBUG_COMMAND_HANDLER(debug_command_step) {
+    u32 granularity = parse_int(debug, ctx);
+    u32 thread_id = parse_int(debug, ctx);
+    
+    if (granularity == 1) {
+        ON_THREAD(thread_id) {
+            (*thread)->pause_at_next_line = true;
+            (*thread)->pause_within = -1;
+            resume_thread(*thread);
+        }
+    }
 
-          clr_brk_send_error:
-            send_response_header(debug, msg_id);
-            send_bool(debug, false);
-            break;
+    if (granularity == 2) {
+        ON_THREAD(thread_id) {
+            (*thread)->run_count = 1;
+            resume_thread(*thread);
         }
+    }
 
-        case CMD_STEP: {
-            u32 granularity = parse_int(debug, ctx);
-            u32 thread_id = parse_int(debug, ctx);
-            
-            if (granularity == 1) {
-                ON_THREAD(thread_id) {
-                    (*thread)->pause_at_next_line = true;
-                    (*thread)->pause_within = -1;
-                    resume_thread(*thread);
-                }
-            }
+    if (granularity == 3) {
+        ON_THREAD(thread_id) {
+            ovm_stack_frame_t *last_frame = &bh_arr_last((*thread)->ovm_state->stack_frames);
+            (*thread)->pause_at_next_line = true;
+            (*thread)->pause_within = last_frame->func->id;
+            (*thread)->extra_frames_since_last_pause = 0;
+            resume_thread(*thread);
+        }
+    }
 
-            if (granularity == 2) {
-                ON_THREAD(thread_id) {
-                    (*thread)->run_count = 1;
-                    resume_thread(*thread);
-                }
+    if (granularity == 4) {
+        ON_THREAD(thread_id) {
+            if (bh_arr_length((*thread)->ovm_state->stack_frames) == 1) {
+                (*thread)->pause_within = -1;
+            } else {
+                ovm_stack_frame_t *last_frame = &bh_arr_last((*thread)->ovm_state->stack_frames);
+                (*thread)->pause_within = (last_frame - 1)->func->id;
             }
 
-            if (granularity == 3) {
-                ON_THREAD(thread_id) {
-                    ovm_stack_frame_t *last_frame = &bh_arr_last((*thread)->ovm_state->stack_frames);
-                    (*thread)->pause_at_next_line = true;
-                    (*thread)->pause_within = last_frame->func->id;
-                    (*thread)->extra_frames_since_last_pause = 0;
-                    resume_thread(*thread);
-                }
-            }
+            (*thread)->pause_at_next_line = true;
+            (*thread)->extra_frames_since_last_pause = 0;
+            resume_thread(*thread);
+        }
+    }
 
-            if (granularity == 4) {
-                ON_THREAD(thread_id) {
-                    if (bh_arr_length((*thread)->ovm_state->stack_frames) == 1) {
-                        (*thread)->pause_within = -1;
-                    } else {
-                        ovm_stack_frame_t *last_frame = &bh_arr_last((*thread)->ovm_state->stack_frames);
-                        (*thread)->pause_within = (last_frame - 1)->func->id;
-                    }
+    send_response_header(debug, msg_id);
+}
 
-                    (*thread)->pause_at_next_line = true;
-                    (*thread)->extra_frames_since_last_pause = 0;
-                    resume_thread(*thread);
-                }
-            }
+static DEBUG_COMMAND_HANDLER(debug_command_trace) {
+    unsigned int thread_id = parse_int(debug, ctx);
 
-            send_response_header(debug, msg_id);
+    debug_thread_state_t *thread = NULL;
+    bh_arr_each(debug_thread_state_t *, pthread, debug->threads) {
+        if ((*pthread)->id == thread_id) {
+            thread = *pthread;
             break;
         }
+    }
 
-        case CMD_TRACE: {
-            unsigned int thread_id = parse_int(debug, ctx);
+    if (thread == NULL) {
+        send_response_header(debug, msg_id);
+        send_int(debug, 0);
+        return;
+    }
 
-            debug_thread_state_t *thread = NULL;
-            bh_arr_each(debug_thread_state_t *, pthread, debug->threads) {
-                if ((*pthread)->id == thread_id) {
-                    thread = *pthread;
-                    break;
-                }
-            }
+    bh_arr(ovm_stack_frame_t) frames = thread->ovm_state->stack_frames;
 
-            if (thread == NULL) {
-                send_response_header(debug, msg_id);
-                send_int(debug, 0);
-                break;
-            }
+    send_response_header(debug, msg_id);
+    send_int(debug, bh_arr_length(frames));
 
-            bh_arr(ovm_stack_frame_t) frames = thread->ovm_state->stack_frames;
+    bh_arr_rev_each(ovm_stack_frame_t, frame, frames) {
+        debug_func_info_t func_info;
+        debug_file_info_t file_info;
+        debug_loc_info_t  loc_info;
 
-            send_response_header(debug, msg_id);
-            send_int(debug, bh_arr_length(frames));
+        get_stack_frame_location(debug, &func_info, &file_info, &loc_info, thread, frame);
 
-            bh_arr_rev_each(ovm_stack_frame_t, frame, frames) {
-                debug_func_info_t func_info;
-                debug_file_info_t file_info;
-                debug_loc_info_t  loc_info;
+        send_string(debug, func_info.name);
+        send_string(debug, file_info.name);
+        send_int(debug, loc_info.line);
+    }
+}
 
-                get_stack_frame_location(debug, &func_info, &file_info, &loc_info, thread, frame);
+static DEBUG_COMMAND_HANDLER(debug_command_threads) {
+    bh_arr(debug_thread_state_t *) threads = debug->threads;
 
-                send_string(debug, func_info.name);
-                send_string(debug, file_info.name);
-                send_int(debug, loc_info.line);
-            }
+    send_response_header(debug, msg_id);
+    send_int(debug, bh_arr_length(threads));
 
-            break;
-        }
+    char buf[128];
+    bh_arr_each(debug_thread_state_t *, thread, threads) {
+        send_int(debug, (*thread)->id);
 
-        case CMD_THREADS: {
-            bh_arr(debug_thread_state_t *) threads = debug->threads;
+        snprintf(buf, 128, "thread #%d", (*thread)->id);
+        send_string(debug, buf);
+    }
+}
 
-            send_response_header(debug, msg_id);
-            send_int(debug, bh_arr_length(threads));
+static DEBUG_COMMAND_HANDLER(debug_command_vars) {
+    i32 stack_frame = parse_int(debug, ctx);
+    u32 thread_id   = parse_int(debug, ctx);
+    u32 layers      = parse_int(debug, ctx);
 
-            char buf[128];
-            bh_arr_each(debug_thread_state_t *, thread, threads) {
-                send_int(debug, (*thread)->id);
+    debug_thread_state_t **thread = NULL;
+    bh_arr_each(debug_thread_state_t *, t, debug->threads)
+        if ((*t)->id == thread_id)
+            thread = t;
 
-                snprintf(buf, 128, "thread #%d", (*thread)->id);
-                send_string(debug, buf);
-            }
+    if (thread == NULL) {
+        goto vars_error;
+    }
 
-            break;
-        }
+    bh_arr(ovm_stack_frame_t) frames = (*thread)->ovm_state->stack_frames;
+    if (stack_frame >= bh_arr_length(frames)) {
+        goto vars_error;
+    }
 
-        case CMD_VARS: {
-            i32 stack_frame = parse_int(debug, ctx);
-            u32 thread_id   = parse_int(debug, ctx);
-            u32 layers      = parse_int(debug, ctx);
+    ovm_stack_frame_t *frame = &frames[bh_arr_length(frames) - 1 - stack_frame];
 
-            ON_THREAD(thread_id) {
-                bh_arr(ovm_stack_frame_t) frames = (*thread)->ovm_state->stack_frames;
-                if (stack_frame >= bh_arr_length(frames)) {
-                    goto vars_error;
-                }
+    debug_func_info_t func_info;
+    debug_file_info_t file_info;
+    debug_loc_info_t  loc_info;
 
-                ovm_stack_frame_t *frame = &frames[bh_arr_length(frames) - 1 - stack_frame];
+    get_stack_frame_location(debug, &func_info, &file_info, &loc_info, *thread, frame);
 
-                debug_func_info_t func_info;
-                debug_file_info_t file_info;
-                debug_loc_info_t  loc_info;
-
-                get_stack_frame_location(debug, &func_info, &file_info, &loc_info, *thread, frame);
-
-                send_response_header(debug, msg_id);
-
-                debug_runtime_value_builder_t builder;
-                builder.state = debug;
-                builder.info = debug->info;
-                builder.ovm_state = (*thread)->ovm_state;
-                builder.ovm_frame = frame;
-                builder.func_info = func_info;
-                builder.file_info = file_info;
-                builder.loc_info = loc_info;
-                debug_runtime_value_build_init(&builder, bh_heap_allocator());
-
-                //
-                // The first layer specified is the symbol id to drill into.
-                // Therefore, the first layer is peeled off here before the
-                // following while loop. This makes the assumption that no
-                // symbol will have the id 0xffffffff. This is probably safe
-                // to assume, especially since just one more symbol and this
-                // whole system crashes...
-                u32 sym_id_to_match = 0xffffffff;
-                if (layers > 0) {
-                    sym_id_to_match = parse_int(debug, ctx);
-                    layers--;
+    send_response_header(debug, msg_id);
+
+    debug_runtime_value_builder_t builder;
+    builder.state = debug;
+    builder.info = debug->info;
+    builder.ovm_state = (*thread)->ovm_state;
+    builder.ovm_frame = frame;
+    builder.func_info = func_info;
+    builder.file_info = file_info;
+    builder.loc_info = loc_info;
+    debug_runtime_value_build_init(&builder, bh_heap_allocator());
+
+    //
+    // The first layer specified is the symbol id to drill into.
+    // Therefore, the first layer is peeled off here before the
+    // following while loop. This makes the assumption that no
+    // symbol will have the id 0xffffffff. This is probably safe
+    // to assume, especially since just one more symbol and this
+    // whole system crashes...
+    u32 sym_id_to_match = 0xffffffff;
+    if (layers > 0) {
+        sym_id_to_match = parse_int(debug, ctx);
+        layers--;
+    }
+
+    i32 symbol_scope = loc_info.symbol_scope;
+    while (symbol_scope != -1) {
+        debug_sym_scope_t sym_scope = debug->info->symbol_scopes[symbol_scope];
+        builder.sym_scope = sym_scope;
+
+        bh_arr_each(u32, sym_id, sym_scope.symbols) {
+            debug_sym_info_t *sym = &debug->info->symbols[*sym_id];
+            debug_runtime_value_build_set_location(&builder, sym->loc_kind, sym->loc, sym->type, sym->name);
+
+            //
+            // If we are drilling to a particular symbol, and this is that symbol,
+            // we have to do the generation a little differently. We first have to
+            // pull the other layer queries in, and descend into those layers.
+            // Then, we loop through each value at that layer and print their values.
+            if (sym->sym_id == sym_id_to_match && sym_id_to_match != 0xffffffff) {
+                while (layers--) {
+                    u32 desc = parse_int(debug, ctx);
+                    debug_runtime_value_build_descend(&builder, desc);
                 }
 
-                i32 symbol_scope = loc_info.symbol_scope;
-                while (symbol_scope != -1) {
-                    debug_sym_scope_t sym_scope = debug->info->symbol_scopes[symbol_scope];
-                    builder.sym_scope = sym_scope;
-
-                    bh_arr_each(u32, sym_id, sym_scope.symbols) {
-                        debug_sym_info_t *sym = &debug->info->symbols[*sym_id];
-                        debug_runtime_value_build_set_location(&builder, sym->loc_kind, sym->loc, sym->type, sym->name);
-
-                        //
-                        // If we are drilling to a particular symbol, and this is that symbol,
-                        // we have to do the generation a little differently. We first have to
-                        // pull the other layer queries in, and descend into those layers.
-                        // Then, we loop through each value at that layer and print their values.
-                        if (sym->sym_id == sym_id_to_match && sym_id_to_match != 0xffffffff) {
-                            while (layers--) {
-                                u32 desc = parse_int(debug, ctx);
-                                debug_runtime_value_build_descend(&builder, desc);
-                            }
-
-                            while (debug_runtime_value_build_step(&builder)) {
-                                debug_runtime_value_build_string(&builder);
-                                debug_type_info_t *type = &debug->info->types[builder.it_type];
-
-                                send_int(debug, 0);
-                                send_string(debug, builder.it_name);
-                                send_bytes(debug, builder.output.data, builder.output.length);
-                                send_string(debug, type->name);
-                                send_int(debug, builder.it_index - 1); // CLEANUP This should be 0 indexed, but because this is after the while loop condition, it is 1 indexed.
-                                send_bool(debug, builder.it_has_children);
-
-                                debug_runtime_value_build_clear(&builder);
-                            }
-                            
-                            // This is important, as when doing a layered query, only one symbol
-                            // should be considered, and once found, should immediate stop.
-                            goto syms_done;
-
-                        } else if (sym_id_to_match == 0xffffffff) {
-                            // Otherwise, we simply print the value of the symbol as is.
-                            debug_type_info_t *type = &debug->info->types[sym->type];
-
-                            debug_runtime_value_build_string(&builder);
-
-                            send_int(debug, 0);
-                            send_string(debug, sym->name);
-                            send_bytes(debug, builder.output.data, builder.output.length);
-                            send_string(debug, type->name);
-                            send_int(debug, sym->sym_id);
-                            send_bool(debug, builder.it_has_children);
-
-                            debug_runtime_value_build_clear(&builder);
-                        }
-                    }
+                while (debug_runtime_value_build_step(&builder)) {
+                    debug_runtime_value_build_string(&builder);
+                    debug_type_info_t *type = &debug->info->types[builder.it_type];
 
-                    symbol_scope = sym_scope.parent;
+                    send_int(debug, 0);
+                    send_string(debug, builder.it_name);
+                    send_bytes(debug, builder.output.data, builder.output.length);
+                    send_string(debug, type->name);
+                    send_int(debug, builder.it_index - 1); // CLEANUP This should be 0 indexed, but because this is after the while loop condition, it is 1 indexed.
+                    send_bool(debug, builder.it_has_children);
+                    send_int(debug, debug_runtime_value_get_it_addr(&builder));
+
+                    debug_runtime_value_build_clear(&builder);
                 }
                 
-              syms_done:
-                send_int(debug, 1);
-                debug_runtime_value_build_free(&builder);
-                return;
-            }
+                // This is important, as when doing a layered query, only one symbol
+                // should be considered, and once found, should immediate stop.
+                goto syms_done;
 
-          vars_error:
-            send_response_header(debug, msg_id);
-            send_int(debug, 1);
-            break;
+            } else if (sym_id_to_match == 0xffffffff) {
+                // Otherwise, we simply print the value of the symbol as is.
+                debug_type_info_t *type = &debug->info->types[sym->type];
+
+                debug_runtime_value_build_string(&builder);
+
+                send_int(debug, 0);
+                send_string(debug, sym->name);
+                send_bytes(debug, builder.output.data, builder.output.length);
+                send_string(debug, type->name);
+                send_int(debug, sym->sym_id);
+                send_bool(debug, builder.it_has_children);
+                send_int(debug, debug_runtime_value_get_it_addr(&builder));
+
+                debug_runtime_value_build_clear(&builder);
+            }
         }
+
+        symbol_scope = sym_scope.parent;
+    }
+        
+  syms_done:
+    send_int(debug, 1);
+    debug_runtime_value_build_free(&builder);
+    return;
+
+  vars_error:
+    send_response_header(debug, msg_id);
+    send_int(debug, 1);
+}
+
+static DEBUG_COMMAND_HANDLER(debug_command_memory_read) {
+    u32 addr = parse_int(debug, ctx);
+    u32 count = parse_int(debug, ctx);
+
+    count = bh_min(count, 2048);
+
+    send_response_header(debug, msg_id);
+    send_bytes(debug, bh_pointer_add(debug->ovm_engine->memory, addr), count);
+}
+
+static DEBUG_COMMAND_HANDLER(debug_command_memory_write) {
+    u32 addr = parse_int(debug, ctx);
+    u32 count;
+
+    u8 *data = parse_bytes(debug, ctx, &count);
+    memcpy(bh_pointer_add(debug->ovm_engine->memory, addr), data, count);
+
+    send_response_header(debug, msg_id);
+    send_int(debug, count);
+}
+
+static debug_command_handler_t command_handlers[] = {
+    [CMD_NOP]     = debug_command_nop,
+    [CMD_RES]     = debug_command_res,
+    [CMD_PAUSE]   = debug_command_pause,
+    [CMD_BRK]     = debug_command_brk,
+    [CMD_CLR_BRK] = debug_command_clr_brk,
+    [CMD_STEP]    = debug_command_step,
+    [CMD_TRACE]   = debug_command_trace,
+    [CMD_THREADS] = debug_command_threads,
+    [CMD_VARS]    = debug_command_vars,
+    [CMD_MEM_R]   = debug_command_memory_read,
+    [CMD_MEM_W]   = debug_command_memory_write,
+};
+
+static void process_command(debug_state_t *debug, struct msg_parse_ctx_t *ctx) {
+    u32 msg_id     = parse_int(debug, ctx);
+    u32 command_id = parse_int(debug, ctx);
+
+    if (command_id >= sizeof(command_handlers) / sizeof(command_handlers[0])) {
+        send_response_header(debug, msg_id);
+        return;
     }
+
+    command_handlers[command_id](debug, ctx, msg_id);
 }
 
 static void process_message(debug_state_t *debug, char *msg, unsigned int bytes_read) {
index 058e3dcd16750f2a5e7b4e1c09ea27b2ab4d3d4e..f3812dd9092a515caf6c103c01b65377f079d1be 100644 (file)
@@ -89,12 +89,12 @@ class OVMDebugSession extends debugadapter_1.LoggingDebugSession {
         // make VS Code send setExpression request
         response.body.supportsSetExpression = false;
         // make VS Code send disassemble request
-        response.body.supportsDisassembleRequest = false;
+        response.body.supportsDisassembleRequest = true;
         response.body.supportsSteppingGranularity = true;
         response.body.supportsInstructionBreakpoints = false;
         // make VS Code able to read and write variable memory
-        response.body.supportsReadMemoryRequest = false;
-        response.body.supportsWriteMemoryRequest = false;
+        response.body.supportsReadMemoryRequest = true;
+        response.body.supportsWriteMemoryRequest = true;
         response.body.supportSuspendDebuggee = false;
         response.body.supportTerminateDebuggee = true;
         response.body.supportsFunctionBreakpoints = true;
@@ -157,7 +157,9 @@ class OVMDebugSession extends debugadapter_1.LoggingDebugSession {
                         threadId: args.threadId,
                         frameIndex: i
                     });
-                    return new debugadapter_1.StackFrame(frameRef, f.funcname, source, f.line);
+                    let stack_frame = new debugadapter_1.StackFrame(frameRef, f.funcname, source, f.line);
+                    stack_frame.instructionPointerReference = "1234";
+                    return stack_frame;
                 })
             };
             this.sendResponse(response);
@@ -193,6 +195,9 @@ class OVMDebugSession extends debugadapter_1.LoggingDebugSession {
                 if (v.hasChildren) {
                     nv.variablesReference = this._variableReferences.create(Object.assign(Object.assign({}, frameRef), { variableChain: frameRef.variableChain.concat([v.symId]) }));
                 }
+                if (v.memoryReference > 0) {
+                    nv.memoryReference = v.memoryReference.toString();
+                }
                 return nv;
             });
             response.body = { variables: vs };
@@ -263,6 +268,40 @@ class OVMDebugSession extends debugadapter_1.LoggingDebugSession {
         this.debugger.step("line", args.threadId);
         this.sendResponse(response);
     }
+    disassembleRequest(response, args, request) {
+        console.log(args);
+        response.body = {
+            instructions: [
+                {
+                    address: "0",
+                    instruction: "i32.add %3, %1, %2",
+                }
+            ]
+        };
+        this.sendResponse(response);
+    }
+    readMemoryRequest(response, args, request) {
+        return __awaiter(this, void 0, void 0, function* () {
+            let addr = parseInt(args.memoryReference) + args.offset;
+            let mem = yield this.debugger.read_memory(addr, args.count);
+            response.body = {
+                address: addr.toString(),
+                data: Buffer.from(mem.data).toString("base64"),
+            };
+            this.sendResponse(response);
+        });
+    }
+    writeMemoryRequest(response, args, request) {
+        return __awaiter(this, void 0, void 0, function* () {
+            let addr = parseInt(args.memoryReference) + args.offset;
+            let data = Buffer.from(args.data, "base64");
+            let bytesWritten = yield this.debugger.write_memory(addr, data);
+            response.body = {
+                bytesWritten: bytesWritten,
+            };
+            this.sendResponse(response);
+        });
+    }
     fileNameToShortName(filename) {
         return filename.substring(filename.lastIndexOf("/") + 1);
     }
@@ -279,6 +318,8 @@ var OVMCommand;
     OVMCommand[OVMCommand["TRACE"] = 6] = "TRACE";
     OVMCommand[OVMCommand["THREADS"] = 7] = "THREADS";
     OVMCommand[OVMCommand["VARS"] = 8] = "VARS";
+    OVMCommand[OVMCommand["MEM_R"] = 9] = "MEM_R";
+    OVMCommand[OVMCommand["MEM_W"] = 10] = "MEM_W";
 })(OVMCommand || (OVMCommand = {}));
 var OVMEvent;
 (function (OVMEvent) {
@@ -434,6 +475,35 @@ class OVMDebugger extends EventEmitter {
         this.pending_responses[cmd_id] = OVMCommand.VARS;
         return this.preparePromise(cmd_id);
     }
+    read_memory(addr, count) {
+        if (this.client == null)
+            return Promise.resolve({});
+        let data = new ArrayBuffer(16);
+        let view = new DataView(data);
+        let cmd_id = this.next_command_id;
+        view.setUint32(0, cmd_id, true);
+        view.setUint32(4, OVMCommand.MEM_R, true);
+        view.setUint32(8, addr, true);
+        view.setUint32(12, count, true);
+        this.client.write(new Uint8Array(data));
+        this.pending_responses[cmd_id] = OVMCommand.MEM_R;
+        return this.preparePromise(cmd_id);
+    }
+    write_memory(addr, data_to_write) {
+        if (this.client == null)
+            return Promise.resolve(0);
+        let data = new ArrayBuffer(16 + data_to_write.byteLength);
+        let view = new DataView(data);
+        let cmd_id = this.next_command_id;
+        view.setUint32(0, cmd_id, true);
+        view.setUint32(4, OVMCommand.MEM_W, true);
+        view.setUint32(8, addr, true);
+        view.setUint32(12, data_to_write.byteLength, true);
+        new Uint8Array(data).set(new Uint8Array(data_to_write), 16);
+        this.client.write(new Uint8Array(data));
+        this.pending_responses[cmd_id] = OVMCommand.MEM_W;
+        return this.preparePromise(cmd_id);
+    }
     parseIncoming(data) {
         let parser = new DataParser(data);
         while (parser.offset != data.length) {
@@ -534,11 +604,22 @@ class OVMDebugger extends EventEmitter {
                     let type = parser.parseString();
                     let symId = parser.parseUint32();
                     let hasChildren = parser.parseBool();
-                    result.push({ name, value, type, symId, hasChildren });
+                    let memoryReference = parser.parseUint32();
+                    result.push({ name, value, type, symId, hasChildren, memoryReference });
                 }
                 this.resolvePromise(msg_id, result);
                 break;
             }
+            case OVMCommand.MEM_R: {
+                let data = parser.parseBytes();
+                this.resolvePromise(msg_id, { data: data });
+                break;
+            }
+            case OVMCommand.MEM_W: {
+                let count = parser.parseUint32();
+                this.resolvePromise(msg_id, count);
+                break;
+            }
             default:
             // console.log("Unrecognized command. ", cmd_id, msg_id);
         }
@@ -601,6 +682,12 @@ class DataParser {
         this.offset += len;
         return str;
     }
+    parseBytes() {
+        let len = this.parseUint32();
+        let result = this.data.buffer.slice(this.offset, this.offset + len);
+        this.offset += len;
+        return result;
+    }
     parseBool() {
         if (this.offset >= this.data.length)
             return false;
index 940f68c628cf734a88fd3676077fe1133d459425..b6680210aa17ecdc766eee580b3439af436ccdeb 100644 (file)
@@ -3,7 +3,7 @@ import {
        LoggingDebugSession,
        InitializedEvent, TerminatedEvent, StoppedEvent, BreakpointEvent, OutputEvent,
        ProgressStartEvent, ProgressUpdateEvent, ProgressEndEvent, InvalidatedEvent,
-       Thread, StackFrame, Scope, Source, Handles, Breakpoint, MemoryEvent, ThreadEvent, LoadedSourceEvent, Variable
+       Thread, StackFrame, Scope, Source, Handles, Breakpoint, MemoryEvent, ThreadEvent, LoadedSourceEvent, Variable,
 } from '@vscode/debugadapter';
 import { DebugProtocol } from '@vscode/debugprotocol';
 import EventEmitter = require('node:events');
@@ -36,6 +36,7 @@ interface IVariableReference {
        frameIndex: number;
        threadId: number;
        variableChain: number[];
+       memoryLocation?: number;
 }
 
 export class OVMDebugSession extends LoggingDebugSession {
@@ -145,13 +146,13 @@ export class OVMDebugSession extends LoggingDebugSession {
                response.body.supportsSetExpression = false;
 
                // make VS Code send disassemble request
-               response.body.supportsDisassembleRequest = false;
+               response.body.supportsDisassembleRequest = true;
                response.body.supportsSteppingGranularity = true;
                response.body.supportsInstructionBreakpoints = false;
 
                // make VS Code able to read and write variable memory
-               response.body.supportsReadMemoryRequest = false;
-               response.body.supportsWriteMemoryRequest = false;
+               response.body.supportsReadMemoryRequest = true;
+               response.body.supportsWriteMemoryRequest = true;
 
                response.body.supportSuspendDebuggee = false;
                response.body.supportTerminateDebuggee = true;
@@ -235,7 +236,11 @@ export class OVMDebugSession extends LoggingDebugSession {
                                        threadId: args.threadId,
                                        frameIndex: i
                                });
-                               return new StackFrame(frameRef, f.funcname, source, f.line);
+
+                               let stack_frame = new StackFrame(frameRef, f.funcname, source, f.line);
+                               stack_frame.instructionPointerReference = "1234";
+                               
+                               return stack_frame;
                        })
                };
 
@@ -283,6 +288,10 @@ export class OVMDebugSession extends LoggingDebugSession {
                                        });
                                }
 
+                               if (v.memoryReference > 0) {
+                                       nv.memoryReference = v.memoryReference.toString();
+                               }
+
                                return nv;
                        });
 
@@ -366,6 +375,48 @@ export class OVMDebugSession extends LoggingDebugSession {
                this.sendResponse(response);
        }
 
+       protected disassembleRequest(response: DebugProtocol.DisassembleResponse, args: DebugProtocol.DisassembleArguments, request?: DebugProtocol.Request): void {
+               console.log(args);
+
+               response.body = {
+                       instructions: [
+                               {
+                                       address: "0",
+                                       instruction: "i32.add %3, %1, %2",
+                               }
+                       ]
+               };
+
+               this.sendResponse(response);
+       }
+
+       protected async readMemoryRequest(response: DebugProtocol.ReadMemoryResponse, args: DebugProtocol.ReadMemoryArguments, request?: DebugProtocol.Request): Promise<void> {
+               let addr = parseInt(args.memoryReference) + args.offset;
+
+               let mem = await this.debugger.read_memory(addr, args.count);
+
+               response.body = {
+                       address: addr.toString(),
+                       data: Buffer.from(mem.data).toString("base64"),
+               };
+
+               this.sendResponse(response);
+       }
+
+       protected async writeMemoryRequest(response: DebugProtocol.WriteMemoryResponse, args: DebugProtocol.WriteMemoryArguments, request?: DebugProtocol.Request): Promise<void> {
+               let addr = parseInt(args.memoryReference) + args.offset;
+
+               let data = Buffer.from(args.data, "base64");
+
+               let bytesWritten = await this.debugger.write_memory(addr, data);
+
+               response.body = {
+                       bytesWritten: bytesWritten,
+               };
+
+               this.sendResponse(response);
+       }
+
        private fileNameToShortName(filename: string): string {
                return filename.substring(filename.lastIndexOf("/") + 1);
        }
@@ -394,6 +445,11 @@ interface IVariableInfo {
        type: string;
        symId: number;
        hasChildren: boolean;
+       memoryReference: number;
+}
+
+interface IReadMemory {
+       data: ArrayBuffer;
 }
 
 enum OVMCommand {
@@ -405,7 +461,9 @@ enum OVMCommand {
        STEP    = 5,
        TRACE   = 6,
        THREADS = 7,
-       VARS    = 8
+       VARS    = 8,
+       MEM_R   = 9,
+       MEM_W   = 10,
 }
 
 enum OVMEvent {
@@ -612,6 +670,48 @@ class OVMDebugger extends EventEmitter {
                return this.preparePromise(cmd_id);
        }
 
+       read_memory(addr: number, count: number): Promise<IReadMemory> {
+               if (this.client == null) return Promise.resolve({} as IReadMemory);
+
+        let data = new ArrayBuffer(16);
+        let view = new DataView(data);
+
+        let cmd_id = this.next_command_id;
+
+        view.setUint32(0, cmd_id, true);
+        view.setUint32(4, OVMCommand.MEM_R, true);
+        view.setUint32(8, addr, true);
+        view.setUint32(12, count, true);
+
+        this.client.write(new Uint8Array(data));
+
+        this.pending_responses[cmd_id] = OVMCommand.MEM_R;
+
+               return this.preparePromise(cmd_id);
+       }
+
+       write_memory(addr: number, data_to_write: ArrayBuffer): Promise<number> {
+               if (this.client == null) return Promise.resolve(0);
+
+        let data = new ArrayBuffer(16 + data_to_write.byteLength);
+        let view = new DataView(data);
+
+        let cmd_id = this.next_command_id;
+
+        view.setUint32(0, cmd_id, true);
+        view.setUint32(4, OVMCommand.MEM_W, true);
+        view.setUint32(8, addr, true);
+        view.setUint32(12, data_to_write.byteLength, true);
+
+               new Uint8Array(data).set(new Uint8Array(data_to_write), 16);
+
+        this.client.write(new Uint8Array(data));
+
+        this.pending_responses[cmd_id] = OVMCommand.MEM_W;
+
+               return this.preparePromise(cmd_id);
+       }
+
        private parseIncoming(data: Buffer): void {
                let parser = new DataParser(data);
 
@@ -732,13 +832,28 @@ class OVMDebugger extends EventEmitter {
                                        let type  = parser.parseString();
                                        let symId    = parser.parseUint32();
                                        let hasChildren = parser.parseBool();
-                                       result.push({name, value, type, symId, hasChildren});
+                                       let memoryReference = parser.parseUint32();
+                                       result.push({name, value, type, symId, hasChildren, memoryReference});
                                }
 
                                this.resolvePromise(msg_id, result);
                                break;
                        }
 
+                       case OVMCommand.MEM_R: {
+                               let data = parser.parseBytes();
+
+                               this.resolvePromise(msg_id, { data: data });
+                               break;
+                       }
+
+                       case OVMCommand.MEM_W: {
+                               let count = parser.parseUint32();
+
+                               this.resolvePromise(msg_id, count);
+                               break;
+                       }
+
                        default:
                                // console.log("Unrecognized command. ", cmd_id, msg_id);
                }
@@ -818,6 +933,14 @@ class DataParser {
         return str;
     }
 
+       parseBytes(): ArrayBuffer {
+        let len      = this.parseUint32();
+               let result   = this.data.buffer.slice(this.offset, this.offset + len);
+               this.offset += len;
+
+               return result;
+       }
+
     parseBool() {
                if (this.offset >= this.data.length) return false;