Implement source debugging for interpreter and AOT (#769)

Implement source debugging feature for classic interpreter and AOT:
- use `cmake -DWAMR_BUILD_DEBUG_INTERP=1` to enable interpreter debugging
- use `cmake -DWAMR_BUILD_DEBUG_AOT=1` to enable AOT debugging

See doc/source_debugging.md for more details.
This commit is contained in:
Wenyong Huang 2021-09-29 13:36:46 +08:00 committed by GitHub
parent b5a67cb91e
commit 9ef37dd781
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
55 changed files with 10092 additions and 63 deletions

View File

@ -28,6 +28,7 @@ iwasm VM core
- [Multiple modules as dependencies](./doc/multi_module.md), ref to [sample](samples/multi-module) - [Multiple modules as dependencies](./doc/multi_module.md), ref to [sample](samples/multi-module)
- [Thread management and pthread library](./doc/pthread_library.md), ref to [sample](samples/multi-thread) - [Thread management and pthread library](./doc/pthread_library.md), ref to [sample](samples/multi-thread)
- [Linux SGX (Intel Software Guard Extension) support](./doc/linux_sgx.md) - [Linux SGX (Intel Software Guard Extension) support](./doc/linux_sgx.md)
- [Source debugging](./doc/source_debugging.md)
### post-MVP features ### post-MVP features
- [Non-trapping float-to-int conversions](https://github.com/WebAssembly/nontrapping-float-to-int-conversions) - [Non-trapping float-to-int conversions](https://github.com/WebAssembly/nontrapping-float-to-int-conversions)

View File

@ -239,3 +239,9 @@ endif ()
if (WAMR_DISABLE_APP_ENTRY EQUAL 1) if (WAMR_DISABLE_APP_ENTRY EQUAL 1)
message (" WAMR application entry functions excluded") message (" WAMR application entry functions excluded")
endif () endif ()
if (WAMR_BUILD_DEBUG_INTERP EQUAL 1)
message (" Debug Interpreter enabled")
endif ()
if (WAMR_BUILD_DEBUG_AOT EQUAL 1)
message (" Debug AOT enabled")
endif ()

File diff suppressed because it is too large Load Diff

View File

@ -84,6 +84,11 @@ if (WAMR_BUILD_LIB_PTHREAD EQUAL 1)
set (WAMR_BUILD_SHARED_MEMORY 1) set (WAMR_BUILD_SHARED_MEMORY 1)
endif () endif ()
if (WAMR_BUILD_DEBUG_INTERP EQUAL 1)
set (WAMR_BUILD_THREAD_MGR 1)
include (${IWASM_DIR}/libraries/debug-engine/debug_engine.cmake)
endif ()
if (WAMR_BUILD_THREAD_MGR EQUAL 1) if (WAMR_BUILD_THREAD_MGR EQUAL 1)
include (${IWASM_DIR}/libraries/thread-mgr/thread_mgr.cmake) include (${IWASM_DIR}/libraries/thread-mgr/thread_mgr.cmake)
endif () endif ()
@ -132,6 +137,7 @@ set (source_all
${LIB_PTHREAD_SOURCE} ${LIB_PTHREAD_SOURCE}
${THREAD_MGR_SOURCE} ${THREAD_MGR_SOURCE}
${LIBC_EMCC_SOURCE} ${LIBC_EMCC_SOURCE}
${DEBUG_ENGINE_SOURCE}
) )
set (WAMR_RUNTIME_LIB_SOURCE ${source_all}) set (WAMR_RUNTIME_LIB_SOURCE ${source_all})

View File

@ -14,6 +14,10 @@
#include "../compilation/aot_llvm.h" #include "../compilation/aot_llvm.h"
#include "../interpreter/wasm_loader.h" #include "../interpreter/wasm_loader.h"
#endif #endif
#if WASM_ENABLE_DEBUG_AOT != 0
#include "debug/elf_parser.h"
#include "debug/jit_debug.h"
#endif
#define XMM_PLT_PREFIX "__xmm@" #define XMM_PLT_PREFIX "__xmm@"
#define REAL_PLT_PREFIX "__real@" #define REAL_PLT_PREFIX "__real@"
@ -1231,7 +1235,6 @@ load_init_data_section(const uint8 *buf, const uint8 *buf_end,
} }
return true; return true;
fail: fail:
return false; return false;
} }
@ -1257,12 +1260,30 @@ load_text_section(const uint8 *buf, const uint8 *buf_end,
module->code = (void*)(buf + module->literal_size); module->code = (void*)(buf + module->literal_size);
module->code_size = (uint32)(buf_end - (uint8*)module->code); module->code_size = (uint32)(buf_end - (uint8*)module->code);
#if WASM_ENABLE_DEBUG_AOT != 0
module->elf_size = module->code_size;
if (is_ELF(module->code)) {
/* Now code points to an ELF object, we pull it down to .text section */
uint64 offset;
uint64 size;
char *buf = module->code;
module->elf_hdr = buf;
if (!get_text_section(buf, &offset, &size)) {
set_error_buf(error_buf, error_buf_size,
"get text section of ELF failed");
return false;
}
module->code = buf + offset;
module->code_size -= (uint32)offset;
}
#endif
if ((module->code_size > 0) && (module->native_symbol_count == 0)) { if ((module->code_size > 0) && (module->native_symbol_count == 0)) {
plt_base = (uint8 *)buf_end - get_plt_table_size(); plt_base = (uint8 *)buf_end - get_plt_table_size();
init_plt_table(plt_base); init_plt_table(plt_base);
} }
return true; return true;
fail: fail:
return false; return false;
} }
@ -1451,7 +1472,6 @@ load_export_section(const uint8 *buf, const uint8 *buf_end,
} }
return true; return true;
fail: fail:
return false; return false;
} }
@ -2247,6 +2267,13 @@ load_from_sections(AOTModule *module, AOTSection *sections,
#if WASM_ENABLE_MEMORY_TRACING != 0 #if WASM_ENABLE_MEMORY_TRACING != 0
wasm_runtime_dump_module_mem_consumption((WASMModuleCommon*)module); wasm_runtime_dump_module_mem_consumption((WASMModuleCommon*)module);
#endif #endif
#if WASM_ENABLE_DEBUG_AOT != 0
if (!jit_code_entry_create(module->elf_hdr, module->elf_size)) {
set_error_buf(error_buf, error_buf_size, "create jit code entry failed");
return false;
}
#endif
return true; return true;
} }
@ -2893,6 +2920,9 @@ aot_unload(AOTModule *module)
if (module->data_sections) if (module->data_sections)
destroy_object_data_sections(module->data_sections, destroy_object_data_sections(module->data_sections,
module->data_section_count); module->data_section_count);
#if WASM_ENABLE_DEBUG_AOT != 0
jit_code_entry_destroy(module->elf_hdr);
#endif
wasm_runtime_free(module); wasm_runtime_free(module);
} }

View File

@ -254,6 +254,10 @@ typedef struct AOTModule {
WASIArguments wasi_args; WASIArguments wasi_args;
bool is_wasi_module; bool is_wasi_module;
#endif #endif
#if WASM_ENABLE_DEBUG_AOT != 0
void *elf_hdr;
uint32 elf_size;
#endif
} AOTModule; } AOTModule;
typedef union { typedef union {

View File

@ -0,0 +1,152 @@
/*
* Copyright (C) 2021 Ant Group. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include <stdio.h>
#include <assert.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdbool.h>
#include <elf.h>
#include "aot_runtime.h"
#include "bh_log.h"
#include "elf_parser.h"
bool
is_ELF(void *buf)
{
Elf32_Ehdr *eh = (Elf32_Ehdr *)buf;
if (!strncmp((char *)eh->e_ident, "\177ELF", 4)) {
LOG_VERBOSE("the buffer is ELF entry!");
return true;
}
LOG_VERBOSE("the buffer is not ELF entry!");
return false;
}
static bool
is64Bit(Elf32_Ehdr *eh)
{
if (eh->e_ident[EI_CLASS] == ELFCLASS64)
return true;
else
return false;
}
static bool
is32Bit(Elf32_Ehdr *eh)
{
if (eh->e_ident[EI_CLASS] == ELFCLASS32)
return true;
else
return false;
}
bool
is_ELF64(void *buf)
{
Elf64_Ehdr *eh = (Elf64_Ehdr *)buf;
if (!strncmp((char *)eh->e_ident, "\177ELF", 4)) {
LOG_VERBOSE("the buffer is ELF entry!");
return true;
}
LOG_VERBOSE("the buffer is not ELF entry!");
return false;
}
static void
read_section_header_table(Elf32_Ehdr *eh, Elf32_Shdr *sh_table[])
{
uint32_t i;
char *buf = (char *)eh;
buf += eh->e_shoff;
LOG_VERBOSE("str index = %d count=%d", eh->e_shstrndx, eh->e_shnum);
for (i = 0; i < eh->e_shnum; i++) {
sh_table[i] = (Elf32_Shdr *)buf;
buf += eh->e_shentsize;
}
}
static void
read_section_header_table64(Elf64_Ehdr *eh, Elf64_Shdr *sh_table[])
{
uint32_t i;
char *buf = (char *)eh;
buf += eh->e_shoff;
for (i = 0; i < eh->e_shnum; i++) {
sh_table[i] = (Elf64_Shdr *)buf;
buf += eh->e_shentsize;
}
}
static char *
get_section(Elf32_Ehdr *eh, Elf32_Shdr *section_header)
{
char *buf = (char *)eh;
return buf + section_header->sh_offset;
}
static char *
get_section64(Elf64_Ehdr *eh, Elf64_Shdr *section_header)
{
char *buf = (char *)eh;
return buf + section_header->sh_offset;
}
bool
get_text_section(void *buf, uint64_t *offset, uint64_t *size)
{
bool ret = false;
uint32 i;
char *sh_str;
if (is64Bit(buf)) {
Elf64_Ehdr *eh = (Elf64_Ehdr *)buf;
Elf64_Shdr **sh_table =
wasm_runtime_malloc(eh->e_shnum * sizeof(Elf64_Shdr *));
if (sh_table) {
read_section_header_table64(eh, sh_table);
sh_str = get_section64(eh, sh_table[eh->e_shstrndx]);
for (i= 0; i < eh->e_shnum; i++) {
if (!strcmp(sh_str + sh_table[i]->sh_name, ".text")) {
*offset = sh_table[i]->sh_offset;
*size = sh_table[i]->sh_size;
sh_table[i]->sh_addr = (Elf64_Addr)(uintptr_t)
((char *)buf + sh_table[i]->sh_offset);
ret = true;
break;
}
}
wasm_runtime_free(sh_table);
}
}
else if (is32Bit(buf)) {
Elf32_Ehdr *eh = (Elf32_Ehdr *)buf;
Elf32_Shdr **sh_table =
wasm_runtime_malloc(eh->e_shnum * sizeof(Elf32_Shdr *));
if (sh_table) {
read_section_header_table(eh, sh_table);
sh_str = get_section(eh, sh_table[eh->e_shstrndx]);
for (i= 0; i < eh->e_shnum; i++) {
if (!strcmp(sh_str + sh_table[i]->sh_name, ".text")) {
*offset = sh_table[i]->sh_offset;
*size = sh_table[i]->sh_size;
sh_table[i]->sh_addr = (Elf32_Addr)(uintptr_t)
((char *)buf + sh_table[i]->sh_offset);
ret = true;
break;
}
}
wasm_runtime_free(sh_table);
}
}
return ret;
}

View File

@ -0,0 +1,27 @@
/*
* Copyright (C) 2021 Ant Group. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#ifndef _ELF_PARSERE_H_
#define _ELF_PARSER_H_
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
bool
is_ELF(void *buf);
bool
is_ELF64(void *buf);
bool
get_text_section(void *buf, uint64_t *offset, uint64_t *size);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,253 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2021 Ant Group. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "bh_log.h"
#include "bh_platform.h"
#include "wasm_runtime.h"
#include <stdio.h>
#include <assert.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdbool.h>
/* This must be kept in sync with gdb/gdb/jit.h */
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
JIT_NOACTION = 0,
JIT_REGISTER_FN,
JIT_UNREGISTER_FN
} JITAction;
typedef struct JITCodeEntry {
struct JITCodeEntry *next_;
struct JITCodeEntry *prev_;
const uint8 *symfile_addr_;
uint64 symfile_size_;
} JITCodeEntry;
typedef struct JITDescriptor {
uint32 version_;
uint32 action_flag_;
JITCodeEntry *relevant_entry_;
JITCodeEntry *first_entry_;
} JITDescriptor;
/* LLVM has already define this */
#if (WASM_ENABLE_WAMR_COMPILER == 0) && (WASM_ENABLE_JIT == 0)
/**
* GDB will place breakpoint into this function.
* To prevent GCC from inlining or removing it we place noinline attribute
* and inline assembler statement inside.
*/
void __attribute__((noinline)) __jit_debug_register_code();
void __attribute__((noinline)) __jit_debug_register_code()
{
int x;
*(char *)&x = '\0';
}
/**
* GDB will inspect contents of this descriptor.
* Static initialization is necessary to prevent GDB from seeing
* uninitialized descriptor.
*/
JITDescriptor __jit_debug_descriptor = { 1, JIT_NOACTION, NULL, NULL };
#else
extern void __jit_debug_register_code();
extern JITDescriptor __jit_debug_descriptor;
#endif
/**
* Call __jit_debug_register_code indirectly via global variable.
* This gives the debugger an easy way to inject custom code to
* handle the events.
*/
void (*__jit_debug_register_code_ptr)() = __jit_debug_register_code;
#ifdef __cplusplus
}
#endif
typedef struct WASMJITDebugEngine {
korp_mutex jit_entry_lock;
bh_list jit_entry_list;
} WASMJITDebugEngine;
typedef struct WASMJITEntryNode {
struct WASMJITEntryNode *next;
JITCodeEntry *entry;
} WASMJITEntryNode;
static WASMJITDebugEngine *jit_debug_engine;
static JITCodeEntry *
CreateJITCodeEntryInternal(const uint8 *symfile_addr, uint64 symfile_size)
{
JITCodeEntry *entry;
os_mutex_lock(&jit_debug_engine->jit_entry_lock);
if (!(entry = wasm_runtime_malloc(sizeof(JITCodeEntry)))) {
LOG_ERROR("WASM JIT Debug Engine error: failed to allocate memory");
os_mutex_unlock(&jit_debug_engine->jit_entry_lock);
return NULL;
}
entry->symfile_addr_ = symfile_addr;
entry->symfile_size_ = symfile_size;
entry->prev_ = NULL;
entry->next_ = __jit_debug_descriptor.first_entry_;
if (entry->next_ != NULL) {
entry->next_->prev_ = entry;
}
__jit_debug_descriptor.first_entry_ = entry;
__jit_debug_descriptor.relevant_entry_ = entry;
__jit_debug_descriptor.action_flag_ = JIT_REGISTER_FN;
(*__jit_debug_register_code_ptr)();
os_mutex_unlock(&jit_debug_engine->jit_entry_lock);
return entry;
}
static void
DestroyJITCodeEntryInternal(JITCodeEntry *entry)
{
os_mutex_lock(&jit_debug_engine->jit_entry_lock);
if (entry->prev_ != NULL) {
entry->prev_->next_ = entry->next_;
}
else {
__jit_debug_descriptor.first_entry_ = entry->next_;
}
if (entry->next_ != NULL) {
entry->next_->prev_ = entry->prev_;
}
__jit_debug_descriptor.relevant_entry_ = entry;
__jit_debug_descriptor.action_flag_ = JIT_UNREGISTER_FN;
(*__jit_debug_register_code_ptr)();
wasm_runtime_free(entry);
os_mutex_unlock(&jit_debug_engine->jit_entry_lock);
}
bool
jit_debug_engine_init()
{
if (jit_debug_engine) {
return true;
}
if (!(jit_debug_engine =
wasm_runtime_malloc(sizeof(WASMJITDebugEngine)))) {
LOG_ERROR("WASM JIT Debug Engine error: failed to allocate memory");
return false;
}
memset(jit_debug_engine, 0, sizeof(WASMJITDebugEngine));
if (os_mutex_init(&jit_debug_engine->jit_entry_lock) != 0) {
wasm_runtime_free(jit_debug_engine);
jit_debug_engine = NULL;
return false;
}
bh_list_init(&jit_debug_engine->jit_entry_list);
return true;
}
void
jit_debug_engine_destroy()
{
if (jit_debug_engine) {
WASMJITEntryNode *node, *node_next;
/* Destroy all nodes */
node = bh_list_first_elem(&jit_debug_engine->jit_entry_list);
while (node) {
node_next = bh_list_elem_next(node);
DestroyJITCodeEntryInternal(node->entry);
bh_list_remove(&jit_debug_engine->jit_entry_list, node);
wasm_runtime_free(node);
node = node_next;
}
/* Destroy JIT Debug Engine */
os_mutex_destroy(&jit_debug_engine->jit_entry_lock);
wasm_runtime_free(jit_debug_engine);
jit_debug_engine = NULL;
}
}
bool
jit_code_entry_create(const uint8 *symfile_addr, uint64 symfile_size)
{
JITCodeEntry *entry;
WASMJITEntryNode *node;
if (!(node = wasm_runtime_malloc(sizeof(WASMJITEntryNode)))) {
LOG_ERROR("WASM JIT Debug Engine error: failed to allocate memory");
return false;
}
entry = CreateJITCodeEntryInternal(symfile_addr, symfile_size);
if (!entry) {
wasm_runtime_free(node);
return false;
}
node->entry = entry;
os_mutex_lock(&jit_debug_engine->jit_entry_lock);
bh_list_insert(&jit_debug_engine->jit_entry_list, node);
os_mutex_unlock(&jit_debug_engine->jit_entry_lock);
return true;
}
void
jit_code_entry_destroy(const uint8 *symfile_addr)
{
WASMJITEntryNode *node;
node = bh_list_first_elem(&jit_debug_engine->jit_entry_list);
while (node) {
WASMJITEntryNode *next_node = bh_list_elem_next(node);
if (node->entry->symfile_addr_ == symfile_addr) {
DestroyJITCodeEntryInternal(node->entry);
os_mutex_lock(&jit_debug_engine->jit_entry_lock);
bh_list_remove(&jit_debug_engine->jit_entry_list, node);
os_mutex_unlock(&jit_debug_engine->jit_entry_lock);
wasm_runtime_free(node);
}
node = next_node;
}
}

View File

