mirror of
https://github.com/bytecodealliance/wasm-micro-runtime.git
synced 2025-02-09 00:15:07 +00:00
![TianlongLiang](/assets/img/avatar_default.png)
Change main thread hangs when encounter debugger encounters error to main thread exits when debugger encounters error Change main thread blocks when debugger detaches to main thread continues executing when debugger detaches, and main thread exits normally when finishing executing
1352 lines
39 KiB
C
1352 lines
39 KiB
C
/*
|
|
* Copyright (C) 2021 Ant Group. All rights reserved.
|
|
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
*/
|
|
|
|
#include "debug_engine.h"
|
|
#include "gdbserver.h"
|
|
#include "handler.h"
|
|
#include "bh_platform.h"
|
|
#include "wasm_interp.h"
|
|
#include "wasm_opcode.h"
|
|
#include "wasm_runtime.h"
|
|
|
|
static const uint8 break_instr[] = { DEBUG_OP_BREAK };
|
|
|
|
typedef struct WASMDebugEngine {
|
|
struct WASMDebugEngine *next;
|
|
WASMDebugControlThread *control_thread;
|
|
char ip_addr[128];
|
|
int32 process_base_port;
|
|
bh_list debug_instance_list;
|
|
korp_mutex instance_list_lock;
|
|
} 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);
|
|
}
|
|
|
|
void
|
|
on_thread_exit_event(WASMDebugInstance *debug_inst, WASMExecEnv *exec_env)
|
|
{
|
|
os_mutex_lock(&debug_inst->wait_lock);
|
|
|
|
/* DBG_LAUNCHING: exit when debugger detached,
|
|
* DBG_ERROR: exit when debugger error */
|
|
if (debug_inst->current_state != DBG_LAUNCHING
|
|
&& debug_inst->current_state != DBG_ERROR) {
|
|
/* only when exit normally the debugger thread will participate in
|
|
* teardown phase */
|
|
debug_inst->stopped_thread = exec_env;
|
|
}
|
|
|
|
os_mutex_unlock(&debug_inst->wait_lock);
|
|
}
|
|
|
|
static WASMDebugEngine *g_debug_engine;
|
|
|
|
static uint32 current_instance_id = 1;
|
|
|
|
static uint32
|
|
allocate_instance_id()
|
|
{
|
|
uint32 id;
|
|
|
|
bh_assert(g_debug_engine);
|
|
|
|
os_mutex_lock(&g_debug_engine->instance_list_lock);
|
|
id = current_instance_id++;
|
|
os_mutex_unlock(&g_debug_engine->instance_list_lock);
|
|
|
|
return id;
|
|
}
|
|
|
|
static bool
|
|
is_thread_running(WASMDebugControlThread *control_thread)
|
|
{
|
|
return control_thread->status == RUNNING;
|
|
}
|
|
|
|
static bool
|
|
is_thread_stopped(WASMDebugControlThread *control_thread)
|
|
{
|
|
return control_thread->status == STOPPED;
|
|
}
|
|
|
|
static bool
|
|
is_thread_detached(WASMDebugControlThread *control_thread)
|
|
{
|
|
return control_thread->status == DETACHED;
|
|
}
|
|
|
|
static void *
|
|
control_thread_routine(void *arg)
|
|
{
|
|
WASMDebugInstance *debug_inst = (WASMDebugInstance *)arg;
|
|
WASMDebugControlThread *control_thread = NULL;
|
|
|
|
control_thread = debug_inst->control_thread;
|
|
bh_assert(control_thread);
|
|
|
|
os_mutex_lock(&debug_inst->wait_lock);
|
|
|
|
control_thread->status = RUNNING;
|
|
|
|
debug_inst->id = allocate_instance_id();
|
|
|
|
control_thread->debug_engine = g_debug_engine;
|
|
control_thread->debug_instance = debug_inst;
|
|
bh_strcpy_s(control_thread->ip_addr, sizeof(control_thread->ip_addr),
|
|
g_debug_engine->ip_addr);
|
|
if (control_thread->port == -1) {
|
|
control_thread->port =
|
|
(g_debug_engine->process_base_port == 0)
|
|
? 0
|
|
: g_debug_engine->process_base_port + debug_inst->id - 1;
|
|
}
|
|
|
|
LOG_WARNING("control thread of debug object %p start\n", debug_inst);
|
|
|
|
control_thread->server =
|
|
wasm_create_gdbserver(control_thread->ip_addr, &control_thread->port);
|
|
|
|
if (!control_thread->server) {
|
|
LOG_ERROR("Failed to create debug server\n");
|
|
control_thread->port = 0;
|
|
os_cond_signal(&debug_inst->wait_cond);
|
|
os_mutex_unlock(&debug_inst->wait_lock);
|
|
return NULL;
|
|
}
|
|
|
|
control_thread->server->thread = control_thread;
|
|
|
|
/*
|
|
* 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);
|
|
|
|
if (!wasm_gdbserver_listen(control_thread->server)) {
|
|
LOG_ERROR("Failed while listening for debugger\n");
|
|
goto fail;
|
|
}
|
|
|
|
/* outer infinite loop: try to connect with the debugger */
|
|
while (true) {
|
|
/* wait lldb client to connect */
|
|
if (!wasm_gdbserver_accept(control_thread->server)) {
|
|
LOG_ERROR("Failed while accepting debugger connection\n");
|
|
goto fail;
|
|
}
|
|
|
|
control_thread->status = RUNNING;
|
|
/* when reattached, send signal */
|
|
wasm_cluster_send_signal_all(debug_inst->cluster, WAMR_SIG_SINGSTEP);
|
|
|
|
/* inner infinite loop: keep serving until detach */
|
|
while (true) {
|
|
os_mutex_lock(&control_thread->wait_lock);
|
|
if (is_thread_running(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;
|
|
LOG_ERROR("An error occurs when handling a packet\n");
|
|
os_mutex_unlock(&control_thread->wait_lock);
|
|
goto fail;
|
|
}
|
|
}
|
|
else if (is_thread_detached(control_thread)) {
|
|
os_mutex_unlock(&control_thread->wait_lock);
|
|
break;
|
|
}
|
|
else if (is_thread_stopped(control_thread)) {
|
|
os_mutex_unlock(&control_thread->wait_lock);
|
|
return NULL;
|
|
}
|
|
os_mutex_unlock(&control_thread->wait_lock);
|
|
}
|
|
}
|
|
fail:
|
|
wasm_debug_instance_on_failure(debug_inst);
|
|
LOG_VERBOSE("control thread of debug object [%p] stopped with failure\n",
|
|
debug_inst);
|
|
return NULL;
|
|
}
|
|
|
|
static WASMDebugControlThread *
|
|
wasm_debug_control_thread_create(WASMDebugInstance *debug_instance, int32 port)
|
|
{
|
|
WASMDebugControlThread *control_thread;
|
|
|
|
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));
|
|
control_thread->port = port;
|
|
|
|
if (os_mutex_init(&control_thread->wait_lock) != 0)
|
|
goto fail;
|
|
|
|
debug_instance->control_thread = control_thread;
|
|
|
|
os_mutex_lock(&debug_instance->wait_lock);
|
|
|
|
if (0
|
|
!= os_thread_create(&control_thread->tid, control_thread_routine,
|
|
debug_instance, APP_THREAD_STACK_SIZE_DEFAULT)) {
|
|
os_mutex_unlock(&debug_instance->wait_lock);
|
|
goto fail1;
|
|
}
|
|
|
|
/* 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) {
|
|
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 */
|
|
bh_list_insert(&g_debug_engine->debug_instance_list, debug_instance);
|
|
os_mutex_unlock(&g_debug_engine->instance_list_lock);
|
|
|
|
/* If we set WAMR_SIG_STOP here, the VSCode debugger adaptor will raise an
|
|
* exception in the UI. We use WAMR_SIG_SINGSTEP to avoid this exception for
|
|
* better user experience */
|
|
wasm_cluster_send_signal_all(debug_instance->cluster, WAMR_SIG_SINGSTEP);
|
|
|
|
return control_thread;
|
|
|
|
fail1:
|
|
os_mutex_destroy(&control_thread->wait_lock);
|
|
fail:
|
|
wasm_runtime_free(control_thread);
|
|
return NULL;
|
|
}
|
|
|
|
static void
|
|
wasm_debug_control_thread_destroy(WASMDebugInstance *debug_instance)
|
|
{
|
|
WASMDebugControlThread *control_thread = debug_instance->control_thread;
|
|
|
|
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);
|
|
os_mutex_unlock(&control_thread->wait_lock);
|
|
os_thread_join(control_thread->tid, NULL);
|
|
wasm_runtime_free(control_thread->server);
|
|
|
|
os_mutex_destroy(&control_thread->wait_lock);
|
|
wasm_runtime_free(control_thread);
|
|
}
|
|
|
|
static WASMDebugEngine *
|
|
wasm_debug_engine_create()
|
|
{
|
|
WASMDebugEngine *engine;
|
|
|
|
if (!(engine = wasm_runtime_malloc(sizeof(WASMDebugEngine)))) {
|
|
LOG_ERROR("WASM Debug Engine error: failed to allocate memory");
|
|
return NULL;
|
|
}
|
|
memset(engine, 0, sizeof(WASMDebugEngine));
|
|
|
|
if (os_mutex_init(&engine->instance_list_lock) != 0) {
|
|
wasm_runtime_free(engine);
|
|
LOG_ERROR("WASM Debug Engine error: failed to init mutex");
|
|
return NULL;
|
|
}
|
|
|
|
/* reset current instance id */
|
|
current_instance_id = 1;
|
|
|
|
bh_list_init(&engine->debug_instance_list);
|
|
return engine;
|
|
}
|
|
|
|
void
|
|
wasm_debug_engine_destroy()
|
|
{
|
|
if (g_debug_engine) {
|
|
wasm_debug_handler_deinit();
|
|
os_mutex_destroy(&g_debug_engine->instance_list_lock);
|
|
wasm_runtime_free(g_debug_engine);
|
|
g_debug_engine = NULL;
|
|
}
|
|
}
|
|
|
|
bool
|
|
wasm_debug_engine_init(char *ip_addr, int32 process_port)
|
|
{
|
|
if (wasm_debug_handler_init() != 0) {
|
|
return false;
|
|
}
|
|
|
|
if (g_debug_engine == NULL) {
|
|
g_debug_engine = wasm_debug_engine_create();
|
|
}
|
|
|
|
if (g_debug_engine) {
|
|
g_debug_engine->process_base_port =
|
|
(process_port > 0) ? process_port : 0;
|
|
if (ip_addr)
|
|
snprintf(g_debug_engine->ip_addr, sizeof(g_debug_engine->ip_addr),
|
|
"%s", ip_addr);
|
|
else
|
|
snprintf(g_debug_engine->ip_addr, sizeof(g_debug_engine->ip_addr),
|
|
"%s", "127.0.0.1");
|
|
}
|
|
else {
|
|
wasm_debug_handler_deinit();
|
|
}
|
|
|
|
return g_debug_engine != NULL ? true : false;
|
|
}
|
|
|
|
/* A debug Instance is a debug "process" in gdb remote protocol
|
|
and bound to a runtime cluster */
|
|
WASMDebugInstance *
|
|
wasm_debug_instance_create(WASMCluster *cluster, int32 port)
|
|
{
|
|
WASMDebugInstance *instance;
|
|
WASMExecEnv *exec_env = NULL;
|
|
wasm_module_inst_t module_inst = NULL;
|
|
|
|
if (!g_debug_engine) {
|
|
return NULL;
|
|
}
|
|
|
|
if (!(instance = wasm_runtime_malloc(sizeof(WASMDebugInstance)))) {
|
|
LOG_ERROR("WASM Debug Engine error: failed to allocate memory");
|
|
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;
|
|
exec_env = bh_list_first_elem(&cluster->exec_env_list);
|
|
bh_assert(exec_env);
|
|
|
|
instance->current_tid = exec_env->handle;
|
|
|
|
module_inst = wasm_runtime_get_module_inst(exec_env);
|
|
bh_assert(module_inst);
|
|
|
|
/* Allocate linear memory for evaluating expressions during debugging. If
|
|
* the allocation failed, the debugger will not be able to evaluate
|
|
* expressions */
|
|
instance->exec_mem_info.size = DEBUG_EXECUTION_MEMORY_SIZE;
|
|
instance->exec_mem_info.start_offset = wasm_runtime_module_malloc(
|
|
module_inst, instance->exec_mem_info.size, NULL);
|
|
if (instance->exec_mem_info.start_offset == 0) {
|
|
LOG_WARNING(
|
|
"WASM Debug Engine warning: failed to allocate linear memory for "
|
|
"execution. \n"
|
|
"Will not be able to evaluate expressions during "
|
|
"debugging");
|
|
}
|
|
instance->exec_mem_info.current_pos = instance->exec_mem_info.start_offset;
|
|
|
|
if (!wasm_debug_control_thread_create(instance, port)) {
|
|
LOG_ERROR("WASM Debug Engine error: failed to create control thread");
|
|
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;
|
|
}
|
|
|
|
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)
|
|
{
|
|
WASMDebugInstance *instance = NULL;
|
|
|
|
if (!g_debug_engine) {
|
|
return;
|
|
}
|
|
|
|
instance = cluster->debug_inst;
|
|
if (instance) {
|
|
/* destroy control thread */
|
|
wasm_debug_control_thread_destroy(instance);
|
|
|
|
os_mutex_lock(&g_debug_engine->instance_list_lock);
|
|
bh_list_remove(&g_debug_engine->debug_instance_list, instance);
|
|
os_mutex_unlock(&g_debug_engine->instance_list_lock);
|
|
|
|
/* 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;
|
|
}
|
|
}
|
|
|
|
WASMExecEnv *
|
|
wasm_debug_instance_get_current_env(WASMDebugInstance *instance)
|
|
{
|
|
WASMExecEnv *exec_env = NULL;
|
|
|
|
if (instance) {
|
|
exec_env = bh_list_first_elem(&instance->cluster->exec_env_list);
|
|
while (exec_env) {
|
|
if (exec_env->handle == instance->current_tid)
|
|
break;
|
|
exec_env = bh_list_elem_next(exec_env);
|
|
}
|
|
}
|
|
return exec_env;
|
|
}
|
|
|
|
#if WASM_ENABLE_LIBC_WASI != 0
|
|
bool
|
|
wasm_debug_instance_get_current_object_name(WASMDebugInstance *instance,
|
|
char name_buffer[], uint32 len)
|
|
{
|
|
WASMExecEnv *exec_env;
|
|
WASIArguments *wasi_args;
|
|
WASMModuleInstance *module_inst;
|
|
|
|
if (!instance)
|
|
return false;
|
|
|
|
exec_env = bh_list_first_elem(&instance->cluster->exec_env_list);
|
|
if (!exec_env)
|
|
return false;
|
|
|
|
module_inst = (WASMModuleInstance *)exec_env->module_inst;
|
|
wasi_args = &module_inst->module->wasi_args;
|
|
if (wasi_args && wasi_args->argc > 0) {
|
|
char *argv_name = wasi_args->argv[0];
|
|
uint32 name_len = (uint32)strlen(argv_name);
|
|
|
|
printf("the module name is %s\n", argv_name);
|
|
if (len - 1 >= name_len)
|
|
bh_strcpy_s(name_buffer, len, argv_name);
|
|
else
|
|
bh_strcpy_s(name_buffer, len, argv_name + (name_len + 1 - len));
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
#endif
|
|
|
|
uint64
|
|
wasm_debug_instance_get_pid(WASMDebugInstance *instance)
|
|
{
|
|
if (instance != NULL) {
|
|
return (uint64)instance->id;
|
|
}
|
|
return (uint64)0;
|
|
}
|
|
|
|
korp_tid
|
|
wasm_debug_instance_get_tid(WASMDebugInstance *instance)
|
|
{
|
|
if (instance != NULL) {
|
|
return instance->current_tid;
|
|
}
|
|
return (korp_tid)(uintptr_t)0;
|
|
}
|
|
|
|
uint32
|
|
wasm_debug_instance_get_tids(WASMDebugInstance *instance, korp_tid tids[],
|
|
uint32 len)
|
|
{
|
|
WASMExecEnv *exec_env;
|
|
uint32 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", threads_num);
|
|
return threads_num;
|
|
}
|
|
|
|
uint32
|
|
wasm_debug_instance_get_thread_status(WASMDebugInstance *instance, korp_tid 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 (uint32)exec_env->current_status->signal_flag;
|
|
}
|
|
exec_env = bh_list_elem_next(exec_env);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
wasm_debug_instance_set_cur_thread(WASMDebugInstance *instance, korp_tid tid)
|
|
{
|
|
instance->current_tid = tid;
|
|
}
|
|
|
|
uint64
|
|
wasm_debug_instance_get_pc(WASMDebugInstance *instance)
|
|
{
|
|
WASMExecEnv *exec_env;
|
|
|
|
if (!instance)
|
|
return 0;
|
|
|
|
exec_env = wasm_debug_instance_get_current_env(instance);
|
|
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(
|
|
WasmObj, instance->id,
|
|
(exec_env->cur_frame->ip - module_inst->module->load_addr));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
uint64
|
|
wasm_debug_instance_get_load_addr(WASMDebugInstance *instance)
|
|
{
|
|
WASMExecEnv *exec_env;
|
|
|
|
if (!instance)
|
|
return WASM_ADDR(WasmInvalid, 0, 0);
|
|
|
|
exec_env = bh_list_first_elem(&instance->cluster->exec_env_list);
|
|
if (exec_env) {
|
|
return WASM_ADDR(WasmObj, instance->id, 0);
|
|
}
|
|
|
|
return WASM_ADDR(WasmInvalid, 0, 0);
|
|
}
|
|
|
|
WASMDebugMemoryInfo *
|
|
wasm_debug_instance_get_memregion(WASMDebugInstance *instance, uint64 addr)
|
|
{
|
|
WASMDebugMemoryInfo *mem_info;
|
|
WASMExecEnv *exec_env;
|
|
WASMModuleInstance *module_inst;
|
|
WASMMemoryInstance *memory;
|
|
uint32 num_bytes_per_page;
|
|
uint32 linear_mem_size = 0;
|
|
|
|
if (!instance)
|
|
return NULL;
|
|
|
|
exec_env = bh_list_first_elem(&instance->cluster->exec_env_list);
|
|
if (!exec_env)
|
|
return NULL;
|
|
|
|
if (!(mem_info = wasm_runtime_malloc(sizeof(WASMDebugMemoryInfo)))) {
|
|
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';
|
|
mem_info->permisson[0] = '\0';
|
|
|
|
module_inst = (WASMModuleInstance *)exec_env->module_inst;
|
|
|
|
switch (WASM_ADDR_TYPE(addr)) {
|
|
case WasmObj:
|
|
if (WASM_ADDR_OFFSET(addr) < module_inst->module->load_size) {
|
|
mem_info->start = WASM_ADDR(WasmObj, instance->id, 0);
|
|
mem_info->size = module_inst->module->load_size;
|
|
snprintf(mem_info->name, sizeof(mem_info->name), "%s",
|
|
"module");
|
|
snprintf(mem_info->permisson, sizeof(mem_info->permisson), "%s",
|
|
"rx");
|
|
}
|
|
break;
|
|
case WasmMemory:
|
|
{
|
|
memory = wasm_get_default_memory(module_inst);
|
|
|
|
if (memory) {
|
|
num_bytes_per_page = memory->num_bytes_per_page;
|
|
linear_mem_size = num_bytes_per_page * memory->cur_page_count;
|
|
}
|
|
if (WASM_ADDR_OFFSET(addr) < linear_mem_size) {
|
|
mem_info->start = WASM_ADDR(WasmMemory, instance->id, 0);
|
|
mem_info->size = linear_mem_size;
|
|
snprintf(mem_info->name, sizeof(mem_info->name), "%s",
|
|
"memory");
|
|
snprintf(mem_info->permisson, sizeof(mem_info->permisson), "%s",
|
|
"rw");
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
mem_info->start = WASM_ADDR(WasmInvalid, 0, 0);
|
|
mem_info->size = 0;
|
|
}
|
|
return mem_info;
|
|
}
|
|
|
|
void
|
|
wasm_debug_instance_destroy_memregion(WASMDebugInstance *instance,
|
|
WASMDebugMemoryInfo *mem_info)
|
|
{
|
|
wasm_runtime_free(mem_info);
|
|
}
|
|
|
|
bool
|
|
wasm_debug_instance_get_obj_mem(WASMDebugInstance *instance, uint64 offset,
|
|
char *buf, uint64 *size)
|
|
{
|
|
WASMExecEnv *exec_env;
|
|
WASMModuleInstance *module_inst;
|
|
WASMDebugBreakPoint *breakpoint;
|
|
WASMFastOPCodeNode *fast_opcode;
|
|
|
|
if (!instance)
|
|
return false;
|
|
|
|
exec_env = bh_list_first_elem(&instance->cluster->exec_env_list);
|
|
if (!exec_env)
|
|
return false;
|
|
|
|
module_inst = (WASMModuleInstance *)exec_env->module_inst;
|
|
|
|
if (offset + *size > module_inst->module->load_size) {
|
|
LOG_VERBOSE("wasm_debug_instance_get_data_mem size over flow!\n");
|
|
*size = module_inst->module->load_size >= offset
|
|
? module_inst->module->load_size - offset
|
|
: 0;
|
|
}
|
|
|
|
bh_memcpy_s(buf, (uint32)*size, module_inst->module->load_addr + offset,
|
|
(uint32)*size);
|
|
|
|
breakpoint = bh_list_first_elem(&instance->break_point_list);
|
|
while (breakpoint) {
|
|
if (offset <= breakpoint->addr && breakpoint->addr < offset + *size) {
|
|
bh_memcpy_s(buf + (breakpoint->addr - offset), sizeof(break_instr),
|
|
&breakpoint->orignal_data, sizeof(break_instr));
|
|
}
|
|
breakpoint = bh_list_elem_next(breakpoint);
|
|
}
|
|
|
|
fast_opcode = bh_list_first_elem(&module_inst->module->fast_opcode_list);
|
|
while (fast_opcode) {
|
|
if (offset <= fast_opcode->offset
|
|
&& fast_opcode->offset < offset + *size) {
|
|
*(uint8 *)(buf + (fast_opcode->offset - offset)) =
|
|
fast_opcode->orig_op;
|
|
}
|
|
fast_opcode = bh_list_elem_next(fast_opcode);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
wasm_debug_instance_get_linear_mem(WASMDebugInstance *instance, uint64 offset,
|
|
char *buf, uint64 *size)
|
|
{
|
|
WASMExecEnv *exec_env;
|
|
WASMModuleInstance *module_inst;
|
|
WASMMemoryInstance *memory;
|
|
uint32 num_bytes_per_page;
|
|
uint32 linear_mem_size;
|
|
|
|
if (!instance)
|
|
return false;
|
|
|
|
exec_env = wasm_debug_instance_get_current_env(instance);
|
|
if (!exec_env)
|
|
return false;
|
|
|
|
module_inst = (WASMModuleInstance *)exec_env->module_inst;
|
|
memory = wasm_get_default_memory(module_inst);
|
|
if (memory) {
|
|
num_bytes_per_page = memory->num_bytes_per_page;
|
|
linear_mem_size = num_bytes_per_page * memory->cur_page_count;
|
|
if (offset + *size > linear_mem_size) {
|
|
LOG_VERBOSE("wasm_debug_instance_get_linear_mem size over flow!\n");
|
|
*size = linear_mem_size >= offset ? linear_mem_size - offset : 0;
|
|
}
|
|
bh_memcpy_s(buf, (uint32)*size, memory->memory_data + offset,
|
|
(uint32)*size);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
wasm_debug_instance_set_linear_mem(WASMDebugInstance *instance, uint64 offset,
|
|
char *buf, uint64 *size)
|
|
{
|
|
WASMExecEnv *exec_env;
|
|
WASMModuleInstance *module_inst;
|
|
WASMMemoryInstance *memory;
|
|
uint32 num_bytes_per_page;
|
|
uint32 linear_mem_size;
|
|
|
|
if (!instance)
|
|
return false;
|
|
|
|
exec_env = wasm_debug_instance_get_current_env(instance);
|
|
if (!exec_env)
|
|
return false;
|
|
|
|
module_inst = (WASMModuleInstance *)exec_env->module_inst;
|
|
memory = wasm_get_default_memory(module_inst);
|
|
if (memory) {
|
|
num_bytes_per_page = memory->num_bytes_per_page;
|
|
linear_mem_size = num_bytes_per_page * memory->cur_page_count;
|
|
if (offset + *size > linear_mem_size) {
|
|
LOG_VERBOSE("wasm_debug_instance_get_linear_mem size over flow!\n");
|
|
*size = linear_mem_size >= offset ? linear_mem_size - offset : 0;
|
|
}
|
|
bh_memcpy_s(memory->memory_data + offset, (uint32)*size, buf,
|
|
(uint32)*size);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
wasm_debug_instance_get_mem(WASMDebugInstance *instance, uint64 addr, char *buf,
|
|
uint64 *size)
|
|
{
|
|
switch (WASM_ADDR_TYPE(addr)) {
|
|
case WasmMemory:
|
|
return wasm_debug_instance_get_linear_mem(
|
|
instance, WASM_ADDR_OFFSET(addr), buf, size);
|
|
break;
|
|
case WasmObj:
|
|
return wasm_debug_instance_get_obj_mem(
|
|
instance, WASM_ADDR_OFFSET(addr), buf, size);
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool
|
|
wasm_debug_instance_set_mem(WASMDebugInstance *instance, uint64 addr, char *buf,
|
|
uint64 *size)
|
|
{
|
|
switch (WASM_ADDR_TYPE(addr)) {
|
|
case WasmMemory:
|
|
return wasm_debug_instance_set_linear_mem(
|
|
instance, WASM_ADDR_OFFSET(addr), buf, size);
|
|
break;
|
|
case WasmObj:
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
WASMDebugInstance *
|
|
wasm_exec_env_get_instance(WASMExecEnv *exec_env)
|
|
{
|
|
WASMDebugInstance *instance = NULL;
|
|
|
|
if (!g_debug_engine) {
|
|
return NULL;
|
|
}
|
|
|
|
os_mutex_lock(&g_debug_engine->instance_list_lock);
|
|
instance = bh_list_first_elem(&g_debug_engine->debug_instance_list);
|
|
while (instance) {
|
|
if (instance->cluster == exec_env->cluster)
|
|
break;
|
|
instance = bh_list_elem_next(instance);
|
|
}
|
|
|
|
os_mutex_unlock(&g_debug_engine->instance_list_lock);
|
|
return instance;
|
|
}
|
|
|
|
uint32
|
|
wasm_debug_instance_get_call_stack_pcs(WASMDebugInstance *instance,
|
|
korp_tid tid, uint64 buf[], uint64 size)
|
|
{
|
|
WASMExecEnv *exec_env;
|
|
struct WASMInterpFrame *frame;
|
|
uint32 i = 0;
|
|
|
|
if (!instance)
|
|
return 0;
|
|
|
|
exec_env = bh_list_first_elem(&instance->cluster->exec_env_list);
|
|
while (exec_env) {
|
|
if (exec_env->handle == tid) {
|
|
WASMModuleInstance *module_inst =
|
|
(WASMModuleInstance *)exec_env->module_inst;
|
|
frame = exec_env->cur_frame;
|
|
while (frame && i < size) {
|
|
if (frame->ip != NULL) {
|
|
buf[i++] =
|
|
WASM_ADDR(WasmObj, instance->id,
|
|
(frame->ip - module_inst->module->load_addr));
|
|
}
|
|
frame = frame->prev_frame;
|
|
}
|
|
return i;
|
|
}
|
|
exec_env = bh_list_elem_next(exec_env);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
bool
|
|
wasm_debug_instance_add_breakpoint(WASMDebugInstance *instance, uint64 addr,
|
|
uint64 length)
|
|
{
|
|
WASMExecEnv *exec_env;
|
|
WASMModuleInstance *module_inst;
|
|
uint64 offset;
|
|
|
|
if (!instance)
|
|
return false;
|
|
|
|
exec_env = bh_list_first_elem(&instance->cluster->exec_env_list);
|
|
if (!exec_env)
|
|
return false;
|
|
|
|
module_inst = (WASMModuleInstance *)exec_env->module_inst;
|
|
if (WASM_ADDR_TYPE(addr) != WasmObj)
|
|
return false;
|
|
|
|
offset = WASM_ADDR_OFFSET(addr);
|
|
|
|
if (length >= sizeof(break_instr)) {
|
|
if (offset + sizeof(break_instr) <= module_inst->module->load_size) {
|
|
WASMDebugBreakPoint *breakpoint;
|
|
if (!(breakpoint =
|
|
wasm_runtime_malloc(sizeof(WASMDebugBreakPoint)))) {
|
|
LOG_ERROR("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? */
|
|
bh_memcpy_s(&breakpoint->orignal_data, (uint32)sizeof(break_instr),
|
|
module_inst->module->load_addr + offset,
|
|
(uint32)sizeof(break_instr));
|
|
|
|
bh_memcpy_s(module_inst->module->load_addr + offset,
|
|
(uint32)sizeof(break_instr), break_instr,
|
|
(uint32)sizeof(break_instr));
|
|
|
|
bh_list_insert(&instance->break_point_list, breakpoint);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
wasm_debug_instance_remove_breakpoint(WASMDebugInstance *instance, uint64 addr,
|
|
uint64 length)
|
|
{
|
|
WASMExecEnv *exec_env;
|
|
WASMModuleInstance *module_inst;
|
|
uint64 offset;
|
|
|
|
if (!instance)
|
|
return false;
|
|
|
|
exec_env = bh_list_first_elem(&instance->cluster->exec_env_list);
|
|
if (!exec_env)
|
|
return false;
|
|
|
|
module_inst = (WASMModuleInstance *)exec_env->module_inst;
|
|
|
|
if (WASM_ADDR_TYPE(addr) != WasmObj)
|
|
return false;
|
|
offset = WASM_ADDR_OFFSET(addr);
|
|
|
|
if (length >= sizeof(break_instr)) {
|
|
if (offset + sizeof(break_instr) <= module_inst->module->load_size) {
|
|
WASMDebugBreakPoint *breakpoint =
|
|
bh_list_first_elem(&instance->break_point_list);
|
|
while (breakpoint) {
|
|
WASMDebugBreakPoint *next_break = bh_list_elem_next(breakpoint);
|
|
if (breakpoint->addr == offset) {
|
|
/* TODO: how to if more than one breakpoints are set
|
|
at the same addr? */
|
|
bh_memcpy_s(module_inst->module->load_addr + offset,
|
|
(uint32)sizeof(break_instr),
|
|
&breakpoint->orignal_data,
|
|
(uint32)sizeof(break_instr));
|
|
bh_list_remove(&instance->break_point_list, breakpoint);
|
|
wasm_runtime_free(breakpoint);
|
|
}
|
|
breakpoint = next_break;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
wasm_debug_instance_on_failure(WASMDebugInstance *instance)
|
|
{
|
|
WASMExecEnv *exec_env;
|
|
|
|
if (!instance)
|
|
return false;
|
|
|
|
os_mutex_lock(&instance->wait_lock);
|
|
exec_env = bh_list_first_elem(&instance->cluster->exec_env_list);
|
|
if (!exec_env) {
|
|
os_mutex_unlock(&instance->wait_lock);
|
|
return false;
|
|
}
|
|
|
|
if (instance->stopped_thread == NULL
|
|
&& instance->current_state == DBG_LAUNCHING) {
|
|
/* if fail in start stage: may need wait for main thread to notify it */
|
|
os_cond_wait(&instance->wait_cond, &instance->wait_lock);
|
|
}
|
|
instance->current_state = DBG_ERROR;
|
|
instance->stopped_thread = NULL;
|
|
|
|
/* terminate the wasm execution thread */
|
|
while (exec_env) {
|
|
/* Resume all threads so they can receive the TERM signal */
|
|
os_mutex_lock(&exec_env->wait_lock);
|
|
wasm_cluster_thread_send_signal(exec_env, WAMR_SIG_TERM);
|
|
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);
|
|
}
|
|
os_mutex_unlock(&instance->wait_lock);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
wasm_debug_instance_continue(WASMDebugInstance *instance)
|
|
{
|
|
WASMExecEnv *exec_env;
|
|
|
|
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;
|
|
|
|
while (exec_env) {
|
|
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;
|
|
}
|
|
|
|
bool
|
|
wasm_debug_instance_detach(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;
|
|
|
|
wasm_gdbserver_detach(instance->control_thread->server);
|
|
|
|
while (exec_env) {
|
|
if (instance->current_state == APP_STOPPED) {
|
|
/* Resume all threads since remote debugger detached*/
|
|
wasm_cluster_thread_continue(exec_env);
|
|
}
|
|
exec_env = bh_list_elem_next(exec_env);
|
|
}
|
|
|
|
/* relaunch, accept new debug connection */
|
|
instance->current_state = DBG_LAUNCHING;
|
|
instance->control_thread->status = DETACHED;
|
|
instance->stopped_thread = NULL;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
wasm_debug_instance_kill(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_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;
|
|
}
|
|
|
|
bool
|
|
wasm_debug_instance_singlestep(WASMDebugInstance *instance, korp_tid tid)
|
|
{
|
|
WASMExecEnv *exec_env;
|
|
|
|
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;
|
|
|
|
while (exec_env) {
|
|
if (exec_env->handle == tid || tid == (korp_tid)(uintptr_t)~0LL) {
|
|
wasm_cluster_thread_send_signal(exec_env, WAMR_SIG_SINGSTEP);
|
|
wasm_cluster_thread_step(exec_env);
|
|
}
|
|
exec_env = bh_list_elem_next(exec_env);
|
|
}
|
|
|
|
instance->current_state = APP_RUNNING;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
wasm_debug_instance_get_local(WASMDebugInstance *instance, int32 frame_index,
|
|
int32 local_index, char buf[], int32 *size)
|
|
{
|
|
WASMExecEnv *exec_env;
|
|
struct WASMInterpFrame *frame;
|
|
WASMFunctionInstance *cur_func;
|
|
uint8 local_type = 0xFF;
|
|
uint32 local_offset;
|
|
int32 param_count;
|
|
int32 fi = 0;
|
|
|
|
if (!instance)
|
|
return false;
|
|
|
|
exec_env = wasm_debug_instance_get_current_env(instance);
|
|
if (!exec_env)
|
|
return false;
|
|
|
|
frame = exec_env->cur_frame;
|
|
while (frame && fi++ != frame_index) {
|
|
frame = frame->prev_frame;
|
|
}
|
|
|
|
if (!frame)
|
|
return false;
|
|
cur_func = frame->function;
|
|
if (!cur_func)
|
|
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];
|
|
else if (local_index < cur_func->local_count + param_count)
|
|
local_type = cur_func->local_types[local_index - param_count];
|
|
|
|
switch (local_type) {
|
|
case VALUE_TYPE_I32:
|
|
case VALUE_TYPE_F32:
|
|
*size = 4;
|
|
bh_memcpy_s(buf, 4, (char *)(frame->lp + local_offset), 4);
|
|
break;
|
|
case VALUE_TYPE_I64:
|
|
case VALUE_TYPE_F64:
|
|
*size = 8;
|
|
bh_memcpy_s(buf, 8, (char *)(frame->lp + local_offset), 8);
|
|
break;
|
|
default:
|
|
*size = 0;
|
|
break;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
wasm_debug_instance_get_global(WASMDebugInstance *instance, int32 frame_index,
|
|
int32 global_index, char buf[], int32 *size)
|
|
{
|
|
WASMExecEnv *exec_env;
|
|
struct WASMInterpFrame *frame;
|
|
WASMModuleInstance *module_inst;
|
|
WASMGlobalInstance *globals, *global;
|
|
uint8 *global_addr;
|
|
uint8 global_type = 0xFF;
|
|
uint8 *global_data;
|
|
int32 fi = 0;
|
|
|
|
if (!instance)
|
|
return false;
|
|
|
|
exec_env = wasm_debug_instance_get_current_env(instance);
|
|
if (!exec_env)
|
|
return false;
|
|
|
|
frame = exec_env->cur_frame;
|
|
while (frame && fi++ != frame_index) {
|
|
frame = frame->prev_frame;
|
|
}
|
|
|
|
if (!frame)
|
|
return false;
|
|
|
|
module_inst = (WASMModuleInstance *)exec_env->module_inst;
|
|
global_data = module_inst->global_data;
|
|
globals = module_inst->e->globals;
|
|
|
|
if ((global_index < 0)
|
|
|| ((uint32)global_index >= module_inst->e->global_count)) {
|
|
return false;
|
|
}
|
|
global = globals + global_index;
|
|
|
|
#if WASM_ENABLE_MULTI_MODULE == 0
|
|
global_addr = global_data + global->data_offset;
|
|
#else
|
|
global_addr = global->import_global_inst
|
|
? global->import_module_inst->global_data
|
|
+ global->import_global_inst->data_offset
|
|
: global_data + global->data_offset;
|
|
#endif
|
|
global_type = global->type;
|
|
|
|
switch (global_type) {
|
|
case VALUE_TYPE_I32:
|
|
case VALUE_TYPE_F32:
|
|
*size = 4;
|
|
bh_memcpy_s(buf, 4, (char *)(global_addr), 4);
|
|
break;
|
|
case VALUE_TYPE_I64:
|
|
case VALUE_TYPE_F64:
|
|
*size = 8;
|
|
bh_memcpy_s(buf, 8, (char *)(global_addr), 8);
|
|
break;
|
|
default:
|
|
*size = 0;
|
|
break;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
uint64
|
|
wasm_debug_instance_mmap(WASMDebugInstance *instance, uint32 size,
|
|
int32 map_prot)
|
|
{
|
|
WASMExecEnv *exec_env;
|
|
uint32 offset = 0;
|
|
(void)map_prot;
|
|
|
|
if (!instance)
|
|
return 0;
|
|
|
|
exec_env = wasm_debug_instance_get_current_env(instance);
|
|
if (!exec_env)
|
|
return 0;
|
|
|
|
if (instance->exec_mem_info.start_offset == 0) {
|
|
return 0;
|
|
}
|
|
|
|
if ((uint64)instance->exec_mem_info.current_pos
|
|
- instance->exec_mem_info.start_offset + size
|
|
<= (uint64)instance->exec_mem_info.size) {
|
|
offset = instance->exec_mem_info.current_pos;
|
|
instance->exec_mem_info.current_pos += size;
|
|
}
|
|
|
|
if (offset == 0) {
|
|
LOG_WARNING("the memory may be not enough for debug, try use larger "
|
|
"--heap-size");
|
|
return 0;
|
|
}
|
|
|
|
return WASM_ADDR(WasmMemory, 0, offset);
|
|
}
|
|
|
|
bool
|
|
wasm_debug_instance_ummap(WASMDebugInstance *instance, uint64 addr)
|
|
{
|
|
WASMExecEnv *exec_env;
|
|
|
|
if (!instance)
|
|
return false;
|
|
|
|
exec_env = wasm_debug_instance_get_current_env(instance);
|
|
if (!exec_env)
|
|
return false;
|
|
|
|
if (instance->exec_mem_info.start_offset == 0) {
|
|
return false;
|
|
}
|
|
|
|
(void)addr;
|
|
|
|
/* Currently we don't support to free the execution memory, simply return
|
|
* true here */
|
|
return true;
|
|
}
|