memset(builder, 0, sizeof(*builder));
builder->info = info;
- bh_arr_new(bh_heap_allocator(), builder->symbol_scope_stack, 8);
}
void debug_info_builder_prepare(debug_info_builder_t *builder, u8 *data) {
builder->reader_offset = 0;
builder->current_file_id = 0;
builder->current_line = 0;
+ builder->current_scope = -1;
builder->next_file_line_offset = 0;
builder->remaining_reps = 0;
}
+static i32 debug_info_builder_push_scope(debug_info_builder_t *builder) {
+ debug_sym_scope_t scope;
+ scope.symbols = NULL;
+ bh_arr_new(builder->info->alloc, scope.symbols, 4);
+ scope.parent = builder->current_scope;
+
+ i32 scope_id = bh_arr_length(builder->info->symbol_scopes);
+ builder->current_scope = scope_id;
+
+ bh_arr_push(builder->info->symbol_scopes, scope);
+ return scope_id;
+}
+
+static i32 debug_info_builder_pop_scope(debug_info_builder_t *builder) {
+ if (builder->current_scope == -1) return -1;
+
+ debug_sym_scope_t *scope = &builder->info->symbol_scopes[builder->current_scope];
+ builder->current_scope = scope->parent;
+ return builder->current_scope;
+}
+
+static void debug_info_builder_add_symbol(debug_info_builder_t *builder, u32 sym_id) {
+ if (builder->current_scope == -1) return;
+
+ debug_sym_scope_t *scope = &builder->info->symbol_scopes[builder->current_scope];
+ bh_arr_push(scope->symbols, sym_id);
+}
+
static void debug_info_builder_parse(debug_info_builder_t *builder) {
u32 count = 0;
builder->current_file_id = uleb128_to_uint(builder->data, &builder->reader_offset);
builder->current_line = uleb128_to_uint(builder->data, &builder->reader_offset);
break;
- case 2: break;
- case 3: break;
+
+ case 2:
+ debug_info_builder_push_scope(builder);
+ break;
+
+ case 3:
+ debug_info_builder_pop_scope(builder);
+ break;
+
case 4:
- uleb128_to_uint(builder->data, &builder->reader_offset);
+ debug_info_builder_add_symbol(
+ builder,
+ uleb128_to_uint(builder->data, &builder->reader_offset));
break;
}
break;
debug_info_builder_parse(builder);
debug_loc_info_t info;
- info.file_id = builder->current_file_id;
- info.line = builder->current_line;
- info.symbols = 0;
+ info.file_id = builder->current_file_id;
+ info.line = builder->current_line;
+ info.symbol_scope = builder->current_scope;
bh_arr_push(builder->info->line_info, info);
debug_file_info_t *file_info = &builder->info->files[info.file_id];
#include <sys/socket.h>
#include <sys/un.h>
#include <assert.h>
+#include <poll.h>
#define CMD_NOP 0
#define CMD_CLR_BRK 3
#define CMD_STEP 5
#define CMD_TRACE 6
+#define CMD_THREADS 7
+#define CMD_VARS 8
#define EVT_NOP 0
#define EVT_BRK_HIT 1
#define EVT_PAUSE 2
+#define EVT_NEW_THREAD 3 // Not Implemented
#define EVT_RESPONSE 0xffffffff
struct msg_parse_ctx_t {
static void send_response_header(debug_state_t *debug, unsigned int message_number) {
unsigned int RESPONSE_HEADER = EVT_RESPONSE;
- send(debug->client_fd, &RESPONSE_HEADER, 4, 0);
- send(debug->client_fd, &message_number, 4, 0);
+ bh_buffer_write_u32(&debug->send_buffer, EVT_RESPONSE);
+ bh_buffer_write_u32(&debug->send_buffer, message_number);
}
static void send_string(debug_state_t *debug, const char *str) {
- unsigned int len;
if (!str) {
- len = 0;
- send(debug->client_fd, &len, 4, 0);
+ bh_buffer_write_u32(&debug->send_buffer, 0);
} else {
- len = strlen(str);
- send(debug->client_fd, &len, 4, 0);
- send(debug->client_fd, str, len, 0);
+ unsigned int len = strlen(str);
+ bh_buffer_write_u32(&debug->send_buffer, len);
+ bh_buffer_append(&debug->send_buffer, str, len);
}
}
static void send_bytes(debug_state_t *debug, const char *bytes, unsigned int len) {
- send(debug->client_fd, &len, 4, 0);
- send(debug->client_fd, bytes, len, 0);
+ bh_buffer_write_u32(&debug->send_buffer, len);
+ bh_buffer_append(&debug->send_buffer, bytes, len);
}
static void send_int(debug_state_t *debug, unsigned int x) {
- send(debug->client_fd, &x, 4, 0);
+ bh_buffer_write_u32(&debug->send_buffer, x);
}
static void send_bool(debug_state_t *debug, bool x) {
bool v = x ? 1 : 0;
- send(debug->client_fd, &v, 1, 0);
+ bh_buffer_write_byte(&debug->send_buffer, v);
}
static int parse_int(debug_state_t *debug, struct msg_parse_ctx_t *ctx) {
sem_post(&thread->wait_semaphore);
}
+static void get_stack_frame_location(debug_state_t *debug,
+ debug_func_info_t *func_info, debug_file_info_t *file_info, debug_loc_info_t *loc_info,
+ debug_thread_state_t *thread, ovm_stack_frame_t *frame) {
+
+ ovm_func_t *func = frame->func;
+
+ assert(debug_info_lookup_func(debug->info, func->id, func_info));
+
+ u32 instr;
+ if (frame == &bh_arr_last(thread->ovm_state->stack_frames)) {
+ instr = thread->ovm_state->pc;
+ } else {
+ instr = (frame + 1)->return_address;
+ }
+
+ while (!debug_info_lookup_location(debug->info, instr, loc_info))
+ instr++;
+
+ 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) {
#define ON_THREAD(tid) \
bh_arr_each(debug_thread_state_t *, thread, debug->threads) \
break;
}
- // The trace command should be probably eclipse
- // the loc command at some point?
case CMD_TRACE: {
unsigned int thread_id = parse_int(debug, ctx);
send_int(debug, bh_arr_length(frames));
bh_arr_rev_each(ovm_stack_frame_t, frame, frames) {
- ovm_func_t *func = frame->func;
-
debug_func_info_t func_info;
- assert(debug_info_lookup_func(debug->info, func->id, &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_string(debug, func_info.name);
+ send_string(debug, file_info.name);
+ send_int(debug, loc_info.line);
+ }
- debug_loc_info_t loc_info;
- debug_file_info_t file_info;
+ break;
+ }
- u32 instr;
- if (frame == &bh_arr_last(frames)) {
- instr = thread->ovm_state->pc;
- } else {
- instr = (frame + 1)->return_address;
+ case CMD_THREADS: {
+ bh_arr(debug_thread_state_t *) threads = debug->threads;
+
+ send_response_header(debug, msg_id);
+ send_int(debug, bh_arr_length(threads));
+
+ char buf[128];
+ bh_arr_each(debug_thread_state_t *, thread, threads) {
+ send_int(debug, (*thread)->id);
+
+ snprintf(buf, 128, "thread #%d", (*thread)->id);
+ send_string(debug, buf);
+ }
+
+ break;
+ }
+
+ case CMD_VARS: {
+ i32 stack_frame = parse_int(debug, ctx);
+ u32 thread_id = parse_int(debug, ctx);
+
+ 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;
}
- while (!debug_info_lookup_location(debug->info, instr, &loc_info))
- instr++;
+ ovm_stack_frame_t *frame = &frames[bh_arr_length(frames) - 1 - stack_frame];
- assert(debug_info_lookup_file(debug->info, loc_info.file_id, &file_info));
+ debug_func_info_t func_info;
+ debug_file_info_t file_info;
+ debug_loc_info_t loc_info;
- 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);
+
+ send_response_header(debug, msg_id);
+
+ i32 symbol_scope = loc_info.symbol_scope;
+ while (symbol_scope != -1) {
+ debug_sym_scope_t sym_scope = debug->info->symbol_scopes[symbol_scope];
+
+ bh_arr_each(u32, sym_id, sym_scope.symbols) {
+ debug_sym_info_t *sym = &debug->info->symbols[*sym_id];
+
+ send_int(debug, 0);
+ send_string(debug, sym->name);
+ send_string(debug, "???");
+ send_string(debug, "unknown type");
+ }
+
+ symbol_scope = sym_scope.parent;
+ }
+
+ send_int(debug, 1);
+ return;
}
+ vars_error:
+ send_response_header(debug, msg_id);
+ send_int(debug, 1);
break;
}
}
// Disable blocking reads and write in the client socket
// Alternatively, a MSG_DONTWAIT could be used below
fcntl(debug->client_fd, F_SETFL, O_NONBLOCK);
+ fcntl(debug->state_change_pipes[0], F_SETFL, O_NONBLOCK);
printf("[INFO ] Client connected\n");
+ bh_buffer_init(&debug->send_buffer, bh_heap_allocator(), 1024);
+
+ struct pollfd poll_fds[2];
+ poll_fds[0].fd = debug->state_change_pipes[0];
+ poll_fds[0].events = POLLIN;
+ poll_fds[1].fd = debug->client_fd;
+ poll_fds[1].events = POLLIN;
+
char command[4096];
while (debug->debug_thread_running) {
+ poll(poll_fds, 2, 1000);
+
//
// Try to read commands from the client.
// If an error was returned, bail out of this thread.
//
// Check the state of the running program and report any changes.
-
+
+ char buf;
+ int dummy = read(debug->state_change_pipes[0], &buf, 1);
+
bh_arr_each(debug_thread_state_t *, thread, debug->threads) {
if ((*thread)->state == debug_state_hit_breakpoint) {
(*thread)->state = debug_state_paused;
- u32 instr, bp_id = (*thread)->last_breakpoint_hit;
+ i32 instr = -1, bp_id = (*thread)->last_breakpoint_hit;
bh_arr_each(debug_breakpoint_t, bp, (*thread)->breakpoints) {
if (bp->id == bp_id) {
instr = bp->instr;
}
}
+ if (instr == -1) continue;
+
debug_loc_info_t loc_info;
debug_info_lookup_location(debug->info, instr, &loc_info);
send_int(debug, (*thread)->pause_reason);
}
}
-
+
+ send(debug->client_fd, debug->send_buffer.data, debug->send_buffer.length, 0);
+ bh_buffer_clear(&debug->send_buffer);
bh_arena_clear(&debug->tmp_arena);
}