Search documentation of kernel

# erl_debugger (kernel v11.0.3)

Copy Markdown View Source

Erlang debugger support (EXPERIMENTAL).

This module exposes low-level functionality for the implementation of a debugger for Erlang.

Any local process can register itself as the debugger for a node, but there can be at most one such process registered at any given time. Using the BIFs in this module, a debugger can:

- set breakpoints;
- inspect internal process state, such registers, stack-frames;
- get notified on debugger events such as a process hitting a breakpoint;
- resume processes paused on breakpoints

At the moment, the API is highly experimental; so don't depend on it, or otherwise expect frequent incompatible changes.

## Summary

### Types

event()

Debugger events.

event_message()

The debugger process will receive debugger-event messages, wrapped in an envelope of this type.

instrumentation()

Debugging instrumentations that can be applied on module loading.

reg_val()

The value of an X or a Y register, provided it fits within the requested size.

session()

Debugger session identifier.

stack_frame()

A stack-frame, including the value of each slot.

stack_frame_fun()

What is running in each stack frame, including special VM frames.

stack_frame_info()

Extra information about a stack-frame.

stack_frame_slot()

The contents of a stack frame slot can be a Y register or an exception handler.

### Functions

breakpoint(Module, Line, Flag)

Sets or clear a breakpoint on the given Module/Line.

breakpoints(Module)

Returns information on available breakpoints for a module.

breakpoints(Module, FunName, Arity)

Returns information on available breakpoints for a given function. .

instrumentations()

Returns the instrumentations that will be applied on module loading.

peek_stack_frame_slot(Pid, FrameNo, Slot, MaxSize)

Gets the value of a slot in a suspended process stack-frame.

peek_xreg(Pid, Reg, MaxSize)

Get the value of an X register for a suspended process.

register(Pid)

Register the given process as the debugger.

stack_frames(Pid, MaxTermSize)

Get the all the stack-frames for a suspended process.

supported()

Returns `true` if the emulator supports debugging.

toggle_instrumentations(Toggle)

Updates the instrumentations that will be applied on module loading.

unregister(Pid, Session)

Unregisters the given process.

whereis()

Returns the pid of the registered debugger.

xregs_count(Pid)

Get the number of X registers currently in use by a suspended process.

## Types

# event()

(since OTP 28.0)

    -type event() :: {breakpoint, pid(), mfa(), Line :: pos_integer(), Resume :: fun(() -> ok)}.

Debugger events.

Here are the possible events:

- `{breakpoint, Pid, {M,F,A}, Line, Resume}`: process Pid hit a breakpoint on module `M`, at the given `Line`. The debugger can resume the process by executing `Resume()`.

# event_message()

(since OTP 28.0)

    -type event_message() :: {debugger_event, session(), event()}.

The debugger process will receive debugger-event messages, wrapped in an envelope of this type.

# instrumentation()

(since OTP 28.0)

    -type instrumentation() :: line_breakpoint.

Debugging instrumentations that can be applied on module loading.

- `line_breakpoint`: Allows setting breakpoints at the beginning of executable lines

# reg_val()

(since OTP 28.0)

    -type reg_val() :: {value, term()} | {too_large, Size :: pos_integer()}.

The value of an X or a Y register, provided it fits within the requested size.

If it is too large, then size of the term.

# session()

(since OTP 28.0)

    -opaque session()

Debugger session identifier.

It is attached to all debugger events.

# stack_frame()

(since OTP 28.0)

    -type stack_frame() :: {FrameNo :: non_neg_integer(), stack_frame_fun(), stack_frame_info()}.

A stack-frame, including the value of each slot.

# stack_frame_fun()

(since OTP 28.0)

    -type stack_frame_fun() ::
              #{function := mfa(), line := pos_integer() | undefined} |
              '<terminate process>' | '<continue terminate process>' | '<terminate process normally>' |
              '<breakpoint>' | 'unknown function'.

What is running in each stack frame, including special VM frames.

# stack_frame_info()

(since OTP 28.0)

    -type stack_frame_info() :: #{slots := [stack_frame_slot()], code := pos_integer()}.

Extra information about a stack-frame.

- `slots`: Y-registers (in order `[Y0,...Yk])`, followed by exception-handlers.
- `code`: Memory address of the next instruction to execute in this frame.

# stack_frame_slot()

(since OTP 28.0)

    -type stack_frame_slot() :: reg_val() | {'catch', stack_frame_fun()}.

The contents of a stack frame slot can be a Y register or an exception handler.

## Functions

# breakpoint(Module, Line, Flag)

(since OTP 28.0)

    -spec breakpoint(Module, Line, Flag) -> ok | {error, Reason}
                        when
                            Module :: module(),
                            Line :: pos_integer(),
                            Flag :: boolean(),
                            Reason :: {unsupported, Module | Line} | {badkey, Module | Line}.

Sets or clear a breakpoint on the given Module/Line.

When a process hits a breakpoint, it will pause and a `breakpoint` message is sent to the registered debugger.

Returns `ok` on success. It can fail with the following reasons:

- `{badkey, Module}`: The given module is not loaded.
- `{unsupported, Module}`: The module was loaded without support for line breakpoints.
- `{badkey, Line}`: The line is not relevant; it could refer to a comment, not existing in the module source, and so on.
- `{unsupported, Line}`: It is not possible to set a breakpoint in in the given line; for example, if it refers to a function head.

# breakpoints(Module)

(since OTP 28.0)

    -spec breakpoints(Module) -> {ok, Result} | {error, Reason}
                         when
                             Module :: module(),
                             Result :: #{Fun => #{Line => boolean()}},
                             Fun :: {atom(), arity()},
                             Line :: pos_integer(),
                             Reason :: badkey.

Returns information on available breakpoints for a module.

For each function in the module, returns a map `#{Line => boolean()}`, where the keys are lines where breakpoints can be set, and the value represents whether be breakpoint is enabled (`true`) or not (`false`).

# breakpoints(Module, FunName, Arity)

(since OTP 28.0)

    -spec breakpoints(Module, FunName, Arity) -> {ok, Result} | {error, Reason}
                         when
                             Module :: module(),
                             FunName :: atom(),
                             Arity :: arity(),
                             Result :: #{Line => boolean()},
                             Line :: pos_integer(),
                             Reason :: {badkey, module() | {FunName, Arity}}.

Returns information on available breakpoints for a given function. .

The function need not be exported.

Returns a map `#{Line => boolean()}`, where the keys are lines where breakpoints can be set, and the value represents whether be breakpoint is enabled (`true`) or not (`false`).

# instrumentations()

(since OTP 28.0)

    -spec instrumentations() -> #{instrumentation() => boolean()}.

Returns the instrumentations that will be applied on module loading.

Modules that are already loaded may have had a different set of instrumentations applied.

# peek_stack_frame_slot(Pid, FrameNo, Slot, MaxSize)

(since OTP 28.0)

    -spec peek_stack_frame_slot(Pid, FrameNo, Slot, MaxSize) -> running | undefined | stack_frame_slot()
                                   when
                                       Pid :: pid(),
                                       FrameNo :: pos_integer(),
                                       Slot :: non_neg_integer(),
                                       MaxSize :: non_neg_integer().

Gets the value of a slot in a suspended process stack-frame.

Returns `running` if the process is not suspended, and `undefined` if the frame or the slot does not exist for that process. Otherwise, returns the slot, that can be a term, if its size is less than `MaxTermSize`, or an exeption handler.

# peek_xreg(Pid, Reg, MaxSize)

(since OTP 28.0)

    -spec peek_xreg(Pid, Reg, MaxSize) -> running | undefined | reg_val()
                       when Pid :: pid(), Reg :: non_neg_integer(), MaxSize :: non_neg_integer().

Get the value of an X register for a suspended process.

# register(Pid)

(since OTP 28.0)

    -spec register(Pid) -> {ok, session()} | {error, already_exists} when Pid :: pid().

Register the given process as the debugger.

If the registration succeeds, it returns `{ok, Session}`, where `Session` is a token that will be included in every message sent to the process.

Returns `{error, already_exists}` if some process is currently registered as debugger.

# stack_frames(Pid, MaxTermSize)

(since OTP 28.0)

    -spec stack_frames(Pid, MaxTermSize) -> running | [stack_frame()]
                          when Pid :: pid(), MaxTermSize :: non_neg_integer().

Get the all the stack-frames for a suspended process.

If the given process is not in a suspended state, returns `running`. Otherwise, a list of stack frames including the content of each slot is returned. For slots containing terms, `MaxTermSize` controls the maximum size of values that are allowed to be returned (to avoid accidentally blowing the heap of the caller).

# supported()

(since OTP 28.0)

    -spec supported() -> boolean().

Returns `true` if the emulator supports debugging.

The debugger can only be used if the `+D` argument was passed to the emulator on start-up.

# toggle_instrumentations(Toggle)

(since OTP 28.0)

    -spec toggle_instrumentations(Toggle) -> ok when Toggle :: #{instrumentation() => boolean()}.

Updates the instrumentations that will be applied on module loading.

Modules that are already loaded will keep the instrumentation they had at their time of loading.

# unregister(Pid, Session)

(since OTP 28.0)

    -spec unregister(Pid, Session) -> ok when Pid :: pid(), Session :: session().

Unregisters the given process.

The session given on registration needs to be provided.

# whereis()

(since OTP 28.0)

    -spec whereis() -> undefined | pid().

Returns the pid of the registered debugger.

# xregs_count(Pid)

(since OTP 28.0)

    -spec xregs_count(Pid) -> running | non_neg_integer() when Pid :: pid().

Get the number of X registers currently in use by a suspended process.