Devel-ebug-0.55000755001750001750 012122201364 13650 5ustar00awwaiidawwaiid000000000000Devel-ebug-0.55/MANIFEST000444001750001750 247412122201364 15145 0ustar00awwaiidawwaiid000000000000Build.PL CHANGES MANIFEST This list of files README TODO bin/ebug bin/ebug_backend_perl bin/ebug_client bin/ebug_server lib/Devel/ebug.pm lib/Devel/ebug/Backend.pm lib/Devel/ebug/Backend/Plugin/ActionPoints.pm lib/Devel/ebug/Backend/Plugin/Basic.pm lib/Devel/ebug/Backend/Plugin/Codelines.pm lib/Devel/ebug/Backend/Plugin/Commands.pm lib/Devel/ebug/Backend/Plugin/Eval.pm lib/Devel/ebug/Backend/Plugin/Filenames.pm lib/Devel/ebug/Backend/Plugin/Output.pm lib/Devel/ebug/Backend/Plugin/Pad.pm lib/Devel/ebug/Backend/Plugin/Ping.pm lib/Devel/ebug/Backend/Plugin/Run.pm lib/Devel/ebug/Backend/Plugin/StackTrace.pm lib/Devel/ebug/Console.pm lib/Devel/ebug/Plugin/ActionPoints.pm lib/Devel/ebug/Plugin/Basic.pm lib/Devel/ebug/Plugin/Codelines.pm lib/Devel/ebug/Plugin/Eval.pm lib/Devel/ebug/Plugin/Filenames.pm lib/Devel/ebug/Plugin/Output.pm lib/Devel/ebug/Plugin/Pad.pm lib/Devel/ebug/Plugin/Run.pm lib/Devel/ebug/Plugin/StackTrace.pm t/Calc.pm t/basic.t t/break_point.t t/calc.pl t/calc_oo.pl t/calc_subref.pl t/carp.pl t/codelines.t t/ebug.t t/eval.t t/filenames.t t/finished.t t/koremutake.pl t/koremutake.t t/oo.t t/output.t t/pad.t t/pod.pl t/pod.t t/return.t t/run.t t/signal.pl t/signal.t t/stack.pl t/stack.t t/subrefs.t t/subroutine.t t/undo.t t/watch_point.t t/yaml.pl t/breakOnLoad.t t/load_calc.pl Makefile.PL META.yml META.json Devel-ebug-0.55/Build.PL000444001750001750 161312122201364 15302 0ustar00awwaiidawwaiid000000000000use strict; use lib 'lib'; use lib '../lib'; use Module::Build; my $requires = { 'Carp' => '0', 'Class::Accessor::Chained::Fast' => '0', 'Devel::StackTrace' => '0', 'IO::Socket::INET' => '0', 'File::Find' => '0', 'Module::Pluggable' => '0', 'PadWalker' => '0', 'Proc::Background' => '0', 'Scalar::Util' => '0', 'String::Koremutake' => '0', 'Test::More' => '0', 'YAML' => '0', }; # Test::Expect doesn't run under Windows atm if ($^O !~ /mswin32/i) { $requires->{'Test::Expect'} = '0'; } my $build = Module::Build->new( create_makefile_pl => 'small', license => 'perl', module_name => 'Devel::ebug', requires => $requires, script_files => ['bin/ebug', 'bin/ebug_client', 'bin/ebug_server', 'bin/ebug_backend_perl'], ); $build->create_build_script; Devel-ebug-0.55/CHANGES000444001750001750 2436512122201364 15032 0ustar00awwaiidawwaiid000000000000Revision history for Perl module Devel::ebug 0.55 2013.03.19 - Extra version to add missing files :) 0.54 2013.03.19 - Add 'break on file loading' feature (thanks jchassler!) - Fix commands starting with ^h 0.53 2012.02.29 - Add tests for codeline tracking and subrefs - Fix YAML vs YAML::Syck (dunno) - Had to disable return-value-override feature - Fix tests to work with new Carp - Use findbin to load backend - Improve argument param handling 0.52 2011.11.08 - Oops, forgot to update CHANGES for 0.51 :) - Slight refactor of backend executable by pmurias (thanks!) - Extract backend connection code into separate method - Shuffle executables into bin/ - Fix wantarray test for older perls - Fix some windows path usage 0.50 Thu Oct 20 20:15:05 EDT 2011 - Fix failing tests - Add YAML build dependency 0.49 Thu Oct 16 20:07:34 BST 2008 - Add a human-readable license to the documentation 0.48 Mon Apr 30 20:37:06 CEST 2007 - Added ebug-server(1), a remote debugger server - Added ebug-client(1), a remote debugger client - Fixed [?h] input handling so Perl expression with 'h' or '?' won't wrongly invoke help - Added check for PERL_DEBUG_DONT_RELAY_IO environment variable to keep STDOUT/STDERR on server side, instead of relaying to debugger frontend - Switched YAML.pm to YAML::Syck for performance reasons - All patches by Taisuke Yamada 0.47 Mon Mar 19 19:43:35 GMT 2007 - add break_points_with_condition and all_break_points_with_condition, make break_point and break_point_subroutine return a line number, make break_points optionally take a filename, make eval return whether there was an exception (patch by Mattia Barbon) 0.46 Mon Mar 6 20:52:22 GMT 2006 - workaround for bless globs (thanks to SAMV) 0.45 Fri Sep 2 15:01:42 BST 2005 - moved subroutine into basic information - moved ebug_http into its own distribution (patch by Jesse Vincent) 0.44 Wed Aug 31 16:36:03 BST 2005 - require PPI 1.003 (and work with new API) - update ebug_http to new Catalyst (removes warning) - fix bug with "run" stopping after returning back to main:: - new run.t 0.43 Mon May 16 18:55:37 BST 2005 - document that we don't quite work under 5.8.0 (thanks Simon) - Devel::ebug does not handle signals under Windows atm, so skip the tests for now (spotted by LTjake) - updated to Prototype 1.2.0 - try and find our templates a little harder - you can set set break points in ebug_http by clicking on a line number (and delete them by clickling on the little stop sign icon) - you can now evaluate Perl expressions in the web interface - major attempt to make the web interface prettier (icons!) - make some attempt at caching static files - interactive evaluation is now the default in ebug(1) (patch by Jesse Vincent) - ebug(1) now ships with an interactive console mode (patch by Jesse Vincent) 0.42 Thu Apr 28 17:42:00 BST 2005 - fix ebug_http error message - fix bug in ebug_http where the pretty printing was getting confused if the debugged program had inline POD (spotted by sri) - HTML tooltips are now in monospace, have a sensible "Not defined" error message, and show lists or hashes depending on the type. Scalars no longer have a --- prefix - fixed a bug with a missing 'Devel::ebug::Build' (spotted by obra) - use Catalyst 5.10 and its new template bundling (completely obsoleting the above change) - removed obsolete "examine" code from Devel::ebug::HTTP and template 0.41 Tue Apr 19 21:04:18 BST 2005 - remove "work around" as it is fixed in Catalyst 5.03 - fix small HTML bug (spotted by LTjake) - new xmlns + language declarations (thanks to LTjake) - minor tweak to generate valid HTML 0.40 Tue Apr 19 17:13:44 BST 2005 - whoops, we were depending on Catalyst 4 to still be around - "work around" Catalyst bug with external hostnames - updated prereqs - update docs for ebug_http 0.39 Tue Apr 19 13:16:51 BST 2005 - major refactoring of ebug_http to now use Catalyst 5.0 - we now capture STDOUT, STDERR - their contents are available using the new output method - ebug now shows STDOUT, STDERR - ebug_http now shows STDOUT, STDERR - no longer stop processing as the program exits - tab completion of variables in ebug (x $var), as suggested by Autrijus - in ebug_http, new dynamic tooltips to show the value of variables on the current line, using prototype and overlib - "return" not in a subroutine is now the same as "run" instead of giving an error (spotted by clkao) - documented that ebug and ebug_http can run programs with arguments by quoting them (spotted by clkao) - minor output patch for ebug.t - tweaked the test to skip Test::Expect under Windows - new yaml method to return the YAML representation of a variable - improved undo tests - better use of PPI (spotted by Alias) - install the templates / JavaScript / CSS / images to sitelib 0.38 Tue Apr 12 14:47:24 BST 2005 - optimisation: only scan for plugins on start of backend - be sure to use strict and warnings in the plugins - in ebug and ebug_http, allow examining a variable using YAML 0.37 Tue Apr 5 22:55:18 CST 2005 - moved ebug code into Devel::ebug::Console - moved the backend into Devel::ebug::Backend - major refactoring of Devel::ebug::Backend: move everything to subroutines, pass the context around - major refactoring to place functionality in plugins (patch by Simon Wistow) - fix a problem with code references (spotted by nadim) - we now use YAML instead of Storable - make stack_trace_human deal with undef strings, list refs, hash refs, and objects in arguments - new pad_human method for a human-readable pad view - in ebug_http, allow you to set simple break points and run - be sure to produce valid XHTML - added support for invoking the debugger by sending a signal (requested by Sam Vilain) 0.36 Sun Apr 3 20:56:56 CST 2005 - total rearrange of Devel::ebug::HTTP and increase in documentation (thanks to Mark Fowler) - create valid XML no matter what the variables or code contains (thanks to Mark Fowler) - correct the =head1 NAME of ebug and ebug_http (spotted by Smylers) - stack_trace_human is now more robust - Test::Expect doesn't work under Windows, so don't require or use it in Windows environments - this means we now require Module::Build (spotted by Johan Lindstrom) - make codelines() remove DOS as well as UNIX newlines (spotted by Johan Lindstrom) - in ebug, l 40 will to set the number of lines to list (patch by Johan Lindstrom) 0.35 Sat Apr 2 23:34:56 CST 2005 - added undo method which undos the last action - in ebug_http, using the back button in the browser actually steps backwards in the program (suggested by autrijus) - in ebug_http, use monikers for blessed objects and make the stack trace use a smaller font - in ebug, restart the program instead of exiting at the end of the program (suggested by obra) - in ebug_http, restart the program instead of stopping the webserver at the end of the program - added stack_trace_human method for a human-readable stack trace - pointed out ebug and ebug_http in the docs 0.34 Sat Apr 2 15:39:25 CST 2005 - give ebug_http a hashbang line (spotted by obra, who complains all the time ;-) - make Devel::ebug::HTTP return full HTTP requests - basic docs for ebug and ebug_http - ebug_http now opens the browser for you under Mac OS X and Windows (patch by Johan Lindstrom) - ebug now has the ability to always list the lines around the IP - L toggles (patch by Johan Lindstrom) - fix a problem where we were displaying the wrong codelines in modules with POD - now use the environment instead of the command line to pass the secret for portability (patch by Johan Lindstrom) - in ebug_http, we now jump to the current line (patch by Johan Lindstrom) - in ebug_http, make our actions POSTs, for they change state - in ebug_http, cache the call to PPI::HTML - in ebug_http, link module names to search.cpan.org - in ebug_http, syntax highlight single and double-quoted strings - tweak Devel::ebug's introductory docs - added break_point_delete method which deletes a break point - added stack_trace method which provides basic stack trace information using Devel::StackTrace - in ebug_http, added a slightly ugly stack trace - added return(@values) method to return your own values from a subroutine, instead of what the subroutine would have returned 0.33 Fri Apr 1 16:40:43 CST 2005 - update the manifest, doh (it's been a long week) 0.32 Fri Apr 1 14:09:00 CST 2005 - added "ebug_http" to script_files so that it will get installed 0.31 Fri Apr 1 13:36:00 CST 2005 - added return(), which returns from a subroutine - fix bug with 'l' showing inaccurate lines in ebug - added filenames() method which returns a list of the filenames of all the files currently loaded - added a String::Koremutake test - added a new finished() method to return whether the program has finished running (spotted by clkao) - added ebug_http, which presents a web interface to debugging 0.30 Thu Mar 31 00:13:13 CST 2005 - autrijus noticed that 0.29 shipped with a broken ebug. to keep me from embarassing myself in future, there is now an ebug.t which uses the newly-released Test::Expect - codelines() now returns an array - codelines() now returns the whole file if no line numbers are passed - codelines() can now return the source code of files other than the currently executing program - added some security to the TCP connection (port, secret) - added a new "y" to ebug, which YAML::Dump's variables - minor code cleanups 0.29 Tue Mar 29 21:02:59 CST 2005 - initial release Devel-ebug-0.55/Makefile.PL000444001750001750 42512122201364 15740 0ustar00awwaiidawwaiid000000000000# Note: this file was auto-generated by Module::Build::Compat version 0.4003 use Module::Build::Compat 0.02; Module::Build::Compat->run_build_pl(args => \@ARGV); require Module::Build; Module::Build::Compat->write_makefile(build_class => 'Module::Build'); Devel-ebug-0.55/TODO000444001750001750 271412122201364 14501 0ustar00awwaiidawwaiid000000000000Things it would be good to have in Devel::ebug: Add more Ajax to ebug_http Add more features to ebug_http Allow debugging of regexes Better error message for when server goes away (storable) Better action point setting in ebug_http Command line arguments Document keyboard shortcuts Edit program in place while still debugging using Module::Refresh Emacs Devel::ebug mode Forks: when the program being debugged forks, follow the child in ebug_http Forks: when the program being debugged forks, open a new window in ebug_http If you mouseover a variable declaration, every use of that variable is highlighted - Alias Jump to stack frame in ebug_http Localise ebug, ebug_http Make break_points able to return break points in other filenames Make break_point_subroutine take a condition Merge watch points and break points Online documentation for ebug_http (tutorial?) Optimise ebug (make timing graphs and see if we can add pipelining) PPI failures with weird characters - cope Return list/listrefs and hash/hashrefs depending on context Smart::Comments for debugging Test coverage Test ebug more Test ebug_http Test minicpan Test with bigger examples Tidy up code Use Class::ISA to show inheritance Interesting discussions about debuggers: http://blogs.msdn.com/ricksp/archive/2004/03/29/101410.aspx http://www.codeproject.com/csharp/DebuggerVisualizers.asp http://msdn.microsoft.com/msdnmag/issues/04/05/VisualStudio2005Debugging/ http://www.daimi.au.dk/~beta/ooli/Debugging.html Devel-ebug-0.55/META.json000444001750001750 1037112122201364 15450 0ustar00awwaiidawwaiid000000000000{ "abstract" : "A simple, extensible Perl debugger", "author" : [ "Latest releases by Brock Wilcox, C<< >>", "Leon Brocard, C<< >>" ], "dynamic_config" : 1, "generated_by" : "Module::Build version 0.4003, CPAN::Meta::Converter version 2.120921", "license" : [ "perl_5" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : "2" }, "name" : "Devel-ebug", "prereqs" : { "configure" : { "requires" : { "Module::Build" : "0.40" } }, "runtime" : { "requires" : { "Carp" : "0", "Class::Accessor::Chained::Fast" : "0", "Devel::StackTrace" : "0", "File::Find" : "0", "IO::Socket::INET" : "0", "Module::Pluggable" : "0", "PadWalker" : "0", "Proc::Background" : "0", "Scalar::Util" : "0", "String::Koremutake" : "0", "Test::Expect" : "0", "Test::More" : "0", "YAML" : "0" } } }, "provides" : { "DB::fake" : { "file" : "lib/Devel/ebug/Backend.pm", "version" : 0 }, "Devel::ebug" : { "file" : "lib/Devel/ebug.pm", "version" : "0.55" }, "Devel::ebug::Backend::Plugin::ActionPoints" : { "file" : "lib/Devel/ebug/Backend/Plugin/ActionPoints.pm", "version" : 0 }, "Devel::ebug::Backend::Plugin::Basic" : { "file" : "lib/Devel/ebug/Backend/Plugin/Basic.pm", "version" : 0 }, "Devel::ebug::Backend::Plugin::Codelines" : { "file" : "lib/Devel/ebug/Backend/Plugin/Codelines.pm", "version" : 0 }, "Devel::ebug::Backend::Plugin::Commands" : { "file" : "lib/Devel/ebug/Backend/Plugin/Commands.pm", "version" : 0 }, "Devel::ebug::Backend::Plugin::Eval" : { "file" : "lib/Devel/ebug/Backend/Plugin/Eval.pm", "version" : 0 }, "Devel::ebug::Backend::Plugin::Filenames" : { "file" : "lib/Devel/ebug/Backend/Plugin/Filenames.pm", "version" : 0 }, "Devel::ebug::Backend::Plugin::Output" : { "file" : "lib/Devel/ebug/Backend/Plugin/Output.pm", "version" : 0 }, "Devel::ebug::Backend::Plugin::Pad" : { "file" : "lib/Devel/ebug/Backend/Plugin/Pad.pm", "version" : 0 }, "Devel::ebug::Backend::Plugin::Ping" : { "file" : "lib/Devel/ebug/Backend/Plugin/Ping.pm", "version" : 0 }, "Devel::ebug::Backend::Plugin::Run" : { "file" : "lib/Devel/ebug/Backend/Plugin/Run.pm", "version" : 0 }, "Devel::ebug::Backend::Plugin::StackTrace" : { "file" : "lib/Devel/ebug/Backend/Plugin/StackTrace.pm", "version" : 0 }, "Devel::ebug::Console" : { "file" : "lib/Devel/ebug/Console.pm", "version" : 0 }, "Devel::ebug::Plugin::ActionPoints" : { "file" : "lib/Devel/ebug/Plugin/ActionPoints.pm", "version" : 0 }, "Devel::ebug::Plugin::Basic" : { "file" : "lib/Devel/ebug/Plugin/Basic.pm", "version" : 0 }, "Devel::ebug::Plugin::Codelines" : { "file" : "lib/Devel/ebug/Plugin/Codelines.pm", "version" : 0 }, "Devel::ebug::Plugin::Eval" : { "file" : "lib/Devel/ebug/Plugin/Eval.pm", "version" : 0 }, "Devel::ebug::Plugin::Filenames" : { "file" : "lib/Devel/ebug/Plugin/Filenames.pm", "version" : 0 }, "Devel::ebug::Plugin::Output" : { "file" : "lib/Devel/ebug/Plugin/Output.pm", "version" : 0 }, "Devel::ebug::Plugin::Pad" : { "file" : "lib/Devel/ebug/Plugin/Pad.pm", "version" : 0 }, "Devel::ebug::Plugin::Run" : { "file" : "lib/Devel/ebug/Plugin/Run.pm", "version" : 0 }, "Devel::ebug::Plugin::StackTrace" : { "file" : "lib/Devel/ebug/Plugin/StackTrace.pm", "version" : 0 } }, "release_status" : "stable", "resources" : { "license" : [ "http://dev.perl.org/licenses/" ] }, "version" : "0.55" } Devel-ebug-0.55/META.yml000444001750001750 564012122201364 15263 0ustar00awwaiidawwaiid000000000000--- abstract: 'A simple, extensible Perl debugger' author: - 'Latest releases by Brock Wilcox, C<< >>' - 'Leon Brocard, C<< >>' build_requires: {} configure_requires: Module::Build: 0.40 dynamic_config: 1 generated_by: 'Module::Build version 0.4003, CPAN::Meta::Converter version 2.120921' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: 1.4 name: Devel-ebug provides: DB::fake: file: lib/Devel/ebug/Backend.pm version: 0 Devel::ebug: file: lib/Devel/ebug.pm version: 0.55 Devel::ebug::Backend::Plugin::ActionPoints: file: lib/Devel/ebug/Backend/Plugin/ActionPoints.pm version: 0 Devel::ebug::Backend::Plugin::Basic: file: lib/Devel/ebug/Backend/Plugin/Basic.pm version: 0 Devel::ebug::Backend::Plugin::Codelines: file: lib/Devel/ebug/Backend/Plugin/Codelines.pm version: 0 Devel::ebug::Backend::Plugin::Commands: file: lib/Devel/ebug/Backend/Plugin/Commands.pm version: 0 Devel::ebug::Backend::Plugin::Eval: file: lib/Devel/ebug/Backend/Plugin/Eval.pm version: 0 Devel::ebug::Backend::Plugin::Filenames: file: lib/Devel/ebug/Backend/Plugin/Filenames.pm version: 0 Devel::ebug::Backend::Plugin::Output: file: lib/Devel/ebug/Backend/Plugin/Output.pm version: 0 Devel::ebug::Backend::Plugin::Pad: file: lib/Devel/ebug/Backend/Plugin/Pad.pm version: 0 Devel::ebug::Backend::Plugin::Ping: file: lib/Devel/ebug/Backend/Plugin/Ping.pm version: 0 Devel::ebug::Backend::Plugin::Run: file: lib/Devel/ebug/Backend/Plugin/Run.pm version: 0 Devel::ebug::Backend::Plugin::StackTrace: file: lib/Devel/ebug/Backend/Plugin/StackTrace.pm version: 0 Devel::ebug::Console: file: lib/Devel/ebug/Console.pm version: 0 Devel::ebug::Plugin::ActionPoints: file: lib/Devel/ebug/Plugin/ActionPoints.pm version: 0 Devel::ebug::Plugin::Basic: file: lib/Devel/ebug/Plugin/Basic.pm version: 0 Devel::ebug::Plugin::Codelines: file: lib/Devel/ebug/Plugin/Codelines.pm version: 0 Devel::ebug::Plugin::Eval: file: lib/Devel/ebug/Plugin/Eval.pm version: 0 Devel::ebug::Plugin::Filenames: file: lib/Devel/ebug/Plugin/Filenames.pm version: 0 Devel::ebug::Plugin::Output: file: lib/Devel/ebug/Plugin/Output.pm version: 0 Devel::ebug::Plugin::Pad: file: lib/Devel/ebug/Plugin/Pad.pm version: 0 Devel::ebug::Plugin::Run: file: lib/Devel/ebug/Plugin/Run.pm version: 0 Devel::ebug::Plugin::StackTrace: file: lib/Devel/ebug/Plugin/StackTrace.pm version: 0 requires: Carp: 0 Class::Accessor::Chained::Fast: 0 Devel::StackTrace: 0 File::Find: 0 IO::Socket::INET: 0 Module::Pluggable: 0 PadWalker: 0 Proc::Background: 0 Scalar::Util: 0 String::Koremutake: 0 Test::Expect: 0 Test::More: 0 YAML: 0 resources: license: http://dev.perl.org/licenses/ version: 0.55 Devel-ebug-0.55/README000444001750001750 2657612122201364 14725 0ustar00awwaiidawwaiid000000000000NAME Devel::ebug - A simple, extensible Perl debugger SYNOPSIS use Devel::ebug; my $ebug = Devel::ebug->new; $ebug->program("calc.pl"); $ebug->load; print "At line: " . $ebug->line . "\n"; print "In subroutine: " . $ebug->subroutine . "\n"; print "In package: " . $ebug->package . "\n"; print "In filename: " . $ebug->filename . "\n"; print "Code: " . $ebug->codeline . "\n"; $ebug->step; $ebug->step; $ebug->next; my($stdout, $stderr) = $ebug->output; my $actual_line = $ebug->break_point(6); $ebug->break_point(6, '$e = 4'); $ebug->break_point("t/Calc.pm", 29); $ebug->break_point("t/Calc.pm", 29, '$i == 2'); my $actual_line = $ebug->break_point_subroutine("main::add"); $ebug->break_point_delete(29); $ebug->break_point_delete("t/Calc.pm", 29); my @filenames = $ebug->filenames(); my @break_points = $ebug->break_points(); my @break_points = $ebug->break_points("t/Calc.pm"); my @break_points = $ebug->break_points_with_condition(); my @break_points = $ebug->break_points_with_condition("t/Calc.pm"); my @break_points = $ebug->all_break_points_with_condition(); $ebug->watch_point('$x > 100'); my $codelines = $ebug->codelines(@span); $ebug->run; my $pad = $ebug->pad; foreach my $k (sort keys %$pad) { my $v = $pad->{$k}; print "Variable: $k = $v\n"; } my $v = $ebug->eval('2 ** $exp'); my( $v, $is_exception ) = $ebug->eval('die 123'); my $y = $ebug->yaml('$z'); my @frames = $ebug->stack_trace; my @frames2 = $ebug->stack_trace_human; $ebug->undo; $ebug->return; print "Finished!\n" if $ebug->finished; DESCRIPTION A debugger is a computer program that is used to debug other programs. Devel::ebug is a simple, extensible Perl debugger with a clean API. Using this module, you may easily write a Perl debugger to debug your programs. Alternatively, it comes with an interactive debugger, ebug. perl5db.pl, Perl's current debugger is currently 2,600 lines of magic and special cases. The code is nearly unreadable: fixing bugs and adding new features is fraught with difficulties. The debugger has no test suite which has caused breakage with changes that couldn't be properly tested. It will also not debug regexes. Devel::ebug is aimed at fixing these problems and delivering a replacement debugger which provides a well-tested simple programmatic interface to debugging programs. This makes it easier to build debuggers on top of Devel::ebug, be they console-, curses-, GUI- or Ajax-based. There are currently two user interfaces to Devel::debug, ebug and ebug_http. ebug is a console-based interface to debugging programs, much like perl5db.pl. ebug_http is an innovative web-based interface to debugging programs. Note that if you're debugging a program, you can invoke the debugger in the program itself by using the INT signal: kill 2, $$ if $square > 100; Devel::ebug is a work in progress. Internally, Devel::ebug consists of two parts. The frontend is Devel::ebug, which you interact with. The frontend starts the code you are debugging in the background under the backend (running it under perl -d:ebug code.pl). The backend starts a TCP server, which the frontend then connects to, and uses this to drive the backend. This adds some flexibilty in the debugger. There is some minor security in the client/server startup (a secret word), and a random port is used from 3141-4165 so that multiple debugging sessions can happen concurrently. CONSTRUCTOR new The constructor creats a Devel::ebug object: my $ebug = Devel::ebug->new; program The program method selects which program to load: $ebug->program("calc.pl"); load The load method loads the program and gets ready to debug it: $ebug->load; METHODS break_point The break_point method sets a break point in a program. If you are run-ing through a program, the execution will stop at a break point. Break points can be set in a few ways. A break point can be set at a line number in the current file: my $actual_line = $ebug->break_point(6); A break point can be set at a line number in the current file with a condition that must be true for execution to stop at the break point: my $actual_line = $ebug->break_point(6, '$e = 4'); A break point can be set at a line number in a file: my $actual_line = $ebug->break_point("t/Calc.pm", 29); A break point can be set at a line number in a file with a condition that must be true for execution to stop at the break point: my $actual_line = $ebug->break_point("t/Calc.pm", 29, '$i == 2'); Breakpoints can not be set on some lines (for example comments); in this case a breakpoint will be set at the next breakable line, and the line number will be returned. If no such line exists, no breakpoint is set and the function returns "undef". break_point_delete The break_point_delete method deletes an existing break point. A break point at a line number in the current file can be deleted: $ebug->break_point_delete(29); A break point at a line number in a file can be deleted: $ebug->break_point_delete("t/Calc.pm", 29); break_point_subroutine The break_point_subroutine method sets a break point in a program right at the beginning of the subroutine. The subroutine is specified with the full package name: my $line = $ebug->break_point_subroutine("main::add"); $ebug->break_point_subroutine("Calc::fib"); The return value is the line at which the break point is set. break_points The break_points method returns a list of all the line numbers in a given file that have a break point set. Return the list of breakpoints in the current file: my @break_points = $ebug->break_points(); Return the list of breakpoints in a given file: my @break_points = $ebug->break_points("t/Calc.pm"); break_points_with_condition The break_points method returns a list of break points for a given file. Return the list of breakpoints in the current file: my @break_points = $ebug->break_points_with_condition(); Return the list of breakpoints in a given file: my @break_points = $ebug->break_points_with_condition("t/Calc.pm"); Each element of the list has the form { filename => "t/Calc.pm", line => 29, condition => "$foo > 12", } where "condition" might not be present. all_break_points_with_condition Like "break_points_with_condition" but returns a list of break points for the whole program. codeline The codeline method returns the line of code that is just about to be executed: print "Code: " . $ebug->codeline . "\n"; codelines The codelines method returns lines of code. It can return all the code lines in the current file: my @codelines = $ebug->codelines(); It can return a span of code lines from the current file: my @codelines = $ebug->codelines(1, 3, 4, 5); It can return all the code lines in a file: my @codelines = $ebug->codelines("t/Calc.pm"); It can return a span of code lines in a file: my @codelines = $ebug->codelines("t/Calc.pm", 5, 6); eval The eval method evaluates Perl code in the current program and returns the result. If the evalutation results in an exception, $@ is returned. my $v = $ebug->eval('2 ** $exp'); In list context, eval also returns a flag indicating if the evalutation resulted in an exception. my( $v, $is_exception ) = $ebug->eval('die 123'); filename The filename method returns the filename of the currently running code: print "In filename: " . $ebug->filename . "\n"; filenames The filenames method returns a list of the filenames of all the files currently loaded: my @filenames = $ebug->filenames(); finished The finished method returns whether the program has finished running: print "Finished!\n" if $ebug->finished; line The line method returns the line number of the statement about to be executed: print "At line: " . $ebug->line . "\n"; next The next method steps onto the next line in the program. It executes any subroutine calls but does not step through them. $ebug->next; output The output method returns any content the program has output to either standard output or standard error: my($stdout, $stderr) = $ebug->output; package The package method returns the package of the currently running code: print "In package: " . $ebug->package . "\n"; pad my $pad = $ebug->pad; foreach my $k (sort keys %$pad) { my $v = $pad->{$k}; print "Variable: $k = $v\n"; } return The return subroutine returns from a subroutine. It continues running the subroutine, then single steps when the program flow has exited the subroutine: $ebug->return; It can also return your own values from a subroutine, for testing purposes: $ebug->return(3.141); run The run subroutine starts executing the code. It will only stop on a break point or watch point. $ebug->run; step The step method steps onto the next line in the program. It steps through into any subroutine calls. $ebug->step; subroutine The subroutine method returns the subroutine of the currently working code: print "In subroutine: " . $ebug->subroutine . "\n"; stack_trace The stack_trace method returns the current stack trace, using Devel::StackTrace. It returns a list of Devel::StackTraceFrame methods: my @frames = $ebug->stack_trace; foreach my $frame (@trace) { print $frame->package, "->",$frame->subroutine, "(", $frame->filename, "#", $frame->line, ")\n"; } stack_trace_human The stack_trace_human method returns the current stack trace in a human-readable format: my @frames = $ebug->stack_trace_human; foreach my $frame (@trace) { print "$frame\n"; } undo The undo method undos the last action. It accomplishes this by restarting the process and passing (almost) all the previous commands to it. Note that commands which do not change state are ignored. Commands that change state are: break_point, break_point_delete, break_point_subroutine, eval, next, step, return, run and watch_point. $ebug->undo; It can also undo multiple commands: $ebug->undo(3); watch_point The watch point method sets a watch point. A watch point has a condition, and the debugger will stop run-ing as soon as this condition is true: $ebug->watch_point('$x > 100'); yaml The eval method evaluates Perl code in the current program and returns the result of YAML's Dump() method: my $y = $ebug->yaml('$z'); SEE ALSO perldebguts BUGS Devel::ebug does not quite work under 5.8.0. Devel::ebug does not handle signals under Windows. AUTHOR Leon Brocard, "" COPYRIGHT Copyright (C) 2005-8, Leon Brocard LICENSE This module is free software; you can redistribute it or modify it under the same terms as Perl itself. Devel-ebug-0.55/lib000755001750001750 012122201364 14416 5ustar00awwaiidawwaiid000000000000Devel-ebug-0.55/lib/Devel000755001750001750 012122201364 15455 5ustar00awwaiidawwaiid000000000000Devel-ebug-0.55/lib/Devel/ebug.pm000444001750001750 3351612122201364 17122 0ustar00awwaiidawwaiid000000000000package Devel::ebug; use strict; use warnings; use Carp; use Class::Accessor::Chained::Fast; use Devel::StackTrace; use IO::Socket::INET; use Proc::Background; use String::Koremutake; # use YAML::Syck; use YAML; use Module::Pluggable require => 1; use FindBin qw($Bin); use base qw(Class::Accessor::Chained::Fast); __PACKAGE__->mk_accessors(qw( backend port program socket proc package filename line codeline subroutine finished)); our $VERSION = "0.55"; # let's run the code under our debugger and connect to the server it # starts up sub load { my $self = shift; my $program = $self->program; # import all the plugins into our namespace do { eval "use $_ " } for $self->plugins; my $k = String::Koremutake->new; my $rand = int(rand(100_000)); my $secret = $k->integer_to_koremutake($rand); my $port = 3141 + ($rand % 1024); $ENV{SECRET} = $secret; my $backend = $self->backend || "$Bin/ebug_backend_perl"; my $command = "$backend $program";; my $proc = Proc::Background->new( {'die_upon_destroy' => 1}, $command ); croak(qq{Devel::ebug: Failed to start up "$program" in load()}) unless $proc->alive; $self->proc($proc); $ENV{SECRET} = ""; $self->attach($port, $secret); } sub attach { my ($self, $port, $key) = @_; # import all the plugins into our namespace do { eval "use $_ " } for $self->plugins; # try and connect to the server my $socket; foreach ( 1 .. 10 ) { $socket = IO::Socket::INET->new( PeerAddr => "localhost", PeerPort => $port, Proto => 'tcp', Reuse => 1, ReuserAddr => 1, ); last if $socket; sleep 1; } die "Could not connect: $!" unless $socket; $self->socket($socket); my $response = $self->talk( { command => "ping", version => $VERSION, secret => $key, } ); my $version = $response->{version}; die "Client version $version != our version $VERSION" unless $version eq $VERSION; $self->basic; # get basic information for the first line } # # FIXME : this would mean that plugin writers don't need to Export stuff # #sub load_plugins { # my $self = shift; # my $obj = Devel::Symdump->new($self->plugins); # # for ($obj->functions) { # my $name = (split /::/)[-1]; # next if substr($name,0,1) eq '_'; # *basic = \&$_; # } # #} # at the moment, we talk hex-encoded YAML serialisation # don't worry about this too much sub talk { my($self, $req) = @_; my $socket = $self->socket; my $data = unpack("h*", Dump($req)); $socket->print($data . "\n"); $data = <$socket>; if ($data) { my $res = Load(pack("h*", $data)); return $res; } } 1; __END__ =head1 NAME Devel::ebug - A simple, extensible Perl debugger =head1 SYNOPSIS use Devel::ebug; my $ebug = Devel::ebug->new; $ebug->program("calc.pl"); $ebug->load; print "At line: " . $ebug->line . "\n"; print "In subroutine: " . $ebug->subroutine . "\n"; print "In package: " . $ebug->package . "\n"; print "In filename: " . $ebug->filename . "\n"; print "Code: " . $ebug->codeline . "\n"; $ebug->step; $ebug->step; $ebug->next; my($stdout, $stderr) = $ebug->output; my $actual_line = $ebug->break_point(6); $ebug->break_point(6, '$e == 4'); $ebug->break_point("t/Calc.pm", 29); $ebug->break_point("t/Calc.pm", 29, '$i == 2'); $ebug->break_on_load("t/Calc.pm"); my $actual_line = $ebug->break_point_subroutine("main::add"); $ebug->break_point_delete(29); $ebug->break_point_delete("t/Calc.pm", 29); my @filenames = $ebug->filenames(); my @break_points = $ebug->break_points(); my @break_points = $ebug->break_points("t/Calc.pm"); my @break_points = $ebug->break_points_with_condition(); my @break_points = $ebug->break_points_with_condition("t/Calc.pm"); my @break_points = $ebug->all_break_points_with_condition(); $ebug->watch_point('$x > 100'); my $codelines = $ebug->codelines(@span); $ebug->run; my $pad = $ebug->pad; foreach my $k (sort keys %$pad) { my $v = $pad->{$k}; print "Variable: $k = $v\n"; } my $v = $ebug->eval('2 ** $exp'); my( $v, $is_exception ) = $ebug->eval('die 123'); my $y = $ebug->yaml('$z'); my @frames = $ebug->stack_trace; my @frames2 = $ebug->stack_trace_human; $ebug->undo; $ebug->return; print "Finished!\n" if $ebug->finished; =head1 DESCRIPTION A debugger is a computer program that is used to debug other programs. L is a simple, extensible Perl debugger with a clean API. Using this module, you may easily write a Perl debugger to debug your programs. Alternatively, it comes with an interactive debugger, L. perl5db.pl, Perl's current debugger is currently 2,600 lines of magic and special cases. The code is nearly unreadable: fixing bugs and adding new features is fraught with difficulties. The debugger has no test suite which has caused breakage with changes that couldn't be properly tested. It will also not debug regexes. L is aimed at fixing these problems and delivering a replacement debugger which provides a well-tested simple programmatic interface to debugging programs. This makes it easier to build debuggers on top of L, be they console-, curses-, GUI- or Ajax-based. There are currently two user interfaces to L, L and L. L is a console-based interface to debugging programs, much like perl5db.pl. L is an innovative web-based interface to debugging programs. Note that if you're debugging a program, you can invoke the debugger in the program itself by using the INT signal: kill 2, $$ if $square > 100; L is a work in progress. Internally, L consists of two parts. The frontend is L, which you interact with. The frontend starts the code you are debugging in the background under the backend (running it under perl -d:ebug code.pl). The backend starts a TCP server, which the frontend then connects to, and uses this to drive the backend. This adds some flexibilty in the debugger. There is some minor security in the client/server startup (a secret word), and a random port is used from 3141-4165 so that multiple debugging sessions can happen concurrently. =head1 CONSTRUCTOR =head2 new The constructor creats a Devel::ebug object: my $ebug = Devel::ebug->new; =head2 program The program method selects which program to load: $ebug->program("calc.pl"); =head2 load The load method loads the program and gets ready to debug it: $ebug->load; =head1 METHODS =head2 break_point The break_point method sets a break point in a program. If you are run-ing through a program, the execution will stop at a break point. Break points can be set in a few ways. A break point can be set at a line number in the current file: my $actual_line = $ebug->break_point(6); A break point can be set at a line number in the current file with a condition that must be true for execution to stop at the break point: my $actual_line = $ebug->break_point(6, '$e = 4'); A break point can be set at a line number in a file: my $actual_line = $ebug->break_point("t/Calc.pm", 29); A break point can be set at a line number in a file with a condition that must be true for execution to stop at the break point: my $actual_line = $ebug->break_point("t/Calc.pm", 29, '$i == 2'); Breakpoints can not be set on some lines (for example comments); in this case a breakpoint will be set at the next breakable line, and the line number will be returned. If no such line exists, no breakpoint is set and the function returns C. =head2 break_on_load Set a breakpoint on file loading, the file name can be relative or absolute. =head2 break_point_delete The break_point_delete method deletes an existing break point. A break point at a line number in the current file can be deleted: $ebug->break_point_delete(29); A break point at a line number in a file can be deleted: $ebug->break_point_delete("t/Calc.pm", 29); =head2 break_point_subroutine The break_point_subroutine method sets a break point in a program right at the beginning of the subroutine. The subroutine is specified with the full package name: my $line = $ebug->break_point_subroutine("main::add"); $ebug->break_point_subroutine("Calc::fib"); The return value is the line at which the break point is set. =head2 break_points The break_points method returns a list of all the line numbers in a given file that have a break point set. Return the list of breakpoints in the current file: my @break_points = $ebug->break_points(); Return the list of breakpoints in a given file: my @break_points = $ebug->break_points("t/Calc.pm"); =head2 break_points_with_condition The break_points method returns a list of break points for a given file. Return the list of breakpoints in the current file: my @break_points = $ebug->break_points_with_condition(); Return the list of breakpoints in a given file: my @break_points = $ebug->break_points_with_condition("t/Calc.pm"); Each element of the list has the form { filename => "t/Calc.pm", line => 29, condition => "$foo > 12", } where C might not be present. =head2 all_break_points_with_condition Like C but returns a list of break points for the whole program. =head2 codeline The codeline method returns the line of code that is just about to be executed: print "Code: " . $ebug->codeline . "\n"; =head2 codelines The codelines method returns lines of code. It can return all the code lines in the current file: my @codelines = $ebug->codelines(); It can return a span of code lines from the current file: my @codelines = $ebug->codelines(1, 3, 4, 5); It can return all the code lines in a file: my @codelines = $ebug->codelines("t/Calc.pm"); It can return a span of code lines in a file: my @codelines = $ebug->codelines("t/Calc.pm", 5, 6); =head2 eval The eval method evaluates Perl code in the current program and returns the result. If the evalutation results in an exception, C<$@> is returned. my $v = $ebug->eval('2 ** $exp'); In list context, eval also returns a flag indicating if the evalutation resulted in an exception. my( $v, $is_exception ) = $ebug->eval('die 123'); =head2 filename The filename method returns the filename of the currently running code: print "In filename: " . $ebug->filename . "\n"; =head2 filenames The filenames method returns a list of the filenames of all the files currently loaded: my @filenames = $ebug->filenames(); =head2 finished The finished method returns whether the program has finished running: print "Finished!\n" if $ebug->finished; =head2 line The line method returns the line number of the statement about to be executed: print "At line: " . $ebug->line . "\n"; =head2 next The next method steps onto the next line in the program. It executes any subroutine calls but does not step through them. $ebug->next; =head2 output The output method returns any content the program has output to either standard output or standard error: my($stdout, $stderr) = $ebug->output; =head2 package The package method returns the package of the currently running code: print "In package: " . $ebug->package . "\n"; =head2 pad my $pad = $ebug->pad; foreach my $k (sort keys %$pad) { my $v = $pad->{$k}; print "Variable: $k = $v\n"; } =head2 return The return subroutine returns from a subroutine. It continues running the subroutine, then single steps when the program flow has exited the subroutine: $ebug->return; It can also return your own values from a subroutine, for testing purposes: $ebug->return(3.141); =head2 run The run subroutine starts executing the code. It will only stop on a break point or watch point. $ebug->run; =head2 step The step method steps onto the next line in the program. It steps through into any subroutine calls. $ebug->step; =head2 subroutine The subroutine method returns the subroutine of the currently working code: print "In subroutine: " . $ebug->subroutine . "\n"; =head2 stack_trace The stack_trace method returns the current stack trace, using L. It returns a list of L methods: my @frames = $ebug->stack_trace; foreach my $frame (@trace) { print $frame->package, "->",$frame->subroutine, "(", $frame->filename, "#", $frame->line, ")\n"; } =head2 stack_trace_human The stack_trace_human method returns the current stack trace in a human-readable format: my @frames = $ebug->stack_trace_human; foreach my $frame (@trace) { print "$frame\n"; } =head2 undo The undo method undos the last action. It accomplishes this by restarting the process and passing (almost) all the previous commands to it. Note that commands which do not change state are ignored. Commands that change state are: break_point, break_point_delete, break_point_subroutine, eval, next, step, return, run and watch_point. $ebug->undo; It can also undo multiple commands: $ebug->undo(3); =head2 watch_point The watch point method sets a watch point. A watch point has a condition, and the debugger will stop run-ing as soon as this condition is true: $ebug->watch_point('$x > 100'); =head2 yaml The eval method evaluates Perl code in the current program and returns the result of YAML's Dump() method: my $y = $ebug->yaml('$z'); =head1 SEE ALSO L =head1 BUGS Devel::ebug does not quite work under 5.8.0. Devel::ebug does not handle signals under Windows. =head1 AUTHOR Latest releases by Brock Wilcox, C<< >> Leon Brocard, C<< >> =head1 COPYRIGHT Copyright (C) 2005-2008, Leon Brocard Copyright (C) 2011-NOW, Brock Wilcox =head1 LICENSE This module is free software; you can redistribute it or modify it under the same terms as Perl itself. Devel-ebug-0.55/lib/Devel/ebug000755001750001750 012122201364 16377 5ustar00awwaiidawwaiid000000000000Devel-ebug-0.55/lib/Devel/ebug/Backend.pm000444001750001750 1332112122201364 20441 0ustar00awwaiidawwaiid000000000000package DB; use strict; use warnings; use IO::Socket::INET; use String::Koremutake; # use YAML::Syck; use YAML; use Module::Pluggable search_path => 'Devel::ebug::Backend::Plugin', require => 1; our $VERSION = "0.55"; use vars qw(@dbline %dbline); # Let's catch INT signals and set a flag when they occur $SIG{INT} = sub { $DB::signal = 1; return; }; my $context = { finished => 0, initialise => 1, mode => "step", stack => [], watch_points => [], }; # Commands that the back end can respond to # Set record if the command changes start and should thus be recorded # in order for undo to work properly my %commands = (); sub DB { my ($package, $filename, $line) = caller; ($context->{package}, $context->{filename}, $context->{line}) = ($package, $filename, $line); initialise() if $context->{initialise}; # we're here because of a signal, reset the flag if ($DB::signal) { $DB::signal = 0; } # single step my $old_single = $DB::single; $DB::single = 1; if (@{ $context->{watch_points} }) { my %delete; foreach my $watch_point (@{ $context->{watch_points} }) { local $SIG{__WARN__} = sub { }; my $v = eval "package $package; $watch_point"; if ($v) { $context->{watch_single} = 1; $delete{$watch_point} = 1; } } if ($context->{watch_single} == 0) { return; } else { @{ $context->{watch_points} } = grep { !$delete{$_} } @{ $context->{watch_points} }; } } # we're here because of a break point, test the condition if ($old_single == 0) { my $condition = break_point_condition($filename, $line); if ($condition) { local $SIG{__WARN__} = sub { }; my $v = eval "package $package; $condition"; unless ($v) { # condition not true, go back to running $DB::single = 0; return; } } } $context->{watch_single} = 1; $context->{codeline} = (fetch_codelines($filename, $line - 1))[0]; chomp $context->{codeline}; while (1) { my $req = get(); my $command = $req->{command}; my $sub = $commands{$command}->{sub}; if (defined $sub) { put($sub->($req, $context)); if ($context->{last}) { delete $context->{last}; last; } } else { die "unknown command $command"; } } } sub initialise { my $k = String::Koremutake->new; my $int = $k->koremutake_to_integer($ENV{SECRET}); my $port = 3141 + ($int % 1024); my $server = IO::Socket::INET->new( Listen => 5, LocalAddr => 'localhost', LocalPort => $port, Proto => 'tcp', ReuseAddr => 1, Reuse => 1, ) || die $!; $context->{socket} = $server->accept; foreach my $plugin (__PACKAGE__->plugins) { my $sub = $plugin->can("register_commands"); next unless $sub; my %new = &$sub; foreach my $command (keys %new) { $commands{$command} = $new{$command}; } } $context->{initialise} = 0; } sub put { my ($res) = @_; my $data = unpack("h*", Dump($res)); $context->{socket}->print($data . "\n"); } sub get { exit unless $context->{socket}; my $data = $context->{socket}->getline; my $req = Load(pack("h*", $data)); push @{ $context->{history} }, $req if exists $commands{ $req->{command} }->{record}; return $req; } sub sub { my (@args) = @_; my $sub = $DB::sub; my $frame = { single => $DB::single, sub => $sub }; push @{ $context->{stack} }, $frame; # If we are in 'next' mode, then skip all the lines in the sub $DB::single = 0 if defined $context->{mode} && $context->{mode} eq 'next'; no strict 'refs'; if (wantarray) { my @ret = &$sub; my $frame = pop @{ $context->{stack} }; $DB::single = $frame->{single}; $DB::single = 0 if defined $context->{mode} && $context->{mode} eq 'run' && !@{$context->{watch_points}}; if ($frame->{return}) { return @{ $frame->{return} }; } else { return @ret; } } else { my $ret = &$sub; my $frame = pop @{ $context->{stack} }; $DB::single = $frame->{single}; $DB::single = 0 if defined $context->{mode} && $context->{mode} eq 'run' && !@{$context->{watch_points}}; if ($frame->{return}) { return $frame->{return}->[0]; } else { return $ret; } } } sub DB::postponed { # If this is a subroutine, let postponed_sub() deal with it. return &postponed_sub unless ref \$_[0] eq 'GLOB'; my ($fileName) = @_; $fileName =~ s/^.*_rel2abs( $fileName)} ){ $DB::single = 1; } } sub fetch_codelines { my ($filename, @lines) = @_; #use vars qw(@dbline %dbline); *dbline = $main::{ '_<' . $filename }; my @codelines = @dbline; # for modules, not sure why shift @codelines if not defined $codelines[0]; # defined! @codelines = map { defined($_) ? $_ : "" } @codelines; # remove newlines @codelines = map { $_ =~ s/\s+$//; $_ } @codelines; # we run it with -d:ebug::Backend, so remove this extra line @codelines = grep { $_ ne 'use Devel::ebug::Backend;' } @codelines; # for some reasons, the perl internals leave the opening POD line # around but strip the rest. so let's strip the opening POD line @codelines = map { $_ =~ /^=(head|over|item|back|over|cut|pod|begin|end|for)/ ? "" : $_ } @codelines; if (@lines) { @codelines = @codelines[@lines]; } return @codelines; } sub break_point_condition { my ($filename, $line) = @_; *dbline = $main::{ '_<' . $filename }; return $dbline{$line}; } sub END { $context->{finished} = 1; $DB::single = 1; DB::fake::at_exit(); } package DB::fake; sub at_exit { 1; } package DB; # Do not trace this 1; below! 1; Devel-ebug-0.55/lib/Devel/ebug/Console.pm000444001750001750 1362512122201364 20523 0ustar00awwaiidawwaiid000000000000package Devel::ebug::Console; use strict; use warnings; use lib 'lib'; use Carp; use Class::Accessor::Chained::Fast; use Devel::ebug; use Term::ReadLine; use base qw(Class::Accessor::Chained::Fast); sub run { my $self = shift; my $backend = shift; $SIG{INT} = sub { die "INT"; }; my $filename = join " ", @ARGV; unless ($filename) { $filename = '-e "Interactive ebugging shell"'; } my $ebug = Devel::ebug->new; $ebug->program($filename); $ebug->backend($backend); $ebug->load; my $codelines; print "* Welcome to Devel::ebug $Devel::ebug::VERSION\n"; my $term = Term::ReadLine->new('ebug'); my $attribs = $term->Attribs; $attribs->{completion_function} = sub { my ($text, $line, $start) = @_; my $pad = $ebug->pad || {}; return unless $line =~ s/^x //; my @result = grep { /^\Q$line/ } keys %$pad; if ($line =~ /^[\$\@]/) { @result = map { s/^[\$\@]//; $_ } @result; } return @result; }; my $last_command = "s"; my $list_always = 0; my $list_lines_count = 9; while (1) { if ($ebug->finished) { print "ebug: Program finished. Enter 'restart' or 'q'\n"; } else { if ($list_always) { show_codelines($codelines, $ebug, $list_lines_count) if($list_always); } else { print $ebug->subroutine . "(" . $ebug->filename . "#" . $ebug->line . "):\n" . $ebug->codeline, "\n"; } } my $command = $term->readline("ebug: "); $command = "q" if not defined $command; $command = $last_command if ($command eq ""); if ($command =~ /^\s*[?h](elp)?\s*$/) { print 'Commands: b Set break point at a line number (eg: b 6, b code.pl 6, b code.pl 6 $x > 7, b Calc::fib) d Delete a break point (d 6, d code.pl 6) e Eval Perl code and print the result (eg: e $x+$y) f Show all the filenames loaded l List codelines or set number of codelines to list (eg: l, l 20) L List codelines always (toggle) n Next (steps over subroutine calls) o Output (show STDOUT, STDERR) p Show pad r Run until next break point or watch point ret Return from subroutine (eg: ret, ret 3.141) restart Restart the program s Step (steps into subroutine calls) T Show a stack trace u Undo (eg: u, u 4) w Set a watchpoint (eg: w $t > 10) x Dump a variable using YAML (eg: x $object) q Quit '; } elsif ($command eq 'l') { show_codelines($codelines, $ebug, $list_lines_count); } elsif ($command =~ /^ l \s+ (\d+) $/x) { $list_lines_count = $1 if $1 > 0; show_codelines($codelines, $ebug, $list_lines_count); } elsif ($command eq 'L') { $list_always = !$list_always; } elsif ($command eq 'p') { my $pad = $ebug->pad_human; foreach my $k (sort keys %$pad) { my $v = $pad->{$k}; print " $k = $v;\n"; } } elsif ($command eq 's') { $ebug->step; } elsif ($command eq 'n') { $ebug->next; } elsif ($command eq 'o') { my($stdout, $stderr) = $ebug->output; print "STDOUT:\n$stdout\n"; print "STDERR:\n$stderr\n"; } elsif ($command eq 'r') { $ebug->run; # TODO: Consider using this instead: # eval { $ebug->run }; } elsif ($command eq 'restart') { $ebug->load; } elsif ($command =~ /^ret ?(.*)/) { $ebug->return($1); } elsif ($command eq 'T') { my @trace = $ebug->stack_trace_human; foreach my $frame (@trace) { print "$frame\n"; } } elsif ($command eq 'f') { print "$_\n" foreach $ebug->filenames; } elsif (my($line, $condition) = $command =~ /^b (\d+) ?(.*)/) { undef $condition unless $condition; $ebug->break_point($line, $condition); } elsif ($command =~ /^b (.+?) (\d+) ?(.*)/) { $ebug->break_point($1, $2, $3); } elsif ($command =~ /^b (.+)/) { $ebug->break_point_subroutine($1); } elsif ($command =~ /^d (.+?) (\d+)/) { $ebug->break_point_delete($1, $2); } elsif ($command =~ /^d (\d+)/) { $ebug->break_point_delete($1); } elsif ($command =~ /^w (.+)/) { my($watch_point) = $command =~ /^w (.+)/; $ebug->watch_point($watch_point); } elsif ($command =~ /^u ?(.*)/) { $ebug->undo($1); } elsif ($command eq 'q') { exit; } elsif ($command =~ /^x (.+)/) { my $v = $ebug->eval("use YAML; Dump($1)") || ""; print "$v\n"; } elsif ($command =~ /^e (.+)/) { my $v = $ebug->eval($1) || ""; print "$v\n"; } elsif ($command) { my $v = $ebug->eval($command) || ""; print "$v\n"; } $last_command = $command; } } sub show_codelines { my ($codelines, $ebug, $list_lines_count) = @_; my $line_count = int($list_lines_count / 2); if (not exists $codelines->{$ebug->filename}) { $codelines->{$ebug->filename} = [$ebug->codelines]; } my @span = ($ebug->line-$line_count .. $ebug->line+$line_count); @span = grep { $_ > 0 } @span; my @codelines = @{$codelines->{$ebug->filename}}; my @break_points = $ebug->break_points(); my %break_points; $break_points{$_}++ foreach @break_points; foreach my $s (@span) { my $codeline = $codelines[$s -1 ]; next unless defined $codeline; if ($s == $ebug->line) { print "*"; } elsif ($break_points{$s}) { print "b"; } else { print " "; } print "$s:$codeline\n"; } } 1; __END__ =head1 NAME Devel::ebug::Console - Console front end to Devel::ebug =head1 SYNOPSIS # it's easier to use the 'ebug' script use Devel::ebug::Console; my $console = Devel::ebug::Console->new(); $console->run(); =head1 DESCRIPTION L is an interactive commmand-line front end to L. It is a simple Perl debugger, much like perl5db.pl. =head1 SEE ALSO L, L =head1 AUTHOR Leon Brocard, C<< >> =head1 COPYRIGHT Copyright (C) 2005, Leon Brocard This program is free software; you can redistribute it or modify it under the same terms as Perl itself. Devel-ebug-0.55/lib/Devel/ebug/Plugin000755001750001750 012122201364 17635 5ustar00awwaiidawwaiid000000000000Devel-ebug-0.55/lib/Devel/ebug/Plugin/StackTrace.pm000444001750001750 472512122201364 22364 0ustar00awwaiidawwaiid000000000000package Devel::ebug::Plugin::StackTrace; use strict; use warnings; use Scalar::Util qw(blessed); use base qw(Exporter); our @EXPORT = qw(stack_trace stack_trace_human stack_trace_human_args); # return the stack trace sub stack_trace { my($self) = @_; my $response = $self->talk({ command => "stack_trace" }); return @{$response->{stack_trace}||[]}; } # return the stack trace in a human-readable format sub stack_trace_human { my($self) = @_; my @human; my @stack = $self->stack_trace; foreach my $frame (@stack) { my $subroutine = $frame->subroutine; my $package = $frame->package; my @args = $frame->args; my $first = $args[0]; my $first_class = ref($first); my($subroutine_class, $subroutine_method) = $subroutine =~ /^(.+)::([^:])+?$/; # warn "first: $first, first class: $first_class, package: $package, subroutine: $subroutine ($subroutine_class :: $subroutine_method)\n"; if (defined $first && blessed($first) && $subroutine =~ /^${first_class}::/ && $subroutine =~ /^$package/) { $subroutine =~ s/^${first_class}:://; shift @args; push @human, "\$self->$subroutine" . $self->stack_trace_human_args(@args); } elsif (defined $first && blessed($first) && $subroutine =~ /^${first_class}::/) { $subroutine =~ s/^${first_class}:://; shift @args; my($name) = $first_class =~ /([^:]+)$/; $first = '$' . lc($name); push @human, "$first->$subroutine" . $self->stack_trace_human_args(@args); } elsif ($subroutine =~ s/^${package}:://) { push @human, "$subroutine" . $self->stack_trace_human_args(@args); } elsif (defined $first && $subroutine_class eq $first) { shift @args; push @human, "$first->new" . $self->stack_trace_human_args(@args); } else { push @human, "$subroutine" . $self->stack_trace_human_args(@args); } } return @human; } sub stack_trace_human_args { my($self, @args) = @_; foreach my $arg (@args) { if (not defined $arg) { $arg = "undef"; } elsif (ref($arg) eq 'ARRAY') { $arg = "[...]"; } elsif (ref($arg) eq 'HASH') { $arg = "{...}"; } elsif (ref($arg)) { my($name) = ref($arg) =~ /([^:]+)$/; $arg = '$' . lc($name); } elsif ($arg =~ /^-?[\d.]+$/) { # number, do nothing } elsif ($arg =~ /^[\w:]*$/) { $arg =~ s/([\'\\])/\\$1/g; $arg = qq{'$arg'}; } else { $arg =~ s/([\'\\])/\\$1/g; $arg = qq{"$arg"}; } } return '(' . join(", ", @args) . ')'; } 1; Devel-ebug-0.55/lib/Devel/ebug/Plugin/Codelines.pm000444001750001750 100212122201364 22226 0ustar00awwaiidawwaiid000000000000package Devel::ebug::Plugin::Codelines; use strict; use warnings; use base qw(Exporter); our @EXPORT = qw(codelines); # return some lines of code sub codelines { my($self) = shift; my($filename, @lines); if (!defined($_[0]) || $_[0] =~ /^\d+$/) { $filename = $self->filename; } else { $filename = shift; } @lines = map { $_ -1 } @_; my $response = $self->talk({ command => "codelines", filename => $filename, lines => \@lines, }); return @{$response->{codelines}}; } 1; Devel-ebug-0.55/lib/Devel/ebug/Plugin/Filenames.pm000444001750001750 41712122201364 22215 0ustar00awwaiidawwaiid000000000000package Devel::ebug::Plugin::Filenames; use strict; use warnings; use base qw(Exporter); our @EXPORT = qw(filenames); # list filenames sub filenames { my($self) = @_; my $response = $self->talk({ command => "filenames" }); return @{$response->{filenames}}; } 1; Devel-ebug-0.55/lib/Devel/ebug/Plugin/Pad.pm000444001750001750 140112122201364 21030 0ustar00awwaiidawwaiid000000000000package Devel::ebug::Plugin::Pad; use strict; use warnings; use base qw(Exporter); our @EXPORT = qw(pad pad_human); # find the pad sub pad { my($self) = @_; my $response = $self->talk({ command => "pad" }); return $response->{pad}; } # human-readable pad sub pad_human { my($self) = @_; my $pad = $self->pad; foreach my $var (keys %$pad) { if ($var =~ /^@/) { my @values = @{$pad->{$var}}; my $value = $self->stack_trace_human_args(@values); $pad->{$var} = $value; } elsif ($var =~ /^%/) { $pad->{$var} = '(...)'; } else { my $value = $pad->{$var}; $value = $self->stack_trace_human_args($value); $value =~ s/^\(//; $value =~ s/\)$//; $pad->{$var} = $value; } } return $pad; } 1; Devel-ebug-0.55/lib/Devel/ebug/Plugin/Basic.pm000444001750001750 74212122201364 21334 0ustar00awwaiidawwaiid000000000000package Devel::ebug::Plugin::Basic; use strict; use warnings; use base qw(Exporter); our @EXPORT = qw(basic); # get basic debugging information sub basic { my ($self) = @_; my $response = $self->talk({ command => "basic" }); $self->codeline($response->{codeline}); $self->filename($response->{filename}); $self->finished($response->{finished}); $self->line($response->{line}); $self->package($response->{package}); $self->subroutine($response->{subroutine}); } 1; Devel-ebug-0.55/lib/Devel/ebug/Plugin/Output.pm000444001750001750 43312122201364 21610 0ustar00awwaiidawwaiid000000000000package Devel::ebug::Plugin::Output; use strict; use warnings; use base qw(Exporter); our @EXPORT = qw(output); # return stdout, stderr sub output { my($self) = @_; my $response = $self->talk({ command => "output" }); return ($response->{stdout}, $response->{stderr}); } 1; Devel-ebug-0.55/lib/Devel/ebug/Plugin/Run.pm000444001750001750 241312122201364 21074 0ustar00awwaiidawwaiid000000000000package Devel::ebug::Plugin::Run; use strict; use warnings; use base qw(Exporter); our @EXPORT = qw(undo run return step next); # undo sub undo { my($self, $levels) = @_; $levels ||= 1; my $response = $self->talk({ command => "commands" }); my @commands = @{$response->{commands}}; pop @commands foreach 1..$levels; # use YAML; warn Dump \@commands; my $proc = $self->proc; $proc->die; $self->load; $self->talk($_) foreach @commands; $self->basic; } # run until a breakpoint sub run { my($self) = @_; my $response = $self->talk({ command => "run" }); $self->basic; # get basic information for the new line } # return from a subroutine sub return { my($self, @values) = @_; my $values; $values = \@values if @values; my $response = $self->talk({ command => "return", values => $values, }); $self->basic; # get basic information for the new line } # step onto the next line (going into subroutines) sub step { my($self) = @_; my $response = $self->talk({ command => "step" }); $self->basic; # get basic information for the new line } # step onto the next line (going over subroutines) sub next { my($self) = @_; my $response = $self->talk({ command => "next" }); $self->basic; # get basic information for the new line } 1; Devel-ebug-0.55/lib/Devel/ebug/Plugin/Eval.pm000444001750001750 77612122201364 21211 0ustar00awwaiidawwaiid000000000000package Devel::ebug::Plugin::Eval; use strict; use warnings; use base qw(Exporter); our @EXPORT = qw(eval yaml); # eval sub eval { my($self, $eval) = @_; my $response = $self->talk({ command => "eval", eval => $eval, }); return wantarray ? ( $response->{eval}, $response->{exception} ) : $response->{eval}; } # yaml sub yaml { my($self, $yaml) = @_; my $response = $self->talk({ command => "yaml", yaml => $yaml, }); return $response->{yaml}; } 1; Devel-ebug-0.55/lib/Devel/ebug/Plugin/ActionPoints.pm000444001750001750 466112122201364 22751 0ustar00awwaiidawwaiid000000000000package Devel::ebug::Plugin::ActionPoints; use strict; use warnings; use base qw(Exporter); our @EXPORT = qw(break_point break_point_delete break_point_subroutine break_points break_points_with_condition all_break_points_with_condition watch_point break_on_load); # set a break point (by default in the current file) sub break_point { my $self = shift; my($filename, $line, $condition); if ($_[0] =~ /^\d+$/) { $filename = $self->filename; } else { $filename = shift; } ($line, $condition) = @_; my $response = $self->talk({ command => "break_point", filename => $filename, line => $line, condition => $condition, }); return $response->{line}; } # delete a break point (by default in the current file) sub break_point_delete { my $self = shift; my($filename, $line); my $first = shift; if ($first =~ /^\d+$/) { $line = $first; $filename = $self->filename; } else { $filename = $first; $line = shift; } my $response = $self->talk({ command => "break_point_delete", filename => $filename, line => $line, }); } # set a break point sub break_point_subroutine { my($self, $subroutine) = @_; my $response = $self->talk({ command => "break_point_subroutine", subroutine => $subroutine, }); return $response->{line}; } # list break points sub break_points { my($self, $filename) = @_; my $response = $self->talk({ command => "break_points", filename => $filename, }); return @{$response->{break_points}}; } # list break points with condition sub break_points_with_condition { my($self, $filename) = @_; my $response = $self->talk({ command => "break_points_with_condition", filename => $filename, }); return @{$response->{break_points}}; } # list break points with condition for the whole program sub all_break_points_with_condition { my($self, $filename) = @_; my $response = $self->talk({ command => "all_break_points_with_condition", filename => $filename, }); return @{$response->{break_points}}; } # set a watch point sub watch_point { my($self, $watch_point) = @_; my $response = $self->talk({ command => "watch_point", watch_point => $watch_point, }); } # set a break point on file loading sub break_on_load { my $self = shift; my($filename) = @_; my $response = $self->talk({ command => "break_on_load", filename => $filename, }); return $response->{line}; } 1; Devel-ebug-0.55/lib/Devel/ebug/Backend000755001750001750 012122201364 17726 5ustar00awwaiidawwaiid000000000000Devel-ebug-0.55/lib/Devel/ebug/Backend/Plugin000755001750001750 012122201364 21164 5ustar00awwaiidawwaiid000000000000Devel-ebug-0.55/lib/Devel/ebug/Backend/Plugin/Ping.pm000444001750001750 52612122201364 22537 0ustar00awwaiidawwaiid000000000000package Devel::ebug::Backend::Plugin::Ping; use strict; use warnings; sub register_commands { return ( ping => { sub => \&ping } ); } sub ping { my($req, $context) = @_; my $secret = $ENV{SECRET}; die "Did not pass secret" unless $req->{secret} eq $secret; $ENV{SECRET} = ""; return { version => $DB::VERSION, } } 1; Devel-ebug-0.55/lib/Devel/ebug/Backend/Plugin/StackTrace.pm000444001750001750 65112122201364 23665 0ustar00awwaiidawwaiid000000000000package Devel::ebug::Backend::Plugin::StackTrace; use strict; use warnings; use Devel::StackTrace; sub register_commands { return ( stack_trace => { sub => \&stack_trace } ); } sub stack_trace { my($req, $context) = @_; my $trace = Devel::StackTrace->new; my @frames = $trace->frames; # remove our internal frames shift @frames; shift @frames; shift @frames; return { stack_trace => \@frames }; } 1; Devel-ebug-0.55/lib/Devel/ebug/Backend/Plugin/Codelines.pm000444001750001750 53312122201364 23545 0ustar00awwaiidawwaiid000000000000package Devel::ebug::Backend::Plugin::Codelines; use strict; use warnings; sub register_commands { return ( codelines => { sub => \&codelines } ); } sub codelines { my($req, $context) = @_; my $filename = $req->{filename}; my @lines = @{$req->{lines}}; return { codelines => [ DB::fetch_codelines($filename, @lines)] }; } 1; Devel-ebug-0.55/lib/Devel/ebug/Backend/Plugin/Filenames.pm000444001750001750 70512122201364 23544 0ustar00awwaiidawwaiid000000000000package Devel::ebug::Backend::Plugin::Filenames; use strict; use warnings; sub register_commands { return ( filenames => { sub => \&filenames } ); } sub filenames { my($req, $context) = @_; my %filenames; foreach my $sub (keys %DB::sub) { my($filename, $start, $end) = $DB::sub{$sub} =~ m/^(.+):(\d+)-(\d+)$/; next if $filename =~ /^\(eval/; $filenames{$filename}++; } return { filenames => [sort keys %filenames] }; } 1; Devel-ebug-0.55/lib/Devel/ebug/Backend/Plugin/Pad.pm000444001750001750 123212122201364 22361 0ustar00awwaiidawwaiid000000000000package Devel::ebug::Backend::Plugin::Pad; use strict; use warnings; use PadWalker; sub register_commands { return ( pad => { sub => \&DB::pad } ) } package DB; use Scalar::Util qw(blessed reftype); sub pad { my($req, $context) = @_; my $pad; my $h = eval { PadWalker::peek_my(2) }; foreach my $k (sort keys %$h) { if ($k =~ /^@/) { my @v = eval "package $context->{package}; ($k)"; $pad->{$k} = \@v; } else { my $v = eval "package $context->{package}; $k"; $pad->{$k} = $v; # workaround for blessed globs $pad->{$k} = "".$v if blessed $v and reftype $v eq "GLOB"; } } return { pad => $pad }; } 1; Devel-ebug-0.55/lib/Devel/ebug/Backend/Plugin/Basic.pm000444001750001750 136712122201364 22707 0ustar00awwaiidawwaiid000000000000package Devel::ebug::Backend::Plugin::Basic; use strict; use warnings; sub register_commands { return (basic => { sub => \&basic }); } sub basic { my ($req, $context) = @_; return { codeline => $context->{codeline}, filename => $context->{filename}, finished => $context->{finished}, line => $context->{line}, package => $context->{package}, subroutine => subroutine($req, $context), }; } sub subroutine { my ($req, $context) = @_; foreach my $sub (keys %DB::sub) { my ($filename, $start, $end) = $DB::sub{$sub} =~ m/^(.+):(\d+)-(\d+)$/; next if $filename ne $context->{filename}; next unless $context->{line} >= $start && $context->{line} <= $end; return $sub; } return 'main'; } 1; Devel-ebug-0.55/lib/Devel/ebug/Backend/Plugin/Output.pm000444001750001750 107312122201364 23160 0ustar00awwaiidawwaiid000000000000package Devel::ebug::Backend::Plugin::Output; use strict; use warnings; my $stdout = ""; my $stderr = ""; if ($ENV{PERL_DEBUG_DONT_RELAY_IO}) { open NULL, ">/dev/null"; open NULL, '>', \$stdout; open NULL, '>', \$stderr; } else { close STDOUT; open STDOUT, '>', \$stdout or die "Can't open STDOUT: $!"; close STDERR; open STDERR, '>', \$stderr or die "Can't open STDOUT: $!"; } sub register_commands { return (output => { sub => \&output }); } sub output { my($req, $context) = @_; return { stdout => $stdout, stderr => $stderr, }; } 1; Devel-ebug-0.55/lib/Devel/ebug/Backend/Plugin/Run.pm000444001750001750 272212122201364 22426 0ustar00awwaiidawwaiid000000000000package Devel::ebug::Backend::Plugin::Run; use strict; use warnings; sub register_commands { return ( next => { sub => \&next, record => 1 }, return => { sub => \&return, record => 1 }, run => { sub => \&run, record => 1 }, step => { sub => \&step, record => 1 }, ); } sub next { my($req, $context) = @_; $context->{mode} = "next"; # single step (but over subroutines) $context->{last} = 1; # and out of the loop return {}; } sub return { my($req, $context) = @_; if ($req->{values}) { $context->{stack}->[0]->{return} = $req->{values}; } $context->{mode} = "return"; # run until returned from subroutine $DB::single = 0; # run if ($context->{stack}->[-1]) { $context->{stack}->[-1]->{single} = 1; # single step higher up } $context->{last} = 1; # and out of the loop return {}; } sub run { my($req, $context) = @_; $context->{mode} = "run"; # run until break point if (@{$context->{watch_points}}) { # watch points, let's go slow $context->{watch_single} = 0; } else { # no watch points? let's go fast! $DB::single = 0; # run until next break point } $context->{last} = 1; # and out of the loop return {}; } sub step { my($req, $context) = @_; $DB::single = 1; # single step $context->{mode} = "step"; # single step (into subroutines) $context->{last} = 1; # and out of the loop, onto the next command return {}; } 1; Devel-ebug-0.55/lib/Devel/ebug/Backend/Plugin/Eval.pm000444001750001750 152512122201364 22551 0ustar00awwaiidawwaiid000000000000package Devel::ebug::Backend::Plugin::Eval; use strict; use warnings; sub register_commands { return ( eval => { sub => \&DB::eval, record => 1 }, yaml => { sub => \&DB::yaml }, ); } package DB; # there appears to be something semi-magical about the DB # namespace that makes this eval only work when it's in it sub eval { my($req, $context) = @_; my $eval = $req->{eval}; local $SIG{__WARN__} = sub {}; my $v = eval "package $context->{package}; $eval"; if ($@) { return { eval => $@, exception => 1 }; } else { return { eval => $v, exception => 0 }; } } sub yaml { my($req, $context) = @_; my $eval = $req->{yaml}; local $SIG{__WARN__} = sub {}; my $v = eval "package $context->{package}; use YAML; Dump($eval)"; if ($@) { return { yaml => $@ }; } else { return { yaml => $v }; } } 1; Devel-ebug-0.55/lib/Devel/ebug/Backend/Plugin/ActionPoints.pm000444001750001750 705612122201364 24301 0ustar00awwaiidawwaiid000000000000package Devel::ebug::Backend::Plugin::ActionPoints; use strict; use warnings; use File::Spec; sub register_commands { return ( break_point => { sub => \&break_point, record => 1 }, break_points => { sub => \&break_points }, break_points_with_condition => { sub => \&break_points_with_condition }, all_break_points_with_condition => { sub => \&all_break_points_with_condition }, break_point_delete => { sub => \&break_point_delete, record => 1 }, break_point_subroutine => { sub => \&break_point_subroutine, record => 1 }, watch_point => { sub => \&watch_point, record => 1 }, break_on_load => { sub => \&break_on_load }, ); } sub break_point { my($req, $context) = @_; my $line = set_break_point($req->{filename}, $req->{line}, $req->{condition}); return $line ? { line => $line } : {}; } sub break_points { my($req, $context) = @_; use vars qw(@dbline %dbline); my $filename = $req->{filename} || $context->{filename}; *DB::dbline = $main::{ '_<' . $filename }; my $break_points = [ sort { $a <=> $b } grep { $DB::dbline{$_} } keys %DB::dbline ]; return { break_points => $break_points }; } sub break_points_with_condition { my($req, $context) = @_; use vars qw(@dbline %dbline); my $filename = $req->{filename} || $context->{filename}; *DB::dbline = $main::{ '_<' . $filename }; my $break_points = [ map { my $c = $DB::dbline{$_}; { filename => $filename, line => $_, ( $c && $c != 1 ) ? ( condition => $c ) : () } } sort { $a <=> $b } grep { $DB::dbline{$_} } keys %DB::dbline ]; return { break_points => $break_points }; } sub all_break_points_with_condition { my($req, $context) = @_; use vars qw(@dbline %dbline); my $files = Devel::ebug::Backend::Plugin::Filenames::filenames ( $req, $context ); # breaks encapsulation my @break_points; foreach my $file ( sort @{$files->{filenames}} ) { *DB::dbline = $main::{ '_<' . $file }; push @break_points, map { my $c = $DB::dbline{$_}; { filename => $file, line => $_, ( $c && $c != 1 ) ? ( condition => $c ) : () } } sort { $a <=> $b } grep { $DB::dbline{$_} } keys %DB::dbline; } return { break_points => \@break_points }; } sub break_point_delete { my($req, $context) = @_; use vars qw(@dbline %dbline); *DB::dbline = $main::{ '_<' . $req->{filename} }; $DB::dbline{$req->{line}} = 0; return {}; } sub break_point_subroutine { my($req, $context) = @_; my($filename, $start, $end) = $DB::sub{$req->{subroutine}} =~ m/^(.+):(\d+)-(\d+)$/; my $line = set_break_point($filename, $start); return $line ? { line => $line } : {}; } sub watch_point { my($req, $context) = @_; my $watch_point = $req->{watch_point}; push @{$context->{watch_points}}, $watch_point; return {}; } # set a break point sub set_break_point { my($filename, $line, $condition) = @_; $condition ||= 1; *DB::dbline = $main::{ '_<' . $filename }; # move forward until a line we can actually break on while (1) { return 0 if not defined $DB::dbline[$line]; # end of code last unless $DB::dbline[$line] == 0; # not breakable $line++; } $DB::dbline{$line} = $condition; return $line; } #set a break point on file loading sub break_on_load{ my($req, $context) = @_; my $filename = $req->{filename}; $DB::break_on_load{$filename} = 1; if (!File::Spec->file_name_is_absolute( $filename )){ #add the absolute path $filename = File::Spec->rel2abs( $filename); $DB::break_on_load{$filename} = 1; } return {}; } 1; Devel-ebug-0.55/lib/Devel/ebug/Backend/Plugin/Commands.pm000444001750001750 37012122201364 23400 0ustar00awwaiidawwaiid000000000000package Devel::ebug::Backend::Plugin::Commands; use strict; use warnings; sub register_commands { return ( commands => { sub => \&commands }, ); } sub commands { my($req, $context) = @_; return { commands => $context->{history} }; } 1; Devel-ebug-0.55/bin000755001750001750 012122201364 14420 5ustar00awwaiidawwaiid000000000000Devel-ebug-0.55/bin/ebug000555001750001750 141212122201364 15423 0ustar00awwaiidawwaiid000000000000#!/usr/bin/env perl use strict; use warnings; use lib 'lib'; use Devel::ebug::Console; my $backend; if ($ARGV[0] eq '--backend') { $backend = $ARGV[1]; shift(@ARGV); shift(@ARGV); } my $console = Devel::ebug::Console->new(); $console->run($backend); __END__ =head1 NAME ebug - A simple, extensible console Perl debugger =head1 SYNOPSIS % ebug calc.pl % ebug "add.pl 3 4" =head1 DESCRIPTION ebug is an interactive commmand-line front end to L. It is a simple Perl debugger, much like perl5db.pl. =head1 SEE ALSO L =head1 AUTHOR Leon Brocard, C<< >> =head1 COPYRIGHT Copyright (C) 2005, Leon Brocard This program is free software; you can redistribute it or modify it under the same terms as Perl itself. Devel-ebug-0.55/bin/ebug_client000555001750001750 336612122201364 16773 0ustar00awwaiidawwaiid000000000000#!/usr/bin/perl =head1 NAME ebug-client - Debugger client for remote debugging Perl script =head1 SYNOPSIS ebug-client -key -port =head1 DESCRIPTION ebug-client is an debugger front end for attaching to remotely executing perl script, running on ebug-server. To invoke ebug-client, you must first invoke ebug-server to run debuggee and generate "key" and "port" needed for connection. When ebug-server is invoked, it will show exact command-line to invoke ebug-client. =head1 EXAMPLE # Attach to ebug-server running on port 4023, with key "begripra" $ ebug-client -key begripra -port 4023 =head1 NOTE Currently, you cannot "restart" debuggee. You'll need to restart one manually by re-invoking both ebug-server and ebug-client. Since Devel::ebug::Backend listens to "localhost" socket, you will need to relay I/O using tool like socat for true remote debugging. Internally, thanks for it being free software, it is almost a complete ripoff of Devel::ebug source. =head1 SEE ALSO L, L, L =head1 AUTHOR Taisuke Yamada, =cut package Devel::ebug; use Devel::ebug; use IO::Socket::INET; use strict; use warnings; our $VERSION = $Devel::ebug::VERSION; our $ARG = {}; # Replace 'load' with one that just attaches sub load { my $self = shift; $self->attach($ARG->{port}, $ARG->{key}); } package main; use Devel::ebug::Console; use Getopt::Long; use strict; use warnings; GetOptions( my $OPT = {}, 'help', 'port=i', 'key=s' ) || help(); help() if $OPT->{help}; $Devel::ebug::ARG = $OPT; my $console = Devel::ebug::Console->new(); $console->run(); exit(0); sub help { print STDERR < -port -- debuggee args... EOF exit(1); } Devel-ebug-0.55/bin/ebug_backend_perl000555001750001750 20112122201364 20067 0ustar00awwaiidawwaiid000000000000#!/usr/bin/env perl use strict; use warnings; use lib 'lib'; my $program = "@ARGV"; exec("$^X -Ilib -d:ebug::Backend $program"); Devel-ebug-0.55/bin/ebug_server000555001750001750 324512122201364 17017 0ustar00awwaiidawwaiid000000000000#!/usr/bin/perl =head1 NAME ebug-server - Debugger server for remote debugging Perl script =head1 SYNOPSIS ebug-server [-keepio][-port port] -- script args... =head1 DESCRIPTION ebug-server is an debugger server for remote debugging Perl script, using ebug-client. When invoked, it will show you how to invoke ebug-client. =head1 EXAMPLE # Run hello.pl and wait for "ebug-client" to attach $ ebug-server -- hello.pl # Same as above, but keep I/O happen on server side $ ebug-server -keepio -- hello.pl =head1 NOTE You can't specify secret key - it must be generated automatically. Also, you can't specify port below 3141. Since Devel::ebug::Backend listens to "localhost" socket, you will need to relay I/O using tool like socat for true remote debugging. =head1 SEE ALSO L, L, L =head1 AUTHOR Taisuke Yamada, =cut use String::Koremutake; use Getopt::Long; use strict; use warnings; GetOptions( my $OPT = {}, 'help', 'port=i', 'keepio' ) || help(); help() if $OPT->{help} || !@ARGV; help() if $OPT->{port} && $OPT->{port} < 3141; my $cmd = "$^X -d:ebug::Backend @ARGV"; my $gen = String::Koremutake->new; my $rand = $OPT->{port} ? $OPT->{port} - 3141 : int( rand(100_000) ); my $key = $gen->integer_to_koremutake($rand); my $port = 3141 + ( $rand % 1024 ); $ENV{PERL_DEBUG_DONT_RELAY_IO} = 1 if $OPT->{keepio}; $ENV{SECRET} = $key; print STDERR <] -- debuggee args... Note: - Listening port must be >= 3141 EOF exit(1); } Devel-ebug-0.55/t000755001750001750 012122201364 14113 5ustar00awwaiidawwaiid000000000000Devel-ebug-0.55/t/subrefs.t000444001750001750 477312122201364 16121 0ustar00awwaiidawwaiid000000000000#!perl use strict; use warnings; use lib 'lib'; use Test::More tests => 30; use Devel::ebug; note "First we'll step over the subref"; my $ebug = Devel::ebug->new; $ebug->program("t/calc_subref.pl"); $ebug->backend("$^X bin/ebug_backend_perl"); $ebug->load; # Let's step through the program, and check that we step through the # lines in the right order is($ebug->line, 7, "Next line is 7"); is($ebug->filename, 't/calc_subref.pl', 'Still in t/calc_subref.pl'); $ebug->next; is($ebug->line, 9, "Next line is 9"); is($ebug->filename, 't/calc_subref.pl', 'Still in t/calc_subref.pl'); $ebug->next; is($ebug->line, 10, "Next line is 10"); is($ebug->filename, 't/calc_subref.pl', 'Still in t/calc_subref.pl'); $ebug->next; is($ebug->line, 11, "Next line is 11"); is($ebug->filename, 't/calc_subref.pl', 'Still in t/calc_subref.pl'); $ebug->next; is($ebug->line, 12, "Next line is 12"); is($ebug->filename, 't/calc_subref.pl', 'Still in t/calc_subref.pl'); $ebug->next; is($ebug->line, 13, "Next line is 13"); is($ebug->filename, 't/calc_subref.pl', 'Still in t/calc_subref.pl'); $ebug->next; is($ebug->line, 15, "Next line is 15"); is($ebug->filename, 't/calc_subref.pl', 'Still in t/calc_subref.pl'); $ebug->next; note "Now testing stepping into the subref"; $ebug = Devel::ebug->new; $ebug->program("t/calc_subref.pl"); $ebug->backend("$^X bin/ebug_backend_perl"); $ebug->load; is($ebug->line, 7, "Next line is 7"); is($ebug->filename, 't/calc_subref.pl', 'Still in t/calc_subref.pl'); $ebug->step; is($ebug->line, 9, "Next line is 9"); is($ebug->filename, 't/calc_subref.pl', 'Still in t/calc_subref.pl'); $ebug->step; is($ebug->line, 10, "Next line is 10"); is($ebug->filename, 't/calc_subref.pl', 'Still in t/calc_subref.pl'); $ebug->step; is($ebug->line, 11, "Next line is 11"); is($ebug->filename, 't/calc_subref.pl', 'Still in t/calc_subref.pl'); $ebug->step; is($ebug->line, 4, 'Inside of subref'); is($ebug->package, 'main', 'Still package main'); is($ebug->subroutine, 'main::__ANON__[t/calc_subref.pl:7]', 'ANON subref'); is($ebug->filename, 't/calc_subref.pl', 'Still in t/calc_subref.pl'); note "Try a breakpoint in the subref"; $ebug = Devel::ebug->new; $ebug->program("t/calc_subref.pl"); $ebug->backend("$^X bin/ebug_backend_perl"); $ebug->load; $ebug->break_point("t/calc_subref.pl", 4); $ebug->run; is($ebug->line, 4, 'Inside of subref'); is($ebug->package, 'main', 'Still package main'); is($ebug->subroutine, 'main::__ANON__[t/calc_subref.pl:7]', 'ANON subref'); is($ebug->filename, 't/calc_subref.pl', 'Still in t/calc_subref.pl'); Devel-ebug-0.55/t/codelines.t000444001750001750 353512122201364 16410 0ustar00awwaiidawwaiid000000000000#!perl use strict; use warnings; use lib 'lib'; use Test::More tests => 20; use Devel::ebug; my $ebug = Devel::ebug->new; $ebug->program("t/calc.pl"); $ebug->backend("$^X bin/ebug_backend_perl"); $ebug->load; # Let's get some lines of code SKIP: { my @codelines = $ebug->codelines(); skip "Don't try lining up codelines because of sitecustomize", 20 if $codelines[0] =~ /sitecustomize/; my @calc = ( '#!perl', '', 'my $q = 1;', 'my $w = 2;', 'my $e = add($q, $w);', '$e++;', '$e++;', '', 'print "$e\\n";', '', 'sub add {', ' my($z, $x) = @_;', ' my $c = $z + $x;', ' return $c;', '}', '', '# unbreakable line', 'my $breakable_line = 1;', '# other unbreakable line', ); is_deeply(\@codelines, \@calc); @codelines = $ebug->codelines(1, 3, 4, 5); is_deeply(\@codelines, [ '#!perl', 'my $q = 1;', 'my $w = 2;', 'my $e = add($q, $w);', ]); # Let's step through the program, and check that codeline is correct my @lines = (3, 4, 5, 12, 13, 14, 6, 7, 9); foreach my $l (@lines) { is($ebug->codeline, $calc[$l-1]); $ebug->step; } $ebug = Devel::ebug->new; $ebug->program("t/calc_oo.pl"); $ebug->backend("$^X bin/ebug_backend_perl"); $ebug->load; @codelines = $ebug->codelines("t/calc_oo.pl", 7, 8); is_deeply(\@codelines, [ 'my $calc = Calc->new;', 'my $r = $calc->add(5, 10); # 15', ]); @codelines = $ebug->codelines("t/Calc.pm", 5, 6); is_deeply(\@codelines, [ 'use base qw(Class::Accessor::Chained::Fast);', 'our $VERSION = "0.29";', ]); @codelines = $ebug->codelines("t/Calc.pm"); is(scalar(@codelines), 34); $ebug->program("t/pod.pl"); $ebug->backend("$^X bin/ebug_backend_perl"); $ebug->load; @codelines = $ebug->codelines(); is($codelines[0], '#!perl'); is($codelines[8], 'print "Result is $zz!\n";'); is($codelines[9], ''); is($codelines[10], ''); is($codelines[11], ''); is($codelines[31], 'sub add {'); } Devel-ebug-0.55/t/finished.t000444001750001750 76612122201364 16217 0ustar00awwaiidawwaiid000000000000#!perl use strict; use warnings; use lib 'lib'; use Test::More tests => 10; use Devel::ebug; my $ebug = Devel::ebug->new; $ebug->program("t/yaml.pl"); $ebug->backend("$^X bin/ebug_backend_perl"); $ebug->load; is($ebug->finished, 0); is($ebug->line, 3); is($ebug->subroutine, "main"); $ebug->next; is($ebug->finished, 0); is($ebug->line, 4); is($ebug->subroutine, "main"); $ebug->next; is($ebug->finished, 0); is($ebug->line, 5); is($ebug->subroutine, "main"); $ebug->next; is($ebug->finished, 1); Devel-ebug-0.55/t/eval.t000444001750001750 121412122201364 15362 0ustar00awwaiidawwaiid000000000000#!perl use strict; use warnings; use lib 'lib'; use Test::More tests => 9; use Devel::ebug; my $ebug = Devel::ebug->new; $ebug->program("t/calc.pl"); $ebug->backend("$^X bin/ebug_backend_perl"); $ebug->load; $ebug->break_point(6); $ebug->run; is($ebug->line, 6); is($ebug->eval('$e'), 3); is_deeply([$ebug->eval('$e')], [3, 0]); my $exception = $ebug->eval('die 123'); like($exception, qr/^123 at \(eval \d+\)/); my @exception = $ebug->eval('die 123'); is($exception[1], 1); # no like_deeply like($exception[0], qr/^123 at \(eval \d+\)/); $ebug->step; is($ebug->eval('$e'), 4); $ebug->step; is($ebug->eval('$e'), 5); is($ebug->yaml('$e'), "--- 5\n"); Devel-ebug-0.55/t/breakOnLoad.t000444001750001750 54312122201364 16600 0ustar00awwaiidawwaiid000000000000#!perl use strict; use warnings; use lib 'lib'; use Test::More tests => 3; use Devel::ebug; my $ebug = Devel::ebug->new; $ebug->program("t/load_calc.pl"); $ebug->backend("$^X bin/ebug_backend_perl"); $ebug->load; $ebug->break_on_load("t/Calc.pm"); $ebug->run; is($ebug->line, 6); is($ebug->filename, "t/Calc.pm"); $ebug->run; is($ebug->finished, 1); Devel-ebug-0.55/t/yaml.pl000444001750001750 20212122201364 15521 0ustar00awwaiidawwaiid000000000000use YAML; my $hash = { '/foo/foo- hate' => 'bz' }; print YAML::Dump ($hash); print YAML::Dump (YAML::Load (YAML::Dump ($hash))); Devel-ebug-0.55/t/undo.t000444001750001750 171112122201364 15402 0ustar00awwaiidawwaiid000000000000#!perl use strict; use warnings; use lib 'lib'; use Test::More tests => 21; use Devel::ebug; my $ebug = Devel::ebug->new; $ebug->program("t/calc.pl"); $ebug->backend("$^X bin/ebug_backend_perl"); $ebug->load; is($ebug->line, 3); is($ebug->subroutine, "main"); is($ebug->package, "main"); is($ebug->filename, "t/calc.pl"); $ebug->step; is($ebug->line, 4); $ebug->step; is($ebug->line, 5); $ebug->undo; is($ebug->line, 4); $ebug->undo; is($ebug->line, 3); $ebug->break_point(6); $ebug->break_point(12); $ebug->break_point(9); $ebug->undo; is_deeply([$ebug->break_points], [6, 12]); is($ebug->line, 3); is($ebug->subroutine, "main"); is($ebug->package, "main"); is($ebug->filename, "t/calc.pl"); $ebug->run; is($ebug->line, 12); $ebug->run; is($ebug->line, 6); $ebug->step; $ebug->step; is($ebug->pad->{'$e'}, 5); $ebug->undo; is($ebug->line, 7); is($ebug->subroutine, "main"); is($ebug->package, "main"); is($ebug->filename, "t/calc.pl"); is($ebug->pad->{'$e'}, 4); Devel-ebug-0.55/t/filenames.t000444001750001750 51312122201364 16357 0ustar00awwaiidawwaiid000000000000#!perl use strict; use warnings; use lib 'lib'; use Test::More tests => 2; use Devel::ebug; my $ebug = Devel::ebug->new; $ebug->program("t/calc_oo.pl"); $ebug->backend("$^X bin/ebug_backend_perl"); $ebug->load; my %filenames; $filenames{$_}++ foreach $ebug->filenames; ok($filenames{'t/calc_oo.pl'}); ok($filenames{'t/Calc.pm'}); Devel-ebug-0.55/t/basic.t000444001750001750 77312122201364 15505 0ustar00awwaiidawwaiid000000000000#!perl use strict; use warnings; use lib 'lib'; use Test::More tests => 36; use Devel::ebug; my $ebug = Devel::ebug->new; $ebug->backend("$^X bin/ebug_backend_perl"); $ebug->program("t/calc.pl"); $ebug->load; # Let's step through the program, and check that we step through the # lines in the right order my @lines = (3, 4, 5, 12, 13, 14, 6, 7, 9); foreach my $l (@lines) { is($ebug->line, $l); is($ebug->package, 'main'); is($ebug->filename, 't/calc.pl'); ok($ebug->codeline); $ebug->step; } Devel-ebug-0.55/t/stack.pl000444001750001750 46712122201364 15701 0ustar00awwaiidawwaiid000000000000#!perl use strict; use warnings; use String::Koremutake; my $k = String::Koremutake->new; my %hash = ('a' => 1); show(); show(1, undef, 2); show(123); show(-0.3); show('a'); show('orange o rama'); show([]); show({}); show($k); sub show { my($first, @rest) = @_; print $first, @rest, "\n"; my $n = 1; } Devel-ebug-0.55/t/koremutake.pl000444001750001750 26512122201364 16737 0ustar00awwaiidawwaiid000000000000use String::Koremutake; my $k = String::Koremutake->new; my $s = $k->integer_to_koremutake(65535); # botretre my $i = $k->koremutake_to_integer('koremutake'); # 10610353957 Devel-ebug-0.55/t/signal.pl000444001750001750 21012122201364 16033 0ustar00awwaiidawwaiid000000000000#!perl use strict; use warnings; foreach my $i (1..50) { my $square = $i * $i; kill 2, $$ if $square > 100; print "$square\n"; } Devel-ebug-0.55/t/oo.t000444001750001750 156412122201364 15060 0ustar00awwaiidawwaiid000000000000#!perl use strict; use warnings; use lib 'lib'; use Test::More tests => 12; use Devel::ebug; my $ebug = Devel::ebug->new; $ebug->program("t/calc_oo.pl"); $ebug->backend("$^X bin/ebug_backend_perl"); $ebug->load; # Let's step through the program, and check that we step through the # lines in the right order is($ebug->line, 7); is($ebug->filename, 't/calc_oo.pl'); $ebug->next; is($ebug->line, 8); is($ebug->filename, 't/calc_oo.pl'); $ebug->next; is($ebug->line, 9); is($ebug->filename, 't/calc_oo.pl'); $ebug->next; is($ebug->line, 10); is($ebug->filename, 't/calc_oo.pl'); $ebug->next; $ebug = Devel::ebug->new; $ebug->program("t/calc_oo.pl"); $ebug->backend("$^X bin/ebug_backend_perl"); $ebug->load; $ebug->break_point_subroutine("Calc::add"); $ebug->run; is($ebug->line, 9); is($ebug->package, 'Calc'); is($ebug->subroutine, 'Calc::add'); is($ebug->filename, 't/Calc.pm'); Devel-ebug-0.55/t/return.t000444001750001750 163612122201364 15762 0ustar00awwaiidawwaiid000000000000#!perl use strict; use warnings; use lib 'lib'; use Test::More tests => 13; use Devel::ebug; my $ebug = Devel::ebug->new; $ebug->program("t/calc_oo.pl"); $ebug->backend("$^X bin/ebug_backend_perl"); $ebug->load; $ebug->break_point_subroutine("Calc::add"); $ebug->run; is($ebug->line, 9); is($ebug->subroutine, 'Calc::add'); is($ebug->filename, 't/Calc.pm'); $ebug->return(); is($ebug->pad->{'$r'}, 15); is($ebug->line, 9); is($ebug->subroutine, 'main'); is($ebug->filename, 't/calc_oo.pl'); $ebug = Devel::ebug->new; $ebug->program("t/calc_oo.pl"); $ebug->backend("$^X bin/ebug_backend_perl"); $ebug->load; $ebug->break_point_subroutine("Calc::add"); $ebug->run; is($ebug->line, 9); is($ebug->subroutine, 'Calc::add'); $ebug->return(3.141); TODO: { local $TODO = 'Hmm... I broke the return...'; is($ebug->pad->{'$r'}, 3.141); } is($ebug->line, 9); is($ebug->subroutine, 'main'); is($ebug->filename, 't/calc_oo.pl'); Devel-ebug-0.55/t/signal.t000444001750001750 107112122201364 15711 0ustar00awwaiidawwaiid000000000000#!perl use strict; use warnings; use lib 'lib'; use Devel::ebug; use Test::More; plan skip_all => "Devel::ebug does not handle signals under Windows atm" if $^O =~ /mswin32/i; plan tests => 8; my $ebug = Devel::ebug->new; $ebug->program("t/signal.pl"); $ebug->backend("$^X bin/ebug_backend_perl"); $ebug->load; $ebug->run; is($ebug->finished, 0); is($ebug->line, 8); my $pad = $ebug->pad; is($pad->{'$i'}, 11); is($pad->{'$square'}, 121); $ebug->run; is($ebug->finished, 0); is($ebug->line, 8); $pad = $ebug->pad; is($pad->{'$i'}, 12); is($pad->{'$square'}, 144); Devel-ebug-0.55/t/break_point.t000444001750001750 506312122201364 16736 0ustar00awwaiidawwaiid000000000000#!perl use strict; use warnings; use lib 'lib'; use Test::More tests => 27; use Devel::ebug; my $ebug = Devel::ebug->new; $ebug->program("t/calc.pl"); $ebug->backend("$^X bin/ebug_backend_perl"); $ebug->load; # set break points at line numbers is( $ebug->break_point(6), 6 ); is( $ebug->break_point(12), 12 ); $ebug->break_point(9); is( $ebug->break_point(17), 18 ); # break on next breakable line is( $ebug->break_point(19), undef ); # no more breakable lines is_deeply([$ebug->break_points], [6, 9, 12, 18]); $ebug->run; is($ebug->line, 12); $ebug->run; is($ebug->line, 6); $ebug->run; is($ebug->line, 9); is($ebug->pad->{'$e'}, 5); $ebug->step; # set break point at add() $ebug = Devel::ebug->new; $ebug->program("t/calc.pl"); $ebug->backend("$^X bin/ebug_backend_perl"); $ebug->load; is( $ebug->break_point_subroutine("main::add"), 12 ); $ebug->run; is($ebug->line, 12); # set break point at fib2() $ebug = Devel::ebug->new; $ebug->program("t/calc_oo.pl"); $ebug->backend("$^X bin/ebug_backend_perl"); $ebug->load; $ebug->break_point("t/Calc.pm", 29); is_deeply([$ebug->break_points], []); is_deeply([$ebug->break_points("t/Calc.pm")], [29]); $ebug->run; is($ebug->line, 29); is($ebug->eval('$i'), 1); # set break point at add() $ebug = Devel::ebug->new; $ebug->program("t/calc.pl"); $ebug->backend("$^X bin/ebug_backend_perl"); $ebug->load; $ebug->break_point(6, '$e == 4'); $ebug->break_point(7, '$e == 4'); $ebug->run; is($ebug->line, 7); is($ebug->eval('$e'), 4); # set break point at fib2() $ebug = Devel::ebug->new; $ebug->program("t/calc_oo.pl"); $ebug->backend("$^X bin/ebug_backend_perl"); $ebug->load; $ebug->break_point("t/Calc.pm", 29, '$i == 2'); is_deeply([$ebug->break_points_with_condition], []); $ebug->break_point(11); is_deeply([$ebug->break_points_with_condition("t/Calc.pm")], [{filename => "t/Calc.pm", line => 29, condition => '$i == 2'}]); is_deeply([$ebug->all_break_points_with_condition], [{filename => "t/Calc.pm", line => 29, condition => '$i == 2'}, {filename => "t/calc_oo.pl", line => 11}, ]); $ebug->run; is($ebug->line, 29); is($ebug->eval('$i'), 2); is($ebug->eval('$x1'), 1); is($ebug->eval('$x2'), 2); # set break points at line numbers and delete one $ebug = Devel::ebug->new; $ebug->program("t/calc.pl"); $ebug->backend("$^X bin/ebug_backend_perl"); $ebug->load; $ebug->break_point(6); $ebug->break_point(12); $ebug->break_point(9); $ebug->break_point_delete(6); $ebug->break_point_delete("t/calc.pl", 12); is_deeply([$ebug->break_points], [9]); $ebug->run; is($ebug->line, 9); is($ebug->pad->{'$e'}, 5); $ebug->step; Devel-ebug-0.55/t/carp.pl000444001750001750 53312122201364 15513 0ustar00awwaiidawwaiid000000000000#!perl use strict; use warnings; use Carp; my $x = -4; print "Hi!\nAbout to get square_root($x)\n"; warn "\$x is -4"; my $result = square_root($x); print "$result\n"; sub square_root { my $arg = shift; carp "debug: In square_root, $arg is $arg"; if ($arg < 0) { croak "square_root of negative number: $arg"; } return sqrt($arg); } Devel-ebug-0.55/t/subroutine.t000444001750001750 105212122201364 16632 0ustar00awwaiidawwaiid000000000000#!perl use strict; use warnings; use lib 'lib'; use Test::More tests => 9; use Devel::ebug; my $ebug = Devel::ebug->new; $ebug->program("t/calc.pl"); $ebug->backend("$^X bin/ebug_backend_perl"); $ebug->load; # Let's step through the program, and check that we get the # correct subroutine for each line foreach (1..9) { my $line = $ebug->line; my $sub = $ebug->subroutine; my $want_sub = 'main'; # sub add { ... } is lines 11 to 15 if ($line > 11 && $line < 15) { $want_sub = 'main::add'; } is($sub, $want_sub); $ebug->step; } Devel-ebug-0.55/t/Calc.pm000444001750001750 100612122201364 15445 0ustar00awwaiidawwaiid000000000000package Calc; use strict; use warnings; use Class::Accessor::Chained::Fast; use base qw(Class::Accessor::Chained::Fast); our $VERSION = "0.29"; sub add { my($self, $l, $r) = @_; return $l + $r; } sub fib1 { my($self, $n) = @_; if ($n < 2) { return 1; } else { return $self->fib1($n - 1) + $self->fib1($n - 2); } } sub fib2 { my($self, $n) = @_; my $x1 = 1; my $x2 = 1; my $tmp = 0; foreach my $i (1..$n) { $tmp = $x1 + $x2; $x1 = $x2; $x2 = $tmp; } return $x1; } Devel-ebug-0.55/t/koremutake.t000444001750001750 116412122201364 16606 0ustar00awwaiidawwaiid000000000000#!perl use strict; use warnings; use lib 'lib'; use Test::More tests => 3; use Devel::ebug; my $ebug = Devel::ebug->new; $ebug->program("t/koremutake.pl"); $ebug->backend("$^X bin/ebug_backend_perl"); $ebug->load; $ebug->run; $ebug = Devel::ebug->new; $ebug->program("t/koremutake.pl"); $ebug->backend("$^X bin/ebug_backend_perl"); $ebug->load; my $filename = (grep { $_ =~ /Koremutake/ } $ebug->filenames)[0]; ok($filename); $ebug->break_point_subroutine("String::Koremutake::integer_to_koremutake"); $ebug->run; is($ebug->subroutine, "String::Koremutake::integer_to_koremutake"); is($ebug->filename, $filename); $ebug->run; Devel-ebug-0.55/t/calc.pl000444001750001750 32312122201364 15465 0ustar00awwaiidawwaiid000000000000#!perl my $q = 1; my $w = 2; my $e = add($q, $w); $e++; $e++; print "$e\n"; sub add { my($z, $x) = @_; my $c = $z + $x; return $c; } # unbreakable line my $breakable_line = 1; # other unbreakable line Devel-ebug-0.55/t/output.t000444001750001750 422212122201364 15775 0ustar00awwaiidawwaiid000000000000#!perl use strict; use warnings; use lib 'lib'; use Test::More tests => 28; use Devel::ebug; my $ebug = Devel::ebug->new; $ebug->program("t/carp.pl"); $ebug->backend("$^X bin/ebug_backend_perl"); $ebug->load; is($ebug->line, 6); my($stdout, $stderr) = $ebug->output; is($stdout, ""); is($stderr, ""); $ebug->step; is($ebug->line, 7); ($stdout, $stderr) = $ebug->output; is($stdout, ""); is($stderr, ""); $ebug->step; is($ebug->line, 8); ($stdout, $stderr) = $ebug->output; is($stdout, "Hi!\nAbout to get square_root(-4)\n"); is($stderr, ""); $ebug->step; is($ebug->line, 9); ($stdout, $stderr) = $ebug->output; is($stdout, "Hi!\nAbout to get square_root(-4)\n"); is($stderr, "\$x is -4 at t/carp.pl line 8, line 10.\n"); $ebug->step; is($ebug->line, 13); ($stdout, $stderr) = $ebug->output; is($stdout, "Hi!\nAbout to get square_root(-4)\n"); is($stderr, "\$x is -4 at t/carp.pl line 8, line 10.\n"); $ebug->step; is($ebug->line, 14); ($stdout, $stderr) = $ebug->output; is($stdout, "Hi!\nAbout to get square_root(-4)\n"); is($stderr, "\$x is -4 at t/carp.pl line 8, line 10.\n"); $ebug->next; is($ebug->line, 15); ($stdout, $stderr) = $ebug->output; is($stdout, "Hi!\nAbout to get square_root(-4)\n"); like($stderr, qr{ \Qx is -4 at t/carp.pl line 8\E .* \Qdebug: In square_root, -4 is -4 at t/carp.pl line 14\E .* \Qmain::square_root(-4) called at t/carp.pl line 9\E }msx); $ebug->next; is($ebug->line, 16); ($stdout, $stderr) = $ebug->output; is($stdout, "Hi!\nAbout to get square_root(-4)\n"); like($stderr, qr{ \Qx is -4 at t/carp.pl line 8\E .* \Qdebug: In square_root, -4 is -4 at t/carp.pl line 14\E .* \Qmain::square_root(-4) called at t/carp.pl line 9\E }msx); $ebug->next; ok($ebug->finished); is($ebug->package, "DB::fake"); # bit of a side effect ($stdout, $stderr) = $ebug->output; is($stdout, "Hi!\nAbout to get square_root(-4)\n"); like($stderr, qr{ \Qx is -4 at t/carp.pl line 8\E .* \Qdebug: In square_root, -4 is -4 at t/carp.pl line 14\E .* \Qmain::square_root(-4) called at t/carp.pl line 9\E .* \Qsquare_root of negative number: -4 at t/carp.pl line 16\E .* \Qmain::square_root(-4) called at t/carp.pl line 9\E }msx); Devel-ebug-0.55/t/load_calc.pl000444001750001750 17012122201364 16464 0ustar00awwaiidawwaiid000000000000#!perl my $q = 1; my $w = 2; use lib "t"; eval "use Calc"; print "after Calc.pm is loaded"; eval "Calc::add(1,2)"; Devel-ebug-0.55/t/pod.pl000444001750001750 114012122201364 15363 0ustar00awwaiidawwaiid000000000000#!perl use strict; use warnings; my $x = 1; my $y = 2; my $z = add(1, 2); my $zz = subtract($x, $z); print "Result is $zz!\n"; =head1 NAME pod.pl - An example program with POD =head1 SYNOPSIS # none =head1 DESCRIPTION No usage really, it's just to check out any embedded POD issues with Devel::ebug. =head1 SUBROUTINES =head2 add Add two integers together. =cut sub add { my($z, $x) = @_; my $c = $z + $x; return $c; } =head2 subtract Subtract one number from another. =cut sub subtract { my($z, $x) = @_; my $c = $z - $x; return $c; } 1; __END__ =head2 AUTHOR Me! =cut Devel-ebug-0.55/t/calc_oo.pl000444001750001750 31312122201364 16161 0ustar00awwaiidawwaiid000000000000#!perl use strict; use warnings; use lib "t"; use Calc; my $calc = Calc->new; my $r = $calc->add(5, 10); # 15 my $f = $calc->fib1($r); # 987 my $f2 = $calc->fib2($r); # 987 my $f3 = 1; # breakable line Devel-ebug-0.55/t/pod.t000444001750001750 22012122201364 15171 0ustar00awwaiidawwaiid000000000000#!perl -T use Test::More; eval "use Test::Pod 1.14"; plan skip_all => "Test::Pod 1.14 required for testing POD: $@" if $@; all_pod_files_ok(); Devel-ebug-0.55/t/stack.t000444001750001750 517012122201364 15545 0ustar00awwaiidawwaiid000000000000#!perl use strict; use warnings; use lib 'lib'; use Test::More tests => 29; use Devel::ebug; use File::Spec; my $ebug = Devel::ebug->new; $ebug->program("t/calc.pl"); $ebug->backend("$^X bin/ebug_backend_perl"); $ebug->load; my @trace = $ebug->stack_trace; is(scalar(@trace), 0); $ebug->break_point(12); $ebug->run; @trace = $ebug->stack_trace; is(scalar(@trace), 1); # use YAML; warn Dump \@trace; my $trace = $trace[0]; is($trace->package , "main"); is($trace->filename , File::Spec->catfile('t','calc.pl'), "trace is on correct file name"); is($trace->subroutine, "main::add"); ok(! $trace->wantarray ); # Forced boolean context is($trace->line , 5); is_deeply([$trace->args], [1, 2]); @trace = $ebug->stack_trace_human; is(scalar(@trace), 1); is($trace[0], 'add(1, 2)'); $ebug = Devel::ebug->new; $ebug->program("t/calc_oo.pl"); $ebug->backend("$^X bin/ebug_backend_perl"); $ebug->load; $ebug->break_point("t/Calc.pm", 19); $ebug->run; @trace = $ebug->stack_trace_human; is(scalar(@trace), 1); is($trace[0], '$calc->fib1(15)'); $ebug->run; @trace = $ebug->stack_trace_human; is(scalar(@trace), 2); is($trace[1], '$calc->fib1(15)'); is($trace[0], '$self->fib1(14)'); $ebug = Devel::ebug->new; $ebug->program("t/koremutake.pl"); $ebug->backend("$^X bin/ebug_backend_perl"); $ebug->load; $ebug->step; @trace = $ebug->stack_trace_human; is(scalar(@trace), 1); is($trace[0], 'String::Koremutake->new()'); $ebug = Devel::ebug->new; $ebug->program("t/koremutake.pl"); $ebug->backend("$^X bin/ebug_backend_perl"); $ebug->load; $ebug->break_point_subroutine("String::Koremutake::integer_to_koremutake"); $ebug->run; @trace = $ebug->stack_trace_human; is(scalar(@trace), 1); is($trace[0], '$koremutake->integer_to_koremutake(65535)'); $ebug = Devel::ebug->new; $ebug->program("t/stack.pl"); $ebug->backend("$^X bin/ebug_backend_perl"); $ebug->load; $ebug->break_point_subroutine("main::show"); $ebug->run; @trace = $ebug->stack_trace_human; is(scalar(@trace), 1); is($trace[0], 'show()'); $ebug->run; @trace = $ebug->stack_trace_human; is($trace[0], 'show(1, undef, 2)'); $ebug->run; @trace = $ebug->stack_trace_human; is($trace[0], 'show(123)'); $ebug->run; @trace = $ebug->stack_trace_human; is($trace[0], 'show(-0.3)'); $ebug->run; @trace = $ebug->stack_trace_human; is($trace[0], "show('a')"); $ebug->run; @trace = $ebug->stack_trace_human; is($trace[0], 'show("orange o rama")'); $ebug->run; @trace = $ebug->stack_trace_human; is($trace[0], 'show([...])'); $ebug->run; @trace = $ebug->stack_trace_human; is($trace[0], 'show({...})'); $ebug->run; @trace = $ebug->stack_trace_human; is($trace[0], 'show($koremutake)'); # use YAML; warn Dump \@trace; Devel-ebug-0.55/t/pad.t000444001750001750 336412122201364 15207 0ustar00awwaiidawwaiid000000000000#!perl use strict; use warnings; use lib 'lib'; use Test::More tests => 22; use Devel::ebug; my $ebug = Devel::ebug->new; $ebug->program("t/calc.pl"); $ebug->backend("$^X bin/ebug_backend_perl"); $ebug->load; # Let's step through the program, and check that we get the # lexical variables for each line my $want_vars = { 3 => '', 4 => '$q=1', 5 => '$q=1,$w=2', 12 => '$e=undef,$q=1,$w=2', 13 => '$e=undef,$q=1,$w=2,$x=2,$z=1', 14 => '$c=3,$e=undef,$q=1,$w=2,$x=2,$z=1', 6 => '$e=3,$q=1,$w=2', 7 => '$e=4,$q=1,$w=2', 9 => '$e=5,$q=1,$w=2', }; foreach (1..9) { my $line = $ebug->line; my $pad = $ebug->pad; my @vars; foreach my $k (sort keys %$pad) { my $v = $pad->{$k} || 'undef'; push @vars, "$k=$v"; } my $vars = join ',', @vars; $vars ||= ''; is($vars, $want_vars->{$line}, "$line has $vars"); $ebug->step; } $ebug = Devel::ebug->new; $ebug->program("t/stack.pl"); $ebug->backend("$^X bin/ebug_backend_perl"); $ebug->load; $ebug->break_point(22); $ebug->run; my $pad = $ebug->pad_human; is($pad->{'$first'}, 'undef'); is($pad->{'%hash'}, '(...)'); $ebug->run; $pad = $ebug->pad; is($pad->{'$first'}, '1'); is_deeply($pad->{'@rest'}, [undef, 2]); $pad = $ebug->pad_human; is($pad->{'$first'}, '1'); is($pad->{'@rest'}, "(undef, 2)"); $ebug->run; $pad = $ebug->pad_human; is($pad->{'$first'}, '123'); $ebug->run; $pad = $ebug->pad_human; is($pad->{'$first'}, '-0.3'); $ebug->run; $pad = $ebug->pad_human; is($pad->{'$first'}, "'a'"); $ebug->run; $pad = $ebug->pad_human; is($pad->{'$first'}, '"orange o rama"'); $ebug->run; $pad = $ebug->pad_human; is($pad->{'$first'}, '[...]'); $ebug->run; $pad = $ebug->pad_human; is($pad->{'$first'}, '{...}'); $ebug->run; $pad = $ebug->pad_human; is($pad->{'$first'}, '$koremutake'); Devel-ebug-0.55/t/run.t000444001750001750 55112122201364 15222 0ustar00awwaiidawwaiid000000000000#!perl use strict; use warnings; use lib 'lib'; use Test::More tests => 3; use Devel::ebug; my $ebug = Devel::ebug->new; $ebug->program("t/calc.pl"); $ebug->backend("$^X bin/ebug_backend_perl"); $ebug->load; is($ebug->line, 3); $ebug->step; $ebug->step; $ebug->step; is($ebug->line, 12); $ebug->run; ok($ebug->finished); my($stdout, $stderr) = $ebug->output; Devel-ebug-0.55/t/watch_point.t000444001750001750 136012122201364 16754 0ustar00awwaiidawwaiid000000000000#!perl use strict; use warnings; use lib 'lib'; use Test::More tests => 8; use Devel::ebug; my $ebug = Devel::ebug->new; $ebug->program("t/calc.pl"); $ebug->backend("$^X bin/ebug_backend_perl"); $ebug->load; # just one watch point $ebug->watch_point('$e == 4'); $ebug->run; is($ebug->line, 7); is($ebug->pad->{'$e'}, 4); $ebug = Devel::ebug->new; $ebug->program("t/calc.pl"); $ebug->backend("$^X bin/ebug_backend_perl"); $ebug->load; # multiple watch points - they disappear $ebug->watch_point('$e == 4'); $ebug->watch_point('$w > 0'); $ebug->watch_point('defined $c'); $ebug->run; is($ebug->line, 5); is($ebug->pad->{'$w'}, 2); $ebug->run; is($ebug->line, 14); is($ebug->pad->{'$c'}, 3); $ebug->run; is($ebug->line, 7); is($ebug->pad->{'$e'}, 4); Devel-ebug-0.55/t/ebug.t000444001750001750 357512122201364 15371 0ustar00awwaiidawwaiid000000000000#!perl use strict; use warnings; use lib 'lib'; use Devel::ebug; use Test::More; eval "use Test::Expect"; plan skip_all => "Test::Expect required for testing ebug: $@" if $@; eval "use Expect::Simple"; plan skip_all => "Expect::Simple required for testing ebug: $@" if $@; plan tests => 17; expect_run( command => "PERL_RL=\"o=0\" $^X bin/ebug --backend \"$^X bin/ebug_backend_perl\" t/calc.pl", prompt => 'ebug: ', quit => 'q', ); my $version = $Devel::ebug::VERSION; expect_like(qr/Welcome to Devel::ebug $version/, 'Got welcome'); expect_like(qr{main\(t/calc.pl#3\):\nmy \$q = 1;}, 'Got initial lines'); expect("h", 'Commands: b Set break point at a line number (eg: b 6, b code.pl 6, b code.pl 6 $x > 7, b Calc::fib) d Delete a break point (d 6, d code.pl 6) e Eval Perl code and print the result (eg: e $x+$y) f Show all the filenames loaded l List codelines or set number of codelines to list (eg: l, l 20) L List codelines always (toggle) n Next (steps over subroutine calls) o Output (show STDOUT, STDERR) p Show pad r Run until next break point or watch point ret Return from subroutine (eg: ret, ret 3.141) restart Restart the program s Step (steps into subroutine calls) T Show a stack trace u Undo (eg: u, u 4) w Set a watchpoint (eg: w $t > 10) x Dump a variable using YAML (eg: x $object) q Quit main(t/calc.pl#3): my $q = 1;', 'Got help'); expect("b 9", "main(t/calc.pl#3):\nmy \$q = 1;", 'set breakpoint'); expect("s", "main(t/calc.pl#4):\nmy \$w = 2;", 'step'); expect("", "main(t/calc.pl#5):\nmy \$e = add(\$q, \$w);", 'step again'); expect("n", "main(t/calc.pl#6):\n\$e++;", 'next'); expect("r", qq{main(t/calc.pl#9):\nprint "\$e\\n";}, 'run'); expect("r", qq{}, 'run to end'); # expect("r", qq{Program finished. Enter 'restart' or 'q'}, 'run to end'); # expect("q", qq{}); Devel-ebug-0.55/t/calc_subref.pl000444001750001750 33512122201364 17036 0ustar00awwaiidawwaiid000000000000#!perl my $add = sub { my($z, $x) = @_; my $c = $z + $x; return $c; }; my $q = 1; my $w = 2; my $e = $add->($q, $w); $e++; $e++; print "$e\n"; # unbreakable line my $breakable_line = 1; # other unbreakable line