View Source edb (edb_core v0.5.0)
The (new!) Erlang debugger
Summary
Types
A breakpoint may not be added for various reasons
Functions
Set a breakpoint on the line of a loaded module on the attached node.
Start a debugging session by attaching to the given node.
Returns the node being debugged.
Clear a previously set breakpoint on the attached node.
Clear all previously set breakpoints of a module on the attached node.
Continues the execution on the attached node and returns right away.
Returns not_paused
if no process was paused, otherwise resumed
.
Detach from the currently attached node.
The provided function will be given the requested stack-frame variables of the process, and the result of the evaluation, if successful, will be returned.
Add a single process to the set of processes excluded from debugging.
It is equivalent to exclude_processes([{proc, Proc}])
.
Extend the set of processes excluded by the debugger.
List the pids that will not be paused by the debugger on the attached node.
Get all currently set breakpoints on the attached node.
Get currently set breakpoints for a given module on the attached node.
Get the list of processes currently paused at a breakpoint on the attached node.
Check if there exists paused processes.
Pause the execution of the attached node.
Get information about a process managed by the debugger on the attached node.
Get the set of processes managed by the debugger on the attached node.
Prepare for attachment by a node that doesn't exist yet.
Request that a sync
event is sent to the given subscription.
Set breakpoints on multiple lines of a given module, on the attached node.
Get the local variables for a paused processes at a give frame.
Get the local variables for a paused process at a given frame.
Get the stack frames for a paused process.
Continues the execution on the attached node and returns right away.
Execution will stop once Pid
enters the current call target, or if
an exception raised by any of its arguments is caught.
Continues the execution on the attached node and returns right away.
Execution will stop once Pid
exits the current function.
Continues the execution on the attached node and returns right away.
Execution will stop once Pid
finishes executing the next expression.
Subscribe caller process to receive debugging events from the attached node.
Terminates the debugging session.
Removes an exclusion previously added with exclude_processes/1
.
Remove a previously added subscription.
Waits until the node gets paused.
Types
-type add_breakpoint_error() :: unsupported | {unsupported, module()} | {unsupported, Line :: line()} | {badkey, module()} | {badkey, Line :: line()}.
A breakpoint may not be added for various reasons:
unsupported
: The node does not support line-breakpoint instrumentations (likely for not being started with the+D
emulator flag).{badkey, Module}
: The given module does not exist or can't be loaded.{unsupported, Module}
: The module was loaded without suppor for line-breakpoints.{badkey, Line}
: The line is not relevant; it could refer to a comment, not exist in the module source, and so on.{unsupported, Line}
: It is not possible to set a breakpoint in the given line; for example, if it refers to a function head.
-type eval_error() :: timeout | {exception, #{class := error | exit | throw, reason := term(), stacktrace := erlang:stacktrace()}} | {killed, Reason :: term()}.
-type event() :: {resumed, resumed_event()} | {paused, paused_event()} | {sync, reference()} | {terminated, Reason :: term()} | unsubscribed | {nodedown, node(), Reason :: term()}.
-type event_envelope(Event) :: {edb_event, event_subscription(), Event}.
-type event_subscription() :: edb_events:subscription().
-type exclusion_reason() ::
debugger_component | excluded_application | excluded_pid | excluded_regname | system_component.
-type frame_id() :: non_neg_integer().
-type fun_name() :: atom().
-type line() :: pos_integer().
-type process_info() :: #{application => atom(), current_bp => {line, line()}, current_fun => mfa(), current_loc => {string(), line()}, exclusion_reasons => [exclusion_reason()], message_queue_len => non_neg_integer(), parent => atom() | pid(), pid_string => binary(), registered_name => atom(), status => process_status()}.
-type process_info_field() ::
application | current_bp | current_fun | current_loc | exclusion_reasons | message_queue_len |
parent | pid_string | registered_name | status.
-type process_status() :: running | paused | breakpoint.
-type resumed_event() :: {continue, all} | {excluded, #{pid() => []}} | {termination, all}.
-type set_breakpoints_result() :: [{line(), Result :: ok | {error, add_breakpoint_error()}}].
-type stack_frame() :: #{id := frame_id(), mfa := mfa() | unknown, source := file:filename() | undefined, line := line() | undefined}.
-type step_error() :: not_paused | {cannot_breakpoint, module()}.
-type step_in_error() :: step_error() | {call_target, call_target_error()}.
-type value() :: {value, term()} | {too_large, Size :: pos_integer(), Max :: non_neg_integer()}.
Functions
-spec add_breakpoint(Module, Line) -> ok | {error, Reason} when Module :: module(), Line :: line(), Reason :: edb:add_breakpoint_error().
Set a breakpoint on the line of a loaded module on the attached node.
-spec attach(#{node := node(), timeout => timeout(), cookie => atom()}) -> ok | {error, Reason} when Reason :: attachment_in_progress | nodedown | {bootstrap_failed, bootstrap_failure()}.
Start a debugging session by attaching to the given node.
If edb was already attached to a node, it will get detached first. The attached node may already have a debugging session in progress, in this case, edb joins it.
This call may start distribution and set the node name.
Arguments:
node
- the node to attach totimeout
- how long to wait for the node to be up; defaults to 0,- 'cookie' - cookie to use for connecting to the node
-spec attached_node() -> node().
Returns the node being debugged.
Will raise a not_attached
error if not attached.
-spec clear_breakpoint(Module, Line) -> ok | {error, not_found} when Module :: module(), Line :: line().
Clear a previously set breakpoint on the attached node.
-spec clear_breakpoints(Module) -> ok when Module :: module().
Clear all previously set breakpoints of a module on the attached node.
-spec continue() -> {ok, resumed | not_paused}.
Continues the execution on the attached node and returns right away.
Returns not_paused
if no process was paused, otherwise resumed
.
-spec detach() -> ok.
Detach from the currently attached node.
The debugger session running on the node is left undisturbed.
-spec eval(Opts) -> not_paused | undefined | {ok, Result} | {eval_error, eval_error()} when Opts :: #{context := {pid(), frame_id()}, max_term_size := non_neg_integer(), timeout := timeout(), function := fun((Vars :: stack_frame_vars()) -> Result), dependencies => [module()]}.
The provided function will be given the requested stack-frame variables of the process, and the result of the evaluation, if successful, will be returned.
Notice that, if missing, the debuggee node will load the given function's module,
and any other modules listed under dependencies
, taking the object code from the
caller node. It is the caller's responsibility to ensure that any dependency of the
function is listed under dependencies
.
Add a single process to the set of processes excluded from debugging.
It is equivalent to exclude_processes([{proc, Proc}])
.
-spec exclude_processes(Specs) -> ok when Specs :: [procs_spec()].
Extend the set of processes excluded by the debugger.
Processes can be specified in the following ways:
- by pid,
- by being part of an application,
- exception list for pids that should not be excluded
E.g. a spec like:
[Pid1, {appication, foo}, {application, bar}, {except, Pid2}, {except, Pid3}]
will exclude Pid1
and all processes in applications foo
and bar
; however
Pid2
and Pid3
are guaranteed not to be excluded, whether they are part
of foo
, bar
, etc. The order of the spec clauses is irrelevant and, in
particular, except
clauses are global.
If any specified processes are currently paused, they will be automatically resumed.
-spec excluded_processes(RequestedFields) -> #{pid() => []} when RequestedFields :: [process_info_field()].
List the pids that will not be paused by the debugger on the attached node.
-spec get_breakpoints() -> #{module() => [breakpoint_info()]}.
Get all currently set breakpoints on the attached node.
-spec get_breakpoints(Module) -> [breakpoint_info()] when Module :: module().
Get currently set breakpoints for a given module on the attached node.
-spec get_breakpoints_hit() -> #{pid() => breakpoint_info()}.
Get the list of processes currently paused at a breakpoint on the attached node.
-spec is_paused() -> boolean().
Check if there exists paused processes.
-spec pause() -> ok.
Pause the execution of the attached node.
-spec process_info(Pid, RequestedFields) -> {ok, process_info()} | undefined when Pid :: pid(), RequestedFields :: [process_info_field()].
Get information about a process managed by the debugger on the attached node.
-spec processes(RequestedFields) -> #{pid() => process_info()} when RequestedFields :: [process_info_field()].
Get the set of processes managed by the debugger on the attached node.
-spec reverse_attach(Opts) -> {ok, Info} | {error, Reason} when Opts :: #{name_domain := longnames | shortnames, timeout => timeout()}, Info :: #{erl_code_to_inject := binary(), notification_ref := reference()}, Reason :: attachment_in_progress.
Prepare for attachment by a node that doesn't exist yet.
The caller is expected to start a new node, and ensure it executes the
code returned by this call. The caller can then expect to receive a message tagged
with the reference in notification_ref
, containing the result of the reverse attachment.
When the node executes the injected code, it will be forced to become attached, and immediately paused.
As long as timeout
is not infinity
, the caller is guaranteed to eventually receive
a message of the form:
{NotificationRef, ok}
: The reverse attachment succeeded, the node is now paused.{NotificationRef, timeout}
: The reverse attachment timed out; it will now never happen.{NotificationRef, {error, {bootstrap_failed, BootstrapFailure}}}
: We tried to bootstrap edb on the node but failed
This call may start distribution and set the node name.
Options:
name_domain
: whether we expect to be attached by a node using longnames or shortnames;timeout
: how long to wait for the node to be up; defaults to infinity.
-spec send_sync_event(Subscription) -> {ok, SyncRef} | undefined when Subscription :: event_subscription(), SyncRef :: reference().
Request that a sync
event is sent to the given subscription.
The process holding the subscription will receive a sync
event,
with the returned reference as value. This can be used to ensure that
there are no events the server is planning to send.
Returns {error, unknown_subscription}
if the subscription is not known.
-spec set_breakpoints(Module, [Line]) -> Result when Module :: module(), Line :: line(), Result :: set_breakpoints_result().
Set breakpoints on multiple lines of a given module, on the attached node.
Notice that Module
may get loaded as a side-effect of this call.
-spec stack_frame_vars(Pid, FrameId) -> not_paused | undefined | {ok, Result} when Pid :: pid(), FrameId :: frame_id(), Result :: stack_frame_vars().
Get the local variables for a paused processes at a give frame.
Equivalent to stack_frame_vars(Pid, FrameId, 2048)
.
-spec stack_frame_vars(Pid, FrameId, MaxTermSize) -> not_paused | undefined | {ok, Result} when Pid :: pid(), FrameId :: frame_id(), MaxTermSize :: non_neg_integer(), Result :: stack_frame_vars().
Get the local variables for a paused process at a given frame.
The value of FrameId
must be one of the frame-ids returned
by stack_frames/1
, or the call will return undefined
.
For each variable, the value is returned only if its internal
size is at most MaxTermSize
, otherwise {too_large, Size, MaxTermSize}
is returned. This is to prevent the caller from getting
objects that are larger than they are willing to handle.
-spec stack_frames(Pid) -> not_paused | {ok, [Frame]} when Pid :: pid(), Frame :: stack_frame().
Get the stack frames for a paused process.
The FrameNo
can then be used to retrieve the variables for
a particular frame.
-spec step_in(Pid) -> ok | {error, step_in_error()} when Pid :: pid().
Continues the execution on the attached node and returns right away.
Execution will stop once Pid
enters the current call target, or if
an exception raised by any of its arguments is caught.
Returns {error, {call_target, Reason}}
in case the call-target cannot
be determined.
-spec step_out(Pid) -> ok | {error, step_error()} when Pid :: pid().
Continues the execution on the attached node and returns right away.
Execution will stop once Pid
exits the current function.
-spec step_over(Pid) -> ok | {error, step_error()} when Pid :: pid().
Continues the execution on the attached node and returns right away.
Execution will stop once Pid
finishes executing the next expression.
Caveat:
- If the next expression is a recursive tail-call, execution will stop when the callee starts.
- This is unlike non-recursive tail-calls, where execution will stop when the callee ends
-spec subscribe() -> {ok, event_subscription()}.
Subscribe caller process to receive debugging events from the attached node.
The caller process can then expect messages of type event_envelope(event())
, with
the specified subscription in the envelope.
A process can hold multiple subscriptions and can unsubscribe from them individually.
-spec terminate() -> ok.
Terminates the debugging session.
Detaches from the node, but stopping the debugger running on it. That means that breakpoints will be cleared, and any paused processes will be resumed, etc.
-spec unexclude_processes(Specs) -> ok when Specs :: [procs_spec()].
Removes an exclusion previously added with exclude_processes/1
.
If there are currently paused processes, any specified processes will be paused as well.
-spec unsubscribe(Subscription) -> ok when Subscription :: event_subscription().
Remove a previously added subscription.
The caller process need not be the one holding the subscription. An unsubscribed
event
will be sent as final event to the subscription, which marks the end of the event stream.
-spec wait() -> {ok, paused}.
Waits until the node gets paused.