Skip to content

Commit 51a7109

Browse files
authored
Support dynamic aot debug (#3788)
Enable dynamic aot debug feature which debugs the aot file and is able to set the break point and do single step. Refer to the README for the detailed steps. Signed-off-by: zhangliangyu3 <[email protected]>
1 parent e9cc873 commit 51a7109

File tree

9 files changed

+307
-0
lines changed

9 files changed

+307
-0
lines changed

build-scripts/config_common.cmake

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,10 @@ endif ()
404404
if (WAMR_BUILD_DEBUG_AOT EQUAL 1)
405405
message (" Debug AOT enabled")
406406
endif ()
407+
if (WAMR_BUILD_DYNAMIC_AOT_DEBUG EQUAL 1)
408+
add_definitions (-DWASM_ENABLE_DYNAMIC_AOT_DEBUG=1)
409+
message (" Dynamic AOT debug enabled")
410+
endif ()
407411
if (WAMR_BUILD_LOAD_CUSTOM_SECTION EQUAL 1)
408412
add_definitions (-DWASM_ENABLE_LOAD_CUSTOM_SECTION=1)
409413
message (" Load custom section enabled")

core/config.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,10 @@
7575
#define WASM_ENABLE_AOT 0
7676
#endif
7777

78+
#ifndef WASM_ENABLE_DYNAMIC_AOT_DEBUG
79+
#define WASM_ENABLE_DYNAMIC_AOT_DEBUG 0
80+
#endif
81+
7882
#ifndef WASM_ENABLE_WORD_ALIGN_READ
7983
#define WASM_ENABLE_WORD_ALIGN_READ 0
8084
#endif

core/iwasm/aot/aot_runtime.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5072,6 +5072,18 @@ aot_const_str_set_insert(const uint8 *str, int32 len, AOTModule *module,
50725072
return c_str;
50735073
}
50745074

5075+
#if WASM_ENABLE_DYNAMIC_AOT_DEBUG != 0
5076+
AOTModule *g_dynamic_aot_module = NULL;
5077+
5078+
void __attribute__((noinline)) __enable_dynamic_aot_debug(void)
5079+
{
5080+
/* empty implementation. */
5081+
}
5082+
5083+
void (*__enable_dynamic_aot_debug_ptr)(void)
5084+
__attribute__((visibility("default"))) = __enable_dynamic_aot_debug;
5085+
#endif
5086+
50755087
bool
50765088
aot_set_module_name(AOTModule *module, const char *name, char *error_buf,
50775089
uint32_t error_buf_size)
@@ -5085,6 +5097,12 @@ aot_set_module_name(AOTModule *module, const char *name, char *error_buf,
50855097
false,
50865098
#endif
50875099
error_buf, error_buf_size);
5100+
#if WASM_ENABLE_DYNAMIC_AOT_DEBUG != 0
5101+
/* export g_dynamic_aot_module for dynamic aot debug */
5102+
g_dynamic_aot_module = module;
5103+
/* trigger breakpoint __enable_dynamic_aot_debug */
5104+
(*__enable_dynamic_aot_debug_ptr)();
5105+
#endif
50885106
return module->name != NULL;
50895107
}
50905108

product-mini/platforms/nuttx/CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,12 @@ else()
4949
add_definitions(-DWASM_ENABLE_WORD_ALIGN_READ=0)
5050
endif()
5151

52+
if(CONFIG_INTERPRETERS_WAMR_DYNAMIC_AOT_DEBUG)
53+
add_definitions(-DWASM_ENABLE_DYNAMIC_AOT_DEBUG=1)
54+
else()
55+
add_definitions(-DWASM_ENABLE_DYNAMIC_AOT_DEBUG=0)
56+
endif()
57+
5258
if(CONFIG_INTERPRETERS_WAMR_STACK_GUARD_SIZE)
5359
add_definitions(-DWASM_STACK_GUARD_SIZE=0)
5460
else()

product-mini/platforms/nuttx/wamr.mk

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,12 @@ else
148148
CFLAGS += -DWASM_ENABLE_WORD_ALIGN_READ=0
149149
endif
150150

151+
ifeq ($(CONFIG_INTERPRETERS_WAMR_DYNAMIC_AOT_DEBUG),y)
152+
CFLAGS += -DWASM_ENABLE_DYNAMIC_AOT_DEBUG=1
153+
else
154+
CFLAGS += -DWASM_ENABLE_DYNAMIC_AOT_DEBUG=0
155+
endif
156+
151157
ifeq ($(CONFIG_INTERPRETERS_WAMR_MEM_DUAL_BUS_MIRROR),y)
152158
CFLAGS += -DWASM_MEM_DUAL_BUS_MIRROR=1
153159
else

product-mini/platforms/posix/main.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -928,6 +928,15 @@ main(int argc, char *argv[])
928928
goto fail2;
929929
}
930930

