Skip to content

Commit

Permalink
Fix source debugging issues (bytecodealliance#776)
Browse files Browse the repository at this point in the history
- fix data race issue between debug control thread and main thread
- fix possible memory leaks in breakpoints list
- fix memory uninitialized issues
- remove unused data structures
- add more checks when handling packet and args
- fix mini-loader issues
- fix config_common.cmake fast interp prompt issue
  • Loading branch information
xujuntwt95329 authored Oct 9, 2021
1 parent 52b6c73 commit 0be1f68
Show file tree
Hide file tree
Showing 8 changed files with 202 additions and 94 deletions.
2 changes: 1 addition & 1 deletion build-scripts/config_common.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ elseif (WAMR_BUILD_LIBC_WASI EQUAL 1)
else ()
message (" Libc WASI disabled")
endif ()
if (WAMR_BUILD_FAST_INTERP EQUAL 1)
if ((WAMR_BUILD_FAST_INTERP EQUAL 1) AND (WAMR_BUILD_INTERP EQUAL 1))
add_definitions (-DWASM_ENABLE_FAST_INTERP=1)
message (" Fast interpreter enabled")
else ()
Expand Down
2 changes: 1 addition & 1 deletion core/iwasm/interpreter/wasm_mini_loader.c
Original file line number Diff line number Diff line change
Expand Up @@ -2438,7 +2438,7 @@ wasm_loader_unload(WASMModule *module)
}

bool
wasm_loader_find_block_addr(BlockAddr *block_addr_cache,
wasm_loader_find_block_addr(WASMExecEnv *exec_env, BlockAddr *block_addr_cache,
const uint8 *start_addr, const uint8 *code_end_addr,
uint8 label_type, uint8 **p_else_addr,
uint8 **p_end_addr)
Expand Down
167 changes: 118 additions & 49 deletions core/iwasm/libraries/debug-engine/debug_engine.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ typedef struct WASMDebugEngine {
bool active;
} WASMDebugEngine;

static WASMDebugEngine *g_debug_engine;

static bool
should_stop(WASMDebugControlThread *control_thread)
{
Expand All @@ -33,69 +35,112 @@ should_stop(WASMDebugControlThread *control_thread)
static void *
control_thread_routine(void *arg)
{
WASMDebugObject *debug_object = (WASMDebugObject *)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);

control_thread->status = RUNNING;

debug_inst->id = g_debug_engine->debug_instance_list.len + 1;

control_thread->debug_engine = g_debug_engine;
control_thread->debug_instance = debug_inst;
strcpy(control_thread->ip_addr, g_debug_engine->ip_addr);
control_thread->port =
g_debug_engine->process_base_port + debug_inst->id;

LOG_WARNING("control thread of debug object %p start at %s:%d\n",
debug_object, debug_object->control_thread->ip_addr,
debug_object->control_thread->port);
debug_inst, control_thread->ip_addr, control_thread->port);

debug_object->control_thread->server =
wasm_launch_gdbserver(debug_object->control_thread->ip_addr,
debug_object->control_thread->port);
if (!debug_object->control_thread->server) {
control_thread->server =
wasm_launch_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);
return NULL;
}

debug_object->control_thread->server->thread =
debug_object->control_thread;
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);

while (true) {
os_mutex_lock(&debug_object->control_thread->wait_lock);
if (!should_stop(debug_object->control_thread)) {
if (!wasm_gdbserver_handle_packet(
debug_object->control_thread->server))
debug_object->control_thread->status = STOPPED;
os_mutex_lock(&control_thread->wait_lock);
if (!should_stop(control_thread)) {
if (!wasm_gdbserver_handle_packet(control_thread->server)) {
control_thread->status = STOPPED;
}
}
else {
os_mutex_unlock(&debug_object->control_thread->wait_lock);
os_mutex_unlock(&control_thread->wait_lock);
break;
}
os_mutex_unlock(&debug_object->control_thread->wait_lock);
os_mutex_unlock(&control_thread->wait_lock);
}

LOG_VERBOSE("control thread of debug object %p stop\n", debug_object);
LOG_VERBOSE("control thread of debug object %p stop\n", debug_inst);
return NULL;
}

