mirror of
https://github.com/bytecodealliance/wasm-micro-runtime.git
synced 2024-11-26 07:21:54 +00:00
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:
parent
b5a67cb91e
commit
9ef37dd781
|
@ -28,6 +28,7 @@ iwasm VM core
|
|||
- [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)
|
||||
- [Linux SGX (Intel Software Guard Extension) support](./doc/linux_sgx.md)
|
||||
- [Source debugging](./doc/source_debugging.md)
|
||||
|
||||
### post-MVP features
|
||||
- [Non-trapping float-to-int conversions](https://github.com/WebAssembly/nontrapping-float-to-int-conversions)
|
||||
|
|
|
@ -239,3 +239,9 @@ endif ()
|
|||
if (WAMR_DISABLE_APP_ENTRY EQUAL 1)
|
||||
message (" WAMR application entry functions excluded")
|
||||
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 ()
|
||||
|
|
5779
build-scripts/lldb-wasm.patch
Normal file
5779
build-scripts/lldb-wasm.patch
Normal file
File diff suppressed because it is too large
Load Diff
|
@ -84,6 +84,11 @@ if (WAMR_BUILD_LIB_PTHREAD EQUAL 1)
|
|||
set (WAMR_BUILD_SHARED_MEMORY 1)
|
||||
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)
|
||||
include (${IWASM_DIR}/libraries/thread-mgr/thread_mgr.cmake)
|
||||
endif ()
|
||||
|
@ -132,6 +137,7 @@ set (source_all
|
|||
${LIB_PTHREAD_SOURCE}
|
||||
${THREAD_MGR_SOURCE}
|
||||
${LIBC_EMCC_SOURCE}
|
||||
${DEBUG_ENGINE_SOURCE}
|
||||
)
|
||||
|
||||
set (WAMR_RUNTIME_LIB_SOURCE ${source_all})
|
||||
|
|
|
@ -14,6 +14,10 @@
|
|||
#include "../compilation/aot_llvm.h"
|
||||
#include "../interpreter/wasm_loader.h"
|
||||
#endif
|
||||
#if WASM_ENABLE_DEBUG_AOT != 0
|
||||
#include "debug/elf_parser.h"
|
||||
#include "debug/jit_debug.h"
|
||||
#endif
|
||||
|
||||
#define XMM_PLT_PREFIX "__xmm@"
|
||||
#define REAL_PLT_PREFIX "__real@"
|
||||
|
@ -1231,7 +1235,6 @@ load_init_data_section(const uint8 *buf, const uint8 *buf_end,
|
|||
}
|
||||
|
||||
return true;
|
||||
|
||||
fail:
|
||||
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_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)) {
|
||||
plt_base = (uint8 *)buf_end - get_plt_table_size();
|
||||
init_plt_table(plt_base);
|
||||
}
|
||||
return true;
|
||||
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
@ -1451,7 +1472,6 @@ load_export_section(const uint8 *buf, const uint8 *buf_end,
|
|||
}
|
||||
|
||||
return true;
|
||||
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
@ -2247,6 +2267,13 @@ load_from_sections(AOTModule *module, AOTSection *sections,
|
|||
#if WASM_ENABLE_MEMORY_TRACING != 0
|
||||
wasm_runtime_dump_module_mem_consumption((WASMModuleCommon*)module);
|
||||
#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;
|
||||
}
|
||||
|
||||
|
@ -2893,6 +2920,9 @@ aot_unload(AOTModule *module)
|
|||
if (module->data_sections)
|
||||
destroy_object_data_sections(module->data_sections,
|
||||
module->data_section_count);
|
||||
#if WASM_ENABLE_DEBUG_AOT != 0
|
||||
jit_code_entry_destroy(module->elf_hdr);
|
||||
#endif
|
||||
|
||||
wasm_runtime_free(module);
|
||||
}
|
||||
|
|
|
@ -254,6 +254,10 @@ typedef struct AOTModule {
|
|||
WASIArguments wasi_args;
|
||||
bool is_wasi_module;
|
||||
#endif
|
||||
#if WASM_ENABLE_DEBUG_AOT != 0
|
||||
void *elf_hdr;
|
||||
uint32 elf_size;
|
||||
#endif
|
||||
} AOTModule;
|
||||
|
||||
typedef union {
|
||||
|
|
152
core/iwasm/aot/debug/elf_parser.c
Normal file
152
core/iwasm/aot/debug/elf_parser.c
Normal 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;
|
||||
}
|
27
core/iwasm/aot/debug/elf_parser.h
Normal file
27
core/iwasm/aot/debug/elf_parser.h
Normal 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
|
253
core/iwasm/aot/debug/jit_debug.c
Normal file
253
core/iwasm/aot/debug/jit_debug.c
Normal 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;
|
||||
}
|
||||
}
|
29
core/iwasm/aot/debug/jit_debug.h
Normal file
29
core/iwasm/aot/debug/jit_debug.h
Normal 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
|
|
@ -31,5 +31,10 @@ else ()
|
|||
message (FATAL_ERROR "Build target isn't set")
|
||||
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})
|
||||
|
||||
|
|
|
@ -18,6 +18,9 @@
|
|||
|
||||
#if WASM_ENABLE_THREAD_MGR != 0
|
||||
#include "../libraries/thread-mgr/thread_manager.h"
|
||||
#if WASM_ENABLE_DEBUG_INTERP != 0
|
||||
#include "../libraries/debug-engine/debug_engine.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
WASMExecEnv *
|
||||
|
@ -46,6 +49,12 @@ wasm_exec_env_create_internal(struct WASMModuleInstanceCommon *module_inst,
|
|||
|
||||
if (os_cond_init(&exec_env->wait_cond) != 0)
|
||||
goto fail3;
|
||||
|
||||
#if WASM_ENABLE_DEBUG_INTERP != 0
|
||||
if (!(exec_env->current_status = wasm_cluster_create_exenv_status()))
|
||||
goto fail4;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
exec_env->module_inst = module_inst;
|
||||
|
@ -68,6 +77,10 @@ wasm_exec_env_create_internal(struct WASMModuleInstanceCommon *module_inst,
|
|||
return exec_env;
|
||||
|
||||
#if WASM_ENABLE_THREAD_MGR != 0
|
||||
#if WASM_ENABLE_DEBUG_INTERP != 0
|
||||
fail4:
|
||||
os_cond_destroy(&exec_env->wait_cond);
|
||||
#endif
|
||||
fail3:
|
||||
os_mutex_destroy(&exec_env->wait_lock);
|
||||
fail2:
|
||||
|
@ -86,6 +99,9 @@ wasm_exec_env_destroy_internal(WASMExecEnv *exec_env)
|
|||
#if WASM_ENABLE_THREAD_MGR != 0
|
||||
os_mutex_destroy(&exec_env->wait_lock);
|
||||
os_cond_destroy(&exec_env->wait_cond);
|
||||
#if WASM_ENABLE_DEBUG_INTERP != 0
|
||||
wasm_cluster_destroy_exenv_status(exec_env->current_status);
|
||||
#endif
|
||||
#endif
|
||||
#if WASM_ENABLE_AOT != 0
|
||||
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);
|
||||
return NULL;
|
||||
}
|
||||
#if WASM_ENABLE_DEBUG_INTERP != 0
|
||||
wasm_debug_instance_create(cluster);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
return exec_env;
|
||||
}
|
||||
|
@ -142,6 +162,12 @@ wasm_exec_env_destroy(WASMExecEnv *exec_env)
|
|||
/* Terminate all sub-threads */
|
||||
WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env);
|
||||
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_del_exec_env(cluster, exec_env);
|
||||
}
|
||||
|
|
|
@ -20,6 +20,9 @@ struct WASMInterpFrame;
|
|||
|
||||
#if WASM_ENABLE_THREAD_MGR != 0
|
||||
typedef struct WASMCluster WASMCluster;
|
||||
#if WASM_ENABLE_DEBUG_INTERP != 0
|
||||
typedef struct WASMCurrentEnvStatus WASMCurrentEnvStatus;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef OS_ENABLE_HW_BOUND_CHECK
|
||||
|
@ -97,6 +100,10 @@ typedef struct WASMExecEnv {
|
|||
korp_cond wait_cond;
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_DEBUG_INTERP != 0
|
||||
WASMCurrentEnvStatus *current_status;
|
||||
#endif
|
||||
|
||||
/* attachment for native function */
|
||||
void *attachment;
|
||||
|
||||
|
|
|
@ -14,9 +14,15 @@
|
|||
#endif
|
||||
#if WASM_ENABLE_AOT != 0
|
||||
#include "../aot/aot_runtime.h"
|
||||
#if WASM_ENABLE_DEBUG_AOT != 0
|
||||
#include "../aot/debug/jit_debug.h"
|
||||
#endif
|
||||
#endif
|
||||
#if WASM_ENABLE_THREAD_MGR != 0
|
||||
#include "../libraries/thread-mgr/thread_manager.h"
|
||||
#if WASM_ENABLE_DEBUG_INTERP != 0
|
||||
#include "../libraries/debug-engine/debug_engine.h"
|
||||
#endif
|
||||
#endif
|
||||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||
#include "wasm_shared_memory.h"
|
||||
|
@ -128,20 +134,29 @@ wasm_runtime_env_init()
|
|||
goto fail6;
|
||||
}
|
||||
#endif
|
||||
#if WASM_ENABLE_DEBUG_AOT != 0
|
||||
if (!jit_debug_engine_init()) {
|
||||
goto fail7;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_REF_TYPES != 0
|
||||
if (!wasm_externref_map_init()) {
|
||||
goto fail7;
|
||||
goto fail8;
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
|
||||
#if WASM_ENABLE_REF_TYPES != 0
|
||||
fail7:
|
||||
fail8:
|
||||
#endif
|
||||
#if WASM_ENABLE_AOT != 0
|
||||
#if WASM_ENABLE_DEBUG_AOT != 0
|
||||
jit_debug_engine_destroy();
|
||||
fail7:
|
||||
#endif
|
||||
#ifdef OS_ENABLE_HW_BOUND_CHECK
|
||||
aot_signal_destroy();
|
||||
fail6:
|
||||
|
@ -201,6 +216,9 @@ wasm_runtime_destroy()
|
|||
#endif
|
||||
|
||||
#if WASM_ENABLE_AOT != 0
|
||||
#if WASM_ENABLE_DEBUG_AOT != 0
|
||||
jit_debug_engine_destroy();
|
||||
#endif
|
||||
#ifdef OS_ENABLE_HW_BOUND_CHECK
|
||||
aot_signal_destroy();
|
||||
#endif
|
||||
|
@ -220,6 +238,9 @@ wasm_runtime_destroy()
|
|||
#endif
|
||||
|
||||
#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();
|
||||
#endif
|
||||
|
||||
|
@ -241,6 +262,16 @@ wasm_runtime_full_init(RuntimeInitArgs *init_args)
|
|||
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
|
||||
&& !wasm_runtime_register_natives(init_args->native_module_name,
|
||||
init_args->native_symbols,
|
||||
|
|
|
@ -774,24 +774,24 @@ wasm_runtime_finalize_call_function(WASMExecEnv *exec_env,
|
|||
|
||||
bool
|
||||
wasm_runtime_get_export_func_type(const WASMModuleCommon *module_comm,
|
||||
const WASMExport *export_func_type,
|
||||
const WASMExport *export_,
|
||||
WASMType **out);
|
||||
|
||||
bool
|
||||
wasm_runtime_get_export_global_type(const WASMModuleCommon *module_comm,
|
||||
const WASMExport *export_global_type,
|
||||
const WASMExport *export_,
|
||||
uint8 *out_val_type,
|
||||
bool *out_mutability);
|
||||
|
||||
bool
|
||||
wasm_runtime_get_export_memory_type(const WASMModuleCommon *module_comm,
|
||||
const WASMExport *export_memory_type,
|
||||
const WASMExport *export_,
|
||||
uint32 *out_min_page,
|
||||
uint32 *out_max_page);
|
||||
|
||||
bool
|
||||
wasm_runtime_get_export_table_type(const WASMModuleCommon *module_comm,
|
||||
const WASMExport *export_table_type,
|
||||
const WASMExport *export_,
|
||||
uint8 *out_elem_type,
|
||||
uint32 *out_min_size,
|
||||
uint32 *out_max_size);
|
||||
|
|
|
@ -21,6 +21,10 @@ typedef InitializerExpression AOTInitExpr;
|
|||
typedef WASMType AOTFuncType;
|
||||
typedef WASMExport AOTExport;
|
||||
|
||||
#if WASM_ENABLE_DEBUG_AOT != 0
|
||||
typedef void * dwar_extractor_handle_t;
|
||||
#endif
|
||||
|
||||
typedef enum AOTIntCond {
|
||||
INT_EQZ = 0,
|
||||
INT_EQ,
|
||||
|
@ -251,6 +255,9 @@ typedef struct AOTCompData {
|
|||
uint32 aux_stack_size;
|
||||
|
||||
WASMModule *wasm_module;
|
||||
#if WASM_ENABLE_DEBUG_AOT != 0
|
||||
dwar_extractor_handle_t extractor;
|
||||
#endif
|
||||
} AOTCompData;
|
||||
|
||||
typedef struct AOTNativeSymbol {
|
||||
|
|
|
@ -32,6 +32,9 @@
|
|||
#include "../interpreter/wasm_opcode.h"
|
||||
#include <errno.h>
|
||||
|
||||
#if WASM_ENABLE_DEBUG_AOT != 0
|
||||
#include "debug/dwarf_extractor.h"
|
||||
#endif
|
||||
|
||||
#define CHECK_BUF(buf, buf_end, length) do { \
|
||||
if (buf + length > buf_end) { \
|
||||
|
@ -153,6 +156,9 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
|
|||
float32 f32_const;
|
||||
float64 f64_const;
|
||||
AOTFuncType *func_type = NULL;
|
||||
#if WASM_ENABLE_DEBUG_AOT != 0
|
||||
LLVMMetadataRef location;
|
||||
#endif
|
||||
|
||||
/* Start to translate the opcodes */
|
||||
LLVMPositionBuilderAtEnd(comp_ctx->builder,
|
||||
|
@ -160,6 +166,15 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
|
|||
->llvm_entry_block);
|
||||
while (frame_ip < frame_ip_end) {
|
||||
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) {
|
||||
case WASM_OP_UNREACHABLE:
|
||||
if (!aot_compile_op_unreachable(comp_ctx, func_ctx, &frame_ip))
|
||||
|
@ -2440,6 +2455,10 @@ aot_compile_wasm(AOTCompContext *comp_ctx)
|
|||
errno = 0;
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_DEBUG_AOT != 0
|
||||
LLVMDIBuilderFinalize(comp_ctx->debug_builder);
|
||||
#endif
|
||||
|
||||
bh_print_time("Begin to verify LLVM module");
|
||||
|
||||
ret = LLVMVerifyModule(comp_ctx->module, LLVMPrintMessageAction, &msg);
|
||||
|
|
|
@ -1757,22 +1757,34 @@ aot_resolve_target_info(AOTCompContext *comp_ctx, AOTObjectData *obj_data)
|
|||
static bool
|
||||
aot_resolve_text(AOTObjectData *obj_data)
|
||||
{
|
||||
LLVMSectionIteratorRef sec_itr;
|
||||
char *name;
|
||||
#if WASM_ENABLE_DEBUG_AOT != 0
|
||||
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))) {
|
||||
aot_set_last_error("llvm get section iterator failed.");
|
||||
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;
|
||||
if (!(sec_itr = LLVMObjectFileCopySectionIterator(obj_data->binary))) {
|
||||
aot_set_last_error("llvm get section iterator failed.");
|
||||
return false;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -8,6 +8,10 @@
|
|||
#include "../aot/aot_runtime.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_suffix[] = { "begin", "else", "end" };
|
||||
|
||||
|
@ -158,14 +162,22 @@ handle_next_reachable_block(AOTCompContext *comp_ctx,
|
|||
uint8 *frame_ip = NULL;
|
||||
uint32 i;
|
||||
AOTFuncType *func_type;
|
||||
LLVMValueRef ret;
|
||||
#if WASM_ENABLE_DEBUG_AOT != 0
|
||||
LLVMMetadataRef return_location;
|
||||
#endif
|
||||
|
||||
aot_checked_addr_list_destroy(func_ctx);
|
||||
|
||||
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
|
||||
&& block->llvm_else_block
|
||||
&& !block->skip_wasm_code_else
|
||||
&& *p_frame_ip <= block->wasm_code_else) {
|
||||
/* Clear value stack and start to translate else branch */
|
||||
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->result_count) {
|
||||
/* 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.");
|
||||
goto fail;
|
||||
}
|
||||
#if WASM_ENABLE_DEBUG_AOT != 0
|
||||
LLVMInstructionSetDebugLoc(ret, return_location);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
if (!LLVMBuildRetVoid(comp_ctx->builder)) {
|
||||
if (!(ret = LLVMBuildRetVoid(comp_ctx->builder))) {
|
||||
aot_set_last_error("llvm build return void failed.");
|
||||
goto fail;
|
||||
}
|
||||
#if WASM_ENABLE_DEBUG_AOT != 0
|
||||
LLVMInstructionSetDebugLoc(ret, return_location);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
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));
|
||||
|
||||
/* 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,
|
||||
&else_addr, &end_addr))) {
|
||||
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 */
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -1070,12 +1089,22 @@ aot_compile_op_return(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
|||
{
|
||||
AOTBlock *block_func = func_ctx->block_stack.block_list_head;
|
||||
LLVMValueRef value;
|
||||
LLVMValueRef ret;
|
||||
AOTFuncType *func_type;
|
||||
uint32 i, param_index, result_index;
|
||||
#if WASM_ENABLE_DEBUG_AOT != 0
|
||||
LLVMMetadataRef return_location;
|
||||
#endif
|
||||
|
||||
bh_assert(block_func);
|
||||
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) {
|
||||
/* Store extra result values to function parameters */
|
||||
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 */
|
||||
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.");
|
||||
goto fail;
|
||||
}
|
||||
#if WASM_ENABLE_DEBUG_AOT != 0
|
||||
LLVMInstructionSetDebugLoc(ret, return_location);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
if (!LLVMBuildRetVoid(comp_ctx->builder)) {
|
||||
if (!(ret = LLVMBuildRetVoid(comp_ctx->builder))) {
|
||||
aot_set_last_error("llvm build return void failed.");
|
||||
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);
|
||||
|
|
|
@ -109,7 +109,7 @@ aot_emit_exception(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
|||
|
||||
/* Create return IR */
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ create_func_return_block(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
|
|||
|
||||
/* Create return IR */
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -313,7 +313,7 @@ call_aot_alloc_frame_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
|||
/* If frame alloc failed, return this function
|
||||
so the runtime can catch the exception */
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -897,7 +897,7 @@ aot_compile_op_memory_init(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
|||
/* If memory.init failed, return this function
|
||||
so the runtime can catch the exception */
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -1231,7 +1231,7 @@ aot_compile_op_atomic_wait(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
|||
/* If atomic wait failed, return this function
|
||||
so the runtime can catch the exception */
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,10 @@
|
|||
#include "../aot/aot_runtime.h"
|
||||
#include "../aot/aot_intrinsic.h"
|
||||
|
||||
#if WASM_ENABLE_DEBUG_AOT != 0
|
||||
#include "debug/dwarf_extractor.h"
|
||||
#endif
|
||||
|
||||
LLVMTypeRef
|
||||
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)))
|
||||
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);
|
||||
|
||||
/* Add local variables */
|
||||
|
@ -1462,6 +1470,29 @@ aot_create_comp_context(AOTCompData *comp_data,
|
|||
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)
|
||||
comp_ctx->enable_bulk_memory = true;
|
||||
|
||||
|
@ -2213,6 +2244,7 @@ aot_checked_addr_list_destroy(AOTFuncContext *func_ctx)
|
|||
|
||||
bool
|
||||
aot_build_zero_function_ret(AOTCompContext *comp_ctx,
|
||||
AOTFuncContext *func_ctx,
|
||||
AOTFuncType *func_type)
|
||||
{
|
||||
LLVMValueRef ret = NULL;
|
||||
|
@ -2251,6 +2283,10 @@ aot_build_zero_function_ret(AOTCompContext *comp_ctx,
|
|||
aot_set_last_error("llvm build ret failed.");
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,9 @@
|
|||
#include "llvm-c/Initialization.h"
|
||||
#include "llvm-c/Support.h"
|
||||
#endif
|
||||
#if WASM_ENABLE_DEBUG_AOT != 0
|
||||
#include "llvm-c/DebugInfo.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
@ -148,6 +151,9 @@ typedef struct AOTFuncContext {
|
|||
LLVMBasicBlockRef func_return_block;
|
||||
LLVMValueRef exception_id_phi;
|
||||
LLVMValueRef func_type_indexes;
|
||||
#if WASM_ENABLE_DEBUG_AOT != 0
|
||||
LLVMMetadataRef debug_func;
|
||||
#endif
|
||||
LLVMValueRef locals[1];
|
||||
} AOTFuncContext;
|
||||
|
||||
|
@ -245,6 +251,11 @@ typedef struct AOTCompContext {
|
|||
LLVMContextRef context;
|
||||
LLVMModuleRef module;
|
||||
LLVMBuilderRef builder;
|
||||
#if WASM_ENABLE_DEBUG_AOT
|
||||
LLVMDIBuilderRef debug_builder;
|
||||
LLVMMetadataRef debug_file;
|
||||
LLVMMetadataRef debug_comp_unit;
|
||||
#endif
|
||||
LLVMTargetMachineRef target_machine;
|
||||
char *target_cpu;
|
||||
char target_arch[16];
|
||||
|
@ -407,6 +418,7 @@ aot_checked_addr_list_destroy(AOTFuncContext *func_ctx);
|
|||
|
||||
bool
|
||||
aot_build_zero_function_ret(AOTCompContext *comp_ctx,
|
||||
AOTFuncContext *func_ctx,
|
||||
AOTFuncType *func_type);
|
||||
|
||||
LLVMValueRef
|
||||
|
|
530
core/iwasm/compilation/debug/dwarf_extractor.cpp
Normal file
530
core/iwasm/compilation/debug/dwarf_extractor.cpp
Normal 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;
|
||||
}
|
58
core/iwasm/compilation/debug/dwarf_extractor.h
Normal file
58
core/iwasm/compilation/debug/dwarf_extractor.h
Normal 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
|
|
@ -2,9 +2,17 @@ set (IWASM_COMPL_DIR ${CMAKE_CURRENT_LIST_DIR})
|
|||
|
||||
include_directories(${IWASM_COMPL_DIR})
|
||||
|
||||
file (GLOB_RECURSE source_all
|
||||
${IWASM_COMPL_DIR}/*.c
|
||||
${IWASM_COMPL_DIR}/*.cpp)
|
||||
if (WAMR_BUILD_DEBUG_AOT EQUAL 1)
|
||||
file (GLOB_RECURSE source_all
|
||||
${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})
|
||||
|
||||
|
|
|
@ -26,6 +26,12 @@ aot_create_comp_data(void *wasm_module);
|
|||
void
|
||||
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 {
|
||||
AOT_FORMAT_FILE,
|
||||
AOT_OBJECT_FILE,
|
||||
|
|
|
@ -133,6 +133,11 @@ typedef struct RuntimeInitArgs {
|
|||
/* maximum thread number, only used when
|
||||
WASM_ENABLE_THREAD_MGR is defined */
|
||||
uint32_t max_thread_num;
|
||||
#if WASM_ENABLE_DEBUG_INTERP != 0
|
||||
char ip_addr[128];
|
||||
int platform_port;
|
||||
int instance_port;
|
||||
#endif
|
||||
} RuntimeInitArgs;
|
||||
|
||||
#ifndef WASM_VALKIND_T_DEFINED
|
||||
|
|
|
@ -316,6 +316,13 @@ typedef struct StringNode {
|
|||
char *str;
|
||||
} StringNode, *StringList;
|
||||
|
||||
#if WASM_ENABLE_DEBUG_INTERP != 0
|
||||
typedef struct WASMFastOPCodeNode {
|
||||
struct WASMFastOPCodeNode *next;
|
||||
uint64 offset;
|
||||
uint8 orig_op;
|
||||
} WASMFastOPCodeNode;
|
||||
#endif
|
||||
struct WASMModule {
|
||||
/* Module type, for module loaded from WASM bytecode binary,
|
||||
this field is Wasm_Module_Bytecode;
|
||||
|
@ -404,6 +411,13 @@ struct WASMModule {
|
|||
bh_list import_module_list_head;
|
||||
bh_list *import_module_list;
|
||||
#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 {
|
||||
|
|
|
@ -12,6 +12,9 @@
|
|||
#if WASM_ENABLE_SHARED_MEMORY != 0
|
||||
#include "../common/wasm_shared_memory.h"
|
||||
#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 int64 CellType_I64;
|
||||
|
@ -848,27 +851,70 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst,
|
|||
#endif
|
||||
|
||||
#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 { \
|
||||
if (exec_env->suspend_flags.flags != 0) { \
|
||||
if (exec_env->suspend_flags.flags & 0x01) { \
|
||||
/* terminate current thread */ \
|
||||
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)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_LABELS_AS_VALUES != 0
|
||||
|
||||
#define HANDLE_OP(opcode) HANDLE_##opcode
|
||||
#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()
|
||||
#endif
|
||||
|
||||
#else /* else of WASM_ENABLE_LABELS_AS_VALUES */
|
||||
|
||||
#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
|
||||
#endif
|
||||
|
||||
#endif /* end of WASM_ENABLE_LABELS_AS_VALUES */
|
||||
|
||||
|
@ -941,6 +987,16 @@ handle_op_block:
|
|||
else if (cache_items[1].start_addr == frame_ip) {
|
||||
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 {
|
||||
end_addr = NULL;
|
||||
}
|
||||
|
@ -978,7 +1034,8 @@ handle_op_if:
|
|||
else_addr = cache_items[1].else_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,
|
||||
LABEL_TYPE_IF,
|
||||
&else_addr, &end_addr)) {
|
||||
|
@ -1030,7 +1087,8 @@ handle_op_if:
|
|||
label_pop_csp_n:
|
||||
POP_CSP_N(depth);
|
||||
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,
|
||||
LABEL_TYPE_BLOCK,
|
||||
&else_addr, &end_addr)) {
|
||||
|
@ -3178,7 +3236,17 @@ label_pop_csp_n:
|
|||
frame_sp = frame->sp;
|
||||
frame_csp = frame->csp;
|
||||
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
|
||||
default:
|
||||
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);
|
||||
|
||||
wasm_exec_env_set_cur_frame(exec_env, (WASMRuntimeFrame*)frame);
|
||||
#if WASM_ENABLE_THREAD_MGR != 0
|
||||
CHECK_SUSPEND_FLAGS();
|
||||
#endif
|
||||
}
|
||||
HANDLE_OP_END ();
|
||||
}
|
||||
|
|
|
@ -10,6 +10,9 @@
|
|||
#include "wasm_opcode.h"
|
||||
#include "wasm_runtime.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
|
||||
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) {
|
||||
buf_code = section->section_body;
|
||||
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) {
|
||||
buf_func = section->section_body;
|
||||
|
@ -3296,10 +3303,26 @@ create_module(char *error_buf, uint32 error_buf_size)
|
|||
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
module->import_module_list = &module->import_module_list_head;
|
||||
#endif
|
||||
#if WASM_ENABLE_DEBUG_INTERP != 0
|
||||
bh_list_init(&module->fast_opcode_list);
|
||||
#endif
|
||||
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 *
|
||||
wasm_loader_load_from_sections(WASMSection *section_list,
|
||||
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;
|
||||
}
|
||||
|
||||
#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)) {
|
||||
goto fail;
|
||||
}
|
||||
|
@ -3593,7 +3621,6 @@ wasm_loader_unload(WASMModule *module)
|
|||
*/
|
||||
wasm_runtime_free(node);
|
||||
/*
|
||||
*
|
||||
* the module file reading buffer will be released
|
||||
* in runtime_destroy()
|
||||
*/
|
||||
|
@ -3601,12 +3628,21 @@ wasm_loader_unload(WASMModule *module)
|
|||
}
|
||||
}
|
||||
#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);
|
||||
}
|
||||
|
||||
bool
|
||||
wasm_loader_find_block_addr(BlockAddr *block_addr_cache,
|
||||
wasm_loader_find_block_addr(WASMExecEnv *exec_env,
|
||||
BlockAddr *block_addr_cache,
|
||||
const uint8 *start_addr,
|
||||
const uint8 *code_end_addr,
|
||||
uint8 label_type,
|
||||
|
@ -3638,7 +3674,9 @@ wasm_loader_find_block_addr(BlockAddr *block_addr_cache,
|
|||
|
||||
while (p < code_end_addr) {
|
||||
opcode = *p++;
|
||||
|
||||
#if WASM_ENABLE_DEBUG_INTERP != 0
|
||||
op_break_retry:
|
||||
#endif
|
||||
switch (opcode) {
|
||||
case WASM_OP_UNREACHABLE:
|
||||
case WASM_OP_NOP:
|
||||
|
@ -4156,6 +4194,31 @@ wasm_loader_find_block_addr(BlockAddr *block_addr_cache,
|
|||
break;
|
||||
}
|
||||
#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:
|
||||
return false;
|
||||
|
@ -6317,6 +6380,9 @@ handle_op_block_and_loop:
|
|||
* to new extended opcode so that interpreter can resolve the
|
||||
* 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);
|
||||
#endif
|
||||
}
|
||||
|
@ -7196,13 +7262,28 @@ handle_op_block_and_loop:
|
|||
#else
|
||||
#if (WASM_ENABLE_WAMR_COMPILER == 0) && (WASM_ENABLE_JIT == 0)
|
||||
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;
|
||||
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;
|
||||
else
|
||||
}
|
||||
else {
|
||||
#if WASM_ENABLE_DEBUG_INTERP != 0
|
||||
record_fast_op(module, p_org, *p_org);
|
||||
#endif
|
||||
*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;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
@ -7254,13 +7335,28 @@ handle_op_block_and_loop:
|
|||
#else
|
||||
#if (WASM_ENABLE_WAMR_COMPILER == 0) && (WASM_ENABLE_JIT == 0)
|
||||
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;
|
||||
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;
|
||||
else
|
||||
}
|
||||
else {
|
||||
#if WASM_ENABLE_DEBUG_INTERP != 0
|
||||
record_fast_op(module, p_org, *p_org);
|
||||
#endif
|
||||
*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;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
@ -7309,13 +7405,28 @@ handle_op_block_and_loop:
|
|||
#else
|
||||
#if (WASM_ENABLE_WAMR_COMPILER == 0) && (WASM_ENABLE_JIT == 0)
|
||||
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;
|
||||
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;
|
||||
else
|
||||
}
|
||||
else {
|
||||
#if WASM_ENABLE_DEBUG_INTERP != 0
|
||||
record_fast_op(module, p_org, *p_org);
|
||||
#endif
|
||||
*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;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
@ -7344,6 +7455,9 @@ handle_op_block_and_loop:
|
|||
#if (WASM_ENABLE_WAMR_COMPILER == 0) && (WASM_ENABLE_JIT == 0)
|
||||
if (global_type == VALUE_TYPE_I64
|
||||
|| 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;
|
||||
}
|
||||
#endif
|
||||
|
@ -7393,10 +7507,16 @@ handle_op_block_and_loop:
|
|||
#if WASM_ENABLE_FAST_INTERP == 0
|
||||
if (global_type == VALUE_TYPE_I64
|
||||
|| 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;
|
||||
}
|
||||
else if (module->aux_stack_size > 0
|
||||
&& 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;
|
||||
}
|
||||
#else /* else of WASM_ENABLE_FAST_INTERP */
|
||||
|
|
|
@ -62,8 +62,10 @@ wasm_loader_unload(WASMModule *module);
|
|||
*
|
||||
* @return true if success, false otherwise
|
||||
*/
|
||||
|
||||
bool
|
||||
wasm_loader_find_block_addr(BlockAddr *block_addr_cache,
|
||||
wasm_loader_find_block_addr(WASMExecEnv *exec_env,
|
||||
BlockAddr *block_addr_cache,
|
||||
const uint8 *start_addr,
|
||||
const uint8 *code_end_addr,
|
||||
uint8 block_type,
|
||||
|
|
|
@ -267,6 +267,10 @@ typedef enum WASMOpcode {
|
|||
EXT_OP_LOOP = 0xd4, /* loop 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 */
|
||||
WASM_OP_MISC_PREFIX = 0xfc,
|
||||
WASM_OP_SIMD_PREFIX = 0xfd,
|
||||
|
@ -673,6 +677,14 @@ typedef enum WASMAtomicEXTOpcode {
|
|||
}
|
||||
#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.
|
||||
*/
|
||||
|
@ -900,6 +912,7 @@ do { \
|
|||
HANDLE_OPCODE (WASM_OP_MISC_PREFIX); /* 0xfc */ \
|
||||
_name[WASM_OP_ATOMIC_PREFIX] = \
|
||||
HANDLE_OPCODE (WASM_OP_ATOMIC_PREFIX); /* 0xfe */ \
|
||||
DEF_DEBUG_BREAK_HANDLE(_name) \
|
||||
} while (0)
|
||||
#endif /* end of _WASM_OPCODE_H */
|
||||
|
||||
|
|
|
@ -16,6 +16,9 @@
|
|||
#if WASM_ENABLE_THREAD_MGR != 0
|
||||
#include "../libraries/thread-mgr/thread_manager.h"
|
||||
#endif
|
||||
#if WASM_ENABLE_DEBUG_INTERP != 0
|
||||
#include "../libraries/debug-engine/debug_engine.h"
|
||||
#endif
|
||||
|
||||
static void
|
||||
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
|
||||
&& 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,
|
||||
module_inst->malloc_function,
|
||||
module_inst->retain_function,
|
||||
size, &offset)) {
|
||||
#if WASM_ENABLE_DEBUG_INTERP != 0
|
||||
wasm_debug_set_engine_active(active);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
#if WASM_ENABLE_DEBUG_INTERP != 0
|
||||
wasm_debug_set_engine_active(active);
|
||||
#endif
|
||||
/* 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;
|
||||
addr = offset ? memory->memory_data + offset : NULL;
|
||||
}
|
||||
|
@ -1915,9 +1934,19 @@ wasm_module_free(WASMModuleInstance *module_inst, uint32 ptr)
|
|||
&& module_inst->free_function
|
||||
&& memory->memory_data <= addr
|
||||
&& 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,
|
||||
module_inst->free_function,
|
||||
ptr);
|
||||
#if WASM_ENABLE_DEBUG_INTERP != 0
|
||||
wasm_debug_set_engine_active(active);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
1011
core/iwasm/libraries/debug-engine/debug_engine.c
Normal file
1011
core/iwasm/libraries/debug-engine/debug_engine.c
Normal file
File diff suppressed because it is too large
Load Diff
12
core/iwasm/libraries/debug-engine/debug_engine.cmake
Normal file
12
core/iwasm/libraries/debug-engine/debug_engine.cmake
Normal 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})
|
193
core/iwasm/libraries/debug-engine/debug_engine.h
Normal file
193
core/iwasm/libraries/debug-engine/debug_engine.h
Normal 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
|
177
core/iwasm/libraries/debug-engine/gdbserver.c
Normal file
177
core/iwasm/libraries/debug-engine/gdbserver.c
Normal 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;
|
||||
}
|
43
core/iwasm/libraries/debug-engine/gdbserver.h
Normal file
43
core/iwasm/libraries/debug-engine/gdbserver.h
Normal 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
|
598
core/iwasm/libraries/debug-engine/handler.c
Normal file
598
core/iwasm/libraries/debug-engine/handler.c
Normal 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 *)®data, 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);
|
||||
}
|
||||
}
|
55
core/iwasm/libraries/debug-engine/handler.h
Normal file
55
core/iwasm/libraries/debug-engine/handler.h
Normal 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
|
173
core/iwasm/libraries/debug-engine/packets.c
Normal file
173
core/iwasm/libraries/debug-engine/packets.c
Normal 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;
|
||||
}
|
22
core/iwasm/libraries/debug-engine/packets.h
Normal file
22
core/iwasm/libraries/debug-engine/packets.h
Normal 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
|
45
core/iwasm/libraries/debug-engine/utils.c
Normal file
45
core/iwasm/libraries/debug-engine/utils.c
Normal 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);
|
||||
}
|
23
core/iwasm/libraries/debug-engine/utils.h
Normal file
23
core/iwasm/libraries/debug-engine/utils.h
Normal 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 */
|
|
@ -484,6 +484,119 @@ fail1:
|
|||
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
|
||||
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);
|
||||
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 */
|
||||
/* Free aux stack space */
|
||||
free_aux_stack(cluster, exec_env->aux_stack_bottom.bottom);
|
||||
|
@ -537,8 +653,13 @@ int32
|
|||
wasm_cluster_cancel_thread(WASMExecEnv *exec_env)
|
||||
{
|
||||
/* 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;
|
||||
return 0;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -621,6 +742,7 @@ void
|
|||
wasm_cluster_resume_thread(WASMExecEnv *exec_env)
|
||||
{
|
||||
exec_env->suspend_flags.flags &= ~0x02;
|
||||
os_cond_signal(&exec_env->wait_cond);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -15,7 +15,63 @@
|
|||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#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
|
||||
{
|
||||
struct WASMCluster *next;
|
||||
|
|
86
doc/source_debugging.md
Normal file
86
doc/source_debugging.md
Normal 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***
|
|
@ -82,6 +82,17 @@ if (NOT DEFINED WAMR_BUILD_SIMD)
|
|||
set (WAMR_BUILD_SIMD 1)
|
||||
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_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}")
|
||||
|
||||
|
|
|
@ -90,6 +90,17 @@ if (NOT DEFINED WAMR_BUILD_REF_TYPES)
|
|||
set (WAMR_BUILD_REF_TYPES 0)
|
||||
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)
|
||||
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage")
|
||||
endif ()
|
||||
|
|
|
@ -49,6 +49,9 @@ print_help()
|
|||
#endif
|
||||
#if WASM_ENABLE_LIB_PTHREAD != 0
|
||||
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
|
||||
return 1;
|
||||
}
|
||||
|
@ -241,6 +244,11 @@ main(int argc, char *argv[])
|
|||
const char *env_list[8] = { NULL };
|
||||
uint32 env_list_size = 0;
|
||||
#endif
|
||||
#if WASM_ENABLE_DEBUG_INTERP != 0
|
||||
char * ip_addr = NULL;
|
||||
//int platform_port = 0;
|
||||
int instance_port = 0;
|
||||
#endif
|
||||
|
||||
/* Process options. */
|
||||
for (argc--, argv++; argc > 0 && argv[0][0] == '-'; argc--, argv++) {
|
||||
|
@ -321,6 +329,19 @@ main(int argc, char *argv[])
|
|||
return print_help();
|
||||
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
|
||||
else
|
||||
return print_help();
|
||||
|
@ -346,6 +367,13 @@ main(int argc, char *argv[])
|
|||
init_args.mem_alloc_option.allocator.free_func = free;
|
||||
#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 */
|
||||
if (!wasm_runtime_full_init(&init_args)) {
|
||||
printf("Init runtime environment failed.\n");
|
||||
|
|
|
@ -59,6 +59,17 @@ if (NOT DEFINED WAMR_BUILD_LIBC_WASI)
|
|||
set (WAMR_BUILD_LIBC_WASI 0)
|
||||
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 (WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../..)
|
||||
|
|
|
@ -109,6 +109,9 @@ message ("-- CMAKE_BUILD_TYPE = " ${CMAKE_BUILD_TYPE})
|
|||
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
add_definitions(-DBH_DEBUG=1)
|
||||
endif ()
|
||||
if (WAMR_BUILD_DEBUG_AOT EQUAL 1)
|
||||
add_definitions(-DWASM_ENABLE_DEBUG_AOT=1)
|
||||
endif()
|
||||
|
||||
# Enable 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 "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 MSVC)
|
||||
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)
|
||||
|
||||
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()
|
||||
target_link_libraries (wamrc aotclib vmlib ${LLVM_AVAILABLE_LIBS})
|
||||
target_link_libraries (wamrc aotclib vmlib ${lib_lldb} ${LLVM_AVAILABLE_LIBS})
|
||||
endif()
|
||||
|
|
|
@ -248,6 +248,12 @@ main(int argc, char *argv[])
|
|||
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");
|
||||
|
||||
if (!(comp_ctx = aot_create_comp_context(comp_data,
|
||||
|
|
Loading…
Reference in New Issue
Block a user