[source debug] refine some code in source debugging (#856)
- move the wait_cond from exec_env to debug_instance, so the debug thread can be waken up by any threads - process more general query message from debugger - refine debug instance create/destroy mechanism - avoid creating debug instance during module instantiating - avoid blocking execution thread during creating debug instance - update related documents
This commit is contained in:
@ -148,9 +148,6 @@ wasm_exec_env_create(struct WASMModuleInstanceCommon *module_inst,
|
||||
wasm_exec_env_destroy_internal(exec_env);
|
||||
return NULL;
|
||||
}
|
||||
#if WASM_ENABLE_DEBUG_INTERP != 0
|
||||
wasm_debug_instance_create(cluster);
|
||||
#endif
|
||||
#endif /* end of WASM_ENABLE_THREAD_MGR */
|
||||
|
||||
return exec_env;
|
||||
@ -165,7 +162,6 @@ wasm_exec_env_destroy(WASMExecEnv *exec_env)
|
||||
if (cluster) {
|
||||
#if WASM_ENABLE_DEBUG_INTERP != 0
|
||||
wasm_cluster_thread_exited(exec_env);
|
||||
wasm_debug_instance_destroy(cluster);
|
||||
#endif
|
||||
wasm_cluster_terminate_all_except_self(cluster, exec_env);
|
||||
wasm_cluster_del_exec_env(cluster, exec_env);
|
||||
|
||||
@ -294,6 +294,26 @@ get_package_type(const uint8 *buf, uint32 size)
|
||||
return Package_Type_Unknown;
|
||||
}
|
||||
|
||||
#if (WASM_ENABLE_THREAD_MGR != 0) && (WASM_ENABLE_DEBUG_INTERP != 0)
|
||||
uint32
|
||||
wasm_runtime_start_debug_instance(WASMExecEnv *exec_env)
|
||||
{
|
||||
WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env);
|
||||
bh_assert(cluster);
|
||||
|
||||
if (cluster->debug_inst) {
|
||||
LOG_WARNING("Cluster already bind to a debug instance");
|
||||
return cluster->debug_inst->control_thread->port;
|
||||
}
|
||||
|
||||
if (wasm_debug_instance_create(cluster)) {
|
||||
return cluster->debug_inst->control_thread->port;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
static module_reader reader;
|
||||
static module_destroyer destroyer;
|
||||
@ -1431,7 +1451,7 @@ wasm_runtime_create_exec_env_and_call_wasm(
|
||||
if (module_inst->module_type == Wasm_Module_Bytecode)
|
||||
ret = wasm_create_exec_env_and_call_function(
|
||||
(WASMModuleInstance *)module_inst, (WASMFunctionInstance *)function,
|
||||
argc, argv);
|
||||
argc, argv, true);
|
||||
#endif
|
||||
#if WASM_ENABLE_AOT != 0
|
||||
if (module_inst->module_type == Wasm_Module_AoT)
|
||||
|
||||
@ -494,6 +494,12 @@ wasm_runtime_call_wasm_v(WASMExecEnv *exec_env,
|
||||
uint32 num_results, wasm_val_t *results,
|
||||
uint32 num_args, ...);
|
||||
|
||||
#if WASM_ENABLE_DEBUG_INTERP != 0
|
||||
/* See wasm_export.h for description */
|
||||
WASM_RUNTIME_API_EXTERN uint32
|
||||
wasm_runtime_start_debug_instance(WASMExecEnv *exec_env);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Call a function reference of a given WASM runtime instance with
|
||||
* arguments.
|
||||
|
||||
@ -408,6 +408,26 @@ wasm_runtime_create_exec_env(wasm_module_inst_t module_inst,
|
||||
WASM_RUNTIME_API_EXTERN void
|
||||
wasm_runtime_destroy_exec_env(wasm_exec_env_t exec_env);
|
||||
|
||||
/**
|
||||
* Start debug instance based on given execution environment.
|
||||
* Note:
|
||||
* The debug instance will be destroyed during destroying the
|
||||
* execution environment, developers don't need to destroy it
|
||||
* manually.
|
||||
* If the cluster of this execution environment has already
|
||||
* been bound to a debug instance, this function will return true
|
||||
* directly.
|
||||
* If developer spawns some exec_env by wasm_runtime_spawn_exec_env,
|
||||
* don't need to call this function for every spawned exec_env as
|
||||
* they are sharing the same cluster with the main exec_env.
|
||||
*
|
||||
* @param exec_env the execution environment to start debug instance
|
||||
*
|
||||
* @return debug port if success, 0 otherwise.
|
||||
*/
|
||||
WASM_RUNTIME_API_EXTERN uint32_t
|
||||
wasm_runtime_start_debug_instance(wasm_exec_env_t exec_env);
|
||||
|
||||
/**
|
||||
* Initialize thread environment.
|
||||
* Note:
|
||||
|
||||
@ -419,6 +419,20 @@ struct WASMModule {
|
||||
uint64 buf_code_size;
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_DEBUG_INTERP != 0
|
||||
/**
|
||||
* Count how many instances reference this module. When source
|
||||
* debugging feature enabled, the debugger may modify the code
|
||||
* section of the module, so we need to report a warning if user
|
||||
* create several instances based on the same module
|
||||
*
|
||||
* Sub_instances created by lib-pthread or spawn API will not
|
||||
* influence or check the ref count
|
||||
*/
|
||||
uint32 ref_count;
|
||||
korp_mutex ref_count_lock;
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_CUSTOM_NAME_SECTION != 0
|
||||
const uint8 *name_section_buf;
|
||||
const uint8 *name_section_buf_end;
|
||||
|
||||
@ -3237,6 +3237,10 @@ create_module(char *error_buf, uint32 error_buf_size)
|
||||
#endif
|
||||
#if WASM_ENABLE_DEBUG_INTERP != 0
|
||||
bh_list_init(&module->fast_opcode_list);
|
||||
if (os_mutex_init(&module->ref_count_lock) != 0) {
|
||||
wasm_runtime_free(module);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
return module;
|
||||
}
|
||||
@ -3568,6 +3572,7 @@ wasm_loader_unload(WASMModule *module)
|
||||
wasm_runtime_free(fast_opcode);
|
||||
fast_opcode = next;
|
||||
}
|
||||
os_mutex_destroy(&module->ref_count_lock);
|
||||
#endif
|
||||
wasm_runtime_free(module);
|
||||
}
|
||||
|
||||
@ -900,7 +900,7 @@ execute_post_inst_function(WASMModuleInstance *module_inst)
|
||||
return true;
|
||||
|
||||
return wasm_create_exec_env_and_call_function(module_inst, post_inst_func,
|
||||
0, NULL);
|
||||
0, NULL, false);
|
||||
}
|
||||
|
||||
#if WASM_ENABLE_BULK_MEMORY != 0
|
||||
@ -929,7 +929,7 @@ execute_memory_init_function(WASMModuleInstance *module_inst)
|
||||
return true;
|
||||
|
||||
return wasm_create_exec_env_and_call_function(module_inst, memory_init_func,
|
||||
0, NULL);
|
||||
0, NULL, false);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -944,7 +944,8 @@ execute_start_function(WASMModuleInstance *module_inst)
|
||||
bh_assert(!func->is_import_func && func->param_cell_num == 0
|
||||
&& func->ret_cell_num == 0);
|
||||
|
||||
return wasm_create_exec_env_and_call_function(module_inst, func, 0, NULL);
|
||||
return wasm_create_exec_env_and_call_function(module_inst, func, 0, NULL,
|
||||
false);
|
||||
}
|
||||
|
||||
static bool
|
||||
@ -972,11 +973,11 @@ execute_malloc_function(WASMModuleInstance *module_inst,
|
||||
}
|
||||
|
||||
ret = wasm_create_exec_env_and_call_function(module_inst, malloc_func, argc,
|
||||
argv);
|
||||
argv, false);
|
||||
|
||||
if (retain_func && ret) {
|
||||
ret = wasm_create_exec_env_and_call_function(module_inst, retain_func,
|
||||
1, argv);
|
||||
1, argv, false);
|
||||
}
|
||||
|
||||
if (ret)
|
||||
@ -992,7 +993,7 @@ execute_free_function(WASMModuleInstance *module_inst,
|
||||
|
||||
argv[0] = offset;
|
||||
return wasm_create_exec_env_and_call_function(module_inst, free_func, 1,
|
||||
argv);
|
||||
argv, false);
|
||||
}
|
||||
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
@ -1125,6 +1126,19 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, uint32 stack_size,
|
||||
if (!module)
|
||||
return NULL;
|
||||
|
||||
#if WASM_ENABLE_DEBUG_INTERP != 0
|
||||
if (!is_sub_inst) {
|
||||
os_mutex_lock(&module->ref_count_lock);
|
||||
if (module->ref_count != 0) {
|
||||
LOG_WARNING(
|
||||
"warning: multiple instances referencing the same module may "
|
||||
"cause unexpected behaviour during debugging");
|
||||
}
|
||||
module->ref_count++;
|
||||
os_mutex_unlock(&module->ref_count_lock);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Check heap size */
|
||||
heap_size = align_uint(heap_size, 8);
|
||||
if (heap_size > APP_HEAP_SIZE_MAX)
|
||||
@ -1133,6 +1147,13 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, uint32 stack_size,
|
||||
/* Allocate the memory */
|
||||
if (!(module_inst = runtime_malloc(sizeof(WASMModuleInstance), error_buf,
|
||||
error_buf_size))) {
|
||||
#if WASM_ENABLE_DEBUG_INTERP != 0
|
||||
if (!is_sub_inst) {
|
||||
os_mutex_lock(&module->ref_count_lock);
|
||||
module->ref_count--;
|
||||
os_mutex_unlock(&module->ref_count_lock);
|
||||
}
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -1519,7 +1540,9 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, uint32 stack_size,
|
||||
(WASMModuleInstanceCommon *)module_inst);
|
||||
#endif
|
||||
(void)global_data_end;
|
||||
|
||||
return module_inst;
|
||||
|
||||
fail:
|
||||
wasm_deinstantiate(module_inst, false);
|
||||
return NULL;
|
||||
@ -1576,6 +1599,14 @@ wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_DEBUG_INTERP != 0
|
||||
if (!is_sub_inst) {
|
||||
os_mutex_lock(&module_inst->module->ref_count_lock);
|
||||
module_inst->module->ref_count--;
|
||||
os_mutex_unlock(&module_inst->module->ref_count_lock);
|
||||
}
|
||||
#endif
|
||||
|
||||
wasm_runtime_free(module_inst);
|
||||
}
|
||||
|
||||
@ -1661,7 +1692,8 @@ wasm_call_function(WASMExecEnv *exec_env, WASMFunctionInstance *function,
|
||||
bool
|
||||
wasm_create_exec_env_and_call_function(WASMModuleInstance *module_inst,
|
||||
WASMFunctionInstance *func,
|
||||
unsigned argc, uint32 argv[])
|
||||
unsigned argc, uint32 argv[],
|
||||
bool enable_debug)
|
||||
{
|
||||
WASMExecEnv *exec_env;
|
||||
bool ret;
|
||||
@ -1680,6 +1712,11 @@ wasm_create_exec_env_and_call_function(WASMModuleInstance *module_inst,
|
||||
}
|
||||
|
||||
#if WASM_ENABLE_THREAD_MGR != 0
|
||||
if (enable_debug) {
|
||||
#if WASM_ENABLE_DEBUG_INTERP != 0
|
||||
wasm_runtime_start_debug_instance(exec_env);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@ -320,7 +320,8 @@ wasm_call_function(WASMExecEnv *exec_env, WASMFunctionInstance *function,
|
||||
bool
|
||||
wasm_create_exec_env_and_call_function(WASMModuleInstance *module_inst,
|
||||
WASMFunctionInstance *function,
|
||||
unsigned argc, uint32 argv[]);
|
||||
unsigned argc, uint32 argv[],
|
||||
bool enable_debug);
|
||||
|
||||
bool
|
||||
wasm_create_exec_env_singleton(WASMModuleInstance *module_inst);
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
static WASMDebugInstance *
|
||||
wasm_cluster_get_debug_instance(WASMDebugEngine *engine, WASMCluster *cluster)
|
||||
{
|
||||
WASMDebugInstance *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);
|
||||
wasm_cluster_set_debug_inst(cluster, instance);
|
||||
|
||||
return instance;
|
||||
|
||||
fail3:
|
||||
os_cond_destroy(&instance->wait_cond);
|
||||
fail2:
|
||||
os_mutex_destroy(&instance->wait_lock);
|
||||
fail1:
|
||||
wasm_runtime_free(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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
uint64
|
||||
wasm_debug_instance_wait_thread(WASMDebugInstance *instance, uint64 tid,
|
||||
uint32 *status)
|
||||
{
|
||||
WASMExecEnv *exec_env;
|
||||
WASMExecEnv *last_exec_env = NULL;
|
||||
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 = 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) {
|
||||
last_exec_env = exec_env;
|
||||
if (instance->current_tid != 0
|
||||
&& last_exec_env->handle == instance->current_tid) {
|
||||
break;
|
||||
if (exec_env->handle == tid) {
|
||||
return exec_env->current_status->signal_flag;
|
||||
}
|
||||
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;
|
||||
}
|
||||
else {
|
||||
*status = ~0;
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@ -42,6 +42,8 @@ typedef struct WASMDebugInstance {
|
||||
WASMCluster *cluster;
|
||||
uint32 id;
|
||||
korp_tid current_tid;
|
||||
korp_mutex wait_lock;
|
||||
korp_cond wait_cond;
|
||||
} WASMDebugInstance;
|
||||
|
||||
typedef enum WASMDebugEventKind {
|
||||
@ -160,6 +162,9 @@ uint64
|
||||
wasm_debug_instance_wait_thread(WASMDebugInstance *instance, uint64 tid,
|
||||
uint32 *status);
|
||||
|
||||
uint32
|
||||
wasm_debug_instance_get_thread_status(WASMDebugInstance *instance, uint64 tid);
|
||||
|
||||
bool
|
||||
wasm_debug_instance_singlestep(WASMDebugInstance *instance, uint64 tid);
|
||||
|
||||
|
||||
@ -51,17 +51,18 @@ static struct packet_handler_elem packet_handler_table[255] = {
|
||||
};
|
||||
|
||||
WASMGDBServer *
|
||||
wasm_launch_gdbserver(char *host, int port)
|
||||
wasm_create_gdbserver(char *host, int *port)
|
||||
{
|
||||
int listen_fd = -1;
|
||||
const int one = 1;
|
||||
struct sockaddr_in addr;
|
||||
socklen_t socklen;
|
||||
int ret;
|
||||
int sockt_fd = 0;
|
||||
|
||||
WASMGDBServer *server;
|
||||
|
||||
bh_assert(port);
|
||||
|
||||
if (!(server = wasm_runtime_malloc(sizeof(WASMGDBServer)))) {
|
||||
LOG_ERROR("wasm gdb server error: failed to allocate memory");
|
||||
return NULL;
|
||||
@ -90,7 +91,7 @@ wasm_launch_gdbserver(char *host, int port)
|
||||
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = inet_addr(host);
|
||||
addr.sin_port = htons(port);
|
||||
addr.sin_port = htons(*port);
|
||||
|
||||
ret = bind(listen_fd, (struct sockaddr *)&addr, sizeof(addr));
|
||||
if (ret < 0) {
|
||||
@ -103,25 +104,12 @@ wasm_launch_gdbserver(char *host, int port)
|
||||
LOG_ERROR("%s", strerror(errno));
|
||||
goto fail;
|
||||
}
|
||||
LOG_WARNING("Debug server listening on %s:%d\n", host,
|
||||
ntohs(addr.sin_port));
|
||||
|
||||
LOG_WARNING("Listening on %s:%d\n", host, ntohs(addr.sin_port));
|
||||
|
||||
ret = listen(listen_fd, 1);
|
||||
if (ret < 0) {
|
||||
LOG_ERROR("wasm gdb server error: listen() failed");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
*port = ntohs(addr.sin_port);
|
||||
server->listen_fd = listen_fd;
|
||||
|
||||
sockt_fd = accept(listen_fd, NULL, NULL);
|
||||
if (sockt_fd < 0) {
|
||||
LOG_ERROR("wasm gdb server error: accept() failed");
|
||||
goto fail;
|
||||
}
|
||||
LOG_VERBOSE("accept gdb client");
|
||||
server->socket_fd = sockt_fd;
|
||||
server->noack = false;
|
||||
return server;
|
||||
|
||||
fail:
|
||||
@ -134,6 +122,35 @@ fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool
|
||||
wasm_gdbserver_listen(WASMGDBServer *server)
|
||||
{
|
||||
int ret;
|
||||
int sockt_fd = 0;
|
||||
|
||||
ret = listen(server->listen_fd, 1);
|
||||
if (ret < 0) {
|
||||
LOG_ERROR("wasm gdb server error: listen() failed");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
sockt_fd = accept(server->listen_fd, NULL, NULL);
|
||||
if (sockt_fd < 0) {
|
||||
LOG_ERROR("wasm gdb server error: accept() failed");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
LOG_VERBOSE("accept gdb client");
|
||||
server->socket_fd = sockt_fd;
|
||||
server->noack = false;
|
||||
return true;
|
||||
|
||||
fail:
|
||||
shutdown(server->listen_fd, SHUT_RDWR);
|
||||
close(server->listen_fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
wasm_close_gdbserver(WASMGDBServer *server)
|
||||
{
|
||||
|
||||
@ -33,7 +33,10 @@ typedef struct WASMGDBServer {
|
||||
} WASMGDBServer;
|
||||
|
||||
WASMGDBServer *
|
||||
wasm_launch_gdbserver(char *addr, int port);
|
||||
wasm_create_gdbserver(char *addr, int *port);
|
||||
|
||||
bool
|
||||
wasm_gdbserver_listen(WASMGDBServer *server);
|
||||
|
||||
void
|
||||
wasm_close_gdbserver(WASMGDBServer *server);
|
||||
|
||||
@ -17,6 +17,9 @@
|
||||
#define MAX_PACKET_SIZE (0x20000)
|
||||
static char tmpbuf[MAX_PACKET_SIZE];
|
||||
|
||||
static void
|
||||
send_thread_stop_status(WASMGDBServer *server, uint32_t status, uint64_t tid);
|
||||
|
||||
void
|
||||
handle_generay_set(WASMGDBServer *server, char *payload)
|
||||
{
|
||||
@ -261,6 +264,20 @@ handle_generay_query(WASMGDBServer *server, char *payload)
|
||||
if (args && (!strcmp(name, "WasmGlobal"))) {
|
||||
porcess_wasm_global(server, args);
|
||||
}
|
||||
|
||||
if (!strcmp(name, "Offsets")) {
|
||||
write_packet(server, "");
|
||||
}
|
||||
|
||||
if (!strncmp(name, "ThreadStopInfo", strlen("ThreadStopInfo"))) {
|
||||
int32 prefix_len = strlen("ThreadStopInfo");
|
||||
uint64 tid = strtol(name + prefix_len, NULL, 16);
|
||||
|
||||
uint32 status = wasm_debug_instance_get_thread_status(
|
||||
server->thread->debug_instance, tid);
|
||||
|
||||
send_thread_stop_status(server, status, tid);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@ -332,19 +349,32 @@ handle_v_packet(WASMGDBServer *server, char *payload)
|
||||
write_packet(server, "vCont;c;C;s;S;");
|
||||
|
||||
if (!strcmp("Cont", name)) {
|
||||
if (args && args[0] == 's') {
|
||||
char *numstring = strchr(args, ':');
|
||||
if (numstring) {
|
||||
*numstring++ = '\0';
|
||||
uint64_t tid = strtol(numstring, NULL, 16);
|
||||
wasm_debug_instance_set_cur_thread(
|
||||
(WASMDebugInstance *)server->thread->debug_instance, tid);
|
||||
wasm_debug_instance_singlestep(
|
||||
(WASMDebugInstance *)server->thread->debug_instance, tid);
|
||||
tid = wasm_debug_instance_wait_thread(
|
||||
(WASMDebugInstance *)server->thread->debug_instance, tid,
|
||||
&status);
|
||||
send_thread_stop_status(server, status, tid);
|
||||
if (args) {
|
||||
if (args[0] == 's' || args[0] == 'c') {
|
||||
char *numstring = strchr(args, ':');
|
||||
if (numstring) {
|
||||
*numstring++ = '\0';
|
||||
uint64_t tid = strtol(numstring, NULL, 16);
|
||||
wasm_debug_instance_set_cur_thread(
|
||||
(WASMDebugInstance *)server->thread->debug_instance,
|
||||
tid);
|
||||
|
||||
if (args[0] == 's') {
|
||||
wasm_debug_instance_singlestep(
|
||||
(WASMDebugInstance *)server->thread->debug_instance,
|
||||
tid);
|
||||
}
|
||||
else {
|
||||
wasm_debug_instance_continue(
|
||||
(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -332,7 +332,7 @@ create_cluster_info(WASMCluster *cluster)
|
||||
if (!(node = wasm_runtime_malloc(sizeof(ClusterInfoNode)))) {
|
||||
return NULL;
|
||||
}
|
||||
memset(node, 0, sizeof(WASMCluster));
|
||||
memset(node, 0, sizeof(ClusterInfoNode));
|
||||
|
||||
node->thread_list = &node->thread_list_head;
|
||||
ret = bh_list_init(node->thread_list);
|
||||
|
||||
@ -5,6 +5,10 @@
|
||||
|
||||
#include "thread_manager.h"
|
||||
|
||||
#if WASM_ENABLE_DEBUG_INTERP != 0
|
||||
#include "debug_engine.h"
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
bh_list_link l;
|
||||
void (*destroy_cb)(WASMCluster *);
|
||||
@ -227,6 +231,11 @@ wasm_cluster_destroy(WASMCluster *cluster)
|
||||
wasm_runtime_free(cluster->stack_tops);
|
||||
if (cluster->stack_segment_occupied)
|
||||
wasm_runtime_free(cluster->stack_segment_occupied);
|
||||
|
||||
#if WASM_ENABLE_DEBUG_INTERP != 0
|
||||
wasm_debug_instance_destroy(cluster);
|
||||
#endif
|
||||
|
||||
wasm_runtime_free(cluster);
|
||||
}
|
||||
|
||||
@ -488,31 +497,18 @@ wasm_cluster_create_exenv_status()
|
||||
WASMCurrentEnvStatus *status;
|
||||
|
||||
if (!(status = wasm_runtime_malloc(sizeof(WASMCurrentEnvStatus)))) {
|
||||
goto fail;
|
||||
return NULL;
|
||||
}
|
||||
if (os_mutex_init(&status->wait_lock) != 0)
|
||||
goto fail1;
|
||||
|
||||
if (os_cond_init(&status->wait_cond) != 0)
|
||||
goto fail2;
|
||||
status->step_count = 0;
|
||||
status->signal_flag = 0;
|
||||
status->running_status = 0;
|
||||
return status;
|
||||
|
||||
fail2:
|
||||
os_mutex_destroy(&status->wait_lock);
|
||||
fail1:
|
||||
wasm_runtime_free(status);
|
||||
fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
wasm_cluster_destroy_exenv_status(WASMCurrentEnvStatus *status)
|
||||
{
|
||||
os_mutex_destroy(&status->wait_lock);
|
||||
os_cond_destroy(&status->wait_cond);
|
||||
wasm_runtime_free(status);
|
||||
}
|
||||
|
||||
@ -529,29 +525,34 @@ wasm_cluster_clear_thread_signal(WASMExecEnv *exec_env)
|
||||
exec_env->current_status->signal_flag = 0;
|
||||
}
|
||||
|
||||
void
|
||||
wasm_cluster_wait_thread_status(WASMExecEnv *exec_env, uint32 *status)
|
||||
{
|
||||
os_mutex_lock(&exec_env->current_status->wait_lock);
|
||||
while (wasm_cluster_thread_is_running(exec_env)) {
|
||||
os_cond_wait(&exec_env->current_status->wait_cond,
|
||||
&exec_env->current_status->wait_lock);
|
||||
}
|
||||
*status = exec_env->current_status->signal_flag;
|
||||
os_mutex_unlock(&exec_env->current_status->wait_lock);
|
||||
}
|
||||
|
||||
void
|
||||
wasm_cluster_thread_send_signal(WASMExecEnv *exec_env, uint32 signo)
|
||||
{
|
||||
exec_env->current_status->signal_flag = signo;
|
||||
}
|
||||
|
||||
static void
|
||||
notify_debug_instance(WASMExecEnv *exec_env)
|
||||
{
|
||||
WASMCluster *cluster;
|
||||
|
||||
cluster = wasm_exec_env_get_cluster(exec_env);
|
||||
bh_assert(cluster);
|
||||
|
||||
if (!cluster->debug_inst) {
|
||||
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);
|
||||
}
|
||||
|
||||
void
|
||||
wasm_cluster_thread_stopped(WASMExecEnv *exec_env)
|
||||
{
|
||||
exec_env->current_status->running_status = STATUS_STOP;
|
||||
os_cond_signal(&exec_env->current_status->wait_cond);
|
||||
notify_debug_instance(exec_env);
|
||||
}
|
||||
|
||||
void
|
||||
@ -578,7 +579,7 @@ void
|
||||
wasm_cluster_thread_exited(WASMExecEnv *exec_env)
|
||||
{
|
||||
exec_env->current_status->running_status = STATUS_EXIT;
|
||||
os_cond_signal(&exec_env->current_status->wait_cond);
|
||||
notify_debug_instance(exec_env);
|
||||
}
|
||||
|
||||
void
|
||||
@ -595,7 +596,14 @@ wasm_cluster_thread_step(WASMExecEnv *exec_env)
|
||||
exec_env->current_status->running_status = STATUS_STEP;
|
||||
os_cond_signal(&exec_env->wait_cond);
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
wasm_cluster_set_debug_inst(WASMCluster *cluster, WASMDebugInstance *inst)
|
||||
{
|
||||
cluster->debug_inst = inst;
|
||||
}
|
||||
|
||||
#endif /* end of WASM_ENABLE_DEBUG_INTERP */
|
||||
|
||||
int32
|
||||
wasm_cluster_join_thread(WASMExecEnv *exec_env, void **ret_val)
|
||||
|
||||
@ -39,6 +39,8 @@ typedef struct WASMCurrentEnvStatus {
|
||||
korp_cond wait_cond;
|
||||
} WASMCurrentEnvStatus;
|
||||
|
||||
typedef struct WASMDebugInstance WASMDebugInstance;
|
||||
|
||||
WASMCurrentEnvStatus *
|
||||
wasm_cluster_create_exenv_status();
|
||||
|
||||
@ -69,6 +71,9 @@ wasm_cluster_thread_send_signal(WASMExecEnv *exec_env, uint32 signo);
|
||||
void
|
||||
wasm_cluster_thread_step(WASMExecEnv *exec_env);
|
||||
|
||||
void
|
||||
wasm_cluster_set_debug_inst(WASMCluster *cluster, WASMDebugInstance *inst);
|
||||
|
||||
#endif
|
||||
typedef struct WASMCluster {
|
||||
struct WASMCluster *next;
|
||||
@ -84,6 +89,9 @@ typedef struct WASMCluster {
|
||||
uint32 stack_size;
|
||||
/* Record which segments are occupied */
|
||||
bool *stack_segment_occupied;
|
||||
#if WASM_ENABLE_DEBUG_INTERP != 0
|
||||
WASMDebugInstance *debug_inst;
|
||||
#endif
|
||||
} WASMCluster;
|
||||
|
||||
void
|
||||
|
||||
Reference in New Issue
Block a user