diff --git a/build-scripts/runtime_lib.cmake b/build-scripts/runtime_lib.cmake index 513a0a6c2b..e7f7860cfc 100644 --- a/build-scripts/runtime_lib.cmake +++ b/build-scripts/runtime_lib.cmake @@ -87,6 +87,12 @@ endif () if (WAMR_BUILD_DEBUG_INTERP EQUAL 1) set (WAMR_BUILD_THREAD_MGR 1) include (${IWASM_DIR}/libraries/debug-engine/debug_engine.cmake) + + if (WAMR_BUILD_FAST_INTERP EQUAL 1) + set (WAMR_BUILD_FAST_INTERP 0) + message(STATUS + "Debugger doesn't work with fast interpreter, switch to classic interpreter") + endif () endif () if (WAMR_BUILD_THREAD_MGR EQUAL 1) @@ -95,7 +101,7 @@ endif () if (WAMR_BUILD_LIBC_EMCC EQUAL 1) include (${IWASM_DIR}/libraries/libc-emcc/libc_emcc.cmake) -endif() +endif () ####################### Common sources ####################### if (NOT MSVC) diff --git a/core/iwasm/common/wasm_exec_env.c b/core/iwasm/common/wasm_exec_env.c index 6a3af642d0..1d5da53492 100644 --- a/core/iwasm/common/wasm_exec_env.c +++ b/core/iwasm/common/wasm_exec_env.c @@ -160,10 +160,12 @@ wasm_exec_env_destroy(WASMExecEnv *exec_env) /* Terminate all sub-threads */ WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env); if (cluster) { + wasm_cluster_terminate_all_except_self(cluster, exec_env); #if WASM_ENABLE_DEBUG_INTERP != 0 + /* Must fire exit event after other threads exits, otherwise + the stopped thread will be overrided by other threads */ wasm_cluster_thread_exited(exec_env); #endif - wasm_cluster_terminate_all_except_self(cluster, exec_env); wasm_cluster_del_exec_env(cluster, exec_env); } #endif /* end of WASM_ENABLE_THREAD_MGR */ diff --git a/core/iwasm/libraries/debug-engine/debug_engine.c b/core/iwasm/libraries/debug-engine/debug_engine.c index 4fa34f5371..6fc0cd37bc 100644 --- a/core/iwasm/libraries/debug-engine/debug_engine.c +++ b/core/iwasm/libraries/debug-engine/debug_engine.c @@ -24,6 +24,20 @@ typedef struct WASMDebugEngine { bool active; } WASMDebugEngine; +void +on_thread_stop_event(WASMDebugInstance *debug_inst, WASMExecEnv *exec_env) +{ + os_mutex_lock(&debug_inst->wait_lock); + debug_inst->stopped_thread = exec_env; + + if (debug_inst->current_state == DBG_LAUNCHING) { + /* In launching phase, send a signal so that handle_threadstop_request + * can be woken up */ + os_cond_signal(&debug_inst->wait_cond); + } + os_mutex_unlock(&debug_inst->wait_lock); +} + static WASMDebugEngine *g_debug_engine; static uint32 current_instance_id = 1; @@ -104,6 +118,50 @@ control_thread_routine(void *arg) while (true) { os_mutex_lock(&control_thread->wait_lock); if (!should_stop(control_thread)) { + /* send thread stop reply */ + if (debug_inst->stopped_thread + && debug_inst->current_state == APP_RUNNING) { + uint32 status; + korp_tid tid; + + status = + (uint32) + debug_inst->stopped_thread->current_status->signal_flag; + tid = debug_inst->stopped_thread->handle; + + if (debug_inst->stopped_thread->current_status->running_status + == STATUS_EXIT) { + /* If the thread exits, report "W00" if it's the last thread + * in the cluster, otherwise ignore this event */ + status = 0; + + /* By design, all the other threads should have been stopped + * at this moment, so it is safe to access the + * exec_env_list.len without lock */ + if (debug_inst->cluster->exec_env_list.len != 1) { + debug_inst->stopped_thread = NULL; + /* The exiting thread may wait for the signal */ + os_cond_signal(&debug_inst->wait_cond); + os_mutex_unlock(&control_thread->wait_lock); + continue; + } + } + + wasm_debug_instance_set_cur_thread( + debug_inst, debug_inst->stopped_thread->handle); + + send_thread_stop_status(control_thread->server, status, tid); + + debug_inst->current_state = APP_STOPPED; + debug_inst->stopped_thread = NULL; + + if (status == 0) { + /* The exiting thread may wait for the signal */ + os_cond_signal(&debug_inst->wait_cond); + } + } + + /* Processing incoming requests */ if (!wasm_gdbserver_handle_packet(control_thread->server)) { control_thread->status = STOPPED; } @@ -148,8 +206,10 @@ wasm_debug_control_thread_create(WASMDebugInstance *debug_instance) /* wait until the debug control thread ready */ os_cond_wait(&debug_instance->wait_cond, &debug_instance->wait_lock); os_mutex_unlock(&debug_instance->wait_lock); - if (!control_thread->server) + if (!control_thread->server) { + os_thread_join(control_thread->tid, NULL); goto fail1; + } os_mutex_lock(&g_debug_engine->instance_list_lock); /* create control thread success, append debug instance to debug engine */ @@ -467,46 +527,6 @@ wasm_debug_instance_get_tids(WASMDebugInstance *instance, korp_tid tids[], return threads_num; } -static WASMExecEnv * -get_stopped_thread(WASMCluster *cluster) -{ - WASMExecEnv *exec_env; - - exec_env = bh_list_first_elem(&cluster->exec_env_list); - while (exec_env) { - if (exec_env->current_status->running_status != STATUS_RUNNING) { - return exec_env; - } - exec_env = bh_list_elem_next(exec_env); - } - - return NULL; -} - -korp_tid -wasm_debug_instance_wait_thread(WASMDebugInstance *instance, korp_tid tid, - uint32 *status) -{ - WASMExecEnv *exec_env = NULL; - - os_mutex_lock(&instance->wait_lock); - while ((instance->cluster->exec_env_list.len != 0) - && ((exec_env = get_stopped_thread(instance->cluster)) == NULL)) { - os_cond_wait(&instance->wait_cond, &instance->wait_lock); - } - os_mutex_unlock(&instance->wait_lock); - - /* If cluster has no exec_env, then this whole cluster is exiting */ - if (instance->cluster->exec_env_list.len == 0) { - *status = 0; - return 0; - } - - instance->current_tid = exec_env->handle; - *status = (uint32)exec_env->current_status->signal_flag; - return exec_env->handle; -} - uint32 wasm_debug_instance_get_thread_status(WASMDebugInstance *instance, korp_tid tid) { @@ -538,7 +558,8 @@ wasm_debug_instance_get_pc(WASMDebugInstance *instance) return 0; exec_env = wasm_debug_instance_get_current_env(instance); - if ((exec_env->cur_frame != NULL) && (exec_env->cur_frame->ip != NULL)) { + if ((exec_env != NULL) && (exec_env->cur_frame != NULL) + && (exec_env->cur_frame->ip != NULL)) { WASMModuleInstance *module_inst = (WASMModuleInstance *)exec_env->module_inst; return WASM_ADDR( @@ -935,6 +956,11 @@ wasm_debug_instance_continue(WASMDebugInstance *instance) if (!instance) return false; + if (instance->current_state == APP_RUNNING) { + LOG_VERBOSE("Already in running state, ignore continue request"); + return false; + } + exec_env = bh_list_first_elem(&instance->cluster->exec_env_list); if (!exec_env) return false; @@ -943,6 +969,28 @@ wasm_debug_instance_continue(WASMDebugInstance *instance) wasm_cluster_thread_continue(exec_env); exec_env = bh_list_elem_next(exec_env); } + + instance->current_state = APP_RUNNING; + + return true; +} + +bool +wasm_debug_instance_interrupt_all_threads(WASMDebugInstance *instance) +{ + WASMExecEnv *exec_env; + + if (!instance) + return false; + + exec_env = bh_list_first_elem(&instance->cluster->exec_env_list); + if (!exec_env) + return false; + + while (exec_env) { + wasm_cluster_thread_send_signal(exec_env, WAMR_SIG_TRAP); + exec_env = bh_list_elem_next(exec_env); + } return true; } @@ -960,8 +1008,17 @@ wasm_debug_instance_kill(WASMDebugInstance *instance) while (exec_env) { wasm_cluster_thread_send_signal(exec_env, WAMR_SIG_TERM); + if (instance->current_state == APP_STOPPED) { + /* Resume all threads so they can receive the TERM signal */ + os_mutex_lock(&exec_env->wait_lock); + exec_env->current_status->running_status = STATUS_RUNNING; + os_cond_signal(&exec_env->wait_cond); + os_mutex_unlock(&exec_env->wait_lock); + } exec_env = bh_list_elem_next(exec_env); } + + instance->current_state = APP_RUNNING; return true; } @@ -973,6 +1030,11 @@ wasm_debug_instance_singlestep(WASMDebugInstance *instance, korp_tid tid) if (!instance) return false; + if (instance->current_state == APP_RUNNING) { + LOG_VERBOSE("Already in running state, ignore step request"); + return false; + } + exec_env = bh_list_first_elem(&instance->cluster->exec_env_list); if (!exec_env) return false; @@ -984,6 +1046,9 @@ wasm_debug_instance_singlestep(WASMDebugInstance *instance, korp_tid tid) } exec_env = bh_list_elem_next(exec_env); } + + instance->current_state = APP_RUNNING; + return true; } diff --git a/core/iwasm/libraries/debug-engine/debug_engine.h b/core/iwasm/libraries/debug-engine/debug_engine.h index ef44543fba..5dd8dca8eb 100644 --- a/core/iwasm/libraries/debug-engine/debug_engine.h +++ b/core/iwasm/libraries/debug-engine/debug_engine.h @@ -35,6 +35,15 @@ typedef struct WASMDebugBreakPoint { uint64 orignal_data; } WASMDebugBreakPoint; +typedef enum debug_state_t { + /* Debugger state conversion sequence: + * DBG_LAUNCHING ---> APP_STOPPED <---> APP_RUNNING + */ + DBG_LAUNCHING, + APP_RUNNING, + APP_STOPPED +} debug_state_t; + typedef struct WASMDebugInstance { struct WASMDebugInstance *next; WASMDebugControlThread *control_thread; @@ -44,6 +53,13 @@ typedef struct WASMDebugInstance { korp_tid current_tid; korp_mutex wait_lock; korp_cond wait_cond; + /* Last stopped thread, it should be set to NULL when sending + * out the thread stop reply */ + WASMExecEnv *volatile stopped_thread; + /* Currently status of the debug instance, it will be set to + * RUNNING when receiving STEP/CONTINUE commands, and set to + * STOPPED when any thread stopped */ + volatile debug_state_t current_state; } WASMDebugInstance; typedef enum WASMDebugEventKind { @@ -77,6 +93,9 @@ typedef enum WasmAddressType { #define INVALIED_ADDR (0xFFFFFFFFFFFFFFFF) +void +on_thread_stop_event(WASMDebugInstance *debug_inst, WASMExecEnv *exec_env); + WASMDebugInstance * wasm_debug_instance_create(WASMCluster *cluster); @@ -152,16 +171,15 @@ bool wasm_debug_instance_remove_breakpoint(WASMDebugInstance *instance, uint64 addr, uint64 length); +bool +wasm_debug_instance_interrupt_all_threads(WASMDebugInstance *instance); + bool wasm_debug_instance_continue(WASMDebugInstance *instance); bool wasm_debug_instance_kill(WASMDebugInstance *instance); -korp_tid -wasm_debug_instance_wait_thread(WASMDebugInstance *instance, korp_tid tid, - uint32 *status); - uint32 wasm_debug_instance_get_thread_status(WASMDebugInstance *instance, korp_tid tid); diff --git a/core/iwasm/libraries/debug-engine/gdbserver.c b/core/iwasm/libraries/debug-engine/gdbserver.c index 7d52b19155..98f8aa2754 100644 --- a/core/iwasm/libraries/debug-engine/gdbserver.c +++ b/core/iwasm/libraries/debug-engine/gdbserver.c @@ -51,6 +51,14 @@ wasm_create_gdbserver(const char *host, int32 *port) memset(server, 0, sizeof(WASMGDBServer)); + if (!(server->receive_ctx = + wasm_runtime_malloc(sizeof(rsp_recv_context_t)))) { + LOG_ERROR("wasm gdb server error: failed to allocate memory"); + goto fail; + } + + memset(server->receive_ctx, 0, sizeof(rsp_recv_context_t)); + if (0 != os_socket_create(&listen_fd, 1)) { LOG_ERROR("wasm gdb server error: create socket failed"); goto fail; @@ -71,6 +79,8 @@ wasm_create_gdbserver(const char *host, int32 *port) os_socket_shutdown(listen_fd); os_socket_close(listen_fd); } + if (server->receive_ctx) + wasm_runtime_free(server->receive_ctx); if (server) wasm_runtime_free(server); return NULL; @@ -108,6 +118,9 @@ wasm_gdbserver_listen(WASMGDBServer *server) void wasm_close_gdbserver(WASMGDBServer *server) { + if (server->receive_ctx) { + wasm_runtime_free(server->receive_ctx); + } if (server->socket_fd > 0) { os_socket_shutdown(server->socket_fd); os_socket_close(server->socket_fd); @@ -119,57 +132,170 @@ wasm_close_gdbserver(WASMGDBServer *server) } static inline void -handler_packet(WASMGDBServer *server, char request, char *payload) +handle_packet(WASMGDBServer *server, char request, char *payload) { if (packet_handler_table[(int)request].handler != NULL) packet_handler_table[(int)request].handler(server, payload); } +static void +process_packet(WASMGDBServer *server) +{ + uint8 *inbuf = (uint8 *)server->receive_ctx->receive_buffer; + char request; + char *payload = NULL; + + request = inbuf[0]; + + if (request == '\0') { + LOG_VERBOSE("ignore empty request"); + return; + } + + payload = (char *)&inbuf[1]; + + LOG_VERBOSE("receive request:%c %s\n", request, payload); + handle_packet(server, request, payload); +} + +static inline void +push_byte(rsp_recv_context_t *ctx, unsigned char ch, bool checksum) +{ + if (ctx->receive_index >= sizeof(ctx->receive_buffer)) { + LOG_ERROR("RSP message buffer overflow"); + bh_assert(false); + return; + } + + ctx->receive_buffer[ctx->receive_index++] = ch; + + if (checksum) { + ctx->check_sum += ch; + } +} + /** * The packet layout is: + * 1. Normal packet: * '$' + payload + '#' + checksum(2bytes) * ^ - * packetend_ptr + * packetend + * 2. Interrupt: + * 0x03 */ -static void -process_packet(WASMGDBServer *server) + +/* return: + * 0: incomplete message received + * 1: complete message received + * 2: interrupt message received + */ +static int +on_rsp_byte_arrive(unsigned char ch, rsp_recv_context_t *ctx) { - uint8 *inbuf = server->pkt.buf; - int32 inbuf_size = server->pkt.size; - uint8 *packetend_ptr = (uint8 *)memchr(inbuf, '#', inbuf_size); - int32 packet_size = (int32)(uintptr_t)(packetend_ptr - inbuf); - char request = inbuf[1]; - char *payload = NULL; - uint8 checksum = 0; + if (ctx->phase == Phase_Idle) { + ctx->receive_index = 0; + ctx->check_sum = 0; - if (packet_size == 1) { - LOG_VERBOSE("receive empty request, ignore it\n"); - return; + if (ch == 0x03) { + LOG_VERBOSE("Receive interrupt package"); + return 2; + } + else if (ch == '$') { + ctx->phase = Phase_Payload; + } + + return 0; } + else if (ctx->phase == Phase_Payload) { + if (ch == '#') { + ctx->phase = Phase_Checksum; + push_byte(ctx, ch, false); + } + else { + push_byte(ctx, ch, true); + } - bh_assert('$' == inbuf[0]); - inbuf[packet_size] = '\0'; + return 0; + } + else if (ctx->phase == Phase_Checksum) { + ctx->size_in_phase++; + push_byte(ctx, ch, false); - for (int i = 1; i < packet_size; i++) - checksum += inbuf[i]; - bh_assert( - checksum - == (hex(inbuf[packet_size + 1]) << 4 | hex(inbuf[packet_size + 2]))); + if (ctx->size_in_phase == 2) { + ctx->size_in_phase = 0; - payload = (char *)&inbuf[2]; + if ((hex(ctx->receive_buffer[ctx->receive_index - 2]) << 4 + | hex(ctx->receive_buffer[ctx->receive_index - 1])) + != ctx->check_sum) { + LOG_WARNING("RSP package checksum error, ignore it"); + ctx->phase = Phase_Idle; + return 0; + } + else { + /* Change # to \0 */ + ctx->receive_buffer[ctx->receive_index - 3] = '\0'; + ctx->phase = Phase_Idle; + return 1; + } + } - LOG_VERBOSE("receive request:%c %s\n", request, payload); - handler_packet(server, request, payload); + return 0; + } - inbuf_erase_head(server, packet_size + 3); + /* Should never reach here */ + bh_assert(false); + return 0; } bool wasm_gdbserver_handle_packet(WASMGDBServer *server) { - bool ret; - ret = read_packet(server); - if (ret) - process_packet(server); - return ret; + int32 n; + char buf[1024]; + + if (os_socket_settimeout(server->socket_fd, 1000) != 0) { + LOG_ERROR("Set socket recv timeout failed"); + return false; + } + + n = os_socket_recv(server->socket_fd, buf, sizeof(buf)); + + if (n == 0) { + LOG_VERBOSE("Debugger disconnected"); + return false; + } + else if (n < 0) { +#if defined(BH_PLATFORM_WINDOWS) + if (WSAGetLastError() == WSAETIMEDOUT) +#else + if (errno == EAGAIN || errno == EWOULDBLOCK) +#endif + { + /* No bytes arrived */ + return true; + } + else { + LOG_ERROR("Socket receive error"); + return false; + } + } + else { + int32 i, ret; + + for (i = 0; i < n; i++) { + ret = on_rsp_byte_arrive(buf[i], server->receive_ctx); + + if (ret == 1) { + if (!server->noack) + write_data_raw(server, (uint8 *)"+", 1); + + process_packet(server); + } + else if (ret == 2) { + handle_interrupt(server); + } + } + } + + return true; } diff --git a/core/iwasm/libraries/debug-engine/gdbserver.h b/core/iwasm/libraries/debug-engine/gdbserver.h index f5d0453510..98ff834350 100644 --- a/core/iwasm/libraries/debug-engine/gdbserver.h +++ b/core/iwasm/libraries/debug-engine/gdbserver.h @@ -18,6 +18,23 @@ enum GDBStoppointType { eWatchpointRead, eWatchpointReadWrite }; + +typedef enum rsp_recv_phase_t { + Phase_Idle, + Phase_Payload, + Phase_Checksum +} rsp_recv_phase_t; + +/* Remote Serial Protocol Receive Context */ +typedef struct rsp_recv_context_t { + rsp_recv_phase_t phase; + uint16 receive_index; + uint16 size_in_phase; + uint8 check_sum; + /* RSP packet should not be too long */ + char receive_buffer[1024]; +} rsp_recv_context_t; + typedef struct WasmDebugPacket { unsigned char buf[PACKET_BUF_SIZE]; uint32 size; @@ -30,6 +47,7 @@ typedef struct WASMGDBServer { WasmDebugPacket pkt; bool noack; struct WASMDebugControlThread *thread; + rsp_recv_context_t *receive_ctx; } WASMGDBServer; WASMGDBServer * diff --git a/core/iwasm/libraries/debug-engine/handler.c b/core/iwasm/libraries/debug-engine/handler.c index b746a1c1c7..d39bb35b9f 100644 --- a/core/iwasm/libraries/debug-engine/handler.c +++ b/core/iwasm/libraries/debug-engine/handler.c @@ -26,8 +26,11 @@ wasm_debug_handler_deinit() os_mutex_destroy(&tmpbuf_lock); } -static void -send_thread_stop_status(WASMGDBServer *server, uint32 status, korp_tid tid); +void +handle_interrupt(WASMGDBServer *server) +{ + wasm_debug_instance_interrupt_all_threads(server->thread->debug_instance); +} void handle_generay_set(WASMGDBServer *server, char *payload) @@ -91,7 +94,7 @@ process_xfer(WASMGDBServer *server, const char *name, char *args) } void -porcess_wasm_local(WASMGDBServer *server, char *args) +process_wasm_local(WASMGDBServer *server, char *args) { int32 frame_index; int32 local_index; @@ -114,7 +117,7 @@ porcess_wasm_local(WASMGDBServer *server, char *args) } void -porcess_wasm_global(WASMGDBServer *server, char *args) +process_wasm_global(WASMGDBServer *server, char *args) { int32 frame_index; int32 global_index; @@ -189,12 +192,12 @@ handle_generay_query(WASMGDBServer *server, char *payload) } if (!strcmp(name, "HostInfo")) { - // Todo: change vendor to Intel for outside tree? - mem2hex("wasm32-Ant-wasi-wasm", triple, strlen("wasm32-Ant-wasi-wasm")); + mem2hex("wasm32-wamr-wasi-wasm", triple, + strlen("wasm32-wamr-wasi-wasm")); os_mutex_lock(&tmpbuf_lock); snprintf(tmpbuf, sizeof(tmpbuf), - "vendor:Ant;ostype:wasi;arch:wasm32;" + "vendor:wamr;ostype:wasi;arch:wasm32;" "triple:%s;endian:little;ptrsize:4;", triple); write_packet(server, tmpbuf); @@ -220,13 +223,13 @@ handle_generay_query(WASMGDBServer *server, char *payload) uint64 pid; pid = wasm_debug_instance_get_pid( (WASMDebugInstance *)server->thread->debug_instance); - // arch-vendor-os-env(format) - mem2hex("wasm32-Ant-wasi-wasm", triple, strlen("wasm32-Ant-wasi-wasm")); + mem2hex("wasm32-wamr-wasi-wasm", triple, + strlen("wasm32-wamr-wasi-wasm")); os_mutex_lock(&tmpbuf_lock); snprintf(tmpbuf, sizeof(tmpbuf), "pid:%" PRIx64 ";parent-pid:%" PRIx64 - ";vendor:Ant;ostype:wasi;arch:wasm32;" + ";vendor:wamr;ostype:wasi;arch:wasm32;" "triple:%s;endian:little;ptrsize:4;", pid, pid, triple); write_packet(server, tmpbuf); @@ -298,11 +301,11 @@ handle_generay_query(WASMGDBServer *server, char *payload) } if (args && (!strcmp(name, "WasmLocal"))) { - porcess_wasm_local(server, args); + process_wasm_local(server, args); } if (args && (!strcmp(name, "WasmGlobal"))) { - porcess_wasm_global(server, args); + process_wasm_global(server, args); } if (!strcmp(name, "Offsets")) { @@ -322,7 +325,7 @@ handle_generay_query(WASMGDBServer *server, char *payload) } } -static void +void send_thread_stop_status(WASMGDBServer *server, uint32 status, korp_tid tid) { int32 len = 0; @@ -391,7 +394,6 @@ handle_v_packet(WASMGDBServer *server, char *payload) { const char *name; char *args; - uint32 status; args = strchr(payload, ';'); if (args) @@ -427,11 +429,6 @@ handle_v_packet(WASMGDBServer *server, char *payload) (WASMDebugInstance *) server->thread->debug_instance); } - - tid = wasm_debug_instance_wait_thread( - (WASMDebugInstance *)server->thread->debug_instance, - tid, &status); - send_thread_stop_status(server, status, tid); } } } @@ -441,14 +438,34 @@ handle_v_packet(WASMGDBServer *server, char *payload) void handle_threadstop_request(WASMGDBServer *server, char *payload) { - korp_tid tid = wasm_debug_instance_get_tid( - (WASMDebugInstance *)server->thread->debug_instance); + korp_tid tid; uint32 status; + WASMDebugInstance *debug_inst = + (WASMDebugInstance *)server->thread->debug_instance; + bh_assert(debug_inst); + + /* According to + https://sourceware.org/gdb/onlinedocs/gdb/Packets.html#Packets, the "?" + package should be sent when connection is first established to query the + reason the target halted */ + bh_assert(debug_inst->current_state == DBG_LAUNCHING); - tid = wasm_debug_instance_wait_thread( - (WASMDebugInstance *)server->thread->debug_instance, tid, &status); + /* Waiting for the stop event */ + os_mutex_lock(&debug_inst->wait_lock); + while (!debug_inst->stopped_thread) { + os_cond_wait(&debug_inst->wait_cond, &debug_inst->wait_lock); + } + os_mutex_unlock(&debug_inst->wait_lock); + + tid = debug_inst->stopped_thread->handle; + status = (uint32)debug_inst->stopped_thread->current_status->signal_flag; + + wasm_debug_instance_set_cur_thread(debug_inst, tid); send_thread_stop_status(server, status, tid); + + debug_inst->current_state = APP_STOPPED; + debug_inst->stopped_thread = NULL; } void @@ -611,37 +628,15 @@ handle_remove_break(WASMGDBServer *server, char *payload) void handle_continue_request(WASMGDBServer *server, char *payload) { - korp_tid tid; - uint32 status; - wasm_debug_instance_continue( (WASMDebugInstance *)server->thread->debug_instance); - - tid = wasm_debug_instance_get_tid( - (WASMDebugInstance *)server->thread->debug_instance); - - tid = wasm_debug_instance_wait_thread( - (WASMDebugInstance *)server->thread->debug_instance, tid, &status); - - send_thread_stop_status(server, status, tid); } void handle_kill_request(WASMGDBServer *server, char *payload) { - korp_tid tid; - uint32 status; - wasm_debug_instance_kill( (WASMDebugInstance *)server->thread->debug_instance); - - tid = wasm_debug_instance_get_tid( - (WASMDebugInstance *)server->thread->debug_instance); - - tid = wasm_debug_instance_wait_thread( - (WASMDebugInstance *)server->thread->debug_instance, tid, &status); - - send_thread_stop_status(server, status, tid); } static void diff --git a/core/iwasm/libraries/debug-engine/handler.h b/core/iwasm/libraries/debug-engine/handler.h index d64b73ce43..b2db17b411 100644 --- a/core/iwasm/libraries/debug-engine/handler.h +++ b/core/iwasm/libraries/debug-engine/handler.h @@ -14,6 +14,9 @@ wasm_debug_handler_init(); void wasm_debug_handler_deinit(); +void +handle_interrupt(WASMGDBServer *server); + void handle_generay_set(WASMGDBServer *server, char *payload); @@ -58,4 +61,7 @@ handle_kill_request(WASMGDBServer *server, char *payload); void handle____request(WASMGDBServer *server, char *payload); + +void +send_thread_stop_status(WASMGDBServer *server, uint32 status, korp_tid tid); #endif diff --git a/core/iwasm/libraries/debug-engine/packets.c b/core/iwasm/libraries/debug-engine/packets.c index e8b80b4e3e..1bdb3d2ce8 100644 --- a/core/iwasm/libraries/debug-engine/packets.c +++ b/core/iwasm/libraries/debug-engine/packets.c @@ -7,56 +7,6 @@ #include "packets.h" #include "gdbserver.h" -void -pktbuf_insert(WASMGDBServer *gdbserver, const uint8 *buf, ssize_t len) -{ - WasmDebugPacket *pkt = &gdbserver->pkt; - - if ((unsigned long)(pkt->size + len) >= sizeof(pkt->buf)) { - LOG_ERROR("Packet buffer overflow"); - exit(-2); - } - - memcpy(pkt->buf + pkt->size, buf, len); - pkt->size += len; -} - -void -pktbuf_erase_head(WASMGDBServer *gdbserver, ssize_t index) -{ - WasmDebugPacket *pkt = &gdbserver->pkt; - memmove(pkt->buf, pkt->buf + index, pkt->size - index); - pkt->size -= index; -} - -void -inbuf_erase_head(WASMGDBServer *gdbserver, ssize_t index) -{ - pktbuf_erase_head(gdbserver, index); -} - -void -pktbuf_clear(WASMGDBServer *gdbserver) -{ - WasmDebugPacket *pkt = &gdbserver->pkt; - pkt->size = 0; -} - -int32 -read_data_once(WASMGDBServer *gdbserver) -{ - ssize_t nread; - uint8 buf[4096]; - - nread = os_socket_recv(gdbserver->socket_fd, buf, sizeof(buf)); - if (nread <= 0) { - LOG_ERROR("Connection closed"); - return -1; - } - pktbuf_insert(gdbserver, buf, nread); - return nread; -} - void write_data_raw(WASMGDBServer *gdbserver, const uint8 *data, ssize_t len) { @@ -139,40 +89,3 @@ write_binary_packet(WASMGDBServer *gdbserver, const char *pfx, write_packet_bytes(gdbserver, buf, buf_num_bytes); wasm_runtime_free(buf); } - -bool -skip_to_packet_start(WASMGDBServer *gdbserver) -{ - ssize_t start_index = -1, i; - - for (i = 0; i < (ssize_t)gdbserver->pkt.size; ++i) { - if (gdbserver->pkt.buf[i] == '$') { - start_index = i; - break; - } - } - - if (start_index < 0) { - pktbuf_clear(gdbserver); - return false; - } - - pktbuf_erase_head(gdbserver, start_index); - - bh_assert(1 <= gdbserver->pkt.size); - bh_assert('$' == gdbserver->pkt.buf[0]); - - return true; -} - -bool -read_packet(WASMGDBServer *gdbserver) -{ - while (!skip_to_packet_start(gdbserver)) { - if (read_data_once(gdbserver) < 0) - return false; - } - if (!gdbserver->noack) - write_data_raw(gdbserver, (uint8 *)"+", 1); - return true; -} diff --git a/core/iwasm/libraries/debug-engine/packets.h b/core/iwasm/libraries/debug-engine/packets.h index 7361bd6dfd..b35889394f 100644 --- a/core/iwasm/libraries/debug-engine/packets.h +++ b/core/iwasm/libraries/debug-engine/packets.h @@ -8,13 +8,10 @@ #include "gdbserver.h" -bool -read_packet(WASMGDBServer *gdbserver); - void -write_packet(WASMGDBServer *gdbserver, const char *data); +write_data_raw(WASMGDBServer *gdbserver, const uint8 *data, ssize_t len); void -inbuf_erase_head(WASMGDBServer *gdbserver, ssize_t end); +write_packet(WASMGDBServer *gdbserver, const char *data); #endif diff --git a/core/iwasm/libraries/thread-mgr/thread_manager.c b/core/iwasm/libraries/thread-mgr/thread_manager.c index 8db457c275..0a25c11b4a 100644 --- a/core/iwasm/libraries/thread-mgr/thread_manager.c +++ b/core/iwasm/libraries/thread-mgr/thread_manager.c @@ -284,6 +284,22 @@ wasm_cluster_del_exec_env(WASMCluster *cluster, WASMExecEnv *exec_env) { bool ret = true; bh_assert(exec_env->cluster == cluster); + +#if WASM_ENABLE_DEBUG_INTERP != 0 + /* Wait for debugger control thread to process the + stop event of this thread */ + if (cluster->debug_inst) { + /* lock the debug_inst->wait_lock so + other threads can't fire stop events */ + os_mutex_lock(&cluster->debug_inst->wait_lock); + while (cluster->debug_inst->stopped_thread == exec_env) { + os_cond_wait(&cluster->debug_inst->wait_cond, + &cluster->debug_inst->wait_lock); + } + os_mutex_unlock(&cluster->debug_inst->wait_lock); + } +#endif + os_mutex_lock(&cluster->lock); if (bh_list_remove(&cluster->exec_env_list, exec_env) != 0) ret = false; @@ -447,6 +463,9 @@ thread_manager_start_routine(void *arg) free_aux_stack(cluster, exec_env->aux_stack_bottom.bottom); /* Detach the native thread here to ensure the resources are freed */ wasm_cluster_detach_thread(exec_env); +#if WASM_ENABLE_DEBUG_INTERP != 0 + wasm_cluster_thread_exited(exec_env); +#endif /* Remove and destroy exec_env */ wasm_cluster_del_exec_env(cluster, exec_env); wasm_exec_env_destroy_internal(exec_env); @@ -563,9 +582,7 @@ notify_debug_instance(WASMExecEnv *exec_env) return; } - os_mutex_lock(&cluster->debug_inst->wait_lock); - os_cond_signal(&cluster->debug_inst->wait_cond); - os_mutex_unlock(&cluster->debug_inst->wait_lock); + on_thread_stop_event(cluster->debug_inst, exec_env); } void @@ -744,7 +761,6 @@ wasm_cluster_cancel_thread(WASMExecEnv *exec_env) /* Set the termination flag */ #if WASM_ENABLE_DEBUG_INTERP != 0 wasm_cluster_thread_send_signal(exec_env, WAMR_SIG_TERM); - wasm_cluster_thread_exited(exec_env); #else exec_env->suspend_flags.flags |= 0x01; #endif diff --git a/core/shared/platform/common/posix/posix_socket.c b/core/shared/platform/common/posix/posix_socket.c index 6492724622..0f7e8fcaea 100644 --- a/core/shared/platform/common/posix/posix_socket.c +++ b/core/shared/platform/common/posix/posix_socket.c @@ -71,6 +71,22 @@ os_socket_bind(bh_socket_t socket, const char *host, int *port) return BHT_ERROR; } +int +os_socket_settimeout(bh_socket_t socket, uint64 timeout_us) +{ + struct timeval tv; + tv.tv_sec = timeout_us / 1000000UL; + tv.tv_usec = timeout_us % 1000000UL; + + if (setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (const char *)&tv, + sizeof(tv)) + != 0) { + return BHT_ERROR; + } + + return BHT_OK; +} + int os_socket_listen(bh_socket_t socket, int max_client) { diff --git a/core/shared/platform/include/platform_api_extension.h b/core/shared/platform/include/platform_api_extension.h index cd3c7e95af..937882ca95 100644 --- a/core/shared/platform/include/platform_api_extension.h +++ b/core/shared/platform/include/platform_api_extension.h @@ -226,6 +226,17 @@ os_socket_create(bh_socket_t *sock, int tcp_or_udp); int os_socket_bind(bh_socket_t socket, const char *addr, int *port); +/** + * Set timeout for the given socket + * + * @param socket the socket to set timeout + * @param timeout_us timeout in microseconds + * + * @return 0 if success, -1 otherwise + */ +int +os_socket_settimeout(bh_socket_t socket, uint64 timeout_us); + /** * Make the socket as a passive socket to accept incoming connection requests * diff --git a/core/shared/platform/windows/win_socket.c b/core/shared/platform/windows/win_socket.c index 0057aeeda5..512d50280e 100644 --- a/core/shared/platform/windows/win_socket.c +++ b/core/shared/platform/windows/win_socket.c @@ -85,6 +85,20 @@ os_socket_bind(bh_socket_t socket, const char *host, int *port) return BHT_ERROR; } +int +os_socket_settimeout(bh_socket_t socket, uint64 timeout_us) +{ + DWORD tv = (DWORD)(timeout_us / 1000UL); + + if (setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (const char *)&tv, + sizeof(tv)) + != 0) { + return BHT_ERROR; + } + + return BHT_OK; +} + int os_socket_listen(bh_socket_t socket, int max_client) {