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 <zhangliangyu3@xiaomi.com>
This commit is contained in:
Liangyu Zhang
2024-09-18 11:02:10 +08:00
committed by GitHub
parent e9cc8731da
commit 51a71092bf
9 changed files with 307 additions and 0 deletions

View File

@ -0,0 +1,139 @@
# Dynamic AOT Module Debugging
> Note: Dynamic AOT debugging is experimental and only a few debugging capabilities are supported.
This guide explains how to debug WAMR AOT modules with dynamic AOT features. Follow these steps to set up and run your debugging environment.
## 1. Test source code
The following c program file is used as a debugging test file.
```bash
#include <stdio.h>
int main() {
printf("hello, world!\n");
int a = 1024;
printf("a is %d\n",a);
int b = 42;
printf("b is %d\n",b);
return 0;
}
```
## 2. Build iwasm with dynamic aot debugging feature
To enable dynamic AOT debugging, ensure the following
compile options are enabled when you [build iwasm](../../product-mini/README.md):
```bash
cmake -DWAMR_BUILD_AOT=1 -DWAMR_BUILD_DYNAMIC_AOT_DEBUG=1 -DCMAKE_BUILD_TYPE=Debug
```
## 3. Build wamrc
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.
## 4. Dynamic aot debugging and verification across various platforms
You can adjust the compiler options for different architectures and instruction sets.
### 4.1 Linux
#### Compile test.c to test.wasm
```bash
/opt/wasi-sdk/bin/clang -O0 -g -gdwarf-2 -o test.wasm test.c
```
#### Compile test.wasm to test.aot
```bash
./wamrc --opt-level=0 -o test.aot test.wasm
```
#### Compile test.wasm to test object file
> Note: please use the version wamrc which was built with `cmake -DWAMR_BUILD_DEBUG_AOT` flag.
```bash
./wamrc --opt-level=0 --format=object -o test.obj test.wasm
```
#### Launch the program using gdbserver on the remote linux host
```bash
cd ~/aot_debug # This directory contains iwasm and test.aot
gdbserver hostip:port ./iwasm test.aot
```
#### Local remote debugging
```bash
expport OBJ_PATH=~/aot_debug
cd ~/aot_debug # This directory contains iwasm, test.c, test obj file and dynamic_aot_debug.py
gdb ./iwasm
(gdb) target remote hostip:port
(gdb) source dynamic_aot_debug.py
(gdb) c
(gdb) b test.c:main
(gdb) n
```
### 4.2 ARMv7
#### Compile test.c to test.wasm
```bash
/opt/wasi-sdk/bin/clang -O0 -nostdlib -z stack-size=8192 -Wl,--initial-memory=65536
-g -gdwarf-2 -o test.wasm test.c -Wl,--export=main -Wl,--export=__main_argc_argv
-Wl,--export=__heap_base -Wl,--export=__data_end -Wl,--no-entry -Wl,--allow-undefined
```
#### Compile test.wasm to test.aot
```bash
./wamrc --opt-level=0 --target=thumbv7 --target-abi=gnueabihf --cpu=cortex-a7
--cpu-features=-neon -o test.aot test.wasm
```
#### Compile test.wasm to test object file
> Note: please use the version wamrc which was built with `cmake -DWAMR_BUILD_DEBUG_AOT` flag.
```bash
./wamrc --opt-level=0 --format=object --target=thumbv7 --target-abi=gnueabihf
--cpu=cortex-a7 --cpu-features=-neon -o test.obj test.wasm
```
#### Start Emulator
In Terminal 1, start the emulator in debug mode and launch the GDB server:
```bash
# start emulator on debug mode, and will start gdb server, set port as 1234
./emulator.sh vela -qemu -S -s
ap> iwasm test.aot
```
#### Start NuttX Using GDB
In Terminal 2, set the path to your object file and start NuttX with GDB:
```bash
# You can save test.obj file in this path
export OBJ_PATH=~/work/data/aot_debug
gdb-multiarch nuttx -ex "tar remote:1234" -ex "source dynamic_aot_debug.py"
```
In the GDB prompt:
```bash
(gdb) c
(gdb) b test.c:main
(gdb) n
```
## 5. Workflow
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.

View File

@ -0,0 +1,104 @@
#!/usr/bin/env python3
#
# Copyright (C) 2021 XiaoMi Corporation. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#
import os
import gdb
# Get object file path from environment variable or use default value
path_objs = os.getenv("OBJ_PATH", "~/objects/")
# Expand user directory symbol (~)
path_objs = os.path.expanduser(path_objs)
print(f"Object files will be loaded from: {path_objs} on localhost")
def add_symbol_with_aot_info(aot_module_info):
"""Add symbol file with AOT information to GDB and list current breakpoints."""
try:
text_addr = aot_module_info.get("code")
file_name = aot_module_info.get("name")
if not text_addr or not file_name:
print("Error: 'code' or 'name' missing in AOT module info.")
return
# Extract base file name without extension
file_name_without_extension, _ = os.path.splitext(file_name)
# Remove directory part if present
file_name = os.path.basename(file_name_without_extension)
# Add .obj extension to the file name
file_name = file_name + ".obj"
# Construct the path for the symbol file
path_symfile = os.path.join(path_objs, file_name)
# Construct the command to add the symbol file
cmd = f"add-symbol-file {path_symfile} {text_addr}"
gdb.execute(cmd)
# Print current breakpoints
breakpoints = gdb.execute("info breakpoints", to_string=True)
print("Current breakpoints:", breakpoints)
except gdb.error as e:
print(f"GDB error: {e}")
except Exception as e:
print(f"Unexpected error: {e}")
class ReadGDynamicAotModule(gdb.Command):
"""Command to read the g_dynamic_aot_module structure and extract information."""
def __init__(self):
super(self.__class__, self).__init__("read_gda", gdb.COMMAND_USER)
def invoke(self, args, from_tty):
"""Retrieve and process the g_dynamic_aot_module structure."""
try:
aot_module = gdb.parse_and_eval("g_dynamic_aot_module")
aot_module_info = {}
# Ensure aot_module is a pointer and dereference it
if aot_module.type.code == gdb.TYPE_CODE_PTR:
aot_module = aot_module.dereference()
# Check if it's a structure type
if aot_module.type.strip_typedefs().code == gdb.TYPE_CODE_STRUCT:
for field in aot_module.type.fields():
field_name = field.name
var = aot_module[field_name]
if field_name == "name":
aot_module_info["name"] = var.string()
elif field_name == "code":
aot_module_info["code"] = str(var)
if "name" in aot_module_info and "code" in aot_module_info:
add_symbol_with_aot_info(aot_module_info)
else:
print("Could not find 'name' or 'code' in Aot_module.")
else:
print("Aot_module is not of struct type.")
else:
print("Aot_module is not a pointer type.")
except gdb.error as e:
print(f"An error occurred: {e}")
def init():
"""Initialize environment and set up debugger."""
# Register the command to gdb
ReadGDynamicAotModule()
# Set a breakpoint at function __enable_dynamic_aot_debug
breakpoint = gdb.Breakpoint("__enable_dynamic_aot_debug")
# Attach the self-defined command to the created breakpoint, read_gda means read global dynamic aot info.
breakpoint.commands = "read_gda"
init()

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 94 KiB