#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
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;
}
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) {
// 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;
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);
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 };
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);
}
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) {
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) {
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);
}
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;
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');
frameIndex: number;
threadId: number;
variableChain: number[];
+ memoryLocation?: number;
}
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;
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;
})
};
});
}
+ if (v.memoryReference > 0) {
+ nv.memoryReference = v.memoryReference.toString();
+ }
+
return nv;
});
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);
}
type: string;
symId: number;
hasChildren: boolean;
+ memoryReference: number;
+}
+
+interface IReadMemory {
+ data: ArrayBuffer;
}
enum OVMCommand {
STEP = 5,
TRACE = 6,
THREADS = 7,
- VARS = 8
+ VARS = 8,
+ MEM_R = 9,
+ MEM_W = 10,
}
enum OVMEvent {
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);
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);
}
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;