Skip to content
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

Add support for debug information for a native debugger #9334

Merged
merged 5 commits into from
Feb 3, 2025

Conversation

bjorng
Copy link
Contributor

@bjorng bjorng commented Jan 23, 2025

This pull request introduces support for adding debug information to BEAM files for a native debugger and for the BEAM loader to load that information. For more information, see the individual commit messages.

This is one of the components needed for the new debugger being developed by WhatsApp.

@bjorng bjorng added team:VM Assigned to OTP team VM feature testing currently being tested, tag is used by OTP internal CI labels Jan 23, 2025
@bjorng bjorng self-assigned this Jan 23, 2025
@bjorng bjorng requested a review from jhogberg January 23, 2025 06:28
Copy link
Contributor

github-actions bot commented Jan 23, 2025

CT Test Results

     7 files     638 suites   3h 14m 51s ⏱️
 6 061 tests  5 729 ✅ 331 💤 1 ❌
12 385 runs  11 977 ✅ 407 💤 1 ❌

For more details on these failures, see this check.

Results for commit fcbaf38.

♻️ 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

lib/kernel/src/code.erl Outdated Show resolved Hide resolved
@bjorng bjorng force-pushed the bjorn/beam_debug_info/OTP-19440 branch 2 times, most recently from da264dc to 3ae448c Compare January 24, 2025 08:30
Temporary variables generated by compiler passes must have names
that are not allowed in Erlang source code to ensure that they
will not be included in debug information.
Add `split_blocks_after/4` to split the block after the instruction
for which the predicate returns `true`. Rename `split_blocks/4` to
`split_blocks_before/4`.
@bjorng bjorng force-pushed the bjorn/beam_debug_info/OTP-19440 branch 3 times, most recently from 43dde6e to 6bb66fb Compare January 28, 2025 11:53
@bjorng bjorng requested a review from lucioleKi January 29, 2025 09:02
Copy link
Contributor

@jhogberg jhogberg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've made a first pass and it LGTM. I'll have a second look tomorrow. :-)

erts/emulator/beam/beam_bif_load.c Outdated Show resolved Hide resolved
erts/emulator/beam/beam_bif_load.c Outdated Show resolved Hide resolved
erts/emulator/beam/beam_bif_load.c Outdated Show resolved Hide resolved
erts/emulator/beam/beam_bif_load.c Outdated Show resolved Hide resolved
erts/emulator/beam/beam_file.c Outdated Show resolved Hide resolved
erts/emulator/beam/beam_bif_load.c Show resolved Hide resolved
lib/compiler/src/beam_validator.erl Outdated Show resolved Hide resolved
lib/compiler/src/core_pp.erl Outdated Show resolved Hide resolved
@bjorng bjorng force-pushed the bjorn/beam_debug_info/OTP-19440 branch from 463d057 to a692a92 Compare January 30, 2025 06:01
The `beam_debug_info` compiler option will insert `debug_line`
instructions on lines containing executable code, and it will maintain
information about which variables the BEAM registers contain at each
`debug_line` instruction. This information will be inserted into a
"DbgB" chunk in the BEAM file.

When a `debug_line` is executed, the current stack frame (if any) is
guaranteed to be fully initialized. The number of live X registers is
given as the second operand for the `debug_line` instruction (it is
guaranteed that there are no "holes").

Here is an example where the debug information translated to text has
been inserted as comments before the lines they apply to:

    %% function entry (no stack frame); x0, x1, x2 are live
    sum(A, B, _Ignored) ->
	%% no stack frame; A in x0, B in x1, _Ignored in x2
	C = A + B,

	%% no stack frame; B in x1, C in x0
	io:format("~p\n", [C]),

	%% stack frame size is 1; C in y0
	D = 10 * C,

	%% stack frame size is 1; C in y0, D in x0
	{ok,D}.

Note that not all variables are available in the debug information.

For example, before the call to `io:format/2`, the sum of A and B have
overwritten the register that used to hold the value of A, and the value
for _Ignore was wiped out by the `+` operation.

The size of the current stack frame is also given at each `debug_line`
to be able to easily find the beginning of the previous stack frame.
This commit implements support for loading the debug information from
a BEAM file and the `code:get_debug_info/1` BIF for retrieving the
debug information.

As an example, given the following module:

    -module(example).                               %  1
    -export([foo/1]).                               %  2

    foo(A) ->                                       %  4
        case A of                                   %  5
            0 ->                                    %  6
                B = 1,                              %  7
                io:format("~p\n", [B]);             %  8
            1 ->                                    %  9
                C = [1,2,3],                        % 10
                io:format("~p\n", [C])              % 11
        end,                                        % 12
        A.                                          % 13

    sign(N) when N < 0 -> 1;                        % 15
    sign(N) when N == 0 -> 0;                       % 16
    sign(_) -> 1.                                   % 17

here is how to compile it with BEAM debug information and
display the debug information:

     1> c(example, beam_debug_info).
     {ok,example}
     2> code:get_debug_info(example).
     [{4,{entry,[{1,{x,0}}]}},
      {5,{1,[{<<"A">>,{y,0}}]}},
      {7,{1,[{<<"A">>,{y,0}}]}},
      {8,{1,[{<<"B">>,{value,1}},{<<"A">>,{y,0}}]}},
      {10,{1,[{<<"A">>,{y,0}}]}},
      {11,{1,[{<<"C">>,{value,[1,2,3]}},{<<"A">>,{y,0}}]}},
      {13,{1,[{<<"A">>,{y,0}}]}},
      {15,{entry,[{1,{x,0}}]}},
      {15,{none,[{<<"N">>,{x,0}}]}},
      {16,{none,[{<<"N">>,{x,0}}]}},
      {17,{none,[]}}]

List elements having the frame size `entry` refers to a `debug_line`
instruction at the beginning of the function (before all
clauses). Note that the line number for such entries *may* be the same
as the line number for the first clause. All other line numbers are
guaranteed to be unique.
@bjorng bjorng force-pushed the bjorn/beam_debug_info/OTP-19440 branch from a692a92 to fcbaf38 Compare January 31, 2025 12:20
@bjorng bjorng merged commit 2807a49 into erlang:master Feb 3, 2025
27 of 29 checks passed
@bjorng bjorng deleted the bjorn/beam_debug_info/OTP-19440 branch February 3, 2025 07:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature team:VM Assigned to OTP team VM testing currently being tested, tag is used by OTP internal CI
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants