[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)
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)

View File

@ -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 */

View File

@ -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;
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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 *

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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)
{

View File

@ -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
*

View File

@ -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)
{