[debugger enhance] don't block gdbserver thread while executing (#989)

Allow to set break point again when all break points are removed and
wasm app starts running.
This commit is contained in:
Xu Jun 2022-02-16 17:35:35 +08:00 committed by GitHub
parent 985dea9493
commit 3fe191b0df
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 424 additions and 221 deletions

View File

@ -87,6 +87,12 @@ endif ()
if (WAMR_BUILD_DEBUG_INTERP EQUAL 1) if (WAMR_BUILD_DEBUG_INTERP EQUAL 1)
set (WAMR_BUILD_THREAD_MGR 1) set (WAMR_BUILD_THREAD_MGR 1)
include (${IWASM_DIR}/libraries/debug-engine/debug_engine.cmake) 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 () endif ()
if (WAMR_BUILD_THREAD_MGR EQUAL 1) if (WAMR_BUILD_THREAD_MGR EQUAL 1)
@ -95,7 +101,7 @@ endif ()
if (WAMR_BUILD_LIBC_EMCC EQUAL 1) if (WAMR_BUILD_LIBC_EMCC EQUAL 1)
include (${IWASM_DIR}/libraries/libc-emcc/libc_emcc.cmake) include (${IWASM_DIR}/libraries/libc-emcc/libc_emcc.cmake)
endif() endif ()
####################### Common sources ####################### ####################### Common sources #######################
if (NOT MSVC) if (NOT MSVC)

View File

@ -160,10 +160,12 @@ wasm_exec_env_destroy(WASMExecEnv *exec_env)
/* Terminate all sub-threads */ /* Terminate all sub-threads */
WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env); WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env);
if (cluster) { if (cluster) {
wasm_cluster_terminate_all_except_self(cluster, exec_env);
#if WASM_ENABLE_DEBUG_INTERP != 0 #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); wasm_cluster_thread_exited(exec_env);
#endif #endif
wasm_cluster_terminate_all_except_self(cluster, exec_env);
wasm_cluster_del_exec_env(cluster, exec_env); wasm_cluster_del_exec_env(cluster, exec_env);
} }
#endif /* end of WASM_ENABLE_THREAD_MGR */ #endif /* end of WASM_ENABLE_THREAD_MGR */

View File

