Skip to content

addr2line: enhance call-stack symbolicator, samples, tests, and CI#4972

Open
TianlongLiang wants to merge 1 commit into
bytecodealliance:mainfrom
TianlongLiang:dev/addr2line_enhance
Open

addr2line: enhance call-stack symbolicator, samples, tests, and CI#4972
TianlongLiang wants to merge 1 commit into
bytecodealliance:mainfrom
TianlongLiang:dev/addr2line_enhance

Conversation

@TianlongLiang

Copy link
Copy Markdown
Contributor

Refactor test-tools/addr2line/addr2line.py to reliably symbolicate WAMR call stacks across the wasi-sdk versions WAMR supports (29+), and add test infrastructure plus two end-to-end debug-tools samples that exercise the workflow.

addr2line.py:

  • Detect wasi-sdk clang version at startup and dispatch to a "modern" resolver (clang >= 22, single llvm-symbolizer call) or a "legacy" resolver (clang < 22, with a DW_TAG_subprogram interval-table overlay built from a single llvm-dwarfdump --debug-info pass at startup). The overlay fixes the clang-22 wasm DWARF bug where the symbolizer returns the wrong outermost function name (e.g. recurse reported as free) for addresses overlapping wasi-libc declarations.
  • Inline frames are rendered with explicit "(inlined into )" annotations so the call chain reads top-down.
  • --no-addr (function-name lookup) prefers non-sysroot candidates so short user-code names (a, b, c) don't collide with wasi-libc helpers in the DWARF.
  • -v/--verbose gates the dispatch-decision log; default silent.
  • Require llvm-symbolizer; drop the legacy llvm-addr2line fallback (every supported wasi-sdk ships symbolizer).

samples/debug-tools (refresh):

  • Use always_inline trap_helper to demonstrate inline expansion.
  • symbolicate.sh is self-locating and prints banner headers per mode (interp / --no-addr / aot) so the three output blocks are distinguishable.
  • verify.sh asserts the precise frame names and inline annotation using anchored regex.
  • Fix make -j race in wasm-apps/CMakeLists.txt (explicit add_dependencies for the AOT custom target).