static WASMDebugControlThread *
wasm_debug_control_thread_create(WASMDebugObject *debug_object)
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)))) {
LOG_ERROR("WASM Debug Engine error: failed to allocate memory");
return NULL;
}
memset(control_thread, 0, sizeof(WASMDebugControlThread));

if (os_mutex_init(&control_thread->wait_lock) != 0)
goto fail;

if (os_cond_init(&control_thread->wait_cond) != 0)
goto fail1;
debug_instance->control_thread = control_thread;

control_thread->status = RUNNING;
os_mutex_lock(&exec_env->wait_lock);

if (0 != os_thread_create(&control_thread->tid, control_thread_routine,
debug_object, APP_THREAD_STACK_SIZE_MAX)) {
goto fail2;
debug_instance, APP_THREAD_STACK_SIZE_MAX)) {
os_mutex_unlock(&control_thread->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);
if (!control_thread->server)
goto fail1;

/* create control thread success, append debug instance to debug engine */
bh_list_insert(&g_debug_engine->debug_instance_list, debug_instance);
wasm_cluster_send_signal_all(debug_instance->cluster, WAMR_SIG_STOP);

return control_thread;

fail2:
os_cond_destroy(&control_thread->wait_cond);
fail1:
os_mutex_destroy(&control_thread->wait_lock);
fail:
Expand All @@ -104,27 +149,23 @@ wasm_debug_control_thread_create(WASMDebugObject *debug_object)
}

static void
wasm_debug_control_thread_destroy(WASMDebugObject *debug_object)
wasm_debug_control_thread_destroy(WASMDebugInstance *debug_instance)
{
WASMDebugControlThread *control_thread = debug_object->control_thread;
WASMDebugControlThread *control_thread = debug_instance->control_thread;
LOG_VERBOSE("control thread of debug object %p stop at %s:%d\n",
debug_object, debug_object->control_thread->ip_addr,
debug_object->control_thread->port);
os_mutex_lock(&control_thread->wait_lock);
debug_instance, control_thread->ip_addr,
control_thread->port);
control_thread->status = STOPPED;
os_mutex_lock(&control_thread->wait_lock);
wasm_close_gdbserver(control_thread->server);
os_mutex_unlock(&control_thread->wait_lock);
os_cond_signal(&control_thread->wait_cond);
os_thread_join(control_thread->tid, NULL);
wasm_runtime_free(control_thread->server);

os_mutex_destroy(&control_thread->wait_lock);
os_cond_destroy(&control_thread->wait_cond);
wasm_runtime_free(control_thread);
}

static WASMDebugEngine *g_debug_engine;

static WASMDebugEngine *
wasm_debug_engine_create()
{
Expand Down Expand Up @@ -215,24 +256,20 @@ wasm_debug_instance_create(WASMCluster *cluster)
return NULL;
}
memset(instance, 0, sizeof(WASMDebugInstance));
instance->cluster = cluster;
instance->control_thread =
wasm_debug_control_thread_create((WASMDebugObject *)instance);
instance->control_thread->debug_engine = (WASMDebugObject *)g_debug_engine;
instance->control_thread->debug_instance = (WASMDebugObject *)instance;
strcpy(instance->control_thread->ip_addr, g_debug_engine->ip_addr);
instance->id = g_debug_engine->debug_instance_list.len + 1;
bh_list_init(&instance->break_point_list);

instance->cluster = cluster;
exec_env = bh_list_first_elem(&cluster->exec_env_list);
bh_assert(exec_env);

/* exec_evn is created, but handle may not be set yet. */
instance->current_tid = exec_env ? exec_env->handle : 0;
instance->current_tid = exec_env->handle;

if (!wasm_debug_control_thread_create(instance)) {
LOG_ERROR("WASM Debug Engine error: failed to create control thread");
wasm_runtime_free(instance);
return NULL;
}

instance->control_thread->port =
g_debug_engine->process_base_port + instance->id;
bh_list_init(&instance->break_point_list);
bh_list_insert(&g_debug_engine->debug_instance_list, instance);
wasm_cluster_send_signal_all(instance->cluster, WAMR_SIG_STOP);
return instance;
}

