mirror of
https://github.com/bytecodealliance/wasm-micro-runtime.git
synced 2025-03-12 08:55:28 +00:00
[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:
parent
c8fe1004aa
commit
2af5ae5abb
|
@ -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);
|
||||
goto fail3;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
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) {
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
|
||||
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,22 +349,35 @@ handle_v_packet(WASMGDBServer *server, char *payload)
|
|||
write_packet(server, "vCont;c;C;s;S;");
|
||||
|
||||
if (!strcmp("Cont", name)) {
|
||||
if (args && args[0] == 's') {
|
||||
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);
|
||||
(WASMDebugInstance *)server->thread->debug_instance,
|
||||
tid);
|
||||
|
||||
if (args[0] == 's') {
|
||||
wasm_debug_instance_singlestep(
|
||||
(WASMDebugInstance *)server->thread->debug_instance, tid);
|
||||
(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);
|
||||
(WASMDebugInstance *)server->thread->debug_instance,
|
||||
tid, &status);
|
||||
send_thread_stop_status(server, status, tid);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -146,6 +146,10 @@ Currently we only profile the memory consumption of module, module_instance and
|
|||
> Note: The WAMR application entry (`core/iwasm/common/wasm_application.c`) encapsulate some common process to instantiate, execute the wasm functions and print the results. Some platform related APIs are used in these functions, so you can enable this flag to exclude this file if your platform doesn't support those APIs.
|
||||
> *Don't enable this flag if you are building `product-mini`*
|
||||
|
||||
#### **Enable source debugging features**
|
||||
- **WAMR_BUILD_DEBUG_INTERP**=1/0, default to 0 if not set
|
||||
> Note: There are some other setup required by source debugging, please refer to [source_debugging.md](./source_debugging.md) for more details.
|
||||
|
||||
**Combination of configurations:**
|
||||
|
||||
We can combine the configurations. For example, if we want to disable interpreter, enable AOT and WASI, we can run command:
|
||||
|
|
|
@ -89,3 +89,51 @@ lldb-12 iwasm -- test.aot
|
|||
```
|
||||
|
||||
Then you can use lldb commands to debug both wamr runtime and your wasm application in ***current terminal***
|
||||
|
||||
## Enable debugging in embedders (for interpreter)
|
||||
|
||||
There are three steps to enable debugging in embedders
|
||||
|
||||
1. Set the debug parameters when initializing the runtime environment:
|
||||
``` c
|
||||
RuntimeInitArgs init_args;
|
||||
memset(&init_args, 0, sizeof(RuntimeInitArgs));
|
||||
|
||||
/* ... */
|
||||
strcpy(init_args.ip_addr, "127.0.0.1");
|
||||
init_args.instance_port = 1234;
|
||||
/*
|
||||
* Or set port to 0 to use a port assigned by os
|
||||
* init_args.instance_port = 0;
|
||||
*/
|
||||
|
||||
if (!wasm_runtime_full_init(&init_args)) {
|
||||
return false;
|
||||
}
|
||||
```
|
||||
|
||||
2. Use `wasm_runtime_start_debug_instance` to create the debug instance:
|
||||
``` c
|
||||
/*
|
||||
initialization, loading and instantiating
|
||||
...
|
||||
*/
|
||||
exec_env = wasm_runtime_create_exec_env(module_inst, stack_size);
|
||||
uint32_t debug_port = wasm_runtime_start_debug_instance();
|
||||
```
|
||||
|
||||
3. Enable source debugging features during building
|
||||
|
||||
You can use `-DWAMR_BUILD_DEBUG_INTERP=1` during cmake configuration
|
||||
|
||||
Or you can set it directly in `cmake` files:
|
||||
``` cmake
|
||||
set (WAMR_BUILD_DEBUG_INTERP 1)
|
||||
```
|
||||
|
||||
### Attentions
|
||||
- Debugging `multi-thread wasm module` is not supported, if your wasm module use pthread APIs (see [pthread_library.md](./pthread_library.md)), or the embedder use `wasm_runtime_spawn_thread` to create new wasm threads, then there may be **unexpected behaviour** during debugging.
|
||||
|
||||
> Note: This attention is about "wasm thread" rather than native threads. Executing wasm functions in several different native threads will **not** affect the normal behaviour of debugging feature.
|
||||
|
||||
- When using source debugging features, **don't** create multiple `wasm_instance` from the same `wasm_module`, because the debugger may change the bytecode (set/unset breakpoints) of the `wasm_module`. If you do need several instance from the same bytecode, you need to copy the bytecode to a new butter, then load a new `wasm_module`, and then instantiate the new wasm module to get the new instance.
|
||||
|
|
Loading…
Reference in New Issue
Block a user