#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
-
+#include <assert.h>
#define CMD_NOP 0
#define CMD_RES 1
#define CMD_BRK 2
-#define CMD_LOC 3
+#define CMD_CLR_BRK 3
+#define CMD_LOC 4
+#define CMD_STEP 5
+#define CMD_TRACE 6
+
+#define EVT_NOP 0
+#define EVT_BRK_HIT 1
+#define EVT_PAUSE 2
+#define EVT_RESPONSE 0xffffffff
struct msg_parse_ctx_t {
char *data;
};
static void send_response_header(debug_state_t *debug, unsigned int message_number) {
- unsigned int RESPONSE_HEADER = 0xffffffff;
+ unsigned int RESPONSE_HEADER = EVT_RESPONSE;
send(debug->client_fd, &RESPONSE_HEADER, 4, 0);
send(debug->client_fd, &message_number, 4, 0);
}
return buf;
}
+static void resume_thread(debug_thread_state_t *thread) {
+ thread->run_count = -1;
+ sem_post(&thread->wait_semaphore);
+}
+
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);
- printf("[INFO ] Recv command: %d\n", command_id);
+
+ // printf("[INFO ] Recv command: %d\n", command_id);
switch (command_id) {
case CMD_NOP: {
- // Returns: header
-
send_response_header(debug, msg_id);
break;
}
case CMD_RES: {
- // Returns: nothing
-
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) {
- // 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);
+ resume_thread(*thread);
resumed_a_thread = true;
}
}
}
case CMD_BRK: {
- //
- // Returns: header success:bool breakpoint_handle:u32
-
- char *filename = parse_string(debug, ctx);
- int line = parse_int(debug, ctx);
+ char *filename = parse_string(debug, ctx);
+ unsigned int line = parse_int(debug, ctx);
//
// TODO: This translation logic will have to be abstracted
debug_file_info_t file_info;
bool file_found = debug_info_lookup_file_by_name(debug->info, filename, &file_info);
if (!file_found) {
- goto send_error;
+ goto brk_send_error;
}
if (line > file_info.line_count) {
- goto send_error;
+ goto brk_send_error;
}
u32 instr;
line += 1;
if (line > file_info.line_count) {
- goto send_error;
+ goto brk_send_error;
}
}
printf("[INFO ] Setting breakpoint at %s:%d (%xd)\n", filename, line, instr);
+ 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_each(debug_thread_state_t *, thread, debug->threads) {
- bh_arr_push((*thread)->breakpoints, instr);
+ bh_arr_push((*thread)->breakpoints, bp);
}
send_response_header(debug, msg_id);
send_bool(debug, true);
- send_int(debug, 1); // TODO: This should be a unique breakpoint ID
+ send_int(debug, bp.id); // TODO: This should be a unique breakpoint ID
send_int(debug, line);
break;
- send_error:
+ brk_send_error:
send_response_header(debug, msg_id);
send_bool(debug, false);
send_int(debug, -1);
break;
}
+ case CMD_CLR_BRK: {
+ char *filename = parse_string(debug, ctx);
+
+ 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;
+ }
+
+ bh_arr_each(debug_thread_state_t *, thread, debug->threads) {
+ bh_arr_each(debug_breakpoint_t, bp, (*thread)->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((*thread)->breakpoints, bp - (*thread)->breakpoints);
+ bp--;
+ }
+ }
+ }
+
+ send_response_header(debug, msg_id);
+ send_bool(debug, true);
+ break;
+
+ clr_brk_send_error:
+ send_response_header(debug, msg_id);
+ send_bool(debug, false);
+ break;
+ }
+
case CMD_LOC: {
u32 thread_id = parse_int(debug, ctx);
send_int(debug, -1);
break;
}
+
+ case CMD_STEP: {
+ u32 granularity = parse_int(debug, ctx);
+ u32 thread_id = parse_int(debug, ctx);
+
+ if (granularity == 1) {
+ bh_arr_each(debug_thread_state_t *, thread, debug->threads) {
+ if ((*thread)->id == thread_id) {
+ (*thread)->pause_at_next_line = true;
+ resume_thread(*thread);
+ }
+ }
+ }
+
+ send_response_header(debug, msg_id);
+ 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);
+
+ debug_thread_state_t *thread = NULL;
+ bh_arr_each(debug_thread_state_t *, pthread, debug->threads) {
+ if ((*pthread)->id == thread_id) {
+ thread = *pthread;
+ break;
+ }
+ }
+
+ if (thread == NULL) {
+ send_response_header(debug, msg_id);
+ send_int(debug, 0);
+ break;
+ }
+
+ bh_arr(ovm_stack_frame_t) frames = thread->ovm_state->stack_frames;
+
+ send_response_header(debug, msg_id);
+ 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));
+ send_string(debug, func_info.name);
+
+ // :CopyPaste from CMD_LOC case
+ debug_loc_info_t loc_info;
+ debug_file_info_t file_info;
+
+ u32 instr;
+ if (frame == &bh_arr_last(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));
+
+ send_string(debug, file_info.name);
+ send_int(debug, loc_info.line);
+ }
+
+ break;
+ }
}
}
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];
+ u32 instr, bp_id = (*thread)->last_breakpoint_hit;
+ bh_arr_each(debug_breakpoint_t, bp, (*thread)->breakpoints) {
+ if (bp->id == bp_id) {
+ instr = bp->instr;
+ break;
+ }
+ }
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, EVT_BRK_HIT);
send_int(debug, bp_id);
send_int(debug, (*thread)->id);
}
if ((*thread)->state == debug_state_pausing) {
(*thread)->state = debug_state_paused;
- send_int(debug, 2);
+ send_int(debug, EVT_PAUSE);
send_int(debug, (*thread)->id);
+ send_int(debug, (*thread)->pause_reason);
}
}