931+
#if WASM_ENABLE_DYNAMIC_AOT_DEBUG != 0
932+
if (!wasm_runtime_set_module_name(wasm_module, wasm_file, error_buf,
933+
sizeof(error_buf))) {
934+
printf("set aot module name failed in dynamic aot debug mode, %s\n",
935+
error_buf);
936+
goto fail3;
937+
}
938+
#endif
939+
931940
#if WASM_ENABLE_LIBC_WASI != 0
932941
libc_wasi_init(wasm_module, argc, argv, &wasi_parse_ctx);
933942
#endif
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
# Dynamic AOT Module Debugging
2+
3+
> Note: Dynamic AOT debugging is experimental and only a few debugging capabilities are supported.
4+
5+
This guide explains how to debug WAMR AOT modules with dynamic AOT features. Follow these steps to set up and run your debugging environment.
6+
7+
## 1. Test source code
8+
9+
The following c program file is used as a debugging test file.
10+
11+
```bash
12+
#include <stdio.h>
13+
14+
int main() {
15+
printf("hello, world!\n");
16+
int a = 1024;
17+
printf("a is %d\n",a);
18+
int b = 42;
19+
printf("b is %d\n",b);
20+
return 0;
21+
}
22+
```
23+
24+
## 2. Build iwasm with dynamic aot debugging feature
25+
26+
To enable dynamic AOT debugging, ensure the following
27+
compile options are enabled when you [build iwasm](../../product-mini/README.md):
28+
29+
```bash
30+
cmake -DWAMR_BUILD_AOT=1 -DWAMR_BUILD_DYNAMIC_AOT_DEBUG=1 -DCMAKE_BUILD_TYPE=Debug
31+
```
32+
33+
## 3. Build wamrc
34+
35+
Developer may need to build out two versions of wamrc, one is to compile the wasm binary into the AOT file, the other is to compile the wasm binary into an object file. To build out the former, just build wamrc as normal, see [wamrc-compiler/README.md](../../wamr-compiler/README.md). To build out the latter, the `WAMR_BUILD_DEBUG_AOT` flag must be added to cmake, please refer to the first two steps in [doc/source_debugging_aot.md](../../doc/source_debugging_aot.md), and if you encounter the error “‘eLanguageTypeC17’ not declared in this scope”, you can bypass it by commenting out the case judgments. This will not affect the debugging results.
36+
37+
## 4. Dynamic aot debugging and verification across various platforms
38+
39+
You can adjust the compiler options for different architectures and instruction sets.
40+
41+
### 4.1 Linux
42+
43+
#### Compile test.c to test.wasm
44+
45+
```bash
46+
/opt/wasi-sdk/bin/clang -O0 -g -gdwarf-2 -o test.wasm test.c
47+
```
48+
49+
#### Compile test.wasm to test.aot
50+
51+
```bash
52+
./wamrc --opt-level=0 -o test.aot test.wasm
53+
```
54+
55+
#### Compile test.wasm to test object file
56+
57+
> Note: please use the version wamrc which was built with `cmake -DWAMR_BUILD_DEBUG_AOT` flag.
58+
59+
```bash
60+
./wamrc --opt-level=0 --format=object -o test.obj test.wasm
61+
```
62+
63+
#### Launch the program using gdbserver on the remote linux host
64+
65+
```bash
66+
cd ~/aot_debug # This directory contains iwasm and test.aot
67+
gdbserver hostip:port ./iwasm test.aot
68+
```
69+
70+
#### Local remote debugging
71+
72+
```bash
73+
expport OBJ_PATH=~/aot_debug
74+
cd ~/aot_debug # This directory contains iwasm, test.c, test obj file and dynamic_aot_debug.py
75+
gdb ./iwasm
76+
(gdb) target remote hostip:port
77+
(gdb) source dynamic_aot_debug.py
78+
(gdb) c
79+
(gdb) b test.c:main
80+
(gdb) n
81+
```
82+
83+
### 4.2 ARMv7
84+
85+
#### Compile test.c to test.wasm
86+
87+
```bash
88+
/opt/wasi-sdk/bin/clang -O0 -nostdlib -z stack-size=8192 -Wl,--initial-memory=65536
89+
-g -gdwarf-2 -o test.wasm test.c -Wl,--export=main -Wl,--export=__main_argc_argv
90+
-Wl,--export=__heap_base -Wl,--export=__data_end -Wl,--no-entry -Wl,--allow-undefined
91+
```
92+
93+
#### Compile test.wasm to test.aot
94+
95+
```bash
96+
./wamrc --opt-level=0 --target=thumbv7 --target-abi=gnueabihf --cpu=cortex-a7
97+
--cpu-features=-neon -o test.aot test.wasm
98+
```
99+
100+
#### Compile test.wasm to test object file
101+
102+
> Note: please use the version wamrc which was built with `cmake -DWAMR_BUILD_DEBUG_AOT` flag.
103+
104+
```bash
105+
./wamrc --opt-level=0 --format=object --target=thumbv7 --target-abi=gnueabihf
106+
--cpu=cortex-a7 --cpu-features=-neon -o test.obj test.wasm
107+
```
108+
109+
#### Start Emulator
110+
111+
In Terminal 1, start the emulator in debug mode and launch the GDB server:
112+
113+
```bash
114+
# start emulator on debug mode, and will start gdb server, set port as 1234
115+
./emulator.sh vela -qemu -S -s
116+
ap> iwasm test.aot
117+
```
118+
119+
#### Start NuttX Using GDB
120+
121+
In Terminal 2, set the path to your object file and start NuttX with GDB:
122+
123+
```bash
124+
# You can save test.obj file in this path
125+
export OBJ_PATH=~/work/data/aot_debug
126+
gdb-multiarch nuttx -ex "tar remote:1234" -ex "source dynamic_aot_debug.py"
127+
```
128+
129+
In the GDB prompt:
130+
131+
```bash
132+
(gdb) c
133+
(gdb) b test.c:main
134+
(gdb) n
135+
```
136+
137+
## 5. Workflow
138+
139+
Refer to the workflow diagram (wasm-micro-runtime/test-tools/dynamic-aot-debug) for an overview of the debugging process. In addition, the implementation of this dynamic aot debugging solution is not complete yet. It only supports breakpoints and single-step execution, and it is not yet known to view detailed information such as variables.
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
#!/usr/bin/env python3
2+
#
3+
# Copyright (C) 2021 XiaoMi Corporation. All rights reserved.
4+
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5+
#
6+
7+
import os
8+
import gdb
9+
10+
# Get object file path from environment variable or use default value
11+
path_objs = os.getenv("OBJ_PATH", "~/objects/")
12+
13+
# Expand user directory symbol (~)
14+
path_objs = os.path.expanduser(path_objs)
15+
print(f"Object files will be loaded from: {path_objs} on localhost")
16+
17+
18+
def add_symbol_with_aot_info(aot_module_info):
19+
"""Add symbol file with AOT information to GDB and list current breakpoints."""
20+
try:
21+
text_addr = aot_module_info.get("code")
22+
file_name = aot_module_info.get("name")
23+
24+
if not text_addr or not file_name:
25+
print("Error: 'code' or 'name' missing in AOT module info.")
26+
return
27+
28+
# Extract base file name without extension
29+
file_name_without_extension, _ = os.path.splitext(file_name)
30+
31+
# Remove directory part if present
32+
file_name = os.path.basename(file_name_without_extension)
33+
34+
# Add .obj extension to the file name
35+
file_name = file_name + ".obj"
36+
37+
# Construct the path for the symbol file
38+
path_symfile = os.path.join(path_objs, file_name)
39+
40+
# Construct the command to add the symbol file
41+
cmd = f"add-symbol-file {path_symfile} {text_addr}"
42+
gdb.execute(cmd)
43+
44+
# Print current breakpoints
45+
breakpoints = gdb.execute("info breakpoints", to_string=True)
46+
print("Current breakpoints:", breakpoints)
47+
48+
except gdb.error as e:
49+
print(f"GDB error: {e}")
50+
except Exception as e:
51+
print(f"Unexpected error: {e}")
52+
53+
54+
class ReadGDynamicAotModule(gdb.Command):
55+
"""Command to read the g_dynamic_aot_module structure and extract information."""
56+
57+
def __init__(self):
58+
super(self.__class__, self).__init__("read_gda", gdb.COMMAND_USER)
59+
60+
def invoke(self, args, from_tty):
61+
"""Retrieve and process the g_dynamic_aot_module structure."""
62+
try:
63+
aot_module = gdb.parse_and_eval("g_dynamic_aot_module")
64+
aot_module_info = {}
65+
66+
# Ensure aot_module is a pointer and dereference it
67+
if aot_module.type.code == gdb.TYPE_CODE_PTR:
68+
aot_module = aot_module.dereference()
69+
70+
# Check if it's a structure type
71+
if aot_module.type.strip_typedefs().code == gdb.TYPE_CODE_STRUCT:
72+
for field in aot_module.type.fields():
73+
field_name = field.name
74+
var = aot_module[field_name]
75+
76+
if field_name == "name":
77+
aot_module_info["name"] = var.string()
78+
elif field_name == "code":
79+
aot_module_info["code"] = str(var)
80+
81+
if "name" in aot_module_info and "code" in aot_module_info:
82+
add_symbol_with_aot_info(aot_module_info)
83+
else:
84+
print("Could not find 'name' or 'code' in Aot_module.")
85+
else:
86+
print("Aot_module is not of struct type.")
87+
else:
88+
print("Aot_module is not a pointer type.")
89+
except gdb.error as e:
90+
print(f"An error occurred: {e}")
91+
92+
93+
def init():
94+
"""Initialize environment and set up debugger."""
95+
# Register the command to gdb
96+
ReadGDynamicAotModule()
97+
98+
# Set a breakpoint at function __enable_dynamic_aot_debug
99+
breakpoint = gdb.Breakpoint("__enable_dynamic_aot_debug")
100+
# Attach the self-defined command to the created breakpoint, read_gda means read global dynamic aot info.
101+
breakpoint.commands = "read_gda"
102+
103+
104+
init()

0 commit comments

Comments
 (0)