mirror of
https://github.com/bytecodealliance/wasm-micro-runtime.git
synced 2025-03-11 16:35:33 +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)
|
||||
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)
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 @@ fail:
|
|||
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 @@ fail:
|
|||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* The packet layout is:
|
||||
* '$' + payload + '#' + checksum(2bytes)
|
||||
* ^
|
||||
* packetend_ptr
|
||||
*/
|
||||
static void
|
||||
process_packet(WASMGDBServer *server)
|
||||
{
|
||||
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];
|
||||
uint8 *inbuf = (uint8 *)server->receive_ctx->receive_buffer;
|
||||
char request;
|
||||
char *payload = NULL;
|
||||
uint8 checksum = 0;
|
||||
|
||||
if (packet_size == 1) {
|
||||
LOG_VERBOSE("receive empty request, ignore it\n");
|
||||
request = inbuf[0];
|
||||
|
||||
if (request == '\0') {
|
||||
LOG_VERBOSE("ignore empty request");
|
||||
return;
|
||||
}
|
||||
|
||||
bh_assert('$' == inbuf[0]);
|
||||
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];
|
||||
payload = (char *)&inbuf[1];
|
||||
|
||||
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
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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 *
|
||||
|
|
|
@ -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);
|
||||
|
||||
tid = wasm_debug_instance_wait_thread(
|
||||
(WASMDebugInstance *)server->thread->debug_instance, tid, &status);
|
||||
/* 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);
|
||||
|
||||
/* 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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -8,13 +8,10 @@
|
|||
|
||||
#include "gdbserver.h"
|
||||
|
||||
bool
|
||||
read_packet(WASMGDBServer *gdbserver);
|
||||
void
|
||||
write_data_raw(WASMGDBServer *gdbserver, const uint8 *data, ssize_t len);
|
||||
|
||||
void
|
||||
write_packet(WASMGDBServer *gdbserver, const char *data);
|
||||
|
||||
void
|
||||
inbuf_erase_head(WASMGDBServer *gdbserver, ssize_t end);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -71,6 +71,22 @@ fail:
|
|||
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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
*
|
||||
|
|
|
@ -85,6 +85,20 @@ fail:
|
|||
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)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue
Block a user