mirror of
https://github.com/bytecodealliance/wasm-micro-runtime.git
synced 2025-05-08 20:56:13 +00:00
[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:
parent
985dea9493
commit
3fe191b0df
|
@ -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)
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 *
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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
|
||||||
*
|
*
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue
Block a user