NAME
Devel::Chitin - Programmatic interface to the Perl debugging API
SYNOPSIS
package CLIENT;
use base 'Devel::Chitin';
# These inherited methods can be called by the client class
CLIENT->attach(); # Register with the debugging system
CLIENT->detach(); # Un-register with the debugging system
CLIENT->step(); # single-step into subs
CLIENT->stepover(); # single-step over subs
CLIENT->stepout(); # Return from the current sub, then stop
CLIENT->continue(); # Run until the next breakpoint
CLIENT->trace([$flag]); # Get/set the trace flag
CLIENT->disable_debugger(); # Deactivate the debugging system
CLIENT->is_loaded($file); # Return true if the file is loaded
CLIENT->loaded_files(); # Return a list of loaded file names
CLIENT->postpone($file, $subref); # Run $subref->() when $file is loaded
CLIENT->is_breakable($file, $line); # Return true if the line is executable
CLIENT->stack(); # Return Devel::Chitin::Stack
CLIENT->current_location(); # Where is the program stopped at?
CLIENT->next_statement(); # Return the next statement to execute
CLIENT->next_fragment([$parents]); # Return the next op to execute
CLIENT->add_watchexpr($expr); # Add a new watch expression
CLIENT->remove_watchexpr($expr); # Remove a watch expression
# These methods are called by the debugging system at the appropriate time.
# Base-class methods do nothing. These methods must not block.
CLIENT->init(); # Called when the debugging system is ready
CLIENT->poll($location); # Return true if there is user input
CLIENT->idle($location); # Handle user interaction (can block)
CLIENT->notify_trace($location); # Called on each executable statement
CLIENT->notify_trace_resumed($location); # Called before the program gets control after trace
CLIENT->notify_stopped($location); # Called when a break has occured
CLIENT->notify_resumed($location); # Called before the program gets control after a break
CLIENT->notify_fork_parent($location,$pid); # Called after fork() in parent
CLIENT->notify_fork_child($location); # Called after fork() in child
CLIENT->notify_program_terminated($?); # Called as the program is finishing
CLIENT->notify_program_exit(); # Called as the program is exiting
CLIENT->notify_uncaught_exception($exc); # Called after an uncaught exception
CLIENT->notify_watch_expr($location, $expr, $old, $new);
# Called when a watch expr changes
DESCRIPTION
This class exposes the Perl debugging facilities as an API useful for implementing debuggers, tracers, profilers, etc so they can all benefit from common code.
Devel::Chitin is not a usable debugger per se. It has no mechanism for interacting with a user such as reading command input or printing results. Instead, clients of this API may call methods to inspect the debugged program state. The debugger core calls methods on clients when certain events occur, such as when the program is stopped by breakpoint or when the program exits. Multiple clients can attach themselves to Devel::Chitin simultaneously within the same debugged program.
CONSTRUCTOR
This class does not supply a constructor. Clients wishing to use this API must inherit from this class and call the attach
method. They may use whatever mechanism they wish to implement their object or class.
API Methods
These methods are provided by the debugging API and may be called as inherited methods by clients.
- CLIENT->attach()
-
Attaches a client to the debugging API. May be called as a class or instance method. When later client methods are called by the debugging API, the same invocant will be used.
- CLIENT->detach()
-
Removes a client from the debugging API. The invocant must match a previous
attach
call. - CLIENT->trace([1 | 0])
-
Get or set the trace flag. If trace is on, the client will get notified before every executable statement by having its
notify_trace
method called, and before returning to the debugged program by having itsnotify_trace_resumed
method called. - CLIENT->disable_debugger()
-
Turn off the debugging system. The debugged program will continue normally. The debugger system will not be triggered afterward.
- CLIENT->postpone($file, $subref)
-
Causes
$subref
to be called when $file is loaded. If $file is already loaded, then $subref will be called immediately.
Program control methods
- CLIENT->step()
-
Single-step the next statement in the debugged program. If the next statement is a subroutine call, the debugger will stop on its first executable statement.
- CLIENT->stepover()
-
Single-step the next statement in the debugged program. If the next statement is a subroutine call, the debugger will stop on its first executable statement after that subroutine call returns.
- CLIENT->stepout()
-
Continue running the debugged program until the current subroutine returns or until the next breakpoint, whichever comes first.
- CLIENT->stepout(cb => $subref);
-
This form of stepout() allows registering a callback to be invoked when the current subroutine returns. The callback's first argument is an instance of Devel::Chitin::SubroutineReturn, which provides access to the location the function is returning from, its wantarray status, and the function's return value. The
rv
property of the SubroutineReturn object is mutable, and actually changes the value being returned from the function.Callbacks are invoked in the order they are queued, and a return value changed in this way is presented as the return value to the next callback. The final callback gets the last say about the ultimate return value from the function.
- CLIENT->continue()
-
Continue running the debugged program until the next breakpoint.
- CLIENT->user_requested_exit()
-
Sets a flag that indicates the program should completely exit after the debugged program ends. Normally, the debugger will regain control after the program ends.
- CLIENT->eval($string, $wantarray, $coderef);
-
Evaluate the given string in the context of the most recent stack frame of the program being debugged. Because of the limitations of Perl's debugging hooks, this function does not return the value directly. Instead, the caller must cede control back to the debugger system and the eval will be done before the next statement in the program being debugged. If the debugged program is currently stopped at a breakpoint, then the eval will be done before resuming.
The result is delivered by calling the given $coderef with two arguments: the $result and $exception. If $wantarray was true, then the result will be an arrayref.
- CLIENT->eval_at($string [, $level]);
-
Evaluate the given string in the context of the program being debugged. If $level is omitted, the string is run in the context of the most recent stack frame of the debugged program. Otherwise, $level is the number of stack frames before the most recent to evaluate the code in. Negative numbers are treated as 0. eval_at returns a list of two items, the result and exception.
This method requires the PadWalker module.
This method is not yet implemented.
- CLIENT->get_var_at_level($string, $level);
-
Return the value of the given variable expression. $level is the stack level in the context of the debugged program; 0 is the most recent level. $string is the name of the variable to inspect, including the sigil. This method handles some more complicated expressions such array and hash elements and slices.
This method is temporary, until eval_at() is implemented.
Informational methods
- CLIENT->is_loaded($file)
-
Return true if the file is loaded
- CLIENT->loaded_files()
-
Return a list of loaded file names
- CLIENT->is_breakable($file, $line)
-
Return true if the line has an executable statement. Only lines with executable statements may have breakpoints. In particular, line containing only comments, whitespace or block delimiters are typically not breakable.
- CLIENT->subroutine_location($subroutine)
-
Return a Devel::Chitin::SubroutineLocation instance for where the named subroutine was defined.
$subroutine
should be fully qualified including the package name.If the named function does not exist, it returns undef.
- CLIENT->stack()
-
Return an instance of Devel::Chitin::Stack. This object represents the execution/call stack of the debugged program.
- CLIENT->current_location()
-
Return an instance of Devel::Chitin::Location representing the currently stopped location in the debugged program. This method returns undef if called when the debugged program is actively running.
- CLIENT->next_statement()
-
Returns a string representing the next Perl statement to execute when control returns to the debugged program with "step over". This involves inspecting the OpTree of the currently executing subroutine and deparsing it at the stopped location. Since the returned string is a reconstruction based on the OpTree, it may not match the original source code exactly.
The deparse normally starts by finding the closest contol OP (COP) before the current OP, then deparsing its sibling. In some cases this results in a misleading deparse, so some adjustments may be made to the starting OP:
- while loop (enterloop/leaveloop)
-
Return the while loop condition instead of the whole loop
- list or function call (pushmark)
-
Return either the list construction or the function call
- if() or unless() statement
-
Return the if () condition instead of the entire if()/unless() statement
- block map/grep (mapstart/grepstart)
-
Return the list being mapped/grepped over
Requires the Devel::Callsite module to be installed.
- CLIENT->next_fragment($parents)
-
Returns a string representing the next Perl operation to execute when control returns to the debugged program. This differes from next_statement() in that next_fragment() only deparses the immediately next opcode (and its children).
$parents
is an optional param to indicate how many parent OPs to back up before deparsing. - CLIENT->file_source($filename)
-
Return a list of strings containing the source code for a loaded file.
Breakpoints and Actions
See Devel::Chitin::Actionable for documentation on setting breakpoints and actions.
Watch expressions
Watch expressions are evaluated before each statement in the program. If a watched expression's value ever changes, the client that added the expression will be notified via its notify_watch_expr()
method. These expressions are always evaluated in list context. They are considered changed if the list's length changes, or if one of the elements has a different value when compared as strings. This comparison is only shallow; it will not recurse into references or nested data structures.
- CLIENT->add_watch_expr($expression)
-
Adds a new watch expression linked to the calling client.
- CLIENT->remove_watch_expr($expression)
-
Remove a previously added watch expression. Returns false if the expression was not previously added with
add_watch_expr()
.
CLIENT METHODS
These methods exist in the base class, but only as empty stubs. They are called at the appropriate time by the debugging system. Clients may provide their own implementation.
With the exception of idle
, these client-provided methods must not block so that other clients may get called.
- CLIENT->init()
-
Called before the first breakpoint, usually before the first executable statement in the debugged program. Its return value is ignored
- CLIENT->poll($location)
-
Called when the debugger is stopped on a line. This method should return true to indicate that it wants its
idle
method called.$location
is an instance of Devel::Chitin::Location indicating the next statement to be executed in the debugged program. - CLIENT->idle($location)
-
Called when the client can block, to accept and process user input, for example. This method should return true to indicate to the debugger system that it has finished processing, and that it is OK to continue the debugged program. The loop around calls to
idle
will stop when all clients return true. - CLIENT->notify_trace($location)
-
If a client has turned on the trace flag, this method will be called before each executable statement. The return value is ignored.
- CLIENT->notify_trace_resumed($location)
-
If a client has turned on the trace flag, this method will be called before the debugged program regains control. The return value is ignored.
notify_trace() will be called only on clients that have requested tracing by calling CLIENT->trace(1).
- CLIENT->notify_stopped($location)
-
This method is called when a breakpoint has occurred. Its return value is ignored.
- CLIENT->notify_resumed($location)
-
This method is called after a breakpoint, after any calls to
idle
, and just before the debugged program resumes execution. The return value is ignored. - CLIENT->notify_fork_parent($location, $pid)
-
This method is called immediately after the debugged program calls fork() in the context of the parent process.
$pid
is the child process ID created by the fork. The return value is ignored.Note that the $location will be the first executable statement after the fork() in the parent process.
- CLIENT->notify_fork_child($location)
-
This method is called immediately after the debugged program calls fork() in the context of the child process. The return value is ignored.
Note that the $location will be the first executable statement after the fork() in the parent process.
- CLIENT->notify_program_terminated($?)
-
This method is called after the last executable statement in the debugged program. After all clients are notified, the debugger system emulates one final breakpoint inside a function called
at_exit
and the program remains running, though stopped. - CLIENT->notify_program_exit()
-
If the a client has requested that the program terminate completely by calling CLIENT->user_requested_exit(), then this method will be called during the debugger's END block as the interpreter is cleaning up.
- CLIENT->notify_uncaught_exception($exception)
-
The debugger system installs a __DIE__ handler to trap exceptions that are not otherwise handled by the debugged program. When an uncaught exception occurs, this method is called. $exception is an instance of Devel::Chitin::Exception.
- CLIENT->notify_watch_expr($location, $expr, $old, $new);
-
Called when a client has added a watchexpr expression and its value has changed. Since watch expressions are evaluated in list context, $old and $new are listrefs containing the previous and new values.
The location reported is whichever program line was executing immediately prior to the current line.
Note that this does not stop execution of the debugged program. The notify_watch_expr() method should call
CLIENT->step
to trigger a breakpoint.
BUGS
As this is an extremely early release, this API should be considered experimental. It was developed to extract the debugger-specific code from Devel::hdb. I encourage others to make suggestions and submit bug reports so we can converge on a usable API quickly.
SEE ALSO
Devel::Chitin::Location, Devel::Chitin::Exception, Devel::Chitin::Stack, Devel::Chitin::Actionable, Devel::Chitin::GetVarAtLevel, Devel::Callsite
The API for this module was inspired by DB
AUTHOR
Anthony Brummett <brummett@cpan.org>
COPYRIGHT
Copyright 2017, Anthony Brummett. This module is free software. It may be used, redistributed and/or modified under the same terms as Perl itself.