Skip to content

Add call-targets to the info available via +beam_debug_info #9814

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

jcpetruzza
Copy link
Contributor

Context

For implementing a stepping-into functionality, we need to know, given the current location of a suspended process, what are the possible next targets. At the moment, the edb debugger is relying on the AST we get via +debug_info. This however has several drawbacks; in particular we are forced to implement a code-analysis that is tricky to get right, requires maintenance as new language constructs are added (similar to what happens with int) and limits this feature to modules that are backed by a file, and compiled with +debug_info.

Instead, we'd like this info to be provided by the compiler when +beam_debug_info is used, as an additional bit of data associated to each debug location.

What we do here

  • To simplify handling of further additions of debug symbols, we change code:get_debug_info/1 so that it uses a map, instead of a tuple, to return the data. This means we can add more keys in the future, without major API changes
  • We also modify the format used in the encoding of the DbgB chunk to make it more extensible: where before, each item was encoded using call FrameSize VarMappings, we now use one call for the FrameSize and an optional call for the VarMappings. The first argument of the call` now tell us what the payload in the second argument is.
  • We can then analyze the SSA to find all the call instructions and record their target. The targets we care about are of the form {M, F, A} or {F, A}, where M and F can be atoms, if they are known statically, or a binary representing a user variable, for dynamic calls. We also allow plain user variables as target. This will allow edb to soon support stepping-into the target of a dynamic call.
  • The way the "calls" are encoded in the argument of their call instruction is as a list of integers, binaries or atoms, as follows:
    • [{M, F, A},...] gets encoded as [A,M,F,...];
    • [{F, A}, ...] gets encoded as [A+256, F, ...];
    • [V,...] (for V a binary) gets encoded as [V,...]

We can then unambiguously reconstruct the list of targets from this list of terms

jcpetruzza and others added 5 commits May 7, 2025 15:33
At the moment, we are only saving frame-size and var mappings
as debug-info, but we are planning to add more information.
Because code:get_debug_info/1 returns the current info in a
tuple, it will not be possible to add more fields without
making breaking changes.

So instead use a map `#{frame_size => ..., vars => ...}`, so that
new fields can be added in the future by extending this map
At the moment, we only store frame-size and var-mappings
in the DbgB chunk, but we would like to store more information.
This will require to bump the version of the chunk encoding.

In doing this, we would like to make it so that it is easier to
extend this in the future retaining backwards compatibility.

Where today every item is encoded with a `call` instruction,
where the first argument is the frame size and the secod one
it the var mapping, we will now use a `call` instruction with
the first argument being a key (for now "frame size" or "var
mappings"), and the second a payload.

As long as the loader is prepared for missing entries, we
retain backwards compatibility.
At the moment, we only expose frame-size and variable-mappings
when compiling with `+beam_debug_info`. Internally, they are
stored as a tuple.

We are planning to add more debug-info, but this will mean changing
all places where the tuple is used, to turn it into a triple, and
the same will happen if we later add another one, etc.

So to make this refactorings easier, we introduce a map.
We extend the DbgB chunk with an optional list of all calls
performed at a debug_line. Calls are expressed as:

* {M, F, A} for remote calls,
* {F, A} for local calls,
* V for variables (fun refs, etc)

M and F above can be either atoms or user variables
During code loading, we now also save the new calls debug
info, and use it to build the response in `code:get_debug_info/1`
Copy link
Contributor

github-actions bot commented May 8, 2025

CT Test Results

    5 files    523 suites   2h 0m 0s ⏱️
3 787 tests 3 481 ✅ 305 💤 1 ❌
9 589 runs  9 203 ✅ 385 💤 1 ❌

For more details on these failures, see this check.

Results for commit 86062ed.

♻️ This comment has been updated with latest results.

To speed up review, make sure that you have read Contributing to Erlang/OTP and that all checks pass.

See the TESTING and DEVELOPMENT HowTo guides for details about how to run test locally.

Artifacts

// Erlang/OTP Github Action Bot

@jhogberg jhogberg added the team:VM Assigned to OTP team VM label May 12, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
team:VM Assigned to OTP team VM
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants