Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 43 additions & 11 deletions .github/workflows/build-and-test-macos.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ jobs:
https://cdn.jsdelivr.net/hex

- name: "Install deps"
run: brew update && HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 brew install gperf doxygen socat ${{ matrix.mbedtls }}
run: brew update && HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 brew install coreutils gperf doxygen socat ${{ matrix.mbedtls }}

- name: "Workaround for nxdomain random issues"
run: |
Expand Down Expand Up @@ -147,20 +147,41 @@ jobs:

- name: "Test: dwarf (test_executable_line)"
if: matrix.cmake_opts_other == '-DAVM_DISABLE_JIT=OFF -DAVM_DISABLE_JIT_DWARF=OFF'
timeout-minutes: 4
working-directory: build
env:
# Apple lldb < 2100 hangs forever resolving pending source-line
# breakpoints against JIT-emitted DWARF on macOS 26 (the active
# Xcode 26.2 lldb is 1703.x). The CommandLineTools lldb is at
# 2100 and works.
LLDB: /Library/Developer/CommandLineTools/usr/bin/lldb
run: |
OUTPUT=$(lldb -b \
[ -x "$LLDB" ] || { echo "FAIL: $LLDB not executable"; exit 1; }
echo "## using $LLDB"
"$LLDB" --version | head -2
LOG=/tmp/lldb-test_executable_line.log
set +e
gtimeout --foreground -k 30 120 "$LLDB" -b \
-o "log enable -f /tmp/lldb-jit-loader.log lldb jit" \
-o "log enable -f /tmp/lldb-gdb-test.log gdb-remote packets" \
-o "settings set plugin.jit-loader.gdb.enable on" \
-o "breakpoint set -f test_executable_line.erl -l 49" \
-o "breakpoint set -f test_executable_line.erl -l 52" \
-o "run" \
-o "print term_to_int(ctx->x[0])" \
-o "c" \
-o "print term_to_int(ctx->x[0])" \
-- ./tests/test-erlang test_executable_line 2>&1)
echo "$OUTPUT"
# Extract printed values in order
VALUES=$(echo "$OUTPUT" | sed -n 's/.*(\(avm_int_t\)) \(-\{0,1\}[0-9][0-9]*\).*/\2/p')
-o "quit" \
-- ./tests/test-erlang test_executable_line 2>&1 | tee "$LOG"
LLDB_RC=${PIPESTATUS[0]}
set -e
if [ "$LLDB_RC" -eq 124 ] || [ "$LLDB_RC" -eq 137 ]; then
echo "FAIL: lldb timed out (rc=$LLDB_RC)"
[ -f /tmp/lldb-jit-loader.log ] && { echo "## jit log"; head -200 /tmp/lldb-jit-loader.log; }
[ -f /tmp/lldb-gdb-test.log ] && { echo "## gdb-remote packets (tail)"; tail -120 /tmp/lldb-gdb-test.log; }
exit 1
fi
VALUES=$(sed -n 's/^(\(avm_int_t\)) \(-\{0,1\}[0-9][0-9]*\).*/\2/p' "$LOG")
FIRST=$(echo "$VALUES" | sed -n '1p')
SECOND=$(echo "$VALUES" | sed -n '2p')
if [ "$FIRST" != "42" ]; then
Expand All @@ -175,20 +196,31 @@ jobs:

- name: "Test: dwarf (test_debug_line)"
if: matrix.cmake_opts_other == '-DAVM_DISABLE_JIT=OFF -DAVM_DISABLE_JIT_DWARF=OFF'
timeout-minutes: 6
working-directory: build
env:
LLDB: /Library/Developer/CommandLineTools/usr/bin/lldb
run: |
OUTPUT=$(lldb -b \
[ -x "$LLDB" ] || { echo "FAIL: $LLDB not executable"; exit 1; }
LOG=/tmp/lldb-test_debug_line.log
set +e
gtimeout --foreground -k 30 240 "$LLDB" -b \
-o "settings set plugin.jit-loader.gdb.enable on" \
-o "breakpoint set -f test_debug_line.erl -l 49" \
-o "breakpoint set -f test_debug_line.erl -l 52" \
-o "run" \
-o "print term_to_int(N)" \
-o "c" \
-o "print term_to_int(Z)" \
-- ./tests/test-erlang test_debug_line 2>&1)
echo "$OUTPUT"
# Extract printed values in order
VALUES=$(echo "$OUTPUT" | sed -n 's/.*(\(avm_int_t\)) \(-\{0,1\}[0-9][0-9]*\).*/\2/p')
-o "quit" \
-- ./tests/test-erlang test_debug_line 2>&1 | tee "$LOG"
LLDB_RC=${PIPESTATUS[0]}
set -e
if [ "$LLDB_RC" -eq 124 ] || [ "$LLDB_RC" -eq 137 ]; then
echo "FAIL: lldb timed out (rc=$LLDB_RC)"
exit 1
fi
VALUES=$(sed -n 's/^(\(avm_int_t\)) \(-\{0,1\}[0-9][0-9]*\).*/\2/p' "$LOG")
FIRST=$(echo "$VALUES" | sed -n '1p')
SECOND=$(echo "$VALUES" | sed -n '2p')
if [ "$FIRST" != "42" ]; then
Expand Down
23 changes: 20 additions & 3 deletions doc/src/jit.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,9 +172,26 @@ If the Erlang source was compiled with debug information and the BEAM Line chunk
```

```{note}
LLDB 19 has a regression in the JIT loader that causes hangs when resolving breakpoints in JIT-loaded modules. Use LLDB 20 or later.
On macOS, you can use lldb that ships with Xcode 26+ or install lldb 20 from [MacPorts](https://www.macports.org/) (`port install lldb-20`) or
build from the [LLVM project source](https://github.com/llvm/llvm-project).
Upstream LLVM LLDB 19 and Apple LLDB versions earlier than `lldb-2100` (shipped in Xcode 26.4 and later) hang when resolving pending source-line breakpoints against JIT-emitted DWARF.

Workarounds without changing lldb:

* Set breakpoints by symbol name (`breakpoint set -n 'mod:fun/N'`) instead of file/line
* Defer source-line breakpoints until after the relevant module has been JIT-registered (e.g. break first on a symbol, then add the source-line breakpoint, then continue).

For a fresh lldb:

* On macOS 26, the LLDB shipped with the CommandLineTools is already at `lldb-2100` (independent of the active Xcode), so a quick fix is to invoke it directly:

```shell
$ /Library/Developer/CommandLineTools/usr/bin/lldb -- ...
```

Alternatively, switch the active Xcode to 26.4 or later (`sudo xcode-select -s /Applications/Xcode_26.4.app`).

* On any platform, install upstream LLDB 20 or later with `sudo port install lldb-20` from [MacPorts](https://www.macports.org/), `brew install llvm` (Homebrew), or build from the [LLVM project source](https://github.com/llvm/llvm-project). A self-signed `lldb` binary on macOS needs a debugger entitlement.

`lldb --version` reports the version: `lldb-1703.x` and earlier are affected; `lldb-2100.x` and upstream LLDB 20+ are fixed.
```

### Disassembling precompiled modules
Expand Down
Loading