@ -0,0 +1,29 @@
/*
* Copyright (C) 2021 Ant Group. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#ifndef _JIT_DEBUG_H_
#define _JIT_DEBUG_H_
#ifdef __cplusplus
extern "C" {
#endif
bool
jit_debug_engine_init();
void
jit_debug_engine_destroy();
bool
jit_code_entry_create(const uint8 *symfile_addr, uint64 symfile_size);
void
jit_code_entry_destroy(const uint8 *symfile_addr);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -31,5 +31,10 @@ else ()
message (FATAL_ERROR "Build target isn't set") message (FATAL_ERROR "Build target isn't set")
endif () endif ()
set (IWASM_AOT_SOURCE ${c_source_all} ${arch_source}) if (WAMR_BUILD_DEBUG_AOT EQUAL 1)
add_definitions(-DWASM_ENABLE_DEBUG_AOT=1)
file(GLOB debug_source ${IWASM_AOT_DIR}/debug/*.c)
endif()
set (IWASM_AOT_SOURCE ${c_source_all} ${arch_source} ${debug_source})

View File

@ -18,6 +18,9 @@
#if WASM_ENABLE_THREAD_MGR != 0 #if WASM_ENABLE_THREAD_MGR != 0
#include "../libraries/thread-mgr/thread_manager.h" #include "../libraries/thread-mgr/thread_manager.h"
#if WASM_ENABLE_DEBUG_INTERP != 0
#include "../libraries/debug-engine/debug_engine.h"
#endif
#endif #endif
WASMExecEnv * WASMExecEnv *
@ -46,6 +49,12 @@ wasm_exec_env_create_internal(struct WASMModuleInstanceCommon *module_inst,
if (os_cond_init(&exec_env->wait_cond) != 0) if (os_cond_init(&exec_env->wait_cond) != 0)
goto fail3; goto fail3;
#if WASM_ENABLE_DEBUG_INTERP != 0
if (!(exec_env->current_status = wasm_cluster_create_exenv_status()))
goto fail4;
#endif
#endif #endif
exec_env->module_inst = module_inst; exec_env->module_inst = module_inst;
@ -68,6 +77,10 @@ wasm_exec_env_create_internal(struct WASMModuleInstanceCommon *module_inst,
return exec_env; return exec_env;
#if WASM_ENABLE_THREAD_MGR != 0 #if WASM_ENABLE_THREAD_MGR != 0
#if WASM_ENABLE_DEBUG_INTERP != 0
fail4:
os_cond_destroy(&exec_env->wait_cond);
#endif
fail3: fail3:
os_mutex_destroy(&exec_env->wait_lock); os_mutex_destroy(&exec_env->wait_lock);
fail2: fail2:
@ -86,6 +99,9 @@ wasm_exec_env_destroy_internal(WASMExecEnv *exec_env)
#if WASM_ENABLE_THREAD_MGR != 0 #if WASM_ENABLE_THREAD_MGR != 0
os_mutex_destroy(&exec_env->wait_lock); os_mutex_destroy(&exec_env->wait_lock);
os_cond_destroy(&exec_env->wait_cond); os_cond_destroy(&exec_env->wait_cond);
#if WASM_ENABLE_DEBUG_INTERP != 0
wasm_cluster_destroy_exenv_status(exec_env->current_status);
#endif
#endif #endif
#if WASM_ENABLE_AOT != 0 #if WASM_ENABLE_AOT != 0
wasm_runtime_free(exec_env->argv_buf); wasm_runtime_free(exec_env->argv_buf);
@ -131,6 +147,10 @@ wasm_exec_env_create(struct WASMModuleInstanceCommon *module_inst,
wasm_exec_env_destroy_internal(exec_env); wasm_exec_env_destroy_internal(exec_env);
return NULL; return NULL;
} }
#if WASM_ENABLE_DEBUG_INTERP != 0
wasm_debug_instance_create(cluster);
#endif
#endif #endif
return exec_env; return exec_env;
} }
@ -142,6 +162,12 @@ wasm_exec_env_destroy(WASMExecEnv *exec_env)
/* Terminate all sub-threads */ /* Terminate all sub-threads */
WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env); WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env);
if (cluster) { if (cluster) {
#if WASM_ENABLE_THREAD_MGR != 0
#if WASM_ENABLE_DEBUG_INTERP != 0
wasm_cluster_thread_exited(exec_env);
wasm_debug_instance_destroy(cluster);
#endif
#endif
wasm_cluster_terminate_all_except_self(cluster, exec_env); wasm_cluster_terminate_all_except_self(cluster, exec_env);
wasm_cluster_del_exec_env(cluster, exec_env); wasm_cluster_del_exec_env(cluster, exec_env);
} }

View File