samples/debug-tools-optimized (new):

  • Production-realistic workflow: clang -Oz -g -flto then wasm-opt -Oz -g to produce a stripped .prod.wasm plus a DWARF companion (.debug.wasm) with byte-identical code.
  • AOT path via wamrc --enable-dump-call-stack --bounds-checks=1.
  • WAMR_DISABLE_HW_BOUND_CHECK=1 so OOB traps go through the interpreter exception path (capturing frame_ip) instead of the SIGSEGV signal handler (which doesn't update frame->ip).
  • Two apps: oob (cross-TU inlined memory trap) and stackoverflow (non-tail recursion that exhausts the operand stack at ~20 frames with --stack-size=4096).
  • verify.sh covers all (app, mode, interp) combinations.

test-tools/addr2line/tests (new):

  • Pytest suite covering 13 scenarios: simple resolution, basic and deep inline chains, cross-TU LTO inlining, mid-function trap, multi-frame call stack, C++ demangling, AOT mode, fast-interp fallback, --no-addr, offset=0 fallback, empty input, version dispatch, and modern-vs-legacy equivalence under --multi-sdk.
  • conftest.py exposes wasi_sdk/wabt/binaryen/build_wasm fixtures; filters SDK candidates by llvm-symbolizer presence; prints invocation IO under pytest -v -s.
  • 8 purpose-built C/C++ test apps under apps/, 3 fixture call stacks.

CI:

  • Per-PR job: addr2line_tests removed; debug-tools-optimized folded into build_samples_others (no separate runner / runtime install). Matrix-style classic+fast interp coverage via in-step loop.
  • Nightly: addr2line_tests_multi_sdk parametrizes pytest over wasi-sdk 29 and 33 for the modern/legacy equivalence test.
  • macOS workflow: existing debug-tools step now calls verify.sh.
  • install-wasi-sdk-wabt action: bump default wasi-sdk 25 -> 29 (pre-29 bundles lack llvm-symbolizer). New wasi_sdk_version input lets callers pin a version when needed.

Documentation:

  • New test-tools/addr2line/README.md explains the script's architecture (modern/legacy split, the LLVM symbolizer wasm bug, --mode={interp,aot,fast-interp} offset spaces, the four tools involved). Sample READMEs link there to avoid duplication.
  • tests/README.md describes every test case with the regression class it guards against.

@TianlongLiang

Copy link
Copy Markdown
Contributor Author

This is all in one PR; I will break it into a series of PRs so it is easier to review

Refactor test-tools/addr2line/addr2line.py to reliably symbolicate WAMR
call stacks across the wasi-sdk versions WAMR supports (29+), and add
test infrastructure plus two end-to-end debug-tools samples that
exercise the workflow.

addr2line.py:
- Detect wasi-sdk clang version at startup and dispatch to a "modern"
  resolver (clang >= 22, single llvm-symbolizer call) or a "legacy"
  resolver (clang < 22, with a DW_TAG_subprogram interval-table overlay
  built from a single llvm-dwarfdump --debug-info pass at startup).
  The overlay fixes the clang-22 wasm DWARF bug where the symbolizer
  returns the wrong outermost function name (e.g. `recurse` reported
  as `free`) for addresses overlapping wasi-libc declarations.
- Inline frames are rendered with explicit "(inlined into <next>)"
  annotations so the call chain reads top-down.
- `--no-addr` (function-name lookup) prefers non-sysroot candidates so
  short user-code names (`a`, `b`, `c`) don't collide with wasi-libc
  helpers in the DWARF.
- `-v`/`--verbose` gates the dispatch-decision log; default silent.
- Require llvm-symbolizer; drop the legacy llvm-addr2line fallback
  (every supported wasi-sdk ships symbolizer).

samples/debug-tools (refresh):
- Use always_inline trap_helper to demonstrate inline expansion.
- symbolicate.sh is self-locating and prints banner headers per mode
  (interp / --no-addr / aot) so the three output blocks are
  distinguishable.
- verify.sh asserts the precise frame names and inline annotation
  using anchored regex.
- Fix `make -j` race in wasm-apps/CMakeLists.txt (explicit
  add_dependencies for the AOT custom target).

samples/debug-tools-optimized (new):
- Production-realistic workflow: `clang -Oz -g -flto` then
  `wasm-opt -Oz -g` to produce a stripped .prod.wasm plus a DWARF
  companion (.debug.wasm) with byte-identical code.
- AOT path via wamrc --enable-dump-call-stack --bounds-checks=1.
- WAMR_DISABLE_HW_BOUND_CHECK=1 so OOB traps go through the
  interpreter exception path (capturing frame_ip) instead of the
  SIGSEGV signal handler (which doesn't update frame->ip).
- Two apps: oob (cross-TU inlined memory trap) and stackoverflow
  (non-tail recursion that exhausts the operand stack at ~20 frames
  with --stack-size=4096).
- verify.sh covers all (app, mode, interp) combinations.

test-tools/addr2line/tests (new):
- Pytest suite covering 13 scenarios: simple resolution, basic and
  deep inline chains, cross-TU LTO inlining, mid-function trap,
  multi-frame call stack, C++ demangling, AOT mode, fast-interp
  fallback, --no-addr, offset=0 fallback, empty input, version
  dispatch, and modern-vs-legacy equivalence under --multi-sdk.
- conftest.py exposes wasi_sdk/wabt/binaryen/build_wasm fixtures;
  filters SDK candidates by llvm-symbolizer presence; prints
  invocation IO under pytest -v -s.
- 8 purpose-built C/C++ test apps under apps/, 3 fixture call stacks.

CI:
- Per-PR job: addr2line_tests removed; debug-tools-optimized folded
  into build_samples_others (no separate runner / runtime install).
  Matrix-style classic+fast interp coverage via in-step loop.
- Nightly: addr2line_tests_multi_sdk parametrizes pytest over
  wasi-sdk 29 and 33 for the modern/legacy equivalence test.
- macOS workflow: existing debug-tools step now calls verify.sh.
- install-wasi-sdk-wabt action: bump default wasi-sdk 25 -> 29
  (pre-29 bundles lack llvm-symbolizer). New `wasi_sdk_version`
  input lets callers pin a version when needed.

Documentation:
- New test-tools/addr2line/README.md explains the script's
  architecture (modern/legacy split, the LLVM symbolizer wasm bug,
  --mode={interp,aot,fast-interp} offset spaces, the four tools
  involved). Sample READMEs link there to avoid duplication.
- tests/README.md describes every test case with the regression
  class it guards against.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant