|
|
@@ -7,7 +7,7 @@
|
|
|
|
|
|
#include "bh_log.h"
|
|
|
#include "gdbserver.h"
|
|
|
-#include "platform_api_extension.h"
|
|
|
+#include "bh_platform.h"
|
|
|
#include "wasm_interp.h"
|
|
|
#include "wasm_opcode.h"
|
|
|
#include "wasm_runtime.h"
|
|
|
@@ -54,20 +54,11 @@ control_thread_routine(void *arg)
|
|
|
{
|
|
|
WASMDebugInstance *debug_inst = (WASMDebugInstance *)arg;
|
|
|
WASMDebugControlThread *control_thread = NULL;
|
|
|
- WASMCluster *cluster = NULL;
|
|
|
- WASMExecEnv *exec_env;
|
|
|
- bh_assert(debug_inst);
|
|
|
|
|
|
control_thread = debug_inst->control_thread;
|
|
|
bh_assert(control_thread);
|
|
|
|
|
|
- cluster = debug_inst->cluster;
|
|
|
- bh_assert(cluster);
|
|
|
-
|
|
|
- exec_env = bh_list_first_elem(&cluster->exec_env_list);
|
|
|
- bh_assert(exec_env);
|
|
|
-
|
|
|
- os_mutex_lock(&exec_env->wait_lock);
|
|
|
+ os_mutex_lock(&debug_inst->wait_lock);
|
|
|
|
|
|
control_thread->status = RUNNING;
|
|
|
|
|
|
@@ -84,19 +75,31 @@ control_thread_routine(void *arg)
|
|
|
LOG_WARNING("control thread of debug object %p start\n", debug_inst);
|
|
|
|
|
|
control_thread->server =
|
|
|
- wasm_launch_gdbserver(control_thread->ip_addr, control_thread->port);
|
|
|
+ wasm_create_gdbserver(control_thread->ip_addr, &control_thread->port);
|
|
|
+
|
|
|
if (!control_thread->server) {
|
|
|
LOG_ERROR("Failed to create debug server\n");
|
|
|
- os_cond_signal(&exec_env->wait_cond);
|
|
|
- os_mutex_unlock(&exec_env->wait_lock);
|
|
|
+ os_cond_signal(&debug_inst->wait_cond);
|
|
|
+ os_mutex_unlock(&debug_inst->wait_lock);
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
control_thread->server->thread = control_thread;
|
|
|
|
|
|
- /* control thread ready, notify main thread */
|
|
|
- os_cond_signal(&exec_env->wait_cond);
|
|
|
- os_mutex_unlock(&exec_env->wait_lock);
|
|
|
+ /*
|
|
|
+ * wasm gdbserver created, the execution thread
|
|
|
+ * doesn't need to wait for the debugger connection,
|
|
|
+ * so we wake up the execution thread before listen
|
|
|
+ */
|
|
|
+ os_cond_signal(&debug_inst->wait_cond);
|
|
|
+ os_mutex_unlock(&debug_inst->wait_lock);
|
|
|
+
|
|
|
+ /* wait lldb client to connect */
|
|
|
+ if (!wasm_gdbserver_listen(control_thread->server)) {
|
|
|
+ LOG_ERROR("Failed while connecting debugger\n");
|
|
|
+ wasm_runtime_free(control_thread->server);
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
|
|
|
while (true) {
|
|
|
os_mutex_lock(&control_thread->wait_lock);
|
|
|
@@ -112,7 +115,7 @@ control_thread_routine(void *arg)
|
|
|
os_mutex_unlock(&control_thread->wait_lock);
|
|
|
}
|
|
|
|
|
|
- LOG_VERBOSE("control thread of debug object %p stop\n", debug_inst);
|
|
|
+ LOG_VERBOSE("control thread of debug object [%p] stopped\n", debug_inst);
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
@@ -120,12 +123,6 @@ static WASMDebugControlThread *
|
|
|
wasm_debug_control_thread_create(WASMDebugInstance *debug_instance)
|
|
|
{
|
|
|
WASMDebugControlThread *control_thread;
|
|
|
- WASMCluster *cluster = debug_instance->cluster;
|
|
|
- WASMExecEnv *exec_env;
|
|
|
- bh_assert(cluster);
|
|
|
-
|
|
|
- exec_env = bh_list_first_elem(&cluster->exec_env_list);
|
|
|
- bh_assert(exec_env);
|
|
|
|
|
|
if (!(control_thread =
|
|
|
wasm_runtime_malloc(sizeof(WASMDebugControlThread)))) {
|
|
|
@@ -139,18 +136,18 @@ wasm_debug_control_thread_create(WASMDebugInstance *debug_instance)
|
|
|
|
|
|
debug_instance->control_thread = control_thread;
|
|
|
|
|
|
- os_mutex_lock(&exec_env->wait_lock);
|
|
|
+ os_mutex_lock(&debug_instance->wait_lock);
|
|
|
|
|
|
if (0
|
|
|
!= os_thread_create(&control_thread->tid, control_thread_routine,
|
|
|
debug_instance, APP_THREAD_STACK_SIZE_MAX)) {
|
|
|
- os_mutex_unlock(&control_thread->wait_lock);
|
|
|
+ os_mutex_unlock(&debug_instance->wait_lock);
|
|
|
goto fail1;
|
|
|
}
|
|
|
|
|
|
/* wait until the debug control thread ready */
|
|
|
- os_cond_wait(&exec_env->wait_cond, &exec_env->wait_lock);
|
|
|
- os_mutex_unlock(&exec_env->wait_lock);
|
|
|
+ os_cond_wait(&debug_instance->wait_cond, &debug_instance->wait_lock);
|
|
|
+ os_mutex_unlock(&debug_instance->wait_lock);
|
|
|
if (!control_thread->server)
|
|
|
goto fail1;
|
|
|
|
|
|
@@ -174,7 +171,8 @@ static void
|
|
|
wasm_debug_control_thread_destroy(WASMDebugInstance *debug_instance)
|
|
|
{
|
|
|
WASMDebugControlThread *control_thread = debug_instance->control_thread;
|
|
|
- LOG_VERBOSE("control thread of debug object %p stop\n", debug_instance);
|
|
|
+ LOG_VERBOSE("stopping control thread of debug object [%p]\n",
|
|
|
+ debug_instance);
|
|
|
control_thread->status = STOPPED;
|
|
|
os_mutex_lock(&control_thread->wait_lock);
|
|
|
wasm_close_gdbserver(control_thread->server);
|
|
|
@@ -286,6 +284,15 @@ wasm_debug_instance_create(WASMCluster *cluster)
|
|
|
return NULL;
|
|
|
}
|
|
|
memset(instance, 0, sizeof(WASMDebugInstance));
|
|
|
+
|
|
|
+ if (os_mutex_init(&instance->wait_lock) != 0) {
|
|
|
+ goto fail1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (os_cond_init(&instance->wait_cond) != 0) {
|
|
|
+ goto fail2;
|
|
|
+ }
|
|
|
+
|
|
|
bh_list_init(&instance->break_point_list);
|
|
|
|
|
|
instance->cluster = cluster;
|
|
|
@@ -297,29 +304,21 @@ wasm_debug_instance_create(WASMCluster *cluster)
|
|
|
if (!wasm_debug_control_thread_create(instance)) {
|
|
|
LOG_ERROR("WASM Debug Engine error: failed to create control thread");
|
|
|
wasm_runtime_free(instance);
|
|
|
- return NULL;
|
|
|
+ goto fail3;
|
|
|
}
|
|
|
|
|
|
- return instance;
|
|
|
-}
|
|
|
+ wasm_cluster_set_debug_inst(cluster, instance);
|
|
|
|
|
|
-static WASMDebugInstance *
|
|
|
-wasm_cluster_get_debug_instance(WASMDebugEngine *engine, WASMCluster *cluster)
|
|
|
-{
|
|
|
- WASMDebugInstance *instance;
|
|
|
+ return instance;
|
|
|
|
|
|
- os_mutex_lock(&g_debug_engine->instance_list_lock);
|
|
|
- instance = bh_list_first_elem(&engine->debug_instance_list);
|
|
|
- while (instance) {
|
|
|
- if (instance->cluster == cluster) {
|
|
|
- os_mutex_unlock(&g_debug_engine->instance_list_lock);
|
|
|
- return instance;
|
|
|
- }
|
|
|
- instance = bh_list_elem_next(instance);
|
|
|
- }
|
|
|
- os_mutex_unlock(&g_debug_engine->instance_list_lock);
|
|
|
+fail3:
|
|
|
+ os_cond_destroy(&instance->wait_cond);
|
|
|
+fail2:
|
|
|
+ os_mutex_destroy(&instance->wait_lock);
|
|
|
+fail1:
|
|
|
+ wasm_runtime_free(instance);
|
|
|
|
|
|
- return instance;
|
|
|
+ return NULL;
|
|
|
}
|
|
|
|
|
|
static void
|
|
|
@@ -347,7 +346,7 @@ wasm_debug_instance_destroy(WASMCluster *cluster)
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- instance = wasm_cluster_get_debug_instance(g_debug_engine, cluster);
|
|
|
+ instance = cluster->debug_inst;
|
|
|
if (instance) {
|
|
|
/* destroy control thread */
|
|
|
wasm_debug_control_thread_destroy(instance);
|
|
|
@@ -359,7 +358,11 @@ wasm_debug_instance_destroy(WASMCluster *cluster)
|
|
|
/* destroy all breakpoints */
|
|
|
wasm_debug_instance_destroy_breakpoints(instance);
|
|
|
|
|
|
+ os_mutex_destroy(&instance->wait_lock);
|
|
|
+ os_cond_destroy(&instance->wait_cond);
|
|
|
+
|
|
|
wasm_runtime_free(instance);
|
|
|
+ cluster->debug_inst = NULL;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -434,47 +437,78 @@ wasm_debug_instance_get_tids(WASMDebugInstance *instance, uint64 tids[],
|
|
|
int len)
|
|
|
{
|
|
|
WASMExecEnv *exec_env;
|
|
|
- int i = 0;
|
|
|
+ int i = 0, threads_num = 0;
|
|
|
|
|
|
if (!instance)
|
|
|
return 0;
|
|
|
|
|
|
exec_env = bh_list_first_elem(&instance->cluster->exec_env_list);
|
|
|
while (exec_env && i < len) {
|
|
|
- tids[i++] = exec_env->handle;
|
|
|
+ /* Some threads may not be ready */
|
|
|
+ if (exec_env->handle != 0) {
|
|
|
+ tids[i++] = exec_env->handle;
|
|
|
+ threads_num++;
|
|
|
+ }
|
|
|
exec_env = bh_list_elem_next(exec_env);
|
|
|
}
|
|
|
- LOG_VERBOSE("find %d tids\n", i);
|
|
|
- return i;
|
|
|
+ LOG_VERBOSE("find %d tids\n", threads_num);
|
|
|
+ return threads_num;
|
|
|
}
|
|
|
|
|
|
-uint64
|
|
|
-wasm_debug_instance_wait_thread(WASMDebugInstance *instance, uint64 tid,
|
|
|
- uint32 *status)
|
|
|
+static WASMExecEnv *
|
|
|
+get_stopped_thread(WASMCluster *cluster)
|
|
|
{
|
|
|
WASMExecEnv *exec_env;
|
|
|
- WASMExecEnv *last_exec_env = NULL;
|
|
|
|
|
|
- exec_env = bh_list_first_elem(&instance->cluster->exec_env_list);
|
|
|
+ exec_env = bh_list_first_elem(&cluster->exec_env_list);
|
|
|
while (exec_env) {
|
|
|
- last_exec_env = exec_env;
|
|
|
- if (instance->current_tid != 0
|
|
|
- && last_exec_env->handle == instance->current_tid) {
|
|
|
- break;
|
|
|
+ if (exec_env->current_status->running_status != STATUS_RUNNING) {
|
|
|
+ return exec_env;
|
|
|
}
|
|
|
exec_env = bh_list_elem_next(exec_env);
|
|
|
}
|
|
|
|
|
|
- if (last_exec_env) {
|
|
|
- wasm_cluster_wait_thread_status(last_exec_env, status);
|
|
|
- if (instance->current_tid == 0)
|
|
|
- instance->current_tid = last_exec_env->handle;
|
|
|
- return last_exec_env->handle;
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
+uint64
|
|
|
+wasm_debug_instance_wait_thread(WASMDebugInstance *instance, uint64 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);
|
|
|
}
|
|
|
- else {
|
|
|
- *status = ~0;
|
|
|
+ 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 = exec_env->current_status->signal_flag;
|
|
|
+ return exec_env->handle;
|
|
|
+}
|
|
|
+
|
|
|
+uint32
|
|
|
+wasm_debug_instance_get_thread_status(WASMDebugInstance *instance, uint64 tid)
|
|
|
+{
|
|
|
+ WASMExecEnv *exec_env = NULL;
|
|
|
+
|
|
|
+ exec_env = bh_list_first_elem(&instance->cluster->exec_env_list);
|
|
|
+ while (exec_env) {
|
|
|
+ if (exec_env->handle == tid) {
|
|
|
+ return exec_env->current_status->signal_flag;
|
|
|
+ }
|
|
|
+ exec_env = bh_list_elem_next(exec_env);
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
void
|