@ -20,6 +20,9 @@ struct WASMInterpFrame;
#if WASM_ENABLE_THREAD_MGR != 0 #if WASM_ENABLE_THREAD_MGR != 0
typedef struct WASMCluster WASMCluster; typedef struct WASMCluster WASMCluster;
#if WASM_ENABLE_DEBUG_INTERP != 0
typedef struct WASMCurrentEnvStatus WASMCurrentEnvStatus;
#endif
#endif #endif
#ifdef OS_ENABLE_HW_BOUND_CHECK #ifdef OS_ENABLE_HW_BOUND_CHECK
@ -97,6 +100,10 @@ typedef struct WASMExecEnv {
korp_cond wait_cond; korp_cond wait_cond;
#endif #endif
#if WASM_ENABLE_DEBUG_INTERP != 0
WASMCurrentEnvStatus *current_status;
#endif
/* attachment for native function */ /* attachment for native function */
void *attachment; void *attachment;

View File

@ -14,9 +14,15 @@
#endif #endif
#if WASM_ENABLE_AOT != 0 #if WASM_ENABLE_AOT != 0
#include "../aot/aot_runtime.h" #include "../aot/aot_runtime.h"
#if WASM_ENABLE_DEBUG_AOT != 0
#include "../aot/debug/jit_debug.h"
#endif
#endif #endif
#if WASM_ENABLE_THREAD_MGR != 0 #if WASM_ENABLE_THREAD_MGR != 0
#include "../libraries/thread-mgr/thread_manager.h" #include "../libraries/thread-mgr/thread_manager.h"
#if WASM_ENABLE_DEBUG_INTERP != 0
#include "../libraries/debug-engine/debug_engine.h"
#endif
#endif #endif
#if WASM_ENABLE_SHARED_MEMORY != 0 #if WASM_ENABLE_SHARED_MEMORY != 0
#include "wasm_shared_memory.h" #include "wasm_shared_memory.h"
@ -128,20 +134,29 @@ wasm_runtime_env_init()
goto fail6; goto fail6;
} }
#endif #endif
#if WASM_ENABLE_DEBUG_AOT != 0
if (!jit_debug_engine_init()) {
goto fail7;
}
#endif
#endif #endif
#if WASM_ENABLE_REF_TYPES != 0 #if WASM_ENABLE_REF_TYPES != 0
if (!wasm_externref_map_init()) { if (!wasm_externref_map_init()) {
goto fail7; goto fail8;
} }
#endif #endif
return true; return true;
#if WASM_ENABLE_REF_TYPES != 0 #if WASM_ENABLE_REF_TYPES != 0
fail7: fail8:
#endif #endif
#if WASM_ENABLE_AOT != 0 #if WASM_ENABLE_AOT != 0
#if WASM_ENABLE_DEBUG_AOT != 0
jit_debug_engine_destroy();
fail7:
#endif
#ifdef OS_ENABLE_HW_BOUND_CHECK #ifdef OS_ENABLE_HW_BOUND_CHECK
aot_signal_destroy(); aot_signal_destroy();
fail6: fail6:
@ -201,6 +216,9 @@ wasm_runtime_destroy()
#endif #endif
#if WASM_ENABLE_AOT != 0 #if WASM_ENABLE_AOT != 0
#if WASM_ENABLE_DEBUG_AOT != 0
jit_debug_engine_destroy();
#endif
#ifdef OS_ENABLE_HW_BOUND_CHECK #ifdef OS_ENABLE_HW_BOUND_CHECK
aot_signal_destroy(); aot_signal_destroy();
#endif #endif
@ -220,6 +238,9 @@ wasm_runtime_destroy()
#endif #endif
#if (WASM_ENABLE_WAMR_COMPILER == 0) && (WASM_ENABLE_THREAD_MGR != 0) #if (WASM_ENABLE_WAMR_COMPILER == 0) && (WASM_ENABLE_THREAD_MGR != 0)
#if WASM_ENABLE_DEBUG_INTERP != 0
wasm_debug_engine_destroy();
#endif
thread_manager_destroy(); thread_manager_destroy();
#endif #endif
@ -241,6 +262,16 @@ wasm_runtime_full_init(RuntimeInitArgs *init_args)
return false; return false;
} }
#if WASM_ENABLE_DEBUG_INTERP != 0
if (strlen(init_args->ip_addr))
if (!wasm_debug_engine_init(init_args->ip_addr,
init_args->platform_port,
init_args->instance_port)) {
wasm_runtime_destroy();
return false;
}
#endif
if (init_args->n_native_symbols > 0 if (init_args->n_native_symbols > 0
&& !wasm_runtime_register_natives(init_args->native_module_name, && !wasm_runtime_register_natives(init_args->native_module_name,
init_args->native_symbols, init_args->native_symbols,

View File

@ -774,24 +774,24 @@ wasm_runtime_finalize_call_function(WASMExecEnv *exec_env,
bool bool
wasm_runtime_get_export_func_type(const WASMModuleCommon *module_comm, wasm_runtime_get_export_func_type(const WASMModuleCommon *module_comm,
const WASMExport *export_func_type, const WASMExport *export_,
WASMType **out); WASMType **out);
bool bool
wasm_runtime_get_export_global_type(const WASMModuleCommon *module_comm, wasm_runtime_get_export_global_type(const WASMModuleCommon *module_comm,
const WASMExport *export_global_type, const WASMExport *export_,
uint8 *out_val_type, uint8 *out_val_type,
bool *out_mutability); bool *out_mutability);
bool bool
wasm_runtime_get_export_memory_type(const WASMModuleCommon *module_comm, wasm_runtime_get_export_memory_type(const WASMModuleCommon *module_comm,
const WASMExport *export_memory_type, const WASMExport *export_,
uint32 *out_min_page, uint32 *out_min_page,
uint32 *out_max_page); uint32 *out_max_page);
bool bool
wasm_runtime_get_export_table_type(const WASMModuleCommon *module_comm, wasm_runtime_get_export_table_type(const WASMModuleCommon *module_comm,
const WASMExport *export_table_type, const WASMExport *export_,
uint8 *out_elem_type, uint8 *out_elem_type,
uint32 *out_min_size, uint32 *out_min_size,
uint32 *out_max_size); uint32 *out_max_size);

View File

@ -21,6 +21,10 @@ typedef InitializerExpression AOTInitExpr;
typedef WASMType AOTFuncType; typedef WASMType AOTFuncType;
typedef WASMExport AOTExport; typedef WASMExport AOTExport;
#if WASM_ENABLE_DEBUG_AOT != 0
typedef void * dwar_extractor_handle_t;
#endif
typedef enum AOTIntCond { typedef enum AOTIntCond {
INT_EQZ = 0, INT_EQZ = 0,
INT_EQ, INT_EQ,
@ -251,6 +255,9 @@ typedef struct AOTCompData {
uint32 aux_stack_size; uint32 aux_stack_size;
WASMModule *wasm_module; WASMModule *wasm_module;
#if WASM_ENABLE_DEBUG_AOT != 0
dwar_extractor_handle_t extractor;
#endif
} AOTCompData; } AOTCompData;
typedef struct AOTNativeSymbol { typedef struct AOTNativeSymbol {

View File

@ -32,6 +32,9 @@
#include "../interpreter/wasm_opcode.h" #include "../interpreter/wasm_opcode.h"
#include <errno.h> #include <errno.h>
#if WASM_ENABLE_DEBUG_AOT != 0
#include "debug/dwarf_extractor.h"
#endif
#define CHECK_BUF(buf, buf_end, length) do { \ #define CHECK_BUF(buf, buf_end, length) do { \
if (buf + length > buf_end) { \ if (buf + length > buf_end) { \
@ -153,6 +156,9 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
float32 f32_const; float32 f32_const;
float64 f64_const; float64 f64_const;
AOTFuncType *func_type = NULL; AOTFuncType *func_type = NULL;
#if WASM_ENABLE_DEBUG_AOT != 0
LLVMMetadataRef location;
#endif
/* Start to translate the opcodes */ /* Start to translate the opcodes */
LLVMPositionBuilderAtEnd(comp_ctx->builder, LLVMPositionBuilderAtEnd(comp_ctx->builder,
@ -160,6 +166,15 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
->llvm_entry_block); ->llvm_entry_block);
while (frame_ip < frame_ip_end) { while (frame_ip < frame_ip_end) {
opcode = *frame_ip++; opcode = *frame_ip++;
#if WASM_ENABLE_DEBUG_AOT != 0
location = dwarf_gen_location(
comp_ctx, func_ctx,
(frame_ip - 1) - comp_ctx->comp_data->wasm_module->buf_code
);
LLVMSetCurrentDebugLocation2(comp_ctx->builder, location);
#endif
switch (opcode) { switch (opcode) {
case WASM_OP_UNREACHABLE: case WASM_OP_UNREACHABLE:
if (!aot_compile_op_unreachable(comp_ctx, func_ctx, &frame_ip)) if (!aot_compile_op_unreachable(comp_ctx, func_ctx, &frame_ip))
@ -2440,6 +2455,10 @@ aot_compile_wasm(AOTCompContext *comp_ctx)
errno = 0; errno = 0;
#endif #endif
#if WASM_ENABLE_DEBUG_AOT != 0
LLVMDIBuilderFinalize(comp_ctx->debug_builder);
#endif
bh_print_time("Begin to verify LLVM module"); bh_print_time("Begin to verify LLVM module");
ret = LLVMVerifyModule(comp_ctx->module, LLVMPrintMessageAction, &msg); ret = LLVMVerifyModule(comp_ctx->module, LLVMPrintMessageAction, &msg);

View File

@ -1757,22 +1757,34 @@ aot_resolve_target_info(AOTCompContext *comp_ctx, AOTObjectData *obj_data)
static bool static bool
aot_resolve_text(AOTObjectData *obj_data) aot_resolve_text(AOTObjectData *obj_data)
{ {
LLVMSectionIteratorRef sec_itr; #if WASM_ENABLE_DEBUG_AOT != 0
char *name; LLVMBinaryType bin_type = LLVMBinaryGetType(obj_data->binary);
if (bin_type == LLVMBinaryTypeELF32L || bin_type == LLVMBinaryTypeELF64L) {
obj_data->text = (char *)LLVMGetBufferStart(obj_data->mem_buf);
obj_data->text_size = (uint32)LLVMGetBufferSize(obj_data->mem_buf);
}
else
#endif
{
LLVMSectionIteratorRef sec_itr;
char *name;
if (!(sec_itr = LLVMObjectFileCopySectionIterator(obj_data->binary))) { if (!(sec_itr = LLVMObjectFileCopySectionIterator(obj_data->binary))) {
aot_set_last_error("llvm get section iterator failed."); aot_set_last_error("llvm get section iterator failed.");
return false; return false;
}
while (!LLVMObjectFileIsSectionIteratorAtEnd(obj_data->binary, sec_itr)) {
if ((name = (char *)LLVMGetSectionName(sec_itr)) && !strcmp(name, ".text")) {
obj_data->text = (char *)LLVMGetSectionContents(sec_itr);
obj_data->text_size = (uint32)LLVMGetSectionSize(sec_itr);
break;
} }
LLVMMoveToNextSection(sec_itr); while (
!LLVMObjectFileIsSectionIteratorAtEnd(obj_data->binary, sec_itr)) {
if ((name = (char *)LLVMGetSectionName(sec_itr))
&& !strcmp(name, ".text")) {
obj_data->text = (char *)LLVMGetSectionContents(sec_itr);
obj_data->text_size = (uint32)LLVMGetSectionSize(sec_itr);
break;
}
LLVMMoveToNextSection(sec_itr);
}
LLVMDisposeSectionIterator(sec_itr);
} }
LLVMDisposeSectionIterator(sec_itr);
return true; return true;
} }

View File

@ -8,6 +8,10 @@
#include "../aot/aot_runtime.h" #include "../aot/aot_runtime.h"
#include "../interpreter/wasm_loader.h" #include "../interpreter/wasm_loader.h"
#if WASM_ENABLE_DEBUG_AOT != 0
#include "debug/dwarf_extractor.h"
#endif
static char *block_name_prefix[] = { "block", "loop", "if" }; static char *block_name_prefix[] = { "block", "loop", "if" };
static char *block_name_suffix[] = { "begin", "else", "end" }; static char *block_name_suffix[] = { "begin", "else", "end" };
@ -158,14 +162,22 @@ handle_next_reachable_block(AOTCompContext *comp_ctx,
uint8 *frame_ip = NULL; uint8 *frame_ip = NULL;
uint32 i; uint32 i;
AOTFuncType *func_type; AOTFuncType *func_type;
LLVMValueRef ret;
#if WASM_ENABLE_DEBUG_AOT != 0
LLVMMetadataRef return_location;
#endif
aot_checked_addr_list_destroy(func_ctx); aot_checked_addr_list_destroy(func_ctx);
bh_assert(block); bh_assert(block);
#if WASM_ENABLE_DEBUG_AOT != 0
return_location = dwarf_gen_location(
comp_ctx, func_ctx,
(*p_frame_ip - 1) - comp_ctx->comp_data->wasm_module->buf_code
);
#endif
if (block->label_type == LABEL_TYPE_IF if (block->label_type == LABEL_TYPE_IF
&& block->llvm_else_block && block->llvm_else_block
&& !block->skip_wasm_code_else
&& *p_frame_ip <= block->wasm_code_else) { && *p_frame_ip <= block->wasm_code_else) {
/* Clear value stack and start to translate else branch */ /* Clear value stack and start to translate else branch */
aot_value_stack_destroy(&block->value_stack); aot_value_stack_destroy(&block->value_stack);
@ -237,16 +249,23 @@ handle_next_reachable_block(AOTCompContext *comp_ctx,
if (block->label_type == LABEL_TYPE_FUNCTION) { if (block->label_type == LABEL_TYPE_FUNCTION) {
if (block->result_count) { if (block->result_count) {
/* Return the first return value */ /* Return the first return value */
if (!LLVMBuildRet(comp_ctx->builder, block->result_phis[0])) { if (!(ret =
LLVMBuildRet(comp_ctx->builder, block->result_phis[0]))) {
aot_set_last_error("llvm build return failed."); aot_set_last_error("llvm build return failed.");
goto fail; goto fail;
} }
#if WASM_ENABLE_DEBUG_AOT != 0
LLVMInstructionSetDebugLoc(ret, return_location);
#endif
} }
else { else {
if (!LLVMBuildRetVoid(comp_ctx->builder)) { if (!(ret = LLVMBuildRetVoid(comp_ctx->builder))) {
aot_set_last_error("llvm build return void failed."); aot_set_last_error("llvm build return void failed.");
goto fail; goto fail;
} }
#if WASM_ENABLE_DEBUG_AOT != 0
LLVMInstructionSetDebugLoc(ret, return_location);
#endif
} }
} }
aot_block_destroy(block); aot_block_destroy(block);
@ -381,7 +400,7 @@ aot_compile_op_block(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
memset(block_addr_cache, 0, sizeof(block_addr_cache)); memset(block_addr_cache, 0, sizeof(block_addr_cache));
/* Get block info */ /* Get block info */
if (!(wasm_loader_find_block_addr((BlockAddr*)block_addr_cache, if (!(wasm_loader_find_block_addr(NULL, (BlockAddr*)block_addr_cache,
*p_frame_ip, frame_ip_end, (uint8)label_type, *p_frame_ip, frame_ip_end, (uint8)label_type,
&else_addr, &end_addr))) { &else_addr, &end_addr))) {
aot_set_last_error("find block end addr failed."); aot_set_last_error("find block end addr failed.");
@ -709,7 +728,7 @@ check_suspend_flags(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
/* Move builder to terminate block */ /* Move builder to terminate block */
SET_BUILDER_POS(terminate_block); SET_BUILDER_POS(terminate_block);
if (!aot_build_zero_function_ret(comp_ctx, aot_func_type)) { if (!aot_build_zero_function_ret(comp_ctx, func_ctx, aot_func_type)) {
goto fail; goto fail;
} }
@ -1070,12 +1089,22 @@ aot_compile_op_return(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
{ {
AOTBlock *block_func = func_ctx->block_stack.block_list_head; AOTBlock *block_func = func_ctx->block_stack.block_list_head;
LLVMValueRef value; LLVMValueRef value;
LLVMValueRef ret;
AOTFuncType *func_type; AOTFuncType *func_type;
uint32 i, param_index, result_index; uint32 i, param_index, result_index;
#if WASM_ENABLE_DEBUG_AOT != 0
LLVMMetadataRef return_location;
#endif
bh_assert(block_func); bh_assert(block_func);
func_type = func_ctx->aot_func->func_type; func_type = func_ctx->aot_func->func_type;
#if WASM_ENABLE_DEBUG_AOT != 0
return_location = dwarf_gen_location(
comp_ctx, func_ctx,
(*p_frame_ip - 1) - comp_ctx->comp_data->wasm_module->buf_code
);
#endif
if (block_func->result_count) { if (block_func->result_count) {
/* Store extra result values to function parameters */ /* Store extra result values to function parameters */
for (i = 0; i < block_func->result_count - 1; i++) { for (i = 0; i < block_func->result_count - 1; i++) {
@ -1091,16 +1120,22 @@ aot_compile_op_return(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
} }
/* Return the first result value */ /* Return the first result value */
POP(value, block_func->result_types[0]); POP(value, block_func->result_types[0]);
if (!LLVMBuildRet(comp_ctx->builder, value)) { if (!(ret = LLVMBuildRet(comp_ctx->builder, value))) {
aot_set_last_error("llvm build return failed."); aot_set_last_error("llvm build return failed.");
goto fail; goto fail;
} }
#if WASM_ENABLE_DEBUG_AOT != 0
LLVMInstructionSetDebugLoc(ret, return_location);
#endif
} }
else { else {
if (!LLVMBuildRetVoid(comp_ctx->builder)) { if (!(ret = LLVMBuildRetVoid(comp_ctx->builder))) {
aot_set_last_error("llvm build return void failed."); aot_set_last_error("llvm build return void failed.");
goto fail; goto fail;
} }
#if WASM_ENABLE_DEBUG_AOT != 0
LLVMInstructionSetDebugLoc(ret, return_location);
#endif
} }
return handle_next_reachable_block(comp_ctx, func_ctx, p_frame_ip); return handle_next_reachable_block(comp_ctx, func_ctx, p_frame_ip);

View File

@ -109,7 +109,7 @@ aot_emit_exception(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
/* Create return IR */ /* Create return IR */
AOTFuncType *aot_func_type = func_ctx->aot_func->func_type; AOTFuncType *aot_func_type = func_ctx->aot_func->func_type;
if (!aot_build_zero_function_ret(comp_ctx, aot_func_type)) { if (!aot_build_zero_function_ret(comp_ctx, func_ctx, aot_func_type)) {
return false; return false;
} }

View File

@ -35,7 +35,7 @@ create_func_return_block(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
/* Create return IR */ /* Create return IR */
LLVMPositionBuilderAtEnd(comp_ctx->builder, func_ctx->func_return_block); LLVMPositionBuilderAtEnd(comp_ctx->builder, func_ctx->func_return_block);
if (!aot_build_zero_function_ret(comp_ctx, aot_func_type)) { if (!aot_build_zero_function_ret(comp_ctx, func_ctx, aot_func_type)) {
return false; return false;
} }
} }
@ -313,7 +313,7 @@ call_aot_alloc_frame_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
/* If frame alloc failed, return this function /* If frame alloc failed, return this function
so the runtime can catch the exception */ so the runtime can catch the exception */
LLVMPositionBuilderAtEnd(comp_ctx->builder, frame_alloc_fail); LLVMPositionBuilderAtEnd(comp_ctx->builder, frame_alloc_fail);
if (!aot_build_zero_function_ret(comp_ctx, aot_func_type)) { if (!aot_build_zero_function_ret(comp_ctx, func_ctx, aot_func_type)) {
return false; return false;
} }

View File

@ -897,7 +897,7 @@ aot_compile_op_memory_init(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
/* If memory.init failed, return this function /* If memory.init failed, return this function
so the runtime can catch the exception */ so the runtime can catch the exception */
LLVMPositionBuilderAtEnd(comp_ctx->builder, mem_init_fail); LLVMPositionBuilderAtEnd(comp_ctx->builder, mem_init_fail);
if (!aot_build_zero_function_ret(comp_ctx, aot_func_type)) { if (!aot_build_zero_function_ret(comp_ctx, func_ctx, aot_func_type)) {
goto fail; goto fail;
} }
@ -1231,7 +1231,7 @@ aot_compile_op_atomic_wait(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
/* If atomic wait failed, return this function /* If atomic wait failed, return this function
so the runtime can catch the exception */ so the runtime can catch the exception */
LLVMPositionBuilderAtEnd(comp_ctx->builder, wait_fail); LLVMPositionBuilderAtEnd(comp_ctx->builder, wait_fail);
if (!aot_build_zero_function_ret(comp_ctx, aot_func_type)) { if (!aot_build_zero_function_ret(comp_ctx, func_ctx, aot_func_type)) {
goto fail; goto fail;
} }

View File

@ -9,6 +9,10 @@
#include "../aot/aot_runtime.h" #include "../aot/aot_runtime.h"
#include "../aot/aot_intrinsic.h" #include "../aot/aot_intrinsic.h"
#if WASM_ENABLE_DEBUG_AOT != 0
#include "debug/dwarf_extractor.h"
#endif
LLVMTypeRef LLVMTypeRef
wasm_type_to_llvm_type(AOTLLVMTypes *llvm_types, uint8 wasm_type) wasm_type_to_llvm_type(AOTLLVMTypes *llvm_types, uint8 wasm_type)
{ {
@ -634,6 +638,10 @@ aot_create_func_context(AOTCompData *comp_data, AOTCompContext *comp_ctx,
func, aot_func_type))) func, aot_func_type)))
goto fail; goto fail;
#if WASM_ENABLE_DEBUG_AOT != 0
func_ctx->debug_func = dwarf_gen_func_info(comp_ctx, func_ctx);
#endif
aot_block_stack_push(&func_ctx->block_stack, aot_block); aot_block_stack_push(&func_ctx->block_stack, aot_block);
/* Add local variables */ /* Add local variables */
@ -1462,6 +1470,29 @@ aot_create_comp_context(AOTCompData *comp_data,
goto fail; goto fail;
} }
#if WASM_ENABLE_DEBUG_AOT != 0
if (!(comp_ctx->debug_builder = LLVMCreateDIBuilder(comp_ctx->module))) {
aot_set_last_error("create LLVM Debug Infor builder failed.");
goto fail;
}
LLVMAddModuleFlag(
comp_ctx->module, LLVMModuleFlagBehaviorWarning, "Debug Info Version",
strlen("Debug Info Version"),
LLVMValueAsMetadata(LLVMConstInt(LLVMInt32Type(), 3, false)));
comp_ctx->debug_file = dwarf_gen_file_info(comp_ctx);
if (!comp_ctx->debug_file) {
aot_set_last_error("dwarf generate file info failed");
goto fail;
}
comp_ctx->debug_comp_unit = dwarf_gen_comp_unit_info(comp_ctx);
if (!comp_ctx->debug_comp_unit) {
aot_set_last_error("dwarf generate compile unit info failed");
goto fail;
}
#endif
if (option->enable_bulk_memory) if (option->enable_bulk_memory)
comp_ctx->enable_bulk_memory = true; comp_ctx->enable_bulk_memory = true;
@ -2213,6 +2244,7 @@ aot_checked_addr_list_destroy(AOTFuncContext *func_ctx)
bool bool
aot_build_zero_function_ret(AOTCompContext *comp_ctx, aot_build_zero_function_ret(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
AOTFuncType *func_type) AOTFuncType *func_type)
{ {
LLVMValueRef ret = NULL; LLVMValueRef ret = NULL;
@ -2251,6 +2283,10 @@ aot_build_zero_function_ret(AOTCompContext *comp_ctx,
aot_set_last_error("llvm build ret failed."); aot_set_last_error("llvm build ret failed.");
return false; return false;
} }
#if WASM_ENABLE_DEBUG_AOT != 0
LLVMMetadataRef return_location = dwarf_gen_func_ret_location(comp_ctx, func_ctx);
LLVMInstructionSetDebugLoc(ret, return_location);
#endif
return true; return true;
} }

View File

@ -25,6 +25,9 @@
#include "llvm-c/Initialization.h" #include "llvm-c/Initialization.h"
#include "llvm-c/Support.h" #include "llvm-c/Support.h"
#endif #endif
#if WASM_ENABLE_DEBUG_AOT != 0
#include "llvm-c/DebugInfo.h"
#endif
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -148,6 +151,9 @@ typedef struct AOTFuncContext {
LLVMBasicBlockRef func_return_block; LLVMBasicBlockRef func_return_block;
LLVMValueRef exception_id_phi; LLVMValueRef exception_id_phi;
LLVMValueRef func_type_indexes; LLVMValueRef func_type_indexes;
#if WASM_ENABLE_DEBUG_AOT != 0
LLVMMetadataRef debug_func;
#endif
LLVMValueRef locals[1]; LLVMValueRef locals[1];
} AOTFuncContext; } AOTFuncContext;
@ -245,6 +251,11 @@ typedef struct AOTCompContext {
LLVMContextRef context; LLVMContextRef context;
LLVMModuleRef module; LLVMModuleRef module;
LLVMBuilderRef builder; LLVMBuilderRef builder;
#if WASM_ENABLE_DEBUG_AOT
LLVMDIBuilderRef debug_builder;
LLVMMetadataRef debug_file;
LLVMMetadataRef debug_comp_unit;
#endif
LLVMTargetMachineRef target_machine; LLVMTargetMachineRef target_machine;
char *target_cpu; char *target_cpu;
char target_arch[16]; char target_arch[16];
@ -407,6 +418,7 @@ aot_checked_addr_list_destroy(AOTFuncContext *func_ctx);
bool bool
aot_build_zero_function_ret(AOTCompContext *comp_ctx, aot_build_zero_function_ret(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
AOTFuncType *func_type); AOTFuncType *func_type);
LLVMValueRef LLVMValueRef

View File

@ -0,0 +1,530 @@
/*
* Copyright (C) 2021 Ant Group. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "lldb/API/SBBlock.h"
#include "lldb/API/SBCompileUnit.h"
#include "lldb/API/SBCommandReturnObject.h"
#include "lldb/API/SBCommandInterpreter.h"
#include "lldb/API/SBBreakpointLocation.h"
#include "lldb/API/SBDebugger.h"
#include "lldb/API//SBFunction.h"
#include "lldb/API//SBModule.h"
#include "lldb/API//SBProcess.h"
#include "lldb/API//SBStream.h"
#include "lldb/API//SBSymbol.h"
#include "lldb/API//SBTarget.h"
#include "lldb/API//SBThread.h"
#include "lldb/API/SBDeclaration.h"
#include "dwarf_extractor.h"
#include "../aot_llvm.h"
#include "bh_log.h"
#include "../../aot/aot_runtime.h"
#include "llvm/BinaryFormat/Dwarf.h"
using namespace lldb;
typedef struct dwar_extractor
{
SBDebugger debugger;
SBTarget target;
SBModule module;
} dwar_extractor;
#define TO_HANDLE(extractor) (dwar_extractor_handle_t)(extractor)
#define TO_EXTACTOR(handle) (dwar_extractor *)(handle)
static bool is_debugger_initialized;
dwar_extractor_handle_t
create_dwarf_extractor(AOTCompData *comp_data, char * file_name)
{
char *arch = NULL;
char *platform = NULL;
dwar_extractor * extractor = NULL;
//__attribute__((constructor)) may be better?
if (!is_debugger_initialized) {
SBError error = SBDebugger::InitializeWithErrorHandling();
if(error.Fail()) {
LOG_ERROR("Init Dwarf Debugger failed");
return TO_HANDLE(NULL);
}
is_debugger_initialized = true;
}
SBError error;
SBFileSpec exe_file_spec(file_name, true);
if (!(extractor = new dwar_extractor()) ) {
LOG_ERROR("Create Dwarf Extractor error: failed to allocate memory");
goto fail3;
}
extractor->debugger = SBDebugger::Create();
if (!extractor->debugger.IsValid()) {
LOG_ERROR("Create Dwarf Debugger failed");
goto fail2;
}
extractor->target = extractor->debugger.CreateTarget(
file_name, arch, platform, false, error);
if (!error.Success()) {
LOG_ERROR("Create Dwarf target failed:%s", error.GetCString());
goto fail1;
}
if (!extractor->target.IsValid()) {
LOG_ERROR("Create Dwarf target not valid");
goto fail1;
}
extractor->module = extractor->target.FindModule(exe_file_spec);
comp_data->extractor = TO_HANDLE(extractor);
return TO_HANDLE(extractor);
fail1:
SBDebugger::Destroy(extractor->debugger);
fail2:
wasm_runtime_free(extractor);
fail3:
return TO_HANDLE(NULL);
}
void
destroy_dwarf_extractor(dwar_extractor_handle_t handle)
{
dwar_extractor * extractor = TO_EXTACTOR(handle);
if (!extractor)
return;
extractor->debugger.DeleteTarget(extractor->target);
SBDebugger::Destroy(extractor->debugger);
delete extractor;
SBDebugger::Terminate();
is_debugger_initialized = false;
}
LLVMMetadataRef
dwarf_gen_file_info(AOTCompContext *comp_ctx)
{
dwar_extractor *extractor;
int units_number;
LLVMMetadataRef file_info = NULL;
const char *file_name;
const char *dir_name;
if (!(extractor = TO_EXTACTOR(comp_ctx->comp_data->extractor)))
return NULL;
units_number = extractor->module.GetNumCompileUnits();
if (units_number > 0) {
SBCompileUnit compile_unit =
extractor->module.GetCompileUnitAtIndex(0);
auto filespec = compile_unit.GetFileSpec();
file_name = filespec.GetFilename();
dir_name = filespec.GetDirectory();
if (file_name || dir_name) {
file_info = LLVMDIBuilderCreateFile(comp_ctx->debug_builder,
file_name, strlen(file_name),
dir_name, strlen(dir_name));
}
}
return file_info;
}
#if 0
void
dwarf_gen_mock_vm_info(AOTCompContext *comp_ctx)
{
LLVMMetadataRef file_info = NULL;
LLVMMetadataRef comp_unit = NULL;
file_info = LLVMDIBuilderCreateFile(comp_ctx->debug_builder,
"ant_runtime_mock.c", 18, ".", 1);
comp_unit = LLVMDIBuilderCreateCompileUnit(
comp_ctx->debug_builder, LLVMDWARFSourceLanguageC, file_info,
"ant compiler", 12, 0, NULL, 0, 1, NULL, 0, LLVMDWARFEmissionFull, 0, 0,
0, "/", 1, "", 0);
LLVMTypeRef ParamTys[] = {
LLVMVoidType(),
};
LLVMTypeRef FuncTy = LLVMFunctionType(LLVMVoidType(), ParamTys, 0, 0);
LLVMValueRef Function =
LLVMAddFunction(comp_ctx->module, "ant_runtime_mock", FuncTy);
LLVMMetadataRef ParamTypes[0];
LLVMMetadataRef FunctionTy = LLVMDIBuilderCreateSubroutineType(
comp_ctx->debug_builder, file_info, ParamTypes, 0, LLVMDIFlagZero);
/* 0x0015 is subroutine_type */
LLVMMetadataRef ReplaceableFunctionMetadata =
LLVMDIBuilderCreateReplaceableCompositeType(
comp_ctx->debug_builder, 0x15, "ant_runtime_mock", 16, file_info,
file_info, 2, 0, 0, 0, LLVMDIFlagFwdDecl, "", 0);
LLVMMetadataRef FunctionMetadata = LLVMDIBuilderCreateFunction(
comp_ctx->debug_builder, file_info, "ant_runtime_mock", 16,
"ant_runtime_mock", 16, file_info, 2, FunctionTy, true, true, 2, LLVMDIFlagZero,
false);
LLVMMetadataReplaceAllUsesWith(ReplaceableFunctionMetadata,
FunctionMetadata);
LLVMSetSubprogram(Function, FunctionMetadata);
comp_ctx->vm_debug_comp_unit = comp_unit;
comp_ctx->vm_debug_file = file_info;
comp_ctx->vm_debug_func = FunctionMetadata;
}
#endif
LLVMMetadataRef
dwarf_gen_comp_unit_info(AOTCompContext *comp_ctx)
{
dwar_extractor *extractor;
int units_number;
LLVMMetadataRef comp_unit = NULL;
if (!(extractor = TO_EXTACTOR(comp_ctx->comp_data->extractor)))
return NULL;
units_number = extractor->module.GetNumCompileUnits();
if (units_number > 0) {
SBCompileUnit compile_unit =
extractor->module.GetCompileUnitAtIndex(0);
auto lang_type = compile_unit.GetLanguage();
comp_unit = LLVMDIBuilderCreateCompileUnit(
comp_ctx->debug_builder, LLDB_TO_LLVM_LANG_TYPE(lang_type),
comp_ctx->debug_file, "ant compiler", 12, 0, NULL, 0, 1, NULL, 0,
LLVMDWARFEmissionFull, 0, 0, 0, "/", 1, "", 0);
}
return comp_unit;
}
bool
dwarf_get_func_info(dwar_extractor_handle_t handle, uint64_t offset)
{
dwar_extractor *extractor = TO_EXTACTOR(handle);
auto sbaddr = extractor->target.ResolveFileAddress(offset);
SBSymbolContext sc(
sbaddr.GetSymbolContext(eSymbolContextFunction));
if (sc.IsValid()) {
SBFunction function(sc.GetFunction());
if (function.IsValid()) {
}
}
}
static LLVMDWARFTypeEncoding
lldb_get_basic_type_encoding(BasicType basic_type)
{
LLVMDWARFTypeEncoding encoding = 0;
switch (basic_type)
{
case eBasicTypeUnsignedChar:
encoding = llvm::dwarf::DW_ATE_unsigned_char;
break;
case eBasicTypeSignedChar:
encoding = llvm::dwarf::DW_ATE_signed_char;
break;
case eBasicTypeUnsignedInt:
case eBasicTypeUnsignedLong:
case eBasicTypeUnsignedLongLong:
case eBasicTypeUnsignedWChar:
case eBasicTypeUnsignedInt128:
case eBasicTypeUnsignedShort:
encoding = llvm::dwarf::DW_ATE_unsigned;
break;
case eBasicTypeInt:
case eBasicTypeLong:
case eBasicTypeLongLong:
case eBasicTypeWChar:
case eBasicTypeInt128:
case eBasicTypeShort:
encoding = llvm::dwarf::DW_ATE_signed;
break;
case eBasicTypeBool:
encoding = llvm::dwarf::DW_ATE_boolean;
break;
case eBasicTypeHalf:
case eBasicTypeFloat:
case eBasicTypeDouble:
case eBasicTypeLongDouble:
encoding = llvm::dwarf::DW_ATE_float;
break;
default:
break;
}
return encoding;
}
static LLVMMetadataRef
lldb_type_to_type_dbi(AOTCompContext *comp_ctx, SBType &type)
{
LLVMMetadataRef type_info = NULL;
BasicType basic_type = type.GetBasicType();
uint64_t bit_size = type.GetByteSize() * 8;
LLVMDIBuilderRef DIB = comp_ctx->debug_builder;
LLVMDWARFTypeEncoding encoding;
if (basic_type != eBasicTypeInvalid) {
encoding = lldb_get_basic_type_encoding(basic_type);
type_info = LLVMDIBuilderCreateBasicType(
DIB, type.GetName(), strlen(type.GetName()), bit_size, encoding,
LLVMDIFlagZero);
}
else if (type.IsPointerType()) {
SBType pointee_type = type.GetPointeeType();
type_info = LLVMDIBuilderCreatePointerType(
DIB, lldb_type_to_type_dbi(comp_ctx, pointee_type), bit_size, 0, 0,
"", 0);
}
return type_info;
}
static LLVMMetadataRef
lldb_function_to_function_dbi(AOTCompContext *comp_ctx, SBSymbolContext &sc, AOTFuncContext *func_ctx)
{
SBFunction function(sc.GetFunction());
const char *function_name = function.GetName();
const char *link_name = function.GetName();
SBTypeList function_args = function.GetType().GetFunctionArgumentTypes();
SBType return_type = function.GetType().GetFunctionReturnType();
const size_t num_function_args = function_args.GetSize();
dwar_extractor *extractor;
if (!(extractor = TO_EXTACTOR(comp_ctx->comp_data->extractor)))
return NULL;
LLVMDIBuilderRef DIB = comp_ctx->debug_builder;
LLVMMetadataRef File = comp_ctx->debug_file;
LLVMMetadataRef ParamTypes[num_function_args + 1];
ParamTypes[0] = lldb_type_to_type_dbi(comp_ctx, return_type);
for (uint32_t function_arg_idx = 0; function_arg_idx < num_function_args;
++function_arg_idx) {
SBType function_arg_type =
function_args.GetTypeAtIndex(function_arg_idx);
if (function_arg_type.IsValid()) {
ParamTypes[function_arg_idx + 1] = lldb_type_to_type_dbi(comp_ctx, function_arg_type);
}
}
LLVMMetadataRef FunctionTy =
LLVMDIBuilderCreateSubroutineType(DIB, File, ParamTypes, num_function_args + 1, LLVMDIFlagZero);
auto line_entry = sc.GetLineEntry();
LLVMMetadataRef ReplaceableFunctionMetadata =
LLVMDIBuilderCreateReplaceableCompositeType(
DIB, 0x15, function_name, strlen(function_name), File, File,
line_entry.GetLine(), 0, 0, 0, LLVMDIFlagFwdDecl, "", 0);
LLVMMetadataRef FunctionMetadata =
LLVMDIBuilderCreateFunction(DIB, File, function_name, strlen(function_name), link_name, strlen(link_name),
File, line_entry.GetLine(), FunctionTy, true, true, line_entry.GetLine(), LLVMDIFlagZero, false);
LLVMMetadataReplaceAllUsesWith(ReplaceableFunctionMetadata, FunctionMetadata);
LLVMSetSubprogram(func_ctx->func, FunctionMetadata);
LLVMMetadataRef ParamExpression = LLVMDIBuilderCreateExpression(DIB, NULL, 0);
auto variable_list = function.GetBlock().GetVariables(extractor->target, true, false,false);
if (num_function_args != variable_list.GetSize())
{
LOG_ERROR("function args number dismatch!:value number=%d, function args=%d", variable_list.GetSize(), num_function_args);
}
LLVMMetadataRef ParamLocation = LLVMDIBuilderCreateDebugLocation(
comp_ctx->context, line_entry.GetLine(), 0, FunctionMetadata, NULL);
//TODO:change to void * or WasmExenv *
LLVMMetadataRef voidtype = LLVMDIBuilderCreateBasicType(DIB, "void", 4, 0, 0, LLVMDIFlagZero);
LLVMMetadataRef voidpionter = LLVMDIBuilderCreatePointerType(DIB, voidtype, 64, 0, 0, "void *", 6);
LLVMMetadataRef ParamVar = LLVMDIBuilderCreateParameterVariable(
DIB, FunctionMetadata, "exenv",
5, 1,
File, //starts form 1, and 1 is exenv,
line_entry.GetLine(), voidpionter, true,
LLVMDIFlagZero);
LLVMValueRef Param =
LLVMGetParam(func_ctx->func, 0);
LLVMBasicBlockRef block_curr =
LLVMGetEntryBasicBlock(func_ctx->func);
LLVMDIBuilderInsertDbgValueAtEnd(DIB, Param, ParamVar,
ParamExpression, ParamLocation,
block_curr);
for (uint32_t function_arg_idx = 0; function_arg_idx < variable_list.GetSize();
++function_arg_idx) {
SBValue variable(variable_list.GetValueAtIndex(function_arg_idx));
if (variable.IsValid()) {
SBDeclaration dec(variable.GetDeclaration());
auto valtype = variable.GetType();
LLVMMetadataRef ParamLocation = LLVMDIBuilderCreateDebugLocation(
comp_ctx->context, dec.GetLine(), dec.GetColumn(),
FunctionMetadata, NULL);
LLVMMetadataRef ParamVar = LLVMDIBuilderCreateParameterVariable(
DIB, FunctionMetadata, variable.GetName(),
strlen(variable.GetName()), function_arg_idx + 1 + 1,
File, //starts form 1, and 1 is exenv,
dec.GetLine(), ParamTypes[function_arg_idx + 1], true,
LLVMDIFlagZero);
LLVMValueRef Param =
LLVMGetParam(func_ctx->func, function_arg_idx + 1);
LLVMDIBuilderInsertDbgValueAtEnd(DIB, Param, ParamVar,
ParamExpression, ParamLocation,
block_curr);
}
}
return FunctionMetadata;
}
LLVMMetadataRef
dwarf_gen_func_info(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
{
LLVMMetadataRef func_info = NULL;
dwar_extractor *extractor;
uint64_t vm_offset;
AOTFunc *func = func_ctx->aot_func;
if (!(extractor = TO_EXTACTOR(comp_ctx->comp_data->extractor)))
return NULL;
// A code address in DWARF for WebAssembly is the offset of an
// instruction relative within the Code section of the WebAssembly file.
// For this reason Section::GetFileAddress() must return zero for the
// Code section. (refert to ObjectFileWasm.cpp)
vm_offset = func->code - comp_ctx->comp_data->wasm_module->buf_code;
auto sbaddr = extractor->target.ResolveFileAddress(vm_offset);
SBSymbolContext sc(
sbaddr.GetSymbolContext(eSymbolContextFunction | eSymbolContextLineEntry));
if (sc.IsValid()) {
SBFunction function(sc.GetFunction());
if (function.IsValid()) {
func_info = lldb_function_to_function_dbi(comp_ctx, sc, func_ctx);
}
}
return func_info;
}
void
dwarf_get_func_name(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
char *name,
int len)
{
LLVMMetadataRef func_info = NULL;
dwar_extractor *extractor;
uint64_t vm_offset;
AOTFunc *func = func_ctx->aot_func;
name[0] = '\0';
if (!(extractor = TO_EXTACTOR(comp_ctx->comp_data->extractor)))
return ;
// A code address in DWARF for WebAssembly is the offset of an
// instruction relative within the Code section of the WebAssembly file.
// For this reason Section::GetFileAddress() must return zero for the
// Code section. (refert to ObjectFileWasm.cpp)
vm_offset = func->code - comp_ctx->comp_data->wasm_module->buf_code;
auto sbaddr = extractor->target.ResolveFileAddress(vm_offset);
SBSymbolContext sc(sbaddr.GetSymbolContext(eSymbolContextFunction
| eSymbolContextLineEntry));
if (sc.IsValid()) {
SBFunction function(sc.GetFunction());
if (function.IsValid()) {
bh_strcpy_s(name, len, function.GetName());
}
}
}
LLVMMetadataRef
dwarf_gen_location(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint64_t vm_offset)
{
LLVMMetadataRef location_info = NULL;
dwar_extractor *extractor;
AOTFunc *func = func_ctx->aot_func;
if (!(extractor = TO_EXTACTOR(comp_ctx->comp_data->extractor)))
return NULL;
auto sbaddr = extractor->target.ResolveFileAddress(vm_offset);
SBSymbolContext sc(sbaddr.GetSymbolContext(eSymbolContextFunction
| eSymbolContextLineEntry));
if (sc.IsValid()) {
//TODO:need to check if the vm_offset is belong to
SBFunction function(sc.GetFunction());
if (function.IsValid()) {
uint64_t start = func_ctx->aot_func->code
- comp_ctx->comp_data->wasm_module->buf_code;
uint64_t end = func_ctx->aot_func->code
- comp_ctx->comp_data->wasm_module->buf_code
+ func_ctx->aot_func->code_size;
if (function.GetStartAddress().GetOffset() <= start
&& end <= function.GetEndAddress().GetOffset()) {
auto line_entry = sc.GetLineEntry();
location_info =
LLVMDIBuilderCreateDebugLocation(
comp_ctx->context, line_entry.GetLine(),
line_entry.GetColumn(), func_ctx->debug_func, NULL);
//LOG_VERBOSE("Gen the location l:%d, c:%d at %lx", line_entry.GetLine(), line_entry.GetColumn(), vm_offset);
} else
LOG_WARNING("the offset and function is not matched");
}
}
return location_info;
}
LLVMMetadataRef
dwarf_gen_func_ret_location(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
{
LLVMMetadataRef func_info = NULL;
dwar_extractor *extractor;
uint64_t vm_offset;
AOTFunc *func = func_ctx->aot_func;
LLVMMetadataRef location_info = NULL;
if (!(extractor = TO_EXTACTOR(comp_ctx->comp_data->extractor)))
return NULL;
// A code address in DWARF for WebAssembly is the offset of an
// instruction relative within the Code section of the WebAssembly file.
// For this reason Section::GetFileAddress() must return zero for the
// Code section. (refert to ObjectFileWasm.cpp)
vm_offset = (func->code + func->code_size -1) - comp_ctx->comp_data->wasm_module->buf_code;
location_info = dwarf_gen_location(comp_ctx, func_ctx, vm_offset);
return location_info;
}

View File

@ -0,0 +1,58 @@
/*
* Copyright (C) 2021 Ant Group. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#ifndef _DWARF_EXTRACTOR_H_
#define _DWARF_EXTRACTOR_H_
#include "llvm-c/DebugInfo.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef unsigned int LLDBLangType;
#define LLDB_TO_LLVM_LANG_TYPE(lldb_lang_type) \
(LLVMDWARFSourceLanguage)(((lldb_lang_type) > 0 ? (lldb_lang_type)-1 : 1))
struct AOTCompData;
typedef struct AOTCompData *aot_comp_data_t;
typedef void *dwar_extractor_handle_t;
struct AOTCompContext;
typedef struct AOTCompContext AOTCompContext;
struct AOTFuncContext;
typedef struct AOTFuncContext AOTFuncContext;
dwar_extractor_handle_t
create_dwarf_extractor(aot_comp_data_t comp_data, char *file_name);
LLVMMetadataRef
dwarf_gen_file_info(AOTCompContext *comp_ctx);
LLVMMetadataRef
dwarf_gen_comp_unit_info(AOTCompContext *comp_ctx);
LLVMMetadataRef
dwarf_gen_func_info(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx);
LLVMMetadataRef
dwarf_gen_location(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
uint64_t vm_offset);
LLVMMetadataRef
dwarf_gen_func_ret_location(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx);
void
dwarf_get_func_name(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
char *name,
int len);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -2,9 +2,17 @@ set (IWASM_COMPL_DIR ${CMAKE_CURRENT_LIST_DIR})
include_directories(${IWASM_COMPL_DIR}) include_directories(${IWASM_COMPL_DIR})
file (GLOB_RECURSE source_all if (WAMR_BUILD_DEBUG_AOT EQUAL 1)
${IWASM_COMPL_DIR}/*.c file (GLOB_RECURSE source_all
${IWASM_COMPL_DIR}/*.cpp) ${IWASM_COMPL_DIR}/*.c
${IWASM_COMPL_DIR}/*.cpp)
else()
file (GLOB source_all
${IWASM_COMPL_DIR}/simd/*.c
${IWASM_COMPL_DIR}/simd/*.cpp
${IWASM_COMPL_DIR}/*.c
${IWASM_COMPL_DIR}/*.cpp)
endif()
set (IWASM_COMPL_SOURCE ${source_all}) set (IWASM_COMPL_SOURCE ${source_all})

View File

@ -26,6 +26,12 @@ aot_create_comp_data(void *wasm_module);
void void
aot_destroy_comp_data(aot_comp_data_t comp_data); aot_destroy_comp_data(aot_comp_data_t comp_data);
#if WASM_ENABLE_DEBUG_AOT != 0
typedef void * dwar_extractor_handle_t;
dwar_extractor_handle_t
create_dwarf_extractor(aot_comp_data_t comp_data, char * file_name);
#endif
enum { enum {
AOT_FORMAT_FILE, AOT_FORMAT_FILE,
AOT_OBJECT_FILE, AOT_OBJECT_FILE,

View File

@ -133,6 +133,11 @@ typedef struct RuntimeInitArgs {
/* maximum thread number, only used when /* maximum thread number, only used when
WASM_ENABLE_THREAD_MGR is defined */ WASM_ENABLE_THREAD_MGR is defined */
uint32_t max_thread_num; uint32_t max_thread_num;
#if WASM_ENABLE_DEBUG_INTERP != 0
char ip_addr[128];
int platform_port;
int instance_port;
#endif
} RuntimeInitArgs; } RuntimeInitArgs;
#ifndef WASM_VALKIND_T_DEFINED #ifndef WASM_VALKIND_T_DEFINED

View File

@ -316,6 +316,13 @@ typedef struct StringNode {
char *str; char *str;
} StringNode, *StringList; } StringNode, *StringList;
#if WASM_ENABLE_DEBUG_INTERP != 0
typedef struct WASMFastOPCodeNode {
struct WASMFastOPCodeNode *next;
uint64 offset;
uint8 orig_op;
} WASMFastOPCodeNode;
#endif
struct WASMModule { struct WASMModule {
/* Module type, for module loaded from WASM bytecode binary, /* Module type, for module loaded from WASM bytecode binary,
this field is Wasm_Module_Bytecode; this field is Wasm_Module_Bytecode;
@ -404,6 +411,13 @@ struct WASMModule {
bh_list import_module_list_head; bh_list import_module_list_head;
bh_list *import_module_list; bh_list *import_module_list;
#endif #endif
#if WASM_ENABLE_DEBUG_INTERP != 0 || WASM_ENABLE_DEBUG_AOT != 0
bh_list fast_opcode_list;
uint8 *buf_code;
uint8 *load_addr;
uint64 load_size;
uint64 buf_code_size;
#endif
}; };
typedef struct BlockType { typedef struct BlockType {

View File

@ -12,6 +12,9 @@
#if WASM_ENABLE_SHARED_MEMORY != 0 #if WASM_ENABLE_SHARED_MEMORY != 0
#include "../common/wasm_shared_memory.h" #include "../common/wasm_shared_memory.h"
#endif #endif
#if WASM_ENABLE_THREAD_MGR != 0 && WASM_ENABLE_DEBUG_INTERP != 0
#include "../libraries/thread-mgr/thread_manager.h"
#endif
typedef int32 CellType_I32; typedef int32 CellType_I32;
typedef int64 CellType_I64; typedef int64 CellType_I64;
@ -848,27 +851,70 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst,
#endif #endif
#if WASM_ENABLE_THREAD_MGR != 0 #if WASM_ENABLE_THREAD_MGR != 0
#if WASM_ENABLE_DEBUG_INTERP != 0
#define CHECK_SUSPEND_FLAGS() do { \
if (IS_WAMR_TERM_SIG(exec_env->current_status->signal_flag)) { \
return; \
} \
if (IS_WAMR_STOP_SIG(exec_env->current_status->signal_flag)) { \
SYNC_ALL_TO_FRAME(); \
wasm_cluster_thread_stopped(exec_env); \
wasm_cluster_thread_waiting_run(exec_env); \
} \
} while (0)
#else
#define CHECK_SUSPEND_FLAGS() do { \ #define CHECK_SUSPEND_FLAGS() do { \
if (exec_env->suspend_flags.flags != 0) { \ if (exec_env->suspend_flags.flags != 0) { \
if (exec_env->suspend_flags.flags & 0x01) { \ if (exec_env->suspend_flags.flags & 0x01) { \
/* terminate current thread */ \ /* terminate current thread */ \
return; \ return; \
} \ } \
/* TODO: support suspend and breakpoint */ \ while (exec_env->suspend_flags.flags & 0x02){ \
/* suspend current thread */ \
os_cond_wait(&exec_env->wait_cond, \
&exec_env->wait_lock); \
} \
} \ } \
} while (0) } while (0)
#endif #endif
#endif
#if WASM_ENABLE_LABELS_AS_VALUES != 0 #if WASM_ENABLE_LABELS_AS_VALUES != 0
#define HANDLE_OP(opcode) HANDLE_##opcode #define HANDLE_OP(opcode) HANDLE_##opcode
#define FETCH_OPCODE_AND_DISPATCH() goto *handle_table[*frame_ip++] #define FETCH_OPCODE_AND_DISPATCH() goto *handle_table[*frame_ip++]
#if WASM_ENABLE_THREAD_MGR != 0 && WASM_ENABLE_DEBUG_INTERP != 0
#define HANDLE_OP_END() \
do { \
while (exec_env->current_status->signal_flag == WAMR_SIG_SINGSTEP \
&& exec_env->current_status->step_count++ == 1) { \
exec_env->current_status->step_count = 0; \
SYNC_ALL_TO_FRAME(); \
wasm_cluster_thread_stopped(exec_env); \
wasm_cluster_thread_waiting_run(exec_env); \
} \
goto *handle_table[*frame_ip++]; \
} while (0)
#else
#define HANDLE_OP_END() FETCH_OPCODE_AND_DISPATCH() #define HANDLE_OP_END() FETCH_OPCODE_AND_DISPATCH()
#endif
#else /* else of WASM_ENABLE_LABELS_AS_VALUES */ #else /* else of WASM_ENABLE_LABELS_AS_VALUES */
#define HANDLE_OP(opcode) case opcode #define HANDLE_OP(opcode) case opcode
#if WASM_ENABLE_THREAD_MGR != 0 && WASM_ENABLE_DEBUG_INTERP != 0
#define HANDLE_OP_END() \
if (exec_env->current_status->signal_flag == WAMR_SIG_SINGSTEP \
&& exec_env->current_status->step_count++ == 2) { \
exec_env->current_status->step_count = 0; \
SYNC_ALL_TO_FRAME(); \
wasm_cluster_thread_stopped(exec_env); \
wasm_cluster_thread_waiting_run(exec_env); \
} \
continue
#else
#define HANDLE_OP_END() continue #define HANDLE_OP_END() continue
#endif
#endif /* end of WASM_ENABLE_LABELS_AS_VALUES */ #endif /* end of WASM_ENABLE_LABELS_AS_VALUES */
@ -941,6 +987,16 @@ handle_op_block:
else if (cache_items[1].start_addr == frame_ip) { else if (cache_items[1].start_addr == frame_ip) {
end_addr = cache_items[1].end_addr; end_addr = cache_items[1].end_addr;
} }
#if WASM_ENABLE_DEBUG_INTERP != 0
else if (!wasm_loader_find_block_addr(exec_env,
(BlockAddr*)exec_env->block_addr_cache,
frame_ip, (uint8*)-1,
LABEL_TYPE_BLOCK,
&else_addr, &end_addr)) {
wasm_set_exception(module, "find block address failed");
goto got_exception;
}
#endif
else { else {
end_addr = NULL; end_addr = NULL;
} }
@ -978,7 +1034,8 @@ handle_op_if:
else_addr = cache_items[1].else_addr; else_addr = cache_items[1].else_addr;
end_addr = cache_items[1].end_addr; end_addr = cache_items[1].end_addr;
} }
else if (!wasm_loader_find_block_addr((BlockAddr*)exec_env->block_addr_cache, else if (!wasm_loader_find_block_addr(exec_env,
(BlockAddr*)exec_env->block_addr_cache,
frame_ip, (uint8*)-1, frame_ip, (uint8*)-1,
LABEL_TYPE_IF, LABEL_TYPE_IF,
&else_addr, &end_addr)) { &else_addr, &end_addr)) {
@ -1030,7 +1087,8 @@ handle_op_if:
label_pop_csp_n: label_pop_csp_n:
POP_CSP_N(depth); POP_CSP_N(depth);
if (!frame_ip) { /* must be label pushed by WASM_OP_BLOCK */ if (!frame_ip) { /* must be label pushed by WASM_OP_BLOCK */
if (!wasm_loader_find_block_addr((BlockAddr*)exec_env->block_addr_cache, if (!wasm_loader_find_block_addr(exec_env,
(BlockAddr*)exec_env->block_addr_cache,
(frame_csp - 1)->begin_addr, (uint8*)-1, (frame_csp - 1)->begin_addr, (uint8*)-1,
LABEL_TYPE_BLOCK, LABEL_TYPE_BLOCK,
&else_addr, &end_addr)) { &else_addr, &end_addr)) {
@ -3178,7 +3236,17 @@ label_pop_csp_n:
frame_sp = frame->sp; frame_sp = frame->sp;
frame_csp = frame->csp; frame_csp = frame->csp;
goto call_func_from_entry; goto call_func_from_entry;
#if WASM_ENABLE_DEBUG_INTERP != 0
HANDLE_OP (DEBUG_OP_BREAK):
{
wasm_cluster_thread_send_signal(exec_env, WAMR_SIG_TRAP);
exec_env->suspend_flags.flags |= 2;
frame_ip--;
SYNC_ALL_TO_FRAME();
CHECK_SUSPEND_FLAGS();
HANDLE_OP_END ();
}
#endif
#if WASM_ENABLE_LABELS_AS_VALUES == 0 #if WASM_ENABLE_LABELS_AS_VALUES == 0
default: default:
wasm_set_exception(module, "unsupported opcode"); wasm_set_exception(module, "unsupported opcode");
@ -3320,6 +3388,9 @@ label_pop_csp_n:
PUSH_CSP(LABEL_TYPE_FUNCTION, cell_num, frame_ip_end - 1); PUSH_CSP(LABEL_TYPE_FUNCTION, cell_num, frame_ip_end - 1);
wasm_exec_env_set_cur_frame(exec_env, (WASMRuntimeFrame*)frame); wasm_exec_env_set_cur_frame(exec_env, (WASMRuntimeFrame*)frame);
#if WASM_ENABLE_THREAD_MGR != 0
CHECK_SUSPEND_FLAGS();
#endif
} }
HANDLE_OP_END (); HANDLE_OP_END ();
} }

View File

@ -10,6 +10,9 @@
#include "wasm_opcode.h" #include "wasm_opcode.h"
#include "wasm_runtime.h" #include "wasm_runtime.h"
#include "../common/wasm_native.h" #include "../common/wasm_native.h"
#if WASM_ENABLE_DEBUG_INTERP != 0
#include "../libraries/debug-engine/debug_engine.h"
#endif
/* Read a value of given type from the address pointed to by the given /* Read a value of given type from the address pointed to by the given
pointer and increase the pointer to the position just after the pointer and increase the pointer to the position just after the
@ -2934,6 +2937,10 @@ load_from_sections(WASMModule *module, WASMSection *sections,
if (section->section_type == SECTION_TYPE_CODE) { if (section->section_type == SECTION_TYPE_CODE) {
buf_code = section->section_body; buf_code = section->section_body;
buf_code_end = buf_code + section->section_body_size; buf_code_end = buf_code + section->section_body_size;
#if WASM_ENABLE_DEBUG_INTERP != 0 || WASM_ENABLE_DEBUG_AOT != 0
module->buf_code = (uint8 *)buf_code;
module->buf_code_size = section->section_body_size;
#endif
} }
else if (section->section_type == SECTION_TYPE_FUNC) { else if (section->section_type == SECTION_TYPE_FUNC) {
buf_func = section->section_body; buf_func = section->section_body;
@ -3296,10 +3303,26 @@ create_module(char *error_buf, uint32 error_buf_size)
#if WASM_ENABLE_MULTI_MODULE != 0 #if WASM_ENABLE_MULTI_MODULE != 0
module->import_module_list = &module->import_module_list_head; module->import_module_list = &module->import_module_list_head;
#endif
#if WASM_ENABLE_DEBUG_INTERP != 0
bh_list_init(&module->fast_opcode_list);
#endif #endif
return module; return module;
} }
#if WASM_ENABLE_DEBUG_INTERP != 0
static void
record_fast_op(WASMModule *module, uint8 * pos, uint8 orig_op)
{
WASMFastOPCodeNode *fast_op = wasm_runtime_malloc(sizeof(WASMFastOPCodeNode));
if (fast_op) {
fast_op->offset = pos - module->load_addr;
fast_op->orig_op = orig_op;
bh_list_insert(&module->fast_opcode_list, fast_op);
}
}
#endif
WASMModule * WASMModule *
wasm_loader_load_from_sections(WASMSection *section_list, wasm_loader_load_from_sections(WASMSection *section_list,
char *error_buf, uint32 error_buf_size) char *error_buf, uint32 error_buf_size)
@ -3493,6 +3516,11 @@ wasm_loader_load(const uint8 *buf, uint32 size, char *error_buf, uint32 error_bu
return NULL; return NULL;
} }
#if WASM_ENABLE_DEBUG_INTERP != 0
module->load_addr = (uint8 *)buf;
module->load_size = size;
#endif
if (!load(buf, size, module, error_buf, error_buf_size)) { if (!load(buf, size, module, error_buf, error_buf_size)) {
goto fail; goto fail;
} }
@ -3593,7 +3621,6 @@ wasm_loader_unload(WASMModule *module)
*/ */
wasm_runtime_free(node); wasm_runtime_free(node);
/* /*
*
* the module file reading buffer will be released * the module file reading buffer will be released
* in runtime_destroy() * in runtime_destroy()
*/ */
@ -3601,12 +3628,21 @@ wasm_loader_unload(WASMModule *module)
} }
} }
#endif #endif
#if WASM_ENABLE_DEBUG_INTERP != 0
WASMFastOPCodeNode *fast_opcode =
bh_list_first_elem(&module->fast_opcode_list);
while(fast_opcode) {
WASMFastOPCodeNode * next = bh_list_elem_next(fast_opcode);
wasm_runtime_free(fast_opcode);
fast_opcode = next;
}
#endif
wasm_runtime_free(module); wasm_runtime_free(module);
} }
bool 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 *start_addr,
const uint8 *code_end_addr, const uint8 *code_end_addr,
uint8 label_type, uint8 label_type,
@ -3638,7 +3674,9 @@ wasm_loader_find_block_addr(BlockAddr *block_addr_cache,
while (p < code_end_addr) { while (p < code_end_addr) {
opcode = *p++; opcode = *p++;
#if WASM_ENABLE_DEBUG_INTERP != 0
op_break_retry:
#endif
switch (opcode) { switch (opcode) {
case WASM_OP_UNREACHABLE: case WASM_OP_UNREACHABLE:
case WASM_OP_NOP: case WASM_OP_NOP:
@ -4156,6 +4194,31 @@ wasm_loader_find_block_addr(BlockAddr *block_addr_cache,
break; break;
} }
#endif #endif
#if WASM_ENABLE_DEBUG_INTERP != 0
case DEBUG_OP_BREAK: {
WASMDebugInstance *debug_instance =
wasm_exec_env_get_instance(exec_env);
char orignal_opcode[1];
uint64 size = 1;
WASMModuleInstance *module_inst =
(WASMModuleInstance *)exec_env->module_inst;
uint64 offset = (p - 1) >= module_inst->module->load_addr
? (p - 1) - module_inst->module->load_addr
: ~0;
if (debug_instance) {
if (wasm_debug_instance_get_obj_mem(
debug_instance, offset, orignal_opcode, &size)
&& size == 1) {
LOG_VERBOSE("WASM loader find OP_BREAK , recover it "
"with %02x: ",
orignal_opcode[0]);
opcode = orignal_opcode[0];
goto op_break_retry;
}
}
break;
}
#endif
default: default:
return false; return false;
@ -6317,6 +6380,9 @@ handle_op_block_and_loop:
* to new extended opcode so that interpreter can resolve the * to new extended opcode so that interpreter can resolve the
* block quickly. * block quickly.
*/ */
#if WASM_ENABLE_DEBUG_INTERP != 0
record_fast_op(module, p - 2, *(p - 2));
#endif
*(p - 2) = EXT_OP_BLOCK + (opcode - WASM_OP_BLOCK); *(p - 2) = EXT_OP_BLOCK + (opcode - WASM_OP_BLOCK);
#endif #endif
} }
@ -7196,13 +7262,28 @@ handle_op_block_and_loop:
#else #else
#if (WASM_ENABLE_WAMR_COMPILER == 0) && (WASM_ENABLE_JIT == 0) #if (WASM_ENABLE_WAMR_COMPILER == 0) && (WASM_ENABLE_JIT == 0)
if (local_offset < 0x80) { if (local_offset < 0x80) {
#if WASM_ENABLE_DEBUG_INTERP != 0
record_fast_op(module, p_org, *p_org);
#endif
*p_org++ = EXT_OP_GET_LOCAL_FAST; *p_org++ = EXT_OP_GET_LOCAL_FAST;
if (is_32bit_type(local_type)) if (is_32bit_type(local_type)) {
#if WASM_ENABLE_DEBUG_INTERP != 0
record_fast_op(module, p_org, *p_org);
#endif
*p_org++ = (uint8)local_offset; *p_org++ = (uint8)local_offset;
else }
else {
#if WASM_ENABLE_DEBUG_INTERP != 0
record_fast_op(module, p_org, *p_org);
#endif
*p_org++ = (uint8)(local_offset | 0x80); *p_org++ = (uint8)(local_offset | 0x80);
while (p_org < p) }
while (p_org < p) {
#if WASM_ENABLE_DEBUG_INTERP != 0
record_fast_op(module, p_org, *p_org);
#endif
*p_org++ = WASM_OP_NOP; *p_org++ = WASM_OP_NOP;
}
} }
#endif #endif
#endif #endif
@ -7254,13 +7335,28 @@ handle_op_block_and_loop:
#else #else
#if (WASM_ENABLE_WAMR_COMPILER == 0) && (WASM_ENABLE_JIT == 0) #if (WASM_ENABLE_WAMR_COMPILER == 0) && (WASM_ENABLE_JIT == 0)
if (local_offset < 0x80) { if (local_offset < 0x80) {
#if WASM_ENABLE_DEBUG_INTERP != 0
record_fast_op(module, p_org, *p_org);
#endif
*p_org++ = EXT_OP_SET_LOCAL_FAST; *p_org++ = EXT_OP_SET_LOCAL_FAST;
if (is_32bit_type(local_type)) if (is_32bit_type(local_type)) {
#if WASM_ENABLE_DEBUG_INTERP != 0
record_fast_op(module, p_org, *p_org);
#endif
*p_org++ = (uint8)local_offset; *p_org++ = (uint8)local_offset;
else }
else {
#if WASM_ENABLE_DEBUG_INTERP != 0
record_fast_op(module, p_org, *p_org);
#endif
*p_org++ = (uint8)(local_offset | 0x80); *p_org++ = (uint8)(local_offset | 0x80);
while (p_org < p) }
while (p_org < p) {
#if WASM_ENABLE_DEBUG_INTERP != 0
record_fast_op(module, p_org, *p_org);
#endif
*p_org++ = WASM_OP_NOP; *p_org++ = WASM_OP_NOP;
}
} }
#endif #endif
#endif #endif
@ -7309,13 +7405,28 @@ handle_op_block_and_loop:
#else #else
#if (WASM_ENABLE_WAMR_COMPILER == 0) && (WASM_ENABLE_JIT == 0) #if (WASM_ENABLE_WAMR_COMPILER == 0) && (WASM_ENABLE_JIT == 0)
if (local_offset < 0x80) { if (local_offset < 0x80) {
#if WASM_ENABLE_DEBUG_INTERP != 0
record_fast_op(module, p_org, *p_org);
#endif
*p_org++ = EXT_OP_TEE_LOCAL_FAST; *p_org++ = EXT_OP_TEE_LOCAL_FAST;
if (is_32bit_type(local_type)) if (is_32bit_type(local_type)) {
#if WASM_ENABLE_DEBUG_INTERP != 0
record_fast_op(module, p_org, *p_org);
#endif
*p_org++ = (uint8)local_offset; *p_org++ = (uint8)local_offset;
else }
else {
#if WASM_ENABLE_DEBUG_INTERP != 0
record_fast_op(module, p_org, *p_org);
#endif
*p_org++ = (uint8)(local_offset | 0x80); *p_org++ = (uint8)(local_offset | 0x80);
while (p_org < p) }
while (p_org < p) {
#if WASM_ENABLE_DEBUG_INTERP != 0
record_fast_op(module, p_org, *p_org);
#endif
*p_org++ = WASM_OP_NOP; *p_org++ = WASM_OP_NOP;
}
} }
#endif #endif
#endif #endif
@ -7344,6 +7455,9 @@ handle_op_block_and_loop:
#if (WASM_ENABLE_WAMR_COMPILER == 0) && (WASM_ENABLE_JIT == 0) #if (WASM_ENABLE_WAMR_COMPILER == 0) && (WASM_ENABLE_JIT == 0)
if (global_type == VALUE_TYPE_I64 if (global_type == VALUE_TYPE_I64
|| global_type == VALUE_TYPE_F64) { || global_type == VALUE_TYPE_F64) {
#if WASM_ENABLE_DEBUG_INTERP != 0
record_fast_op(module, p_org, *p_org);
#endif
*p_org = WASM_OP_GET_GLOBAL_64; *p_org = WASM_OP_GET_GLOBAL_64;
} }
#endif #endif
@ -7393,10 +7507,16 @@ handle_op_block_and_loop:
#if WASM_ENABLE_FAST_INTERP == 0 #if WASM_ENABLE_FAST_INTERP == 0
if (global_type == VALUE_TYPE_I64 if (global_type == VALUE_TYPE_I64
|| global_type == VALUE_TYPE_F64) { || global_type == VALUE_TYPE_F64) {
#if WASM_ENABLE_DEBUG_INTERP != 0
record_fast_op(module, p_org, *p_org);
#endif
*p_org = WASM_OP_SET_GLOBAL_64; *p_org = WASM_OP_SET_GLOBAL_64;
} }
else if (module->aux_stack_size > 0 else if (module->aux_stack_size > 0
&& global_idx == module->aux_stack_top_global_index) { && global_idx == module->aux_stack_top_global_index) {
#if WASM_ENABLE_DEBUG_INTERP != 0
record_fast_op(module, p_org, *p_org);
#endif
*p_org = WASM_OP_SET_GLOBAL_AUX_STACK; *p_org = WASM_OP_SET_GLOBAL_AUX_STACK;
} }
#else /* else of WASM_ENABLE_FAST_INTERP */ #else /* else of WASM_ENABLE_FAST_INTERP */

View File

@ -62,8 +62,10 @@ wasm_loader_unload(WASMModule *module);
* *
* @return true if success, false otherwise * @return true if success, false otherwise
*/ */
bool 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 *start_addr,
const uint8 *code_end_addr, const uint8 *code_end_addr,
uint8 block_type, uint8 block_type,

View File

@ -267,6 +267,10 @@ typedef enum WASMOpcode {
EXT_OP_LOOP = 0xd4, /* loop with blocktype */ EXT_OP_LOOP = 0xd4, /* loop with blocktype */
EXT_OP_IF = 0xd5, /* if with blocktype */ EXT_OP_IF = 0xd5, /* if with blocktype */
#if WASM_ENABLE_DEBUG_INTERP != 0
DEBUG_OP_BREAK = 0xd6, /* debug break point */
#endif
/* Post-MVP extend op prefix */ /* Post-MVP extend op prefix */
WASM_OP_MISC_PREFIX = 0xfc, WASM_OP_MISC_PREFIX = 0xfc,
WASM_OP_SIMD_PREFIX = 0xfd, WASM_OP_SIMD_PREFIX = 0xfd,
@ -673,6 +677,14 @@ typedef enum WASMAtomicEXTOpcode {
} }
#endif #endif
#if WASM_ENABLE_DEBUG_INTERP != 0
#define DEF_DEBUG_BREAK_HANDLE(_name) \
_name[DEBUG_OP_BREAK] = \
HANDLE_OPCODE (DEBUG_OP_BREAK); /* 0xd6 */
#else
#define DEF_DEBUG_BREAK_HANDLE(_name)
#endif
/* /*
* Macro used to generate computed goto tables for the C interpreter. * Macro used to generate computed goto tables for the C interpreter.
*/ */
@ -900,6 +912,7 @@ do { \
HANDLE_OPCODE (WASM_OP_MISC_PREFIX); /* 0xfc */ \ HANDLE_OPCODE (WASM_OP_MISC_PREFIX); /* 0xfc */ \
_name[WASM_OP_ATOMIC_PREFIX] = \ _name[WASM_OP_ATOMIC_PREFIX] = \
HANDLE_OPCODE (WASM_OP_ATOMIC_PREFIX); /* 0xfe */ \ HANDLE_OPCODE (WASM_OP_ATOMIC_PREFIX); /* 0xfe */ \
DEF_DEBUG_BREAK_HANDLE(_name) \
} while (0) } while (0)
#endif /* end of _WASM_OPCODE_H */ #endif /* end of _WASM_OPCODE_H */

View File

@ -16,6 +16,9 @@
#if WASM_ENABLE_THREAD_MGR != 0 #if WASM_ENABLE_THREAD_MGR != 0
#include "../libraries/thread-mgr/thread_manager.h" #include "../libraries/thread-mgr/thread_manager.h"
#endif #endif
#if WASM_ENABLE_DEBUG_INTERP != 0
#include "../libraries/debug-engine/debug_engine.h"
#endif
static void static void
set_error_buf(char *error_buf, uint32 error_buf_size, const char *string) set_error_buf(char *error_buf, uint32 error_buf_size, const char *string)
@ -1826,14 +1829,30 @@ wasm_module_malloc(WASMModuleInstance *module_inst, uint32 size,
} }
else if (module_inst->malloc_function else if (module_inst->malloc_function
&& module_inst->free_function) { && module_inst->free_function) {
#if WASM_ENABLE_DEBUG_INTERP != 0
/* TODO: obviously, we can not create debug instance for
* module malloc here, so, just disable the engine here,
* it is strange, but we now are lack of ways to indicate
* which calls should not be debugged. And we have other
* execute_xxx_function may need to be taken care of
*/
bool active = wasm_debug_get_engine_active();
wasm_debug_set_engine_active(false);
#endif
if (!execute_malloc_function(module_inst, if (!execute_malloc_function(module_inst,
module_inst->malloc_function, module_inst->malloc_function,
module_inst->retain_function, module_inst->retain_function,
size, &offset)) { size, &offset)) {
#if WASM_ENABLE_DEBUG_INTERP != 0
wasm_debug_set_engine_active(active);
#endif
return 0; return 0;
} }
#if WASM_ENABLE_DEBUG_INTERP != 0
wasm_debug_set_engine_active(active);
#endif
/* If we use app's malloc function, /* If we use app's malloc function,
the default memory may be changed while memory growing */ the default memory may be changed while memory growing */
memory = module_inst->default_memory; memory = module_inst->default_memory;
addr = offset ? memory->memory_data + offset : NULL; addr = offset ? memory->memory_data + offset : NULL;
} }
@ -1915,9 +1934,19 @@ wasm_module_free(WASMModuleInstance *module_inst, uint32 ptr)
&& module_inst->free_function && module_inst->free_function
&& memory->memory_data <= addr && memory->memory_data <= addr
&& addr < memory->memory_data_end) { && addr < memory->memory_data_end) {
#if WASM_ENABLE_DEBUG_INTERP != 0
/*TODO: obviously, we can not create debug instance for module malloc here,
so, just disable the engine here, it is strange. the wasm's call should be
marshed to its own thread */
bool active = wasm_debug_get_engine_active();
wasm_debug_set_engine_active(false);
#endif
execute_free_function(module_inst, execute_free_function(module_inst,
module_inst->free_function, module_inst->free_function,
ptr); ptr);
#if WASM_ENABLE_DEBUG_INTERP != 0
wasm_debug_set_engine_active(active);
#endif
} }
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,12 @@
# Copyright (C) 2021 Ant Group. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
set (DEBUG_ENGINE_DIR ${CMAKE_CURRENT_LIST_DIR})
add_definitions (-DWASM_ENABLE_DEBUG_INTERP=1)
include_directories(${DEBUG_ENGINE_DIR})
file (GLOB source_all ${DEBUG_ENGINE_DIR}/*.c)
set (DEBUG_ENGINE_SOURCE ${source_all})

View File

@ -0,0 +1,193 @@
/*
* Copyright (C) 2021 Ant Group. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#ifndef _DEBUG_ENGINE_H
#define _DEBUG_ENGINE_H
#include "bh_list.h"
#include "gdbserver.h"
#include "thread_manager.h"
typedef enum WASMDebugControlThreadStatus {
RUNNING,
STOPPED,
} WASMDebugControlThreadStatus;
struct WASMDebugObject;
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;
} WASMDebugControlThread;
typedef struct WASMDebugObject {
struct WASMDebugObject *next;
WASMDebugControlThread *control_thread;
} WASMDebugObject;
typedef struct WASMDebugBreakPoint {
struct WASMDebugBreakPoint *next;
uint64 addr;
uint64 orignal_data;
} WASMDebugBreakPoint;
typedef struct WASMDebugInstance {
struct WASMDebugInstance *next;
WASMDebugControlThread *control_thread;
bh_list break_point_list;
WASMCluster *cluster;
uint32 id;
korp_tid current_tid;
} WASMDebugInstance;
typedef enum WASMDebugEventKind {
BREAK_POINT_ADD,
BREAK_POINT_REMOVE
} WASMDebugEventKind;
typedef struct WASMDebugEvent {
WASMDebugEventKind kind;
unsigned char metadata[0];
} WASMDebugEvent;
typedef struct WASMDebugMemoryInfo {
uint64 start;
uint64 size;
char name[128];
char permisson[4];
} WASMDebugMemoryInfo;
typedef enum WasmAddressType {
WasmMemory = 0x00,
WasmObj = 0x01,
WasmInvalid = 0x03
} WasmAddressType;
#define WASM_ADDR(type, id, offset) \
(((uint64)type << 62) | ((uint64)0 << 32) | ((uint64)offset << 0))
#define WASM_ADDR_TYPE(addr) (((addr)&0xC000000000000000) >> 62)
#define WASM_ADDR_OFFSET(addr) (((addr)&0x00000000FFFFFFFF))
#define INVALIED_ADDR (0xFFFFFFFFFFFFFFFF)
WASMDebugInstance *
wasm_debug_instance_create(WASMCluster *cluster);
void
wasm_debug_instance_destroy(WASMCluster *cluster);
WASMDebugInstance *
wasm_exec_env_get_instance(WASMExecEnv *exec_env);
bool
wasm_debug_engine_init(char *ip_addr, int platform_port, int process_port);
void
wasm_debug_engine_destroy();
void
wasm_debug_set_engine_active(bool active);
bool
wasm_debug_get_engine_active(void);
uint64
wasm_debug_instance_get_pid(WASMDebugInstance *instance);
uint64
wasm_debug_instance_get_tid(WASMDebugInstance *instance);
int
wasm_debug_instance_get_tids(WASMDebugInstance *instance,
uint64 tids[], int len);
void
wasm_debug_instance_set_cur_thread(WASMDebugInstance *instance, uint64 tid);
uint64
wasm_debug_instance_get_pc(WASMDebugInstance *instance);
uint64
wasm_debug_instance_get_load_addr(WASMDebugInstance *instance);
WASMDebugMemoryInfo *
wasm_debug_instance_get_memregion(WASMDebugInstance *instance, uint64 addr);
void
wasm_debug_instance_destroy_memregion(WASMDebugInstance *instance,
WASMDebugMemoryInfo *mem_info);
bool
wasm_debug_instance_get_obj_mem(WASMDebugInstance *instance,
uint64 addr, char *buf, uint64 *size);
bool
wasm_debug_instance_get_linear_mem(WASMDebugInstance *instance,
uint64 addr, char *buf, uint64 *size);
bool
wasm_debug_instance_get_mem(WASMDebugInstance *instance,
uint64 addr, char *buf, uint64 *size);
bool
wasm_debug_instance_set_mem(WASMDebugInstance *instance,
uint64 addr, char *buf, uint64 *size);
int
wasm_debug_instance_get_call_stack_pcs(WASMDebugInstance *instance,
uint64 tid, uint64 buf[], uint64 size);
bool
wasm_debug_instance_add_breakpoint(WASMDebugInstance *instance,
uint64 addr, uint64 length);
bool
wasm_debug_instance_remove_breakpoint(WASMDebugInstance *instance,
uint64 addr, uint64 length);
bool
wasm_debug_instance_continue(WASMDebugInstance *instance);
bool
wasm_debug_instance_kill(WASMDebugInstance *instance);
uint64
wasm_debug_instance_wait_thread(WASMDebugInstance *instance,
uint64 tid, uint32 *status);
bool
wasm_debug_instance_singlestep(WASMDebugInstance *instance, uint64 tid);
bool
wasm_debug_instance_get_local(WASMDebugInstance *instance,
int frame_index, int local_index,
char buf[], int *size);
bool
wasm_debug_instance_get_global(WASMDebugInstance *instance,
int frame_index, int global_index,
char buf[], int *size);
#if WASM_ENABLE_LIBC_WASI != 0
bool
wasm_debug_instance_get_current_object_name(WASMDebugInstance *instance,
char name_buffer[], int len);
#endif
uint64
wasm_debug_instance_mmap(WASMDebugInstance *instance,
uint32 size, int map_port);
bool
wasm_debug_instance_ummap(WASMDebugInstance *instance, uint64 addr);
#endif

View File

@ -0,0 +1,177 @@
/*
* Copyright (C) 2021 Ant Group. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "gdbserver.h"
#include <arpa/inet.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/poll.h>
#include <sys/socket.h>
#include <unistd.h>
#include "bh_log.h"
#include "handler.h"
#include "packets.h"
#include "utils.h"
typedef void (*PacketHandler)(WASMGDBServer *server, char *payload);
struct packet_handler_elem {
char request;
PacketHandler handler;
};
#define DEL_HANDLER(r, h) [r] = { .request = r, .handler = h }
static struct packet_handler_elem packet_handler_table[255] = {
DEL_HANDLER('Q', handle_generay_set),
DEL_HANDLER('q', handle_generay_query),
DEL_HANDLER('v', handle_v_packet),
DEL_HANDLER('?', handle_threadstop_request),
DEL_HANDLER('H', handle_set_current_thread),
DEL_HANDLER('p', handle_get_register),
DEL_HANDLER('j', handle_get_json_request),
DEL_HANDLER('m', handle_get_read_memory),
DEL_HANDLER('M', handle_get_write_memory),
DEL_HANDLER('x', handle_get_read_binary_memory),
DEL_HANDLER('Z', handle_add_break),
DEL_HANDLER('z', handle_remove_break),
DEL_HANDLER('c', handle_continue_request),
DEL_HANDLER('k', handle_kill_request),
DEL_HANDLER('_', handle____request),
};
WASMGDBServer *
wasm_launch_gdbserver(char *host, int port)
{
int listen_fd = -1;
const int one = 1;
struct sockaddr_in addr;
int ret;
int sockt_fd = 0;
WASMGDBServer *server;
if (!(server = wasm_runtime_malloc(sizeof(WASMGDBServer)))) {
LOG_ERROR("wasm gdb server error: failed to allocate memory");
return NULL;
}
listen_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (listen_fd < 0) {
LOG_ERROR("wasm gdb server error: socket() failed");
goto fail;
}
ret = fcntl(listen_fd, F_SETFD, FD_CLOEXEC);
if(ret < 0) {
LOG_ERROR("wasm gdb server error: fcntl() failed on setting FD_CLOEXEC");
goto fail;
}
ret = setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
if (ret < 0) {
LOG_ERROR("wasm gdb server error: setsockopt() failed");
goto fail;
}
LOG_VERBOSE("Listening on %s:%d\n", host, port);
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(host);
addr.sin_port = htons(port);
ret = bind(listen_fd, (struct sockaddr *)&addr, sizeof(addr));
if (ret < 0) {
LOG_ERROR("wasm gdb server error: bind() failed");
goto fail;
}
ret = listen(listen_fd, 1);
if (ret < 0) {
LOG_ERROR("wasm gdb server error: listen() failed");
goto fail;
}
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:
if (listen_fd > 0) {
shutdown(listen_fd, SHUT_RDWR);
close(listen_fd);
}
if (server)
wasm_runtime_free(server);
return NULL;
}
void
wasm_close_gdbserver(WASMGDBServer *server)
{
if (server->socket_fd > 0) {
shutdown(server->socket_fd, SHUT_RDWR);
close(server->socket_fd);
}
if (server->listen_fd > 0) {
shutdown(server->listen_fd, SHUT_RDWR);
close(server->listen_fd);
}
}
static inline void
handler_packet(WASMGDBServer *server, char request, char *payload)
{
if (packet_handler_table[(int)request].handler != NULL)
packet_handler_table[(int)request].handler(server, payload);
}
static void
process_packet(WASMGDBServer *server)
{
uint8_t *inbuf = server->pkt.buf;
int inbuf_size = server->pkt.end;
uint8_t *packetend_ptr = (uint8_t *)memchr(inbuf, '#', inbuf_size);
int packetend = packetend_ptr - inbuf;
bh_assert('$' == inbuf[0]);
char request = inbuf[1];
char *payload = (char *)&inbuf[2];
inbuf[packetend] = '\0';
uint8_t checksum = 0;
for (int i = 1; i < packetend; i++)
checksum += inbuf[i];
bh_assert(checksum
== (hex(inbuf[packetend + 1]) << 4 | hex(inbuf[packetend + 2])));
LOG_VERBOSE("receive request:%c %s\n", request, payload);
handler_packet(server, request, payload);
inbuf_erase_head(server, packetend + 3);
}
bool
wasm_gdbserver_handle_packet(WASMGDBServer *server)
{
bool ret;
ret = read_packet(server);
if (ret)
process_packet(server);
return ret;
}

View File

@ -0,0 +1,43 @@
/*
* Copyright (C) 2021 Ant Group. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#ifndef _GDB_SERVER_H
#define _GDB_SERVER_H
#include <stdbool.h>
#define PACKET_BUF_SIZE 0x8000
enum GDBStoppointType {
eStoppointInvalid = -1,
eBreakpointSoftware = 0,
eBreakpointHardware,
eWatchpointWrite,
eWatchpointRead,
eWatchpointReadWrite
};
typedef struct WasmDebugPacket {
unsigned char buf[PACKET_BUF_SIZE];
unsigned int end;
} WasmDebugPacket;
struct WASMDebugControlThread;
typedef struct WASMGDBServer {
int listen_fd;
int socket_fd;
WasmDebugPacket pkt;
bool noack;
struct WASMDebugControlThread *thread;
} WASMGDBServer;
WASMGDBServer *
wasm_launch_gdbserver(char *addr, int port);
void
wasm_close_gdbserver(WASMGDBServer *server);
bool
wasm_gdbserver_handle_packet(WASMGDBServer *server);
#endif

View File

@ -0,0 +1,598 @@
/*
* Copyright (C) 2021 Ant Group. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include <bh_log.h>
#include <handler.h>
#include <limits.h>
#include <string.h>
#include <unistd.h>
#include "debug_engine.h"
#include "packets.h"
#include "utils.h"
#include "wasm_runtime.h"
#define MAX_PACKET_SIZE (0x20000)
static char tmpbuf[MAX_PACKET_SIZE];
void
handle_generay_set(WASMGDBServer *server, char *payload)
{
const char *name;
char *args;
args = strchr(payload, ':');
if (args)
*args++ = '\0';
name = payload;
LOG_VERBOSE("%s:%s\n", __FUNCTION__, payload);
if (!strcmp(name, "StartNoAckMode")) {
server->noack = true;
write_packet(server, "OK");
}
if (!strcmp(name, "ThreadSuffixSupported")) {
write_packet(server, "");
}
if (!strcmp(name, "ListThreadsInStopReply")) {
write_packet(server, "");
}
if (!strcmp(name, "EnableErrorStrings")) {
write_packet(server, "OK");
}
}
static void
process_xfer(WASMGDBServer *server, const char *name, char *args)
{
const char *mode = args;
args = strchr(args, ':');
*args++ = '\0';
if (!strcmp(name, "libraries") && !strcmp(mode, "read")) {
//TODO: how to get current wasm file name?
uint64_t addr = wasm_debug_instance_get_load_addr(
(WASMDebugInstance *)server->thread->debug_instance);
#if WASM_ENABLE_LIBC_WASI != 0
char objname[128];
wasm_debug_instance_get_current_object_name(
(WASMDebugInstance *)server->thread->debug_instance, objname, 128);
sprintf(tmpbuf,
"l<library-list><library name=\"%s\"><section "
"address=\"0x%lx\"/></library></library-list>",
objname, addr);
#else
sprintf(tmpbuf,
"l<library-list><library name=\"%s\"><section "
"address=\"0x%lx\"/></library></library-list>",
"nobody.wasm", addr);
#endif
write_packet(server, tmpbuf);
}
}
void
porcess_wasm_local(WASMGDBServer *server, char *args)
{
int frame_index;
int local_index;
char buf[16];
int size = 16;
bool ret;
sprintf(tmpbuf, "E01");
if (sscanf(args, "%d;%d", &frame_index, &local_index) == 2) {
ret = wasm_debug_instance_get_local(
(WASMDebugInstance *)server->thread->debug_instance, frame_index,
local_index, buf, &size);
if (ret && size > 0) {
mem2hex(buf, tmpbuf, size);
}
}
write_packet(server, tmpbuf);
}
void
porcess_wasm_global(WASMGDBServer *server, char *args)
{
int frame_index;
int global_index;
char buf[16];
int size = 16;
bool ret;
sprintf(tmpbuf, "E01");
if (sscanf(args, "%d;%d", &frame_index, &global_index) == 2) {
ret = wasm_debug_instance_get_global(
(WASMDebugInstance *)server->thread->debug_instance, frame_index,
global_index, buf, &size);
if (ret && size > 0) {
mem2hex(buf, tmpbuf, size);
}
}
write_packet(server, tmpbuf);
}
void
handle_generay_query(WASMGDBServer *server, char *payload)
{
const char *name;
char *args;
args = strchr(payload, ':');
if (args)
*args++ = '\0';
name = payload;
LOG_VERBOSE("%s:%s\n", __FUNCTION__, payload);
if (!strcmp(name, "C")) {
uint64_t pid, tid;
pid = wasm_debug_instance_get_pid(
(WASMDebugInstance *)server->thread->debug_instance);
tid = wasm_debug_instance_get_tid(
(WASMDebugInstance *)server->thread->debug_instance);
snprintf(tmpbuf, sizeof(tmpbuf), "QCp%lx.%lx", pid, tid);
write_packet(server, tmpbuf);
}
if (!strcmp(name, "Supported")) {
sprintf(tmpbuf, "qXfer:libraries:read+;PacketSize=%x;", MAX_PACKET_SIZE);
write_packet(server, tmpbuf);
}
if (!strcmp(name, "Xfer")) {
name = args;
args = strchr(args, ':');
*args++ = '\0';
process_xfer(server, name, args);
}
if (!strcmp(name, "HostInfo")) {
//Todo: change vendor to Intel for outside tree
char triple[256];
mem2hex("wasm32-Ant-wasi-wasm", triple,
strlen("wasm32-Ant-wasi-wasm"));
sprintf(tmpbuf,
"vendor:Ant;ostype:wasi;arch:wasm32;"
"triple:%s;endian:little;ptrsize:4;",
triple);
write_packet(server, tmpbuf);
}
if (!strcmp(name, "GetWorkingDir")) {
if (getcwd(tmpbuf, PATH_MAX))
write_packet(server, tmpbuf);
}
if (!strcmp(name, "QueryGDBServer")) {
write_packet(server, "");
}
if (!strcmp(name, "VAttachOrWaitSupported")) {
write_packet(server, "");
}
if (!strcmp(name, "ProcessInfo")) {
//Todo: process id parent-pid
uint64_t pid;
pid = wasm_debug_instance_get_pid(
(WASMDebugInstance *)server->thread->debug_instance);
char triple[256];
//arch-vendor-os-env(format)
mem2hex("wasm32-Ant-wasi-wasm", triple,
strlen("wasm32-Ant-wasi-wasm"));
sprintf(tmpbuf,
"pid:%lx;parent-pid:%lx;vendor:Ant;ostype:wasi;arch:wasm32;"
"triple:%s;endian:little;ptrsize:4;",
pid, pid, triple);
write_packet(server, tmpbuf);
}
if (!strcmp(name, "RegisterInfo0")) {
sprintf(
tmpbuf,
"name:pc;alt-name:pc;bitsize:64;offset:0;encoding:uint;format:hex;"
"set:General Purpose Registers;gcc:16;dwarf:16;generic:pc;");
write_packet(server, tmpbuf);
}
else if (!strncmp(name, "RegisterInfo", strlen("RegisterInfo"))) {
write_packet(server, "E45");
}
if (!strcmp(name, "StructuredDataPlugins")) {
write_packet(server, "");
}
if (!strcmp(name, "MemoryRegionInfo")) {
uint64_t addr = strtol(args, NULL, 16);
WASMDebugMemoryInfo *mem_info = wasm_debug_instance_get_memregion(
(WASMDebugInstance *)server->thread->debug_instance, addr);
if (mem_info) {
char name[256];
mem2hex(mem_info->name, name, strlen(mem_info->name));
sprintf(tmpbuf, "start:%lx;size:%lx;permissions:%s;name:%s;",
(uint64)mem_info->start, mem_info->size, mem_info->permisson, name);
write_packet(server, tmpbuf);
wasm_debug_instance_destroy_memregion(
(WASMDebugInstance *)server->thread->debug_instance, mem_info);
}
}
if (!strcmp(name, "WasmData")) {
}
if (!strcmp(name, "WasmMem")) {
}
if (!strcmp(name, "Symbol")) {
write_packet(server, "");
}
if (!strcmp(name, "WasmCallStack")) {
uint64_t tid = strtol(args, NULL, 16);
uint64_t buf[1024 / sizeof(uint64_t)];
uint64_t count = wasm_debug_instance_get_call_stack_pcs(
(WASMDebugInstance *)server->thread->debug_instance, tid, buf,
1024 / sizeof(uint64_t));
if (count > 0) {
mem2hex((char *)buf, tmpbuf, count * sizeof(uint64_t));
write_packet(server, tmpbuf);
}
else
write_packet(server, "");
}
if (!strcmp(name, "WasmLocal")) {
porcess_wasm_local(server, args);
}
if (!strcmp(name, "WasmGlobal")) {
porcess_wasm_global(server, args);
}
}
static void
send_thread_stop_status(WASMGDBServer *server, uint32_t status, uint64_t tid)
{
int tids_number, len = 0, i = 0;
uint64_t tids[20];
char pc_string[17];
uint32_t gdb_status = status;
if (status == 0) {
sprintf(tmpbuf, "W%02x", status);
write_packet(server, tmpbuf);
return;
}
tids_number = wasm_debug_instance_get_tids(
(WASMDebugInstance *)server->thread->debug_instance, tids, 20);
uint64_t pc = wasm_debug_instance_get_pc(
(WASMDebugInstance *)server->thread->debug_instance);
if (status == WAMR_SIG_SINGSTEP) {
gdb_status = WAMR_SIG_TRAP;
}
//TODO: how name a wasm thread?
len += sprintf(tmpbuf, "T%02xthread:%lx;name:%s;", gdb_status, tid, "nobody");
if (tids_number > 0) {
len += sprintf(tmpbuf + len, "threads:");
while (i < tids_number) {
if (i == tids_number - 1)
len += sprintf(tmpbuf + len, "%lx;", tids[i]);
else
len += sprintf(tmpbuf + len, "%lx,", tids[i]);
i++;
}
}
mem2hex((void *)&pc, pc_string, 8);
pc_string[8 * 2] = '\0';
if (status == WAMR_SIG_TRAP) {
len += sprintf(tmpbuf + len, "thread-pcs:%lx;00:%s,reason:%s;", pc,
pc_string, "breakpoint");
}
else if (status == WAMR_SIG_SINGSTEP) {
len += sprintf(tmpbuf + len, "thread-pcs:%lx;00:%s,reason:%s;", pc,
pc_string, "trace");
}
else if (status > 0) {
len += sprintf(tmpbuf + len, "thread-pcs:%lx;00:%s,reason:%s;", pc,
pc_string, "signal");
}
write_packet(server, tmpbuf);
}
void
handle_v_packet(WASMGDBServer *server, char *payload)
{
const char *name;
char *args;
uint32_t status;
args = strchr(payload, ';');
if (args)
*args++ = '\0';
name = payload;
LOG_VERBOSE("%s:%s\n", __FUNCTION__, payload);
if (!strcmp("Cont?", name))
write_packet(server, "vCont;c;C;s;S;");
if (!strcmp("Cont", name)) {
if (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);
}
}
}
}
void
handle_threadstop_request(WASMGDBServer *server, char *payload)
{
uint64_t tid = wasm_debug_instance_get_tid(
(WASMDebugInstance *)server->thread->debug_instance);
uint32_t status;
tid = wasm_debug_instance_wait_thread(
(WASMDebugInstance *)server->thread->debug_instance, tid, &status);
send_thread_stop_status(server, status, tid);
}
void
handle_set_current_thread(WASMGDBServer *server, char *payload)
{
LOG_VERBOSE("%s:%s\n", __FUNCTION__, payload, payload);
if ('g' == *payload++) {
uint64_t tid;
tid = strtol(payload, NULL, 16);
if (tid > 0)
wasm_debug_instance_set_cur_thread(
(WASMDebugInstance *)server->thread->debug_instance, tid);
}
write_packet(server, "OK");
}
void
handle_get_register(WASMGDBServer *server, char *payload)
{
int i = strtol(payload, NULL, 16);
if (i != 0) {
write_packet(server, "E01");
return;
}
uint64_t regdata = wasm_debug_instance_get_pc(
(WASMDebugInstance *)server->thread->debug_instance);
mem2hex((void *)&regdata, tmpbuf, 8);
tmpbuf[8 * 2] = '\0';
write_packet(server, tmpbuf);
}
void
handle_get_json_request(WASMGDBServer *server, char *payload)
{
char *args;
args = strchr(payload, ':');
if (args)
*args++ = '\0';
write_packet(server, "");
}
void
handle_get_read_binary_memory(WASMGDBServer *server, char *payload)
{
write_packet(server, "");
}
void
handle_get_read_memory(WASMGDBServer *server, char *payload)
{
size_t maddr, mlen;
bool ret;
sprintf(tmpbuf, "%s", "");
if (sscanf(payload, "%zx,%zx", &maddr, &mlen) == 2) {
if (mlen * 2 > MAX_PACKET_SIZE) {
LOG_ERROR("Buffer overflow!");
mlen = MAX_PACKET_SIZE / 2;
}
char *buff = wasm_runtime_malloc(mlen);
if (buff) {
ret = wasm_debug_instance_get_mem(
(WASMDebugInstance *)server->thread->debug_instance, maddr, buff,
&mlen);
if (ret) {
mem2hex(buff, tmpbuf, mlen);
}
wasm_runtime_free(buff);
}
}
write_packet(server, tmpbuf);
}
void
handle_get_write_memory(WASMGDBServer *server, char *payload)
{
size_t maddr, mlen, hex_len;
int offset, act_len;
char *buff;
bool ret;
sprintf(tmpbuf, "%s", "");
if (sscanf(payload, "%zx,%zx:%n", &maddr, &mlen, &offset) == 2) {
payload += offset;
hex_len = strlen(payload);
act_len = hex_len / 2 < mlen ? hex_len / 2 : mlen;
buff = wasm_runtime_malloc(act_len);
if (buff) {
hex2mem(payload, buff, act_len);
ret = wasm_debug_instance_set_mem(
(WASMDebugInstance *)server->thread->debug_instance, maddr, buff,
&mlen);
if (ret) {
sprintf(tmpbuf, "%s", "OK");
}
wasm_runtime_free(buff);
}
}
write_packet(server, tmpbuf);
}
void
handle_add_break(WASMGDBServer *server, char *payload)
{
size_t type, addr, length;
if (sscanf(payload, "%zx,%zx,%zx", &type, &addr, &length) == 3) {
if (type == eBreakpointSoftware) {
bool ret = wasm_debug_instance_add_breakpoint(
(WASMDebugInstance *)server->thread->debug_instance, addr,
length);
if (ret)
write_packet(server, "OK");
else
write_packet(server, "E01");
return;
}
}
write_packet(server, "");
}
void
handle_remove_break(WASMGDBServer *server, char *payload)
{
size_t type, addr, length;
if (sscanf(payload, "%zx,%zx,%zx", &type, &addr, &length) == 3) {
if (type == eBreakpointSoftware) {
bool ret = wasm_debug_instance_remove_breakpoint(
(WASMDebugInstance *)server->thread->debug_instance, addr,
length);
if (ret)
write_packet(server, "OK");
else
write_packet(server, "E01");
return;
}
}
write_packet(server, "");
}
void
handle_continue_request(WASMGDBServer *server, char *payload)
{
uint64_t tid;
uint32_t status;
wasm_debug_instance_continue(
(WASMDebugInstance *)server->thread->debug_instance);
tid = wasm_debug_instance_get_tid(
(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);
}
void
handle_kill_request(WASMGDBServer *server, char *payload)
{
uint64_t tid;
uint32_t status;
wasm_debug_instance_kill(
(WASMDebugInstance *)server->thread->debug_instance);
tid = wasm_debug_instance_get_tid(
(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);
}
static void
handle_malloc(WASMGDBServer *server, char *payload)
{
char *args;
uint64_t size;
int map_port = MMAP_PROT_NONE;
uint64_t addr;
sprintf(tmpbuf, "%s", "E03");
args = strstr(payload, ",");
if (args)
*args++ = '\0';
size = strtol(payload, NULL, 16);
if (size > 0) {
while (*args) {
if (*args == 'r') {
map_port |= MMAP_PROT_READ;
}
if (*args == 'w') {
map_port |= MMAP_PROT_WRITE;
}
if (*args == 'x') {
map_port |= MMAP_PROT_EXEC;
}
args++;
}
addr = wasm_debug_instance_mmap(
(WASMDebugInstance *)server->thread->debug_instance, size, map_port);
if (addr) {
sprintf(tmpbuf, "%lx", addr);
}
}
write_packet(server, tmpbuf);
}
static void
handle_free(WASMGDBServer *server, char *payload)
{
uint64_t addr;
bool ret;
sprintf(tmpbuf, "%s", "E03");
addr = strtol(payload, NULL, 16);
ret = wasm_debug_instance_ummap(
(WASMDebugInstance *)server->thread->debug_instance, addr);
if (ret) {
sprintf(tmpbuf, "%s", "OK");
}
write_packet(server, tmpbuf);
}
void
handle____request(WASMGDBServer *server, char *payload)
{
char *args;
if (payload[0] == 'M') {
args = payload + 1;
handle_malloc(server, args);
}
if (payload[0] == 'm') {
args = payload + 1;
handle_free(server, args);
}
}

View File

@ -0,0 +1,55 @@
/*
* Copyright (C) 2021 Ant Group. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#ifndef HANDLER_H
#define HANDLER_H
#include "gdbserver.h"
void
handle_generay_set(WASMGDBServer *server, char *payload);
void
handle_generay_query(WASMGDBServer *server, char *payload);
void
handle_v_packet(WASMGDBServer *server, char *payload);
void
handle_threadstop_request(WASMGDBServer *server, char *payload);
void
handle_set_current_thread(WASMGDBServer *server, char *payload);
void
handle_get_register(WASMGDBServer *server, char *payload);
void
handle_get_json_request(WASMGDBServer *server, char *payload);
void
handle_get_read_binary_memory(WASMGDBServer *server, char *payload);
void
handle_get_read_memory(WASMGDBServer *server, char *payload);
void
handle_get_write_memory(WASMGDBServer *server, char *payload);
void
handle_add_break(WASMGDBServer *server, char *payload);
void
handle_remove_break(WASMGDBServer *server, char *payload);
void
handle_continue_request(WASMGDBServer *server, char *payload);
void
handle_kill_request(WASMGDBServer *server, char *payload);
void
handle____request(WASMGDBServer *server, char *payload);
#endif

View File

@ -0,0 +1,173 @@
/*
* Copyright (C) 2021 Ant Group. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "packets.h"
#include <stdbool.h>
#include "bh_log.h"
#include "gdbserver.h"
void
pktbuf_insert(WASMGDBServer *gdbserver, const uint8_t *buf, ssize_t len)
{
WasmDebugPacket *pkt = &gdbserver->pkt;
if ((unsigned long)(pkt->end + len) >= sizeof(pkt->buf)) {
LOG_ERROR("Packet buffer overflow");
exit(-2);
}
memcpy(pkt->buf + pkt->end, buf, len);
pkt->end += len;
}
void
pktbuf_erase_head(WASMGDBServer *gdbserver, ssize_t end)
{
WasmDebugPacket *pkt = &gdbserver->pkt;
memmove(pkt->buf, pkt->buf + end, pkt->end - end);
pkt->end -= end;
}
void
inbuf_erase_head(WASMGDBServer *gdbserver, ssize_t end)
{
pktbuf_erase_head(gdbserver, end);
}
void
pktbuf_clear(WASMGDBServer *gdbserver)
{
WasmDebugPacket *pkt = &gdbserver->pkt;
pkt->end = 0;
}
int
read_data_once(WASMGDBServer *gdbserver)
{
ssize_t nread;
uint8_t buf[4096];
nread = read(gdbserver->socket_fd, buf, sizeof(buf));
if (nread <= 0) {
LOG_ERROR("Connection closed");
return -1;
}
pktbuf_insert(gdbserver, buf, nread);
return nread;
}
void
write_data_raw(WASMGDBServer *gdbserver, const uint8_t *data, ssize_t len)
{
ssize_t nwritten;
nwritten = write(gdbserver->socket_fd, data, len);
if (nwritten < 0) {
LOG_ERROR("Write error\n");
exit(-2);
}
}
void
write_hex(WASMGDBServer *gdbserver, unsigned long hex)
{
char buf[32];
size_t len;
len = snprintf(buf, sizeof(buf) - 1, "%02lx", hex);
write_data_raw(gdbserver, (uint8_t *)buf, len);
}
void
write_packet_bytes(WASMGDBServer *gdbserver,
const uint8_t *data,
size_t num_bytes)
{
uint8_t checksum;
size_t i;
write_data_raw(gdbserver, (uint8_t *)"$", 1);
for (i = 0, checksum = 0; i < num_bytes; ++i)
checksum += data[i];
write_data_raw(gdbserver, (uint8_t *)data, num_bytes);
write_data_raw(gdbserver, (uint8_t *)"#", 1);
write_hex(gdbserver, checksum);
}
void
write_packet(WASMGDBServer *gdbserver, const char *data)
{
LOG_VERBOSE("send replay:%s", data);
write_packet_bytes(gdbserver, (const uint8_t *)data, strlen(data));
}
void
write_binary_packet(WASMGDBServer *gdbserver,
const char *pfx,
const uint8_t *data,
ssize_t num_bytes)
{
uint8_t *buf;
ssize_t pfx_num_chars = strlen(pfx);
ssize_t buf_num_bytes = 0;
int i;
buf = malloc(2 * num_bytes + pfx_num_chars);
memcpy(buf, pfx, pfx_num_chars);
buf_num_bytes += pfx_num_chars;
for (i = 0; i < num_bytes; ++i) {
uint8_t b = data[i];
switch (b) {
case '#':
case '$':
case '}':
case '*':
buf[buf_num_bytes++] = '}';
buf[buf_num_bytes++] = b ^ 0x20;
break;
default:
buf[buf_num_bytes++] = b;
break;
}
}
write_packet_bytes(gdbserver, buf, buf_num_bytes);
free(buf);
}
bool
skip_to_packet_start(WASMGDBServer *gdbserver)
{
ssize_t end = -1;
for (size_t i = 0; i < gdbserver->pkt.end; ++i)
if (gdbserver->pkt.buf[i] == '$') {
end = i;
break;
}
if (end < 0) {
pktbuf_clear(gdbserver);
return false;
}
pktbuf_erase_head(gdbserver, end);
bh_assert(1 <= gdbserver->pkt.end);
bh_assert('$' == gdbserver->pkt.buf[0]);
return true;
}
bool
read_packet(WASMGDBServer *gdbserver)
{
while (!skip_to_packet_start(gdbserver)) {
if(read_data_once(gdbserver) < 0)
return false;
}
if (!gdbserver->noack)
write_data_raw(gdbserver, (uint8_t *)"+", 1);
return true;
}

View File

@ -0,0 +1,22 @@
/*
* Copyright (C) 2021 Ant Group. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#ifndef PACKETS_H
#define PACKETS_H
#include <stdint.h>
#include <unistd.h>
#include "gdbserver.h"
bool
read_packet(WASMGDBServer *gdbserver);
void
write_packet(WASMGDBServer *gdbserver, const char *data);
void
inbuf_erase_head(WASMGDBServer *gdbserver, ssize_t end);
#endif

View File

@ -0,0 +1,45 @@
/*
* Copyright (C) 2021 Ant Group. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "utils.h"
int
hex(char ch)
{
if ((ch >= 'a') && (ch <= 'f'))
return (ch - 'a' + 10);
if ((ch >= '0') && (ch <= '9'))
return (ch - '0');
if ((ch >= 'A') && (ch <= 'F'))
return (ch - 'A' + 10);
return (-1);
}
char *
mem2hex(char *mem, char *buf, int count)
{
unsigned char ch;
for (int i = 0; i < count; i++) {
ch = *(mem++);
*buf++ = hexchars[ch >> 4];
*buf++ = hexchars[ch % 16];
}
*buf = 0;
return (buf);
}
char *
hex2mem(char *buf, char *mem, int count)
{
unsigned char ch;
for (int i = 0; i < count; i++) {
ch = hex(*buf++) << 4;
ch = ch + hex(*buf++);
*(mem++) = ch;
}
return (mem);
}

View File

@ -0,0 +1,23 @@
/*
* Copyright (C) 2021 Ant Group. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#ifndef UTILS_H
#define UTILS_H
static const char hexchars[] = "0123456789abcdef";
int
hex(char ch);
char *
mem2hex(char *mem, char *buf, int count);
char *
hex2mem(char *buf, char *mem, int count);
int
unescape(char *msg, int len);
#endif /* UTILS_H */

View File

@ -484,6 +484,119 @@ fail1:
return -1; return -1;
} }
#if WASM_ENABLE_DEBUG_INTERP != 0
WASMCurrentEnvStatus *
wasm_cluster_create_exenv_status()
{
WASMCurrentEnvStatus *status;
if (!(status = wasm_runtime_malloc(sizeof(WASMCurrentEnvStatus)))) {
goto fail;
}
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);
}
inline static bool
wasm_cluster_thread_is_running(WASMExecEnv *exec_env) {
return exec_env->current_status->running_status == STATUS_RUNNING
|| exec_env->current_status->running_status == STATUS_STEP;
}
void
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;
}
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);
}
void
wasm_cluster_thread_waiting_run(WASMExecEnv *exec_env)
{
os_mutex_lock(&exec_env->wait_lock);
while (!wasm_cluster_thread_is_running(exec_env)) {
os_cond_wait(&exec_env->wait_cond, &exec_env->wait_lock);
}
os_mutex_unlock(&exec_env->wait_lock);
}
void
wasm_cluster_send_signal_all(WASMCluster *cluster, uint32 signo)
{
WASMExecEnv *exec_env = bh_list_first_elem(&cluster->exec_env_list);
while (exec_env) {
wasm_cluster_thread_send_signal(exec_env, signo);
exec_env = bh_list_elem_next(exec_env);
}
}
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);
}
void wasm_cluster_thread_continue(WASMExecEnv *exec_env)
{
wasm_cluster_clear_thread_signal(exec_env);
exec_env->current_status->running_status = STATUS_RUNNING;
os_cond_signal(&exec_env->wait_cond);
}
void wasm_cluster_thread_step(WASMExecEnv *exec_env)
{
exec_env->current_status->running_status = STATUS_STEP;
os_cond_signal(&exec_env->wait_cond);
}
#endif
int32 int32
wasm_cluster_join_thread(WASMExecEnv *exec_env, void **ret_val) wasm_cluster_join_thread(WASMExecEnv *exec_env, void **ret_val)
{ {
@ -520,7 +633,10 @@ wasm_cluster_exit_thread(WASMExecEnv *exec_env, void *retval)
cluster = wasm_exec_env_get_cluster(exec_env); cluster = wasm_exec_env_get_cluster(exec_env);
bh_assert(cluster); bh_assert(cluster);
#if WASM_ENABLE_DEBUG_INTERP != 0
wasm_cluster_clear_thread_signal(exec_env);
wasm_cluster_thread_exited(exec_env);
#endif
/* App exit the thread, free the resources before exit native thread */ /* App exit the thread, free the resources before exit native thread */
/* Free aux stack space */ /* Free aux stack space */
free_aux_stack(cluster, exec_env->aux_stack_bottom.bottom); free_aux_stack(cluster, exec_env->aux_stack_bottom.bottom);
@ -537,8 +653,13 @@ int32
wasm_cluster_cancel_thread(WASMExecEnv *exec_env) wasm_cluster_cancel_thread(WASMExecEnv *exec_env)
{ {
/* Set the termination flag */ /* Set the termination flag */
#if WASM_ENABLE_DEBUG_INTERP != 0
wasm_cluster_thread_send_signal(exec_env, WAMR_SIG_TERM);
wasm_cluster_thread_exited(exec_env);
#else
exec_env->suspend_flags.flags |= 0x01; exec_env->suspend_flags.flags |= 0x01;
return 0; #endif
return 0;
} }
static void static void
@ -621,6 +742,7 @@ void
wasm_cluster_resume_thread(WASMExecEnv *exec_env) wasm_cluster_resume_thread(WASMExecEnv *exec_env)
{ {
exec_env->suspend_flags.flags &= ~0x02; exec_env->suspend_flags.flags &= ~0x02;
os_cond_signal(&exec_env->wait_cond);
} }
static void static void

View File

@ -15,7 +15,63 @@
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
#if WASM_ENABLE_DEBUG_INTERP != 0
#define WAMR_SIG_TRAP (5)
#define WAMR_SIG_STOP (19)
#define WAMR_SIG_TERM (15)
#define WAMR_SIG_SINGSTEP (0x1ff)
#define STATUS_RUNNING (0)
#define STATUS_STOP (1)
#define STATUS_EXIT (2)
#define STATUS_STEP (3)
#define IS_WAMR_TERM_SIG(signo) \
((signo) == WAMR_SIG_TERM)
#define IS_WAMR_STOP_SIG(signo) \
((signo) == WAMR_SIG_STOP || (signo) == WAMR_SIG_TRAP)
typedef struct WASMCurrentEnvStatus
{
uint64 signal_flag:32;
uint64 step_count:16;
uint64 running_status:16;
korp_mutex wait_lock;
korp_cond wait_cond;
}WASMCurrentEnvStatus;
WASMCurrentEnvStatus *
wasm_cluster_create_exenv_status();
void
wasm_cluster_destroy_exenv_status(WASMCurrentEnvStatus *status);
void
wasm_cluster_send_signal_all(WASMCluster *cluster, uint32 signo);
void
wasm_cluster_thread_stopped(WASMExecEnv *exec_env);
void
wasm_cluster_thread_waiting_run(WASMExecEnv *exec_env);
void
wasm_cluster_wait_thread_status(WASMExecEnv *exec_env, uint32 * status);
void
wasm_cluster_thread_exited(WASMExecEnv *exec_env);
void
wasm_cluster_thread_continue(WASMExecEnv *exec_env);
void
wasm_cluster_thread_send_signal(WASMExecEnv *exec_env, uint32 signo);
void
wasm_cluster_thread_step(WASMExecEnv *exec_env);
#endif
typedef struct WASMCluster typedef struct WASMCluster
{ {
struct WASMCluster *next; struct WASMCluster *next;

86
doc/source_debugging.md Normal file
View File

@ -0,0 +1,86 @@
# WAMR source debugging
WAMR supports source level debugging based on DWARF (normally used in C/C++/Rust), source map (normally used in AssemblyScript) is not supported.
## Build wasm application with debug information
To debug your application, you need to compile them with debug information. You can use `-g` option when compiling the source code if you are using wasi-sdk (also work for emcc and rustc):
``` bash
/opt/wasi-sdk/bin/clang -g test.c -o test.wasm
```
Then you will get `test.wasm` which is a WebAssembly module with embedded DWARF sections. Further, you can use `llvm-dwarfdump` to check if the generated wasm file contains DWARF information:
``` bash
llvm-dwarfdump-12 test.wasm
```
## Debugging with interpreter
1. Build iwasm with source debugging feature
``` bash
cd ${WAMR_ROOT}/product-mini/platforms/linux
mkdir build && cd build
cmake .. -DWAMR_BUILD_DEBUG_INTERP=1
make
```
2. Execute iwasm with debug engine enabled
``` bash
iwasm -g=127.0.0.1:1234 test.wasm
```
3. Build customized lldb (assume you have already built llvm)
``` bash
cd ${WAMR_ROOT}/core/deps/llvm
git apply ../../../../build-scripts/lldb-wasm.patch
mkdir build && cd build
cmake ../llvm -DLLVM_ENABLE_PROJECTS="clang,lldb" -DLLVM_TARGETS_TO_BUILD:STRING="X86;WebAssembly"
make -j $(nproc)
```
4. Launch customized lldb and connect to iwasm
``` bash
lldb
(lldb) process connect -p wasm connect://127.0.0.1:1234
```
Then you can use lldb commands to debug your applications. Please refer to [lldb document](https://lldb.llvm.org/use/tutorial.html) for command usage.
> Known issue: `step over` on some function may be treated as `step in`, it will be fixed later.
## Debugging with AoT
> Note: AoT debugging is experimental and only a few debugging capabilities are supported.
1. Build lldb (assume you have already built llvm)
``` bash
cd ${WAMR_ROOT}/core/deps/llvm/build
cmake . -DLLVM_ENABLE_PROJECTS="clang;lldb"
make -j $(nproc)
```
2. Build wamrc with debugging feature
``` bash
cd ${WAMR_ROOT}/wamr-compiler
mkdir build && cd build
cmake .. -DWAMR_BUILD_DEBUG_AOT=1
make -j $(nproc)
```
3. Build iwasm with debugging feature
``` bash
cd ${WAMR_ROOT}/product-mini/platforms/linux
mkdir build && cd build
cmake .. -DWAMR_BUILD_DEBUG_AOT=1
make
```
4. Compile wasm module to AoT module
``` bash
wamrc -o test.aot test.wasm
```
5. Execute iwasm using lldb
``` bash
lldb-12 iwasm -- test.aot
```
Then you can use lldb commands to debug both wamr runtime and your wasm application in ***current terminal***

View File

@ -82,6 +82,17 @@ if (NOT DEFINED WAMR_BUILD_SIMD)
set (WAMR_BUILD_SIMD 1) set (WAMR_BUILD_SIMD 1)
endif () endif ()
if (NOT DEFINED WAMR_BUILD_DEBUG_INTERP)
# Disable Debug feature by default
set (WAMR_BUILD_DEBUG_INTERP 0)
endif ()
if (WAMR_BUILD_DEBUG_INTERP EQUAL 1)
set (WAMR_BUILD_FAST_INTERP 0)
set (WAMR_BUILD_MINI_LOADER 0)
set (WAMR_BUILD_SIMD 0)
endif ()
set (CMAKE_SHARED_LINKER_FLAGS "-Wl,-U,_get_ext_lib_export_apis") set (CMAKE_SHARED_LINKER_FLAGS "-Wl,-U,_get_ext_lib_export_apis")
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}") set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}")

View File

@ -90,6 +90,17 @@ if (NOT DEFINED WAMR_BUILD_REF_TYPES)
set (WAMR_BUILD_REF_TYPES 0) set (WAMR_BUILD_REF_TYPES 0)
endif () endif ()
if (NOT DEFINED WAMR_BUILD_DEBUG_INTERP)
# Disable Debug feature by default
set (WAMR_BUILD_DEBUG_INTERP 0)
endif ()
if (WAMR_BUILD_DEBUG_INTERP EQUAL 1)
set (WAMR_BUILD_FAST_INTERP 0)
set (WAMR_BUILD_MINI_LOADER 0)
set (WAMR_BUILD_SIMD 0)
endif ()
if (COLLECT_CODE_COVERAGE EQUAL 1) if (COLLECT_CODE_COVERAGE EQUAL 1)
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage") set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage")
endif () endif ()

View File

@ -49,6 +49,9 @@ print_help()
#endif #endif
#if WASM_ENABLE_LIB_PTHREAD != 0 #if WASM_ENABLE_LIB_PTHREAD != 0
printf(" --max-threads=n Set maximum thread number per cluster, default is 4\n"); printf(" --max-threads=n Set maximum thread number per cluster, default is 4\n");
#endif
#if WASM_ENABLE_DEBUG_INTERP != 0
printf(" -g=ip:port Set the debug sever address, default is debug disabled\n");
#endif #endif
return 1; return 1;
} }
@ -241,6 +244,11 @@ main(int argc, char *argv[])
const char *env_list[8] = { NULL }; const char *env_list[8] = { NULL };
uint32 env_list_size = 0; uint32 env_list_size = 0;
#endif #endif
#if WASM_ENABLE_DEBUG_INTERP != 0
char * ip_addr = NULL;
//int platform_port = 0;
int instance_port = 0;
#endif
/* Process options. */ /* Process options. */
for (argc--, argv++; argc > 0 && argv[0][0] == '-'; argc--, argv++) { for (argc--, argv++; argc > 0 && argv[0][0] == '-'; argc--, argv++) {
@ -321,6 +329,19 @@ main(int argc, char *argv[])
return print_help(); return print_help();
wasm_runtime_set_max_thread_num(atoi(argv[0] + 14)); wasm_runtime_set_max_thread_num(atoi(argv[0] + 14));
} }
#endif
#if WASM_ENABLE_DEBUG_INTERP != 0
else if (!strncmp(argv[0], "-g=", 3)) {
char * port_str = strchr(argv[0] + 3, ':');
char *port_end;
if (port_str == NULL)
return print_help();
*port_str = '\0';
instance_port = strtoul(port_str + 1, &port_end, 10);
if (port_str[1] == '\0' || *port_end != '\0')
return print_help();
ip_addr = argv[0] + 3;
}
#endif #endif
else else
return print_help(); return print_help();
@ -346,6 +367,13 @@ main(int argc, char *argv[])
init_args.mem_alloc_option.allocator.free_func = free; init_args.mem_alloc_option.allocator.free_func = free;
#endif #endif
#if WASM_ENABLE_DEBUG_INTERP != 0
init_args.platform_port = 0;
init_args.instance_port = instance_port;
if (ip_addr)
strcpy(init_args.ip_addr, ip_addr);
#endif
/* initialize runtime environment */ /* initialize runtime environment */
if (!wasm_runtime_full_init(&init_args)) { if (!wasm_runtime_full_init(&init_args)) {
printf("Init runtime environment failed.\n"); printf("Init runtime environment failed.\n");

View File

@ -59,6 +59,17 @@ if (NOT DEFINED WAMR_BUILD_LIBC_WASI)
set (WAMR_BUILD_LIBC_WASI 0) set (WAMR_BUILD_LIBC_WASI 0)
endif () endif ()
if (NOT DEFINED WAMR_BUILD_DEBUG_INTERP)
# Disable Debug feature by default
set (WAMR_BUILD_DEBUG_INTERP 0)
endif ()
if (WAMR_BUILD_DEBUG_INTERP EQUAL 1)
set (WAMR_BUILD_FAST_INTERP 0)
set (WAMR_BUILD_MINI_LOADER 0)
set (WAMR_BUILD_SIMD 0)
endif ()
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections")
set (WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../..) set (WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../..)

View File

@ -109,6 +109,9 @@ message ("-- CMAKE_BUILD_TYPE = " ${CMAKE_BUILD_TYPE})
if (CMAKE_BUILD_TYPE STREQUAL "Debug") if (CMAKE_BUILD_TYPE STREQUAL "Debug")
add_definitions(-DBH_DEBUG=1) add_definitions(-DBH_DEBUG=1)
endif () endif ()
if (WAMR_BUILD_DEBUG_AOT EQUAL 1)
add_definitions(-DWASM_ENABLE_DEBUG_AOT=1)
endif()
# Enable LLVM # Enable LLVM
if (NOT WAMR_BUILD_WITH_CUSTOM_LLVM) if (NOT WAMR_BUILD_WITH_CUSTOM_LLVM)
@ -133,6 +136,16 @@ add_definitions(${LLVM_DEFINITIONS})
message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")
if (WAMR_BUILD_DEBUG_AOT EQUAL 1)
if(LLVM_BUILD_MAIN_SRC_DIR)
include_directories(${LLVM_BUILD_MAIN_SRC_DIR}/../lldb/include)
include_directories(${LLVM_BUILD_BINARY_DIR}/tools/lldb/include)
endif()
link_directories(${LLVM_LIBRARY_DIRS})
find_library(lib_lldb NAMES lldb HINTS ${LLVM_LIBRARY_DIRS})
message(STATUS "find lldb ${LLDB_ALL_PLUGINS} in: ${LLVM_LIBRARY_DIRS}")
endif()
if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang")) if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang"))
if(NOT MSVC) if(NOT MSVC)
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections")
@ -212,7 +225,7 @@ add_library (aotclib ${IWASM_COMPL_SOURCE})
add_executable (wamrc main.c) add_executable (wamrc main.c)
if (NOT MSVC) if (NOT MSVC)
target_link_libraries (wamrc aotclib vmlib LLVMDemangle ${LLVM_AVAILABLE_LIBS} -lm -ldl -lpthread) target_link_libraries (wamrc aotclib vmlib LLVMDemangle ${LLVM_AVAILABLE_LIBS} -lm -ldl -lpthread ${lib_lldb})
else() else()
target_link_libraries (wamrc aotclib vmlib ${LLVM_AVAILABLE_LIBS}) target_link_libraries (wamrc aotclib vmlib ${lib_lldb} ${LLVM_AVAILABLE_LIBS})
endif() endif()

View File

@ -248,6 +248,12 @@ main(int argc, char *argv[])
goto fail3; goto fail3;
} }
#if WASM_ENABLE_DEBUG_AOT != 0
if (!create_dwarf_extractor(comp_data, wasm_file_name)) {
printf("%s:create dwarf extractor failed\n", wasm_file_name);
}
#endif
bh_print_time("Begin to create compile context"); bh_print_time("Begin to create compile context");
if (!(comp_ctx = aot_create_comp_context(comp_data, if (!(comp_ctx = aot_create_comp_context(comp_data,