@ -24,6 +24,20 @@ typedef struct WASMDebugEngine {
bool active; bool active;
} WASMDebugEngine; } 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 WASMDebugEngine *g_debug_engine;
static uint32 current_instance_id = 1; static uint32 current_instance_id = 1;
@ -104,6 +118,50 @@ control_thread_routine(void *arg)
while (true) { while (true) {
os_mutex_lock(&control_thread->wait_lock); os_mutex_lock(&control_thread->wait_lock);
if (!should_stop(control_thread)) { 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)) { if (!wasm_gdbserver_handle_packet(control_thread->server)) {
control_thread->status = STOPPED; control_thread->status = STOPPED;
} }
@ -148,8 +206,10 @@ wasm_debug_control_thread_create(WASMDebugInstance *debug_instance)
/* wait until the debug control thread ready */ /* wait until the debug control thread ready */
os_cond_wait(&debug_instance->wait_cond, &debug_instance->wait_lock); os_cond_wait(&debug_instance->wait_cond, &debug_instance->wait_lock);
os_mutex_unlock(&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; goto fail1;
}
os_mutex_lock(&g_debug_engine->instance_list_lock); os_mutex_lock(&g_debug_engine->instance_list_lock);
/* create control thread success, append debug instance to debug engine */ /* 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; 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 uint32
wasm_debug_instance_get_thread_status(WASMDebugInstance *instance, korp_tid tid) wasm_debug_instance_get_thread_status(WASMDebugInstance *instance, korp_tid tid)
{ {
@ -538,7 +558,8 @@ wasm_debug_instance_get_pc(WASMDebugInstance *instance)
return 0; return 0;
exec_env = wasm_debug_instance_get_current_env(instance); 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 *module_inst =
(WASMModuleInstance *)exec_env->module_inst; (WASMModuleInstance *)exec_env->module_inst;
return WASM_ADDR( return WASM_ADDR(
@ -935,6 +956,11 @@ wasm_debug_instance_continue(WASMDebugInstance *instance)
if (!instance) if (!instance)
return false; 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); exec_env = bh_list_first_elem(&instance->cluster->exec_env_list);
if (!exec_env) if (!exec_env)
return false; return false;
@ -943,6 +969,28 @@ wasm_debug_instance_continue(WASMDebugInstance *instance)
wasm_cluster_thread_continue(exec_env); wasm_cluster_thread_continue(exec_env);
exec_env = bh_list_elem_next(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; return true;
} }
@ -960,8 +1008,17 @@ wasm_debug_instance_kill(WASMDebugInstance *instance)
while (exec_env) { while (exec_env) {
wasm_cluster_thread_send_signal(exec_env, WAMR_SIG_TERM); 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); exec_env = bh_list_elem_next(exec_env);
} }
instance->current_state = APP_RUNNING;
return true; return true;
} }
@ -973,6 +1030,11 @@ wasm_debug_instance_singlestep(WASMDebugInstance *instance, korp_tid tid)
if (!instance) if (!instance)
return false; 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); exec_env = bh_list_first_elem(&instance->cluster->exec_env_list);
if (!exec_env) if (!exec_env)
return false; return false;
@ -984,6 +1046,9 @@ wasm_debug_instance_singlestep(WASMDebugInstance *instance, korp_tid tid)
} }
exec_env = bh_list_elem_next(exec_env); exec_env = bh_list_elem_next(exec_env);
} }
instance->current_state = APP_RUNNING;
return true; return true;
} }

View File

@ -35,6 +35,15 @@ typedef struct WASMDebugBreakPoint {
uint64 orignal_data; uint64 orignal_data;
} WASMDebugBreakPoint; } 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 { typedef struct WASMDebugInstance {
struct WASMDebugInstance *next; struct WASMDebugInstance *next;
WASMDebugControlThread *control_thread; WASMDebugControlThread *control_thread;
@ -44,6 +53,13 @@ typedef struct WASMDebugInstance {
korp_tid current_tid; korp_tid current_tid;
korp_mutex wait_lock; korp_mutex wait_lock;
korp_cond wait_cond; 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; } WASMDebugInstance;
typedef enum WASMDebugEventKind { typedef enum WASMDebugEventKind {
@ -77,6 +93,9 @@ typedef enum WasmAddressType {
#define INVALIED_ADDR (0xFFFFFFFFFFFFFFFF) #define INVALIED_ADDR (0xFFFFFFFFFFFFFFFF)
void
on_thread_stop_event(WASMDebugInstance *debug_inst, WASMExecEnv *exec_env);
WASMDebugInstance * WASMDebugInstance *
wasm_debug_instance_create(WASMCluster *cluster); wasm_debug_instance_create(WASMCluster *cluster);
@ -152,16 +171,15 @@ bool
wasm_debug_instance_remove_breakpoint(WASMDebugInstance *instance, uint64 addr, wasm_debug_instance_remove_breakpoint(WASMDebugInstance *instance, uint64 addr,
uint64 length); uint64 length);
bool
wasm_debug_instance_interrupt_all_threads(WASMDebugInstance *instance);
bool bool
wasm_debug_instance_continue(WASMDebugInstance *instance); wasm_debug_instance_continue(WASMDebugInstance *instance);
bool bool
wasm_debug_instance_kill(WASMDebugInstance *instance); wasm_debug_instance_kill(WASMDebugInstance *instance);
korp_tid
wasm_debug_instance_wait_thread(WASMDebugInstance *instance, korp_tid tid,
uint32 *status);
uint32 uint32
wasm_debug_instance_get_thread_status(WASMDebugInstance *instance, wasm_debug_instance_get_thread_status(WASMDebugInstance *instance,
korp_tid tid); korp_tid tid);

View File

@ -51,6 +51,14 @@ wasm_create_gdbserver(const char *host, int32 *port)
memset(server, 0, sizeof(WASMGDBServer)); 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)) { if (0 != os_socket_create(&listen_fd, 1)) {
LOG_ERROR("wasm gdb server error: create socket failed"); LOG_ERROR("wasm gdb server error: create socket failed");
goto fail; goto fail;
@ -71,6 +79,8 @@ fail:
os_socket_shutdown(listen_fd); os_socket_shutdown(listen_fd);
os_socket_close(listen_fd); os_socket_close(listen_fd);
} }
if (server->receive_ctx)
wasm_runtime_free(server->receive_ctx);
if (server) if (server)
wasm_runtime_free(server); wasm_runtime_free(server);
return NULL; return NULL;
@ -108,6 +118,9 @@ fail:
void void
wasm_close_gdbserver(WASMGDBServer *server) wasm_close_gdbserver(WASMGDBServer *server)
{ {
if (server->receive_ctx) {
wasm_runtime_free(server->receive_ctx);
}
if (server->socket_fd > 0) { if (server->socket_fd > 0) {
os_socket_shutdown(server->socket_fd); os_socket_shutdown(server->socket_fd);
os_socket_close(server->socket_fd); os_socket_close(server->socket_fd);
@ -119,57 +132,170 @@ wasm_close_gdbserver(WASMGDBServer *server)
} }
static inline void 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) if (packet_handler_table[(int)request].handler != NULL)
packet_handler_table[(int)request].handler(server, payload); packet_handler_table[(int)request].handler(server, payload);
} }
/**
* The packet layout is:
* '$' + payload + '#' + checksum(2bytes)
* ^
* packetend_ptr
*/
static void static void
process_packet(WASMGDBServer *server) process_packet(WASMGDBServer *server)
{ {
uint8 *inbuf = server->pkt.buf; uint8 *inbuf = (uint8 *)server->receive_ctx->receive_buffer;
int32 inbuf_size = server->pkt.size; char request;
uint8 *packetend_ptr = (uint8 *)memchr(inbuf, '#', inbuf_size);
int32 packet_size = (int32)(uintptr_t)(packetend_ptr - inbuf);
char request = inbuf[1];
char *payload = NULL; char *payload = NULL;
uint8 checksum = 0;
if (packet_size == 1) { request = inbuf[0];
LOG_VERBOSE("receive empty request, ignore it\n");
if (request == '\0') {
LOG_VERBOSE("ignore empty request");
return; return;
} }
bh_assert('$' == inbuf[0]); payload = (char *)&inbuf[1];
inbuf[packet_size] = '\0';
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])));
payload = (char *)&inbuf[2];
LOG_VERBOSE("receive request:%c %s\n", request, payload); LOG_VERBOSE("receive request:%c %s\n", request, payload);
handler_packet(server, request, payload); handle_packet(server, request, payload);
}
inbuf_erase_head(server, packet_size + 3); 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
* 2. Interrupt:
* 0x03
*/
/* 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)
{
if (ctx->phase == Phase_Idle) {
ctx->receive_index = 0;
ctx->check_sum = 0;
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);
}
return 0;
}
else if (ctx->phase == Phase_Checksum) {
ctx->size_in_phase++;
push_byte(ctx, ch, false);
if (ctx->size_in_phase == 2) {
ctx->size_in_phase = 0;
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;
}
}
return 0;
}
/* Should never reach here */
bh_assert(false);
return 0;
} }
bool bool
wasm_gdbserver_handle_packet(WASMGDBServer *server) wasm_gdbserver_handle_packet(WASMGDBServer *server)
{ {
bool ret; int32 n;
ret = read_packet(server); char buf[1024];
if (ret)
process_packet(server); if (os_socket_settimeout(server->socket_fd, 1000) != 0) {
return ret; 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;
} }

View File

@ -18,6 +18,23 @@ enum GDBStoppointType {
eWatchpointRead, eWatchpointRead,
eWatchpointReadWrite 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 { typedef struct WasmDebugPacket {
unsigned char buf[PACKET_BUF_SIZE]; unsigned char buf[PACKET_BUF_SIZE];
uint32 size; uint32 size;
@ -30,6 +47,7 @@ typedef struct WASMGDBServer {
WasmDebugPacket pkt; WasmDebugPacket pkt;
bool noack; bool noack;
struct WASMDebugControlThread *thread; struct WASMDebugControlThread *thread;
rsp_recv_context_t *receive_ctx;
} WASMGDBServer; } WASMGDBServer;
WASMGDBServer * WASMGDBServer *

View File

@ -26,8 +26,11 @@ wasm_debug_handler_deinit()
os_mutex_destroy(&tmpbuf_lock); os_mutex_destroy(&tmpbuf_lock);
} }
static void void
send_thread_stop_status(WASMGDBServer *server, uint32 status, korp_tid tid); handle_interrupt(WASMGDBServer *server)
{
wasm_debug_instance_interrupt_all_threads(server->thread->debug_instance);
}
void void
handle_generay_set(WASMGDBServer *server, char *payload) handle_generay_set(WASMGDBServer *server, char *payload)
@ -91,7 +94,7 @@ process_xfer(WASMGDBServer *server, const char *name, char *args)
} }
void void
porcess_wasm_local(WASMGDBServer *server, char *args) process_wasm_local(WASMGDBServer *server, char *args)
{ {
int32 frame_index; int32 frame_index;
int32 local_index; int32 local_index;
@ -114,7 +117,7 @@ porcess_wasm_local(WASMGDBServer *server, char *args)
} }
void void
porcess_wasm_global(WASMGDBServer *server, char *args) process_wasm_global(WASMGDBServer *server, char *args)
{ {
int32 frame_index; int32 frame_index;
int32 global_index; int32 global_index;
@ -189,12 +192,12 @@ handle_generay_query(WASMGDBServer *server, char *payload)
} }
if (!strcmp(name, "HostInfo")) { if (!strcmp(name, "HostInfo")) {
// Todo: change vendor to Intel for outside tree mem2hex("wasm32-wamr-wasi-wasm", triple,
mem2hex("wasm32-Ant-wasi-wasm", triple, strlen("wasm32-Ant-wasi-wasm")); strlen("wasm32-wamr-wasi-wasm"));
os_mutex_lock(&tmpbuf_lock); os_mutex_lock(&tmpbuf_lock);
snprintf(tmpbuf, sizeof(tmpbuf), snprintf(tmpbuf, sizeof(tmpbuf),
"vendor:Ant;ostype:wasi;arch:wasm32;" "vendor:wamr;ostype:wasi;arch:wasm32;"
"triple:%s;endian:little;ptrsize:4;", "triple:%s;endian:little;ptrsize:4;",
triple); triple);
write_packet(server, tmpbuf); write_packet(server, tmpbuf);
@ -220,13 +223,13 @@ handle_generay_query(WASMGDBServer *server, char *payload)
uint64 pid; uint64 pid;
pid = wasm_debug_instance_get_pid( pid = wasm_debug_instance_get_pid(
(WASMDebugInstance *)server->thread->debug_instance); (WASMDebugInstance *)server->thread->debug_instance);
// arch-vendor-os-env(format) mem2hex("wasm32-wamr-wasi-wasm", triple,
mem2hex("wasm32-Ant-wasi-wasm", triple, strlen("wasm32-Ant-wasi-wasm")); strlen("wasm32-wamr-wasi-wasm"));
os_mutex_lock(&tmpbuf_lock); os_mutex_lock(&tmpbuf_lock);
snprintf(tmpbuf, sizeof(tmpbuf), snprintf(tmpbuf, sizeof(tmpbuf),
"pid:%" PRIx64 ";parent-pid:%" PRIx64 "pid:%" PRIx64 ";parent-pid:%" PRIx64
";vendor:Ant;ostype:wasi;arch:wasm32;" ";vendor:wamr;ostype:wasi;arch:wasm32;"
"triple:%s;endian:little;ptrsize:4;", "triple:%s;endian:little;ptrsize:4;",
pid, pid, triple); pid, pid, triple);
write_packet(server, tmpbuf); write_packet(server, tmpbuf);
@ -298,11 +301,11 @@ handle_generay_query(WASMGDBServer *server, char *payload)
} }
if (args && (!strcmp(name, "WasmLocal"))) { if (args && (!strcmp(name, "WasmLocal"))) {
porcess_wasm_local(server, args); process_wasm_local(server, args);
} }
if (args && (!strcmp(name, "WasmGlobal"))) { if (args && (!strcmp(name, "WasmGlobal"))) {
porcess_wasm_global(server, args); process_wasm_global(server, args);
} }
if (!strcmp(name, "Offsets")) { 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) send_thread_stop_status(WASMGDBServer *server, uint32 status, korp_tid tid)
{ {
int32 len = 0; int32 len = 0;
@ -391,7 +394,6 @@ handle_v_packet(WASMGDBServer *server, char *payload)
{ {
const char *name; const char *name;
char *args; char *args;
uint32 status;
args = strchr(payload, ';'); args = strchr(payload, ';');
if (args) if (args)
@ -427,11 +429,6 @@ handle_v_packet(WASMGDBServer *server, char *payload)
(WASMDebugInstance *) (WASMDebugInstance *)
server->thread->debug_instance); 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 void
handle_threadstop_request(WASMGDBServer *server, char *payload) handle_threadstop_request(WASMGDBServer *server, char *payload)
{ {
korp_tid tid = wasm_debug_instance_get_tid( korp_tid tid;
(WASMDebugInstance *)server->thread->debug_instance);
uint32 status; uint32 status;
WASMDebugInstance *debug_inst =
(WASMDebugInstance *)server->thread->debug_instance;
bh_assert(debug_inst);
tid = wasm_debug_instance_wait_thread( /* According to
(WASMDebugInstance *)server->thread->debug_instance, tid, &status); 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);
/* 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); send_thread_stop_status(server, status, tid);
debug_inst->current_state = APP_STOPPED;
debug_inst->stopped_thread = NULL;
} }
void void
@ -611,37 +628,15 @@ handle_remove_break(WASMGDBServer *server, char *payload)
void void
handle_continue_request(WASMGDBServer *server, char *payload) handle_continue_request(WASMGDBServer *server, char *payload)
{ {
korp_tid tid;
uint32 status;
wasm_debug_instance_continue( wasm_debug_instance_continue(
(WASMDebugInstance *)server->thread->debug_instance); (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 void
handle_kill_request(WASMGDBServer *server, char *payload) handle_kill_request(WASMGDBServer *server, char *payload)
{ {
korp_tid tid;
uint32 status;
wasm_debug_instance_kill( wasm_debug_instance_kill(
(WASMDebugInstance *)server->thread->debug_instance); (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 static void

View File

@ -14,6 +14,9 @@ wasm_debug_handler_init();
void void
wasm_debug_handler_deinit(); wasm_debug_handler_deinit();
void
handle_interrupt(WASMGDBServer *server);
void void
handle_generay_set(WASMGDBServer *server, char *payload); handle_generay_set(WASMGDBServer *server, char *payload);
@ -58,4 +61,7 @@ handle_kill_request(WASMGDBServer *server, char *payload);
void void
handle____request(WASMGDBServer *server, char *payload); handle____request(WASMGDBServer *server, char *payload);
void
send_thread_stop_status(WASMGDBServer *server, uint32 status, korp_tid tid);
#endif #endif

View File

@ -7,56 +7,6 @@
#include "packets.h" #include "packets.h"
#include "gdbserver.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 void
write_data_raw(WASMGDBServer *gdbserver, const uint8 *data, ssize_t len) 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); write_packet_bytes(gdbserver, buf, buf_num_bytes);
wasm_runtime_free(buf); 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;
}

View File

@ -8,13 +8,10 @@
#include "gdbserver.h" #include "gdbserver.h"
bool void
read_packet(WASMGDBServer *gdbserver); write_data_raw(WASMGDBServer *gdbserver, const uint8 *data, ssize_t len);
void void
write_packet(WASMGDBServer *gdbserver, const char *data); write_packet(WASMGDBServer *gdbserver, const char *data);
void
inbuf_erase_head(WASMGDBServer *gdbserver, ssize_t end);
#endif #endif

View File

@ -284,6 +284,22 @@ wasm_cluster_del_exec_env(WASMCluster *cluster, WASMExecEnv *exec_env)
{ {
bool ret = true; bool ret = true;
bh_assert(exec_env->cluster == cluster); 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); os_mutex_lock(&cluster->lock);
if (bh_list_remove(&cluster->exec_env_list, exec_env) != 0) if (bh_list_remove(&cluster->exec_env_list, exec_env) != 0)
ret = false; ret = false;
@ -447,6 +463,9 @@ thread_manager_start_routine(void *arg)
free_aux_stack(cluster, exec_env->aux_stack_bottom.bottom); free_aux_stack(cluster, exec_env->aux_stack_bottom.bottom);
/* Detach the native thread here to ensure the resources are freed */ /* Detach the native thread here to ensure the resources are freed */
wasm_cluster_detach_thread(exec_env); wasm_cluster_detach_thread(exec_env);
#if WASM_ENABLE_DEBUG_INTERP != 0
wasm_cluster_thread_exited(exec_env);
#endif
/* Remove and destroy exec_env */ /* Remove and destroy exec_env */
wasm_cluster_del_exec_env(cluster, exec_env); wasm_cluster_del_exec_env(cluster, exec_env);
wasm_exec_env_destroy_internal(exec_env); wasm_exec_env_destroy_internal(exec_env);
@ -563,9 +582,7 @@ notify_debug_instance(WASMExecEnv *exec_env)
return; return;
} }
os_mutex_lock(&cluster->debug_inst->wait_lock); on_thread_stop_event(cluster->debug_inst, exec_env);
os_cond_signal(&cluster->debug_inst->wait_cond);
os_mutex_unlock(&cluster->debug_inst->wait_lock);
} }
void void
@ -744,7 +761,6 @@ wasm_cluster_cancel_thread(WASMExecEnv *exec_env)
/* Set the termination flag */ /* Set the termination flag */
#if WASM_ENABLE_DEBUG_INTERP != 0 #if WASM_ENABLE_DEBUG_INTERP != 0
wasm_cluster_thread_send_signal(exec_env, WAMR_SIG_TERM); wasm_cluster_thread_send_signal(exec_env, WAMR_SIG_TERM);
wasm_cluster_thread_exited(exec_env);
#else #else
exec_env->suspend_flags.flags |= 0x01; exec_env->suspend_flags.flags |= 0x01;
#endif #endif

View File

@ -71,6 +71,22 @@ fail:
return BHT_ERROR; 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 int
os_socket_listen(bh_socket_t socket, int max_client) os_socket_listen(bh_socket_t socket, int max_client)
{ {

View File

@ -226,6 +226,17 @@ os_socket_create(bh_socket_t *sock, int tcp_or_udp);
int int
os_socket_bind(bh_socket_t socket, const char *addr, int *port); 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 * Make the socket as a passive socket to accept incoming connection requests
* *

View File

@ -85,6 +85,20 @@ fail:
return BHT_ERROR; 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 int
os_socket_listen(bh_socket_t socket, int max_client) os_socket_listen(bh_socket_t socket, int max_client)
{ {