diff --git a/test-tools/addr2line/addr2line.py b/test-tools/addr2line/addr2line.py index 8ef3566e8d..174fcf93fa 100644 --- a/test-tools/addr2line/addr2line.py +++ b/test-tools/addr2line/addr2line.py @@ -31,9 +31,10 @@ - run the following command to transfer the address to line info: ``` $ cd test-tools/addr2line - $ python3 addr2line.py --wasi-sdk --wasm-file call_stack.txt + $ python3 addr2line.py --wasi-sdk --wabt --wasm-file call_stack.txt ``` -- the script will use *llvm-dwarfdump* to lookup the line info for each address in the call-stack dump. +- the script will use *wasm-objdump* in wabt to transform address, then use *llvm-dwarfdump* to lookup the line info for each address + in the call-stack dump. - the output will be: ``` #00: 0x0a04 - $f18 @@ -45,6 +46,42 @@ """ +def get_code_section_start(wasm_objdump: Path, wasm_file: Path) -> int: + """ + Find the start offset of Code section in a wasm file. + + if the code section header likes: + Code start=0x0000017c end=0x00004382 (size=0x00004206) count: 47 + + the start offset is 0x0000017c + """ + cmd = f"{wasm_objdump} -h {wasm_file}" + p = subprocess.run( + shlex.split(cmd), + check=True, + capture_output=True, + text=True, + universal_newlines=True, + ) + outputs = p.stdout.split(os.linesep) + + # if there is no .debug section, return -1 + for line in outputs: + line = line.strip() + if ".debug_info" in line: + break + else: + print(f"No .debug_info section found {wasm_file}") + return -1 + + for line in outputs: + line = line.strip() + if "Code" in line: + return int(line.split()[1].split("=")[1], 16) + + return -1 + + def get_line_info(dwarf_dump: Path, wasm_file: Path, offset: int) -> str: """ Find the location info of a given offset in a wasm file. @@ -105,13 +142,21 @@ def parse_call_stack_line(line: str) -> (): def main(): parser = argparse.ArgumentParser(description="addr2line for wasm") parser.add_argument("--wasi-sdk", type=Path, help="path to wasi-sdk") + parser.add_argument("--wabt", type=Path, help="path to wabt") parser.add_argument("--wasm-file", type=Path, help="path to wasm file") parser.add_argument("call_stack_file", type=Path, help="path to a call stack file") args = parser.parse_args() + wasm_objdump = args.wabt.joinpath("bin/wasm-objdump") + assert wasm_objdump.exists() + llvm_dwarf_dump = args.wasi_sdk.joinpath("bin/llvm-dwarfdump") assert llvm_dwarf_dump.exists() + code_section_start = get_code_section_start(wasm_objdump, args.wasm_file) + if code_section_start == -1: + return -1 + assert args.call_stack_file.exists() with open(args.call_stack_file, "rt", encoding="ascii") as f: for line in f: @@ -128,6 +173,7 @@ def main(): _, offset, _ = splitted offset = int(offset, 16) + offset = offset - code_section_start line_info = get_line_info(llvm_dwarf_dump, args.wasm_file, offset) if not line_info: print(line) @@ -143,4 +189,14 @@ def main(): if __name__ == "__main__": + print( + "**************************************************\n" + + "Before running this script, please make sure:\n" + + " - the wasm file is compiled with debug info. (like: clang -g) \n" + + " - the call-stack dump is generated by iwasm\n" + + " - iwasm is compiled with -DWAMR_BUILD_DUMP_CALL_STACK=1\n" + + " - iwasm isn't running under fast-interp mode. -DWAMR_BUILD_FAST_INTERP=0\n" + + " - if using .aot, the aot file is generated with `--enable-dump-call-stack`\n" + + "**************************************************\n" + ) sys.exit(main())