Expand All @@ -249,6 +286,22 @@ wasm_cluster_get_debug_instance(WASMDebugEngine *engine, WASMCluster *cluster)
return instance;
}

static void
wasm_debug_instance_destroy_breakpoints(WASMDebugInstance *instance)
{
WASMDebugBreakPoint *breakpoint, *next_bp;

breakpoint = bh_list_first_elem(&instance->break_point_list);
while (breakpoint) {
next_bp = bh_list_elem_next(breakpoint);

bh_list_remove(&instance->break_point_list, breakpoint);
wasm_runtime_free(breakpoint);

breakpoint = next_bp;
}
}

void
wasm_debug_instance_destroy(WASMCluster *cluster)
{
Expand All @@ -260,8 +313,13 @@ wasm_debug_instance_destroy(WASMCluster *cluster)

instance = wasm_cluster_get_debug_instance(g_debug_engine, cluster);
if (instance) {
wasm_debug_control_thread_destroy((WASMDebugObject *)instance);
/* destroy control thread */
wasm_debug_control_thread_destroy(instance);
bh_list_remove(&g_debug_engine->debug_instance_list, instance);

/* destroy all breakpoints */
wasm_debug_instance_destroy_breakpoints(instance);

wasm_runtime_free(instance);
}
}
Expand Down Expand Up @@ -444,6 +502,7 @@ wasm_debug_instance_get_memregion(WASMDebugInstance *instance, uint64 addr)
LOG_ERROR("WASM Debug Engine error: failed to allocate memory");
return NULL;
}
memset(mem_info, 0, sizeof(WASMDebugMemoryInfo));
mem_info->start = WASM_ADDR(WasmInvalid, 0, 0);
mem_info->size = 0;
mem_info->name[0] = '\0';
Expand Down Expand Up @@ -715,6 +774,7 @@ wasm_debug_instance_add_breakpoint(WASMDebugInstance *instance,
"WASM Debug Engine error: failed to allocate memory");
return false;
}
memset(breakpoint, 0, sizeof(WASMDebugBreakPoint));
breakpoint->addr = offset;
/* TODO: how to if more than one breakpoints are set
at the same addr? */
Expand Down Expand Up @@ -872,6 +932,10 @@ wasm_debug_instance_get_local(WASMDebugInstance *instance,
return false;

param_count = cur_func->param_count;

if (local_index >= param_count + cur_func->local_count)
return false;

local_offset = cur_func->local_offsets[local_index];
if (local_index < param_count)
local_type = cur_func->param_types[local_index];
Expand Down Expand Up @@ -928,6 +992,11 @@ wasm_debug_instance_get_global(WASMDebugInstance *instance,
module_inst = (WASMModuleInstance *)exec_env->module_inst;
global_data = module_inst->global_data;
globals = module_inst->globals;

if ((global_index < 0)
|| ((uint32)global_index >= module_inst->global_count)) {
return false;
}
global = globals + global_index;

#if WASM_ENABLE_MULTI_MODULE == 0
Expand Down
14 changes: 5 additions & 9 deletions core/iwasm/libraries/debug-engine/debug_engine.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,20 @@ typedef enum WASMDebugControlThreadStatus {
STOPPED,
} WASMDebugControlThreadStatus;

struct WASMDebugObject;
struct WASMDebugEngine;
struct WASMDebugInstance;

typedef struct WASMDebugControlThread {
WASMGDBServer *server;
korp_tid tid;
korp_mutex wait_lock;
korp_cond wait_cond;
char ip_addr[128];
int port;
WASMDebugControlThreadStatus status;
struct WASMDebugObject *debug_engine;
struct WASMDebugObject *debug_instance;
struct WASMDebugEngine *debug_engine;
struct WASMDebugInstance *debug_instance;
} WASMDebugControlThread;

typedef struct WASMDebugObject {
struct WASMDebugObject *next;
WASMDebugControlThread *control_thread;
} WASMDebugObject;

typedef struct WASMDebugBreakPoint {
struct WASMDebugBreakPoint *next;
uint64 addr;
Expand Down
Loading

0 comments on commit 0be1f68

Please sign in to comment.