diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..ab5f9f7 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,7 @@ +Author and maintainer: +Kent Sibilev + +Contributers: +Markus Barchfeld +R. Bernstein +Anders Lindgren diff --git a/CHANGES b/CHANGES new file mode 100644 index 0000000..4c9d8b2 --- /dev/null +++ b/CHANGES @@ -0,0 +1,334 @@ +0.10.3 +11/17/08 + + - a backtrace now warns when it thinks the callstack is truncated which it + gets by comparing with caller() + - fix setting $0. + - fix bug in showing variables in post-mortem + - Document how Debugger.start with a block is intended to be used. + - Move Kernel#debugger from ruby-debug-base into ruby-debug + - Get regression tests working again + - Warn and add a "confirmation" when setting a breakpoint on a + file that is not loaded. + +0.10.2 + - debugger(steps=0) breaks inside of debugger rather than wait for a line event. + - trace var varname (stop|nostop) added which issues trace_var. + - start method is now properly defined in Debugger module + - fixed 'finish' command + - rdebug script now works with Ruby 1.8.7 + +0.10.1 +4/10/08 - in honor of the 30th Birthday of Kate Schwarz + +- bin/rdebug + + * "rdebug --post-mortem" now really catches uncaught exceptions and + brings you to post-mortem handling. "info program" shows the exception. + + * rdebug now searches using ENV['PATH'] for a Ruby program to debug + if the program name is not found and doesn't have any path + characters in it. + + * Use ~/.rdboptrc (rdbopt.ini on MS Windows) to change default options. + + * --emacs is now --emacs-basic while --emacs 3 now implies emacs-basic + ---annotate=3 --post-mortem --no-control --no-start --no-quit + +- rdebug (CLI) + + * "info" command additions and changes: + o fix bug in "info variables" when string had embedded %s' + o "info program" now shows uncaught exception information + o "info files" show what Ruby files are loaded + o "info file " specific file information of (e.g. time, # of lines, SHA1) + o "info catch" - Exceptions that can be caught in the current stack frame. + o "info "variables" shows "self" and class variables + o "info threads verbose" shows stack trace of all threads + o "info thread verbose" shows stack trace of thread . + + * "frame" command now accepts an optional thread number argument + + * Long information added to commands with subcommands: show, set, + info, enable, and disable. For example "help info " will give + more detailed information about the "info " command. + + * columnize now pulled in from a separate package. + + * add "var cl[ass]" command. Note "var const" can no longer be + abbreviated "var c"; use "var co" (or const or constant). + + * add "condition" command. Allow removal of condition. + + * $0 == __FILE__ when running rdebug should work -- most of the + time. See comments in code for a better solution. + + * rdebug command history can be displayed with "show commands". Fix a bug + in history saving. + + * INCOMPATIBLE CHANGE: "finish" works like gdb - stop just before the most + recent method finishes. Will now accept a number which stops that many + frames completed. (Note that return line numbers will be funny, the + first line of the method until Ruby 1.8.7.) + + * fix bug in 'list' command when wrapping off the end. + +- Emacs interaction drastically reworked, expanded, and improved. + +- rdebug base + * allow catching multiple exceptions. + INCOMPATIBLE CHANGE: variable "Debugger.catchpoint", a String, was turned + into "Debugger.catchpoints", a Hash. Method "Debugger.catchpoint=" no + longer exists. Debugger.set_catchpoint was turned into + Debugger.add_catchpoint + + * Add Debugger.last_exception which is set in post-mortem. + + * remove Debugger.stop() when an exception is raised that would terminate the + debugged program. This may allow catchpoints to work and allow tracing user + code which handles "Exit" exceptions + + * split off breakpoint code in ruby_debug.c. + + * preface ruby_debug global Ruby variables with rdebug_. + + * Change Debugger.start() to accept an optional options argument + :init => true saves things (like $0 and ARGV) necessary to + allow restart. Default: true + :post_mortem => true runs post-mortem on an uncaught exception + Default: false + + The old Debugger.start() is now renamed to Debugger.start_() + + * split of line caching to an external gem. We now only allow setting + breakpoints on lines where it makes sense to do so. + + * Incompatible enhancement: even return/end will now call event handler + + See ChangeLog for full details, and the reference guide for more complete + documentation of these changes. + +0.10.0 +12/25/07 + +- '-r' option can be used to require additional libraries. +- --noquit option added to stay in debugger when the program exits +- gdb-like --annotate option added. Can be used by front-ends to get information + without polling +- Fixed 'var const' command. Issue #10847. +- Using pretty-print for all var commands. +- Better error reporting for commands that require a numeric argument. +- Fixed Kernel#binding_n method +- Add option -d ($DEBUG = true) and --verbose. Make -v work like ruby. +- Remove debugger messages caused when warnings are turned on. +- "info" and "show" commands added. "set" made more like gdb's + set. subcommands can be abbreviated and are case insensitive. +- restart program if it terminates normally and we've got a tty and + we stop on the first statement. +- help is in tidy column format. method lists are shown that way as well. + the "width" setting ("set/show width") is used for the line width +- stack traces now show parameter names and types. "info args" lists just + the parameters (with the most recent values, not the values at call time). +- post-mortem "exit" bug fixed. +- More Emacs-friendly: rdebug-track.el will track location inside an Emacs + shell. Emacs position information is shown in breakpoints and catchpoints + similar to gdba. Commands to position in another window a unit test traceback + or ruby traceback. Much more work invisioned for Emacs. +- INCOMPATIBLE CHANGE: "break" now sets a breakpoint on the current line + (same as gdb). Use "info break" for a list of breakpoints. +- INCOMPATIBLE CHANGE: "script" command removed. Use "source" command instead + (same as gdb). +- Run .rdebugrc on Debugger.start. Look for a file in the current directory and + run that instead of the one in $HOME if that exists. Again, inspired by and compatible + with gdb. +- Changes compatible with Ruby 1.9. NOTE: this debugger will NOT work with + Ruby 1.9 +- leaving irb shows position same as entering debugger; "list" position + is also cleared when leaving irb +- help "foo" gives message "Undefined command "foo" rather than a list + of help commands. (Message test is gdb's) +- Add set linetrace+ - similar to step+ for linetrace +- Start unit tests. +- Start a reference guide. + +0.9.3 +- Fixed if..elsif..end stepping. +- From irb session Ctrl-C or 'cont' command continues execution without showing the debugger prompt. +- Added Debugger.settings method to programatically modify command settings. +- Added Kernel#breakpoint as alias to Kernel#debugger is the former is not already defined. + +0.9.2 +- Fixed file comparison in Windows platform. +- Added setter methods to Breakpoint properties +- Added breakpoint hit condition functionality (not available via CLI yet) and methods: + Breakpoint:hit_count + Breakpoint:hit_value[=] + Breakpoint:hit_condition[=] + +0.9.1 +- Fixed incorrect stack calculation. +- Context#stop_next= method aliased as Context#step. +- Added the 'force' parameter to Context#step_over. +- Added the 'force' parameter to Context#step. +- 'next+/step+' commands forces to move to another line +- Added a new 'forcestep' setting. + +0.9 +- Kernel#debugger method will start the debugger if it's not running. +- Added Context#stop_reason method. +- Calling a method with a block will create a new frame. This changes the behavior of 'next' command. So in order to step into a block, 'step' command must be used. That fixes bug #9629. +- Added the possibility to add a temporary context-specific breakpoint. Context#breakpoint and Context#set_breakpoint methods are added. +- 'cont' command now accepts a numerical parameter which implements 'Continue until line' behavior. +- Added new Context.frame_class method +- Added new 'framefullpath' setting. +- Added new 'frameclassname' setting. +- All Ruby's 'eval' and require/load methods create a new frame. Fixes bug #9686. + +0.8.1 +- Added a shortcut module 'debugger'. require "ruby-debug/debugger" will start the debugger and stop at the next line (similar to require 'debug'). +- Fixed remote debugging. + +0.8 +- Extract the base debugger API into a separate gem (ruby-debug-base), so it will be easier to add a new interface. +- Added 'set autoirb' setting. +- Bugfixes. + +0.7.5 +- Fixed 'reload on' command +- 'reload on' command is removed in favor of 'set autoreload' +- rdebug will evaluate ~/.rdebugrc script on startup + +0.7.4 +- Added a workaround of the Ruby interpreter problem where a method created with Module#define_method + and which raises an exception doesn't trigger a :return event, this way screwing the stack trace. +- Fixed a situation of an array 'out of bounds' access. +- Fixed the help for 'where' command. + +0.7.3 +- Fixed a case when a frame is not popped up properly. +- Removed Context.ignore= method, since it can result with the segmentation fault error. +- Fixed the case when Context#suspend may effect the state of the thread on Context#resume +- Fixed several cases of seg faults when accessing dyna_vars structure. + +0.7.2 +- Fixed Context#resume (a thread should be waked up only when it was running when it was suspended). +- When handling post-mortem exception, all threads must be suspended. + +0.7.1 +- Fixed 'delete' command + +0.7 +- Eliminated explicit Frame object. Use Context.frame_[binding,file,line] instead. +- Fixed help command. +- Renamed Debugger.keep_frame_info to Debugger.keep_frame_binding +- 'eval' command is available, even when keep_frame_binding is not used. +- New 'set' command is available. + +0.6.2 +- Added thread lookup cache. +- Control thread is always started by rdebug script. +- Ability to specify negative frame number to frame commands. Patch from R. Bernstein. + +0.6.1 +- Another performance optimization. + +0.6 +- Added option to exclude collecting of frame bindings. +- Several performance optimizations. + +0.5.4 +- Added -x/--trace option to rdebug script. Patch from R. Bernstein. +- Removed a live thread reference from the context's structure avoiding memory leakage. + +0.5.3 +- Added Module#post_mortem_method method, which wraps any method with Debugger.post_mortem block. +- Added breakpoint id, which is not dependent on the breakpoint position in Debugger.breakpoints array. + +0.5.2 +- Fixes interoperability problems with rspec. +- Made 'exit' as an alias to 'quit' +- Added 'restart' command. Patch from R. Bernstein. + +0.5.1 +- Bugfixes. + +0.5 +- Added post-mortem debugging +- Added 'irb' command. + +0.4.5 +- Fixed debug_method when applied to setter. +- Added 'reload' command which can be used to reload source code in case it's been changed. +- Added Debugger.reload_source_on_change option (true, by default) which controls whether ruby-debug should keep + track of the source files modification times and reload them if they've been changed. + +0.4.4 +- Renamed Context#set_suspend and Context#clear_suspend methods to Context#suspend and Context#resume respectively. +- Context#resume method not only clears suspend flag, but also resumes the thread execution. +- Bugfixes. + +0.4.3 +- Added Debugger.skip method which allows escaping a block from the debugger reach. +- Bugfixes. + +0.4.2 +- Module#deubg_method added. +- Added rdoc. +- Bugfixes. + +0.4.1 +- New binding_n method for Kernel module. +- Bugfixes. + +0.4 +- Debugger.start method takes a block. If a block is specified, this method starts debugger, yields to the block + and stops debugger at the end. +- 'tm[ate]' command accepts a frame number now. +- 'list' command accepts on/off parameter which controls whether listing will be displayed on every stop. +- 'eval on/off' controls the evaluation of unknown command. +- Debugger reads readline history file .rdebug_hist at startup and saves it at exit. +- 'sa[ve] ' command can be used to save current breackpoints and catchpoint if any +- 'sc[ript] ' command can be used to run script file. Script files can contain only control commands. +- rdebug script accepts '--script FILE' parameter. +- thread commands are available for the control port. + +0.3 (2006-08-07) +- Renamed Debugger.start_server to Debugger.start_remote. +- Debugger.start_remote activates debugger by calling Debugger.start. +- Debugger.start_remote starts a control thread which listen on port 8990 and accepts control + commands, such as adding/deleting breakpoints, assigning catchpoint, etc. (Useful for GUI integration) +- New Debugger.wait_connection option. When it's true, Debugger.start_remote waits until + a remote connection is made. +- New Debugger.stop_on_connect option. When a remote connection is established, debugger + stops the main thread (Thread.main). +- 'interrupt' command is available for the control thread. + +0.2.1 (2006-07-29) +- 'f[rame] nn' command selects a numbered frame. Frame numbers can be obtained by running frame + command without parameters. +- 'l[ist] =' show code in the context of the current line. +- 'tm[ate]' opens the current file in TextMate. Available only on Mac OSX. + +0.2 (2006-07-17) +- Added the remote debugging. It should be activated by calling Debugger#start_server method. +- CHANGED: In order to activate the debugger, it's not enough to require 'ruby-debug'. + Debugger#start method must be called explicitly. +- Debugger used to evaluate anything you enter as long as it's not a command. Starting from + this version the 'eval' command must be used to evaluate an expression. + +0.1.5 (2006-07-13) +- Now the check for a breakpoint uses base filename of the source file. +- Removed compilation warnings when compiling with -Wall + +0.1.4 (2006-07-12) +- Remembers the previous command. Invoke it by typing a carriage return + at the command prompt. + +0.1.3 (2006-07-11) +- Conditional breakpoints +- Bugfixes + +0.1.2 (2006-07-16) +======================== + +- Initial release. diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..14748e3 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,5655 @@ +2009-03-29 03:00 Rocky Bernstein + + * ChangeLog, cli/ruby-debug/commands/breakpoints.rb, lib/ChangeLog, + test/data/annotate.right, test/data/breakpoints.right, + test/data/emacs_basic.right, test/data/info.right, + test/data/save.right: Canonicalize breakpoint locations a little + better. More work should be done and more work should be done on + the testing side too. + +2009-03-17 10:35 Rocky Bernstein + + * cli/ruby-debug/commands/irb.rb: Document irb additions old and + new + +2009-03-17 10:33 Rocky Bernstein + + * cli/ruby-debug/commands/irb.rb: irb "next" -> "n" since "next" is + a reserved word. + +2009-03-17 10:30 Rocky Bernstein + + * cli/ruby-debug/commands/irb.rb: Fix some irb -d breakage when set + autoirb is in effect + +2009-03-17 10:22 Rocky Bernstein + + * cli/ruby-debug/commands/irb.rb: Add "next" and "step" commands in + irb + +2009-03-17 02:05 Rocky Bernstein + + * cli/ruby-debug/commands/irb.rb, cli/ruby-debug/processor.rb, + configure.ac, test/data/ctrl.right, test/data/post-mortem.right, + test/test-ctrl.rb: configure.ac: in 0.10.4vc now. Add -d in irb + facilitate debugger testing via global $rdebug_state. Also set + $rdebug_state in debuggertesting is set. + "kill" is now allowed as a control command, this adjusts output. + and this changes + +2009-03-11 23:42 Rocky Bernstein + + * ChangeLog, doc/ruby-debug.texi, lib/ChangeLog: update texinfo for + catch + +2009-03-11 18:57 Rocky Bernstein + + * cli/ruby-debug/commands/catchpoint.rb, emacs/rdebug-core.el, + emacs/rdebug-track.el, emacs/test/test-regexp.el: Update "catch" + command help string. Reindent some emacs files to make tests + happy. + +2009-02-10 04:32 Rocky Bernstein + + * emacs/rdebug-core.el: Remove the annoying disappearing command + window when we there's an initial error in running the Ruby + program + +2009-01-23 20:51 Rocky Bernstein + + * doc/ruby-debug.texi: Show how to add a new command + +2009-01-23 17:20 Rocky Bernstein + + * cli/ruby-debug/commands/kill.rb, cli/ruby-debug/processor.rb: Add + a kill command + +2008-12-24 03:32 Rocky Bernstein + + * test/cli/commands/unit/regexp.rb: One more quit test. + +2008-12-24 03:21 Rocky Bernstein + + * cli/ruby-debug/commands/quit.rb, doc/ruby-debug.texi, + test/cli/commands/unit/regexp.rb, test/data/annotate.cmd, + test/data/annotate.right, test/data/break_bad.cmd, + test/data/break_bad.right, test/data/breakpoints.cmd, + test/data/breakpoints.right: Allow ! suffix on {q{,uit},exit} to + be the same as "unconditionally" #23299 + +2008-11-25 02:43 Rocky Bernstein + + * ChangeLog, cli/ruby-debug/commands/frame.rb, configure.ac, + doc/ruby-debug.texi, ext/ruby_debug.c, lib/ChangeLog, + test/data/frame.cmd, test/data/frame.right: Frame without a frame + number means frame 0, same as gdb. We are now in 0.10.4 territory + now. + +2008-11-17 07:34 Rocky Bernstein + + * CHANGES: Last commit before release. + +2008-11-16 00:14 Rocky Bernstein + + * ChangeLog, bin/rdebug, lib/ChangeLog: Add rdoc for rdebug script. + +2008-11-15 22:13 Rocky Bernstein + + * Rakefile, ext/ruby_debug.c: Go over RDOC documentation. + +2008-11-15 21:51 Rocky Bernstein + + * doc/ruby-debug.texi: Add one more reference to start with a block + +2008-11-15 21:23 Rocky Bernstein + + * doc/ruby-debug.texi: Remove hard-coded version number in example + output + +2008-11-15 02:21 Rocky Bernstein + + * ext/win32/.cvsignore: More administrivia + +2008-11-15 02:20 Rocky Bernstein + + * ext/win32: More administrivia + +2008-11-15 02:18 Rocky Bernstein + + * ., .cvsignore: More administrivia + +2008-11-14 19:39 Rocky Bernstein + + * ., .cvsignore: More administrivia + +2008-11-14 19:38 Rocky Bernstein + + * .cvsignore: Administrivia + +2008-11-14 19:37 Rocky Bernstein + + * ., README, Rakefile, doc, doc/.cvsignore: Go over documentation + for 0.10.3 release. rdoc creates files in doc/rdoc. + +2008-11-14 19:28 Rocky Bernstein + + * README, configure.ac, doc/ruby-debug.texi, + lib/ruby-debug-base.rb: Go over documentation and revise. + +2008-11-14 15:32 Rocky Bernstein + + * CHANGES, ChangeLog, cli/ruby-debug.rb, + cli/ruby-debug/commands/frame.rb, doc/ruby-debug.texi, + ext/ruby_debug.c, lib/ChangeLog, lib/ruby-debug-base.rb: Move + Debugger#debugger from base to cli. Revert code in ruby_debug.c + and block parameter in debugger. cf. -> Compare with. Document + Debugger.start better. + +2008-11-13 10:29 Rocky Bernstein + + * ChangeLog, ext/ruby_debug.c, lib/ChangeLog: Make + Debugger.start{block} work if Debugger.started? is false. Second + try. + +2008-11-11 15:33 Rocky Bernstein + + * ., Rakefile, test/cli/commands/catchpoint_test.rb, + test/cli/commands/unit, test/cli/commands/unit/regexp.rb: Start + unit test for command regular expressions. Much more willing out + to be done later.... + +2008-11-11 14:42 Rocky Bernstein + + * test/data/raise.right: More line number changes in tdebug + +2008-11-11 14:40 Rocky Bernstein + + * test/data/raise.right: tdebug lines have changed + +2008-11-11 02:07 Rocky Bernstein + + * ChangeLog, cli/ruby-debug/commands/frame.rb, lib/ChangeLog, + test/test-dollar-0.rb, test/test-frame.rb, test/trunc-call.rb: + Tweak truncated stack test since Ruby's caller doesn't seem to + include (tail?) recursive calls and we do. Get regression tests + working in light of recent changes. + +2008-11-10 08:47 Kent Sibilev + + * ext/ruby_debug.c: register debug_frame_t->arg_ary with GC + +2008-11-10 02:56 Kent Sibilev + + * bin/rdebug, ext/ruby_debug.c: Trying to fix "if $0 == __FILE__" + ruby's idiom. Apparently setting $0 to + a new value doesn't work correctly. (Ruby's bug?) + + $ cat t3.rb + p $0 + p File.expand_path $0 + $0 = File.expand_path $0 + p $0 + $ ruby t3.rb + "t3.rb" + "/Users/kent/Work/ruby-debug/trunk/t3.rb" + "/Users/ke" + +2008-11-10 01:50 Kent Sibilev + + * ext/ruby_debug.h: added declaration of + check_breakpoints_by_method method to remove compiler warning + +2008-11-10 01:48 Kent Sibilev + + * lib/ruby-debug-base.rb: a little bit more readable + +2008-11-10 01:43 Kent Sibilev + + * ext/ruby_debug.c: running at_exit hooks at the end of the + debug_load method in order to fix test cases a chance to run + +2008-11-10 01:41 Kent Sibilev + + * ext/ruby_debug.c: can't store a copy of the debug_context in the + stack like that, it doesn't play along with garbage collector. + +2008-11-10 01:39 Kent Sibilev + + * ext/ruby_debug.c: these two methods are unused + +2008-11-10 01:36 Kent Sibilev + + * ext/breakpoint.c: fix the compiler warning + +2008-11-10 01:35 Kent Sibilev + + * lib/ruby-debug-base.rb: Debugger.start must always call the + passed block + +2008-11-07 19:35 Rocky Bernstein + + * ChangeLog, cli/ruby-debug/commands/frame.rb, lib/ChangeLog: + Change truncated frame message. + +2008-11-07 10:39 Rocky Bernstein + + * ChangeLog, bin/rdebug, cli/ruby-debug.rb, + cli/ruby-debug/commands/frame.rb, lib/ChangeLog, test/tdebug.rb: + Add check to "where" to see if the call stack is truncated; task + #2354 + +2008-11-06 16:17 Rocky Bernstein + + * ChangeLog, Rakefile, lib/ChangeLog: #22698 Allow ruby-debug-base + 0.x.y.z be compatible with ruby-debug 0.x.y. + +2008-11-02 21:59 Rocky Bernstein + + * ChangeLog, ext/ruby_debug.c, lib/ChangeLog, + lib/ruby-debug-base.rb: Debugger.start with a block now stops + inside the block. Debugger.debugger with a block works like + Debugger.start with a block. + + The whole interface is hopelessly kludgy and needs to be redone. + +2008-10-27 15:29 Rocky Bernstein + + * ChangeLog, test/data/raise.right: tdebug.rb line numbers changed. + Update test numbers -- I think this is right. + +2008-10-26 14:54 Rocky Bernstein + + * ChangeLog, ext/extconf.rb, ext/ruby_debug.c, lib/ChangeLog: Doc + typo. Add comment to remind me how to turn off optimizationin + extconf.rb + +2008-10-25 18:10 Rocky Bernstein + + * cli/ruby-debug/interface.rb: Fix mismatched interface. + +2008-10-25 16:01 Rocky Bernstein + + * cli/ruby-debug/commands/breakpoints.rb, ext/ruby_debug.c, + lib/ChangeLog, test/data/annotate.right, + test/data/breakpoints.right, test/data/emacs_basic.right, + test/data/finish.right, test/test-finish.rb: Warn and add a + "confirmation" when setting a breakpoint on a file that is not + loaded. Regression tests no longer fail. + +2008-09-22 21:01 Rocky Bernstein + + * cli/ruby-debug.rb: Remove a $DEBUG warning + +2008-09-22 00:07 Rocky Bernstein + + * doc, doc/.cvsignore, lib/ruby-debug-base.rb, + test/data/pm-bug.cmd, test/data/pm-bug.right, + test/data/post-mortem.right, test/pm-bug.rb, test/test-pm.rb: + #22118 bug in showing variables post mortem. Patch thanks to + rubikitch. + Update pm.rb integration test. + +2008-09-21 23:09 Rocky Bernstein + + * CHANGES: In 0.10.3 territory now. + +2008-09-21 23:06 Rocky Bernstein + + * ext/ruby_debug.c, test/tdebug.rb: tdebug.rb: modify frozen string + taken from rdebug. Patch from Martin Krauskopf. + ruby_debug.c: in 0.10.3 now. + +2008-09-03 17:33 Rocky Bernstein + + * doc: Administrivia + +2008-09-03 17:29 Rocky Bernstein + + * ChangeLog, lib/ChangeLog, test/helper.rb: Show line numbers when + $DEBUG is set. Patch #21772 from Martin Krauskopf + +2008-08-28 05:43 Kent Sibilev + + * ext/ruby_debug.c: + +2008-08-28 05:41 Kent Sibilev + + * CHANGES: preparing version 0.10.2 + +2008-08-15 17:36 Kent Sibilev + + * cli/ruby-debug/commands/list.rb: Fixed an exception when calling + Kernel#debugger method from the eval code + +2008-07-10 09:47 Kent Sibilev + + * cli/ruby-debug/commands/continue.rb, cli/ruby-debug/processor.rb: + allow 'continue' command from post-mortem + + here is an example where it is needed: + + ... + Debugger.post_mortem do + method_that_raises_an_exception() + end + ... + + I want to be able to inspect the post_mortem context and then to + continue the program execution + +2008-07-10 08:55 Kent Sibilev + + * ext/ruby_debug.c: fixed segfault and finish command + +2008-07-09 19:43 Kent Sibilev + + * cli/ruby-debug/commands/breakpoints.rb: allow setting a + breakpoint on a file that is not yet loaded + +2008-07-09 19:29 Kent Sibilev + + * cli/ruby-debug/interface.rb: RemoteInterface should extend + Interface class + +2008-07-09 19:25 Kent Sibilev + + * bin/rdebug: $0 is frozen in Ruby 1.8.7 + +2008-07-09 00:43 Rocky Bernstein + + * cli/ruby-debug.rb, cli/ruby-debug/processor.rb: Some meager (and + not complete) support for a verbose mode on + source'ing a file. Some more print's turned to errmsg as + appropriate. + +2008-07-07 07:11 Rocky Bernstein + + * lib/ruby-debug-base.rb: Tracker [#20041] start erroneously moved + to Kernel - should be in + Debugger.start + +2008-07-03 16:03 Rocky Bernstein + + * doc/ruby-debug.texi: Document that backslash can escape debugger + command separation. + +2008-06-20 06:46 Rocky Bernstein + + * CHANGES, cli/ruby-debug/commands/trace.rb, + lib/ruby-debug-base.rb: trace.rb: add "trace var" + ruby-debug-base.rb: remove another undefined warning. + +2008-05-27 03:54 Rocky Bernstein + + * cli/ruby-debug/commands/save.rb, cli/ruby-debug/interface.rb, + test/data/save.cmd, test/data/save.right, test/test-save.rb: Add + save test. save.rb: use pretty-printed regexp. Interface, for now + add restart_file accessor like the others. The processor + interface + need revision though. + +2008-05-24 01:27 Rocky Bernstein + + * ChangeLog, doc/ruby-debug.texi, lib/ChangeLog: Remove dup lines. + +2008-05-23 14:57 Rocky Bernstein + + * cli/ruby-debug/commands/save.rb: Catchpoints have changed. Fix + bug in saving them. + +2008-05-23 01:04 Rocky Bernstein + + * cli/ruby-debug/commands/catchpoint.rb, + cli/ruby-debug/commands/info.rb, ext/breakpoint.c, + test/cli/commands/catchpoint_test.rb, test/data/catch.cmd, + test/data/catch.right, test/test-catch.rb: Lots of bogosity fixed + in catchpoint handling. Added "catch xxx off". + Confirm when deleting all catchpoints. Correct C rdoc. + #20237 + +2008-05-20 07:20 Rocky Bernstein + + * doc/rdebug-emacs.texi, doc/ruby-debug.texi: Use a straight quote + in the typewriter font. + +2008-05-17 22:11 Rocky Bernstein + + * cli/ruby-debug/commands/save.rb: Wording a little closer to gdb's + ;-) + +2008-05-17 11:35 Rocky Bernstein + + * doc/rdebug-emacs.texi, doc/ruby-debug.texi: e.g. -> e.g.@: + +2008-05-15 18:06 Rocky Bernstein + + * test, test/.cvsignore: Ignore config.private.yaml which folks may + use/customize to omit tests + +2008-05-15 17:52 Rocky Bernstein + + * Rakefile, test/cli, test/cli/commands, + test/cli/commands/catchpoint_test.rb: Regression test for recent + "catch nn off" error. Again from Martin Krauskopf + +2008-05-15 16:05 Rocky Bernstein + + * ChangeLog, cli/ruby-debug/commands/catchpoint.rb, lib/ChangeLog: + Handle "catch nnn off" Forgotten there during r656. + From mkrauskopf [#20156]. + +2008-05-12 03:21 Rocky Bernstein + + * cli/ruby-debug/commands/irb.rb: Small doc fix. + +2008-05-11 15:25 Rocky Bernstein + + * test/data/raise.right: tdebug.rb got a line shorter. + +2008-05-11 09:03 Rocky Bernstein + + * test/helper.rb, test/test-init.rb: Patch #19934 multi-interpreter + patch from Martin Krauskopf + +2008-05-11 08:38 Rocky Bernstein + + * bin/rdebug, ext/ruby_debug.c, test/data/output.right, + test/data/quit.right, test/tdebug.rb: Remove stop in debug_load + due to Debugger.start getting called twice. + The fix -- for now -- is to add another parameter to debug_load + to + indicate not to increment debug_count. We could also make that + the + default in debug_load as well, but debug_load might be useful in + other + situations and where control_threads are not relevant (which is + why we + need to call Debugger.start rather than let debug_load do it). + + Bug #19930 + +2008-05-05 18:05 Rocky Bernstein + + * ChangeLog, lib/ChangeLog, test/data/frame.right, + test/test-frame.rb: make test-frame installation independent. Bug + #19931 + +2008-05-01 23:16 Rocky Bernstein + + * doc/ruby-debug.texi: Remove a Texism. texinfo does not do or need + italic correction. + +2008-04-30 20:14 Rocky Bernstein + + * doc/ruby-debug.texi: Fix doc for binding_n(). + +2008-04-29 14:00 Rocky Bernstein + + * cli/ruby-debug/commands/method.rb, doc/ruby-debug.texi, + test/classes.rb, test/data/methodsig.right: Small doc and test + improvements on 'method signature' + +2008-04-29 13:37 Rocky Bernstein + + * ChangeLog, cli/ruby-debug/commands/breakpoints.rb, + cli/ruby-debug/commands/continue.rb, lib/ChangeLog, + test/data/frame.cmd, test/data/frame.right: Test line number in + "continue" command for validity. + +2008-04-29 09:11 Rocky Bernstein + + * cli/ruby-debug/commands/method.rb, + cli/ruby-debug/commands/set.rb, + cli/ruby-debug/commands/variables.rb, test/classes.rb, + test/data/method.cmd, test/data/method.right, + test/data/methodsig.cmd, test/data/methodsig.right, + test/data/setshow.right, test/test-method.rb: Add "method + signature" command to show a method's signature. + +2008-04-29 08:23 Rocky Bernstein + + * test/config.yaml: Forgot to add this on last commit. + +2008-04-28 16:42 Rocky Bernstein + + * cli/ruby-debug/commands/set.rb, test/data/setshow.cmd, + test/data/setshow.right: Catch errors in improper set callstyle + parameter. Bug #19792 + +2008-04-28 16:16 Rocky Bernstein + + * ChangeLog, lib/ChangeLog, test/helper.rb: From Martin Krauskopf + via patch #19779 + + Allow folks to configure Ruby used for CLI tests in the + test/config.yaml. The defaults are for native Ruby, so nothing + needs + to be done for ruby-debug. + + Developers of interfaces other than cli might override + config.yaml by + customized config.private.yaml which is ignored. So there will be + no + trash in e.g. 'svn st' output when developer customize the Ruby + to be + used. + + Handy for alternative interface implementations using + svn:externals. + +2008-04-27 08:28 Rocky Bernstein + + * emacs/rdebug-cmd.el, emacs/rdebug-track.el: Reduce spurious + read-only setting when short-key is turned + on/off in the command buffer. + +2008-04-25 02:54 Rocky Bernstein + + * CHANGES, emacs/rdebug-cmd.el, emacs/rdebug-gud.el, + emacs/rdebug-source.el, emacs/rdebug-track.el: Try to get + rdebug-track under control again. + Remove "<" in the command buffer as a local key setting. + Make more checkdoc friendly. + +2008-04-22 02:49 Rocky Bernstein + + * doc/ruby-debug.texi, lib/ruby-debug-base.rb: Experiment with + debugger(steps=0). Puts us in the debugger call, but this may be + the best we can do for now. See tracker + #19639. + +2008-04-20 21:38 Rocky Bernstein + + * doc/rdebug-emacs.texi, doc/ruby-debug.texi: rdebug-emacs.texi: + update nodes so makeinfo will work. + rdebug-texi: Note slight preference for ruby -rtracer over rdebug + --trace. + +2008-04-19 13:22 Rocky Bernstein + + * ext/ruby_debug.c, test/bp_loop_issue.rb, + test/data/break_loop_bug.cmd, test/data/break_loop_bug.right, + test/data/breakpoints.cmd, test/data/breakpoints.right, + test/data/emacs_basic.right, test/test-break-bad.rb, + test/test-emacs-basic.rb: Change test for whether we have moved + off a line or not for purposes + of stopping at a breakpoint on a line. The line events for which + there + are normally two stops are on NODE if's before the if and after + the + expression evaluation. Tracker #19594. + +2008-04-16 01:11 Rocky Bernstein + + * ChangeLog, cli/ruby-debug/commands/show.rb, + cli/ruby-debug/interface.rb, cli/ruby-debug/processor.rb, + ext/ruby_debug.c, lib/ChangeLog, test/data/setshow.cmd, + test/data/setshow.right: In 0.10.2 now. Some work to cope systems + without readline. More work is needed. + Add test of "set autoeval." Undefined command message more + closely like gdb's. + +2008-04-15 23:56 Rocky Bernstein + + * doc/ruby-debug.texi: Note that Debugger.start is currently broken + when used with a block. + +2008-04-11 22:24 Anders Lindgren + + * doc/rdebug-emacs.texi: Section on 'customize' added. + +2008-04-10 08:49 Rocky Bernstein + + * ChangeLog, cli/ruby-debug/command.rb, lib/ChangeLog: linecache is + required by ruby-debug-base not ruby-debug. Thanks Martin! + +2008-04-10 08:00 Rocky Bernstein + + * ChangeLog, Rakefile, lib/ChangeLog: Last change before 0.10.1 + release. + +2008-04-10 02:03 Rocky Bernstein + + * ChangeLog, doc/rdebug-emacs.texi, lib/ChangeLog: Cosmetic stuff: + spelling corrections. Update node structure so texinfo + doesn't complain. + +2008-04-09 21:22 Anders Lindgren + + * doc/rdebug-emacs.texi: New chapter for multi-window debugging. + Intro reworked. NOTE: Menu nodes not updated. + +2008-04-08 19:55 Anders Lindgren + + * emacs/rdebug-shortkey.el, emacs/test/test-shortkey.el: Logic in + rdebug-internal-short-key-mode reworked. Test case updated. + +2008-04-08 14:52 Rocky Bernstein + + * ChangeLog, Rakefile, lib/ChangeLog: autorequire is deprecated and + presumably no longer needed + http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/182827 + +2008-04-08 14:16 Rocky Bernstein + + * test/data/raise.right: Another test data line number change + +2008-04-08 14:12 Rocky Bernstein + + * test/tdebug.rb: tdebug.rb alignment with rdebug + +2008-04-08 14:02 Rocky Bernstein + + * test/data/linetracep.cmd: Forgot to add this for the linetrace+ + test. + +2008-04-08 14:01 Rocky Bernstein + + * emacs/rdebug-shortkey.el, emacs/test/test-shortkey.el: Attempt a + fix at shortkey internal. There be dragons here. Not sure what's + going on. + +2008-04-08 10:23 Rocky Bernstein + + * test/data/linetracep.right, test/test-trace.rb: Another linetrace + test. This time with linetrace+ set. + +2008-04-08 10:19 Rocky Bernstein + + * cli/ruby-debug/processor.rb, test/data/linetrace.cmd, + test/data/linetrace.right, test/test-trace.rb: processor.rb: + Silence possibly more warnings under $DEBUG + test/*: another linetrace test using the linetrace command. + +2008-04-08 03:17 Rocky Bernstein + + * test/data/output.right, test/data/quit.right: Test line numbers + changed. Sigh + +2008-04-08 03:14 Rocky Bernstein + + * test/tdebug.rb: Track rdebug. + +2008-04-08 03:10 Rocky Bernstein + + * test/test-trace.rb: Oops forget this test + +2008-04-08 03:09 Rocky Bernstein + + * bin/rdebug, cli/ruby-debug/processor.rb, test/data/trace.right, + test/tdebug.rb: Fix bug in --trace. Add regression test for that + as well. + Reduce (but alas not eliminate) extraneous line tracing. + +2008-04-07 00:36 Rocky Bernstein + + * CHANGES, ChangeLog, emacs/Makefile.am, emacs/rdebug-shortkey.el, + emacs/test/test-shortkey.el, lib/ChangeLog, + lib/ruby-debug-base.rb: ruby-debug-base.rb: document + Debugger.start parameters. + CHANGES: Revise what's happened + test-shortkey.el: A failing regression test because I think + rdebug-shortkey-mode + is not correct. + +2008-04-06 03:03 Rocky Bernstein + + * bin/rdebug, test/data/test-init-cygwin.right, test/test-init.rb: + Assigning $0 on cygwin seems weird. cygwin readline different too + +2008-04-06 02:13 Rocky Bernstein + + * test/data/test-init-osx.right, test/test-init.rb: read_command on + OSX seems to work differently. Punt for now. + +2008-04-04 19:22 Rocky Bernstein + + * cli/ruby-debug/commands/eval.rb: Sometimes remove_method isn't + defined. + +2008-04-03 19:13 Rocky Bernstein + + * doc/ruby-debug.texi: Small typos. + +2008-04-03 19:01 Rocky Bernstein + + * ChangeLog, doc/ruby-debug.texi, lib/ChangeLog, + lib/ruby-debug-base.rb, test/pm-base.rb: Allow setting + :post_mortem => true from Debugger.start. + +2008-04-03 14:22 Rocky Bernstein + + * Rakefile: We'll require linecache 0.4 or better. (Use SVN for + now. Will be released at same time as ruby-debug). + +2008-04-03 14:15 Rocky Bernstein + + * test/data/annotate.cmd, test/data/annotate.right, + test/data/post-mortem-osx.right, test/test-pm.rb: test-pm.rb, + post-mortem-osx.right: Allow for tmate command on OSX. + annotate.*: make sure 'set force on' doesn't happen. + +2008-04-03 12:06 Rocky Bernstein + + * cli/ruby-debug/commands/irb.rb: irb is no longer 'experimental'. + +2008-04-02 00:50 Rocky Bernstein + + * emacs/rdebug-annotate.el, emacs/rdebug-core.el, + emacs/rdebug-shortkey.el: Auto indent. + +2008-04-02 00:27 Rocky Bernstein + + * emacs/rdebug-core.el, emacs/rdebug-shortkey.el: Short-key mode is + turning itself on rather than off sometimes. More control over + trying to get rid of it when desired. + +2008-03-30 03:01 Rocky Bernstein + + * doc/ruby-debug.texi: Note that rdebug with test/unit might work. + +2008-03-28 13:53 Rocky Bernstein + + * ChangeLog, emacs/rdebug-annotate.el, lib/ChangeLog: Don't + unconditionally turn on short-key mode when annotations are on. + Use rdebug-short-key-mode setting to decide. + +2008-03-23 17:47 Rocky Bernstein + + * ChangeLog, Rakefile, cli/ruby-debug/commands/set.rb, + cli/ruby-debug/commands/settings.rb, lib/ChangeLog: set.rb -> + settings.rb since it's already one command per file, and + remove another :nodoc. + Rakefile: split long line + +2008-03-23 04:12 Rocky Bernstein + + * cli/ruby-debug/commands/show.rb, emacs/rdebug-core.el: + rdebug-core.el: allow rdebug-reset as an emasc command + show.rb: remove one more :nodoc + +2008-03-21 19:04 Rocky Bernstein + + * emacs/rdebug-breaks.el, emacs/rdebug-core.el, + emacs/rdebug-gud.el, emacs/test/test-cmd.el: Regularize names a + little bit. More work is needed though. + +2008-03-21 18:39 Rocky Bernstein + + * emacs/rdebug-breaks.el, emacs/rdebug-gud.el: Clear breakpoint + icons when quitting the debugger. + +2008-03-19 19:56 Rocky Bernstein + + * doc/ruby-debug.texi: more on --keep-frame-binding (for Martin) + +2008-03-19 15:07 Rocky Bernstein + + * cli/ruby-debug/commands/list.rb, test/data/list.cmd, + test/data/list.right, test/data/raise.right: Fix bug in "list -": + was scrolling back to negative lines. Had also been skipping + lines in forward list. + +2008-03-19 07:36 Rocky Bernstein + + * cli/ruby-debug/commands/info.rb: remove 'nodoc' (and doc) from + InfoCommand class + +2008-03-19 07:31 Rocky Bernstein + + * doc/rdebug-emacs.texi: Spelling correction. + +2008-03-19 00:44 Rocky Bernstein + + * doc/ruby-debug.texi: Some more spelling corrections. + +2008-03-19 00:27 Rocky Bernstein + + * doc/ruby-debug.texi: Spell-checking corrections. + +2008-03-18 19:47 Rocky Bernstein + + * CHANGES: Try to make more readible. + +2008-03-18 16:05 Rocky Bernstein + + * CHANGES, ChangeLog, cli/ruby-debug/commands/list.rb, + lib/ChangeLog, test/data/list.cmd, test/data/list.right, + test/test-finish.rb, test/test-list.rb: Fix bug in 'list' command + when wrapping off the end. + test-finish.rb: tolerate buggy in Ruby versions <= 1.8.7. + +2008-03-18 00:43 Rocky Bernstein + + * cli/ruby-debug/commands/list.rb, + cli/ruby-debug/commands/reload.rb: Split off reload into its own + file. + +2008-03-17 14:29 Rocky Bernstein + + * emacs/Makefile.am, emacs/rdebug-annotate.el, emacs/rdebug-cmd.el, + emacs/rdebug-fns.el, emacs/rdebug-locring.el, + emacs/rdebug-shortkey.el, emacs/rdebug-source.el, + emacs/rdebug-track.el, emacs/rdebug-vars.el, + emacs/test/test-fns.el: Regularize location ring function names. + +2008-03-17 04:03 Rocky Bernstein + + * cli/ruby-debug/command.rb, cli/ruby-debug/commands/stepping.rb, + test/data/stepping.right: stepping.rb: don't step if invalid + parameter + command.rb: remove dupliate defined warning msg + +2008-03-17 03:34 Rocky Bernstein + + * cli/ruby-debug/commands/stepping.rb: Small doc addition + +2008-03-17 03:17 Rocky Bernstein + + * cli/ruby-debug/commands/source.rb: Make source file-not-found and + error + +2008-03-17 03:07 Rocky Bernstein + + * cli/ruby-debug/commands/source.rb: tidy regexp + +2008-03-17 03:05 Rocky Bernstein + + * cli/ruby-debug/commands/script.rb, + cli/ruby-debug/commands/source.rb: Rename to match command name. + Add miniscule doc. + +2008-03-16 22:04 Rocky Bernstein + + * cli/ruby-debug/commands/continue.rb, + cli/ruby-debug/commands/frame.rb, doc/ruby-debug.texi: Doc + changes + +2008-03-16 16:38 Rocky Bernstein + + * doc/ruby-debug.texi, test/base/base.rb, test/base/catchpoint.rb, + test/base/load.rb: Add debug_load test. Document + Debugger::Context better. Small doc changes. + +2008-03-16 15:01 Rocky Bernstein + + * bin/rdebug: Typo. + +2008-03-16 07:39 Rocky Bernstein + + * cli/ruby-debug/commands/frame.rb, + cli/ruby-debug/commands/help.rb: Minor doc changes + +2008-03-16 06:50 Rocky Bernstein + + * test/data/ctrl.cmd, test/data/ctrl.right: Make sure width is set + explicitly so we don't have vagaries of the environment. + +2008-03-16 06:44 Rocky Bernstein + + * test/data/stepping.cmd, test/data/stepping.right: Possibly patch + change to upcoming 1.8.7. Punt for now. + +2008-03-16 04:03 Rocky Bernstein + + * CHANGES, cli/ruby-debug/commands/finish.rb, + cli/ruby-debug/commands/frame.rb, + cli/ruby-debug/commands/quit.rb, doc/ruby-debug.texi, + test/data/breakpoints.cmd, test/data/breakpoints.right, + test/data/finish.cmd, test/data/finish.right, + test/test-finish.rb: Change finish with no args to finish out of + the currently selected + frame and document that. + Add test for "finish" command. + ruby-debug.texi: Note 2nd-hook eval bug in "if" statements. + + ruby-debug.texi: + +2008-03-13 02:15 Rocky Bernstein + + * CHANGES, cli/ruby-debug/commands/finish.rb, + cli/ruby-debug/processor.rb, doc/ruby-debug.texi, + ext/ruby_debug.c, lib/ruby-debug-base.rb, rdbg.rb: INCOMPATIBLE + CHANGE: "finish" works like gdb - stop just before the + most recent method finishes. Will now accept a number which stops + that + many frames completed. (Note that return line numbers will be + funny, + the first line of the method until Ruby 1.8.7.) + +2008-03-11 03:53 Rocky Bernstein + + * test/base/base.rb, test/base/catchpoint.rb: Reduce unnecessary + dependencies and scope. + +2008-03-10 14:51 Rocky Bernstein + + * cli/ruby-debug/commands/catchpoint.rb, + cli/ruby-debug/commands/info.rb: "catch" is same as "info catch". + Document better "catch" command. + +2008-03-10 13:28 Rocky Bernstein + + * ChangeLog, lib/ChangeLog, test/data/raise.right: Dunno why we are + now one line number less. So be it (for now). + +2008-03-10 11:42 Rocky Bernstein + + * cli/ruby-debug/commands/continue.rb, + cli/ruby-debug/commands/finish.rb, + cli/ruby-debug/commands/stepping.rb, cli/ruby-debug/processor.rb: + Break out finish.rb and continue.rb from stepping.rb + +2008-03-09 23:30 Rocky Bernstein + + * CHANGES, ChangeLog, lib/ChangeLog, test/data/info.right: For now + we require the duplicate numbers on conditionals. + +2008-03-09 23:25 Rocky Bernstein + + * Rakefile: Need at least linecache 0.3 now. Probably 0.4 for + release. + +2008-03-07 04:26 Rocky Bernstein + + * Rakefile, bin/rdebug, doc/ruby-debug.texi, test/test-dollar-0.rb: + Use ~/.rdboptrc (rdbopt.ini on MS Windows) to change default + options. + +2008-03-03 04:14 Rocky Bernstein + + * cli/ruby-debug/commands/control.rb, + cli/ruby-debug/commands/quit.rb: Split off quit to it's own file + since it doesn't share code with the + reset of "control". Smaller is better and it helps deal with + meeting + in the middle for extending debug 1.9 code. + +2008-03-03 01:50 Rocky Bernstein + + * cli/ruby-debug/commands/stepping.rb, test/data/stepping.cmd, + test/data/stepping.right: Allow spaces at the end of step and + next. Test ";" between commands. + +2008-03-02 16:45 Rocky Bernstein + + * CHANGES, cli/ruby-debug/commands/breakpoints.rb, + cli/ruby-debug/commands/frame.rb, + cli/ruby-debug/commands/threads.rb, doc/ruby-debug.texi, + test/data/frame.cmd, test/data/frame.right: Add ability to + specify a thread number in a "frame" command. + +2008-03-02 13:47 Rocky Bernstein + + * doc/ruby-debug.texi: Add Instructions for building on Microsoft + Windows. + +2008-03-02 13:07 Rocky Bernstein + + * doc/ruby-debug.texi: Small typo. + +2008-03-02 04:20 Rocky Bernstein + + * cli/ruby-debug/commands/breakpoints.rb, lib/ruby-debug-base.rb, + test/base/base.rb, test/data/breakpoints.right, + test/data/emacs_basic.right: Better error message for an invalid + break command. + +2008-03-02 03:32 Rocky Bernstein + + * emacs/rdebug-cmd.el: Bug in wrapping to newest in + rdebug-older-location. + +2008-03-02 02:48 Rocky Bernstein + + * test/base/base.rb, test/base/binding.rb, test/gcd-dbg-nox.rb: + Small changes. Use unshift instead of << and Remove from $: after + done. + base.rb: Debugger.start -> Debugger.start_ + +2008-03-02 02:24 Rocky Bernstein + + * doc/Makefile.am, doc/rdebug-emacs.texi, doc/ruby-debug.texi: + Split emacs stuff into it's own document. Right now this makes + things + worse. Hopefully the benefit over time will outweigh this. + +2008-03-01 11:36 Rocky Bernstein + + * doc/ruby-debug.texi: Go over post-mortem section. Note the + weirdness concerning breakpoint + file names and how to scope out how to fix. + +2008-03-01 03:39 Rocky Bernstein + + * emacs/rdebug-cmd.el: Add message when wrapping source location + position. Not sure if this is right. We'll see. + +2008-02-29 15:24 Rocky Bernstein + + * emacs/rdebug-cmd.el, emacs/rdebug-frames.el: Fix bug in + rdebug-older-location when ring is empty - index -1. + Set rdebug-frames-current-frame-number variable in comint buffer + which is + needed at least for source location history processing. + +2008-02-29 10:41 Rocky Bernstein + + * emacs/rdebug-cmd.el: Remove gud-gdb-complete command for now. + +2008-02-29 04:34 Rocky Bernstein + + * emacs/rdebug-cmd.el, emacs/rdebug-fns.el, emacs/rdebug-frames.el, + emacs/rdebug-gud.el, emacs/rdebug-secondary.el, + emacs/rdebug-source.el: Wrap when ad top stack frame and trying + to go to a newer one. I think + the bindings for "<" and ">" were reversed. Some checkdoc + warnings addressed. + +2008-02-29 01:33 Rocky Bernstein + + * emacs/rdebug-track.el: Try to make more like rdebug. Get + M-up/M-down working. + Need to revisit this code and rdebug-core to understand, unify, + and simplify + more. + +2008-02-28 20:04 Rocky Bernstein + + * emacs/rdebug-core.el: For the bogus-buffer, use something less + computationally intensive. + +2008-02-28 05:06 Rocky Bernstein + + * ChangeLog, emacs/rdebug-core.el, emacs/rdebug-fns.el, + lib/ChangeLog, test/data/breakpoints.cmd, + test/data/breakpoints.right: breakpoints.{cmd,right}: test for an + invalid stopping line number + rdebug-fns.el: move generic split-string-and-unquote from + rdebug-core. + rdebug-core.el: Add rdebug-common-init to replace + gud-common-init. Is + simpler, and finds files better via debugger output/annotations. + Fix bug in rdebug-setup-windows: gud-find-file can return nil, + and + we still need to set buf. + +2008-02-27 04:04 Rocky Bernstein + + * lib/ruby-debug-base.rb: Slightly more robust handle_post_mortem. + +2008-02-26 17:31 Rocky Bernstein + + * ChangeLog, emacs/rdebug-cmd.el, emacs/rdebug-fns.el, + emacs/rdebug-source.el, emacs/rdebug-vars.el, + emacs/test/test-fns.el, lib/ChangeLog: Go over source location + positioning. 0 is now the oldest (first) position. Add M-S-down + and M-S-up for first and last. More tests needed in test-fns.el + and need to prompt on wrap around. + +2008-02-26 00:57 Rocky Bernstein + + * ChangeLog, cli/ruby-debug/commands/info.rb, lib/ChangeLog, + test/data/info.cmd, test/data/info.right: Fix bug in "info file + xxx breakpoints". + +2008-02-25 12:39 Rocky Bernstein + + * cli/ruby-debug/interface.rb: File.exists? -> File.exist? for Ruby + 1.9 + +2008-02-24 16:36 Rocky Bernstein + + * ChangeLog, bin/rdebug, lib/ChangeLog: rdebug; make more Ruby 1.9 + compatible. + +2008-02-24 16:14 Rocky Bernstein + + * ChangeLog, bin/rdebug, emacs/rdebug-regexp.el, lib/ChangeLog, + rdbg.rb: Minor changes. + rdbg.rb: don't need $DEBUG test any more + rdebug-regexp.el: go over with checkdoc + bin/rdebug: use PATH_SEPARATOR (for 'doze again) + +2008-02-24 04:51 Rocky Bernstein + + * ChangeLog, cli/ruby-debug/commands/info.rb, doc/ruby-debug.texi, + emacs/rdebug-fns.el, emacs/rdebug-layouts.el, + emacs/rdebug-secondary.el, emacs/rdebug-track.el, + emacs/test/test-fns.el, lib/ChangeLog, test/data/help.cmd, + test/data/help.right, test/test-help.rb: CLI: Add long help for + "info file". + + test/test-help.rb: Make test failures easier to fix and more like + the + other tests. + + emacs/test: finish testing all of the funcitons in rdebug-fns.el + + rdebug-layouts.el: Make checkdoc clean. + rdebug-track.el: don't need to rename shell buffer. Do it as an + option only. + rdebug-secondary.el: get rid of hoaky buffer finding for at least + gud-comint-buf. (Should probably do others as well) + + DOC: Note weird line stopping locations. Describe what "ctrl" in + prompt means. + +2008-02-23 21:55 Rocky Bernstein + + * emacs/rdebug-fns.el, emacs/test/test-fns.el: More stringent test + on rdebug-data-process-p. Add a unit test of this too. At least a + start at one. + +2008-02-22 12:57 Rocky Bernstein + + * emacs/rdebug-annotate.el: Make gud-last-frame buffer local to all + secondary buffers. + +2008-02-22 12:44 Rocky Bernstein + + * emacs/rdebug-frames.el: Set source frame arrow type (top or not) + in processing the stack frame + annotation. Even though there is another setting in the anotation + filter hook, we can't remove it in main annotation filter because + we + can't assume annotate=3. + +2008-02-22 09:31 Rocky Bernstein + + * cli/ruby-debug/commands/control.rb: Need to handle glob expansion + in program script on restart. + File.exists? -> File.exist? + +2008-02-22 06:50 Anders Lindgren + + * emacs/rdebug-annotate.el, emacs/rdebug-core.el, + emacs/rdebug-vars.el: Process status is now in color. Renamed + rdebug-mode-line-status to rdebug-inferior-status to be more like + gdb-ui. Moved some complexity from rdebug-mode-line-process to a + new function rdebug-display-inferior-status. + +2008-02-22 02:40 Rocky Bernstein + + * emacs/rdebug-core.el, emacs/rdebug-fns.el, emacs/rdebug-gud.el, + emacs/rdebug-track.el, emacs/test/test-cmd.el: Add some error + checking around gud-call - like dead or nonexistent process. + Set gud-comint-buffer for rdebug-track + rdebug-call -> rdebug-call-return. rdebug-call is just the call + part. + +2008-02-21 19:26 Rocky Bernstein + + * emacs/rdebug-annotate.el, emacs/rdebug-cmd.el, + emacs/rdebug-shortkey.el: A couple of (if .. (progn ...)) turned + into (when ...). + +2008-02-21 19:00 Rocky Bernstein + + * emacs/rdebug-annotate.el, emacs/rdebug-fns.el, + emacs/rdebug-track.el: More work on the simple rdebug-track mode + with respect to location + ring handling. A couple of out-and-out bugs removed. + +2008-02-21 16:27 Rocky Bernstein + + * emacs/rdebug-annotate.el, emacs/rdebug-cmd.el, + emacs/rdebug-fns.el, emacs/rdebug-gud.el, emacs/rdebug-track.el: + Bang on rdebug-track.el to get to work better. Basically added + gud-call-frame, + position tracking and more common initialization for key + bindings. + +2008-02-21 02:56 Rocky Bernstein + + * ChangeLog, emacs/Makefile.am, emacs/rdebug-annotate.el, + emacs/rdebug-error.el, emacs/rdebug-fns.el, + emacs/rdebug-frames.el, emacs/rdebug-vars.el, + emacs/test/test-error.el, emacs/test/test-fns.el, + emacs/test/test-indent.el, lib/ChangeLog: Fringe for frame buffer + the same as in source code. Move + miscellaneous small functions to a new file. Reduce duplication + of + "chomp" code. + +2008-02-20 17:16 Anders Lindgren + + * emacs/rdebug-annotate.el: Process status is now 'running', + 'stopped', 'exited', and 'crashed'. (Detecting the crash + situation is a hack, the prompt is checked if it contains + 'post-mortem'...) + +2008-02-20 07:09 Anders Lindgren + + * emacs/rdebug-annotate.el, emacs/rdebug-breaks.el, + emacs/rdebug-core.el, emacs/rdebug-error.el, + emacs/rdebug-frames.el, emacs/rdebug-help.el, + emacs/rdebug-info.el, emacs/rdebug-output.el, + emacs/rdebug-source.el, emacs/rdebug-varbuf.el, + emacs/rdebug-vars.el, emacs/rdebug-watch.el: Debugger status is + now displayed in the mode line of source and secondary buffers. + +2008-02-19 23:44 Rocky Bernstein + + * CHANGES, ChangeLog, bin/rdebug, emacs/rdebug-cmd.el, + lib/ChangeLog: rdebug-cmd.el: M-insert toggles shortkey mode in + the command buffer + rdebug: search for Ruby program if file is not found and no + SEPARATOR + chars in the filename + +2008-02-19 15:20 Rocky Bernstein + + * cli/ruby-debug/commands/settings.rb, + cli/ruby-debug/commands/show.rb, doc/ruby-debug.texi, + test/data/ctrl.right: Add "show post-mortem". Note "show port" + now requires 3 letters: "show por" + to distinguish it from "show post-mortem". + +2008-02-19 13:56 Rocky Bernstein + + * cli/ruby-debug/interface.rb, cli/ruby-debug/processor.rb, + emacs/rdebug-track.el: remove annotate=2. Emacs code can now + redirect output to command or to buffer. + rdebug-track.el + +2008-02-18 19:56 Rocky Bernstein + + * ChangeLog, emacs/rdebug-annotate.el, lib/ChangeLog: Frame + switching shouldn't be recorded in position history ring. + +2008-02-18 04:49 Rocky Bernstein + + * emacs/rdebug-annotate.el, emacs/rdebug-frames.el, + emacs/rdebug-shortkey.el, emacs/rdebug-vars.el: Make + gud-comint-buffer local in the source file. + Frame indicator is hollow except when it's the top frame. + +2008-02-17 23:51 Rocky Bernstein + + * doc/emacs-notes.txt: Note as to how some of the emacs code is + structured. + +2008-02-17 22:45 Anders Lindgren + + * emacs/test/test-annotate.el: Fixed broken case (rdebug-call-queue + is now a list of lists). + +2008-02-17 22:42 Anders Lindgren + + * emacs/rdebug-annotate.el: Exit messages now go to the echo area. + New command kind supported in rdebug-call-queue, :message. + +2008-02-17 22:00 Rocky Bernstein + + * emacs/Makefile.am, emacs/rdebug-annotate.el, emacs/rdebug-dbg.el, + emacs/rdebug-info.el, emacs/rdebug-shortkey.el, + emacs/rdebug-source.el, emacs/test/test-annotate.el, + emacs/test/test-filter.el, emacs/test/test-frames.el, + emacs/test/test-regexp.el: test-filter.el -> test-annotate.el + Reinstate the ";;; redebug-xxx.el ends here" and ;;; + rdebug-xxx.el --- at the + thop. + +2008-02-17 21:25 Rocky Bernstein + + * emacs/Makefile.am, emacs/rdebug-shortkey.el, + emacs/rdebug-source.el: Move short-key mode from source into + short-key. + Makefile.am: reduce redundancy a tad. + +2008-02-17 17:52 Rocky Bernstein + + * emacs/rdebug-annotate.el, emacs/rdebug-breaks.el, + emacs/rdebug-core.el, emacs/rdebug-frames.el, + emacs/rdebug-help.el, emacs/rdebug-info.el, + emacs/rdebug-output.el, emacs/rdebug-regexp.el, + emacs/rdebug-varbuf.el, emacs/rdebug-watch.el: Replace + rdebug--... with rdebug-. Run checkdoc and deal with some of + those errors. + +2008-02-17 14:56 Anders Lindgren + + * emacs/rdebug-annotate.el, emacs/rdebug-gud.el, + emacs/rdebug-info.el, emacs/rdebug-vars.el: The rdebug-call-queue + system reworked, each entry is now a list of the + command and options telling the system what it should do with the + output. Currently, :tooltip and :info are supported, but more can + easily be added (including support for lambda-expression, if + needed). + + The info buffer now only displays things if explicitly asked to + do so. + + Two proof-of-concept functions added, + rdebug-pretty-print-to-buffer + and rdebug-pretty-print-region-to-buffer. Note that the user + interface + might differ in the future (we don't want too many user-level + function.) + + The info buffer is no longer treated as accumulative, this + simplifies + the rdebug-cmd-XXX functions, but the user has to wait until the + command has terminated until the output is displayed in the info + buffer. + +2008-02-17 13:57 Rocky Bernstein + + * CHANGES, cli/ruby-debug/commands/info.rb, doc/ruby-debug.texi, + lib/ruby-debug-base.rb, test/data/post-mortem.right: Add + Debugger.last_exception. Show exception in post-mortem when "info + program" + is issued. Reorganize list of major changes better. + +2008-02-17 10:35 Rocky Bernstein + + * emacs/rdebug-breaks.el: Improve comment. + +2008-02-17 10:32 Rocky Bernstein + + * emacs/rdebug-breaks.el: Remove rdebug-test-test which doesn't + seem to be used. + +2008-02-17 03:57 Rocky Bernstein + + * emacs/rdebug-breaks.el, emacs/rdebug-core.el: Move some + breakpoint-related code from rdebug-core.el to rdebug-breaks.el + +2008-02-17 02:40 Rocky Bernstein + + * emacs/Makefile.am, emacs/rdebug-annotate.el, + emacs/rdebug-breaks.el, emacs/rdebug-cmd.el, + emacs/rdebug-core.el, emacs/rdebug-error.el, + emacs/rdebug-info.el, emacs/rdebug-shortkey.el, + emacs/rdebug-vars.el, emacs/test/test-error.el, + emacs/test/test-filter.el, emacs/test/test-regexp.el: Create + functions for showing temporary messages and error messages - + don't call show-tooltip() or message() directy. + + Break out annotations and shortkeys from rdebug-core. Break out + filter + test from regular-expression tests. Add chomp test. + +2008-02-16 21:03 Anders Lindgren + + * emacs/rdebug-core.el: The error buffer should work correctly + again (untested) + +2008-02-16 20:56 Anders Lindgren + + * emacs/rdebug-core.el, emacs/rdebug-info.el, + emacs/test/test-regexp.el: Moved handling of command output out + from gud-rdebug-marker-filter. It + is now handled by rdebug-cmd-XXX (which used to be located in + rdebug-info.el.) Tooltip handling is now more robust, e.g. it + works + when more than one annotation is received at once, or if the + annotation arrives in split packages. + + In case the external process echoes the command, it is stipped + away + before it is presented as a tooltip. + + Test of filter function reworked. New cases added to handle + command + output. All filter tests are now tested twice, once when the + entire + block is sent at once, one where the block is sent in character + by + character. + +2008-02-16 17:38 Rocky Bernstein + + * emacs/Makefile.am, emacs/rdebug-cmd.el, emacs/rdebug-core.el, + emacs/test/test-indent.el: Add routine to go to a particular + history location. Break out command buffer + things into its own file. + +2008-02-16 13:47 Rocky Bernstein + + * emacs/rdebug-core.el: Show ring number when moving positions. + +2008-02-16 04:18 Rocky Bernstein + + * emacs/rdebug-core.el, emacs/rdebug-source.el, + emacs/rdebug-vars.el, emacs/rdebug.el: Save stopping points and + give a way to move around in them. + +2008-02-13 21:47 Rocky Bernstein + + * ChangeLog, cli/ruby-debug/processor.rb, lib/ChangeLog: + processor.rb: spelled "post-mortem" incorrectly in prompt. + +2008-02-13 17:58 Rocky Bernstein + + * emacs/rdebug-core.el, emacs/rdebug-regexp.el, + emacs/rdebug-track.el: Use rdebug-input-prompt-regexp rather than + duplicate strings. Set comint-next/previous-prompt + +2008-02-13 17:32 Rocky Bernstein + + * ChangeLog, emacs/rdebug-core.el, lib/ChangeLog: Set up keys for + comint-next-prompt and comint-previous-prompt. + +2008-02-13 13:08 Rocky Bernstein + + * Rakefile: Newer rubygems depricates Gem::Platform::WIN32 + +2008-02-13 03:47 Rocky Bernstein + + * emacs/rdebug-core.el, emacs/rdebug-gud.el, emacs/rdebug-vars.el: + Add ability to show print output as a tooltip. This is more a + proof-of-concept than a finished product. + +2008-02-12 05:34 Anders Lindgren + + * emacs/rdebug-core.el: Better documentation for + rdebug-non-annotated-text-kind. + +2008-02-12 02:06 Rocky Bernstein + + * ChangeLog, cli/ruby-debug/commands/frame.rb, + cli/ruby-debug/commands/info.rb, doc/ruby-debug.texi, + lib/ChangeLog, test/data/info-thread.right, test/thread1.rb: Fix + bug in "info thread verbose" which wasn't showing full traceback. + +2008-02-11 02:29 Rocky Bernstein + + * cli/ruby-debug/commands/frame.rb, + cli/ruby-debug/commands/info.rb, + cli/ruby-debug/commands/threads.rb, doc/ruby-debug.texi, + test/data/ctrl.right, test/data/info-thread.cmd, + test/data/info-thread.right, test/data/info.right, + test/test-info-thread.rb: Add "info thread". Pound on "info + threads" to make it more like + pydb. In particular we can give stack traces for the threads. + Towards + addressing issue #12663. + +2008-02-10 20:46 Rocky Bernstein + + * emacs/rdebug-info.el, emacs/rdebug-source.el: Add key to get to + Info buffer. Add "pl" to list of print commands. + +2008-02-10 17:46 Rocky Bernstein + + * Rakefile, emacs/Makefile.am, emacs/rdebug-core.el: Makefile.am, + rdebug-core.el: require/add rdebug-info.el + Rakefile: some indentation + +2008-02-10 16:06 Anders Lindgren + + * emacs/rdebug-info.el: Got rid of warning. (Had to disabled it the + hard way since rdebug-info calls a function in rdebug-core, but + can't require it because that would lead to cyclic requires.) + +2008-02-10 16:01 Anders Lindgren + + * emacs/rdebug-breaks.el, emacs/rdebug-core.el, + emacs/rdebug-info.el, emacs/rdebug-layouts.el, + emacs/rdebug-output.el, emacs/rdebug-vars.el, + emacs/test/test-indent.el: New secondary window 'info', which + displays output of events and + certain commands. The non-annotated-text system reworked to + handle + this. This should be seen as a proof of concept that we can pick + up + the output of, say, "pp". The end result could very well differ + quite + a lot from what we have now. + + New variable 'rdebug-accumulative-buffer', true for buffers that + grow. + Currently "output" and "info". + +2008-02-10 01:39 Rocky Bernstein + + * emacs/rdebug-gud.el, emacs/rdebug-source.el, + emacs/rdebug-varbuf.el: Add more variations of print commands: + pl, ps, pp, and p. + +2008-02-09 22:20 Anders Lindgren + + * emacs/rdebug-core.el, emacs/rdebug-layouts.el, + emacs/rdebug-source.el, emacs/rdebug.el: * New window layout "no + shell". This is the "standard" layout with the + "watch" window instead of the "debugger shell" window. + + * Fixed a problem where the Watch window was not initialized + properly + until the first annotation arrived. + + * Fixed a problem where we created far too many buffers, e.g + *rdebug-stopping-test.rb* and *rdebug--test.rb*. + +2008-02-09 16:24 Anders Lindgren + + * emacs/rdebug-frames.el, emacs/rdebug-layouts.el, + emacs/test/test-indent.el: Indentation fixes, plus adding all + rdebug-xxx.el files to the list of files to check. + +2008-02-09 15:48 Rocky Bernstein + + * ChangeLog, lib/ChangeLog, test/data/break-bad.cmd, + test/data/break-bad.right, test/data/break_bad.cmd, + test/data/break_bad.right, test/data/emacs-basic.cmd, + test/data/emacs-basic.right, test/data/emacs_basic.cmd, + test/data/emacs_basic.right, test/helper.rb, + test/test-break-bad.rb, test/test-emacs-basic.rb: helper.rb + Failed attempt to DRY tests more. But save what we have + which may someday in the future be used to go further. Minus to + undercore in Data file names in preparation such time. (We'll use + the + filename as the test name). + + testing + +2008-02-09 11:55 Rocky Bernstein + + * ext/ruby_debug.c, test/data/post-mortem-next.cmd, + test/data/post-mortem-next.right, test/data/post-mortem.cmd, + test/data/post-mortem.right, test/test-pm.rb: Fix bug where we + entered debugger code if we "next" over code that + goes raises an uncaught exception. Needed to reset stepping + parameters. Added a routine to do so. + +2008-02-08 02:09 Rocky Bernstein + + * INSTALL.SVN: Add instructions for building on MS Windows. + +2008-02-06 18:15 Rocky Bernstein + + * emacs/rdebug-breaks.el, emacs/rdebug-core.el, + emacs/rdebug-gud.el, emacs/rdebug-source.el, + emacs/rdebug-varbuf.el: Add routines to print a marked expression + or a variable in the + variables buffer. Not perfect but it's a start in the right + direction. + Add key bindings for this and to print a region selected via the + mouse. + +2008-02-06 16:15 Rocky Bernstein + + * ChangeLog, emacs/Makefile.am, emacs/rdebug-gud.el, + emacs/test/test-gud.el, lib/ChangeLog: Add 'nowarn to + find-file-noselect and test that we don't get a warning. + +2008-02-05 16:30 Rocky Bernstein + + * cli/ruby-debug/interface.rb: Remove "* used as prefix argument" + warning. + +2008-02-05 07:52 Anders Lindgren + + * emacs/rdebug-layouts.el, emacs/rdebug-source.el: Added 'Separate + I/O buffer' to options menu. The window layouts now create an + output buffer only when separate io buffer is enabled. + +2008-02-05 01:41 Rocky Bernstein + + * ChangeLog, emacs/rdebug-track.el, emacs/rdebug.el, lib/ChangeLog, + test/data/setshow.cmd, test/data/setshow.right: rdebug.el: Add a + defgroup for rdebug so customization in Emacs 23 is possible. + Some other minor doc fixes. + setshow.* make sure we don't have an $Id line that we have to + check against. + +2008-02-04 21:50 Anders Lindgren + + * emacs/rdebug-core.el, emacs/rdebug.el: New variable + 'rdebug-use-separate-io-buffer' controls if output should go to + shell window or the output window. Contiuous output can now be + received from a running process. 'gud-rdebug-marker-filter' + totally reworked (again) -- introduced the concept of one-liners + and a new helper function. + +2008-02-03 20:26 Anders Lindgren + + * emacs/rdebug-core.el, emacs/rdebug-regexp.el: Annotation filter + reworked. comint-process-echoes is now set, so that the user + commands aren't printed twice. 'quit' now works correcty, and the + stack frame window shows the correct content when post-mortem is + entered. + +2008-02-03 15:23 Rocky Bernstein + + * ChangeLog, Rakefile, doc/ruby-debug.texi, lib/ChangeLog, + test/annotate.cmd, test/annotate.right, test/break-bad.cmd, + test/break-bad.right, test/breakpoints.cmd, + test/breakpoints.right, test/condition.cmd, test/condition.right, + test/ctrl.cmd, test/ctrl.right, test/data, + test/data/annotate.cmd, test/data/annotate.right, + test/data/break-bad.cmd, test/data/break-bad.right, + test/data/breakpoints.cmd, test/data/breakpoints.right, + test/data/condition.cmd, test/data/condition.right, + test/data/ctrl.cmd, test/data/ctrl.right, test/data/display.cmd, + test/data/display.right, test/data/dollar-0.right, + test/data/dollar-0a.right, test/data/dollar-0b.right, + test/data/edit.cmd, test/data/edit.right, + test/data/emacs-basic.cmd, test/data/emacs-basic.right, + test/data/enable.cmd, test/data/enable.right, + test/data/frame.cmd, test/data/frame.right, test/data/help.cmd, + test/data/help.right, test/data/history.right, + test/data/info-var-bug2.cmd, test/data/info-var-bug2.right, + test/data/info-var.cmd, test/data/info-var.right, + test/data/info.cmd, test/data/info.right, test/data/noquit.right, + test/data/output.cmd, test/data/output.right, + test/data/post-mortem.cmd, test/data/post-mortem.right, + test/data/quit.cmd, test/data/quit.right, test/data/raise.cmd, + test/data/raise.right, test/data/setshow.cmd, + test/data/setshow.right, test/data/source.cmd, + test/data/source.right, test/data/stepping.cmd, + test/data/stepping.right, test/data/test-init.right, + test/display.cmd, test/display.right, test/dollar-0.right, + test/dollar-0a.right, test/dollar-0b.right, test/edit.cmd, + test/edit.right, test/emacs-basic.cmd, test/emacs-basic.right, + test/enable.cmd, test/enable.right, test/frame.cmd, + test/frame.right, test/help.cmd, test/help.right, test/helper.rb, + test/history.right, test/info-var-bug2.cmd, + test/info-var-bug2.right, test/info-var.cmd, test/info-var.right, + test/info.cmd, test/info.right, test/noquit.right, + test/output.cmd, test/output.right, test/post-mortem.cmd, + test/post-mortem.right, test/quit.cmd, test/quit.right, + test/raise.cmd, test/raise.right, test/setshow.cmd, + test/setshow.right, test/source.cmd, test/source.right, + test/stepping.cmd, test/stepping.right, test/test-annotate.rb, + test/test-break-bad.rb, test/test-breakpoints.rb, + test/test-condition.rb, test/test-ctrl.rb, test/test-display.rb, + test/test-dollar-0.rb, test/test-edit.rb, + test/test-emacs-basic.rb, test/test-enable.rb, + test/test-frame.rb, test/test-help.rb, test/test-hist.rb, + test/test-info-var.rb, test/test-info.rb, test/test-init.rb, + test/test-init.right, test/test-output.rb, test/test-pm.rb, + test/test-quit.rb, test/test-raise.rb, test/test-setshow.rb, + test/test-source.rb, test/test-stepping.rb: Try to get testing a + little more organized, although more work should + be done: Create a data directory for comparison ("right") and + script + command ("cmd") files. Code is now more uniform (and should DRY'd + a + bit more). + +2008-02-03 12:34 Rocky Bernstein + + * doc/ruby-debug.texi: Remove Debugger.init. Expand Debugger.start, + Debugger.stop and Debugger.started? + +2008-02-03 04:17 Rocky Bernstein + + * cli/ruby-debug/commands/catchpoint.rb, + cli/ruby-debug/commands/info.rb, test/raise.cmd, + test/raise.right: Add some argument checking in setting + catchpoints. + Showing status on "info catch" is a little silly - we can't + recover from + an exception. + +2008-02-02 23:10 Rocky Bernstein + + * ChangeLog, cli/ruby-debug/command.rb, + cli/ruby-debug/commands/breakpoints.rb, + cli/ruby-debug/commands/catchpoint.rb, + cli/ruby-debug/commands/control.rb, + cli/ruby-debug/commands/edit.rb, cli/ruby-debug/commands/eval.rb, + cli/ruby-debug/commands/help.rb, cli/ruby-debug/commands/info.rb, + cli/ruby-debug/commands/list.rb, cli/ruby-debug/commands/save.rb, + cli/ruby-debug/commands/script.rb, + cli/ruby-debug/commands/settings.rb, + cli/ruby-debug/commands/show.rb, + cli/ruby-debug/commands/stepping.rb, + cli/ruby-debug/commands/threads.rb, cli/ruby-debug/processor.rb, + lib/ChangeLog, test/breakpoints.right, test/emacs-basic.right, + test/pm.rb, test/post-mortem.cmd, test/post-mortem.right, + test/test-emacs-basic.rb, test/test-init.rb, test/test-pm.rb, + test/test-quit.rb: Remove commands in post-mortem which are not + applicable, e.g."step", + "next", "continue"... + + "No breakpoints have been set" is now an error message when + trying to + set a breakpoint. + + Add post-mortem test. + + Debug.init no longer exists. + +2008-02-02 18:16 Anders Lindgren + + * emacs/rdebug-core.el: Changing window layout no longer clears the + secondary windows. + +2008-02-02 16:14 Anders Lindgren + + * emacs/rdebug-core.el, emacs/rdebug-source.el: All window layout + menu items are not collected in one place. Comment fixes. + +2008-02-02 09:27 Rocky Bernstein + + * CHANGES, ext/ruby_debug.c, lib/ruby-debug-base.rb, + test/gcd-dbg.rb: Remove Debugger.init and fold options parameter + into Debugger.start. + Old Debugger.start has been renamed Deebugger.start_ + +2008-02-01 03:09 Rocky Bernstein + + * CHANGES, Rakefile, bin/rdebug, + cli/ruby-debug/commands/catchpoint.rb, + cli/ruby-debug/commands/info.rb, cli/ruby-debug/processor.rb, + ext/breakpoint.c, ext/ruby_debug.c, ext/ruby_debug.h, + test/base/base.rb, test/base/catchpoint.rb, test/ctrl.right, + test/info.right: Allow multiple exceptions to be caught. + + INCOMPATIBLE CHANGE: varible Debugger.catchpoint a String was + turned + into Debugger.catchpoints, a Hash. Debugger.catchpoint= no longer + exists. Debugger.set_catchpoint was turned into + Debugger.add_catchpoint + + "info catch" added. + + INCOMPATIBLE CHANGE: variable Debugger.catchpoint is now + Debugger.catchpoints + which is a now hash rather than a String. Debugger.catchpoint= no + longer exists. + + A catchpoint ruby-debug-base test added. use unshift in requires. + + rdebug: --post-mortem now really catches uncaught exceptions and + brings you to post-mortem handling. + +2008-01-31 18:29 Anders Lindgren + + * emacs/rdebug-breaks.el, emacs/rdebug-frames.el: In the frames and + breakpoint windows, the left mouse button simply sets the point. + Double-clicking selects the item. The second and third mouse + button also selects. + +2008-01-31 16:30 Rocky Bernstein + + * ChangeLog, ext/ruby_debug.c, lib/ChangeLog: Leave ruby_debug.c + this way for now. + +2008-01-31 16:24 Rocky Bernstein + + * ChangeLog, cli/ruby-debug/processor.rb, ext/ruby_debug.c, + lib/ChangeLog, test/raise.right, test/tdebug.rb: ruby_debug.c: + more adventures in exception handling + processor.rb: Removal of crash when annotate is on. Need to fix + the source of the + problem though. + +2008-01-31 15:16 Rocky Bernstein + + * bin/rdebug, lib/ruby-debug-base.rb, test/output.right, + test/quit.right, test/raise.rb, test/raise.right, test/tdebug.rb: + Handle post-mortem and exception traceback reporting in + ruby-debug + +2008-01-31 03:01 Rocky Bernstein + + * bin/rdebug, ext/ruby_debug.c, test/helper.rb, test/quit.right, + test/tdebug.rb, test/test-quit.rb, test/test-raise.rb: Have + Debug.load recover from uncaught error raised in a debugged + program. + Go over regression tests. + +2008-01-30 21:33 Anders Lindgren + + * test/raise.cmd, test/raise.rb, test/raise.right, + test/test-raise.rb: Test case ensuring that an error in the user + code doesn't cause the debugger to single step it's own code. + (This is currently broken.) + +2008-01-30 17:13 Rocky Bernstein + + * cli/ruby-debug/commands/info.rb: Add broken "info file" + information. + +2008-01-30 17:01 Rocky Bernstein + + * ChangeLog, cli/ruby-debug/command.rb, + cli/ruby-debug/commands/enable.rb, + cli/ruby-debug/commands/info.rb, cli/ruby-debug/commands/show.rb, + lib/ChangeLog, test/condition.right: Add Command.find() to find a + subcommand name. + condition.right: correct for breakpoint hit counts. + +2008-01-30 11:33 Rocky Bernstein + + * emacs/rdebug-core.el, emacs/rdebug-output.el, + emacs/rdebug-track.el: Add keybindings in shell, output and + command buffers for going to a + traceback line or a $! traceback line. + + rdebug-common-initialization -> rdebug-command-initialization and + fix + up docstring. + + rdebug-core.el: Bug in handling --emacs introduced when a + parameter was added + rdebug-track.el: start with annotate 2. + +2008-01-30 01:43 Rocky Bernstein + + * ChangeLog, cli/ruby-debug/commands/info.rb, lib/ChangeLog, + test/breakpoints.right, test/emacs-basic.right: Add number of + times a breakpoint is hit like gdb does. + +2008-01-29 22:37 Rocky Bernstein + + * ChangeLog, cli/ruby-debug/commands/info.rb, lib/ChangeLog: + Columnize breakpoint output. + +2008-01-29 22:19 Rocky Bernstein + + * cli/ruby-debug/interface.rb, emacs/rdebug-frames.el, + test/test-ctrl.rb: test-ctrl.rb: try to make it influenced less + by environment. + rdebug-frames.el remove unused local variable. + +2008-01-29 21:13 Anders Lindgren + + * cli/ruby-debug/commands/frame.rb, emacs/rdebug-frames.el, + emacs/rdebug-secondary.el: * Fixed a problem where the source + buffer opened in the wrong window. + Turned out that the Stack Frame buffer setup function tried to + display the current frame itself, instead of letting the normal + source annotations handle this. + + * Fixed a problem with an annotation turning up in the debugger + shell + buffer. The 'frame' command emitted a source annotation without + the + "source" part. + + * In the stack frame window, when selecting a frame to display, + the + point is now placed at the beginning of the line of the active + frame. + + * Internal restructuring of the pick source window parts. + +2008-01-29 19:58 Rocky Bernstein + + * emacs/rdebug-frames.el: In the frame secondary buffer, put point + somewhere on the line with + the active frame. (It had been at the end of the buffer.) + +2008-01-29 19:16 Rocky Bernstein + + * emacs/rdebug-layouts.el: So for a layout with one less window and + the command buffer on the bottom. + +2008-01-29 11:20 Rocky Bernstein + + * CHANGES, ChangeLog, bin/rdebug, cli/ruby-debug/interface.rb, + cli/ruby-debug/processor.rb, doc/ruby-debug.texi, + emacs/rdebug-core.el, emacs/rdebug-layouts.el, + emacs/rdebug-source.el, emacs/rdebug.el, emacs/test/test-core.el, + lib/ChangeLog: More annotate=2 fixes. + +2008-01-29 05:03 Anders Lindgren + + * emacs/rdebug-core.el: In Emacs, the current directory of the + debugger shell process is now the directory in which it was + started. + +2008-01-28 21:11 Rocky Bernstein + + * test/history.right, test/test-hist.rb: Disable for now. + +2008-01-28 16:18 Rocky Bernstein + + * test/helper.rb, test/test-hist.rb: Some more work on test-hist. + Not working yet completely though. + +2008-01-28 15:59 Rocky Bernstein + + * ChangeLog, cli/ruby-debug/commands/info.rb, lib/ChangeLog, + test/helper.rb, test/test-dollar-0.rb, test/test-hist.rb, + test/test-output.rb: Add info file breakpoints to show lines + which we can set a breakpoint on. + Revise so we chdir into SRC_DIR. + test-hist.rb is broken - will fix later. + +2008-01-28 15:50 Rocky Bernstein + + * test/history.right: Comparison file for test-hist.rb + +2008-01-28 03:16 Rocky Bernstein + + * doc/Makefile.am: Don't remove Unix manual page. + +2008-01-28 03:15 Rocky Bernstein + + * cli/ruby-debug/commands/show.rb, doc/ruby-debug.texi: Make show + commands a little more like gdb. Document it too. + +2008-01-28 02:24 Rocky Bernstein + + * cli/ruby-debug/commands/show.rb, cli/ruby-debug/interface.rb, + test/ctrl.right, test/test-enable.rb, test/test-hist.rb: + interface.rb: Command history not saved between local rdebug + sessions. Patch from Martin Krauskopf #17491. + show.rb: add "show commands" so we can see the command history. + test/* Add a history regression test. + +2008-01-26 17:12 Anders Lindgren + + * emacs/rdebug-frames.el: debug--setup-frame-buffer rewritten from + scratch, it's now a lot simpler since it no longer has to handle + coloring. + +2008-01-26 17:10 Anders Lindgren + + * emacs/rdebug-layouts.el: comment fix. + +2008-01-26 16:33 Anders Lindgren + + * emacs/rdebug-breaks.el, emacs/rdebug-frames.el: Coloring added to + the Stack frames window + +2008-01-26 01:45 Rocky Bernstein + + * test/test-annotate.rb, test/test-enable.rb, test/test-init.rb, + test/test-init.right: Add test of new Debugger.init + +2008-01-25 21:02 Rocky Bernstein + + * doc/ruby-debug.texi: Document info subcommands and Debugger.init. + Start Class, Module, + method index. Order of index changed slightly. + +2008-01-25 12:11 Rocky Bernstein + + * ChangeLog, cli/ruby-debug/commands/control.rb, + cli/ruby-debug/commands/settings.rb, + cli/ruby-debug/commands/show.rb, lib/ChangeLog, + lib/ruby-debug-base.rb, test/gcd-dbg-nox.rb, test/gcd-dbg.rb: Add + Debugger.init which intializes things that rdebug does. This + allows a restart even though rdebug wasn't called initially. + +2008-01-23 02:53 Rocky Bernstein + + * cli/ruby-debug/command.rb, cli/ruby-debug/commands/enable.rb, + cli/ruby-debug/commands/help.rb, cli/ruby-debug/commands/info.rb, + cli/ruby-debug/commands/settings.rb, + cli/ruby-debug/commands/show.rb, test/breakpoints.cmd, + test/breakpoints.right, test/enable.cmd, test/enable.right, + test/help.cmd, test/help.right, test/test-enable.rb, + test/test-help.rb: Add subcommand/long help for enable, disable, + set, and show. Put Subcommand structure in Command. More work is + needed to reduce redundancy. + +2008-01-22 23:15 Rocky Bernstein + + * ChangeLog, cli/ruby-debug/commands/help.rb, + cli/ruby-debug/commands/info.rb, lib/ChangeLog, + test/annotate.cmd, test/annotate.right, test/ctrl.right, + test/info.cmd, test/info.right, test/test-edit.rb, + test/test-source.rb: Allow "help info xxx". Add ability for long + help on "info" command. + Add "info break xx". + + test: remove test/unit class name conflicts. All the tests we + wrote + now get run. + +2008-01-22 18:48 Rocky Bernstein + + * emacs/rdebug-secondary.el: A small comment spelling mistake. + +2008-01-20 22:01 Rocky Bernstein + + * cli/ruby-debug/commands/breakpoints.rb, test/break-bad.cmd, + test/break-bad.right, test/breakpoints.cmd, + test/breakpoints.right, test/rdebug-save.1, test/source.right, + test/test-break-bad.rb: We now only allow breakpoints on stopping + lines. We get this via + linecache which ultimately gets it from ParseTree. + +2008-01-19 19:28 Rocky Bernstein + + * ChangeLog, Rakefile, lib/ChangeLog, test/base, test/base/base.rb, + test/base/binding.rb, test/test-ruby-debug-base.rb: Move + ruby-debug-base tests to base directory. Add a binding_n + regression test. + +2008-01-17 22:29 Rocky Bernstein + + * cli/ruby-debug/commands/info.rb: lines -> size. + +2008-01-17 20:28 Rocky Bernstein + + * cli/ruby-debug/commands/info.rb, test/ctrl.right, + test/info.right: Add "info file" in addition to "info files" Use + some features in linecache 0.3 + which are in SVN only. Give SHA1, number of lines and timestamp + on a specific + file. + +2008-01-17 06:58 Rocky Bernstein + + * test/ctrl.right: info file -> info files + +2008-01-17 03:33 Rocky Bernstein + + * cli/ruby-debug/commands/info.rb, test/info.right: "info file" -> + "info files" as per gdb. + +2008-01-16 18:42 Rocky Bernstein + + * ChangeLog, cli/ruby-debug/commands/breakpoints.rb, lib/ChangeLog, + test/annotate.right, test/breakpoints.right, + test/condition.right, test/display.right, test/emacs-basic.right, + test/info-var.right: Need to present source filename (__FILE__) + as Ruby and therefore breakpoint + sees it. + + +2008-01-16 12:30 Rocky Bernstein + + * emacs/rdebug-track.el: Slightly better rdebug-track-attach + initialization. Still has problems, but it's better. + +2008-01-16 02:19 Rocky Bernstein + + * ChangeLog, Rakefile, cli/ruby-debug/command.rb, + cli/ruby-debug/commands/breakpoints.rb, + cli/ruby-debug/commands/list.rb, lib/ChangeLog, + lib/ruby-debug-base.rb: Line caching moved to an external gem, + linecache. We now require + version 0.2 of that or greater. + +2008-01-16 01:14 Rocky Bernstein + + * emacs/rdebug-source.el: Get insert working again. + +2008-01-16 01:13 Rocky Bernstein + + * emacs/rdebug-secondary.el: Typo. + +2008-01-16 00:23 Rocky Bernstein + + * emacs/rdebug-core.el: Chomp error before message'ing. + +2008-01-15 23:41 Anders Lindgren + + * emacs/rdebug-core.el: When starting 'rdebug' the first time, the + file name of the current buffer is suggested as script name. + +2008-01-15 23:34 Anders Lindgren + + * emacs/rdebug-core.el, emacs/rdebug-source.el: Local short key + mode renamed to internal short key mode. Original read-only + status saved in local variable. Minor mode text 'ShortKey' added. + +2008-01-15 23:04 Anders Lindgren + + * emacs/rdebug-breaks.el, emacs/rdebug-core.el, + emacs/rdebug-dbg.el, emacs/rdebug-error.el, + emacs/rdebug-frames.el, emacs/rdebug-gud.el, + emacs/rdebug-help.el, emacs/rdebug-layouts.el, + emacs/rdebug-output.el, emacs/rdebug-regexp.el, + emacs/rdebug-secondary.el, emacs/rdebug-source.el, + emacs/rdebug-track.el, emacs/rdebug-varbuf.el, + emacs/rdebug-vars.el, emacs/rdebug-watch.el, emacs/rdebug.el: + Comment fixes. + +2008-01-15 22:48 Anders Lindgren + + * emacs/rdebug-breaks.el: Breakpoints font-lock rules even more + generous, now all characters are matched. + +2008-01-15 22:44 Anders Lindgren + + * emacs/rdebug-core.el: rdebug-get-script-name now skips ruby + options, if present + +2008-01-15 07:56 Rocky Bernstein + + * emacs/rdebug-breaks.el: File names can have a - in them. + +2008-01-15 06:51 Anders Lindgren + + * emacs/rdebug-breaks.el, emacs/rdebug-core.el: The source + breakpoint toggle and toggle enabled commands, when issued in the + breakpoints window, do the right thing. In other non-file buffers + they do nothing. + +2008-01-15 04:57 Rocky Bernstein + + * emacs/test/test-core.el: indentation. + +2008-01-15 04:56 Rocky Bernstein + + * emacs/test/test-core.el: More tests. + +2008-01-14 22:22 Anders Lindgren + + * emacs/rdebug-breaks.el: Replaced code coloring breakpoint buffer + with font-lock rules. Now coloring of breakpoints of kind + 'Type:function' works. + +2008-01-14 07:00 Anders Lindgren + + * emacs/rdebug-core.el, emacs/test/test-core.el: + rdebug-get-script-name now handles something else than 'rdebug' + as command name. Rewritten to get rid of unmaintanable recursive + function. + +2008-01-14 06:58 Anders Lindgren + + * emacs/test/test-cmd.el: Breakpoints are now parsed and cached + when a new annotation arrives. + +2008-01-14 06:57 Anders Lindgren + + * emacs/rdebug-breaks.el: Breakpoints are now parsed and cached + when a new annotation arrives. + +2008-01-14 01:31 Rocky Bernstein + + * ChangeLog, cli/ruby-debug/commands/control.rb, + emacs/rdebug-core.el, emacs/rdebug-track.el, lib/ChangeLog: Make + rdebug-track work better in the face of prompt and error + annotations. + control.rb: need another test when rdebug not called initially. + +2008-01-13 22:03 Rocky Bernstein + + * emacs/rdebug-core.el, emacs/rdebug-layouts.el: A couple more + stack -> frame spots missed + +2008-01-13 21:51 Rocky Bernstein + + * ChangeLog, cli/ruby-debug/commands/breakpoints.rb, + emacs/rdebug-core.el, emacs/rdebug-frames.el, + emacs/rdebug-source.el, ext/breakpoint.c, lib/ChangeLog: Some + stack -> frame renaming + ext/breakpoint.c: put methods in alpha order (to help with + reference man) + breakpoints.rb: one print -> errmsg + +2008-01-13 21:19 Rocky Bernstein + + * doc/ruby-debug.texi: Add info about the 3 kinds of interfaces and + give some + Debugger::Breakpoint methods. + +2008-01-13 20:32 Rocky Bernstein + + * test/test-output.rb: Seems we don't get a core dump any more. + +2008-01-13 18:13 Rocky Bernstein + + * ChangeLog, cli/ruby-debug/commands/condition.rb, + cli/ruby-debug/commands/control.rb, + cli/ruby-debug/commands/display.rb, + cli/ruby-debug/commands/edit.rb, + cli/ruby-debug/commands/frame.rb, + cli/ruby-debug/commands/help.rb, cli/ruby-debug/commands/info.rb, + cli/ruby-debug/interface.rb, cli/ruby-debug/processor.rb, + emacs/Makefile.am, emacs/rdebug-core.el, emacs/rdebug-error.el, + emacs/rdebug-output.el, emacs/rdebug-source.el, lib/ChangeLog, + test/annotate.cmd, test/annotate.right, test/breakpoints.right, + test/condition.right, test/edit.right, test/emacs-basic.right, + test/frame.right: Create errmsg routine for error output, start + tagging error messages + as errors. Under annotate 3, output errors similar to gdb + --annotate + does (although still simplified). Have Emacs pick up debugger + error + annotations. + +2008-01-13 04:05 Rocky Bernstein + + * ChangeLog, cli/ruby-debug/command.rb, + cli/ruby-debug/commands/breakpoints.rb, + cli/ruby-debug/commands/enable.rb, cli/ruby-debug/helper.rb, + cli/ruby-debug/interface.rb, cli/ruby-debug/processor.rb, + lib/ChangeLog, test/condition.cmd, test/condition.right: Check + validity of expressions in breakpoint conditions and don't allow + enabling a syntactically invalid expression. + + Start noting messages which are errors via an errmsg routine. + +2008-01-12 13:35 Rocky Bernstein + + * CHANGES: Typo. + +2008-01-12 13:22 Rocky Bernstein + + * emacs/rdebug-core.el: Typo. + +2008-01-12 12:45 Rocky Bernstein + + * emacs/rdebug-breaks.el, emacs/rdebug-frames.el: breaks.el + gdb-put-breakpoint-icon seems to want to string for a breakpoint + number and our entries are + numbers. + frames.el: wasn't resetting search string to first line pattern + (for subsequent testing of + whether this is the current frame) after processing split entry + with file/line position. Break out + a common routine rdebug-stack-buffer-field which also seems to + simplify it. + +2008-01-12 10:56 Anders Lindgren + + * emacs/rdebug-breaks.el: Breakpoint icons are now displayed in the + margin. This is a simple implementation that used gdb-ui to do + the actual display. + +2008-01-11 18:04 Rocky Bernstein + + * emacs/Makefile.am, emacs/rdebug-frames.el, + emacs/rdebug-regexp.el, emacs/test/test-frames.el: Process frames + which are split across two lines. DRY a little + and add the first frame test. + +2008-01-11 15:08 Rocky Bernstein + + * emacs/Makefile.am: ELC typo. + +2008-01-11 14:01 Rocky Bernstein + + * emacs/Makefile.am: Don't give an error on "make test" if emacs is + not around. + +2008-01-11 10:26 Rocky Bernstein + + * ChangeLog, bin/rdebug, doc/ruby-debug.texi, lib/ChangeLog: + Document that ruby-debug resets $0. Align program options in ref + manual and --help. Alphabetize better. + +2008-01-11 10:10 Rocky Bernstein + + * CHANGES, bin/rdebug, test/output.right, test/quit.right, + test/tdebug.rb, test/test-quit.rb: rdebug: do syntax checking + when running as server as well as local interface. --no-quit + intercepts Syntax Errors now + (which shouldn't happen and means there's another bug in there to + fix; but robustness is good.) + Bring tdebug.rb more in line iwth rdebug until we can get rid of + it altogether. Note some of the current weaknesses. + +2008-01-10 22:56 Rocky Bernstein + + * ChangeLog, bin/rdebug, lib/ChangeLog, test/dollar-0.rb, + test/dollar-0.right, test/dollar-0a.right, test/dollar-0b.right, + test/test-dollar-0.rb: More correct $0 fix. Deal with the case ./ + is automatically added. + However this might not be right in all cases. + +2008-01-10 22:25 Rocky Bernstein + + * ChangeLog, emacs/rdebug-core.el, emacs/test/test-core.el, + lib/ChangeLog: Was gobbling arg in processing --emacs. Add test. + +2008-01-10 21:57 Rocky Bernstein + + * bin/rdebug, emacs/rdebug-core.el, test/dollar-0.rb, + test/dollar-0.right, test/helper.rb, test/test-dollar-0.rb: Fix + for "if $0 == __FILE__" idiom. Bug #16038 + rdebug-core.el add '--'; -emacs -> --emacs + rdebug: add subroutines for calling debugger and processing + options. + +2008-01-10 10:34 Rocky Bernstein + + * CHANGES, ChangeLog, cli/ruby-debug/commands/condition.rb, + cli/ruby-debug/commands/enable.rb, cli/ruby-debug/processor.rb, + doc/ruby-debug.texi, emacs/Makefile.am, emacs/rdebug-breaks.el, + emacs/rdebug-regexp.el, emacs/test/test-regexp.el, + ext/breakpoint.c, lib/ChangeLog, test/condition.cmd, + test/condition.right, test/test-breakpoints.rb, + test/test-condition.rb: Add condition command. + +2008-01-10 09:07 Rocky Bernstein + + * emacs/rdebug-frames.el, emacs/rdebug-regexp.el, + emacs/test/test-cmd.el: rdebug-frames.el: fix redisplay of source + when frames change by running rdebug-display-line in creating + frame buffer. require things we need to require to eval this + file. set-local-variables. + + rdebug-regexp.el: add constants for file and line stack positions + in regexp. + + test-cmd.el: rdebug-cmd -> rdebug-gud. + +2008-01-09 23:00 Rocky Bernstein + + * emacs/rdebug-core.el, emacs/rdebug-gud.el, + emacs/test/test-indent.el: Some more GUD things moved to gud-el. + +2008-01-09 22:56 Rocky Bernstein + + * emacs/Makefile.am, emacs/rdebug-breaks.el, emacs/rdebug-cmd.el, + emacs/rdebug-core.el, emacs/rdebug-gud.el, + emacs/rdebug-regexp.el: rdebug-cmd.el -> rdebug-gud.el + Move gud things from rdebug-core.el to rdebug-gud.el + +2008-01-09 22:37 Rocky Bernstein + + * emacs/rdebug-core.el, emacs/rdebug-source.el: Allow [insert] to + turn on/off short-key-mode. + +2008-01-09 19:10 Rocky Bernstein + + * ChangeLog, Rakefile, emacs/rdebug-dbg.el, lib/ChangeLog: + Rakefile: rdebug.rb -> rdbg.el + rdebug-dbg.el: Add $Id$ + +2008-01-09 19:03 Rocky Bernstein + + * ChangeLog, emacs/Makefile.am, emacs/rdebug-breaks.el, + emacs/rdebug-cmd.el, emacs/rdebug-core.el, emacs/rdebug-dbg.el, + emacs/rdebug-frames.el, emacs/rdebug-help.el, + emacs/rdebug-output.el, emacs/rdebug-secondary.el, + emacs/rdebug-track.el, emacs/rdebug-varbuf.el, + emacs/rdebug-watch.el, emacs/test/test-indent.el, + emacs/test/test-regexp.el, lib/ChangeLog: Break out secondary + buffer into their own file, and also internal + debug code and general secondary commands. Secondary buffer code + removed from rdebug-cmd and moved into the appropriate file. + + rdebug-edit-variables-value is not defined so comment out for + now. + +2008-01-08 16:11 Rocky Bernstein + + * emacs/rdebug-core.el: Change indentation. + +2008-01-08 16:04 Rocky Bernstein + + * ChangeLog, lib/ChangeLog, rdbg.rb: Restore $: to the value it was + before rdebug call. + +2008-01-08 12:04 Rocky Bernstein + + * emacs/Makefile.am, emacs/rdebug-core.el, emacs/rdebug-layouts.el, + emacs/rdebug-vars.el: rdebug-layouts.rb, Makefile.am: window + layouts - split off from rdebug-core.el + Add some output commands: command to add a marker line, clear the + output window, and allow undo. + +2008-01-08 06:30 Anders Lindgren + + * emacs/rdebug-core.el, emacs/rdebug-source.el: New and old + byte-compile warnings eliminated. + +2008-01-08 02:36 Rocky Bernstein + + * INSTALL.SVN, Rakefile, rdbg.rb, test/helper.rb, + test/test-breakpoints.rb, test/test-output.rb, test/test-quit.rb: + Rewrite runner.sh in Ruby: rdbg.rb + Were it not for a bug that needs to be fixed, we could + remove runner.sh. test-output.rb hits this bug. + +2008-01-07 23:02 Rocky Bernstein + + * README: Note need for VC6. + +2008-01-07 20:51 Rocky Bernstein + + * CHANGES: What's changed. + +2008-01-07 20:38 Rocky Bernstein + + * ChangeLog, cli/ruby-debug/commands/info.rb, + cli/ruby-debug/commands/variables.rb, lib/ChangeLog: Add "var + class". This means "var const .." can no longer be abbreviated + "var c"; use "var co" instead. + (Or "var const" or "var constant" + +2008-01-07 19:57 Rocky Bernstein + + * ChangeLog, cli/ruby-debug/commands/info.rb, lib/ChangeLog, + test/info-var-bug.rb, test/info-var.cmd, test/info-var.right: Add + class level variables to "info variables" + +2008-01-07 17:37 Rocky Bernstein + + * ChangeLog, cli/ruby-debug/commands/info.rb, lib/ChangeLog, + test/annotate.right, test/info-var-bug2.right, + test/info-var.right, test/output.right, test/test-info-var.rb: + Add "self" to list "info variables" spits out. + +2008-01-07 10:36 Rocky Bernstein + + * emacs/Makefile.am: Missing a backslash to continue a line. + +2008-01-07 10:21 Anders Lindgren + + * emacs/rdebug-core.el: Fixed problem with byte-compile warning due + to an extra comma. + +2008-01-07 09:59 Rocky Bernstein + + * ChangeLog, Rakefile, bin/rdebug, emacs/rdebug-core.el, + lib/ChangeLog: --emacs sets width to 120. rdebug-core.el will + reset to 120 unless it's already that. + +2008-01-07 09:08 Rocky Bernstein + + * README: Add Anders' instruction on how to compile in MS Windows + (modified slightly). + +2008-01-07 04:29 Rocky Bernstein + + * ChangeLog, Makefile.am, ext/ChangeLog, lib/ChangeLog: Split out + ChangeLogs better (I hope). + +2008-01-06 21:16 Rocky Bernstein + + * bin/rdebug: Syntax error. + +2008-01-06 20:56 Rocky Bernstein + + * ChangeLog, bin/rdebug, cli/ruby-debug/processor.rb, + emacs/rdebug-core.el, emacs/rdebug-regexp.el, + emacs/test/test-regexp.el, ext/ChangeLog, lib/ChangeLog, + test/emacs-basic.cmd, test/emacs-basic.right, test/quit.right, + test/tdebug.rb, test/test-emacs-basic.rb: test/*-emacs-basic*, + tdebug: Add test of running in Emacs without annotations. + + emacs/*.el: make regexp tests work again, move regexp to from + core to regexp. + Add an annotate regexp test. + + processor.rb: Remove some anotation print from bleeding into + output + when annotations are not wanted. Reinstate "Program finished" in + annotations and outside (rdebug). + +2008-01-06 18:55 Rocky Bernstein + + * ChangeLog, cli/ruby-debug/processor.rb, emacs/Makefile.am, + emacs/rdebug-core.el, emacs/test/test-indent.el, ext/ChangeLog, + lib/ChangeLog, test/annotate.right, test/output.right: Create + Processor class and subclass that. Perhaps a mixin would be good. + Remove annotation output bleanding when annotate is off. + Try to reduce the mess annotations is adding to processor.rb + rdebug-core.el: fix indentation to pass the regression test + Anders added + Makefile.am: Add rdebug-source.el to distribution. + Make sure "rake test" + +2008-01-06 12:31 Anders Lindgren + + * bin/rdebug, cli/ruby-debug/processor.rb, emacs/rdebug-core.el, + emacs/rdebug-regexp.el: Emacs interface adopted to new + annotations scheme. + +2008-01-06 06:46 Rocky Bernstein + + * test/source.right: correct output for source test + +2008-01-06 06:44 Rocky Bernstein + + * cli/ruby-debug/commands/save.rb, + cli/ruby-debug/commands/script.rb, cli/ruby-debug/interface.rb, + cli/ruby-debug/processor.rb, test/rdebug-save.1, test/source.cmd, + test/test-source.rb: The source command now allows us to read in + breakpoint in the current + context. More work is needed but this is a start. + +2008-01-06 02:15 Rocky Bernstein + + * ChangeLog, bin/rdebug, cli/ruby-debug/commands/breakpoints.rb, + cli/ruby-debug/commands/control.rb, + cli/ruby-debug/commands/save.rb, + cli/ruby-debug/commands/script.rb, cli/ruby-debug/interface.rb, + cli/ruby-debug/processor.rb, ext/ChangeLog, lib/ChangeLog: Some + work on saving state across a restart. More work is needed on the + script command to get this working. The save-file name is now + optional. save.rb split off from script.rb Display expressions + and + some settings are now captured in the save/restore file. + Add interface.finalize - things that need to be done before quit + or + restart. + +2008-01-05 21:16 Rocky Bernstein + + * ChangeLog, bin/rdebug, cli/ruby-debug/interface.rb, + cli/ruby-debug/processor.rb, ext/ChangeLog, lib/ChangeLog, + test/annotate.right, test/output.cmd, test/output.right, + test/quit.right, test/tdebug.rb, test/test-output.rb: More work + to make annotate more like gdb's. starting/stopping/exiting + should be more similar. Some code has been commented out until we + get + the Emacs interface to match. See "FIXME: ANNOTATE" in + processor.rb. + Also regression tests for output and annotate currently fail for + this + reason. + +2008-01-05 16:32 Anders Lindgren + + * emacs/rdebug-core.el, emacs/rdebug-source.el, emacs/rdebug.el, + emacs/test/test-indent.el: rdebug-source.el now spawned off from + rdebug-core.el. + +2008-01-05 15:46 Anders Lindgren + + * emacs/rdebug-source.el: Initial commit of split of + rdebug-code.el. (Currently, rdebug-source.el is straight copy of + rdebug-core.el.) + +2008-01-05 15:05 Anders Lindgren + + * emacs/rdebug-core.el: New commands for displaying to the source + buffer 'rdebug-display-source-buffer' and ...-resync'. The former + is bound to S in the secondary buffers. Added View->Source to the + menu bar. + +2008-01-05 13:46 Rocky Bernstein + + * cli/ruby-debug/commands/breakpoints.rb, + cli/ruby-debug/commands/edit.rb, cli/ruby-debug/helper.rb, + doc/ruby-debug.texi, test/ctrl.right, test/edit.cmd, + test/edit.right, test/test-edit.rb: Add edit command. + breakpoints.rb/helper.rb: bad regular-expression separation. + +2008-01-05 13:24 Anders Lindgren + + * test/output.cmd, test/output.rb, test/output.right, + test/test-output.rb: Added test case for the 'starting' + annotation. (It currently fails since the annotation is broken.) + +2008-01-05 10:40 Anders Lindgren + + * emacs/rdebug-core.el: New selection algorithm for picking the + best secondary window, as suggested in rubyforge issue 1950. + +2008-01-05 10:36 Rocky Bernstein + + * cli/ruby-debug/commands/breakpoints.rb: Catch places were we + can't set breakpoints or delete breakpoints because + we don't have context set. + +2008-01-04 07:43 Rocky Bernstein + + * cli/ruby-debug/interface.rb: @history_save can sometimes be + undefined. Test for it so we don't get a warning + when $DEBUG/$WARING is true. + +2008-01-03 18:54 Anders Lindgren + + * emacs/rdebug.el: When running 'make' (comp-elisp) an error was + triggered. This is probably a problem in comp-elisp since nil is + part of the initial load-path. A work-around was added in + 'rdebug-compare-directories'. + +2008-01-03 15:44 Rocky Bernstein + + * emacs/rdebug-core.el: Deal with a killed gud-comint-buffer. + +2008-01-03 10:34 Anders Lindgren + + * emacs/rdebug-cmd.el, emacs/rdebug-core.el, + emacs/test/test-indent.el: Indentation: fixed problem with test + case and some real minor indentation issues. + +2008-01-03 10:34 Rocky Bernstein + + * emacs/Makefile.am: Filename typo. + +2008-01-03 07:33 Anders Lindgren + + * emacs/rdebug-cmd.el, emacs/rdebug-core.el, emacs/rdebug.el: The + directory of rdebug.el is added to the load-path. (The trick to + add . doesn't work since it referes to the current directory of + the current user buffer, not the file being loaded.) + +2008-01-03 07:11 Anders Lindgren + + * emacs/rdebug-core.el: Added a Options->Window Layout submenu. It + sets and redisplays the window layout, so that the user can try + out the available window layouts. + +2008-01-02 20:35 Rocky Bernstein + + * ChangeLog, cli/ruby-debug/commands/breakpoints.rb, + cli/ruby-debug/helper.rb, ext/ChangeLog, lib/ChangeLog: + helper.rb: add regexp for a position. TODO: add parsing routine + and use in + various commands + +2008-01-02 17:39 Anders Lindgren + + * emacs/rdebug-cmd.el, emacs/rdebug-core.el, + emacs/rdebug-regexp.el, emacs/rdebug-track.el, emacs/rdebug.el: + New comment headers added. Minor rearrangement of functions. + +2008-01-02 17:31 Rocky Bernstein + + * test/test-ruby-debug-base.rb: A little more robust. + +2008-01-02 14:41 Rocky Bernstein + + * ChangeLog, cli/ruby-debug/processor.rb, emacs/rdebug.el, + ext/ChangeLog, lib/ChangeLog, test/annotate.right: processor.rb: + Redo where starting/exiting annotations are done. + rdebug.el: back off on setting output command for now. + +2008-01-02 04:17 Rocky Bernstein + + * test/quit.cmd, test/quit.right, test/tdebug.rb, + test/test-quit.rb: --no-quit bug fixed. But we don't know how to + test it properly yet. + +2008-01-02 04:04 Rocky Bernstein + + * bin/rdebug, cli/ruby-debug/commands/info.rb, + cli/ruby-debug/processor.rb, cli/ruby-debug/theend.rb, + test/annotate.right, test/ctrl.cmd, test/ctrl.right, + test/test-ctrl.rb, test/test-help.rb, test/test-info.rb: Redo how + --no-quit is handled. We now go into a control state with + limited commands. + + Add annotation for "exiting" + + Add regression test for ctrl debugger state. "info" commands are + allowed this state although most don't do anything. Some tests + comments corrected. + +2008-01-01 15:23 Rocky Bernstein + + * ChangeLog, bin/rdebug, ext/ChangeLog, lib/ChangeLog: Fix --emacs + to do --no-quit properly. + +2008-01-01 09:00 Rocky Bernstein + + * ChangeLog, ext/ChangeLog, ext/breakpoint.c, ext/ruby_debug.c, + ext/ruby_debug.h, lib/ChangeLog: Remove RDoc warnings caused + because C files have been split up. + +2008-01-01 08:18 Rocky Bernstein + + * emacs/rdebug-core.el, emacs/rdebug.el: Add + rdebug-user-separate-io-buffer to let folks decide where output + should appear - similar to gdb-ui's + rdebug-user-separate-io-buffer. + Move customizable variables from rdebug-core.el to rdebug.el. + +2008-01-01 05:51 Rocky Bernstein + + * ChangeLog, emacs/Makefile.am, emacs/test/test-indent.el, + emacs/test/test-reindent.el, ext/ChangeLog, lib/ChangeLog: + reindent -> indent. Makefile.am: wasn't including all test files. + +2008-01-01 05:45 Rocky Bernstein + + * emacs/Makefile.am, emacs/elk-test.el, emacs/rdebug-test-cmd.el, + emacs/rdebug-test-regexp.el, emacs/rdebug-test.el, emacs/test, + emacs/test/elk-test.el, emacs/test/test-cmd.el, + emacs/test/test-core.el, emacs/test/test-regexp.el, + emacs/test/test-reindent.el: Create test directory and put + regression tests in that. + +2007-12-31 15:38 Rocky Bernstein + + * configure.ac: Now in 0.10.1 + +2007-12-31 15:37 Rocky Bernstein + + * doc/triangle.rb: Another example program used in documentation. + +2007-12-31 06:26 Rocky Bernstein + + * ChangeLog, Rakefile, ext/ChangeLog, lib/ChangeLog: Rakefile: add + spit-off C files to ruby-debug-base gem. + +2007-12-31 06:23 Rocky Bernstein + + * ChangeLog, emacs/rdebug-test-cmd.el, ext/ChangeLog, + lib/ChangeLog: rdebug-test-cmd.el: Indentation + +2007-12-31 06:20 Rocky Bernstein + + * ext/breakpoint.c: Was missing check_breakpoint_expression(). + +2007-12-31 06:08 Rocky Bernstein + + * CHANGES, ChangeLog, lib/ChangeLog: Changes and more changes. + +2007-12-31 06:06 Rocky Bernstein + + * ext/ChangeLog, ext/breakpoint.c, ext/ruby_debug.c, + ext/ruby_debug.h: Split off breakpoint code from ruby_debug.c; + add common ruby_debug.h + header Alas this means some statics are now externs and one + inline was + dropped. In some cases though moving static to extern might be + desirable for other packages that want to hook into ruby_debug. + Start to preface the global ruby_debug variables with rdebug. + +2007-12-31 05:55 Rocky Bernstein + + * bin/rdebug, doc/rdebug.1, doc/ruby-debug.texi, emacs/Makefile.am, + emacs/rdebug-core.el, emacs/rdebug-test-cmd.el, + emacs/rdebug-test.el, test/runall: rdebug, emacs/* doc/*: --emacs + is now --emacs-basic while --emacs now implies + --emacs-basic --annotate=3 --post-mortem --no-control --no-start + --no-quit + runall: test-*.rb are tests + rdebug-test-cmd.el: use 'require and add tests of + rdebug-{step,next}. + emacs/Makefile.am: break out individual test as separate targets. + +2007-12-30 10:54 Rocky Bernstein + + * emacs/Makefile.am, emacs/rdebug-test-cmd.el, + emacs/rdebug-test-frame.el, emacs/rdebug-vars.el: rdebug-vars.el: + remove cut-and-paste artifact + rest: rdebug-test-frame.el -> rdebug-test-cmd.el + +2007-12-30 10:26 Rocky Bernstein + + * emacs/Makefile.am, emacs/rdebug-cmd.el, emacs/rdebug-core.el, + emacs/rdebug-regexp.el, emacs/rdebug-track.el, + emacs/rdebug-vars.el: Break up rdebug-core.el. Split out + variables, regexps, and debugger commands. + +2007-12-30 10:13 Anders Lindgren + + * emacs/rdebug-core.el: New function + 'rdebug-turn-on-short-key-mode', designed to be used in user + hooks. + +2007-12-30 10:08 Anders Lindgren + + * emacs/rdebug-core.el: C-x C-a C-q now toggles short key mode + +2007-12-29 23:04 Rocky Bernstein + + * doc/ruby-debug.texi: Add subsection as to why no parameter values + in a call stack. + +2007-12-29 22:05 Rocky Bernstein + + * doc/rdebug.1, doc/ruby-debug.texi: Remove short -n option; + --no-stop remains. + +2007-12-29 15:19 Anders Lindgren + + * emacs/rdebug-core.el: Added 'Customize Rdebug' to the Options + submenu. + +2007-12-29 13:31 Rocky Bernstein + + * ChangeLog, bin/rdebug, cli/ruby-debug/command.rb, ext/ChangeLog, + lib/ChangeLog, test/helper.rb, test/noquit.right, test/null.rb, + test/quit.cmd, test/quit.right, test/tdebug.rb: Remove looping on + quit. "-n" is broken so remove it for now. + +2007-12-29 12:27 Rocky Bernstein + + * emacs/rdebug-core.el: -(require 'cl) needed for ignore-errors. + -Short key bindings added: "b" for break "t" for toggle. + -Common key bindings added/changed + R (along with r) is restart. Restart prompts, like quit does. + +, - and _ are now modifiers to step and next; _ takes the + default. + - Numeric argument on "continue" goes to that line, e.g. M-10 + continue is + "continue 10", not "continue" 10 times. + +2007-12-29 10:50 Anders Lindgren + + * bin/rdebug, cli/ruby-debug/theend.rb: * The 'theend.rb' script is + now always loaded with the 'stop' flag. + + * The 'theend.rb' script is now loaded after the restarted print + statement. + + * Removed an 'if' statement preventing restart when the no-stop + flag + was used. + + * Added end-of-line comment in 'theend.rb' on the same line as + the + single statement. This helps people that use the command-line + debugger. + +2007-12-29 09:29 Anders Lindgren + + * bin/rdebug, cli/ruby-debug/theend.rb: When the end of the program + is reached and the --no-quit option is + used, the user now steps into the file 'theend.rb'. This file + contains + a message telling the user that the end of the application has + been + reached. For a normal debug session this feels better. However, + if the + user file is empty, this prevents the debugger from going into an + infinite loop. + + Note, an alternative implementation would be if the debugger + itself + would create an artificial step point at the of the the user + program. + +2007-12-29 08:49 Anders Lindgren + + * emacs/rdebug-core.el: New feature requested by Rocky: Source + short key mode, in the source buffer that corresponds to the + current frame read-only is activated and the plain secondary + buffer keys are bound. + +2007-12-29 00:50 Rocky Bernstein + + * emacs/rdebug-test-frame.el: Remove c: as that's not OS + independent. + +2007-12-28 20:06 Rocky Bernstein + + * doc/ruby-debug.texi: Another misspelling. + +2007-12-28 20:04 Rocky Bernstein + + * doc/ruby-debug.texi: Another typo. + +2007-12-28 20:01 Rocky Bernstein + + * doc/ruby-debug.texi: Tag code/directory sections better. + +2007-12-28 15:33 Rocky Bernstein + + * ChangeLog, cli/ruby-debug/commands/display.rb, + cli/ruby-debug/commands/info.rb, cli/ruby-debug/processor.rb, + ext/ChangeLog, lib/ChangeLog, test/annotate.right, + test/display.cmd, test/display.right: info.rb: Incorrect test for + no display expressions. + display.rb: Grammar thing. + processor.rb: Slightly cleaner code + test/* more/better tests. + +2007-12-28 15:04 Rocky Bernstein + + * test/annotate.right, test/info-var-bug2.right: Forgot to check in + these files when adding new tests + +2007-12-28 13:48 Rocky Bernstein + + * cli/ruby-debug/processor.rb, test/annotate.cmd: Reduce + unneccessary display annotation output. + +2007-12-28 11:27 Rocky Bernstein + + * emacs/Makefile.am, emacs/rdebug-test-regexp.el, + emacs/rdebug-test.el: Split off Emacs test which are regular + expression oriented. + +2007-12-28 10:54 Rocky Bernstein + + * test/test-annotate.rb: *** empty log message *** + +2007-12-28 10:54 Rocky Bernstein + + * test/test-annotate.rb: Doc bug. + +2007-12-28 10:53 Rocky Bernstein + + * test/test-annotate.rb: My old cut-and-paste error. Gotta get in + my "method redefined" patch into rake's test/unit. + +2007-12-28 10:47 Rocky Bernstein + + * cli/ruby-debug/commands/breakpoints.rb, + cli/ruby-debug/processor.rb, test/annotate.cmd, + test/test-annotate.rb: Reduce unnecesary breakpoint, stack, and + variable post-command annotations. + Fix bug in not showing empty breakpoints when last one is + deleted. + +2007-12-28 10:12 Anders Lindgren + + * emacs/rdebug-test-frame.el, emacs/rdebug-test.el: Test cases for + new source buffer breakpoint commands. + +2007-12-27 23:20 Anders Lindgren + + * emacs/rdebug-core.el: Two new breakpoint commands for source + buffers: toggle break point and toggle enable/disable. (The + commands corresponds to F9 and C-F9 in common debuggers + interfaces.) + +2007-12-27 21:05 Rocky Bernstein + + * emacs/rdebug-track.el: Lacking a quote in the last commit. + +2007-12-27 21:03 Rocky Bernstein + + * ChangeLog, emacs/rdebug-track.el, ext/ChangeLog, lib/ChangeLog: + Be more agressive about resetting gud-last-frame and + gud-last-last-frame. These foul up tracking when debugging is + interrupted. + We probably need a special "reset" command. + +2007-12-27 03:11 Rocky Bernstein + + * Rakefile, cli/ruby-debug/command.rb, + cli/ruby-debug/commands/enable.rb, cli/ruby-debug/helper.rb, + doc/ruby-debug.texi, emacs/rdebug-test-frame.el, + test/test-columnize.rb: Use columnize gem from rubyforge. + Remove toggle since Anders can't use - easy come, easy go. + rdebug-test-frame.el was broken. + +2007-12-26 22:31 Anders Lindgren + + * emacs/rdebug-core.el: Fix for broken 'rdebug-goto-frame-n'. + +2007-12-26 21:20 Rocky Bernstein + + * README: Note we (may) need "sudo" before installing. Also note + the test options. + +2007-12-26 20:29 Rocky Bernstein + + * CHANGES: *** empty log message *** + +2007-12-26 19:10 Rocky Bernstein + + * emacs/Makefile.am, emacs/rdebug-test-frame.el: Add regression + tests for new code. + +2007-12-26 18:42 Rocky Bernstein + + * emacs/rdebug-core.el: Doc fixes. + +2007-12-26 18:35 Rocky Bernstein + + * ChangeLog, ext/ChangeLog, ext/ruby_debug.c, lib/ChangeLog: + Version number games - maybe 0.10.1 is better. + +2007-12-26 18:18 Rocky Bernstein + + * emacs/rdebug-core.el: Number keys should move the frame, not just + position the cursor there. + +2007-12-26 10:41 Rocky Bernstein + + * cli/ruby-debug/commands/info.rb, test/info-var-bug2.cmd, + test/info-var-bug2.rb, test/test-info-var.rb: Need to escape + escape (% -> %%) in "info variables" + +2007-12-26 00:04 Rocky Bernstein + + * ext/ruby_debug.c: 2nd attempt to deal with *both* problems Timur + reported. + + 1. Catchpoint is never called when program raises an object of + type + Exception. So, my exceptional breakpoints doesn't work for + Exception + class. + + + 2. When SystemExit exception is raised debugger become stopped + and + stop method is called as many times, as a number of threads + running in + application. For example, in next code debugger become stopped in + rescue block, but program continues its execution. + +2007-12-25 23:40 Rocky Bernstein + + * ChangeLog, cli/ruby-debug/commands/stepping.rb, + doc/ruby-debug.texi, ext/ChangeLog, lib/ChangeLog, + test/stepping.cmd, test/stepping.right: Add step- and step+. + Document as well as the new toggle command. + +2007-12-25 23:39 Rocky Bernstein + + * cli/ruby-debug/commands/enable.rb: Add toggle requested by Anders + Lindgren. + +2007-12-25 23:36 Rocky Bernstein + + * ext/ruby_debug.c: Expermimental patch to address a problems + reported by Timur Shipilov, + Software engineer, Xored Software Inc.: + + When SystemExit exception is raised debugger become stopped and + stop method is called as many times, as a number of threads + running in + application. For example, in next code debugger become stopped in + rescue block, but program continues its execution. + + Example: + + # Stuff to set up debugger + begin + # if you throw another Exception here, all will be fine + exit + sleep 20 + rescue Exception + puts 'This line is not traced' + end + puts 'And this too' + + # Debugger.stop was implicitly called when SystemExit exception + was thrown + # So, there will be an runtime error + Debugger.stop + +2007-12-25 09:55 Rocky Bernstein + + * ChangeLog, cli/ruby-debug/commands/stepping.rb, + doc/ruby-debug.texi, emacs/rdebug-core.el, ext/ChangeLog, + lib/ChangeLog: Small doc fixes. + +2007-12-25 07:51 Rocky Bernstein + + * ChangeLog, ext/ChangeLog, lib/ChangeLog: Last commit before + 0.10.0 release. + +2007-12-25 02:51 Rocky Bernstein + + * AUTHORS, ChangeLog, README, ext/ChangeLog, lib/ChangeLog, + test/breakpoints.cmd, test/breakpoints.right: breakpoints.*: main + -> Object. Add bad Class name test + AUTHOR: Add Anders + README: note ruby-debug-extra. More precise (I think) + +2007-12-24 21:02 Rocky Bernstein + + * cli/ruby-debug/commands/breakpoints.rb, + cli/ruby-debug/processor.rb, doc/ruby-debug.texi, + test/breakpoints.cmd, test/breakpoints.right: Fix bug in stopping + on a method name. Use this in the examples. + +2007-12-24 09:24 Rocky Bernstein + + * doc/Makefile.am, doc/primes.rb, doc/ruby-debug.texi: Add iterator + example. + +2007-12-24 04:12 Rocky Bernstein + + * doc/hanoi.rb, doc/ruby-debug.texi, doc/test-tri2.rb, doc/tri3.rb: + More work on reference guide. Correct spelling, add example + showing + scope frame (for Enumerable). Other small corrections. + + Check in programs used in documentation. + +2007-12-24 00:25 Rocky Bernstein + + * ChangeLog, Rakefile, ext/ChangeLog, lib/ChangeLog: Rakefile: set + up gem unit test for ruby-debug-base. Add file in test/ + so we could do the same for ruby-debug were it not for other + mysterious + problems. + +2007-12-23 22:19 Rocky Bernstein + + * Rakefile, emacs/rdebug-core.el: Rakefile: don't add html or pdf + to gem. Have to get from ruby-debug-extra. + Since we can't build it, it will cause problems when rake is run. + rdebug-core.el: remove gud control keys from secondary buffers. + C-P, C-N, C-F + should have their normal motion meanings. + +2007-12-23 17:33 Rocky Bernstein + + * CHANGES, ChangeLog, Makefile.am, Rakefile, doc, ext/ChangeLog, + lib/ChangeLog, svn2cl_usermap, test/test-columnize.rb, + test/test-ruby-debug-base.rb, test/test-ruby-debug.rb: Go over + packaging: + ChangeLogs for ruby-debug-base (in ext and lib) separate from CLI + ChangeLog + ChangeLogs now map userid to names + ruby-debug-base regression test included in ruby-debug-base + Columnize test separated. (It will disappear when ruby-debug + requires it + as an external) + +2007-12-22 17:07 Rocky Bernstein + + * CHANGES, doc/ruby-debug.texi: More typos. + +2007-12-22 16:14 Rocky Bernstein + + * doc/ruby-debug.texi, emacs/rdebug-core.el: More doc changes. + +2007-12-22 11:18 Rocky Bernstein + + * INSTALL.SVN, bin/rdebug, doc/rdebug.1, doc/ruby-debug.texi: + Correct lots of little typographical and spelling errors. + +2007-12-22 04:02 Rocky Bernstein + + * bin/rdebug, doc/rdebug.1, doc/ruby-debug.texi, + emacs/rdebug-core.el, test/tdebug.rb: Sort options in + alphabetical order. + rdebug-core.el: docstring elaboration + Revise Emacs section gain. + +2007-12-22 02:53 Rocky Bernstein + + * emacs/rdebug-core.el: Indentation. + +2007-12-21 23:01 Rocky Bernstein + + * Rakefile, bin/rdebug, doc/rdebug.1, doc/ruby-debug.texi, + test/tdebug.rb: Synchronize command options. + +2007-12-21 20:23 Rocky Bernstein + + * emacs/rdebug-core.el: Messed up on how to specify Ctrl-. + +2007-12-21 20:15 Rocky Bernstein + + * emacs/rdebug-core.el: Make more compatible with gdb-key-prefix + commands. + +2007-12-21 20:06 Rocky Bernstein + + * bin/rdebug, doc/ruby-debug.texi, test/quit.cmd, test/quit.right, + test/tdebug.rb, test/test-quit.rb: rdebug, tdebug: Prevent + tracing in the debugger if --no-quit is in effect. + rdebug, tdebug: --noquit => --no-quit, --nostop -> --no-stop + test/*quit* Add quit test. + ruby-debug.texi: Doc above changes, update --help lists (e.g. + 0.9.4 => 0.10.0) + +2007-12-21 14:19 Anders Lindgren + + * emacs/rdebug-core.el: The disabled entries in the menu, finally, + has got the right key bindings. + +2007-12-21 11:38 Rocky Bernstein + + * doc/ruby-debug.texi, emacs/rdebug-core.el, emacs/rdebug.el: + rdebug.el: correct file to autoload for rdebug-track-attach + rdebug-core.el: remove free-variable warning + ruby-debug.texi: Start Emacs Command section. + +2007-12-21 03:19 Rocky Bernstein + + * emacs/rdebug-core.el, emacs/rdebug-track.el, emacs/rdebug.el: + rdebug-set-window-name of rdebug-core.el -> rdebug-track-attach + in + rdebug-track.el. + rdebug.el: add autoload. + +2007-12-20 18:17 Anders Lindgren + + * emacs/rdebug-core.el, emacs/rdebug-test.el, emacs/rdebug.el: + Regression test-case added that ensures that elisp files are + properly indented, plus indentation fixes. + +2007-12-20 09:18 Rocky Bernstein + + * emacs/rdebug-core.el, emacs/rdebug.el: rdebug-core.el: Get gud + commands in secondary buffer working by + pulling things from gud.el's common initialization into + rdebug-set-windows. + + rdebug.el had renamed *rdebugtrack* to rdebug-track + +2007-12-19 20:46 Anders Lindgren + + * emacs/rdebug-core.el: Added 'stop debugger' to the menu. Moved + common gud init code to new function + 'rdebug-common-initialization'. + +2007-12-19 18:04 Anders Lindgren + + * emacs/rdebug-core.el: Simple 'if' typo caused the sentinel not to + be added. + +2007-12-19 17:37 Anders Lindgren + + * emacs/rdebug-core.el, emacs/rdebug-test.el: rdebug-goto-entry-n + failed to go to 10 if there was no entry 1. Fixed and regression + test added for this. + +2007-12-19 13:09 Rocky Bernstein + + * emacs/rdebug-test.el: Add \n's in rdebug-goto-entry-test. Doesn't + change things though. + +2007-12-19 12:59 Rocky Bernstein + + * emacs/rdebug-test.el: Add some tests for recent Emacs bugs found. + +2007-12-19 07:55 Anders Lindgren + + * emacs/rdebug-core.el: rdebug-goto-entry-n didn't work in the + watch window. + +2007-12-18 20:38 Anders Lindgren + + * emacs/rdebug-core.el: Replaced all 'rdebug-goto-entry-' + functions with a generic one. If several digits are pressed in + sequence they are treated as a multi-digit number -- but only if + such a number exist. + +2007-12-18 19:10 Anders Lindgren + + * emacs/rdebug-core.el: New mechanism to pick the best window to + display the source in. + +2007-12-18 17:58 Anders Lindgren + + * emacs/rdebug-core.el: Split + `rdebug-populate-secondary-buffer-map' into two functions, one + simply sets the basic keys (named xxx-plain) and one defines the + all keys, including the prefixed keys, and the menu. + + `gud-prefix-key' is used instead of C-x C-a. + +2007-12-18 17:09 Anders Lindgren + + * emacs/rdebug-core.el: Output window (and all other secondary + windows) are now created with the correct mode. Source window now + has C-x C-a prefix. + +2007-12-18 08:39 Rocky Bernstein + + * cli/ruby-debug/commands/enable.rb, emacs/rdebug-core.el, + test/breakpoints.cmd, test/breakpoints.right: rdebug-core.el: + Remember position in breakpoint window + rest: Fix bugs in enable/disable commands and DRY code a little + bit. Better regression tests + (needed obviously) + +2007-12-18 06:58 Rocky Bernstein + + * emacs/Makefile.am, emacs/rdebug-core.el, emacs/rdebug-track.el, + emacs/rdebug.el: Remove rdebugtrack from rdebug-core and put in + its own file. + +2007-12-18 00:44 Rocky Bernstein + + * INSTALL.SVN: Instructions for building, testing, and installing + from Rubyforge's Subversion. + +2007-12-17 16:19 Rocky Bernstein + + * emacs/rdebug-core.el, emacs/rdebug.el: rdebug.el: move emacs test + here from core + rdebug-core.el: add C-x C-a common keys to all debugger buffers + number keys are bound on display expressions. + Watch expression -> Display expression + +2007-12-17 10:31 Rocky Bernstein + + * emacs, emacs/rdebug-core.el, emacs/rdebug.el: rdebug-core.el, + rdebug.el: adjust docstring to remove layout keys - there are + too many of them and may change. + rdebug.el: bind keys 0-9 to position to the corresponding line + (which may + adjusted for header offsets). + +2007-12-17 07:35 Anders Lindgren + + * emacs/rdebug-core.el: * Menu handling: If a key in bound in the + rdebug common map, that key + binding is presented in the menu. + + * Windows bug fix: `gud-rdebug-marker-regexp' couldn't handle + windows + paths containing a drive letter. + +2007-12-17 05:43 Rocky Bernstein + + * ext/ruby_debug.c: Doc typo. + +2007-12-17 05:40 Rocky Bernstein + + * cli/ruby-debug/commands/info.rb, test/helper.rb, + test/info-var-bug.rb, test/info-var.cmd, test/info-var.right, + test/test-display.rb, test/test-info-var.rb, + test/test-stepping.rb: Fix another "INTERNAL ERROR" bug in using + inspect for local variables. + Add a more thorough regression test here. + + Simplify regression tests by adding a filter Proc to the + run_debugger helper. + +2007-12-16 21:47 Rocky Bernstein + + * cli/ruby-debug/commands/variables.rb: Another place where we need + to guard against a faulty "inspect" routine. + +2007-12-16 21:31 Rocky Bernstein + + * ., ChangeLog, cli/ruby-debug/commands/info.rb, doc, emacs, ext, + lib/ruby-debug-base.rb, test/helper.rb, test/info-var-bug.rb, + test/info-var.cmd, test/info-var.right, test/runall, + test/test-breakpoints.rb, test/test-display.rb, + test/test-help.rb, test/test-info-var.rb: Add "info variables + test". + + ruby-debug-base.rb: Not sure how test(?M, file) ever worked + before but change + to use File.stat(file).mtime + info.rb: ignore debugger variables which are sometimes set. + +2007-12-16 17:01 Rocky Bernstein + + * cli/ruby-debug/commands/info.rb: Guard against buggy "inspect" + and "to_str" methods in "info variables". + +2007-12-16 12:10 Rocky Bernstein + + * emacs/rdebug-test.el: Was broken by the splitting rdebug.el into + rdebug.el and rdebug-core.el + +2007-12-16 12:02 Rocky Bernstein + + * cli/ruby-debug.rb: Fix syntax error with last commit. + +2007-12-16 12:01 Rocky Bernstein + + * cli/ruby-debug.rb: Make init file handling match gdb better and + the comment in run_init_script. + +2007-12-16 11:50 Rocky Bernstein + + * Makefile.am, cli/ruby-debug.rb, cli/ruby-debug/commands/info.rb, + doc/ruby-debug.texi, test/info.right: ruby-debug.rb: The plague + of MS Windows: HOMEDRIVE prepended to HOMEPATH. rdebug.ini used + here instead of .rdebugrc. + + info documentation and help strings revised + + Makefile.am: "test" is the same as "check" (Even though Emacs + testing is + still broken) + +2007-12-16 04:09 Rocky Bernstein + + * doc/ruby-debug.texi: Add "info" section. Rework Emacs section + more. + +2007-12-16 01:12 Rocky Bernstein + + * bin/rdebug, cli/ruby-debug/command.rb, emacs/rdebug-core.el, + test/helper.rb, test/tdebug.rb, test/test-breakpoints.rb, + test/test-display.rb, test/test-stepping.rb: test/*: Be more + precise about file paths rather than assume Unix conventions. + More regular about use of SRC_DIR. Had broken tests previously in + not + reinitializing SRC_DIR. + bin/rdebug: notstop misspelling. + command.rb: Don't assume that Emacs implies are using + annotations, or a specific + line width + rdebug-core.el: add variable to specify what you want the + debugger line width + to be + +2007-12-15 17:46 Anders Lindgren + + * cli/ruby-debug/command.rb, emacs/rdebug-core.el: In Emacs mode, + emit longer lines. The Variables and Watch windows no longer + wraps around, so long lines look good. + +2007-12-15 17:38 Anders Lindgren + + * emacs/rdebug-core.el: Font-lock support added in the Variables + and Watch windows. + +2007-12-15 15:28 Anders Lindgren + + * emacs/rdebug-core.el: Doc string and comment overhaul, including + running a spell-checker. + +2007-12-15 15:23 Anders Lindgren + + * emacs/Makefile.am: License refered to 'Bash', replaced it with + 'This program'. + +2007-12-15 14:24 Anders Lindgren + + * emacs/rdebug-core.el: Reindented and adopted to Emacs + conventions. (Now, 'indent-region' applied to the whole file + considers the entire file to be correctly indented.) + +2007-12-15 13:50 Anders Lindgren + + * emacs/rdebug-core.el, emacs/rdebug.el: * Added comments at the + beginnig of the file, describing the package. + + * Added common key bindings for Eclipse and NetBeans + compatibility, and + `rdebug-populate-common-keys-function' for controlling this. + + * Fixed some `defcustom' stuff. + + * Renamed the `rdebug-many-windows-layout-xxx' to + `rdebug-window-layout-xxx' + + * Removed unused variable `rdebug-temp-directory' + + * Added autoload of `turn-on-rdebugtrack-mode' to rdebug.el. + +2007-12-15 09:18 Rocky Bernstein + + * emacs/Makefile.am: Install rdebug-core.el and put in package. + +2007-12-14 17:14 Anders Lindgren + + * emacs/rdebug-core.el, emacs/rdebug.el: Renamed rdebug.el to + rdebug-core.el. New file rdebug.el is now startup code. + +2007-12-14 17:08 Anders Lindgren + + * emacs/rdebug.el: Updated the doc string of 'rdebug', plus other + small fixes. + +2007-12-14 11:56 Rocky Bernstein + + * configure.ac, doc/ruby-debug.texi, ext/ruby_debug.c: Change + version to 0.10.0 + +2007-12-14 09:03 Anders Lindgren + + * bin/rdebug: Type 'stript' => 'script' + +2007-12-14 07:34 Anders Lindgren + + * cli/ruby-debug/processor.rb: Fixed problem where debugger + messages ended up in the 'output' buffer. + +2007-12-14 03:22 Rocky Bernstein + + * CHANGES, configure.ac, doc/rdebug.1, doc/ruby-debug.texi, + ext/ruby_debug.c: ruby-debug.c, configure.ac, ruby-debug.texi: Up + version to 0.9.9 + rdebug.1: document --no-quit + ruby-debu.texi: More work on Emacs section. + +2007-12-14 02:36 Rocky Bernstein + + * emacs/rdebug.el: Mostly small typos. + + rdebug-set-window-configuration-state: Reduce use of 'debugger + for + rdebug-window-configuration-state, in case we want to expand + values. + + debug--setup-secondary-window-help-buffer: More accurate + single-letter + command names. Fix typo. + +2007-12-13 20:27 Rocky Bernstein + + * emacs/rdebug.el: A little closer to getting running from + rdebug-track working. Set + shell to be the command buffer. rdebug-set-windows probably + should be + more appropriately renamed. + +2007-12-13 20:03 Rocky Bernstein + + * emacs/rdebug.el: Doc typo. + +2007-12-13 13:53 Rocky Bernstein + + * bin/rdebug, emacs/rdebug.el: rdebug.el: Add --post-mortem option + by default + rdebug: Fix bug introduced in adding exception handling + (--no-quit) + +2007-12-13 13:30 Rocky Bernstein + + * bin/rdebug, cli/ruby-debug/processor.rb, doc/ruby-debug.texi: + ruby-debug.texi: Document --no-quit + processor.rb: Annotations aren't an Emacs thing + rdebug: handle exceptions even if --post-mortem not given (but + --no-quit is) + +2007-12-13 12:57 Anders Lindgren + + * emacs/rdebug.el: * The sub-menus specific to a secondary window + is only shown when that + window is active. + * The menu item "Run" is renamed to "Continue" to avoid confusion + for + debugger shell users. + * Break-point commands added to the menu. + * In addition to tracking the original window layout, the + debugger + window layout is also tracked. This allows the user to switch + between + the window layouts. The menu now has three entries: Original, + Debugger, and Initial debugger. The first two also have + radio-buttons! + (Internally, the function `rdebug-set-window-configuration-state' + does + most of the work, so it's easier for the functions that switch + layouts.) + * rdebug-quit now prompts, and uses the new "quit + unconditionally" command. + * The "display" window is now renamed to the "watch" window. + * Some keys are rebound (toggle breakpoint is now "t" since "SPC" + is step). + +2007-12-13 02:22 Rocky Bernstein + + * emacs/rdebug.el: Add --no-quit option. + +2007-12-13 02:20 Rocky Bernstein + + * bin/rdebug, cli/ruby-debug/commands/control.rb, + cli/ruby-debug/commands/info.rb, doc/ruby-debug.texi, + test/breakpoints.cmd, test/breakpoints.right, test/info.right, + test/test-ruby-debug.rb: doc/ruby-debug.texi: + *rdebug-display-program* -> rdebug-watch-program* + note that you can run help info and list info subcommands + control.rb: If unconditionally is given, no questions are asked + info.rb: add "info program" to give program execution status + rdebug: add --noquit which doesn't exit when the program + terminates + +2007-12-12 17:20 Rocky Bernstein + + * cli/ruby-debug/commands/eval.rb: Remove warning that appears when + $VERBOSE is set because we are redefining (potentially) a method. + +2007-12-12 13:12 Rocky Bernstein + + * doc/ruby-debug.texi, emacs/rdebug.el: rdebug.el: wasn't showing + Stack buffer. + ruby-debug.texi: update how to autoload + +2007-12-12 12:16 Rocky Bernstein + + * emacs/rdebug.el: Interim changes from Anders Lindgren: Add + debugger menu to Ruby + buffers. Add Output buffer to standard display. + +2007-12-11 16:47 Rocky Bernstein + + * doc/ruby-debug.texi: Start to revise GNU Emacs section. More work + is needed. + +2007-12-11 03:51 Rocky Bernstein + + * emacs/rdebug.el: Proposed revised key bindings for secondary + buffers. + +2007-12-10 18:53 Rocky Bernstein + + * emacs/rdebug.el: Add key binding for stack motion + +2007-12-10 03:23 Rocky Bernstein + + * doc/ruby-debug.texi, lib/ruby-debug-base.rb: doc changes. + +2007-12-07 21:30 Rocky Bernstein + + * cli/ruby-debug/processor.rb: Don't always show "starting" + annotation. + +2007-12-07 11:03 Rocky Bernstein + + * cli/ruby-debug/processor.rb, emacs/rdebug.el: processor.rb: Code + for "starting"/output annotation + rdebug.el: add my own style window + +2007-12-07 03:45 Rocky Bernstein + + * emacs/rdebug.el: From Anders Lindgren: + * Implemented new annotation, "starting", with a corresponding + Emacs + "output" buffer. + + * New variable `rdebug-many-windows-layout-function' makes the + window + layout user configurable. Three different layouts implemented, + rdebug-many-windows-layout-default, -conservative, and + -stack-of-secondary-windows. + +2007-12-06 01:14 Rocky Bernstein + + * emacs/rdebug.el: From Anders Lindgren: + * `gud-comint-buffer' is now buffer local in all secondary + buffers, + hopefully this will make `rdebug' more independent of other + processes + like `gdb'. + + * The restore window configuration variable now has three + possible + values, when set to :many (which is the new default) the window + configuration is only restored when `rdebug-many-windows' is + active. + + * The `edit variable' command, when reading from the minibuffer, + uses + the old value as the initial content. Mouse-1 is no longer bound + to + `edit' since that prevents a simple copy, instead mouse-2 and + mouse-3 + is used. + + * More robust window configuration restore system. Trace support + for + window configuration state changes added. + +2007-12-05 08:42 Rocky Bernstein + + * emacs/rdebug.el: Python->Ruby typos. + +2007-12-05 00:50 Rocky Bernstein + + * cli/ruby-debug/commands/enable.rb, test/display.cmd, + test/display.right, test/test-display.rb: Fix a couple of + display/undisplay bugs caught by regression testing. + +2007-12-05 00:06 Rocky Bernstein + + * cli/ruby-debug/commands/display.rb, + cli/ruby-debug/commands/info.rb, cli/ruby-debug/processor.rb, + emacs/rdebug.el: From Anders Lindgren: + * Emacs primitive `window-configuration' used instead of + `frame-configuration' since the latter caused (among other + things) the + frame title to freeze. (The workaround for the buffer-list crash + is no + longer needed.) + + * The user can now switch between the secondary windows using + commands + bound to the capital letters B, C, D, R, V. The key ? displays a + help + buffer. + + * Commands to add, delete, and edit display (watch) expressions. + + Breakpoint regexp position change which broke goto-breakpoint. + display.rb, processor.rb: use nil for deleted displays, more + display + annotation + +2007-12-04 11:31 Rocky Bernstein + + * cli/ruby-debug/commands/display.rb, + cli/ruby-debug/commands/enable.rb, doc/ruby-debug.texi, + test/breakpoints.cmd, test/breakpoints.right: enable/disable + default to "breakpoint" when no subcommand specified. + More rigorous test of the code. + + display.rb: Fix bug when Debugger.annotation not initially set. + + ruby-debug.texi: Document enable/disable and remove watchpoint + references. Other small changes. + +2007-12-04 02:51 Rocky Bernstein + + * cli/ruby-debug/commands/display.rb, emacs/rdebug.el: display.rb + Don't show display if annotate > 1 since this goes in the + annotation buffer. + rdebug.el: remove minor-most-alist indicator. + +2007-12-02 22:39 Rocky Bernstein + + * emacs/rdebug.el: * `rdebug' was added to the mode line of all + rdebug buffers, a shell buffer + where the mode was active will have `rdebug' twice in the mode + line. + + * In `rdebug-setup-windows', use `gud-target-name' instead of + variable + `gud-last-last-frame'. Not completely sure about this. + + * Make `rdebug-display-original-frame-configuration' a command. + + * Call `gud-sentinel' from rdebug-process-sentinel. + +2007-12-02 21:56 Rocky Bernstein + + * cli/ruby-debug/processor.rb: Show display values in display + annotation. + +2007-12-02 21:47 Rocky Bernstein + + * cli/ruby-debug/commands/enable.rb, + cli/ruby-debug/commands/info.rb, emacs/rdebug-test.el, + emacs/rdebug.el, ext/ruby_debug.c, test/breakpoints.cmd, + test/breakpoints.right: Allow enabling/disabling breakpoints. Add + unit test of enabling/disabling and + emacs regexp checking. Adjust rdebug.el accordingly. + +2007-12-02 11:45 Rocky Bernstein + + * cli/ruby-debug/commands/display.rb, + cli/ruby-debug/commands/enable.rb, + cli/ruby-debug/commands/info.rb, + cli/ruby-debug/commands/variables.rb: Add enable/disable commands + info: Show disabled display expressions (like gdb) + display: update help text + variables: remove _self from list of local variables. + +2007-12-02 11:00 Rocky Bernstein + + * emacs/rdebug.el: If `rdebug-restore-original-frame-layout' is + non-nil (on by default), + the original frame layout is restored when the debugger process + exits. If the user restarts `rdebug' several times, the first + frame + layout is restored. + + Fix the `rdebug-debug-enter' macro to make it possible to use + edebug + in its body. Workaround for a bug in list-buffers which could + crash if + the frame buffer list contained killed buffers. + + New feature and bug fixes from Anders Lindgren. + +2007-12-01 21:28 Rocky Bernstein + + * emacs/rdebug-test.el, emacs/rdebug.el: Add a marker-filter test. + From Anders Lindgren: some debugging instrumentation and a bug + fix when + editing instance variables. + More python references removed. + +2007-11-30 09:21 Rocky Bernstein + + * test/display.cmd, test/display.right: longer display test + +2007-11-30 09:15 Rocky Bernstein + + * Rakefile: Include tests into package ruby-debug. + +2007-11-30 09:08 Rocky Bernstein + + * cli/ruby-debug/commands/display.rb, + cli/ruby-debug/commands/info.rb, cli/ruby-debug/processor.rb, + test/display.cmd, test/display.right, test/info.cmd, + test/info.right, test/test-display.rb: Correct "info display" + command and make it look more like gdb. + Show annotations on preloop even if they are empty. + Create a regression test for "display" commands. + +2007-11-30 04:03 Rocky Bernstein + + * cli/ruby-debug/commands/display.rb, + cli/ruby-debug/commands/info.rb, + cli/ruby-debug/commands/settings.rb, cli/ruby-debug/processor.rb, + doc/ruby-debug.texi, test/info.right: Add "info display". Allow + annotation level 3. (Both as gdb does) + Reduce unnecessary breakpoint (and stack size) stack size output. + +2007-11-30 01:53 Rocky Bernstein + + * emacs/rdebug.el: Was creating duplicate buffers. Patch courtesy + of Anders Lindgren + +2007-11-29 02:55 Rocky Bernstein + + * cli/ruby-debug/commands/info.rb, + cli/ruby-debug/commands/variables.rb, + cli/ruby-debug/processor.rb, doc/ruby-debug.texi, + emacs/rdebug.el, test/info.right: The old "info variables" is now + called "info global_variables" + "info variables" shows local and instance_variables + rdebug.el: "local"" buffer is now "variable" buffer + Annotation buffer now show "info variables" rather than "info + locals" + +2007-11-26 01:15 Rocky Bernstein + + * doc/rdebug.1: Add "up", and "down"; delete "clear" and add an + $Id$ line. + +2007-11-26 00:48 Rocky Bernstein + + * emacs/rdebug.el: Make sure we ahve emacs 22 or greater. + +2007-11-25 17:49 Rocky Bernstein + + * emacs/rdebug.el: Add $Id$ line + +2007-11-25 16:51 Rocky Bernstein + + * emacs/rdebug.el: Improve breakpoints buffer handling slightly. Is + now a major mode and + more like gdb-ui.el. + +2007-11-25 11:14 Rocky Bernstein + + * doc/ruby-debug.texi: typo step + => step+ + +2007-11-25 11:04 Rocky Bernstein + + * doc/ruby-debug.texi: Small corrections to Debugger.start section + +2007-11-24 11:01 Rocky Bernstein + + * ext/ruby_debug.c: Some documentation typos. + +2007-11-24 11:00 Rocky Bernstein + + * doc/rdebug.1, doc/ruby-debug.texi: *: Go over command options. + document annotation + ruby-debug.texi: Document Debugger.context + +2007-11-24 04:07 Rocky Bernstein + + * ext/ruby_debug.c: Ooops, forgot to do frame_locals and update the + rb_define_method + argument count in a couple of places. + +2007-11-24 03:00 Rocky Bernstein + + * Rakefile, doc/Makefile.am, doc/ruby-debug.texi, ext/ruby_debug.c, + test/test-ruby-debug.rb: ruby_debug.c: context.frame things now + allow the frame postion number to be optional. We'll assume 0 + (the top) as the default. + + test-ruby-debug.rb: add tests of the above an of these routines + in general. Make this + be able to run outside of rake. + + Rakefile: Removed emacs/elisp since that's now part of a + different package. + + doc/Makefile.am: Make manual page + + doc/ruby-debug.texi: try to clarify blocks/frames. Redo incorrect + frame passages as a result of vestiges of the bashdb manual. + +2007-11-23 02:43 Rocky Bernstein + + * Makefile.am, doc/Makefile.am, doc/rdebug.1, emacs/Makefile.am: + Make distcheck now works (tests building outside of source + regression tests installing and uninstalling) + rdebug.1: add manual page + +2007-11-22 13:49 Rocky Bernstein + + * emacs/Makefile.am, emacs/rdebug-test.el: rdebug-test.el: regexp + name changed. Fix test. + +2007-11-22 13:36 Rocky Bernstein + + * Makefile.am: Top-level ruby-trunk-extra automake file + +2007-11-22 13:27 Rocky Bernstein + + * autogen.sh: Make NEWS->CHANGES symlnk since NEWS is what + autotools wants. + +2007-11-22 13:22 Rocky Bernstein + + * autogen.sh, configure.ac, doc/Makefile.am, test/test-frame.rb: + test-frame.rb: remove debugging + rest - use autotools to configure a ruby-debug-extra package + which includes + documentation and GNU Emacs support. + +2007-11-22 13:00 Rocky Bernstein + + * emacs/Makefile.am, emacs/elisp-comp: Pick up from autotools + +2007-11-21 00:16 Rocky Bernstein + + * cli/ruby-debug/interface.rb: Make sure @histfile is initialized + before writing it. It could be uninitialized if entered via + Debugger.start; debugger + +2007-11-20 19:42 Rocky Bernstein + + * emacs/rdebug.el: define-minor-mode keymap doesn't work the way I + thought it would. rdebugrack-mode-text typo. + +2007-11-17 18:09 Rocky Bernstein + + * emacs/rdebug.el: Try using a define-minor-mode. (Not without some + problems + though). Shorten rdebug-rdebugtrack to rdebugtrack in case we + ever do + split out the emacs routines. + +2007-11-17 11:54 Rocky Bernstein + + * emacs/rdebug.el: Set --annotate=3 which is what it is in gdba + +2007-11-17 11:46 Rocky Bernstein + + * emacs/rdebug.el: Use and advise function to hook into gud-reset. + +2007-11-16 15:56 Rocky Bernstein + + * emacs/rdebug.el: Handle stack frame lines that split across two + lines. Make stack frame buffer have its own mode. + +2007-11-16 13:50 Rocky Bernstein + + * cli/ruby-debug/commands/method.rb: And make sure to use "inspect" + when showing instance variables as well. + +2007-11-16 13:48 Rocky Bernstein + + * cli/ruby-debug/commands/method.rb: Sort instance variables. + +2007-11-15 19:03 Rocky Bernstein + + * ext/ruby_debug.c: Fix misspelling of declared. + +2007-11-15 15:59 Rocky Bernstein + + * cli/ruby-debug/commands/info.rb, + cli/ruby-debug/commands/variables.rb, emacs/rdebug.el, + test/helper.rb, test/setshow.right, test/test-setshow.rb: + variables.rb: Add "self" to local variables (unless it's "main") + #12782 + http://rubyforge.org/tracker/index.php?func=detail&aid=12782&group_id=1900&atid=7436 + + info.rb: "info args" and "info locals" output should use inspect + (for arrays and such) + helper.rb: Show output lines if "$DEBUG" (ruby -d) is set. + require "fileutils" since we use it. + setshow.*: simplify test code using common helper.rb routine + + rdebug.el: Add key binding in comint buffer for the more common + kind of traceback + +2007-11-15 00:40 Rocky Bernstein + + * emacs/rdebug.el: Set point to current frame in stack window. + +2007-11-14 01:39 Rocky Bernstein + + * cli/ruby-debug/commands/settings.rb, doc/ruby-debug.texi, + test/setshow.cmd, test/setshow.right, test/test-setshow.rb: Add + 'set history save' and 'set history size'. + +2007-11-13 13:28 Rocky Bernstein + + * cli/ruby-debug/interface.rb: Make sure to convert string HISTSIZE + to a number - This time for sure! + +2007-11-13 13:16 Rocky Bernstein + + * test/setshow.cmd, test/setshow.right: Broke regression test + (actually, it was slightly broken even before.) + +2007-11-13 13:12 Rocky Bernstein + + * cli/ruby-debug/interface.rb: Follow gdb's history length setting + just a little bit closer. + +2007-11-12 14:51 Rocky Bernstein + + * cli/ruby-debug/commands/show.rb, test/setshow.right: Use on/off + to display history saving. + +2007-11-12 04:08 Rocky Bernstein + + * test/setshow.right: Forgot to update output check. + +2007-11-12 03:03 Rocky Bernstein + + * doc/ruby-debug.texi: Small change: Add a reference. + +2007-11-12 02:57 Rocky Bernstein + + * doc/ruby-debug.texi: Document "method iv" and "show history" + commands. + +2007-11-12 01:27 Rocky Bernstein + + * cli/ruby-debug/commands/show.rb, cli/ruby-debug/interface.rb, + doc/ruby-debug.texi, test/setshow.cmd, test/setshow.right, + test/test-setshow.rb: Add gdb-like "show history". We don't allow + set yet though. + +2007-11-09 18:27 Rocky Bernstein + + * cli/ruby-debug/commands/method.rb: Add "method iv" + (instance_variables) + +2007-11-07 12:08 Rocky Bernstein + + * Rakefile: DateTime -> Time. Patch #14983 Hiroshi NAKAMURA (nahi) + +2007-11-07 11:54 Rocky Bernstein + + * emacs/rdebug-test.el: Typo - loading wrong file name. + +2007-11-07 11:52 Rocky Bernstein + + * CHANGES, Rakefile, cli/ruby-debug/interface.rb, emacs/elisp-comp, + emacs/rdebug-track.el, emacs/rdebug.el: Rakefile: add emacs + compile task. Combine common package files into a variableg + to improve DRYness. + interface.rb: Apply Roger Pack's patch #12788 (add "." to + .rdebugsavehist if + other HOME and HOMEPATH aren't defined). + rdebug-track.el is now folded into rdebug.el so it's no longer + needed. + rdebug.el: remove compiler-detected bug + +2007-11-07 02:55 Rocky Bernstein + + * emacs/rdebug-test.el, emacs/rdebug.el: Add routine to goto a + unit/test traceback line + +2007-11-06 12:33 Rocky Bernstein + + * emacs/rdebug.el: rdebugtrack deletes annotations now. Other small + improvements. + +2007-11-06 02:07 Rocky Bernstein + + * emacs/rdebug-test.el, emacs/rdebug.el: Add routine to be parse + traceback position and go to it. + +2007-11-06 00:03 Rocky Bernstein + + * emacs/rdebug.el: cosmetic changes + +2007-11-05 19:12 Rocky Bernstein + + * emacs/rdebug.el: Add ability to edit locals value. Make more like + gud-ui.el + +2007-11-05 15:18 Rocky Bernstein + + * cli/ruby-debug/processor.rb, emacs/rdebug.el, test/test-help.rb: + rdebug.el: not all Emacs have split-string-and-unquote. + processor.rb, test-help.rb: Fix breakage from yesterday. Revert a + change + +2007-11-04 15:05 Rocky Bernstein + + * emacs/rdebug.el, test/test-help.rb: Expand/revise Emacs rdebug + docstring + test-help.rb: skip until we fix properly. + +2007-11-04 14:16 Rocky Bernstein + + * cli/ruby-debug/processor.rb, emacs/rdebug.el: Move prompt display + after preloop. + Make rdebugtrack work with annotations. + +2007-11-04 05:51 Rocky Bernstein + + * emacs/rdebug.el: Small nesting bug. + +2007-11-04 04:15 Rocky Bernstein + + * emacs/rdebug.el: Holdover from when three \032's are what we used + for annotation. (It's two now.) + +2007-11-04 04:05 Rocky Bernstein + + * emacs/rdebug-extra.el: rdebug-extra.el is no longer used. Has + been folded into rdebug.el + +2007-11-04 04:04 Rocky Bernstein + + * Rakefile, bin/rdebug, cli/ruby-debug.rb, + cli/ruby-debug/commands/settings.rb, + cli/ruby-debug/commands/show.rb, cli/ruby-debug/processor.rb, + emacs/rdebug-extra.el, emacs/rdebug-test.el, emacs/rdebug.el: + Debugger "annotation" mode. This is used for example in GNU Emacs + to + track the status of breakpoints, stack and local variables. But + it can + be used by other front-ends as well. The command-line option is + --annotate (-A) and there are set/show commands. + + Add emacs files to the package now. More complete Emacs code. + +2007-11-03 21:20 Rocky Bernstein + + * emacs/rdebug-test.el, emacs/rdebug.el, rdebug.el: Move to the + right place (under emacs) + +2007-11-03 21:19 Rocky Bernstein + + * cli/ruby-debug/commands/info.rb, rdebug.el: First attempt to + update and redo the GNU Emacs-to-rdebug interface + +2007-10-31 03:15 Rocky Bernstein + + * Rakefile: Add emacs files to package + +2007-10-31 03:12 Rocky Bernstein + + * emacs/rdebug-extra.el, emacs/rdebug-test.el: Some test of emacs + rdebug regular expressions. + +2007-10-31 02:19 Rocky Bernstein + + * test/help.cmd: Can't handle "help info" this way. Ignore for now. + +2007-10-31 02:00 Rocky Bernstein + + * test/help.cmd, test/info.cmd, test/info.right, test/test-info.rb: + Add basic test of the info command. (Much more would be nice.) + +2007-10-28 04:29 Rocky Bernstein + + * emacs/rdebug-track.el: We don't use rdebug-safe - remove. + string-to-int -> string-to-number as + elisp compiler suggests. + +2007-10-12 10:41 Rocky Bernstein + + * doc/ruby-debug.texi: Add note regarding needing to specify the + 'main' class to set a breakpoint in a main routine. Some other + small formatting changes. + +2007-10-12 10:15 Rocky Bernstein + + * cli/ruby-debug/interface.rb, runner.sh, test/breakpoints.right, + test/test-breakpoints.rb: interface.rb: print is really printf + runner.sh: was using variable before setting it + test/*breakpoints*: first integration test of breakpoints. + +2007-10-12 01:45 Rocky Bernstein + + * ext/ruby_debug.c, test/breakpoints.cmd: Bug in setting a + breakpoint at a main method (e.g. main.gcd). Inside + breakpoint_by method we seem to get nil for the class name. The + fix + here is to change that to the string "main". Better might be to + have + that class name not be nil. + + test/breakpoints.cmd has a sequence of commands that when run on + gcd.rb will show the problem. + +2007-10-11 08:59 Rocky Bernstein + + * test/test-frame.rb: Name conflick in test class name. + +2007-10-11 01:07 Rocky Bernstein + + * test/frame.cmd, test/frame.right, test/helper.rb, + test/test-frame.rb: helper.rb: move out some common test routines + *frame*: add test of frame commands: up, down, frame + +2007-10-03 01:46 Rocky Bernstein + + * cli/ruby-debug/interface.rb, test/stepping.cmd, + test/stepping.right, test/test-stepping.rb: interface.rb: remove + trailing \n. + test-stepping.rb: remove some bugs in cheap-diff + test/stepping.*: don't need "next 1" or "step 1", check without + parameter. + +2007-09-30 13:09 Rocky Bernstein + + * test/test-stepping.rb: Simplify even more. + +2007-09-30 13:07 Rocky Bernstein + + * test/test-stepping.rb: We're not using Diff::LCS so comment it + out. + +2007-09-30 02:50 Rocky Bernstein + + * cli/ruby-debug.rb: Avoid duplicate constants which happens when + "rake test" is run. + +2007-09-30 02:48 Rocky Bernstein + + * cli/ruby-debug/interface.rb, runner.sh, test/gcd.rb, + test/stepping.cmd, test/stepping.right, test/tdebug.rb, + test/test-setshow.rb, test/test-stepping.rb: + cli/ruby-debug/interface.rb: add a verbose mode to show what + commands are + getting run. + + runner.sh: add the ability to set the rdebug script to run based + on environment + variable RDEBUG + + Both of the above are in support of adding the first integration + test + by running rdebug and comparing output produced. The first test + is of + commands in stepping.rb (step, next, finish). It is still a + little + hoaky and needs more work, but another step in the right + direction. + +2007-09-07 04:30 Rocky Bernstein + + * bin/rdebug, cli/ruby-debug/command.rb, + cli/ruby-debug/commands/control.rb, + cli/ruby-debug/commands/info.rb, + cli/ruby-debug/commands/settings.rb, + cli/ruby-debug/commands/show.rb, test/test-help.rb, + test/test-setshow.rb: control.rb: chdir back to directory where + initial run came from. + command.rb, settings.rb, show.rb info.rb: remove warnings when + running + regression tests (due to initializing constants more than once) + + test/*: Use File.join where appropriate + +2007-09-04 01:50 Rocky Bernstein + + * doc/ruby-debug.texi: Start filling out Debugger Module section. + In particular the settings Array. + +2007-09-03 15:29 Rocky Bernstein + + * doc/ruby-debug.texi: Better wording of step+ n. + +2007-09-03 15:06 Rocky Bernstein + + * doc/ruby-debug.texi: Update doc for recent changes. + +2007-09-03 15:06 Rocky Bernstein + + * CHANGES, cli/ruby-debug/command.rb, + cli/ruby-debug/commands/help.rb, + cli/ruby-debug/commands/settings.rb, + cli/ruby-debug/commands/show.rb, cli/ruby-debug/processor.rb, + test/help.cmd, test/help.right, test/setshow.cmd, + test/setshow.right, test/test-help.rb: help "foo" gives message + "Undefined command "foo" rather than a list + of help commands. (Message test is gdb's) + + Add set linetrace+ - similar step+ for linetrace. Don't show + duplicate + lines. + +2007-08-28 10:28 Rocky Bernstein + + * cli/ruby-debug/commands/control.rb: Get "ruby" from Gem.ruby if + that exists. + +2007-08-28 10:07 Rocky Bernstein + + * test/cmdparse.cmd, test/cmdparse.right, test/setshow.cmd, + test/setshow.right, test/test-cmd.rb, test/test-setshow.rb: + cmdparse -> setshow + +2007-08-28 10:05 Rocky Bernstein + + * Rakefile, test/cmdparse.cmd: Rakefile: Make test/check depend on + lib. Make more ruby like and remove + duplicate "clean" target. + +2007-08-28 03:07 Rocky Bernstein + + * test/cmdparse.cmd: Testing svn propset. + +2007-08-28 03:06 Rocky Bernstein + + * test/cmdparse.cmd: Add $Id$ line propset. + +2007-08-28 02:37 Rocky Bernstein + + * test/cmdparse.cmd, test/cmdparse.right, test/test-cmd.rb: Yay! + Start first real regression test. Here we are just trying out + some set/show commands. + +2007-08-27 01:58 Rocky Bernstein + + * doc/ruby-debug.texi: Add some command names on sample sessions. + +2007-08-27 00:48 Rocky Bernstein + + * doc/ruby-debug.texi: More in tutorial section: Add + Debugger.start, show step+ and mention + set forcestep on. + +2007-08-22 13:00 Rocky Bernstein + + * doc/ruby-debug.texi: Add note about putl running down rather than + across. + +2007-08-22 08:28 Rocky Bernstein + + * CHANGES, cli/ruby-debug/commands/irb.rb, + cli/ruby-debug/processor.rb, doc/ruby-debug.texi: leaving irb + shows position same as entering debugger; "list" position + is also cleared when leaving irb. + + Update documentation for the above but more generally to talk + about + the default position that is used in "list", And more + specifically the + frame command also resets the default position. + +2007-08-21 11:40 Rocky Bernstein + + * doc/ruby-debug.texi: Add some notes about the programming + examples. + +2007-08-18 14:57 Rocky Bernstein + + * doc/ruby-debug.texi: Small typos: + - add link to command files in .rdebugrc + - Debugger.debugger -> debugger + - help output is columnized + - remove duplicate "var global" + - Invode -> Invoke + +2007-08-14 03:19 Rocky Bernstein + + * doc/ruby-debug.texi: Make a stab at "var" and "method" commands. + +2007-08-08 09:28 Rocky Bernstein + + * doc/ruby-debug.texi: Start "ruby-debug/debugger" and unit test + section. Elaboration on + error messages when "set autoeval on" + +2007-08-08 07:58 Rocky Bernstein + + * test/test-ruby-debug.rb: Remove duplicate "include" + +2007-08-07 17:58 Rocky Bernstein + + * cli/ruby-debug/commands/display.rb: Better parsing of undisplay. + This time for sure. + +2007-08-07 17:44 Rocky Bernstein + + * cli/ruby-debug/commands/display.rb: Better parameters parsing for + the "undisplay" command. + +2007-08-06 11:23 Rocky Bernstein + + * doc/ruby-debug.texi: Add ruby-debug version number to title. Add + Example macro to allow for + better customization and flexibility. + +2007-08-05 22:10 Rocky Bernstein + + * ext/ruby_debug.c: Typo. + +2007-08-05 16:52 Rocky Bernstein + + * cli/ruby-debug/commands/control.rb, doc/ruby-debug.texi: Work on + bugs in restart command. + Work on ruby-debug sample sessions. Much more work is still + needed though. + +2007-08-04 13:36 Rocky Bernstein + + * cli/ruby-debug/command.rb, cli/ruby-debug/commands/display.rb, + cli/ruby-debug/commands/eval.rb, + cli/ruby-debug/commands/settings.rb, + cli/ruby-debug/commands/show.rb, + cli/ruby-debug/commands/stepping.rb, cli/ruby-debug/processor.rb, + doc/ruby-debug.texi, ext/ruby_debug.c: settings, processor, show: + display expressions should be shown when line tracing. To this + end change always_run from + a boolean on integer "level" number. + + eval.rb pc -> putl + + ruby_debug.c: replace a non-word in a comment its equivalent + ruby-debug.texi: document recent changes pc->putl, display + expresions appear when line tracing + +2007-07-21 19:18 Rocky Bernstein + + * doc/ruby-debug.texi: Work more on sample session. Start to + document ps and pc and set/show linetrace + +2007-07-21 14:50 Rocky Bernstein + + * CHANGES: *** empty log message *** + +2007-07-21 13:54 Rocky Bernstein + + * cli/ruby-debug/command.rb, ext/ruby_debug.c, runner.sh: Changes + to make ruby-debug work for 1.9 (at least minimally). + ruby_debug.c: parameter saving seems to have a bug in it. Don't + turn on by default. + runner.sh: set which ruby using environment variable RUBY. + +2007-07-19 03:08 Rocky Bernstein + + * cli/ruby-debug/command.rb, cli/ruby-debug/commands/eval.rb, + cli/ruby-debug/commands/frame.rb, + cli/ruby-debug/commands/settings.rb, + cli/ruby-debug/commands/show.rb, ext/ruby_debug.c: Add "set" + option to save scalar values and class names on each call. + Add pc (print columnized) and ps (print sorted columnized). + +2007-07-09 16:37 Rocky Bernstein + + * cli/ruby-debug/commands/show.rb: Guard against unitialized argv + setting - via Debugger.start? + +2007-07-02 15:34 Rocky Bernstein + + * cli/ruby-debug/helper.rb: "," -> ", ". This looks nicer. + +2007-06-27 13:44 Rocky Bernstein + + * doc/ruby-debug.texi: Start section on GNU Emacs. + +2007-06-27 12:46 Rocky Bernstein + + * cli/ruby-debug.rb, doc/ruby-debug.texi: Note recent change to run + HOME *after* a local init file. + +2007-06-26 07:05 Rocky Bernstein + + * CHANGES, bin/rdebug, cli/ruby-debug.rb, lib/ruby-debug-base.rb: + Run .rdebugrc on Debugger.start. Look for this in the current + directory and run that instead the one in $HOME if that exists. + Again, inspired and compatible with gdb. + + rdebug: Check script for syntax errors before loading. We get + more informative errors and it doesn't look like rdebug is at + fault. + +2007-06-25 10:25 Rocky Bernstein + + * doc/ruby-debug.texi: Fill out more set/show commands. + +2007-06-21 11:30 Rocky Bernstein + + * CHANGES: Node script->source. + +2007-06-21 11:25 Rocky Bernstein + + * cli/ruby-debug/commands/script.rb: Some small changes missing + from last update. script->source and change help + wording slightly. + +2007-06-21 11:19 Rocky Bernstein + + * doc/ruby-debug.texi: Document source command and command files. + Break out "Controlling the debugger" into separate sections. Go + over + command index entries. + +2007-06-21 10:39 Rocky Bernstein + + * Rakefile, cli/ruby-debug/command.rb, + cli/ruby-debug/commands/script.rb, doc/ruby-debug.texi, + ext/ruby_debug.c, test/test-ruby-debug.rb: test-ruby-debug.rb, + Rakefile: revise so "rake test" works with recent reorganization. + ruby-debug.c: remove unused variable declaration (and compile + warning) + command.rb: remove a warning given when "$DEBUG" or warnings are + set + script.rb: rename "script" to "source" to be more in line with + gdb + ruby-debug.texi: document "source" command, .rdebugrc and how + command files + work. + +2007-06-05 18:54 Kent Sibilev + + * cli/ruby-debug/helper.rb: moved utility modules to helper.rb + +2007-06-05 16:36 Kent Sibilev + + * bin/rdebug, cli/ruby-debug/command.rb, + cli/ruby-debug/commands/breakpoints.rb, + cli/ruby-debug/commands/control.rb, + cli/ruby-debug/commands/display.rb, + cli/ruby-debug/commands/eval.rb, + cli/ruby-debug/commands/frame.rb, + cli/ruby-debug/commands/help.rb, cli/ruby-debug/commands/info.rb, + cli/ruby-debug/commands/method.rb, + cli/ruby-debug/commands/script.rb, + cli/ruby-debug/commands/settings.rb, + cli/ruby-debug/commands/show.rb, + cli/ruby-debug/commands/stepping.rb, + cli/ruby-debug/commands/threads.rb, + cli/ruby-debug/commands/variables.rb, + cli/ruby-debug/interface.rb, cli/ruby-debug/processor.rb, + ext/ruby_debug.c, lib/ruby-debug-base.rb: code reorganization. + reverted 'run' command. + +2007-06-05 07:59 Kent Sibilev + + * lib/ruby-debug-base.rb: restore post_mortem + +2007-06-05 04:28 Rocky Bernstein + + * cli/ruby-debug/processor.rb: Put back print statements the way + they were. It seems important to use + commas in print statments and not %. + +2007-06-05 03:48 Kent Sibilev + + * cli/ruby-debug/command.rb, cli/ruby-debug/commands/control.rb, + ext/ruby_debug.c: tabs to spaces + changed copy.args to play nicely with GC + +2007-06-04 14:52 Rocky Bernstein + + * cli/ruby-debug/processor.rb: Fix bug: When line contains format + strings like %s, print thinks there were too few arguments. + Fix by expanding % to %% and creating a print1 routine which + takes one parameter. + Not sure if this is the best fix. + + Traceback: + INTERNAL ERROR!!! too few arguments + /usr/lib/ruby/gems/1.8/gems/ruby-debug-0.9.4/cli/ruby-debug/interface.rb:12:in + `printf' + /usr/lib/ruby/gems/1.8/gems/ruby-debug-0.9.4/cli/ruby-debug/interface.rb:12:in + `print' + /usr/lib/ruby/gems/1.8/gems/ruby-debug-0.9.4/cli/ruby-debug/processor.rb:104:in + `print' + /usr/lib/ruby/gems/1.8/gems/ruby-debug-0.9.4/cli/ruby-debug/processor.rb:96:in + `__at_line' + +2007-06-04 11:52 Rocky Bernstein + + * cli/ruby-debug/commands/settings.rb, doc/ruby-debug.texi: + ruby-debug.texi: Start listing "set" commands. + settings.rb: change basename help + +2007-06-04 00:06 Rocky Bernstein + + * bin/rdebug, cli/ruby-debug/commands/control.rb: Small bug in + setting ARGV on restart. + +2007-06-03 23:50 Rocky Bernstein + + * bin/rdebug: Catch all uncaught exceptions in rdebug's top-level + run loop. + +2007-06-03 11:50 Rocky Bernstein + + * bin/rdebug, cli/ruby-debug/commands/control.rb, + cli/ruby-debug/interface.rb: Allow run when there is more than + one thread. + Disallow run unless called from rdebug. + Reset ARGV on run. + +2007-06-03 02:44 Rocky Bernstein + + * bin/rdebug, cli/ruby-debug/commands/control.rb, + cli/ruby-debug/processor.rb, ext/ruby_debug.c: Get warm restart + working for one thread - it might even work on OSX ;-) + +2007-06-02 22:43 Rocky Bernstein + + * cli/ruby-debug/command.rb: Typo. + +2007-06-02 16:14 Rocky Bernstein + + * cli/ruby-debug/command.rb, cli/ruby-debug/commands/settings.rb, + cli/ruby-debug/commands/show.rb, cli/ruby-debug/processor.rb: Add + routine to canonicalize file name. This also helps out Emacs. + Independent it's useful to have a place to funnel how to show + filenames. Add set basename to allow short filename setting which + will be useful in regression tests. + +2007-06-02 15:01 Rocky Bernstein + + * cli/ruby-debug/processor.rb, emacs/rdebug-track.el, + lib/ruby-debug-base.rb: lib/ruby-debug-base.rb: add Quit and + Restart exceptions which can reliably be used after the delayed + exception handling bug is fixed + emacs/rdebug-track.el and cli/ruby-debug/processor.rb: more + accurate line tracking in EMACS. When not in emacs should be more + like what was there. + +2007-06-01 21:57 Rocky Bernstein + + * lib/ruby-debug-base.rb: parens around a print seems to give a + warning. Remove. + +2007-05-31 02:21 Rocky Bernstein + + * CHANGES: Typo. + +2007-05-31 02:15 Rocky Bernstein + + * CHANGES, cli/ruby-debug/processor.rb: Add Emacs locations on + breakpoints and catchpoints + +2007-05-30 16:21 Rocky Bernstein + + * cli/ruby-debug/command.rb: Debug statement creapt in. + +2007-05-30 16:15 Rocky Bernstein + + * cli/ruby-debug/command.rb, runner.sh: runner.sh - allow running + outside of trunk directory + command.rb: do better about putting "at line" on another line + when we overflow the line width. + +2007-05-30 06:05 Rocky Bernstein + + * test/test-ruby-debug.rb: Columnize *has* been added. + +2007-05-30 05:50 Rocky Bernstein + + * bin/rdebug, cli/ruby-debug/commands/settings.rb: Oops another bug + if no "set" parameter has been given. + "set autoirb on" seems to mess up syntax checking. + +2007-05-30 05:21 Rocky Bernstein + + * cli/ruby-debug/commands/settings.rb: arg -> args + +2007-05-27 18:37 Rocky Bernstein + + * bin/rdebug: Catch uncaught exceptions in main loop. + +2007-05-27 15:56 Rocky Bernstein + + * runner.sh: Pass back $? from ruby-debug. + +2007-05-27 15:53 Rocky Bernstein + + * bin/rdebug: Make sure Ruby script syntax checks okay. Otherwise + we get a load + message that looks like rdebug has a problem. + +2007-05-27 14:36 Rocky Bernstein + + * bin/rdebug, runner.sh: Fix bug in ignoring "-r debug" + +2007-05-26 22:18 Rocky Bernstein + + * cli/ruby-debug/command.rb, cli/ruby-debug/commands/show.rb: Add + show version. + +2007-05-26 22:00 Rocky Bernstein + + * bin/rdebug, cli/ruby-debug/command.rb, + cli/ruby-debug/commands/control.rb, + cli/ruby-debug/commands/list.rb, + cli/ruby-debug/commands/settings.rb, + cli/ruby-debug/commands/show.rb: Add set args and set listsize. + +2007-05-26 20:38 Rocky Bernstein + + * cli/ruby-debug/command.rb, cli/ruby-debug/commands/control.rb, + cli/ruby-debug/commands/settings.rb, + cli/ruby-debug/commands/show.rb: command.rb, show.rb: Add show + args + control.rb: back off on using AR + +2007-05-26 13:56 Rocky Bernstein + + * cli/ruby-debug/command.rb, cli/ruby-debug/commands/settings.rb, + cli/ruby-debug/commands/show.rb: Set now allows "on", "off", 1 or + 0. + Add set/show linetrace + Add show keep-frame-bindings, port, port-mortem. + +2007-05-26 04:54 Rocky Bernstein + + * doc/ruby-debug.texi: Document --keep-frame-binding better. + +2007-05-26 04:42 Rocky Bernstein + + * cli/ruby-debug/commands/info.rb: Introduced bug after reworking + "info args". make "local args" truncate + output if it's too long same as info args. + +2007-05-26 04:17 Rocky Bernstein + + * CHANGES: Recent batch of changes. + +2007-05-26 03:22 Rocky Bernstein + + * bin/rdebug, cli/ruby-debug/commands/breakpoints.rb: + breakpoints.rb: break with no arguments sets a breakpoint at the + current line + same as gdb + rdebug: if there's a tty and no stop restart the program when it + finishes + +2007-05-25 13:48 Rocky Bernstein + + * cli/ruby-debug/commands/control.rb: Go over errror messages. + +2007-05-25 13:43 Rocky Bernstein + + * cli/ruby-debug/commands/control.rb: If prepending a ruby command + on restart, add "-I" for each $: + Check to see of Debugger::PROG_SCRIPT exists and is executable. + +2007-05-25 12:35 Rocky Bernstein + + * cli/ruby-debug/commands/control.rb: Fix some small bugs. restart + still has problems though. + +2007-05-25 12:21 Rocky Bernstein + + * cli/ruby-debug/commands/control.rb: Fix small bug in restart + parameter passing i introduced. + +2007-05-25 10:11 Rocky Bernstein + + * cli/ruby-debug/commands/control.rb: Allow restart to work more + often. + +2007-05-25 09:34 Rocky Bernstein + + * cli/ruby-debug/command.rb, cli/ruby-debug/commands/settings.rb, + cli/ruby-debug/commands/show.rb: Reduce the redundancy a little + between set and show. + +2007-05-25 08:50 Rocky Bernstein + + * cli/ruby-debug/command.rb, cli/ruby-debug/commands/info.rb, + cli/ruby-debug/commands/settings.rb, + cli/ruby-debug/commands/show.rb: Add info and show commands with + subcommands. + Setting subcommands made to be more like info and show (and gdb). + +2007-05-25 07:48 Rocky Bernstein + + * cli/ruby-debug/command.rb, ext/ruby_debug.c: Have to back off + from showing parameter values since we are showing the + dynamic value. So instead we show the paramater class. + + It should be possible to show the value however if + --keep-frame-bindings is + true. + +2007-05-25 06:45 Rocky Bernstein + + * Rakefile: rake check is a synonym for rake test + +2007-05-24 18:11 Rocky Bernstein + + * cli/ruby-debug/command.rb: This Ruby, not Perl: "last" => "break" + +2007-05-24 13:03 Rocky Bernstein + + * Rakefile, cli/ruby-debug/command.rb, + cli/ruby-debug/commands/frame.rb, + cli/ruby-debug/commands/help.rb, + cli/ruby-debug/commands/method.rb, + cli/ruby-debug/commands/settings.rb, + cli/ruby-debug/commands/threads.rb, + cli/ruby-debug/commands/variables.rb, ext/ruby_debug.c: Add + sandbox for rocky to work in + +2007-05-23 16:43 Rocky Bernstein + + * lib/ruby-debug-base.rb: post_mortem: to test $! *before* running + debug_at_ext or else we may get an erroneous message: + ruby-debug-base.rb:162:in `current_context': Debugger.start is + not called yet. (RuntimeError) + + A simple test case to show the problem: + + "require rubygems" + "require ruby-debug" + Debugger.start + Debugger.post_mortem + exit # Causes us to incorrectly give the above error + +2007-05-23 02:46 Rocky Bernstein + + * doc/ruby-debug.texi: Slogging on with the doc - further with the + example such as it is. + +2007-05-23 02:29 Rocky Bernstein + + * emacs/elk-test.el: test/unit for emacs. + +2007-05-23 02:20 Rocky Bernstein + + * cli/ruby-debug/commands/breakpoints.rb: Fix type conversion + problem with comparing Fixnum with String. I + really need to start pushing forward on the regression tests. + +2007-05-22 12:28 Rocky Bernstein + + * test, test/test-ruby-debug.rb: Some rudimentary tests. + +2007-05-22 12:28 Rocky Bernstein + + * emacs, emacs/rdebug-track.el: Tracks rdebug debugger in an Emacs + shell window + +2007-05-22 02:17 Rocky Bernstein + + * doc/ruby-debug.texi: Make a stab at documenting the list command. + +2007-05-21 17:56 Rocky Bernstein + + * doc/ruby-debug.texi: Small changes. Explain thread number in + prompt. User input in examples + is bold. + +2007-05-21 13:42 Rocky Bernstein + + * bin/rdebug: Using long option --verbose without a script says you + need a script. + -v doesn't (same as --version). + +2007-05-20 17:17 Rocky Bernstein + + * cli/ruby-debug/commands/threads.rb: Stray debug output got + inserted accidentally. + +2007-05-20 17:01 Rocky Bernstein + + * cli/ruby-debug/commands/stepping.rb: Wasn't returning on a bad + continue argument. + +2007-05-20 16:45 Rocky Bernstein + + * cli/ruby-debug/commands/breakpoints.rb, doc/ruby-debug.texi: + breakpoints.rb: delete now will take a list + of breakpoint numbers. We now check file and line numbers to make + sure they + exist before adding a breakpoint. Overall make more gdb + compatible and use + gdb-like wording in giving status and error output. + + ruby-debug.texi: document break, catch and delete. Extend sample + session a little. + +2007-05-18 09:20 Rocky Bernstein + + * CHANGES: What's up. + +2007-05-18 09:13 Rocky Bernstein + + * cli/ruby-debug/commands/threads.rb, doc/ruby-debug.texi: More + minor tweaks to thread regexps. Allows "thread" and "thread nnn" + work + +2007-05-18 08:52 Rocky Bernstein + + * cli/ruby-debug/commands/threads.rb, doc/ruby-debug.texi: + threads.rb: hoist common thread number parse routines + +2007-05-18 02:34 Rocky Bernstein + + * cli/ruby-debug/commands/threads.rb: Go over regexps to make + errors make more sense. Use getint. Common + code needs refactoring. + +2007-05-17 14:03 Rocky Bernstein + + * bin/rdebug: -d option: turns on $DEBUG + -v option: print version number, then turn on verbose mode + ($VERBOSE) + --verbose turns on verbose mode ($VERBOSE) + --version works the same + --verbose turns on verbose mode ($VERBOSE) + +2007-05-17 03:55 Kent Sibilev + + * ext/ruby_debug.c: removed debug message + +2007-05-16 00:27 Kent Sibilev + + * cli/ruby-debug/commands/stepping.rb: wrong module to include + +2007-05-15 20:22 Kent Sibilev + + * CHANGES, cli/ruby-debug/command.rb, + cli/ruby-debug/commands/breakpoints.rb, + cli/ruby-debug/commands/frame.rb, + cli/ruby-debug/commands/stepping.rb, + cli/ruby-debug/commands/threads.rb, + cli/ruby-debug/commands/variables.rb, lib/ruby-debug-base.rb: + various fixes + +2007-05-09 16:56 Kent Sibilev + + * CHANGES, bin/rdebug, ext/ruby_debug.c: '-r' option can be used to + require additional libraries + +2007-05-02 17:36 Kent Sibilev + + * cli/ruby-debug.rb: expand path before running the script + +2007-04-28 00:32 Kent Sibilev + + * CHANGES: + +2007-04-27 23:30 Kent Sibilev + + * bin/rdebug: added option to not start control thread by default + +2007-04-27 23:21 Kent Sibilev + + * lib/ruby-debug-base.rb: ditto + +2007-04-27 23:20 Kent Sibilev + + * CHANGES: ditto + +2007-04-27 23:19 Kent Sibilev + + * lib/ruby-debug-base.rb: add breakpoint method as an alias for + debugger in case breakpoint method is not defined already + +2007-04-27 21:03 Kent Sibilev + + * cli/ruby-debug/commands/irb.rb: better name + +2007-04-27 20:59 Kent Sibilev + + * cli/ruby-debug/commands/irb.rb: make sure we dont throw in a + wrong context + +2007-04-27 20:43 Kent Sibilev + + * cli/ruby-debug.rb, cli/ruby-debug/command.rb, + cli/ruby-debug/commands/eval.rb, cli/ruby-debug/commands/irb.rb: + fixed rdoc + +2007-04-27 20:31 Kent Sibilev + + * CHANGES, cli/ruby-debug/command.rb, + cli/ruby-debug/commands/eval.rb, + cli/ruby-debug/commands/frame.rb, cli/ruby-debug/commands/irb.rb, + cli/ruby-debug/commands/list.rb, + cli/ruby-debug/commands/settings.rb, + cli/ruby-debug/commands/stepping.rb: - irb 'cont' command + continues execution without showing the debugger prompt. + - added Debugger.settings method to programatically modify + command settings + +2007-04-27 06:14 Kent Sibilev + + * CHANGES: note the latest changes + +2007-04-27 06:12 Kent Sibilev + + * bin/rdebug: Compatibility with Ruby-distributed debug module + +2007-04-27 06:07 Kent Sibilev + + * ext/ruby_debug.c: Ctrl-C exits irb and continutes execution + bypassing the debugger prompt + +2007-04-27 06:07 Kent Sibilev + + * cli/ruby-debug/commands/irb.rb: Ctrl-C exits irb and continutes + execution bypassing the debugger prompt + +2007-04-07 23:21 Kent Sibilev + + * ext/ruby_debug.c: removed wrong if node check + +2007-04-04 20:23 Kent Sibilev + + * CHANGES, ext/ruby_debug.c: added hit conditions to breakpoints + +2007-04-03 18:07 Kent Sibilev + + * CHANGES: ditto + +2007-04-03 18:05 Kent Sibilev + + * ext/ruby_debug.c: Fixed file comparision on Windows platform + +2007-04-03 02:58 Kent Sibilev + + * CHANGES: typo + +2007-04-03 01:48 Kent Sibilev + + * CHANGES, cli/ruby-debug/command.rb, + cli/ruby-debug/commands/settings.rb, + cli/ruby-debug/commands/stepping.rb, ext/ruby_debug.c: Added + force parameter to stepping commands + +2007-04-03 01:16 Kent Sibilev + + * CHANGES, cli/ruby-debug/commands/stepping.rb, ext/ruby_debug.c: + added force option to Context#step_over + +2007-04-02 20:55 Kent Sibilev + + * CHANGES, cli/ruby-debug/commands/breakpoints.rb, + ext/ruby_debug.c: fixed incorrect stack calculation + break help fix + +2007-04-01 17:15 Kent Sibilev + + * cli/ruby-debug/commands/help.rb: + +2007-04-01 17:10 Kent Sibilev + + * cli/ruby-debug/commands/eval.rb: + +2007-04-01 17:08 Kent Sibilev + + * cli/ruby-debug/commands/eval.rb, cli/ruby-debug/interface.rb, + cli/ruby-debug/processor.rb: expose two functions dbg_print and + dbg_puts that might be useful in the remote mode + +2007-03-30 15:09 Kent Sibilev + + * CHANGES: + +2007-03-30 08:03 Kent Sibilev + + * ext/ruby_debug.c: + +2007-03-30 07:40 Kent Sibilev + + * ext/ruby_debug.c: + +2007-03-30 07:39 Kent Sibilev + + * ext/ruby_debug.c: + +2007-03-30 07:21 Kent Sibilev + + * CHANGES, ext/ruby_debug.c: All Ruby's 'eval' and require/load + methods create a new frame. + +2007-03-29 20:50 Kent Sibilev + + * CHANGES, cli/ruby-debug/command.rb, + cli/ruby-debug/commands/frame.rb, + cli/ruby-debug/commands/settings.rb: added frameclassname setting + +2007-03-29 02:50 Kent Sibilev + + * cli/ruby-debug/commands/stepping.rb: + +2007-03-29 02:49 Kent Sibilev + + * cli/ruby-debug/commands/stepping.rb: + +2007-03-29 02:09 Kent Sibilev + + * CHANGES, cli/ruby-debug/command.rb, + cli/ruby-debug/commands/frame.rb, + cli/ruby-debug/commands/settings.rb, ext/ruby_debug.c: Added new + Context.frame_class method + + 'frame' command will display a class name along with method name + + Added new 'fullpath' setting. + +2007-03-29 00:45 Kent Sibilev + + * CHANGES, ext/ruby_debug.c: too many internal changes require a + new major release + +2007-03-29 00:27 Kent Sibilev + + * ext/ruby_debug.c: remove useless stops when performing + 'step_over' operation + +2007-03-28 20:36 Kent Sibilev + + * CHANGES, cli/ruby-debug/commands/stepping.rb, ext/ruby_debug.c: + Added the possibility to add a temporary context-specific + breakpoint. + + Context#breakpoint and Context#set_breakpoint methods are added. + + 'cont' command now accepts a numerical parameter which implements + 'Continue until line' behavior. + +2007-03-27 23:26 Kent Sibilev + + * ext/ruby_debug.c: fixed previous optimization for Proc objects + +2007-03-27 23:22 Kent Sibilev + + * ext/ruby_debug.c: we don't need to create a new frame if there is + no block for a c-call + +2007-03-27 23:08 Kent Sibilev + + * CHANGES, ext/ruby_debug.c: Calling a method with a block will + create a new frame. This changes the behavior of 'next' command. + So in order to step into a block, 'step' command must be used. + That fixes bug #9629. + +2007-03-27 22:50 Kent Sibilev + + * ext/ruby_debug.c: step over shouldn't check that we moved to + another line + +2007-03-26 14:27 Kent Sibilev + + * ext/ruby_debug.c: ditto + +2007-03-26 04:51 Kent Sibilev + + * CHANGES: + +2007-03-26 02:51 Kent Sibilev + + * ext/ruby_debug.c: the frame must be captured when calling + Proc#call method + +2007-03-25 01:03 Kent Sibilev + + * lib/ruby-debug-base.rb: will start the debugger if necessary + +2007-03-24 18:23 Kent Sibilev + + * CHANGES: + +2007-03-24 18:17 Kent Sibilev + + * .: stable becomes the trunk + +2007-03-24 18:11 Kent Sibilev + + * + +2007-03-24 18:03 Kent Sibilev + + * ported stop reason from the trunk + +2007-03-19 08:05 Kent Sibilev + + * + +2007-03-19 07:59 Kent Sibilev + + * + +2007-03-19 07:46 Kent Sibilev + + * fixes processor to handler renaming + added a shortcut module + +2007-03-15 04:00 Kent Sibilev + + * + +2007-03-15 02:59 Kent Sibilev + + * + +2007-03-15 02:58 Kent Sibilev + + * added 'set autoirb' setting + +2007-03-15 02:46 Kent Sibilev + + * + +2007-03-15 02:39 Kent Sibilev + + * + +2007-03-15 02:32 Kent Sibilev + + * + +2007-03-15 02:32 Kent Sibilev + + * fixed help command + +2007-03-13 17:06 Kent Sibilev + + * missing file + +2007-03-13 17:06 Kent Sibilev + + * fixed rdoc + +2007-03-06 22:15 Kent Sibilev + + * updated help for list and eval commands + +2007-03-06 19:51 Kent Sibilev + + * pass the current state to the interface object if it accepts it + +2007-03-01 23:44 Kent Sibilev + + * fixed post-mortem + +2007-02-27 08:02 Kent Sibilev + + * repackaging ruby-debug + +2007-02-23 20:56 Kent Sibilev + + * added an option for Debugger.debug_load to stop at the first line + of code + +2007-02-12 06:59 Kent Sibilev + + * added --emacs option + +2007-02-09 16:56 Kent Sibilev + + * in remote mode the debugger shouldn't stop inside of rdebug + script + +2007-02-09 06:59 Kent Sibilev + + * + +2007-02-09 06:20 Kent Sibilev + + * -- + +2007-02-09 01:00 Kent Sibilev + + * fixed code reloading + made 'reload on' as a part of the 'set' command + evaluate ~/.rdebugrc as an init script + +2007-02-07 02:42 Kent Sibilev + + * should use ignored? method to check for the debugger's thread + +2007-02-06 22:21 Kent Sibilev + + * + +2007-02-05 22:48 Kent Sibilev + + * -- + +2007-02-05 22:11 Kent Sibilev + + * fixed emacs integration + +2007-02-05 20:40 Kent Sibilev + + * -- + +2007-02-05 20:38 Kent Sibilev + + * -- + +2007-02-05 20:34 Kent Sibilev + + * -- + +2007-02-05 20:16 Kent Sibilev + + * fixed another issue where a bogus frame is being left in the + stack + +2007-02-05 08:08 Kent Sibilev + + * should save frame id as well + +2007-02-05 07:55 Kent Sibilev + + * fix stack corruption error + +2007-02-05 01:16 Kent Sibilev + + * store frame's self and dyna_vars along with file/line information + +2007-02-04 23:36 Kent Sibilev + + * seg fault bugfixes + fixed suspend/resume + +2007-02-04 05:06 Kent Sibilev + + * restore prev patch + +2007-02-04 03:49 Kent Sibilev + + * -- + +2007-02-04 03:49 Kent Sibilev + + * A better fix for the segmentation fault + +2007-02-03 22:02 Kent Sibilev + + * found a better patch + +2007-02-03 20:33 Kent Sibilev + + * -- + +2007-02-03 20:24 Kent Sibilev + + * fix seg fault by avoiding ruby's bug + fixed Context#resume + when handling post-mortem all threads must be suspended + +2007-02-02 18:47 Kent Sibilev + + * removed ambiguity with down command + +2007-02-01 23:48 Kent Sibilev + + * typo + +2007-02-01 23:10 Kent Sibilev + + * changes for build 0.7 + +2007-02-01 22:15 Kent Sibilev + + * made eval command available from the control thread + +2007-02-01 17:30 Kent Sibilev + + * fixed dllexport for windows platform + +2007-02-01 15:49 Kent Sibilev + + * ditto + +2007-02-01 07:22 Kent Sibilev + + * added setting command + added Context#suspended? method + dispay suspended status in the thread list + display frame starting from zero + +2007-01-31 22:12 Kent Sibilev + + * store object ids in VALUE type + +2007-01-31 21:13 Kent Sibilev + + * ditto + +2007-01-31 21:12 Kent Sibilev + + * fixed help command + +2007-01-31 21:04 Kent Sibilev + + * ditto + +2007-01-31 20:44 Kent Sibilev + + * make a deep copy when capturing post mortem context + +2007-01-31 19:39 Kent Sibilev + + * fixed frame count + added frame_self method to context + +2007-01-31 16:48 Kent Sibilev + + * removed all references to frames array + fixed post-mortem debugging + +2007-01-31 00:51 Kent Sibilev + + * removed obsolete frames usage + +2007-01-31 00:41 Kent Sibilev + + * refactored out frame class and preallocate stack + made local variable available even when bindings are not + collected. + +2007-01-28 20:25 Kent Sibilev + + * -- + +2007-01-28 06:22 Kent Sibilev + + * - Control thread is always started by rdebug script. + - Ability to specify negative frame number to frame commands. + Patch from R. Bernstein. + +2007-01-28 04:59 Kent Sibilev + + * -- + +2007-01-28 04:52 Kent Sibilev + + * added top frame caching + control thread is always started by rdebug script + +2007-01-28 01:21 Kent Sibilev + + * + +2007-01-27 02:21 Kent Sibilev + + * -- + +2007-01-27 01:43 Kent Sibilev + + * another performance optimization + +2007-01-26 20:28 Kent Sibilev + + * fixed #7484 + +2007-01-26 19:31 Kent Sibilev + + * -- + +2007-01-26 17:59 Kent Sibilev + + * revisited file name comparing procedure + +2007-01-26 09:03 Kent Sibilev + + * performance improvements + +2007-01-26 03:12 Kent Sibilev + + * added option to exclude collecting of frame bindings + +2007-01-25 01:41 Kent Sibilev + + * small optimization + +2007-01-25 00:55 Kent Sibilev + + * remove the live thread ref from locker structure as well + +2007-01-24 20:42 Kent Sibilev + + * don't keep a ref to a live thread. + check contexts that their threads are alive + +2007-01-24 18:47 Kent Sibilev + + * ditto + +2007-01-24 18:33 Kent Sibilev + + * disable tracing when in post-mortem + added -x/--trace option to rdebug script + +2007-01-21 08:35 Kent Sibilev + + * updated changelog + +2007-01-21 08:13 Kent Sibilev + + * + +2007-01-21 03:34 Kent Sibilev + + * assign an id to the breakpoint + +2007-01-21 01:20 Kent Sibilev + + * added post_mortem_method wrap method + +2006-12-21 20:30 Kent Sibilev + + * fix of restart command for windows platform + +2006-12-21 20:16 Kent Sibilev + + * added 'restart' command + +2006-12-21 14:24 Kent Sibilev + + * update changelog + +2006-12-21 14:12 Kent Sibilev + + * made 'exit' an alias to 'quit' + fixed the interoperability problem with rspec + +2006-12-21 13:43 Kent Sibilev + + * fixed trace command in post-mortem mode + +2006-12-21 02:00 Kent Sibilev + + * updated changelog + +2006-12-21 01:59 Kent Sibilev + + * initialize only once + +2006-12-21 01:08 Kent Sibilev + + * fixes irb help command + +2006-12-20 21:19 Kent Sibilev + + * check that debugger has been started + +2006-12-20 20:41 Kent Sibilev + + * + +2006-12-20 20:14 Kent Sibilev + + * bumped version + +2006-12-20 20:08 Kent Sibilev + + * added post-mortem option to rdebug + +2006-12-20 19:38 Kent Sibilev + + * initial support for post-mortem debugging + +2006-12-19 06:13 Kent Sibilev + + * removed 'run' alias + +2006-12-18 08:34 Kent Sibilev + + * added irb command + fixed source_for method + +2006-12-02 19:15 Kent Sibilev + + * added reload command + +2006-12-02 18:32 Kent Sibilev + + * fixed #6518 and #6545 + +2006-12-01 06:49 Kent Sibilev + + * + +2006-12-01 06:47 Kent Sibilev + + * + +2006-11-21 23:29 Kent Sibilev + + * ensure that on/off is the last on the line + +2006-11-16 00:04 Kent Sibilev + + * fixed debug_method for assignment methods + +2006-11-16 00:01 Kent Sibilev + + * added the new branch for the stable version + +2006-10-15 22:43 Kent Sibilev + + * branching a stable version + +2006-10-15 22:26 Kent Sibilev + + * ext/win32/ruby_debug.so, lib/ruby-debug.rb: remove unused require + uploaded new windows binary + +2006-10-15 21:56 Kent Sibilev + + * ext/ruby_debug.c: Debugger.start yields to the block even if it's + already started + +2006-10-15 19:02 Kent Sibilev + + * lib/ruby-debug/commands/display.rb: remove unused constructor + +2006-10-15 18:56 Kent Sibilev + + * CHANGES: ditto + +2006-10-15 16:54 Kent Sibilev + + * ext/ruby_debug.c, lib/ruby-debug.rb, + lib/ruby-debug/commands/threads.rb: new logic of context + suspend/resume + +2006-10-15 07:37 Kent Sibilev + + * CHANGES: ditto + +2006-10-15 07:36 Kent Sibilev + + * bin/rdebug, ext/ruby_debug.c, lib/ruby-debug.rb, + lib/ruby-debug/lock.rb: fixed locking of debugger threads + +2006-10-14 19:11 Kent Sibilev + + * Rakefile, ext/ruby_debug.c: make skip status local to a thread + instead of globally disabling the debugger. + +2006-10-09 22:01 Kent Sibilev + + * ext/ruby_debug.c, ext/win32/ruby_debug.so, + lib/ruby-debug/interface.rb: fixes for windows version + +2006-10-09 19:06 Kent Sibilev + + * CHANGES, ext/ruby_debug.c, lib/ruby-debug.rb, + lib/ruby-debug/interface.rb: added Debugger.skip and + Debugger.debug_at_exit methods + +2006-10-09 16:48 Kent Sibilev + + * .gdb_history, ext/.gdb_history, ext/Makefile, + ext/ruby_debug.bundle: remove intermediate files + +2006-10-09 16:44 Kent Sibilev + + * ., .gdb_history, CHANGES, LICENSE, README, Rakefile, bin, + bin/rdebug, doc, ext, ext/.gdb_history, ext/Makefile, + ext/extconf.rb, ext/ruby_debug.bundle, ext/ruby_debug.c, + ext/win32, ext/win32/ruby_debug.so, lib, lib/ruby-debug, + lib/ruby-debug.rb, lib/ruby-debug/command.rb, + lib/ruby-debug/commands, lib/ruby-debug/commands/breakpoints.rb, + lib/ruby-debug/commands/catchpoint.rb, + lib/ruby-debug/commands/control.rb, + lib/ruby-debug/commands/display.rb, + lib/ruby-debug/commands/eval.rb, + lib/ruby-debug/commands/frame.rb, + lib/ruby-debug/commands/help.rb, lib/ruby-debug/commands/list.rb, + lib/ruby-debug/commands/method.rb, + lib/ruby-debug/commands/script.rb, + lib/ruby-debug/commands/stepping.rb, + lib/ruby-debug/commands/threads.rb, + lib/ruby-debug/commands/tmate.rb, + lib/ruby-debug/commands/trace.rb, + lib/ruby-debug/commands/variables.rb, + lib/ruby-debug/interface.rb, lib/ruby-debug/lock.rb, + lib/ruby-debug/processor.rb: initial import + diff --git a/INSTALL.SVN b/INSTALL.SVN new file mode 100644 index 0000000..2d10b0c --- /dev/null +++ b/INSTALL.SVN @@ -0,0 +1,154 @@ +Building and Installing ruby-debug from rubyforge's Subversion Repository (svn) + +The below are Unix-centric instructions. If you have Microsoft Windows see +the section on building Microsoft Windows. + + +0. Prerequisites: To build the package you'll need at a minimum: + + - Ruby (of course). Currently only version 1.8.6 and above but not + version 1.9.x work. + - Ruby development headers. This typically includes a file called "ruby.h" + - A C compiler like GNU C (gcc) + - Rake + - Subversion (svn) + +If you want to build the documentation and install Emacs files, you'll +also need: + + - a POSIX shell + - autoconf + - automake + - GNU Make + - texinfo + +1. Basic package checkout and installation + +Check out the trunk of repository following the instructions at +http://rubyforge.org/scm/?group_id=1900 For example on a Unixy system, +this may work: + + mkdir ruby-debug + cd ruby-debug + svn checkout svn://rubyforge.org/var/svn/ruby-debug/trunk trunk + +In order to make the Ruby gems, ruby-debug and ruby-debug-base, get +yourself into the trunk directory after the code has been checked out and run: + + cd trunk # This is the same trunk checked out above. + rake package + +If all goes well you should have some gem files put in the directory +pkg. Use the gem command to install that. + + sudo gem install ruby-debug-*.gem # See gem help for other possibilities + +If all goes well the rdebug script has been installed ruby-debug is +now ready to run. But if everything goes well you might want to run +the built-in regression tests to make sure everything is okay. +See step 3 below. + +If the gem install didn't work,'t there may be a problem with your C +compiler or the Ruby headers are not installed. + +2. Trying out without installing. + +You don't have to build a gem file to try out ruby debug. In fact when +developing new features for ruby-debug, developers often you want to +try it out *before* installing. If you have a problem in the latter +part of step 1 you may want to try this approach since we go into a +little more detail as to what happens under the covers when you do the +gem install. + +Run (from trunk) + rake lib + +This creates a Makefile and builds the ruby-debug shared library. (On +Unix the name is ruby_debug.so). + +Once this is done you can run the debugger as you would rdebug using the +script rdbg.rb. For example (again from trunk) + + ./rdbg.rb ~/my-ruby-program.rb + +3. Running the Regression tests + +We've put together some basic tests to make sure ruby-debug is doing +what we think it should do. To run these (from trunk): + + rake test + +If you didn't build the ruby-debug shared library and skipped step 2, +don't worry "rake test" will do step 2 for you. You should see a line that +ends something like: + + Finished in 2.767579 seconds. + + 12 tests, 35 assertions, 0 failures, 0 errors + +The number of seconds, tests, and assertions may be different from the +above. However you *should* see exactly "0 failures, 0 errors". + +4. Building the documentation and testing/installing Emacs files + +Of course, I recommend you read the ruby-debug manual that comes with +the package. If you have the prerequisites described above, run this +once: + sh ./autogen.sh + +Then run: + ./configure + make + make test # Runs Emacs regression tests + sudo make install # Or arrange to do this as root + + +Microsoft Windows + +A problem here seems to be that the "One-click" install is compiled +using Microsoft Visual Studio C 6 which is not sold anymore and is +rather old. + +Instead I suggest building via mingw/msys. +http://eigenclass.org/hiki.rb?cmd=view&p=cross+compiling+rcovrt&key=mingw has instructions on how to do. Some amendments to these instructions. + +First, those instructions are a little GNU/Linux centric. If you are +using Ubuntu or Debian, then this should be the easiest to follow the +instructions. On Ubuntu or Debian there is a mingw3 Debian +package. Installing that will give you the cross compiler that is a +prerequisite. Alternatively if you are running MS Windows I notice +that cygwin also has a mingw package. Or possibly you could use MinGW +directly. For other OS's you might have to build a cross-compiler, +i.e. gcc which emits win32 code and can create a win32 DLL. + +After you have a cross compiler you need to download the Ruby source +and basically build a ruby interpreter. The cross-compile.sh script +works although when I downloaded it, it had lots of blank space at the +beginning which will mess up the Unix magic interpretation. That is +remove the blanks in front of "#/bin/sh" + +On my system, this script fails in running "make ruby" because the +fake.rb that got created needed to have a small change: + + ALT_SEPARATOR = "\"; \ +should be + ALT_SEPARATOR = "\\"; \ + +After fixing this, run + make ruby +Also, I needed to run + make rubyw + +And then "make install" as indicated. + +Once all of that's in place, the place you want be is in +ruby-debug/trunk/ext/win32, not ruby-debug/ext. + +So let's say you've installed the cross-compiled install ruby in +/usr/local/ruby-mingw32/. Here then are the commands to build ruby-debug-base-xxx-mswin32.gem + + cd .../ruby-debug/trunk/ext/win32 + ruby -I /usr/local/ruby-mingw32/lib/ruby/1.8/i386-mingw32 ../extconf.rb + make # Not rake + cd ../.. # back in ruby-debug/trunk + rake win32_gem diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..c5b3b3c --- /dev/null +++ b/LICENSE @@ -0,0 +1,23 @@ +Copyright (C) 2005 Kent Sibilev +All rights reserved. + * +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * +THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. \ No newline at end of file diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..d192367 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,14 @@ +SUBDIRS = doc emacs +PHONY = test ChangeLogs +test: check +ChangeLogs: ChangeLog doc/ChangeLog emacs/ChangeLog lib/ChangeLog +ChangeLog: + svn2cl --authors=svn2cl_usermap svn://rubyforge.org/var/svn/ruby-debug/trunk \ + cli test bin AUTHORS CHANGES LICENSE README runner.sh -o ChangeLog +lib/ChangeLog: + svn2cl --authors=svn2cl_usermap svn://rubyforge.org/var/svn/ruby-debug/trunk \ + lib ext -o lib/ChangeLog +doc/ChangeLog: + svn2cl --authors=svn2cl_usermap svn://rubyforge.org/var/svn/ruby-debug/trunk/doc -o doc/ChangeLog +emacs/ChangeLog: + svn2cl --authors=svn2cl_usermap svn://rubyforge.org/var/svn/ruby-debug/trunk/emacs -o emacs/ChangeLog diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..46dd0ea --- /dev/null +++ b/Rakefile @@ -0,0 +1,255 @@ +#!/usr/bin/env rake +# -*- Ruby -*- +require 'rubygems' +require 'rake/gempackagetask' +require 'rake/rdoctask' +require 'rake/testtask' + +SO_NAME = "ruby_debug.so" + +# ------- Default Package ---------- +RUBY_DEBUG_VERSION = open("ext/ruby_debug.c") do |f| + f.grep(/^#define DEBUG_VERSION/).first[/"(.+)"/,1] +end + +COMMON_FILES = FileList[ + 'AUTHORS', + 'CHANGES', + 'LICENSE', + 'README', + 'Rakefile', +] + +CLI_TEST_FILE_LIST = FileList['test/cli/commands/unit/*.rb', + 'test/cli/commands/*_test.rb', + 'test/cli/**/*_test.rb', + 'test/test-*.rb'] +CLI_FILES = COMMON_FILES + FileList[ + "cli/**/*", + 'ChangeLog', + 'bin/*', + 'doc/rdebug.1', + 'test/**/data/*.cmd', + 'test/**/data/*.right', + 'test/**/*.rb', + 'rdbg.rb', + CLI_TEST_FILE_LIST +] + +BASE_TEST_FILE_LIST = %w( + test/base/base.rb + test/base/binding.rb + test/base/catchpoint.rb) +BASE_FILES = COMMON_FILES + FileList[ + 'ext/breakpoint.c', + 'ext/extconf.rb', + 'ext/ruby_debug.c', + 'ext/ruby_debug.h', + 'ext/win32/*', + 'lib/**/*', + BASE_TEST_FILE_LIST, +] + +desc "Test everything." +task :test => :test_base do + Rake::TestTask.new(:test) do |t| + t.libs << ['./ext', './lib', './cli'] + t.test_files = CLI_TEST_FILE_LIST + t.verbose = true + end +end + +desc "Test ruby-debug-base." +task :test_base => :lib do + Rake::TestTask.new(:test_base) do |t| + t.libs << ['./ext', './lib'] + t.test_files = FileList[BASE_TEST_FILE_LIST] + t.verbose = true + end +end + +desc "Test everything - same as test." +task :check => :test + +desc "Create the core ruby-debug shared library extension" +task :lib do + Dir.chdir("ext") do + system("#{Gem.ruby} extconf.rb && make") + end +end + +desc "Compile Emacs code" +task :emacs => "emacs/rdebug.elc" +file "emacs/rdebug.elc" => ["emacs/elisp-comp", "emacs/rdebug.el"] do + Dir.chdir("emacs") do + system("./elisp-comp ./rdebug.el") + end +end + +desc "Create a GNU-style ChangeLog via svn2cl" +task :ChangeLog do + system("svn2cl --authors=svn2cl_usermap svn://rubyforge.org/var/svn/ruby-debug/trunk") + system("svn2cl --authors=svn2cl_usermap svn://rubyforge.org/var/svn/ruby-debug/trunk/ext -o ext/ChangeLog") + system("svn2cl --authors=svn2cl_usermap svn://rubyforge.org/var/svn/ruby-debug/trunk/lib -o lib/ChangeLog") +end + +# Base GEM Specification +base_spec = Gem::Specification.new do |spec| + spec.name = "ruby-debug-base" + + spec.homepage = "http://rubyforge.org/projects/ruby-debug/" + spec.summary = "Fast Ruby debugger - core component" + spec.description = <<-EOF +ruby-debug is a fast implementation of the standard Ruby debugger debug.rb. +It is implemented by utilizing a new Ruby C API hook. The core component +provides support that front-ends can build on. It provides breakpoint +handling, bindings for stack frames among other things. +EOF + + spec.version = RUBY_DEBUG_VERSION + + spec.author = "Kent Sibilev" + spec.email = "ksibilev@yahoo.com" + spec.platform = Gem::Platform::RUBY + spec.require_path = "lib" + spec.extensions = ["ext/extconf.rb"] + spec.files = BASE_FILES.to_a + + spec.required_ruby_version = '>= 1.8.2' + spec.date = Time.now + spec.rubyforge_project = 'ruby-debug' + spec.add_dependency('linecache', '>= 0.3') + + spec.test_files = FileList[BASE_TEST_FILE_LIST] + + # rdoc + spec.has_rdoc = true + spec.extra_rdoc_files = ['README', 'ext/ruby_debug.c'] +end + +cli_spec = Gem::Specification.new do |spec| + spec.name = "ruby-debug" + + spec.homepage = "http://rubyforge.org/projects/ruby-debug/" + spec.summary = "Command line interface (CLI) for ruby-debug-base" + spec.description = <<-EOF +A generic command line interface for ruby-debug. +EOF + + spec.version = RUBY_DEBUG_VERSION + + spec.author = "Kent Sibilev" + spec.email = "ksibilev@yahoo.com" + spec.platform = Gem::Platform::RUBY + spec.require_path = "cli" + spec.bindir = "bin" + spec.executables = ["rdebug"] + spec.files = CLI_FILES.to_a + + spec.required_ruby_version = '>= 1.8.2' + spec.date = Time.now + spec.rubyforge_project = 'ruby-debug' + spec.add_dependency('columnize', '>= 0.1') + spec.add_dependency('ruby-debug-base', "~> #{RUBY_DEBUG_VERSION}.0") + + # FIXME: work out operational logistics for this + # spec.test_files = FileList[CLI_TEST_FILE_LIST] + + # rdoc + spec.has_rdoc = true + spec.extra_rdoc_files = ['README'] +end + +# Rake task to build the default package +Rake::GemPackageTask.new(base_spec) do |pkg| + pkg.need_tar = true +end +Rake::GemPackageTask.new(cli_spec) do |pkg| + pkg.need_tar = true +end + +task :default => [:package] + +# Windows specification +win_spec = base_spec.clone +win_spec.extensions = [] +## win_spec.platform = Gem::Platform::WIN32 # deprecated +win_spec.platform = 'mswin32' +win_spec.files += ["lib/#{SO_NAME}"] + +desc "Create Windows Gem" +task :win32_gem do + # Copy the win32 extension the top level directory + current_dir = File.expand_path(File.dirname(__FILE__)) + source = File.join(current_dir, "ext", "win32", SO_NAME) + target = File.join(current_dir, "lib", SO_NAME) + cp(source, target) + + # Create the gem, then move it to pkg. + Gem::Builder.new(win_spec).build + gem_file = "#{win_spec.name}-#{win_spec.version}-#{win_spec.platform}.gem" + mv(gem_file, "pkg/#{gem_file}") + + # Remove win extension from top level directory. + rm(target) +end + +desc "Publish ruby-debug to RubyForge." +task :publish do + require 'rake/contrib/sshpublisher' + + # Get ruby-debug path. + ruby_debug_path = File.expand_path(File.dirname(__FILE__)) + + Rake::SshDirPublisher.new("kent@rubyforge.org", + "/var/www/gforge-projects/ruby-debug", ruby_debug_path) +end + +desc "Remove built files" +task :clean do + cd "ext" do + if File.exists?("Makefile") + sh "make clean" + rm "Makefile" + end + derived_files = Dir.glob(".o") + Dir.glob("*.so") + rm derived_files unless derived_files.empty? + end +end + +# --------- RDoc Documentation ------ +desc "Generate rdoc documentation" +Rake::RDocTask.new("rdoc") do |rdoc| + rdoc.rdoc_dir = 'doc/rdoc' + rdoc.title = "ruby-debug" + # Show source inline with line numbers + rdoc.options << "--inline-source" << "--line-numbers" + # Make the readme file the start page for the generated html + rdoc.options << '--main' << 'README' + rdoc.rdoc_files.include('bin/**/*', + 'cli/ruby-debug/commands/*.rb', + 'lib/**/*.rb', + 'ext/**/ruby_debug.c', + 'README', + 'LICENSE') +end + +desc "Publish the release files to RubyForge." +task :rubyforge_upload do + `rubyforge login` + release_command = "rubyforge add_release #{PKG_NAME} #{PKG_NAME} '#{PKG_NAME}-#{PKG_VERSION}' pkg/#{PKG_NAME}-#{PKG_VERSION}.gem" + puts release_command + system(release_command) +end + +PKG_NAME = 'ruby-debug' +desc "Publish the release files to RubyForge." +task :rubyforge_upload do + `rubyforge login` + for pkg_name in ['ruby-debug', 'ruby-debug-base'] do + pkg_file_name = "#{pkg_name}-#{pkg_version}" + release_command = "rubyforge add_release ruby-debug #{pkg_name} '#{pkg_file_name}' pkg/#{pkg_file_name}.gem" + puts release_command + system(release_command) + end +end diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..2176ebc --- /dev/null +++ b/autogen.sh @@ -0,0 +1,4 @@ +#!/bin/sh +# Things to do after doing a clean SVN update to add the proper files. +ln -vfs CHANGES NEWS +autoreconf -i -s diff --git a/bin/.svn/README.txt b/bin/.svn/README.txt new file mode 100644 index 0000000..271a8ce --- /dev/null +++ b/bin/.svn/README.txt @@ -0,0 +1,2 @@ +This is a Subversion working copy administrative directory. +Visit http://subversion.tigris.org/ for more information. diff --git a/bin/.svn/empty-file b/bin/.svn/empty-file new file mode 100644 index 0000000..e69de29 diff --git a/bin/.svn/entries b/bin/.svn/entries new file mode 100644 index 0000000..6cc6464 --- /dev/null +++ b/bin/.svn/entries @@ -0,0 +1,22 @@ + + + + + diff --git a/bin/.svn/format b/bin/.svn/format new file mode 100644 index 0000000..b8626c4 --- /dev/null +++ b/bin/.svn/format @@ -0,0 +1 @@ +4 diff --git a/bin/.svn/prop-base/rdebug.svn-base b/bin/.svn/prop-base/rdebug.svn-base new file mode 100644 index 0000000..a669705 --- /dev/null +++ b/bin/.svn/prop-base/rdebug.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 0 + +END diff --git a/bin/.svn/props/rdebug.svn-work b/bin/.svn/props/rdebug.svn-work new file mode 100644 index 0000000..a669705 --- /dev/null +++ b/bin/.svn/props/rdebug.svn-work @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 0 + +END diff --git a/bin/.svn/text-base/rdebug.svn-base b/bin/.svn/text-base/rdebug.svn-base new file mode 100644 index 0000000..4866fc5 --- /dev/null +++ b/bin/.svn/text-base/rdebug.svn-base @@ -0,0 +1,415 @@ +#!/usr/bin/env ruby + +#=== Summary +# +#A command-line front-end to the Ruby debugger, ruby-debug, the +#Fast Ruby Debugger. +# +#Command invocation: +# +# rdebug [options] [--] [script-options] ruby-script-to-debug +# rdebug [options] [script-options] [--client] +# rdebug [--version | --help] +# +#=== Options +# +#-A | --annotate level:: +# Set gdb-style annotation to level, a number. Additional +# information is output automatically when program state is +# changed. This can be used by front-ends such as GNU Emacs to post +# this updated information without having to poll for it. +# +#--client:: +# Connect to a remote debugger. Used with another rdebug invocation +# using --server. See also --host and +# --cport options +# +#--cport=port:: +# Use port port for access to debugger control. +# +#-d | --debug:: +# Set $DEBUG true. +# +#--emacs:: +# Activates full GNU Emacs mode. Is the equivalent of setting the +# options --emacs-basic --annotate=3 --no-stop --no-control +# --post-mortem. +# +#--emacs-basic:: +# Activates GNU Emacs mode. Debugger prompts are prefaced with two +# octal 032 characters. +# +#-h | --host=host:: +# Use host name host for remote debugging. +# +#-I | --include path +# Add path to $LOAD_PATH +# +#-m | --post-mortem:: +# Activate post-mortem mode. +# +#--no-control:: +# Do not automatically start control thread. +# +#--no-stop:: +# Do not stop when script is loaded. +# +#-p | --port=PORT:: +# Host name used for remote debugging. +# +#-r | --requirescript:: +# Require the library, before executing your script. +# +#--script file:: +# Run debugger script file file +# +#-x | --trace:: +# Show lines before executing them. +# +#--no-quit:: +# Do not quit when script terminates. Instead rerun the +# program. +# +#--version:: +# Show the version number and exit. +# +#--verbose:: +# Turn on verbose mode. +# +#--v:: +# Print the version number, then turn on verbose mode if +# a script name is given. If no script name is given +# just exit after printing the version number. +# +#--nx:: +# Don’t execute commands found in any initialization +# files, e.g. .rdebugrc. +# +#--keep-frame-binding:: +# Keep frame bindings. +# +#--script=file:: +# Name of the script file to run +# +#-s | --server:: +# Listen for remote connections. Another rdebug session +# accesses using the --client option. See also the +# --host, --port and --cport options +# +#-w | --wait:: +# Wait for a client connection; implies -s option. +# +#--help:: +# Show invocation help and exit. + +require 'rubygems' +require 'optparse' +require 'ostruct' +require 'ruby-debug' + +def debug_program(options) + # Make sure Ruby script syntax checks okay. + # Otherwise we get a load message that looks like rdebug has + # a problem. + output = `ruby -c "#{Debugger::PROG_SCRIPT}" 2>&1` + if $?.exitstatus != 0 and RUBY_PLATFORM !~ /mswin/ + puts output + exit $?.exitstatus + end + print "\032\032starting\n" if Debugger.annotate and Debugger.annotate > 2 + + # Record where we are we can know if the call stack has been + # truncated or not. + Debugger.start_sentinal=caller(0)[1] + + bt = Debugger.debug_load(Debugger::PROG_SCRIPT, options.stop, false) + if bt + if options.post_mortem + Debugger.handle_post_mortem(bt) + else + print bt.backtrace.map{|l| "\t#{l}"}.join("\n"), "\n" + print "Uncaught exception: #{bt}\n" + end + end +end + +# Do a shell-like path lookup for prog_script and return the results. +# If we can't find anything return prog_script. +def whence_file(prog_script) + if prog_script.index(File::SEPARATOR) + # Don't search since this name has path separator components + return prog_script + end + for dirname in ENV['PATH'].split(File::PATH_SEPARATOR) do + prog_script_try = File.join(dirname, prog_script) + return prog_script_try if File.exist?(prog_script_try) + end + # Failure + return prog_script +end + +options = OpenStruct.new( + 'annotate' => Debugger.annotate, + 'client' => false, + 'control' => true, + 'cport' => Debugger::PORT + 1, + 'frame_bind' => false, + 'host' => nil, + 'quit' => true, + 'no_rewrite_program' => false, + 'stop' => true, + 'nx' => false, + 'port' => Debugger::PORT, + 'post_mortem' => false, + 'restart_script' => nil, + 'script' => nil, + 'server' => false, + 'tracing' => false, + 'verbose_long' => false, + 'wait' => false +) + +def process_options(options) + program = File.basename($0) + opts = OptionParser.new do |opts| + opts.banner = < -- +EOB + opts.separator "" + opts.separator "Options:" + opts.on("-A", "--annotate LEVEL", Integer, "Set annotation level") do + |annotate| + Debugger.annotate = annotate + end + opts.on("-c", "--client", "Connect to remote debugger") do + options.client = true + end + opts.on("--cport PORT", Integer, "Port used for control commands") do + |cport| + options.cport = cport + end + opts.on("-d", "--debug", "Set $DEBUG=true") {$DEBUG = true} + opts.on("--emacs LEVEL", Integer, + "Activates full Emacs support at annotation level LEVEL") do + |level| + Debugger.annotate = level.to_i + ENV['EMACS'] = '1' + ENV['COLUMNS'] = '120' if ENV['COLUMNS'].to_i < 120 + options.control = false + options.quit = false + options.post_mortem = true + end + opts.on('--emacs-basic', 'Activates basic Emacs mode') do + ENV['EMACS'] = '1' + end + opts.on('-h', '--host HOST', 'Host name used for remote debugging') do + |host| + options.host = host + end + opts.on('-I', '--include PATH', String, 'Add PATH to $LOAD_PATH') do |path| + $LOAD_PATH.unshift(path) + end + opts.on('--keep-frame-binding', 'Keep frame bindings') do + options.frame_bind = true + end + opts.on('-m', '--post-mortem', 'Activate post-mortem mode') do + options.post_mortem = true + end + opts.on('--no-control', 'Do not automatically start control thread') do + options.control = false + end + opts.on('--no-quit', 'Do not quit when script finishes') do + options.quit = false + end + opts.on('--no-rewrite-program', + 'Do not set $0 to the program being debugged') do + options.no_rewrite_program = true + end + opts.on('--no-stop', 'Do not stop when script is loaded') do + options.stop = false + end + opts.on('-nx', 'Not run debugger initialization files (e.g. .rdebugrc') do + options.nx = true + end + opts.on('-p', '--port PORT', Integer, 'Port used for remote debugging') do + |port| + options.port = port + end + opts.on('-r', '--require SCRIPT', String, + 'Require the library, before executing your script') do |name| + if name == 'debug' + puts "ruby-debug is not compatible with Ruby's 'debug' library. This option is ignored." + else + require name + end + end + opts.on('--restart-script FILE', String, + 'Name of the script file to run. Erased after read') do + |restart_script| + options.restart_script = restart_script + unless File.exists?(options.restart_script) + puts "Script file '#{options.restart_script}' is not found" + exit + end + end + opts.on('--script FILE', String, 'Name of the script file to run') do + |script| + options.script = script + unless File.exists?(options.script) + puts "Script file '#{options.script}' is not found" + exit + end + end + opts.on('-s', '--server', 'Listen for remote connections') do + options.server = true + end + opts.on('-w', '--wait', 'Wait for a client connection, implies -s option') do + options.wait = true + end + opts.on('-x', '--trace', 'Turn on line tracing') {options.tracing = true} + opts.separator '' + opts.separator 'Common options:' + opts.on_tail('--help', 'Show this message') do + puts opts + exit + end + opts.on_tail('--version', + 'Print the version') do + puts "ruby-debug #{Debugger::VERSION}" + exit + end + opts.on('--verbose', 'Turn on verbose mode') do + $VERBOSE = true + options.verbose_long = true + end + opts.on_tail('-v', + 'Print version number, then turn on verbose mode') do + puts "ruby-debug #{Debugger::VERSION}" + $VERBOSE = true + end + end + return opts +end + +# What file is used for debugger startup commands. +unless defined?(OPTS_INITFILE) + if RUBY_PLATFORM =~ /mswin/ + # Of course MS Windows has to be different + OPTS_INITFILE = 'rdbopt.ini' + HOME_DIR = (ENV['HOME'] || + ENV['HOMEDRIVE'].to_s + ENV['HOMEPATH'].to_s).to_s + else + OPTS_INITFILE = '.rdboptrc' + HOME_DIR = ENV['HOME'].to_s + end +end +begin + initfile = File.join(HOME_DIR, OPTS_INITFILE) + eval(File.read(initfile)) if + File.exist?(initfile) +rescue +end + +opts = process_options(options) +begin + if not defined? Debugger::ARGV + Debugger::ARGV = ARGV.clone + end + rdebug_path = File.expand_path($0) + if RUBY_PLATFORM =~ /mswin/ + rdebug_path += '.cmd' unless rdebug_path =~ /\.cmd$/i + end + Debugger::RDEBUG_SCRIPT = rdebug_path + Debugger::RDEBUG_FILE = __FILE__ + Debugger::INITIAL_DIR = Dir.pwd + opts.parse! ARGV +rescue StandardError => e + puts opts + puts + puts e.message + exit(-1) +end + +if options.client + Debugger.start_client(options.host, options.port) +else + if ARGV.empty? + exit if $VERBOSE and not options.verbose_long + puts opts + puts + puts 'Must specify a script to run' + exit(-1) + end + + # save script name + prog_script = ARGV.shift + prog_script = whence_file(prog_script) unless File.exist?(prog_script) + Debugger::PROG_SCRIPT = File.expand_path prog_script + + # install interruption handler + trap('INT') { Debugger.interrupt_last } + + # set options + Debugger.wait_connection = options.wait + Debugger.keep_frame_binding = options.frame_bind + + if options.server + # start remote mode + Debugger.start_remote(options.host, [options.port, options.cport], + options.post_mortem) do + # load initrc script + Debugger.run_init_script(StringIO.new) unless options.nx + end + debug_program(options) + else + # Set up trace hook for debugger + Debugger.start + # start control thread + Debugger.start_control(options.host, options.cport) if options.control + + # load initrc script (e.g. .rdebugrc) + Debugger.run_init_script(StringIO.new) unless options.nx + + # run restore-settings startup script if specified + if options.restart_script + require 'fileutils' + Debugger.run_script(options.restart_script) + FileUtils.rm(options.restart_script) + end + + # run startup script if specified + if options.script + Debugger.run_script(options.script) + end + + # activate post-mortem + Debugger.post_mortem if options.post_mortem + options.stop = false if options.tracing + Debugger.tracing = options.tracing + + if !options.quit + if Debugger.started? + until Debugger.stop do end + end + begin + debug_program(options) + rescue SyntaxError + puts $!.backtrace.map{|l| "\t#{l}"}.join("\n") + puts "Uncaught Syntax Error\n" + rescue + print $!.backtrace.map{|l| "\t#{l}"}.join("\n"), "\n" + print "Uncaught exception: #{$!}\n" + end + print "The program finished.\n" unless + Debugger.annotate.to_i > 1 # annotate has its own way + interface = Debugger::LocalInterface.new + # Not sure if ControlCommandProcessor is really the right + # thing to use. CommandProcessor requires a state. + processor = Debugger::ControlCommandProcessor.new(interface) + processor.process_commands + else + debug_program(options) + end + end +end diff --git a/bin/rdebug b/bin/rdebug new file mode 100755 index 0000000..4866fc5 --- /dev/null +++ b/bin/rdebug @@ -0,0 +1,415 @@ +#!/usr/bin/env ruby + +#=== Summary +# +#A command-line front-end to the Ruby debugger, ruby-debug, the +#Fast Ruby Debugger. +# +#Command invocation: +# +# rdebug [options] [--] [script-options] ruby-script-to-debug +# rdebug [options] [script-options] [--client] +# rdebug [--version | --help] +# +#=== Options +# +#-A | --annotate level:: +# Set gdb-style annotation to level, a number. Additional +# information is output automatically when program state is +# changed. This can be used by front-ends such as GNU Emacs to post +# this updated information without having to poll for it. +# +#--client:: +# Connect to a remote debugger. Used with another rdebug invocation +# using --server. See also --host and +# --cport options +# +#--cport=port:: +# Use port port for access to debugger control. +# +#-d | --debug:: +# Set $DEBUG true. +# +#--emacs:: +# Activates full GNU Emacs mode. Is the equivalent of setting the +# options --emacs-basic --annotate=3 --no-stop --no-control +# --post-mortem. +# +#--emacs-basic:: +# Activates GNU Emacs mode. Debugger prompts are prefaced with two +# octal 032 characters. +# +#-h | --host=host:: +# Use host name host for remote debugging. +# +#-I | --include path +# Add path to $LOAD_PATH +# +#-m | --post-mortem:: +# Activate post-mortem mode. +# +#--no-control:: +# Do not automatically start control thread. +# +#--no-stop:: +# Do not stop when script is loaded. +# +#-p | --port=PORT:: +# Host name used for remote debugging. +# +#-r | --requirescript:: +# Require the library, before executing your script. +# +#--script file:: +# Run debugger script file file +# +#-x | --trace:: +# Show lines before executing them. +# +#--no-quit:: +# Do not quit when script terminates. Instead rerun the +# program. +# +#--version:: +# Show the version number and exit. +# +#--verbose:: +# Turn on verbose mode. +# +#--v:: +# Print the version number, then turn on verbose mode if +# a script name is given. If no script name is given +# just exit after printing the version number. +# +#--nx:: +# Don’t execute commands found in any initialization +# files, e.g. .rdebugrc. +# +#--keep-frame-binding:: +# Keep frame bindings. +# +#--script=file:: +# Name of the script file to run +# +#-s | --server:: +# Listen for remote connections. Another rdebug session +# accesses using the --client option. See also the +# --host, --port and --cport options +# +#-w | --wait:: +# Wait for a client connection; implies -s option. +# +#--help:: +# Show invocation help and exit. + +require 'rubygems' +require 'optparse' +require 'ostruct' +require 'ruby-debug' + +def debug_program(options) + # Make sure Ruby script syntax checks okay. + # Otherwise we get a load message that looks like rdebug has + # a problem. + output = `ruby -c "#{Debugger::PROG_SCRIPT}" 2>&1` + if $?.exitstatus != 0 and RUBY_PLATFORM !~ /mswin/ + puts output + exit $?.exitstatus + end + print "\032\032starting\n" if Debugger.annotate and Debugger.annotate > 2 + + # Record where we are we can know if the call stack has been + # truncated or not. + Debugger.start_sentinal=caller(0)[1] + + bt = Debugger.debug_load(Debugger::PROG_SCRIPT, options.stop, false) + if bt + if options.post_mortem + Debugger.handle_post_mortem(bt) + else + print bt.backtrace.map{|l| "\t#{l}"}.join("\n"), "\n" + print "Uncaught exception: #{bt}\n" + end + end +end + +# Do a shell-like path lookup for prog_script and return the results. +# If we can't find anything return prog_script. +def whence_file(prog_script) + if prog_script.index(File::SEPARATOR) + # Don't search since this name has path separator components + return prog_script + end + for dirname in ENV['PATH'].split(File::PATH_SEPARATOR) do + prog_script_try = File.join(dirname, prog_script) + return prog_script_try if File.exist?(prog_script_try) + end + # Failure + return prog_script +end + +options = OpenStruct.new( + 'annotate' => Debugger.annotate, + 'client' => false, + 'control' => true, + 'cport' => Debugger::PORT + 1, + 'frame_bind' => false, + 'host' => nil, + 'quit' => true, + 'no_rewrite_program' => false, + 'stop' => true, + 'nx' => false, + 'port' => Debugger::PORT, + 'post_mortem' => false, + 'restart_script' => nil, + 'script' => nil, + 'server' => false, + 'tracing' => false, + 'verbose_long' => false, + 'wait' => false +) + +def process_options(options) + program = File.basename($0) + opts = OptionParser.new do |opts| + opts.banner = < -- +EOB + opts.separator "" + opts.separator "Options:" + opts.on("-A", "--annotate LEVEL", Integer, "Set annotation level") do + |annotate| + Debugger.annotate = annotate + end + opts.on("-c", "--client", "Connect to remote debugger") do + options.client = true + end + opts.on("--cport PORT", Integer, "Port used for control commands") do + |cport| + options.cport = cport + end + opts.on("-d", "--debug", "Set $DEBUG=true") {$DEBUG = true} + opts.on("--emacs LEVEL", Integer, + "Activates full Emacs support at annotation level LEVEL") do + |level| + Debugger.annotate = level.to_i + ENV['EMACS'] = '1' + ENV['COLUMNS'] = '120' if ENV['COLUMNS'].to_i < 120 + options.control = false + options.quit = false + options.post_mortem = true + end + opts.on('--emacs-basic', 'Activates basic Emacs mode') do + ENV['EMACS'] = '1' + end + opts.on('-h', '--host HOST', 'Host name used for remote debugging') do + |host| + options.host = host + end + opts.on('-I', '--include PATH', String, 'Add PATH to $LOAD_PATH') do |path| + $LOAD_PATH.unshift(path) + end + opts.on('--keep-frame-binding', 'Keep frame bindings') do + options.frame_bind = true + end + opts.on('-m', '--post-mortem', 'Activate post-mortem mode') do + options.post_mortem = true + end + opts.on('--no-control', 'Do not automatically start control thread') do + options.control = false + end + opts.on('--no-quit', 'Do not quit when script finishes') do + options.quit = false + end + opts.on('--no-rewrite-program', + 'Do not set $0 to the program being debugged') do + options.no_rewrite_program = true + end + opts.on('--no-stop', 'Do not stop when script is loaded') do + options.stop = false + end + opts.on('-nx', 'Not run debugger initialization files (e.g. .rdebugrc') do + options.nx = true + end + opts.on('-p', '--port PORT', Integer, 'Port used for remote debugging') do + |port| + options.port = port + end + opts.on('-r', '--require SCRIPT', String, + 'Require the library, before executing your script') do |name| + if name == 'debug' + puts "ruby-debug is not compatible with Ruby's 'debug' library. This option is ignored." + else + require name + end + end + opts.on('--restart-script FILE', String, + 'Name of the script file to run. Erased after read') do + |restart_script| + options.restart_script = restart_script + unless File.exists?(options.restart_script) + puts "Script file '#{options.restart_script}' is not found" + exit + end + end + opts.on('--script FILE', String, 'Name of the script file to run') do + |script| + options.script = script + unless File.exists?(options.script) + puts "Script file '#{options.script}' is not found" + exit + end + end + opts.on('-s', '--server', 'Listen for remote connections') do + options.server = true + end + opts.on('-w', '--wait', 'Wait for a client connection, implies -s option') do + options.wait = true + end + opts.on('-x', '--trace', 'Turn on line tracing') {options.tracing = true} + opts.separator '' + opts.separator 'Common options:' + opts.on_tail('--help', 'Show this message') do + puts opts + exit + end + opts.on_tail('--version', + 'Print the version') do + puts "ruby-debug #{Debugger::VERSION}" + exit + end + opts.on('--verbose', 'Turn on verbose mode') do + $VERBOSE = true + options.verbose_long = true + end + opts.on_tail('-v', + 'Print version number, then turn on verbose mode') do + puts "ruby-debug #{Debugger::VERSION}" + $VERBOSE = true + end + end + return opts +end + +# What file is used for debugger startup commands. +unless defined?(OPTS_INITFILE) + if RUBY_PLATFORM =~ /mswin/ + # Of course MS Windows has to be different + OPTS_INITFILE = 'rdbopt.ini' + HOME_DIR = (ENV['HOME'] || + ENV['HOMEDRIVE'].to_s + ENV['HOMEPATH'].to_s).to_s + else + OPTS_INITFILE = '.rdboptrc' + HOME_DIR = ENV['HOME'].to_s + end +end +begin + initfile = File.join(HOME_DIR, OPTS_INITFILE) + eval(File.read(initfile)) if + File.exist?(initfile) +rescue +end + +opts = process_options(options) +begin + if not defined? Debugger::ARGV + Debugger::ARGV = ARGV.clone + end + rdebug_path = File.expand_path($0) + if RUBY_PLATFORM =~ /mswin/ + rdebug_path += '.cmd' unless rdebug_path =~ /\.cmd$/i + end + Debugger::RDEBUG_SCRIPT = rdebug_path + Debugger::RDEBUG_FILE = __FILE__ + Debugger::INITIAL_DIR = Dir.pwd + opts.parse! ARGV +rescue StandardError => e + puts opts + puts + puts e.message + exit(-1) +end + +if options.client + Debugger.start_client(options.host, options.port) +else + if ARGV.empty? + exit if $VERBOSE and not options.verbose_long + puts opts + puts + puts 'Must specify a script to run' + exit(-1) + end + + # save script name + prog_script = ARGV.shift + prog_script = whence_file(prog_script) unless File.exist?(prog_script) + Debugger::PROG_SCRIPT = File.expand_path prog_script + + # install interruption handler + trap('INT') { Debugger.interrupt_last } + + # set options + Debugger.wait_connection = options.wait + Debugger.keep_frame_binding = options.frame_bind + + if options.server + # start remote mode + Debugger.start_remote(options.host, [options.port, options.cport], + options.post_mortem) do + # load initrc script + Debugger.run_init_script(StringIO.new) unless options.nx + end + debug_program(options) + else + # Set up trace hook for debugger + Debugger.start + # start control thread + Debugger.start_control(options.host, options.cport) if options.control + + # load initrc script (e.g. .rdebugrc) + Debugger.run_init_script(StringIO.new) unless options.nx + + # run restore-settings startup script if specified + if options.restart_script + require 'fileutils' + Debugger.run_script(options.restart_script) + FileUtils.rm(options.restart_script) + end + + # run startup script if specified + if options.script + Debugger.run_script(options.script) + end + + # activate post-mortem + Debugger.post_mortem if options.post_mortem + options.stop = false if options.tracing + Debugger.tracing = options.tracing + + if !options.quit + if Debugger.started? + until Debugger.stop do end + end + begin + debug_program(options) + rescue SyntaxError + puts $!.backtrace.map{|l| "\t#{l}"}.join("\n") + puts "Uncaught Syntax Error\n" + rescue + print $!.backtrace.map{|l| "\t#{l}"}.join("\n"), "\n" + print "Uncaught exception: #{$!}\n" + end + print "The program finished.\n" unless + Debugger.annotate.to_i > 1 # annotate has its own way + interface = Debugger::LocalInterface.new + # Not sure if ControlCommandProcessor is really the right + # thing to use. CommandProcessor requires a state. + processor = Debugger::ControlCommandProcessor.new(interface) + processor.process_commands + else + debug_program(options) + end + end +end diff --git a/cli/.svn/README.txt b/cli/.svn/README.txt new file mode 100644 index 0000000..271a8ce --- /dev/null +++ b/cli/.svn/README.txt @@ -0,0 +1,2 @@ +This is a Subversion working copy administrative directory. +Visit http://subversion.tigris.org/ for more information. diff --git a/cli/.svn/empty-file b/cli/.svn/empty-file new file mode 100644 index 0000000..e69de29 diff --git a/cli/.svn/entries b/cli/.svn/entries new file mode 100644 index 0000000..4a42d69 --- /dev/null +++ b/cli/.svn/entries @@ -0,0 +1,25 @@ + + + + + + diff --git a/cli/.svn/format b/cli/.svn/format new file mode 100644 index 0000000..b8626c4 --- /dev/null +++ b/cli/.svn/format @@ -0,0 +1 @@ +4 diff --git a/cli/.svn/prop-base/ruby-debug.rb.svn-base b/cli/.svn/prop-base/ruby-debug.rb.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/.svn/prop-base/ruby-debug.rb.svn-base @@ -0,0 +1 @@ +END diff --git a/cli/.svn/props/ruby-debug.rb.svn-work b/cli/.svn/props/ruby-debug.rb.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/.svn/props/ruby-debug.rb.svn-work @@ -0,0 +1 @@ +END diff --git a/cli/.svn/text-base/ruby-debug.rb.svn-base b/cli/.svn/text-base/ruby-debug.rb.svn-base new file mode 100644 index 0000000..2c4e6bf --- /dev/null +++ b/cli/.svn/text-base/ruby-debug.rb.svn-base @@ -0,0 +1,176 @@ +require 'pp' +require 'stringio' +require 'socket' +require 'thread' +require 'ruby-debug-base' +require 'ruby-debug/processor' + +module Debugger + self.handler = CommandProcessor.new + + # the port number used for remote debugging + PORT = 8989 unless defined?(PORT) + + # What file is used for debugger startup commands. + unless defined?(INITFILE) + if RUBY_PLATFORM =~ /mswin/ + # Of course MS Windows has to be different + INITFILE = 'rdebug.ini' + HOME_DIR = (ENV['HOME'] || + ENV['HOMEDRIVE'].to_s + ENV['HOMEPATH'].to_s).to_s + else + INITFILE = '.rdebugrc' + HOME_DIR = ENV['HOME'].to_s + end + end + + class << self + # gdb-style annotation mode. Used in GNU Emacs interface + attr_accessor :annotate + + # in remote mode, wait for the remote connection + attr_accessor :wait_connection + + # If set, a string to look for in caller() and is used to see + # if the call stack is truncated. + attr_accessor :start_sentinal + + attr_reader :thread, :control_thread + + def interface=(value) # :nodoc: + handler.interface = value + end + + # + # Starts a remote debugger. + # + def start_remote(host = nil, port = PORT, post_mortem = false) + return if @thread + return if started? + + self.interface = nil + start + self.post_mortem if post_mortem + + if port.kind_of?(Array) + cmd_port, ctrl_port = port + else + cmd_port, ctrl_port = port, port + 1 + end + + start_control(host, ctrl_port) + + yield if block_given? + + mutex = Mutex.new + proceed = ConditionVariable.new + + @thread = DebugThread.new do + server = TCPServer.new(host, cmd_port) + while (session = server.accept) + self.interface = RemoteInterface.new(session) + if wait_connection + mutex.synchronize do + proceed.signal + end + end + end + end + if wait_connection + mutex.synchronize do + proceed.wait(mutex) + end + end + end + alias start_server start_remote + + def start_control(host = nil, ctrl_port = PORT + 1) # :nodoc: + raise "Debugger is not started" unless started? + return if defined?(@control_thread) && @control_thread + @control_thread = DebugThread.new do + server = TCPServer.new(host, ctrl_port) + while (session = server.accept) + interface = RemoteInterface.new(session) + processor = ControlCommandProcessor.new(interface) + processor.process_commands + end + end + end + + # + # Connects to the remote debugger + # + def start_client(host = 'localhost', port = PORT) + require "socket" + interface = Debugger::LocalInterface.new + socket = TCPSocket.new(host, port) + puts "Connected." + + catch(:exit) do + while (line = socket.gets) + case line + when /^PROMPT (.*)$/ + input = interface.read_command($1) + throw :exit unless input + socket.puts input + when /^CONFIRM (.*)$/ + input = interface.confirm($1) + throw :exit unless input + socket.puts input + else + print line + end + end + end + socket.close + end + + # Runs normal debugger initialization scripts + # Reads and executes the commands from init file (if any) in the + # current working directory. This is only done if the current + # directory is different from your home directory. Thus, you can + # have more than one init file, one generic in your home directory, + # and another, specific to the program you are debugging, in the + # directory where you invoke ruby-debug. + def run_init_script(out = handler.interface) + cwd_script_file = File.expand_path(File.join(".", INITFILE)) + run_script(cwd_script_file, out) if File.exists?(cwd_script_file) + + home_script_file = File.expand_path(File.join(HOME_DIR, INITFILE)) + run_script(home_script_file, out) if File.exists?(home_script_file) and + cwd_script_file != home_script_file + end + + # + # Runs a script file + # + def run_script(file, out = handler.interface, verbose=false) + interface = ScriptInterface.new(File.expand_path(file), out) + processor = ControlCommandProcessor.new(interface) + processor.process_commands(verbose) + end + end +end + +module Kernel + + # Enters the debugger in the current thread after _steps_ line events occur. + # Before entering the debugger startup script is read. + # + # Setting _steps_ to 0 will cause a break in the debugger subroutine + # and not wait for a line event to occur. You will have to go "up 1" + # in order to be back in your debugged program rather than the + # debugger. Settings _steps_ to 0 could be useful you want to stop + # right after the last statement in some scope, because the next + # step will take you out of some scope. + def debugger(steps = 1) + Debugger.start unless Debugger.started? + Debugger.run_init_script(StringIO.new) + if 0 == steps + Debugger.current_context.stop_frame = 0 + else + Debugger.current_context.stop_next = steps + end + end + alias breakpoint debugger unless respond_to?(:breakpoint) +end diff --git a/cli/ruby-debug.rb b/cli/ruby-debug.rb new file mode 100644 index 0000000..2c4e6bf --- /dev/null +++ b/cli/ruby-debug.rb @@ -0,0 +1,176 @@ +require 'pp' +require 'stringio' +require 'socket' +require 'thread' +require 'ruby-debug-base' +require 'ruby-debug/processor' + +module Debugger + self.handler = CommandProcessor.new + + # the port number used for remote debugging + PORT = 8989 unless defined?(PORT) + + # What file is used for debugger startup commands. + unless defined?(INITFILE) + if RUBY_PLATFORM =~ /mswin/ + # Of course MS Windows has to be different + INITFILE = 'rdebug.ini' + HOME_DIR = (ENV['HOME'] || + ENV['HOMEDRIVE'].to_s + ENV['HOMEPATH'].to_s).to_s + else + INITFILE = '.rdebugrc' + HOME_DIR = ENV['HOME'].to_s + end + end + + class << self + # gdb-style annotation mode. Used in GNU Emacs interface + attr_accessor :annotate + + # in remote mode, wait for the remote connection + attr_accessor :wait_connection + + # If set, a string to look for in caller() and is used to see + # if the call stack is truncated. + attr_accessor :start_sentinal + + attr_reader :thread, :control_thread + + def interface=(value) # :nodoc: + handler.interface = value + end + + # + # Starts a remote debugger. + # + def start_remote(host = nil, port = PORT, post_mortem = false) + return if @thread + return if started? + + self.interface = nil + start + self.post_mortem if post_mortem + + if port.kind_of?(Array) + cmd_port, ctrl_port = port + else + cmd_port, ctrl_port = port, port + 1 + end + + start_control(host, ctrl_port) + + yield if block_given? + + mutex = Mutex.new + proceed = ConditionVariable.new + + @thread = DebugThread.new do + server = TCPServer.new(host, cmd_port) + while (session = server.accept) + self.interface = RemoteInterface.new(session) + if wait_connection + mutex.synchronize do + proceed.signal + end + end + end + end + if wait_connection + mutex.synchronize do + proceed.wait(mutex) + end + end + end + alias start_server start_remote + + def start_control(host = nil, ctrl_port = PORT + 1) # :nodoc: + raise "Debugger is not started" unless started? + return if defined?(@control_thread) && @control_thread + @control_thread = DebugThread.new do + server = TCPServer.new(host, ctrl_port) + while (session = server.accept) + interface = RemoteInterface.new(session) + processor = ControlCommandProcessor.new(interface) + processor.process_commands + end + end + end + + # + # Connects to the remote debugger + # + def start_client(host = 'localhost', port = PORT) + require "socket" + interface = Debugger::LocalInterface.new + socket = TCPSocket.new(host, port) + puts "Connected." + + catch(:exit) do + while (line = socket.gets) + case line + when /^PROMPT (.*)$/ + input = interface.read_command($1) + throw :exit unless input + socket.puts input + when /^CONFIRM (.*)$/ + input = interface.confirm($1) + throw :exit unless input + socket.puts input + else + print line + end + end + end + socket.close + end + + # Runs normal debugger initialization scripts + # Reads and executes the commands from init file (if any) in the + # current working directory. This is only done if the current + # directory is different from your home directory. Thus, you can + # have more than one init file, one generic in your home directory, + # and another, specific to the program you are debugging, in the + # directory where you invoke ruby-debug. + def run_init_script(out = handler.interface) + cwd_script_file = File.expand_path(File.join(".", INITFILE)) + run_script(cwd_script_file, out) if File.exists?(cwd_script_file) + + home_script_file = File.expand_path(File.join(HOME_DIR, INITFILE)) + run_script(home_script_file, out) if File.exists?(home_script_file) and + cwd_script_file != home_script_file + end + + # + # Runs a script file + # + def run_script(file, out = handler.interface, verbose=false) + interface = ScriptInterface.new(File.expand_path(file), out) + processor = ControlCommandProcessor.new(interface) + processor.process_commands(verbose) + end + end +end + +module Kernel + + # Enters the debugger in the current thread after _steps_ line events occur. + # Before entering the debugger startup script is read. + # + # Setting _steps_ to 0 will cause a break in the debugger subroutine + # and not wait for a line event to occur. You will have to go "up 1" + # in order to be back in your debugged program rather than the + # debugger. Settings _steps_ to 0 could be useful you want to stop + # right after the last statement in some scope, because the next + # step will take you out of some scope. + def debugger(steps = 1) + Debugger.start unless Debugger.started? + Debugger.run_init_script(StringIO.new) + if 0 == steps + Debugger.current_context.stop_frame = 0 + else + Debugger.current_context.stop_next = steps + end + end + alias breakpoint debugger unless respond_to?(:breakpoint) +end diff --git a/cli/ruby-debug/.svn/README.txt b/cli/ruby-debug/.svn/README.txt new file mode 100644 index 0000000..271a8ce --- /dev/null +++ b/cli/ruby-debug/.svn/README.txt @@ -0,0 +1,2 @@ +This is a Subversion working copy administrative directory. +Visit http://subversion.tigris.org/ for more information. diff --git a/cli/ruby-debug/.svn/empty-file b/cli/ruby-debug/.svn/empty-file new file mode 100644 index 0000000..e69de29 diff --git a/cli/ruby-debug/.svn/entries b/cli/ruby-debug/.svn/entries new file mode 100644 index 0000000..5436448 --- /dev/null +++ b/cli/ruby-debug/.svn/entries @@ -0,0 +1,61 @@ + + + + + + + + + + diff --git a/cli/ruby-debug/.svn/format b/cli/ruby-debug/.svn/format new file mode 100644 index 0000000..b8626c4 --- /dev/null +++ b/cli/ruby-debug/.svn/format @@ -0,0 +1 @@ +4 diff --git a/cli/ruby-debug/.svn/prop-base/command.rb.svn-base b/cli/ruby-debug/.svn/prop-base/command.rb.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/.svn/prop-base/command.rb.svn-base @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/.svn/prop-base/debugger.rb.svn-base b/cli/ruby-debug/.svn/prop-base/debugger.rb.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/.svn/prop-base/debugger.rb.svn-base @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/.svn/prop-base/helper.rb.svn-base b/cli/ruby-debug/.svn/prop-base/helper.rb.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/.svn/prop-base/helper.rb.svn-base @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/.svn/prop-base/interface.rb.svn-base b/cli/ruby-debug/.svn/prop-base/interface.rb.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/.svn/prop-base/interface.rb.svn-base @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/.svn/prop-base/processor.rb.svn-base b/cli/ruby-debug/.svn/prop-base/processor.rb.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/.svn/prop-base/processor.rb.svn-base @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/.svn/props/command.rb.svn-work b/cli/ruby-debug/.svn/props/command.rb.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/.svn/props/command.rb.svn-work @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/.svn/props/debugger.rb.svn-work b/cli/ruby-debug/.svn/props/debugger.rb.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/.svn/props/debugger.rb.svn-work @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/.svn/props/helper.rb.svn-work b/cli/ruby-debug/.svn/props/helper.rb.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/.svn/props/helper.rb.svn-work @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/.svn/props/interface.rb.svn-work b/cli/ruby-debug/.svn/props/interface.rb.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/.svn/props/interface.rb.svn-work @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/.svn/props/processor.rb.svn-work b/cli/ruby-debug/.svn/props/processor.rb.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/.svn/props/processor.rb.svn-work @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/.svn/text-base/command.rb.svn-base b/cli/ruby-debug/.svn/text-base/command.rb.svn-base new file mode 100644 index 0000000..f424db9 --- /dev/null +++ b/cli/ruby-debug/.svn/text-base/command.rb.svn-base @@ -0,0 +1,228 @@ +require 'rubygems' +require 'columnize' +require 'ruby-debug/helper' + +module Debugger + RUBY_DEBUG_DIR = File.expand_path(File.dirname(__FILE__)) unless + defined?(RUBY_DEBUG_DIR) + + class Command # :nodoc: + SubcmdStruct=Struct.new(:name, :min, :short_help, :long_help) unless + defined?(SubcmdStruct) + + include Columnize + + # Find param in subcmds. param id downcased and can be abbreviated + # to the minimum length listed in the subcommands + def find(subcmds, param) + param.downcase! + for try_subcmd in subcmds do + if (param.size >= try_subcmd.min) and + (try_subcmd.name[0..param.size-1] == param) + return try_subcmd + end + end + return nil + end + + class << self + def commands + @commands ||= [] + end + + DEF_OPTIONS = { + :allow_in_control => false, + :allow_in_post_mortem => true, + :event => true, + :always_run => 0, + :unknown => false, + :need_context => false, + } unless defined?(DEF_OPTIONS) + + def inherited(klass) + DEF_OPTIONS.each do |o, v| + klass.options[o] = v if klass.options[o].nil? + end + commands << klass + end + + def load_commands + Dir[File.join(Debugger.const_get(:RUBY_DEBUG_DIR), 'commands', '*')].each do |file| + require file if file =~ /\.rb$/ + end + Debugger.constants.grep(/Functions$/).map { |name| Debugger.const_get(name) }.each do |mod| + include mod + end + end + + def method_missing(meth, *args, &block) + if meth.to_s =~ /^(.+?)=$/ + @options[$1.intern] = args.first + else + if @options.has_key?(meth) + @options[meth] + else + super + end + end + end + + def options + @options ||= {} + end + + def settings_map + @@settings_map ||= {} + end + private :settings_map + + def settings + unless true and defined? @settings and @settings + @settings = Object.new + map = settings_map + c = class << @settings; self end + if c.respond_to?(:funcall) + c.funcall(:define_method, :[]) do |name| + raise "No such setting #{name}" unless map.has_key?(name) + map[name][:getter].call + end + else + c.send(:define_method, :[]) do |name| + raise "No such setting #{name}" unless map.has_key?(name) + map[name][:getter].call + end + end + c = class << @settings; self end + if c.respond_to?(:funcall) + c.funcall(:define_method, :[]=) do |name, value| + raise "No such setting #{name}" unless map.has_key?(name) + map[name][:setter].call(value) + end + else + c.send(:define_method, :[]=) do |name, value| + raise "No such setting #{name}" unless map.has_key?(name) + map[name][:setter].call(value) + end + end + end + @settings + end + + def register_setting_var(name, default) + var_name = "@@#{name}" + class_variable_set(var_name, default) + register_setting_get(name) { class_variable_get(var_name) } + register_setting_set(name) { |value| class_variable_set(var_name, value) } + end + + def register_setting_get(name, &block) + settings_map[name] ||= {} + settings_map[name][:getter] = block + end + + def register_setting_set(name, &block) + settings_map[name] ||= {} + settings_map[name][:setter] = block + end + end + + register_setting_var(:basename, false) # use basename in showing files? + register_setting_var(:callstyle, :last) + register_setting_var(:debuggertesting, false) + register_setting_var(:force_stepping, false) + register_setting_var(:full_path, true) + register_setting_var(:listsize, 10) # number of lines in list command + register_setting_var(:stack_trace_on_error, false) + register_setting_var(:tracing_plus, false) # different linetrace lines? + + # width of line output. Use COLUMNS value if it exists and is + # not too rediculously large. + width = ENV['COLUMNS'].to_i + width = 80 unless width > 10 + register_setting_var(:width, width) + + if not defined? Debugger::ARGV + Debugger::ARGV = ARGV.clone + end + register_setting_var(:argv, Debugger::ARGV) + + def initialize(state) + @state = state + end + + def match(input) + @match = regexp.match(input) + end + + protected + + # FIXME: use delegate? + def errmsg(*args) + @state.errmsg(*args) + end + + def print(*args) + @state.print(*args) + end + + def confirm(msg) + @state.confirm(msg) == 'y' + end + + def debug_eval(str, b = get_binding) + begin + val = eval(str, b) + rescue StandardError, ScriptError => e + if Command.settings[:stack_trace_on_error] + at = eval("caller(1)", b) + print "%s:%s\n", at.shift, e.to_s.sub(/\(eval\):1:(in `.*?':)?/, '') + for i in at + print "\tfrom %s\n", i + end + else + print "#{e.class} Exception: #{e.message}\n" + end + throw :debug_error + end + end + + def debug_silent_eval(str) + begin + eval(str, get_binding) + rescue StandardError, ScriptError + nil + end + end + + def get_binding + @state.context.frame_binding(@state.frame_pos) + end + + def line_at(file, line) + Debugger.line_at(file, line) + end + + def get_context(thnum) + Debugger.contexts.find{|c| c.thnum == thnum} + end + end + + Command.load_commands + + # Returns setting object. + # Use Debugger.settings[] and Debugger.settings[]= methods to query and set + # debugger settings. These settings are available: + # + # - :autolist - automatically calls 'list' command on breakpoint + # - :autoeval - evaluates input in the current binding if it's not recognized as a debugger command + # - :autoirb - automatically calls 'irb' command on breakpoint + # - :stack_trace_on_error - shows full stack trace if eval command results with an exception + # - :frame_full_path - displays full paths when showing frame stack + # - :frame_class_names - displays method's class name when showing frame stack + # - :reload_source_on_change - makes 'list' command to always display up-to-date source code + # - :force_stepping - stepping command asways move to the new line + # + def self.settings + Command.settings + end +end diff --git a/cli/ruby-debug/.svn/text-base/debugger.rb.svn-base b/cli/ruby-debug/.svn/text-base/debugger.rb.svn-base new file mode 100644 index 0000000..d581c05 --- /dev/null +++ b/cli/ruby-debug/.svn/text-base/debugger.rb.svn-base @@ -0,0 +1,5 @@ +# Module/Package to do the most-common thing: get into the debugger with +# minimal fuss. Compare with: require "debug" +require "ruby-debug" +Debugger.start +debugger \ No newline at end of file diff --git a/cli/ruby-debug/.svn/text-base/helper.rb.svn-base b/cli/ruby-debug/.svn/text-base/helper.rb.svn-base new file mode 100644 index 0000000..f159c3c --- /dev/null +++ b/cli/ruby-debug/.svn/text-base/helper.rb.svn-base @@ -0,0 +1,69 @@ +module Debugger + + module ParseFunctions + Position_regexp = '(?:(\d+)|(.+?)[:.#]([^.:\s]+))' + + # Parse 'str' of command 'cmd' as an integer between + # min and max. If either min or max is nil, that + # value has no bound. + def get_int(str, cmd, min=nil, max=nil, default=1) + return default unless str + begin + int = Integer(str) + if min and int < min + print "%s argument '%s' needs to at least %s.\n" % [cmd, str, min] + return nil + elsif max and int > max + print "%s argument '%s' needs to at most %s.\n" % [cmd, str, max] + return nil + end + return int + rescue + print "%s argument '%s' needs to be a number.\n" % [cmd, str] + return nil + end + end + + # Return true if arg is 'on' or 1 and false arg is 'off' or 0. + # Any other value raises RuntimeError. + def get_onoff(arg, default=nil, print_error=true) + if arg.nil? or arg == '' + if default.nil? + if print_error + print "Expecting 'on', 1, 'off', or 0. Got nothing.\n" + raise RuntimeError + end + return default + end + end + case arg.downcase + when '1', 'on' + return true + when '0', 'off' + return false + else + if print_error + print "Expecting 'on', 1, 'off', or 0. Got: %s.\n" % arg.to_s + raise RuntimeError + end + end + end + + # Return 'on' or 'off' for supplied parameter. The parmeter should + # be true, false or nil. + def show_onoff(bool) + if not [TrueClass, FalseClass, NilClass].member?(bool.class) + return "??" + end + return bool ? 'on' : 'off' + end + + # Return true if code is syntactically correct for Ruby. + def syntax_valid?(code) + eval("BEGIN {return true}\n#{code}", nil, "", 0) + rescue Exception + false + end + + end +end diff --git a/cli/ruby-debug/.svn/text-base/interface.rb.svn-base b/cli/ruby-debug/.svn/text-base/interface.rb.svn-base new file mode 100644 index 0000000..63feea1 --- /dev/null +++ b/cli/ruby-debug/.svn/text-base/interface.rb.svn-base @@ -0,0 +1,232 @@ +module Debugger + class Interface # :nodoc: + attr_writer :have_readline # true if Readline is available + + def initialize + @have_readline = false + end + + # Common routine for reporting debugger error messages. + # Derived classed may want to override this to capture output. + def errmsg(*args) + if Debugger.annotate.to_i > 2 + aprint 'error-begin' + print(*args) + aprint '' + else + print '*** ' + print(*args) + end + end + + # Format msg with gdb-style annotation header + def afmt(msg, newline="\n") + "\032\032#{msg}#{newline}" + end + + def aprint(msg) + print afmt(msg) + end + + end + + class LocalInterface < Interface # :nodoc: + attr_accessor :command_queue + attr_accessor :histfile + attr_accessor :history_save + attr_accessor :history_length + attr_accessor :restart_file + + unless defined?(FILE_HISTORY) + FILE_HISTORY = ".rdebug_hist" + end + def initialize() + super + @command_queue = [] + @have_readline = false + @history_save = true + # take gdb's default + @history_length = ENV["HISTSIZE"] ? ENV["HISTSIZE"].to_i : 256 + @histfile = File.join(ENV["HOME"]||ENV["HOMEPATH"]||".", + FILE_HISTORY) + open(@histfile, 'r') do |file| + file.each do |line| + line.chomp! + Readline::HISTORY << line + end + end if File.exist?(@histfile) + @restart_file = nil + end + + def read_command(prompt) + readline(prompt, true) + end + + def confirm(prompt) + readline(prompt, false) + end + + def print(*args) + STDOUT.printf(*args) + end + + def close + end + + # Things to do before quitting + def finalize + if Debugger.method_defined?("annotate") and Debugger.annotate.to_i > 2 + print "\032\032exited\n\n" + end + if Debugger.respond_to?(:save_history) + Debugger.save_history + end + end + + def readline_support? + @have_readline + end + + private + begin + require 'readline' + class << Debugger + @have_readline = true + define_method(:save_history) do + iface = self.handler.interface + iface.histfile ||= File.join(ENV["HOME"]||ENV["HOMEPATH"]||".", + FILE_HISTORY) + open(iface.histfile, 'w') do |file| + Readline::HISTORY.to_a.last(iface.history_length).each do |line| + file.puts line unless line.strip.empty? + end if defined?(iface.history_save) and iface.history_save + end rescue nil + end + public :save_history + end + Debugger.debug_at_exit do + finalize if respond_to?(:finalize) + end + + def readline(prompt, hist) + Readline::readline(prompt, hist) + end + rescue LoadError + def readline(prompt, hist) + @histfile = '' + @hist_save = false + STDOUT.print prompt + STDOUT.flush + line = STDIN.gets + exit unless line + line.chomp! + line + end + end + end + + class RemoteInterface < Interface # :nodoc: + attr_accessor :command_queue + attr_accessor :histfile + attr_accessor :history_save + attr_accessor :history_length + attr_accessor :restart_file + + def initialize(socket) + @command_queue = [] + @socket = socket + @history_save = false + @history_length = 256 + @histfile = '' + # Do we read the histfile? +# open(@histfile, 'r') do |file| +# file.each do |line| +# line.chomp! +# Readline::HISTORY << line +# end +# end if File.exist?(@histfile) + @restart_file = nil + end + + def close + @socket.close + rescue Exception + end + + def confirm(prompt) + send_command "CONFIRM #{prompt}" + end + + def finalize + end + + def read_command(prompt) + send_command "PROMPT #{prompt}" + end + + def readline_support? + false + end + + def print(*args) + @socket.printf(*args) + end + + private + + def send_command(msg) + @socket.puts msg + result = @socket.gets + raise IOError unless result + result.chomp + end + end + + class ScriptInterface < Interface # :nodoc: + attr_accessor :command_queue + attr_accessor :histfile + attr_accessor :history_save + attr_accessor :history_length + attr_accessor :restart_file + def initialize(file, out, verbose=false) + super() + @command_queue = [] + @file = file.respond_to?(:gets) ? file : open(file) + @out = out + @verbose = verbose + @history_save = false + @history_length = 256 # take gdb default + @histfile = '' + end + + def finalize + end + + def read_command(prompt) + while result = @file.gets + puts "# #{result}" if @verbose + next if result =~ /^\s*#/ + next if result.strip.empty? + break + end + raise IOError unless result + result.chomp! + end + + def readline_support? + false + end + + def confirm(prompt) + 'y' + end + + def print(*args) + @out.printf(*args) + end + + def close + @file.close + end + end +end diff --git a/cli/ruby-debug/.svn/text-base/processor.rb.svn-base b/cli/ruby-debug/.svn/text-base/processor.rb.svn-base new file mode 100644 index 0000000..dbb85a2 --- /dev/null +++ b/cli/ruby-debug/.svn/text-base/processor.rb.svn-base @@ -0,0 +1,474 @@ +require 'ruby-debug/interface' +require 'ruby-debug/command' + +module Debugger + + # Should this be a mixin? + class Processor # :nodoc + attr_accessor :interface + + # Format msg with gdb-style annotation header + def afmt(msg, newline="\n") + "\032\032#{msg}#{newline}" + end + + def aprint(msg) + print afmt(msg) if Debugger.annotate.to_i > 2 + end + + # FIXME: use delegate? + def errmsg(*args) + @interface.errmsg(*args) + end + + # Callers of this routine should make sure to use comma to + # separate format argments rather than %. Otherwise it seems that + # if the string you want to print has format specifier, which + # could happen if you are trying to show say a source-code line + # with "puts" or "print" in it, this print routine will give an + # error saying it is looking for more arguments. + def print(*args) + @interface.print(*args) + end + + end + + class CommandProcessor < Processor # :nodoc: + attr_reader :display + + # FIXME: get from Command regexp method. + @@Show_breakpoints_postcmd = [ + /^\s*b(?:reak)?/, + /^\s* cond(?:ition)? (?:\s+(\d+)\s*(.*))?$/ix, + /^\s*del(?:ete)?(?:\s+(.*))?$/ix, + /^\s* dis(?:able)? (?:\s+(.*))?$/ix, + /^\s* en(?:able)? (?:\s+(.*))?$/ix, + # "tbreak", "clear", + ] + @@Show_annotations_run = [ + /^\s*c(?:ont(?:inue)?)?(?:\s+(.*))?$/, + /^\s*fin(?:ish)?$/, + /^\s*n(?:ext)?([+-])?(?:\s+(.*))?$/, + /^\s*s(?:tep)?([+-])?(?:\s+(.*))?$/ + ] + + @@Show_annotations_postcmd = [ + /^\s* down (?:\s+(.*))? .*$/x, + /^\s* f(?:rame)? (?:\s+ (.*))? \s*$/x, + /^\s* u(?:p)? (?:\s+(.*))?$/x + ] + + def initialize(interface = LocalInterface.new) + @interface = interface + @display = [] + + @mutex = Mutex.new + @last_cmd = nil + @last_file = nil # Filename the last time we stopped + @last_line = nil # line number the last time we stopped + @debugger_breakpoints_were_empty = false # Show breakpoints 1st time + @debugger_displays_were_empty = true # No display 1st time + @debugger_context_was_dead = true # Assume we haven't started. + end + + def interface=(interface) + @mutex.synchronize do + @interface.close if @interface + @interface = interface + end + end + + require 'pathname' # For cleanpath + + # Regularize file name. + # This is also used as a common funnel place if basename is + # desired or if we are working remotely and want to change the + # basename. Or we are eliding filenames. + def self.canonic_file(filename) + # For now we want resolved filenames + if Command.settings[:basename] + File.basename(filename) + else + # Cache this? + Pathname.new(filename).cleanpath.to_s + end + end + + def self.print_location_and_text(file, line) + file_line = "%s:%s\n%s" % [canonic_file(file), line, + Debugger.line_at(file, line)] + # FIXME: use annotations routines + if Debugger.annotate.to_i > 2 + file_line = "\032\032source #{file_line}" + elsif ENV['EMACS'] + file_line = "\032\032#{file_line}" + end + print file_line + end + + def self.protect(mname) + alias_method "__#{mname}", mname + module_eval %{ + def #{mname}(*args) + @mutex.synchronize do + return unless @interface + __#{mname}(*args) + end + rescue IOError, Errno::EPIPE + self.interface = nil + rescue SignalException + raise + rescue Exception + print "INTERNAL ERROR!!! #\{$!\}\n" rescue nil + print $!.backtrace.map{|l| "\t#\{l\}"}.join("\n") rescue nil + end + } + end + + def at_breakpoint(context, breakpoint) + aprint 'stopped' if Debugger.annotate.to_i > 2 + n = Debugger.breakpoints.index(breakpoint) + 1 + file = CommandProcessor.canonic_file(breakpoint.source) + line = breakpoint.pos + if Debugger.annotate.to_i > 2 + print afmt("source #{file}:#{line}") + end + print "Breakpoint %d at %s:%s\n", n, file, line + end + protect :at_breakpoint + + def at_catchpoint(context, excpt) + aprint 'stopped' if Debugger.annotate.to_i > 2 + file = CommandProcessor.canonic_file(context.frame_file(0)) + line = context.frame_line(0) + print afmt("%s:%d" % [file, line]) if ENV['EMACS'] + print "Catchpoint at %s:%d: `%s' (%s)\n", file, line, excpt, excpt.class + fs = context.stack_size + tb = caller(0)[-fs..-1] + if tb + for i in tb + print "\tfrom %s\n", i + end + end + end + protect :at_catchpoint + + def at_tracing(context, file, line) + return if defined?(Debugger::RDEBUG_FILE) && + Debugger::RDEBUG_FILE == file # Don't trace ourself + @last_file = CommandProcessor.canonic_file(file) + file = CommandProcessor.canonic_file(file) + unless file == @last_file and @last_line == line and + Command.settings[:tracing_plus] + print "Tracing(%d):%s:%s %s", + context.thnum, file, line, Debugger.line_at(file, line) + @last_file = file + @last_line = line + end + always_run(context, file, line, 2) + end + protect :at_tracing + + def at_line(context, file, line) + process_commands(context, file, line) + end + protect :at_line + + def at_return(context, file, line) + context.stop_frame = -1 + process_commands(context, file, line) + end + + private + + # The prompt shown before reading a command. + def prompt(context) + p = '(rdb:%s) ' % (context.dead? ? 'post-mortem' : context.thnum) + p = afmt("pre-prompt")+p+"\n"+afmt("prompt") if + Debugger.annotate.to_i > 2 + return p + end + + # Run these commands, for example display commands or possibly + # the list or irb in an "autolist" or "autoirb". + # We return a list of commands that are acceptable to run bound + # to the current state. + def always_run(context, file, line, run_level) + event_cmds = Command.commands.select{|cmd| cmd.event } + + # Remove some commands in post-mortem + event_cmds = event_cmds.find_all do |cmd| + cmd.allow_in_post_mortem + end if context.dead? + + state = State.new do |s| + s.context = context + s.file = file + s.line = line + s.binding = context.frame_binding(0) + s.display = display + s.interface = interface + s.commands = event_cmds + end + @interface.state = state if @interface.respond_to?('state=') + + # Bind commands to the current state. + commands = event_cmds.map{|cmd| cmd.new(state)} + + commands.select do |cmd| + cmd.class.always_run >= run_level + end.each {|cmd| cmd.execute} + return state, commands + end + + # Handle debugger commands + def process_commands(context, file, line) + state, commands = always_run(context, file, line, 1) + $rdebug_state = state if Command.settings[:debuggertesting] + splitter = lambda do |str| + str.split(/;/).inject([]) do |m, v| + if m.empty? + m << v + else + if m.last[-1] == ?\\ + m.last[-1,1] = '' + m.last << ';' << v + else + m << v + end + end + m + end + end + + preloop(commands, context) + CommandProcessor.print_location_and_text(file, line) + while !state.proceed? + input = if @interface.command_queue.empty? + @interface.read_command(prompt(context)) + else + @interface.command_queue.shift + end + break unless input + catch(:debug_error) do + if input == "" + next unless @last_cmd + input = @last_cmd + else + @last_cmd = input + end + splitter[input].each do |cmd| + one_cmd(commands, context, cmd) + postcmd(commands, context, cmd) + end + end + end + postloop(commands, context) + end # process_commands + + def one_cmd(commands, context, input) + if cmd = commands.find{ |c| c.match(input) } + if context.dead? && cmd.class.need_context + p cmd + print "Command is unavailable\n" + else + cmd.execute + end + else + unknown_cmd = commands.find{|cmd| cmd.class.unknown } + if unknown_cmd + unknown_cmd.execute + else + errmsg "Unknown command: \"#{input}\". Try \"help\".\n" + end + end + end + + def preloop(commands, context) + aprint('stopped') if Debugger.annotate.to_i > 2 + if context.dead? + unless @debugger_context_was_dead + if Debugger.annotate.to_i > 2 + aprint('exited') + print "The program finished.\n" + end + @debugger_context_was_dead = true + end + end + + if Debugger.annotate.to_i > 2 + # if we are here, the stack frames have changed outside the + # command loop (e.g. after a "continue" command), so we show + # the annotations again + breakpoint_annotations(commands, context) + display_annotations(commands, context) + annotation('stack', commands, context, "where") + annotation('variables', commands, context, "info variables") unless + context.dead? + end + end + + def postcmd(commands, context, cmd) + if Debugger.annotate.to_i > 0 + cmd = @last_cmd unless cmd + breakpoint_annotations(commands, context) if + @@Show_breakpoints_postcmd.find{|pat| cmd =~ pat} + display_annotations(commands, context) + if @@Show_annotations_postcmd.find{|pat| cmd =~ pat} + annotation('stack', commands, context, "where") if + context.stack_size > 0 + annotation('variables', commands, context, "info variables") unless + context.dead? + end + if not context.dead? and @@Show_annotations_run.find{|pat| cmd =~ pat} + aprint 'starting' if Debugger.annotate.to_i > 2 + + @debugger_context_was_dead = false + end + end + end + + def postloop(commands, context) + end + + def annotation(label, commands, context, cmd) + print afmt(label) + one_cmd(commands, context, cmd) + ### FIXME ANNOTATE: the following line should be deleted + print "\032\032\n" + end + + def breakpoint_annotations(commands, context) + unless Debugger.breakpoints.empty? and @debugger_breakpoints_were_empty + annotation('breakpoints', commands, context, "info breakpoints") + @debugger_breakpoints_were_empty = Debugger.breakpoints.empty? + end + end + + def display_annotations(commands, context) + return if display.empty? +# have_display = display.find{|d| d[0]} +# return unless have_display and @debugger_displays_were_empty +# @debugger_displays_were_empty = have_display + annotation('display', commands, context, "display") + end + + class State # :nodoc: + attr_accessor :context, :file, :line, :binding + attr_accessor :frame_pos, :previous_line, :display + attr_accessor :interface, :commands + + def initialize + super() + @frame_pos = 0 + @previous_line = nil + @proceed = false + yield self + end + + # FIXME: use delegate? + def errmsg(*args) + @interface.errmsg(*args) + end + + def print(*args) + @interface.print(*args) + end + + def confirm(*args) + @interface.confirm(*args) + end + + def proceed? + @proceed + end + + def proceed + @proceed = true + end + end + end + + class ControlCommandProcessor < Processor # :nodoc: + def initialize(interface) + super() + @interface = interface + @debugger_context_was_dead = true # Assume we haven't started. + end + + def process_commands(verbose=false) + control_cmds = Command.commands.select do |cmd| + cmd.allow_in_control + end + state = State.new(@interface, control_cmds) + commands = control_cmds.map{|cmd| cmd.new(state) } + + unless @debugger_context_was_dead + if Debugger.annotate.to_i > 2 + aprint 'exited' + print "The program finished.\n" + end + @debugger_context_was_dead = true + end + + while input = @interface.read_command(prompt(nil)) + print "+#{input}" if verbose + catch(:debug_error) do + if cmd = commands.find{|c| c.match(input) } + cmd.execute + else + errmsg "Unknown command\n" + end + end + end + rescue IOError, Errno::EPIPE + rescue Exception + print "INTERNAL ERROR!!! #{$!}\n" rescue nil + print $!.backtrace.map{|l| "\t#{l}"}.join("\n") rescue nil + ensure + @interface.close + end + + # The prompt shown before reading a command. + # Note: have an unused 'context' parameter to match the local interface. + def prompt(context) + p = '(rdb:ctrl) ' + p = afmt("pre-prompt")+p+"\n"+afmt("prompt") if + Debugger.annotate.to_i > 2 + return p + end + + class State # :nodoc: + attr_reader :commands, :interface + + def initialize(interface, commands) + @interface = interface + @commands = commands + end + + def proceed + end + + def errmsg(*args) + @interface.print(*args) + end + + def print(*args) + @interface.print(*args) + end + + def confirm(*args) + 'y' + end + + def context + nil + end + + def file + errmsg "No filename given.\n" + throw :debug_error + end + end # State + end +end diff --git a/cli/ruby-debug/command.rb b/cli/ruby-debug/command.rb new file mode 100644 index 0000000..f424db9 --- /dev/null +++ b/cli/ruby-debug/command.rb @@ -0,0 +1,228 @@ +require 'rubygems' +require 'columnize' +require 'ruby-debug/helper' + +module Debugger + RUBY_DEBUG_DIR = File.expand_path(File.dirname(__FILE__)) unless + defined?(RUBY_DEBUG_DIR) + + class Command # :nodoc: + SubcmdStruct=Struct.new(:name, :min, :short_help, :long_help) unless + defined?(SubcmdStruct) + + include Columnize + + # Find param in subcmds. param id downcased and can be abbreviated + # to the minimum length listed in the subcommands + def find(subcmds, param) + param.downcase! + for try_subcmd in subcmds do + if (param.size >= try_subcmd.min) and + (try_subcmd.name[0..param.size-1] == param) + return try_subcmd + end + end + return nil + end + + class << self + def commands + @commands ||= [] + end + + DEF_OPTIONS = { + :allow_in_control => false, + :allow_in_post_mortem => true, + :event => true, + :always_run => 0, + :unknown => false, + :need_context => false, + } unless defined?(DEF_OPTIONS) + + def inherited(klass) + DEF_OPTIONS.each do |o, v| + klass.options[o] = v if klass.options[o].nil? + end + commands << klass + end + + def load_commands + Dir[File.join(Debugger.const_get(:RUBY_DEBUG_DIR), 'commands', '*')].each do |file| + require file if file =~ /\.rb$/ + end + Debugger.constants.grep(/Functions$/).map { |name| Debugger.const_get(name) }.each do |mod| + include mod + end + end + + def method_missing(meth, *args, &block) + if meth.to_s =~ /^(.+?)=$/ + @options[$1.intern] = args.first + else + if @options.has_key?(meth) + @options[meth] + else + super + end + end + end + + def options + @options ||= {} + end + + def settings_map + @@settings_map ||= {} + end + private :settings_map + + def settings + unless true and defined? @settings and @settings + @settings = Object.new + map = settings_map + c = class << @settings; self end + if c.respond_to?(:funcall) + c.funcall(:define_method, :[]) do |name| + raise "No such setting #{name}" unless map.has_key?(name) + map[name][:getter].call + end + else + c.send(:define_method, :[]) do |name| + raise "No such setting #{name}" unless map.has_key?(name) + map[name][:getter].call + end + end + c = class << @settings; self end + if c.respond_to?(:funcall) + c.funcall(:define_method, :[]=) do |name, value| + raise "No such setting #{name}" unless map.has_key?(name) + map[name][:setter].call(value) + end + else + c.send(:define_method, :[]=) do |name, value| + raise "No such setting #{name}" unless map.has_key?(name) + map[name][:setter].call(value) + end + end + end + @settings + end + + def register_setting_var(name, default) + var_name = "@@#{name}" + class_variable_set(var_name, default) + register_setting_get(name) { class_variable_get(var_name) } + register_setting_set(name) { |value| class_variable_set(var_name, value) } + end + + def register_setting_get(name, &block) + settings_map[name] ||= {} + settings_map[name][:getter] = block + end + + def register_setting_set(name, &block) + settings_map[name] ||= {} + settings_map[name][:setter] = block + end + end + + register_setting_var(:basename, false) # use basename in showing files? + register_setting_var(:callstyle, :last) + register_setting_var(:debuggertesting, false) + register_setting_var(:force_stepping, false) + register_setting_var(:full_path, true) + register_setting_var(:listsize, 10) # number of lines in list command + register_setting_var(:stack_trace_on_error, false) + register_setting_var(:tracing_plus, false) # different linetrace lines? + + # width of line output. Use COLUMNS value if it exists and is + # not too rediculously large. + width = ENV['COLUMNS'].to_i + width = 80 unless width > 10 + register_setting_var(:width, width) + + if not defined? Debugger::ARGV + Debugger::ARGV = ARGV.clone + end + register_setting_var(:argv, Debugger::ARGV) + + def initialize(state) + @state = state + end + + def match(input) + @match = regexp.match(input) + end + + protected + + # FIXME: use delegate? + def errmsg(*args) + @state.errmsg(*args) + end + + def print(*args) + @state.print(*args) + end + + def confirm(msg) + @state.confirm(msg) == 'y' + end + + def debug_eval(str, b = get_binding) + begin + val = eval(str, b) + rescue StandardError, ScriptError => e + if Command.settings[:stack_trace_on_error] + at = eval("caller(1)", b) + print "%s:%s\n", at.shift, e.to_s.sub(/\(eval\):1:(in `.*?':)?/, '') + for i in at + print "\tfrom %s\n", i + end + else + print "#{e.class} Exception: #{e.message}\n" + end + throw :debug_error + end + end + + def debug_silent_eval(str) + begin + eval(str, get_binding) + rescue StandardError, ScriptError + nil + end + end + + def get_binding + @state.context.frame_binding(@state.frame_pos) + end + + def line_at(file, line) + Debugger.line_at(file, line) + end + + def get_context(thnum) + Debugger.contexts.find{|c| c.thnum == thnum} + end + end + + Command.load_commands + + # Returns setting object. + # Use Debugger.settings[] and Debugger.settings[]= methods to query and set + # debugger settings. These settings are available: + # + # - :autolist - automatically calls 'list' command on breakpoint + # - :autoeval - evaluates input in the current binding if it's not recognized as a debugger command + # - :autoirb - automatically calls 'irb' command on breakpoint + # - :stack_trace_on_error - shows full stack trace if eval command results with an exception + # - :frame_full_path - displays full paths when showing frame stack + # - :frame_class_names - displays method's class name when showing frame stack + # - :reload_source_on_change - makes 'list' command to always display up-to-date source code + # - :force_stepping - stepping command asways move to the new line + # + def self.settings + Command.settings + end +end diff --git a/cli/ruby-debug/commands/.svn/README.txt b/cli/ruby-debug/commands/.svn/README.txt new file mode 100644 index 0000000..271a8ce --- /dev/null +++ b/cli/ruby-debug/commands/.svn/README.txt @@ -0,0 +1,2 @@ +This is a Subversion working copy administrative directory. +Visit http://subversion.tigris.org/ for more information. diff --git a/cli/ruby-debug/commands/.svn/empty-file b/cli/ruby-debug/commands/.svn/empty-file new file mode 100644 index 0000000..e69de29 diff --git a/cli/ruby-debug/commands/.svn/entries b/cli/ruby-debug/commands/.svn/entries new file mode 100644 index 0000000..4c0ebeb --- /dev/null +++ b/cli/ruby-debug/commands/.svn/entries @@ -0,0 +1,265 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cli/ruby-debug/commands/.svn/format b/cli/ruby-debug/commands/.svn/format new file mode 100644 index 0000000..b8626c4 --- /dev/null +++ b/cli/ruby-debug/commands/.svn/format @@ -0,0 +1 @@ +4 diff --git a/cli/ruby-debug/commands/.svn/prop-base/breakpoints.rb.svn-base b/cli/ruby-debug/commands/.svn/prop-base/breakpoints.rb.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/commands/.svn/prop-base/breakpoints.rb.svn-base @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/commands/.svn/prop-base/catchpoint.rb.svn-base b/cli/ruby-debug/commands/.svn/prop-base/catchpoint.rb.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/commands/.svn/prop-base/catchpoint.rb.svn-base @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/commands/.svn/prop-base/condition.rb.svn-base b/cli/ruby-debug/commands/.svn/prop-base/condition.rb.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/commands/.svn/prop-base/condition.rb.svn-base @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/commands/.svn/prop-base/continue.rb.svn-base b/cli/ruby-debug/commands/.svn/prop-base/continue.rb.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/commands/.svn/prop-base/continue.rb.svn-base @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/commands/.svn/prop-base/control.rb.svn-base b/cli/ruby-debug/commands/.svn/prop-base/control.rb.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/commands/.svn/prop-base/control.rb.svn-base @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/commands/.svn/prop-base/display.rb.svn-base b/cli/ruby-debug/commands/.svn/prop-base/display.rb.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/commands/.svn/prop-base/display.rb.svn-base @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/commands/.svn/prop-base/edit.rb.svn-base b/cli/ruby-debug/commands/.svn/prop-base/edit.rb.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/commands/.svn/prop-base/edit.rb.svn-base @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/commands/.svn/prop-base/enable.rb.svn-base b/cli/ruby-debug/commands/.svn/prop-base/enable.rb.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/commands/.svn/prop-base/enable.rb.svn-base @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/commands/.svn/prop-base/eval.rb.svn-base b/cli/ruby-debug/commands/.svn/prop-base/eval.rb.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/commands/.svn/prop-base/eval.rb.svn-base @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/commands/.svn/prop-base/finish.rb.svn-base b/cli/ruby-debug/commands/.svn/prop-base/finish.rb.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/commands/.svn/prop-base/finish.rb.svn-base @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/commands/.svn/prop-base/frame.rb.svn-base b/cli/ruby-debug/commands/.svn/prop-base/frame.rb.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/commands/.svn/prop-base/frame.rb.svn-base @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/commands/.svn/prop-base/help.rb.svn-base b/cli/ruby-debug/commands/.svn/prop-base/help.rb.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/commands/.svn/prop-base/help.rb.svn-base @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/commands/.svn/prop-base/info.rb.svn-base b/cli/ruby-debug/commands/.svn/prop-base/info.rb.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/commands/.svn/prop-base/info.rb.svn-base @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/commands/.svn/prop-base/irb.rb.svn-base b/cli/ruby-debug/commands/.svn/prop-base/irb.rb.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/commands/.svn/prop-base/irb.rb.svn-base @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/commands/.svn/prop-base/kill.rb.svn-base b/cli/ruby-debug/commands/.svn/prop-base/kill.rb.svn-base new file mode 100644 index 0000000..bdbd305 --- /dev/null +++ b/cli/ruby-debug/commands/.svn/prop-base/kill.rb.svn-base @@ -0,0 +1,5 @@ +K 13 +svn:eol-style +V 6 +native +END diff --git a/cli/ruby-debug/commands/.svn/prop-base/list.rb.svn-base b/cli/ruby-debug/commands/.svn/prop-base/list.rb.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/commands/.svn/prop-base/list.rb.svn-base @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/commands/.svn/prop-base/method.rb.svn-base b/cli/ruby-debug/commands/.svn/prop-base/method.rb.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/commands/.svn/prop-base/method.rb.svn-base @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/commands/.svn/prop-base/quit.rb.svn-base b/cli/ruby-debug/commands/.svn/prop-base/quit.rb.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/commands/.svn/prop-base/quit.rb.svn-base @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/commands/.svn/prop-base/reload.rb.svn-base b/cli/ruby-debug/commands/.svn/prop-base/reload.rb.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/commands/.svn/prop-base/reload.rb.svn-base @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/commands/.svn/prop-base/save.rb.svn-base b/cli/ruby-debug/commands/.svn/prop-base/save.rb.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/commands/.svn/prop-base/save.rb.svn-base @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/commands/.svn/prop-base/set.rb.svn-base b/cli/ruby-debug/commands/.svn/prop-base/set.rb.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/commands/.svn/prop-base/set.rb.svn-base @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/commands/.svn/prop-base/show.rb.svn-base b/cli/ruby-debug/commands/.svn/prop-base/show.rb.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/commands/.svn/prop-base/show.rb.svn-base @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/commands/.svn/prop-base/source.rb.svn-base b/cli/ruby-debug/commands/.svn/prop-base/source.rb.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/commands/.svn/prop-base/source.rb.svn-base @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/commands/.svn/prop-base/stepping.rb.svn-base b/cli/ruby-debug/commands/.svn/prop-base/stepping.rb.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/commands/.svn/prop-base/stepping.rb.svn-base @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/commands/.svn/prop-base/threads.rb.svn-base b/cli/ruby-debug/commands/.svn/prop-base/threads.rb.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/commands/.svn/prop-base/threads.rb.svn-base @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/commands/.svn/prop-base/tmate.rb.svn-base b/cli/ruby-debug/commands/.svn/prop-base/tmate.rb.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/commands/.svn/prop-base/tmate.rb.svn-base @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/commands/.svn/prop-base/trace.rb.svn-base b/cli/ruby-debug/commands/.svn/prop-base/trace.rb.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/commands/.svn/prop-base/trace.rb.svn-base @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/commands/.svn/prop-base/variables.rb.svn-base b/cli/ruby-debug/commands/.svn/prop-base/variables.rb.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/commands/.svn/prop-base/variables.rb.svn-base @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/commands/.svn/props/breakpoints.rb.svn-work b/cli/ruby-debug/commands/.svn/props/breakpoints.rb.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/commands/.svn/props/breakpoints.rb.svn-work @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/commands/.svn/props/catchpoint.rb.svn-work b/cli/ruby-debug/commands/.svn/props/catchpoint.rb.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/commands/.svn/props/catchpoint.rb.svn-work @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/commands/.svn/props/condition.rb.svn-work b/cli/ruby-debug/commands/.svn/props/condition.rb.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/commands/.svn/props/condition.rb.svn-work @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/commands/.svn/props/continue.rb.svn-work b/cli/ruby-debug/commands/.svn/props/continue.rb.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/commands/.svn/props/continue.rb.svn-work @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/commands/.svn/props/control.rb.svn-work b/cli/ruby-debug/commands/.svn/props/control.rb.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/commands/.svn/props/control.rb.svn-work @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/commands/.svn/props/display.rb.svn-work b/cli/ruby-debug/commands/.svn/props/display.rb.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/commands/.svn/props/display.rb.svn-work @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/commands/.svn/props/edit.rb.svn-work b/cli/ruby-debug/commands/.svn/props/edit.rb.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/commands/.svn/props/edit.rb.svn-work @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/commands/.svn/props/enable.rb.svn-work b/cli/ruby-debug/commands/.svn/props/enable.rb.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/commands/.svn/props/enable.rb.svn-work @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/commands/.svn/props/eval.rb.svn-work b/cli/ruby-debug/commands/.svn/props/eval.rb.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/commands/.svn/props/eval.rb.svn-work @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/commands/.svn/props/finish.rb.svn-work b/cli/ruby-debug/commands/.svn/props/finish.rb.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/commands/.svn/props/finish.rb.svn-work @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/commands/.svn/props/frame.rb.svn-work b/cli/ruby-debug/commands/.svn/props/frame.rb.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/commands/.svn/props/frame.rb.svn-work @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/commands/.svn/props/help.rb.svn-work b/cli/ruby-debug/commands/.svn/props/help.rb.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/commands/.svn/props/help.rb.svn-work @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/commands/.svn/props/info.rb.svn-work b/cli/ruby-debug/commands/.svn/props/info.rb.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/commands/.svn/props/info.rb.svn-work @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/commands/.svn/props/irb.rb.svn-work b/cli/ruby-debug/commands/.svn/props/irb.rb.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/commands/.svn/props/irb.rb.svn-work @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/commands/.svn/props/kill.rb.svn-work b/cli/ruby-debug/commands/.svn/props/kill.rb.svn-work new file mode 100644 index 0000000..bdbd305 --- /dev/null +++ b/cli/ruby-debug/commands/.svn/props/kill.rb.svn-work @@ -0,0 +1,5 @@ +K 13 +svn:eol-style +V 6 +native +END diff --git a/cli/ruby-debug/commands/.svn/props/list.rb.svn-work b/cli/ruby-debug/commands/.svn/props/list.rb.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/commands/.svn/props/list.rb.svn-work @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/commands/.svn/props/method.rb.svn-work b/cli/ruby-debug/commands/.svn/props/method.rb.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/commands/.svn/props/method.rb.svn-work @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/commands/.svn/props/quit.rb.svn-work b/cli/ruby-debug/commands/.svn/props/quit.rb.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/commands/.svn/props/quit.rb.svn-work @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/commands/.svn/props/reload.rb.svn-work b/cli/ruby-debug/commands/.svn/props/reload.rb.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/commands/.svn/props/reload.rb.svn-work @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/commands/.svn/props/save.rb.svn-work b/cli/ruby-debug/commands/.svn/props/save.rb.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/commands/.svn/props/save.rb.svn-work @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/commands/.svn/props/set.rb.svn-work b/cli/ruby-debug/commands/.svn/props/set.rb.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/commands/.svn/props/set.rb.svn-work @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/commands/.svn/props/show.rb.svn-work b/cli/ruby-debug/commands/.svn/props/show.rb.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/commands/.svn/props/show.rb.svn-work @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/commands/.svn/props/source.rb.svn-work b/cli/ruby-debug/commands/.svn/props/source.rb.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/commands/.svn/props/source.rb.svn-work @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/commands/.svn/props/stepping.rb.svn-work b/cli/ruby-debug/commands/.svn/props/stepping.rb.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/commands/.svn/props/stepping.rb.svn-work @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/commands/.svn/props/threads.rb.svn-work b/cli/ruby-debug/commands/.svn/props/threads.rb.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/commands/.svn/props/threads.rb.svn-work @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/commands/.svn/props/tmate.rb.svn-work b/cli/ruby-debug/commands/.svn/props/tmate.rb.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/commands/.svn/props/tmate.rb.svn-work @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/commands/.svn/props/trace.rb.svn-work b/cli/ruby-debug/commands/.svn/props/trace.rb.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/commands/.svn/props/trace.rb.svn-work @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/commands/.svn/props/variables.rb.svn-work b/cli/ruby-debug/commands/.svn/props/variables.rb.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/cli/ruby-debug/commands/.svn/props/variables.rb.svn-work @@ -0,0 +1 @@ +END diff --git a/cli/ruby-debug/commands/.svn/text-base/breakpoints.rb.svn-base b/cli/ruby-debug/commands/.svn/text-base/breakpoints.rb.svn-base new file mode 100644 index 0000000..d3b9901 --- /dev/null +++ b/cli/ruby-debug/commands/.svn/text-base/breakpoints.rb.svn-base @@ -0,0 +1,153 @@ +module Debugger + + # Implements debugger "break" command. + class AddBreakpoint < Command + self.allow_in_control = true + + def regexp + / ^\s* + b(?:reak)? + (?: \s+ #{Position_regexp})? \s* + (?: \s+ (.*))? \s* + $ + /x + end + + def execute + if @match[1] + line, _, _, expr = @match.captures + else + _, file, line, expr = @match.captures + end + if expr + if expr !~ /^\s*if\s+(.+)/ + if file or line + errmsg "Expecting 'if' in breakpoint condition; got: #{expr}.\n" + else + errmsg "Invalid breakpoint location: #{expr}.\n" + end + return + else + expr = $1 + end + end + + brkpt_filename = nil + if file.nil? + unless @state.context + errmsg "We are not in a state that has an associated file.\n" + return + end + brkpt_filename = @state.file + file = File.basename(@state.file) + if line.nil? + # Set breakpoint at current line + line = @state.line.to_s + end + elsif line !~ /^\d+$/ + # See if "line" is a method/function name + klass = debug_silent_eval(file) + if klass && klass.kind_of?(Module) + class_name = klass.name if klass + else + errmsg "Unknown class #{file}.\n" + throw :debug_error + end + else + # FIXME: This should be done in LineCache. + file = File.expand_path(file) if file.index(File::SEPARATOR) || \ + File::ALT_SEPARATOR && file.index(File::ALT_SEPARATOR) + brkpt_filename = file + end + + if line =~ /^\d+$/ + line = line.to_i + if LineCache.cache(brkpt_filename, Command.settings[:reload_source_on_change]) + last_line = LineCache.size(brkpt_filename) + if line > last_line + errmsg("There are only %d lines in file \"%s\".\n", last_line, file) + return + end + unless LineCache.trace_line_numbers(brkpt_filename).member?(line) + errmsg("Line %d is not a stopping point in file \"%s\".\n", line, file) + return + end + else + errmsg("No source file named %s\n" % file) + return unless confirm("Set breakpoint anyway? (y/n) ") + end + + unless @state.context + errmsg "We are not in a state we can add breakpoints.\n" + return + end + b = Debugger.add_breakpoint brkpt_filename, line, expr + print "Breakpoint %d file %s, line %s\n", b.id, brkpt_filename, line.to_s + unless syntax_valid?(expr) + errmsg("Expression \"#{expr}\" syntactically incorrect; breakpoint disabled.\n") + b.enabled = false + end + else + method = line.intern.id2name + b = Debugger.add_breakpoint class_name, method, expr + print "Breakpoint %d at %s::%s\n", b.id, class_name, method.to_s + end + end + + class << self + def help_command + 'break' + end + + def help(cmd) + %{ + b[reak] file:line [if expr] + b[reak] class(.|#)method [if expr] + \tset breakpoint to some position, (optionally) if expr == true + } + end + end + end + + # Implements debugger "delete" command. + class DeleteBreakpointCommand < Command + self.allow_in_control = true + + def regexp + /^\s *del(?:ete)? (?:\s+(.*))?$/ix + end + + def execute + unless @state.context + errmsg "We are not in a state we can delete breakpoints.\n" + return + end + brkpts = @match[1] + unless brkpts + if confirm("Delete all breakpoints? (y or n) ") + Debugger.breakpoints.clear + end + else + brkpts.split(/[ \t]+/).each do |pos| + pos = get_int(pos, "Delete", 1) + return unless pos + unless Debugger.remove_breakpoint(pos) + errmsg "No breakpoint number %d\n", pos + end + end + end + end + + class << self + def help_command + 'delete' + end + + def help(cmd) + %{ + del[ete][ nnn...]\tdelete some or all breakpoints + } + end + end + end +end diff --git a/cli/ruby-debug/commands/.svn/text-base/catchpoint.rb.svn-base b/cli/ruby-debug/commands/.svn/text-base/catchpoint.rb.svn-base new file mode 100644 index 0000000..964f6ab --- /dev/null +++ b/cli/ruby-debug/commands/.svn/text-base/catchpoint.rb.svn-base @@ -0,0 +1,55 @@ +module Debugger + class CatchCommand < Command # :nodoc: + self.allow_in_control = true + + def regexp + /^\s* cat(?:ch)? + (?:\s+ (\S+))? + (?:\s+ (off))? \s* $/ix + end + + def execute + excn = @match[1] + if not excn + # No args given. + info_catch + elsif not @match[2] + # One arg given. + if 'off' == excn + Debugger.catchpoints.clear if + confirm("Delete all catchpoints? (y or n) ") + else + binding = @state.context ? get_binding : TOPLEVEL_BINDING + unless debug_eval("#{excn}.is_a?(Class)", binding) + print "Warning #{excn} is not known to be a Class\n" + end + Debugger.add_catchpoint(excn) + print "Catch exception %s.\n", excn + end + elsif @match[2] != 'off' + errmsg "Off expected. Got %s\n", @match[2] + elsif Debugger.catchpoints.member?(excn) + Debugger.catchpoints.delete(excn) + print "Catch for exception %s removed.\n", excn + else + errmsg "Catch for exception %s not found.\n", excn + end + end + + class << self + def help_command + 'catch' + end + + def help(cmd) + %{ + cat[ch]\t\tsame as "info catch" + cat[ch] [on|off] +\tIntercept when there would otherwise be no handler. +\tWith an "on" or "off", turn handling the exception on or off. + cat[ch] off\tdelete all catchpoints + } + end + end + end +end diff --git a/cli/ruby-debug/commands/.svn/text-base/condition.rb.svn-base b/cli/ruby-debug/commands/.svn/text-base/condition.rb.svn-base new file mode 100644 index 0000000..322812e --- /dev/null +++ b/cli/ruby-debug/commands/.svn/text-base/condition.rb.svn-base @@ -0,0 +1,49 @@ +module Debugger + + class ConditionCommand < Command # :nodoc: + + def regexp + /^\s* cond(?:ition)? (?:\s+(\d+)\s*(.*))?$/ix + end + + def execute + if not @match[1] + errmsg "\"condition\" must be followed a breakpoint number and expression\n" + else + breakpoints = Debugger.breakpoints.sort_by{|b| b.id } + largest = breakpoints.inject(0) do |largest, b| + largest = b.id if b.id > largest + end + if 0 == largest + print "No breakpoints have been set.\n" + return + end + pos = get_int(@match[1], "Condition", 1, largest) + return unless pos + breakpoints.each do |b| + if b.id == pos + b.expr = @match[2].empty? ? nil : @match[2] + break + end + end + + end + end + + class << self + def help_command + 'condition' + end + + def help(cmd) + %{ + Condition breakpoint-number expression +Specify breakpoint number N to break only if COND is true. +N is an integer and COND is an expression to be evaluated whenever +breakpoint N is reached. If the empty string is used, the condition is removed. + } + end + end + end + +end # module Debugger diff --git a/cli/ruby-debug/commands/.svn/text-base/continue.rb.svn-base b/cli/ruby-debug/commands/.svn/text-base/continue.rb.svn-base new file mode 100644 index 0000000..5bee4b3 --- /dev/null +++ b/cli/ruby-debug/commands/.svn/text-base/continue.rb.svn-base @@ -0,0 +1,38 @@ +module Debugger + + # Implements debugger "continue" command. + class ContinueCommand < Command + self.allow_in_post_mortem = true + self.need_context = false + def regexp + /^\s* c(?:ont(?:inue)?)? (?:\s+(.*))? $/x + end + + def execute + if @match[1] && !@state.context.dead? + filename = File.expand_path(@state.file) + line_number = get_int(@match[1], "Continue", 0, nil, 0) + return unless line_number + unless LineCache.trace_line_numbers(filename).member?(line_number) + errmsg("Line %d is not a stopping point in file \"%s\".\n", + line_number, filename) + return + end + @state.context.set_breakpoint(filename, line_number) + end + @state.proceed + end + + class << self + def help_command + 'continue' + end + + def help(cmd) + %{ + c[ont[inue]][ nnn]\trun until program ends, hits a breakpoint or reaches line nnn + } + end + end + end +end diff --git a/cli/ruby-debug/commands/.svn/text-base/control.rb.svn-base b/cli/ruby-debug/commands/.svn/text-base/control.rb.svn-base new file mode 100644 index 0000000..78e11b5 --- /dev/null +++ b/cli/ruby-debug/commands/.svn/text-base/control.rb.svn-base @@ -0,0 +1,107 @@ +module Debugger + class RestartCommand < Command # :nodoc: + self.allow_in_control = true + + def regexp + / ^\s* + (?:restart|R) + (?:\s+ (\S?.*\S))? \s* + $ + /ix + end + + def execute + if not defined? Debugger::PROG_SCRIPT + errmsg "Don't know name of debugged program\n" + return + end + prog_script = Debugger::PROG_SCRIPT + if not defined? Debugger::RDEBUG_SCRIPT + # FIXME? Should ask for confirmation? + print "Debugger was not called from the outset...\n" + rdebug_script = prog_script + else + rdebug_script = Debugger::RDEBUG_SCRIPT + end + begin + Dir.chdir(Debugger::INITIAL_DIR) + rescue + print "Failed to change initial directory #{Debugger::INITIAL_DIR}" + end + if not File.exist?(File.expand_path(prog_script)) + errmsg "Ruby program #{prog_script} doesn't exist\n" + return + end + if not File.executable?(prog_script) and rdebug_script == prog_script + print "Ruby program #{prog_script} doesn't seem to be executable...\n" + print "We'll add a call to Ruby.\n" + ruby = begin defined?(Gem) ? Gem.ruby : "ruby" rescue "ruby" end + rdebug_script = "#{ruby} -I#{$:.join(' -I')} #{prog_script}" + else + rdebug_script += ' ' + end + if @match[1] + argv = [prog_script] + @match[1].split(/[ \t]+/) + else + if not defined? Command.settings[:argv] + errmsg "Arguments have not been set. Use 'set args' to set them.\n" + return + else + argv = Command.settings[:argv] + end + end + args = argv.join(' ') + + # An execv would be preferable to the "exec" below. + cmd = rdebug_script + args + print "Re exec'ing:\n\t#{cmd}\n" + exec cmd + rescue Errno::EOPNOTSUPP + print "Restart command is not available at this time.\n" + end + + class << self + def help_command + 'restart' + end + + def help(cmd) + %{ + restart|R [args] + Restart the program. This is is a re-exec - all debugger state + is lost. If command arguments are passed those are used. + } + end + end + end + + class InterruptCommand < Command # :nodoc: + self.allow_in_control = true + self.allow_in_post_mortem = false + self.event = false + self.need_context = true + + def regexp + /^\s*i(?:nterrupt)?\s*$/ + end + + def execute + unless Debugger.interrupt_last + context = Debugger.thread_context(Thread.main) + context.interrupt + end + end + + class << self + def help_command + 'interrupt' + end + + def help(cmd) + %{ + i[nterrupt]\tinterrupt the program + } + end + end + end +end diff --git a/cli/ruby-debug/commands/.svn/text-base/display.rb.svn-base b/cli/ruby-debug/commands/.svn/text-base/display.rb.svn-base new file mode 100644 index 0000000..ff82079 --- /dev/null +++ b/cli/ruby-debug/commands/.svn/text-base/display.rb.svn-base @@ -0,0 +1,120 @@ +module Debugger + module DisplayFunctions # :nodoc: + def display_expression(exp) + print "%s = %s\n", exp, debug_silent_eval(exp).to_s + end + + def active_display_expressions? + @state.display.select{|d| d[0]}.size > 0 + end + + def print_display_expressions + n = 1 + for d in @state.display + if d[0] + print "%d: ", n + display_expression(d[1]) + end + n += 1 + end + end + end + + class AddDisplayCommand < Command # :nodoc: + def regexp + /^\s*disp(?:lay)?\s+(.+)$/ + end + + def execute + exp = @match[1] + @state.display.push [true, exp] + print "%d: ", @state.display.size + display_expression(exp) + end + + class << self + def help_command + 'display' + end + + def help(cmd) + %{ + disp[lay] \tadd expression into display expression list + } + end + end + end + + class DisplayCommand < Command # :nodoc: + def self.always_run + Debugger.annotate = 0 unless Debugger.annotate + if Debugger.annotate > 1 + 0 + else + 2 + end + end + + def regexp + /^\s*disp(?:lay)?$/ + end + + def execute + print_display_expressions + end + + class << self + def help_command + 'display' + end + + def help(cmd) + %{ + disp[lay]\t\tdisplay expression list + } + end + end + end + + class DeleteDisplayCommand < Command # :nodoc: + + def regexp + /^\s* undisp(?:lay)? \s* (?:(\S+))?$/x + end + + def execute + unless pos = @match[1] + if confirm("Clear all expressions? (y/n) ") + for d in @state.display + d[0] = false + end + end + else + pos = get_int(pos, "Undisplay") + return unless pos + if @state.display[pos-1] + @state.display[pos-1][0] = nil + else + errmsg "Display expression %d is not defined.\n", pos + end + end + end + + class << self + def help_command + 'undisplay' + end + + def help(cmd) + %{ + undisp[lay][ nnn] + Cancel some expressions to be displayed when program stops. + Arguments are the code numbers of the expressions to stop displaying. + No argument means cancel all automatic-display expressions. + "delete display" has the same effect as this command. + Do "info display" to see current list of code numbers. + } + end + end + end +end diff --git a/cli/ruby-debug/commands/.svn/text-base/edit.rb.svn-base b/cli/ruby-debug/commands/.svn/text-base/edit.rb.svn-base new file mode 100644 index 0000000..ae12887 --- /dev/null +++ b/cli/ruby-debug/commands/.svn/text-base/edit.rb.svn-base @@ -0,0 +1,48 @@ +module Debugger + class Edit < Command # :nodoc: + self.allow_in_control = true + def regexp + /^\s* ed(?:it)? (?:\s+(.*))?$/ix + end + + def execute + if not @match[1] or @match[1].strip.empty? + unless @state.context + errmsg "We are not in a state that has an associated file.\n" + return + end + file = @state.file + line_number = @state.line + elsif @pos_match = /([^:]+)[:]([0-9]+)/.match(@match[1]) + file, line_number = @pos_match.captures + else + errmsg "Invalid file/line number specification: #{@match[1]}\n" + return + end + editor = ENV['EDITOR'] || 'ex' + if File.readable?(file) + system("#{editor} +#{line_number} #{file}") + else + errmsg "File \"#{file}\" is not readable.\n" + end + end + + class << self + def help_command + 'edit' + end + + def help(cmd) + %{ + Edit specified file. + +With no argument, edits file containing most recent line listed. +Editing targets can also be specified in this: + FILE:LINENUM, to edit at that line in that file, + } + end + end + end + + +end # module Debugger diff --git a/cli/ruby-debug/commands/.svn/text-base/enable.rb.svn-base b/cli/ruby-debug/commands/.svn/text-base/enable.rb.svn-base new file mode 100644 index 0000000..d70f343 --- /dev/null +++ b/cli/ruby-debug/commands/.svn/text-base/enable.rb.svn-base @@ -0,0 +1,202 @@ +module Debugger + # Mix-in module to assist in command parsing. + module EnableDisableFunctions # :nodoc: + def enable_disable_breakpoints(is_enable, args) + breakpoints = Debugger.breakpoints.sort_by{|b| b.id } + largest = breakpoints.inject(0) do |largest, b| + largest = b.id if b.id > largest + end + if 0 == largest + errmsg "No breakpoints have been set.\n" + return + end + args.each do |pos| + pos = get_int(pos, "#{is_enable} breakpoints", 1, largest) + return nil unless pos + breakpoints.each do |b| + if b.id == pos + enabled = ("Enable" == is_enable) + if enabled + unless syntax_valid?(b.expr) + errmsg("Expression \"#{b.expr}\" syntactically incorrect; breakpoint remains disabled.\n") + break + end + end + b.enabled = ("Enable" == is_enable) + break + end + end + end + end + + def enable_disable_display(is_enable, args) + if 0 == @state.display.size + errmsg "No display expressions have been set.\n" + return + end + args.each do |pos| + pos = get_int(pos, "#{is_enable} display", 1, @state.display.size) + return nil unless pos + @state.display[pos-1][0] = ("Enable" == is_enable) + end + end + + end + + class EnableCommand < Command # :nodoc: + Subcommands = + [ + ['breakpoints', 2, "Enable specified breakpoints", +"Give breakpoint numbers (separated by spaces) as arguments. +This is used to cancel the effect of the \"disable\" command." + ], + ['display', 2, + "Enable some expressions to be displayed when program stops", +"Arguments are the code numbers of the expressions to resume displaying. +Do \"info display\" to see current list of code numbers."], + ].map do |name, min, short_help, long_help| + SubcmdStruct.new(name, min, short_help, long_help) + end unless defined?(Subcommands) + + def regexp + /^\s* en(?:able)? (?:\s+(.*))?$/ix + end + + def execute + if not @match[1] + errmsg "\"enable\" must be followed \"display\", \"breakpoints\"" + + " or breakpoint numbers.\n" + else + args = @match[1].split(/[ \t]+/) + param = args.shift + subcmd = find(Subcommands, param) + if subcmd + send("enable_#{subcmd.name}", args) + else + send("enable_breakpoints", args.unshift(param)) + end + end + end + + def enable_breakpoints(args) + enable_disable_breakpoints("Enable", args) + end + + def enable_display(args) + enable_disable_display("Enable", args) + end + + class << self + def help_command + 'enable' + end + + def help(args) + if args[1] + s = args[1] + subcmd = Subcommands.find do |try_subcmd| + (s.size >= try_subcmd.min) and + (try_subcmd.name[0..s.size-1] == s) + end + if subcmd + str = subcmd.short_help + '.' + str += "\n" + subcmd.long_help if subcmd.long_help + return str + else + return "Invalid 'enable' subcommand '#{args[1]}'." + end + end + s = %{ + Enable some things. + This is used to cancel the effect of the "disable" command. + -- + List of enable subcommands: + -- + } + for subcmd in Subcommands do + s += "enable #{subcmd.name} -- #{subcmd.short_help}\n" + end + return s + end + end + end + + class DisableCommand < Command # :nodoc: + Subcommands = + [ + ['breakpoints', 1, "Disable some breakpoints", +"Arguments are breakpoint numbers with spaces in between. +A disabled breakpoint is not forgotten, but has no effect until reenabled."], + ['display', 1, "Disable some display expressions when program stops", +"Arguments are the code numbers of the expressions to stop displaying. +Do \"info display\" to see current list of code numbers."], + ].map do |name, min, short_help, long_help| + SubcmdStruct.new(name, min, short_help, long_help) + end unless defined?(Subcommands) + + def regexp + /^\s* dis(?:able)? (?:\s+(.*))?$/ix + end + + def execute + if not @match[1] + errmsg "\"disable\" must be followed \"display\", \"breakpoints\"" + + " or breakpoint numbers.\n" + else + args = @match[1].split(/[ \t]+/) + param = args.shift + subcmd = find(Subcommands, param) + if subcmd + send("disable_#{subcmd.name}", args) + else + send("disable_breakpoints", args.unshift(param)) + end + end + end + + def disable_breakpoints(args) + enable_disable_breakpoints("Disable", args) + end + + def disable_display(args) + enable_disable_display("Disable", args) + end + + class << self + def help_command + 'disable' + end + + def help(args) + if args[1] + s = args[1] + subcmd = Subcommands.find do |try_subcmd| + (s.size >= try_subcmd.min) and + (try_subcmd.name[0..s.size-1] == s) + end + if subcmd + str = subcmd.short_help + '.' + str += "\n" + subcmd.long_help if subcmd.long_help + return str + else + return "Invalid 'disable' subcommand '#{args[1]}'." + end + end + s = %{ + Disable some things. + + A disabled item is not forgotten, but has no effect until reenabled. + Use the "enable" command to have it take effect again. + -- + List of disable subcommands: + -- + } + for subcmd in Subcommands do + s += "disable #{subcmd.name} -- #{subcmd.short_help}\n" + end + return s + end + end + end + +end # module Debugger diff --git a/cli/ruby-debug/commands/.svn/text-base/eval.rb.svn-base b/cli/ruby-debug/commands/.svn/text-base/eval.rb.svn-base new file mode 100644 index 0000000..f752047 --- /dev/null +++ b/cli/ruby-debug/commands/.svn/text-base/eval.rb.svn-base @@ -0,0 +1,176 @@ +module Debugger + module EvalFunctions # :nodoc: + def run_with_binding + binding = @state.context ? get_binding : TOPLEVEL_BINDING + $__dbg_interface = @state.interface + eval(<<-EOC, binding) + __dbg_verbose_save=$VERBOSE; $VERBOSE=false + def dbg_print(*args) + $__dbg_interface.print(*args) + end + remove_method :puts if self.respond_to?(:puts) && + defined?(remove_method) + def dbg_puts(*args) + $__dbg_interface.print(*args) + $__dbg_interface.print("\n") + end + $VERBOSE=__dbg_verbose_save + EOC + yield binding + ensure + $__dbg_interface = nil + end + end + + class EvalCommand < Command # :nodoc: + self.allow_in_control = true + + register_setting_get(:autoeval) do + EvalCommand.unknown + end + register_setting_set(:autoeval) do |value| + EvalCommand.unknown = value + end + + def match(input) + @input = input + super + end + + def regexp + /^\s*(p|e(?:val)?)\s+/ + end + + def execute + expr = @match ? @match.post_match : @input + run_with_binding do |b| + print "%s\n", debug_eval(expr, b).inspect + end + end + + class << self + def help_command + %w|p eval| + end + + def help(cmd) + if cmd == 'p' + %{ + p expression\tevaluate expression and print its value + } + else + %{ + e[val] expression\tevaluate expression and print its value, + \t\t\talias for p. + * NOTE - to turn on autoeval, use 'set autoeval' + } + end + end + end + end + + class PPCommand < Command # :nodoc: + self.allow_in_control = true + + def regexp + /^\s*pp\s+/ + end + + def execute + out = StringIO.new + run_with_binding do |b| + PP.pp(debug_eval(@match.post_match, b), out) + end + print out.string + rescue + out.puts $!.message + end + + class << self + def help_command + 'pp' + end + + def help(cmd) + %{ + pp expression\tevaluate expression and pretty-print its value + } + end + end + end + + class PutLCommand < Command # :nodoc: + self.allow_in_control = true + + def regexp + /^\s*putl\s+/ + end + + def execute + out = StringIO.new + run_with_binding do |b| + vals = debug_eval(@match.post_match, b) + if vals.is_a?(Array) + vals = vals.map{|item| item.to_s} + print "%s\n", columnize(vals, self.class.settings[:width]) + else + PP.pp(vals, out) + print out.string + end + end + rescue + out.puts $!.message + end + + class << self + def help_command + 'putl' + end + + def help(cmd) + %{ + putl expression\t\tevaluate expression, an array, and columnize its value + } + end + end + end + + class PSCommand < Command # :nodoc: + self.allow_in_control = true + + include EvalFunctions + + def regexp + /^\s*ps\s+/ + end + + def execute + out = StringIO.new + run_with_binding do |b| + vals = debug_eval(@match.post_match, b) + if vals.is_a?(Array) + vals = vals.map{|item| item.to_s} + print "%s\n", columnize(vals.sort!, self.class.settings[:width]) + else + PP.pp(vals, out) + print out.string + end + end + rescue + out.puts $!.message + end + + class << self + def help_command + 'ps' + end + + def help(cmd) + %{ + ps expression\tevaluate expression, an array, sort, and columnize its value + } + end + end + end + +end diff --git a/cli/ruby-debug/commands/.svn/text-base/finish.rb.svn-base b/cli/ruby-debug/commands/.svn/text-base/finish.rb.svn-base new file mode 100644 index 0000000..c7b77ff --- /dev/null +++ b/cli/ruby-debug/commands/.svn/text-base/finish.rb.svn-base @@ -0,0 +1,42 @@ +module Debugger + # Implements the debugger 'finish' command. + class FinishCommand < Command + self.allow_in_post_mortem = false + self.need_context = true + + def regexp + /^\s*fin(?:ish)? (?:\s+(.*))?$/x + end + + def execute + max_frame = @state.context.stack_size - @state.frame_pos + if !@match[1] or @match[1].empty? + frame_pos = @state.frame_pos + else + frame_pos = get_int(@match[1], "Finish", 0, max_frame-1, 0) + return nil unless frame_pos + end + @state.context.stop_frame = frame_pos + @state.frame_pos = 0 + @state.proceed + end + + class << self + def help_command + 'finish' + end + + def help(cmd) + %{ + fin[ish] [frame-number]\tExecute until selected stack frame returns. + +If no frame number is given, we run until the currently selected frame +returns. The currently selected frame starts out the most-recent +frame or 0 if no frame positioning (e.g "up", "down" or "frame") has +been performed. If a frame number is given we run until that frame +returns. + } + end + end + end +end diff --git a/cli/ruby-debug/commands/.svn/text-base/frame.rb.svn-base b/cli/ruby-debug/commands/.svn/text-base/frame.rb.svn-base new file mode 100644 index 0000000..f9b6f26 --- /dev/null +++ b/cli/ruby-debug/commands/.svn/text-base/frame.rb.svn-base @@ -0,0 +1,301 @@ +module Debugger + # Mix-in module to assist in command parsing. + module FrameFunctions # :nodoc: + def adjust_frame(frame_pos, absolute, context=@state.context) + @state.frame_pos = 0 if context != @state.context + if absolute + if frame_pos < 0 + abs_frame_pos = context.stack_size + frame_pos + else + abs_frame_pos = frame_pos + end + else + abs_frame_pos = @state.frame_pos + frame_pos + end + + if abs_frame_pos >= context.stack_size then + errmsg "Adjusting would put us beyond the oldest (initial) frame.\n" + return + elsif abs_frame_pos < 0 then + errmsg "Adjusting would put us beyond the newest (innermost) frame.\n" + return + end + if @state.frame_pos != abs_frame_pos then + @state.previous_line = nil + @state.frame_pos = abs_frame_pos + end + + @state.file = context.frame_file(@state.frame_pos) + @state.line = context.frame_line(@state.frame_pos) + + print_frame(@state.frame_pos, true) + end + + def get_frame_call(prefix, pos, context) + id = context.frame_method(pos) + klass = context.frame_class(pos) + call_str = "" + if id + args = context.frame_args(pos) + locals = context.frame_locals(pos) + if Command.settings[:callstyle] != :short && klass + if Command.settings[:callstyle] == :tracked + arg_info = context.frame_args_info(pos) + end + call_str << "#{klass}." + end + call_str << id.id2name + if args.any? + call_str << "(" + args.each_with_index do |name, i| + case Command.settings[:callstyle] + when :short + call_str += "%s, " % [name] + when :last + klass = locals[name].class + if klass.inspect.size > 20+3 + klass = klass.inspect[0..20]+"..." + end + call_str += "%s#%s, " % [name, klass] + when :tracked + if arg_info && arg_info.size > i + call_str += "#{name}: #{arg_info[i].inspect}, " + else + call_str += "%s, " % name + end + end + if call_str.size > self.class.settings[:width] - prefix.size + # Strip off trailing ', ' if any but add stuff for later trunc + call_str[-2..-1] = ",...XX" + break + end + end + call_str[-2..-1] = ")" # Strip off trailing ', ' if any + end + end + return call_str + end + + def print_frame(pos, adjust = false, context=@state.context) + file = context.frame_file(pos) + line = context.frame_line(pos) + klass = context.frame_class(pos) + + unless Command.settings[:full_path] + path_components = file.split(/[\\\/]/) + if path_components.size > 3 + path_components[0...-3] = '...' + file = path_components.join(File::ALT_SEPARATOR || File::SEPARATOR) + end + end + + frame_num = "#%d " % pos + call_str = get_frame_call(frame_num, pos, context) + file_line = "at line %s:%d\n" % [CommandProcessor.canonic_file(file), line] + print frame_num + unless call_str.empty? + print call_str + print ' ' + if call_str.size + frame_num.size + file_line.size > self.class.settings[:width] + print "\n " + end + end + print file_line + if ENV['EMACS'] && adjust + fmt = (Debugger.annotate.to_i > 1 ? + "\032\032source %s:%d\n" : "\032\032%s:%d\n") + print fmt % [CommandProcessor.canonic_file(file), line] + end + end + + # Check if call stack is truncated. This can happen if + # Debugger.start is not called low enough in the call stack. An + # array of additional callstack lines from caller is returned if + # definitely truncated, false if not, and nil if we don't know. + # + # We determine truncation based on a passed in sentinal set via + # caller which can be nil. + # + # First we see if we can find our position in caller. If so, then + # we compare context position to that in caller using sentinal + # as a place to start ignoring additional caller entries. sentinal + # is set by rdebug, but if it's not set, i.e. nil then additional + # entries are presumably ones that we haven't recorded in context + def truncated_callstack?(context, sentinal=nil, cs=caller) + recorded_size = context.stack_size + to_find_fl = "#{context.frame_file(0)}:#{context.frame_line(0)}" + top_discard = false + cs.each_with_index do |fl, i| + fl.gsub!(/in `.*'$/, '') + fl.gsub!(/:$/, '') + if fl == to_find_fl + top_discard = i + break + end + end + if top_discard + cs = cs[top_discard..-1] + return false unless cs + return cs unless sentinal + if cs.size > recorded_size+2 && cs[recorded_size+2] != sentinal + # caller seems to truncate recursive calls and we don't. + # See if we can find sentinal in the first 0..recorded_size+1 entries + return false if cs[0..recorded_size+1].any?{ |f| f==sentinal } + return cs + end + return false + end + return nil + end + + + end + + # Implements debugger "where" or "backtrace" command. + class WhereCommand < Command + def regexp + /^\s*(?:w(?:here)?|bt|backtrace)$/ + end + + def execute + (0...@state.context.stack_size).each do |idx| + if idx == @state.frame_pos + print "--> " + else + print " " + end + print_frame(idx) + + end + if truncated_callstack?(@state.context, Debugger.start_sentinal) + print "Warning: saved frames may be incomplete; compare with caller(0).\n" + end + end + + class << self + def help_command + %w|where backtrace| + end + + def help(cmd) + s = if cmd == 'where' + %{ + w[here]\tdisplay stack frames + } + else + %{ + bt|backtrace\t\talias for where - display stack frames + } + end + s += %{ +Print the entire stack frame. Each frame is numbered, the most recent +frame is 0. frame number can be referred to in the "frame" command; +"up" and "down" add or subtract respectively to frame numbers shown. +The position of the current frame is marked with -->. } + end + end + end + + class UpCommand < Command # :nodoc: + def regexp + /^\s* u(?:p)? (?:\s+(.*))?$/x + end + + def execute + pos = get_int(@match[1], "Up") + return unless pos + adjust_frame(pos, false) + end + + class << self + def help_command + 'up' + end + + def help(cmd) + %{ + up[count]\tmove to higher frame + } + end + end + end + + class DownCommand < Command # :nodoc: + def regexp + /^\s* down (?:\s+(.*))? .*$/x + end + + def execute + pos = get_int(@match[1], "Down") + return unless pos + adjust_frame(-pos, false) + end + + class << self + def help_command + 'down' + end + + def help(cmd) + %{ + down[count]\tmove to lower frame + } + end + end + end + + class FrameCommand < Command # :nodoc: + def regexp + / ^\s* + f(?:rame)? + (?: \s+ (\S+))? \s* + (?: thread \s+ (.*))? \s* + $/x + end + + def execute + if not @match[1] + pos = 0 + else + pos = get_int(@match[1], "Frame") + return unless pos + end + if @match[2] + context = parse_thread_num('frame', @match[2]) + unless context + errmsg "Thread #{@match[2]} doesn't exist.\n" + return + end + else + context = @state.context + end + adjust_frame(pos, true, context) + end + + class << self + def help_command + 'frame' + end + + def help(cmd) + %{ + f[rame] [frame-number [thread thread-number]] + Move the current frame to the specified frame number, or the + 0 if no frame-number has been given. + + A negative number indicates position from the other end. So + 'frame -1' moves to the oldest frame, and 'frame 0' moves to + the newest frame. + + Without an argument, the command prints the current stack + frame. Since the current position is redisplayed, it may trigger a + resyncronization if there is a front end also watching over + things. + + If a thread number is given then we set the context for evaluating + expressions to that frame of that thread. + } + end + end + end +end diff --git a/cli/ruby-debug/commands/.svn/text-base/help.rb.svn-base b/cli/ruby-debug/commands/.svn/text-base/help.rb.svn-base new file mode 100644 index 0000000..1144621 --- /dev/null +++ b/cli/ruby-debug/commands/.svn/text-base/help.rb.svn-base @@ -0,0 +1,56 @@ +module Debugger + + # Implements debugger "help" command. + class HelpCommand < Command + self.allow_in_control = true + + def regexp + /^\s* h(?:elp)? (?:\s+(.+))? $/x + end + + def execute + if @match[1] + args = @match[1].split + cmds = @state.commands.select do |cmd| + [cmd.help_command].flatten.include?(args[0]) + end + else + args = @match[1] + cmds = [] + end + unless cmds.empty? + help = cmds.map{ |cmd| cmd.help(args) }.join + help = help.split("\n").map{|l| l.gsub(/^ +/, '')} + help.shift if help.first && help.first.empty? + help.pop if help.last && help.last.empty? + print help.join("\n") + else + if args and args[0] + errmsg "Undefined command: \"#{args[0]}\". Try \"help\"." + else + print "ruby-debug help v#{Debugger::VERSION}\n" unless + self.class.settings[:debuggertesting] + print "Type 'help ' for help on a specific command\n\n" + print "Available commands:\n" + cmds = @state.commands.map{ |cmd| cmd.help_command } + cmds = cmds.flatten.uniq.sort + print columnize(cmds, self.class.settings[:width]) + end + end + print "\n" + end + + class << self + def help_command + 'help' + end + + def help(cmd) + %{ + h[elp]\t\tprint this help + h[elp] command\tprint help on command + } + end + end + end +end diff --git a/cli/ruby-debug/commands/.svn/text-base/info.rb.svn-base b/cli/ruby-debug/commands/.svn/text-base/info.rb.svn-base new file mode 100644 index 0000000..3fac50c --- /dev/null +++ b/cli/ruby-debug/commands/.svn/text-base/info.rb.svn-base @@ -0,0 +1,469 @@ +module Debugger + module InfoFunctions # :nodoc: + def info_catch(*args) + unless @state.context + print "No frame selected.\n" + return + end + if Debugger.catchpoints and not Debugger.catchpoints.empty? + # FIXME: show whether Exception is valid or not + # print "Exception: is_a?(Class)\n" + Debugger.catchpoints.each do |exception, hits| + # print "#{exception}: #{exception.is_a?(Class)}\n" + print "#{exception}\n" + end + else + print "No exceptions set to be caught.\n" + end + end + end + + # Implements debugger "info" command. + class InfoCommand < Command + self.allow_in_control = true + Subcommands = + [ + ['args', 1, 'Argument variables of current stack frame'], + ['breakpoints', 1, 'Status of user-settable breakpoints', + 'Without argument, list info about all breakpoints. With an +integer argument, list info on that breakpoint.'], + ['catch', 3, 'Exceptions that can be caught in the current stack frame'], + ['display', 2, 'Expressions to display when program stops'], + ['file', 4, 'Info about a particular file read in', +' +After the file name is supplied, you can list file attributes that +you wish to see. + +Attributes include: "all", "basic", "breakpoint", "lines", "mtime", "path" +and "sha1".'], + ['files', 5, 'File names and timestamps of files read in'], + ['global_variables', 2, 'Global variables'], + ['instance_variables', 2, + 'Instance variables of the current stack frame'], + ['line', 2, + 'Line number and file name of current position in source file'], + ['locals', 2, 'Local variables of the current stack frame'], + ['program', 2, 'Execution status of the program'], + ['stack', 2, 'Backtrace of the stack'], + ['thread', 6, 'List info about thread NUM', ' +If no thread number is given, we list info for all threads. \'terse\' and \'verbose\' +options are possible. If terse, just give summary thread name information. See +"help info threads" for more detail about this summary information. + +If \'verbose\' appended to the end of the command, then the entire +stack trace is given for each thread.'], + ['threads', 7, 'information of currently-known threads', ' +This information includes whether the thread is current (+), if it is +suspended ($), or ignored (!). The thread number and the top stack +item. If \'verbose\' is given then the entire stack frame is shown.'], + ['variables', 1, + 'Local and instance variables of the current stack frame'] + ].map do |name, min, short_help, long_help| + SubcmdStruct.new(name, min, short_help, long_help) + end unless defined?(Subcommands) + + InfoFileSubcommands = + [ + ['all', 1, + 'All file information available - breakpoints, lines, mtime, path, and sha1'], + ['basic', 2, + 'basic information - path, number of lines'], + ['breakpoints', 2, 'Show trace line numbers', + 'These are the line number where a breakpoint can be set.'], + ['lines', 1, 'Show number of lines in the file'], + ['mtime', 1, 'Show modification time of file'], + ['path', 4, 'Show full file path name for file'], + ['sha1', 1, 'Show SHA1 hash of contents of the file'] + ].map do |name, min, short_help, long_help| + SubcmdStruct.new(name, min, short_help, long_help) + end unless defined?(InfoFileSubcommands) + + InfoThreadSubcommands = + [ + ['terse', 1, 'summary information'], + ['verbose', 1, 'summary information and stack frame info'], + ].map do |name, min, short_help, long_help| + SubcmdStruct.new(name, min, short_help, long_help) + end unless defined?(InfoThreadSubcommands) + + def regexp + /^\s* i(?:nfo)? (?:\s+(.*))?$/ix + end + + def execute + if @match[1].empty? + errmsg "\"info\" must be followed by the name of an info command:\n" + print "List of info subcommands:\n\n" + for subcmd in Subcommands do + print "info #{subcmd.name} -- #{subcmd.short_help}\n" + end + else + args = @match[1].split(/[ \t]+/) + param = args.shift + subcmd = find(Subcommands, param) + if subcmd + send("info_#{subcmd.name}", *args) + else + errmsg "Unknown info command #{param}\n" + end + end + end + + def info_args(*args) + unless @state.context + print "No frame selected.\n" + return + end + locals = @state.context.frame_locals(@state.frame_pos) + args = @state.context.frame_args(@state.frame_pos) + args.each do |name| + s = "#{name} = #{locals[name].inspect}" + if s.size > self.class.settings[:width] + s[self.class.settings[:width]-3 .. -1] = "..." + end + print "#{s}\n" + end + end + + def info_breakpoints(*args) + unless @state.context + print "info breakpoints not available here.\n" + return + end + unless Debugger.breakpoints.empty? + brkpts = Debugger.breakpoints.sort_by{|b| b.id} + unless args.empty? + a = args.map{|a| a.to_i} + brkpts = brkpts.select{|b| a.member?(b.id)} + if brkpts.empty? + errmsg "No breakpoints found among list given.\n" + return + end + end + print "Num Enb What\n" + brkpts.each do |b| + if b.expr.nil? + print "%3d %s at %s:%s\n", + b.id, (b.enabled? ? 'y' : 'n'), b.source, b.pos + else + print "%3d %s at %s:%s if %s\n", + b.id, (b.enabled? ? 'y' : 'n'), b.source, b.pos, b.expr + end + hits = b.hit_count + if hits > 0 + s = (hits > 1) ? 's' : '' + print "\tbreakpoint already hit #{hits} time#{s}\n" + end + end + else + print "No breakpoints.\n" + end + end + + def info_display(*args) + unless @state.context + print "info display not available here.\n" + return + end + if @state.display.find{|d| d[0]} + print "Auto-display expressions now in effect:\n" + print "Num Enb Expression\n" + n = 1 + for d in @state.display + print "%3d: %s %s\n", n, (d[0] ? 'y' : 'n'), d[1] if + d[0] != nil + n += 1 + end + else + print "There are no auto-display expressions now.\n" + end + end + + def info_file(*args) + unless args[0] + info_files + return + end + file = args[0] + param = args[1] + + param = 'basic' unless param + subcmd = find(InfoFileSubcommands, param) + unless subcmd + errmsg "Invalid parameter #{param}\n" + return + end + + unless LineCache::cached?(file) + unless LineCache::cached_script?(file) + print "File #{file} is not cached\n" + return + end + LineCache::cache(file, Command.settings[:reload_source_on_change]) + end + + print "File %s", file + path = LineCache.path(file) + if %w(all basic path).member?(subcmd.name) and path != file + print " - %s\n", path + else + print "\n" + end + + if %w(all basic lines).member?(subcmd.name) + lines = LineCache.size(file) + print "\t %d lines\n", lines if lines + end + + if %w(all breakpoints).member?(subcmd.name) + breakpoints = LineCache.trace_line_numbers(file) + if breakpoints + print "\tbreakpoint line numbers:\n" + print columnize(breakpoints.to_a.sort, self.class.settings[:width]) + end + end + + if %w(all mtime).member?(subcmd.name) + stat = LineCache.stat(file) + print "\t%s\n", stat.mtime if stat + end + if %w(all sha1).member?(subcmd.name) + print "\t%s\n", LineCache.sha1(file) + end + end + + def info_files(*args) + files = LineCache::cached_files + files += SCRIPT_LINES__.keys unless 'stat' == args[0] + files.uniq.sort.each do |file| + stat = LineCache::stat(file) + path = LineCache::path(file) + print "File %s", file + if path and path != file + print " - %s\n", path + else + print "\n" + end + print "\t%s\n", stat.mtime if stat + end + end + + def info_instance_variables(*args) + unless @state.context + print "info instance_variables not available here.\n" + return + end + obj = debug_eval('self') + var_list(obj.instance_variables) + end + + def info_line(*args) + unless @state.context + errmsg "info line not available here.\n" + return + end + print "Line %d of \"%s\"\n", @state.line, @state.file + end + + def info_locals(*args) + unless @state.context + errmsg "info line not available here.\n" + return + end + locals = @state.context.frame_locals(@state.frame_pos) + locals.keys.sort.each do |name| + ### FIXME: make a common routine + begin + s = "#{name} = #{locals[name].inspect}" + rescue + begin + s = "#{name} = #{locals[name].to_s}" + rescue + s = "*Error in evaluation*" + end + end + if s.size > self.class.settings[:width] + s[self.class.settings[:width]-3 .. -1] = "..." + end + print "#{s}\n" + end + end + + def info_program(*args) + if not @state.context + print "The program being debugged is not being run.\n" + return + elsif @state.context.dead? + print "The program crashed.\n" + if Debugger.last_exception + print("Exception: #{Debugger.last_exception.inspect}\n") + end + return + end + + print "Program stopped. " + case @state.context.stop_reason + when :step + print "It stopped after stepping, next'ing or initial start.\n" + when :breakpoint + print("It stopped at a breakpoint.\n") + when :catchpoint + print("It stopped at a catchpoint.\n") + when :catchpoint + print("It stopped at a catchpoint.\n") + else + print "unknown reason: %s\n" % @state.context.stop_reason.to_s + end + end + + def info_stack(*args) + if not @state.context + errmsg "info stack not available here.\n" + return + end + (0...@state.context.stack_size).each do |idx| + if idx == @state.frame_pos + print "--> " + else + print " " + end + print_frame(idx) + end + end + + def info_thread_preamble(arg) + if not @state.context + errmsg "info threads not available here.\n" + return false, false + end + verbose = if arg + subcmd = find(InfoThreadSubcommands, arg) + unless subcmd + errmsg "'terse' or 'verbose' expected. Got '#{arg}'\n" + return false, false + end + 'verbose' == subcmd.name + else + false + end + return true, verbose + end + private :info_thread_preamble + + def info_threads(*args) + ok, verbose = info_thread_preamble(args[0]) + return unless ok + threads = Debugger.contexts.sort_by{|c| c.thnum}.each do |c| + display_context(c, !verbose) + if verbose and not c.ignored? + (0...c.stack_size).each do |idx| + print "\t" + print_frame(idx, false, c) + end + end + end + end + + def info_thread(*args) + unless args[0] + info_threads(args[0]) + return + end + ok, verbose = info_thread_preamble(args[1]) + return unless ok + c = parse_thread_num("info thread" , args[0]) + return unless c + display_context(c, !verbose) + if verbose and not c.ignored? + (0...c.stack_size).each do |idx| + print "\t" + print_frame(idx, false, c) + end + end + end + + def info_global_variables(*args) + unless @state.context + errmsg "info global_variables not available here.\n" + return + end + var_list(global_variables) + end + + def info_variables(*args) + if not @state.context + errmsg "info variables not available here.\n" + return + end + obj = debug_eval('self') + locals = @state.context.frame_locals(@state.frame_pos) + locals['self'] = @state.context.frame_self(@state.frame_pos) + locals.keys.sort.each do |name| + next if name =~ /^__dbg_/ # skip debugger pollution + ### FIXME: make a common routine + begin + s = "#{name} = #{locals[name].inspect}" + rescue + begin + s = "#{name} = #{locals[name].to_s}" + rescue + s = "#{name} = *Error in evaluation*" + end + end + if s.size > self.class.settings[:width] + s[self.class.settings[:width]-3 .. -1] = "..." + end + s.gsub!('%', '%%') # protect against printf format strings + print "#{s}\n" + end + var_list(obj.instance_variables, obj.instance_eval{binding()}) + var_class_self + end + + class << self + def help_command + 'info' + end + + def help(args) + if args[1] + s = args[1] + subcmd = Subcommands.find do |try_subcmd| + (s.size >= try_subcmd.min) and + (try_subcmd.name[0..s.size-1] == s) + end + if subcmd + str = subcmd.short_help + '.' + if 'file' == subcmd.name and args[2] + s = args[2] + subsubcmd = InfoFileSubcommands.find do |try_subcmd| + (s.size >= try_subcmd.min) and + (try_subcmd.name[0..s.size-1] == s) + end + if subsubcmd + str += "\n" + subsubcmd.short_help + '.' + else + str += "\nInvalid file attribute #{args[2]}." + end + else + str += "\n" + subcmd.long_help if subcmd.long_help + end + return str + else + return "Invalid 'info' subcommand '#{args[1]}'." + end + end + s = %{ + Generic command for showing things about the program being debugged. + -- + List of info subcommands: + -- + } + for subcmd in Subcommands do + s += "info #{subcmd.name} -- #{subcmd.short_help}\n" + end + return s + end + end + end +end diff --git a/cli/ruby-debug/commands/.svn/text-base/irb.rb.svn-base b/cli/ruby-debug/commands/.svn/text-base/irb.rb.svn-base new file mode 100644 index 0000000..2493e80 --- /dev/null +++ b/cli/ruby-debug/commands/.svn/text-base/irb.rb.svn-base @@ -0,0 +1,123 @@ +require 'irb' + +module IRB # :nodoc: + module ExtendCommand # :nodoc: + class Continue # :nodoc: + def self.execute(conf) + throw :IRB_EXIT, :cont + end + end + class Next # :nodoc: + def self.execute(conf) + throw :IRB_EXIT, :next + end + end + class Step # :nodoc: + def self.execute(conf) + throw :IRB_EXIT, :step + end + end + end + ExtendCommandBundle.def_extend_command "cont", :Continue + ExtendCommandBundle.def_extend_command "n", :Next + ExtendCommandBundle.def_extend_command "step", :Step + + def self.start_session(binding) + unless @__initialized + args = ARGV.dup + ARGV.replace([]) + IRB.setup(nil) + ARGV.replace(args) + @__initialized = true + end + + workspace = WorkSpace.new(binding) + + irb = Irb.new(workspace) + + @CONF[:IRB_RC].call(irb.context) if @CONF[:IRB_RC] + @CONF[:MAIN_CONTEXT] = irb.context + + catch(:IRB_EXIT) do + irb.eval_input + end + end +end + +module Debugger + + # Implements debugger "irb" command. + class IRBCommand < Command + + register_setting_get(:autoirb) do + IRBCommand.always_run + end + register_setting_set(:autoirb) do |value| + IRBCommand.always_run = value + end + + def regexp + /^\s* irb + (?:\s+(-d))? + \s*$/x + end + + def execute + unless @state.interface.kind_of?(LocalInterface) + print "Command is available only in local mode.\n" + throw :debug_error + end + + save_trap = trap("SIGINT") do + throw :IRB_EXIT, :cont if $rdebug_in_irb + end + + add_debugging = @match.is_a?(Array) && '-d' == @match[1] + $rdebug_state = @state if add_debugging + $rdebug_in_irb = true + cont = IRB.start_session(get_binding) + case cont + when :cont + @state.proceed + when :step + force = Command.settings[:force_stepping] + @state.context.step(1, force) + @state.proceed + when :next + force = Command.settings[:force_stepping] + @state.context.step_over(1, @state.frame_pos, force) + @state.proceed + else + file = @state.context.frame_file(0) + line = @state.context.frame_line(0) + CommandProcessor.print_location_and_text(file, line) + @state.previous_line = nil + end + + ensure + $rdebug_in_irb = nil + $rdebug_state = nil if add_debugging + trap("SIGINT", save_trap) if save_trap + end + + class << self + def help_command + 'irb' + end + + def help(cmd) + %{ + irb [-d]\tstarts an Interactive Ruby (IRB) session. + +If -d is added you can get access to debugger state via the global variable +$RDEBUG_state. + +irb is extended with methods "cont", "n" and "step" which +run the corresponding debugger commands. In contrast to the real debugger +commands these commands don't allow command arguments. + } + end + end + end +end + diff --git a/cli/ruby-debug/commands/.svn/text-base/kill.rb.svn-base b/cli/ruby-debug/commands/.svn/text-base/kill.rb.svn-base new file mode 100644 index 0000000..da5d05e --- /dev/null +++ b/cli/ruby-debug/commands/.svn/text-base/kill.rb.svn-base @@ -0,0 +1,51 @@ +module Debugger + + # Implements debugger "kill" command + class KillCommand < Command + self.allow_in_control = true + + def regexp + / ^\s* + (?:kill) \s* + (?:\s+(\S+))?\s* + $ + /ix + end + + def execute + puts @match[1] + if @match[1] + signame = @match[1] + unless Signal.list.member?(signame) + errmsg("signal name #{signame} is not a signal I know about\n") + return false + end + if 'KILL' == signame: + @state.interface.finalize + end + else + if not confirm("Really kill? (y/n) ") + return + else + signame = 'KILL' + end + end + Process.kill(signame, Process.pid) + end + + class << self + def help_command + %w[kill] + end + + def help(cmd) + %{ + kill [SIGNAL] + + Send [signal] to Process.pid +Equivalent of Process.kill(Process.pid) + } + end + end + end +end diff --git a/cli/ruby-debug/commands/.svn/text-base/list.rb.svn-base b/cli/ruby-debug/commands/.svn/text-base/list.rb.svn-base new file mode 100644 index 0000000..165732f --- /dev/null +++ b/cli/ruby-debug/commands/.svn/text-base/list.rb.svn-base @@ -0,0 +1,94 @@ +module Debugger + # Implements debugger "list" command. + class ListCommand < Command + + register_setting_get(:autolist) do + ListCommand.always_run + end + register_setting_set(:autolist) do |value| + ListCommand.always_run = value + end + + def regexp + /^\s* l(?:ist)? (?:\s*([-=])|\s+(.+))? $/x + end + + def execute + listsize = Command.settings[:listsize] + if !@match || !(@match[1] || @match[2]) + b = @state.previous_line ? + @state.previous_line + listsize : @state.line - (listsize/2) + e = b + listsize - 1 + elsif @match[1] == '-' + b = if @state.previous_line + if @state.previous_line > 0 + @state.previous_line - listsize + else + @state.previous_line + end + else + @state.line - (listsize/2) + end + e = b + listsize - 1 + elsif @match[1] == '=' + @state.previous_line = nil + b = @state.line - (listsize/2) + e = b + listsize -1 + else + b, e = @match[2].split(/[-,]/) + if e + b = b.to_i + e = e.to_i + else + b = b.to_i - (listsize/2) + e = b + listsize - 1 + end + end + @state.previous_line = display_list(b, e, @state.file, @state.line) + end + + class << self + def help_command + 'list' + end + + def help(cmd) + %{ + l[ist]\t\tlist forward + l[ist] -\tlist backward + l[ist] =\tlist current line + l[ist] nn-mm\tlist given lines + * NOTE - to turn on autolist, use 'set autolist' + } + end + end + + private + + # Show FILE from line B to E where CURRENT is the current line number. + # If we can show from B to E then we return B, otherwise we return the + # previous line @state.previous_line. + def display_list(b, e, file, current) + print "[%d, %d] in %s\n", b, e, file + lines = LineCache::getlines(file, + Command.settings[:reload_source_on_change]) + if lines + return @state.previous_line if b >= lines.size + e = lines.size if lines.size < e + [b, 1].max.upto(e) do |n| + if n > 0 && lines[n-1] + if n == current + print "=> %d %s\n", n, lines[n-1].chomp + else + print " %d %s\n", n, lines[n-1].chomp + end + end + end + else + errmsg "No sourcefile available for %s\n", file + return @state.previous_line + end + return e == lines.size ? @state.previous_line : b + end + end +end diff --git a/cli/ruby-debug/commands/.svn/text-base/method.rb.svn-base b/cli/ruby-debug/commands/.svn/text-base/method.rb.svn-base new file mode 100644 index 0000000..1d31ead --- /dev/null +++ b/cli/ruby-debug/commands/.svn/text-base/method.rb.svn-base @@ -0,0 +1,84 @@ +module Debugger + + begin + require 'methodsig' + have_methodsig = true + rescue LoadError + have_methodsig = false + end + + # Implements the debugger 'method sig' command. + class MethodSigCommand < Command + def regexp + /^\s*m(?:ethod)?\s+sig(?:nature)?\s+(\S+)\s*$/ + end + + def execute + obj = debug_eval('method(:%s)' % @match[1]) + if obj.is_a?(Method) + begin + print "%s\n", obj.signature.to_s + rescue + errmsg("Can't get signature for '#{@match[1]}'\n") + end + else + errmsg("Can't make method out of '#{@match[1]}'\n") + end + end + + class << self + def help_command + 'method' + end + + def help(cmd) + %{ + m[ethod] sig[nature] \tshow the signature of a method + } + end + end + end if have_methodsig + + # Implements the debugger 'method' command. + class MethodCommand < Command + def regexp + /^\s*m(?:ethod)?\s+((iv)|(i(:?nstance\s+)?)\s+)?/ + end + + def execute + if @match[1] == "iv" + obj = debug_eval(@match.post_match) + obj.instance_variables.sort.each do |v| + print "%s = %s\n", v, obj.instance_variable_get(v).inspect + end + elsif @match[1] + obj = debug_eval(@match.post_match) + print "%s\n", columnize(obj.methods.sort(), + self.class.settings[:width]) + else + obj = debug_eval(@match.post_match) + unless obj.kind_of? Module + print "Should be Class/Module: %s\n", @match.post_match + else + print "%s\n", columnize(obj.instance_methods(false).sort(), + self.class.settings[:width]) + end + end + end + + class << self + def help_command + 'method' + end + + def help(cmd) + %{ + m[ethod] i[nstance] \tshow methods of object + m[ethod] iv \t\tshow instance variables of object + m[ethod] \t\tshow instance methods of class or module + } + end + end + end + +end diff --git a/cli/ruby-debug/commands/.svn/text-base/quit.rb.svn-base b/cli/ruby-debug/commands/.svn/text-base/quit.rb.svn-base new file mode 100644 index 0000000..767fedb --- /dev/null +++ b/cli/ruby-debug/commands/.svn/text-base/quit.rb.svn-base @@ -0,0 +1,39 @@ +module Debugger + + # Implements debugger "quit" command + class QuitCommand < Command + self.allow_in_control = true + + def regexp + / ^\s* + (?:q(?:uit)?|exit) \s* + (!|\s+unconditionally)? \s* + $ + /ix + end + + def execute + if @match[1] or confirm("Really quit? (y/n) ") + @state.interface.finalize + exit! # exit -> exit!: No graceful way to stop threads... + end + end + + class << self + def help_command + %w[quit exit] + end + + def help(cmd) + %{ + q[uit] [!|unconditionally]\texit from debugger. + exit[!]\talias to quit + + Normally we prompt before exiting. However if the parameter + "unconditionally" or is given or suffixed with !, we stop + without asking further questions. + } + end + end + end +end diff --git a/cli/ruby-debug/commands/.svn/text-base/reload.rb.svn-base b/cli/ruby-debug/commands/.svn/text-base/reload.rb.svn-base new file mode 100644 index 0000000..822d5e6 --- /dev/null +++ b/cli/ruby-debug/commands/.svn/text-base/reload.rb.svn-base @@ -0,0 +1,40 @@ +module Debugger + # Implements debugger "reload" command. + class ReloadCommand < Command + self.allow_in_control = true + + register_setting_get(:reload_source_on_change) do + Debugger.reload_source_on_change + end + register_setting_set(:reload_source_on_change) do |value| + Debugger.reload_source_on_change = value + end + + def regexp + /^\s*r(?:eload)?$/ + end + + def execute + Debugger.source_reload + print "Source code is reloaded. Automatic reloading is #{source_reloading}.\n" + end + + private + + def source_reloading + Debugger.reload_source_on_change ? 'on' : 'off' + end + + class << self + def help_command + 'reload' + end + + def help(cmd) + %{ + r[eload]\tforces source code reloading + } + end + end + end +end diff --git a/cli/ruby-debug/commands/.svn/text-base/save.rb.svn-base b/cli/ruby-debug/commands/.svn/text-base/save.rb.svn-base new file mode 100644 index 0000000..d039201 --- /dev/null +++ b/cli/ruby-debug/commands/.svn/text-base/save.rb.svn-base @@ -0,0 +1,90 @@ +module Debugger + module SaveFunctions # :nodoc: + + # Create a temporary file to write in if file is nil + def open_save + require "tempfile" + file = Tempfile.new("rdebug-save") + # We want close to not unlink, so redefine. + def file.close + @tmpfile.close if @tmpfile + end + return file + end + end + + class SaveCommand < Command # :nodoc: + self.allow_in_control = true + + def save_breakpoints(file) + Debugger.breakpoints.each do |b| + file.puts "break #{b.source}:#{b.pos}#{" if #{b.expr}" if b.expr}" + end + end + + def save_catchpoints(file) + Debugger.catchpoints.keys.each do |c| + file.puts "catch #{c}" + end + end + + def save_displays(file) + for d in @state.display + if d[0] + file.puts "display #{d[1]}" + end + end + end + + def save_settings(file) + # FIXME put routine in set + %w(autoeval basename debuggertesting).each do |setting| + on_off = show_onoff(Command.settings[setting.to_sym]) + file.puts "set #{setting} #{on_off}" + end + %w(autolist autoirb).each do |setting| + on_off = show_onoff(Command.settings[setting.to_sym] > 0) + file.puts "set #{setting} #{on_off}" + end + end + + def regexp + /^\s* sa(?:ve)? + (?:\s+(.+))? + \s*$/ix + end + + def execute + if not @match[1] or @match[1].strip.empty? + file = open_save() + else + file = open(@match[1], 'w') + end + save_breakpoints(file) + save_catchpoints(file) + # save_displays(file) + save_settings(file) + print "Saved to '#{file.path}'\n" + if @state and @state.interface + @state.interface.restart_file = file.path + end + file.close + end + + class << self + def help_command + 'save' + end + + def help(cmd) + %{ +save [FILE] +Saves current debugger state to FILE as a script file. +This includes breakpoints, catchpoints, display expressions and some settings. +If no filename is given, we will fabricate one. + +Use the 'source' command in another debug session to restore them.} + end + end + end +end diff --git a/cli/ruby-debug/commands/.svn/text-base/set.rb.svn-base b/cli/ruby-debug/commands/.svn/text-base/set.rb.svn-base new file mode 100644 index 0000000..df9bcfb --- /dev/null +++ b/cli/ruby-debug/commands/.svn/text-base/set.rb.svn-base @@ -0,0 +1,237 @@ +module Debugger + # Implements debugger "set" command. + class SetCommand < Command + SubcmdStruct2=Struct.new(:name, :min, :is_bool, :short_help, + :long_help) unless defined?(SubcmdStruct2) + Subcommands = + [ + ['annotate', 2, false, + "Set annotation level", +"0 == normal; +2 == output annotated suitably for use by programs that control +ruby-debug."], + ['args', 2, false, + "Set argument list to give program being debugged when it is started", +"Follow this command with any number of args, to be passed to the program."], + ['autoeval', 4, true, + "Evaluate every unrecognized command"], + ['autolist', 4, true, + "Execute 'list' command on every breakpoint"], + ['autoirb', 4, true, + "Invoke IRB on every stop"], + ['autoreload', 4, true, + "Reload source code when changed"], + ['basename', 1, true, + "Report file basename only showing file names"], + ['callstyle', 2, false, + "Set how you want call parameters displayed"], + ['debuggertesting', 8, false, + "Used when testing the debugger"], + ['forcestep', 2, true, + "Make sure 'next/step' commands always move to a new line"], + ['fullpath', 2, true, + "Display full file names in frames"], + ['history', 2, false, + "Generic command for setting command history parameters", +"set history filename -- Set the filename in which to record the command history +set history save -- Set saving of the history record on exit +set history size -- Set the size of the command history"], + ['keep-frame-bindings', 1, true, + "Save frame binding on each call"], + ['linetrace+', 10, true, + "Set line execution tracing to show different lines"], + ['linetrace', 3, true, + "Set line execution tracing"], + ['listsize', 3, false, + "Set number of source lines to list by default"], +# ['post-mortem', 3, true, +# "Set whether we do post-mortem handling on an uncaught exception"], + ['trace', 1, true, + "Display stack trace when 'eval' raises exception"], + ['width', 1, false, + "Number of characters the debugger thinks are in a line"], + ].map do |name, min, is_bool, short_help, long_help| + SubcmdStruct2.new(name, min, is_bool, short_help, long_help) + end unless defined?(Subcommands) + + self.allow_in_control = true + + def regexp + /^set (?: \s+ (.*) )?$/ix + end + + def execute + if not @match[1] + print "\"set\" must be followed by the name of an set command:\n" + print "List of set subcommands:\n\n" + for subcmd in Subcommands do + print "set #{subcmd.name} -- #{subcmd.short_help}\n" + end + else + args = @match[1].split(/[ \t]+/) + subcmd = args.shift + subcmd.downcase! + if subcmd =~ /^no/i + set_on = false + subcmd = subcmd[2..-1] + else + set_on = true + end + for try_subcmd in Subcommands do + if (subcmd.size >= try_subcmd.min) and + (try_subcmd.name[0..subcmd.size-1] == subcmd) + begin + if try_subcmd.is_bool + if args.size > 0 + set_on = get_onoff(args[0]) + end + end + case try_subcmd.name + when /^annotate$/ + level = get_int(args[0], "Set annotate", 0, 3, 0) + if level + Debugger.annotate = level + else + return + end + if defined?(Debugger::RDEBUG_SCRIPT) + # rdebug was called initially. 1st arg is script name. + Command.settings[:argv][1..-1] = args + else + # rdebug wasn't called initially. 1st arg is not script name. + Command.settings[:argv] = args + end + when /^args$/ + Command.settings[:argv][1..-1] = args + when /^autolist$/ + Command.settings[:autolist] = (set_on ? 1 : 0) + when /^autoeval$/ + Command.settings[:autoeval] = set_on + when /^basename$/ + Command.settings[:basename] = set_on + when /^callstyle$/ + if args[0] + arg = args[0].downcase.to_sym + case arg + when :short, :last, :tracked + Command.settings[:callstyle] = arg + Debugger.track_frame_args = arg == :tracked ? true : false + print "%s\n" % show_setting(try_subcmd.name) + return + end + end + print "Invalid call style #{arg}. Should be one of: " + + "'short', 'last', or 'tracked'.\n" + when /^trace$/ + Command.settings[:stack_trace_on_error] = set_on + when /^fullpath$/ + Command.settings[:full_path] = set_on + when /^autoreload$/ + Command.settings[:reload_source_on_change] = set_on + when /^autoirb$/ + Command.settings[:autoirb] = (set_on ? 1 : 0) + when /^debuggertesting$/ + Command.settings[:debuggertesting] = set_on + if set_on + Command.settings[:basename] = true + end + when /^forcestep$/ + self.class.settings[:force_stepping] = set_on + when /^history$/ + if 2 == args.size + interface = @state.interface + case args[0] + when /^save$/ + interface.history_save = get_onoff(args[1]) + when /^size$/ + interface.history_length = get_int(args[1], + "Set history size") + else + print "Invalid history parameter #{args[0]}. Should be 'save' or 'size'.\n" + end + else + print "Need two parameters for 'set history'; got #{args.size}.\n" + return + end + when /^keep-frame-bindings$/ + Debugger.keep_frame_binding = set_on + when /^linetrace\+$/ + self.class.settings[:tracing_plus] = set_on + when /^linetrace$/ + Debugger.tracing = set_on + when /^listsize$/ + listsize = get_int(args[0], "Set listsize", 1, nil, 10) + if listsize + self.class.settings[:listsize] = listsize + else + return + end +# when /^post-mortem$/ +# unless Debugger.post_mortem? == set_on +# if set_on +# Debugger.post_mortem +# else +# errmsg "Can't turn off post-mortem once it is on.\n" +# return +# end +# end + when /^width$/ + width = get_int(args[0], "Set width", 10, nil, 80) + if width + self.class.settings[:width] = width + ENV['COLUMNS'] = width.to_s + else + return + end + else + print "Unknown setting #{@match[1]}.\n" + return + end + print "%s\n" % show_setting(try_subcmd.name) + return + rescue RuntimeError + return + end + end + end + print "Unknown set command #{subcmd}\n" + end + end + + class << self + def help_command + "set" + end + + def help(args) + if args[1] + s = args[1] + subcmd = Subcommands.find do |try_subcmd| + (s.size >= try_subcmd.min) and + (try_subcmd.name[0..s.size-1] == s) + end + if subcmd + str = subcmd.short_help + '.' + str += "\n" + subcmd.long_help if subcmd.long_help + return str + else + return "Invalid 'set' subcommand '#{args[1]}'." + end + end + s = %{ + Modifies parts of the ruby-debug environment. Boolean values take + on, off, 1 or 0. + You can see these environment settings with the \"show\" command. + + -- + List of set subcommands: + -- + } + for subcmd in Subcommands do + s += "set #{subcmd.name} -- #{subcmd.short_help}\n" + end + return s + end + end + end +end diff --git a/cli/ruby-debug/commands/.svn/text-base/show.rb.svn-base b/cli/ruby-debug/commands/.svn/text-base/show.rb.svn-base new file mode 100644 index 0000000..f2992ad --- /dev/null +++ b/cli/ruby-debug/commands/.svn/text-base/show.rb.svn-base @@ -0,0 +1,253 @@ +module Debugger + # Mix-in module to showing settings + module ShowFunctions # :nodoc: + def show_setting(setting_name) + case setting_name + when /^annotate$/ + Debugger.annotate ||= 0 + return ("Annotation level is #{Debugger.annotate}") + when /^args$/ + if Command.settings[:argv] and Command.settings[:argv].size > 0 + if defined?(Debugger::RDEBUG_SCRIPT) + # rdebug was called initially. 1st arg is script name. + args = Command.settings[:argv][1..-1].join(' ') + else + # rdebug wasn't called initially. 1st arg is not script name. + args = Command.settings[:argv].join(' ') + end + else + args = '' + end + return "Argument list to give program being debugged when it is started is \"#{args}\"." + when /^autolist$/ + on_off = Command.settings[:autolist] > 0 + return "autolist is #{show_onoff(on_off)}." + when /^autoeval$/ + on_off = Command.settings[:autoeval] + return "autoeval is #{show_onoff(on_off)}." + when /^autoreload$/ + on_off = Command.settings[:reload_source_on_change] + return "autoreload is #{show_onoff(on_off)}." + when /^autoirb$/ + on_off = Command.settings[:autoirb] > 0 + return "autoirb is #{show_onoff(on_off)}." + when /^basename$/ + on_off = Command.settings[:basename] + return "basename is #{show_onoff(on_off)}." + when /^callstyle$/ + style = Command.settings[:callstyle] + return "Frame call-display style is #{style}." + when /^commands(:?\s+(\d+))?$/ + if @state.interface.readline_support? + s = ''; + args = @match[1].split + if args[1] + first_line = args[1].to_i - 4 + last_line = first_line + 10 - 1 + if first_line > Readline::HISTORY.length + first_line = last_line = Readline::HISTORY.length + elsif first_line <= 0 + first_line = 1 + end + if last_line > Readline::HISTORY.length + last_line = Readline::HISTORY.length + end + i = first_line + commands = Readline::HISTORY.to_a[first_line..last_line] + else + if Readline::HISTORY.length > 10 + commands = Readline::HISTORY.to_a[-10..-1] + i = Readline::HISTORY.length - 10 + else + commands = Readline::HISTORY.to_a + i = 1 + end + end + commands.each do |cmd| + s += ("%5d %s\n" % [i, cmd]) + i += 1 + end + else + s='No readline suport' + end + return s + when /^debuggertesting$/ + on_off = Command.settings[:debuggertesting] + return "Currently testing the debugger is #{show_onoff(on_off)}." + when /^forcestep$/ + on_off = self.class.settings[:force_stepping] + return "force-stepping is #{show_onoff(on_off)}." + when /^fullpath$/ + on_off = Command.settings[:full_path] + return "Displaying frame's full file names is #{show_onoff(on_off)}." + when /^history(:?\s+(filename|save|size))?$/ + args = @match[1].split + interface = @state.interface + if args[1] + show_save = show_size = show_filename = false + prefix = false + if args[1] == "save" + show_save = true + elsif args[1] == "size" + show_size = true + elsif args[1] == "filename" + show_filename = true + end + else + show_save = show_size = show_filename = true + prefix = true + end + s = [] + if show_filename + msg = (prefix ? "filename: " : "") + + "The filename in which to record the command history is " + + "#{interface.histfile.inspect}" + s << msg + end + if show_save + msg = (prefix ? "save: " : "") + + "Saving of history save is #{show_onoff(interface.history_save)}." + s << msg + end + if show_size + msg = (prefix ? "size: " : "") + + "Debugger history size is #{interface.history_length}" + s << msg + end + return s.join("\n") + when /^keep-frame-bindings$/ + on_off = Debugger.keep_frame_binding? + return "keep-frame-bindings is #{show_onoff(on_off)}." + when /^linetrace$/ + on_off = Debugger.tracing + return "line tracing is #{show_onoff(on_off)}." + when /^linetrace\+$/ + on_off = Command.settings[:tracing_plus] + if on_off + return "line tracing style is different consecutive lines." + else + return "line tracing style is every line." + end + when /^listsize$/ + listlines = Command.settings[:listsize] + return "Number of source lines to list by default is #{listlines}." + when /^port$/ + return "server port is #{Debugger::PORT}." + when /^post-mortem$/ + on_off = Debugger.post_mortem? + return "post-mortem handling is #{show_onoff(on_off)}." + when /^trace$/ + on_off = Command.settings[:stack_trace_on_error] + return "Displaying stack trace is #{show_onoff(on_off)}." + when /^version$/ + return "ruby-debug #{Debugger::VERSION}" + when /^width$/ + return "width is #{self.class.settings[:width]}." + else + return "Unknown show subcommand #{setting_name}." + end + end + end + + # Implements debugger "show" command. + class ShowCommand < Command + + Subcommands = + [ + ['annotate', 2, "Show annotation level", +"0 == normal; 2 == output annotated suitably for use by programs that control +ruby-debug."], + ['args', 2, + "Show argument list to give program being debugged when it is started", +"Follow this command with any number of args, to be passed to the program."], + ['autoeval', 4, "Show if unrecognized command are evaluated"], + ['autolist', 4, "Show if 'list' commands is run on breakpoints"], + ['autoirb', 4, "Show if IRB is invoked on debugger stops"], + ['autoreload', 4, "Show if source code is reloaded when changed"], + ['basename', 1, "Show if basename used in reporting files"], + ['callstyle', 2, "Show paramater style used showing call frames"], + ['commands', 2, "Show the history of commands you typed", +"You can supply a command number to start with."], + ['forcestep', 1, "Show if sure 'next/step' forces move to a new line"], + ['fullpath', 2, "Show if full file names are displayed in frames"], + ['history', 2, "Generic command for showing command history parameters", +"show history filename -- Show the filename in which to record the command history +show history save -- Show saving of the history record on exit +show history size -- Show the size of the command history"], + ['keep-frame-bindings', 1, "Save frame binding on each call"], + ['linetrace', 3, "Show line execution tracing"], + ['linetrace+', 10, + "Show if consecutive lines should be different are shown in tracing"], + ['listsize', 3, "Show number of source lines to list by default"], + ['port', 3, "Show server port"], + ['post-mortem', 3, "Show whether we go into post-mortem debugging on an uncaught exception"], + ['trace', 1, + "Show if a stack trace is displayed when 'eval' raises exception"], + ['version', 1, + "Show what version of the debugger this is"], + ['width', 1, + "Show the number of characters the debugger thinks are in a line"], + ].map do |name, min, short_help, long_help| + SubcmdStruct.new(name, min, short_help, long_help) + end unless defined?(Subcommands) + + self.allow_in_control = true + + def regexp + /^show (?: \s+ (.+) )?$/xi + end + + def execute + if not @match[1] + print "\"show\" must be followed by the name of an show command:\n" + print "List of show subcommands:\n\n" + for subcmd in Subcommands do + print "show #{subcmd.name} -- #{subcmd.short_help}\n" + end + else + args = @match[1].split(/[ \t]+/) + param = args.shift + subcmd = find(Subcommands, param) + if subcmd + print "%s\n" % show_setting(subcmd.name) + else + print "Unknown show command #{param}\n" + end + end + end + + class << self + def help_command + "show" + end + + def help(args) + if args[1] + s = args[1] + subcmd = Subcommands.find do |try_subcmd| + (s.size >= try_subcmd.min) and + (try_subcmd.name[0..s.size-1] == s) + end + if subcmd + str = subcmd.short_help + '.' + str += "\n" + subcmd.long_help if subcmd.long_help + return str + else + return "Invalid 'show' subcommand '#{args[1]}'." + end + end + s = " + Generic command for showing things about the debugger. + + -- + List of show subcommands: + -- + " + for subcmd in Subcommands do + s += "show #{subcmd.name} -- #{subcmd.short_help}\n" + end + return s + end + end + end +end diff --git a/cli/ruby-debug/commands/.svn/text-base/source.rb.svn-base b/cli/ruby-debug/commands/.svn/text-base/source.rb.svn-base new file mode 100644 index 0000000..a5e7179 --- /dev/null +++ b/cli/ruby-debug/commands/.svn/text-base/source.rb.svn-base @@ -0,0 +1,36 @@ +module Debugger + # Implements debugger "source" command. + class SourceCommand < Command + self.allow_in_control = true + + def regexp + /^\s* so(?:urce)? \s+ (.+) $/x + end + + def execute + file = File.expand_path(@match[1]).strip + unless File.exist?(file) + errmsg "Command file '#{file}' is not found\n" + return + end + if @state and @state.interface + @state.interface.command_queue += File.open(file).readlines + else + Debugger.run_script(file, @state) + end + end + + class << self + def help_command + 'source' + end + + def help(cmd) + %{ + source FILE\texecutes a file containing debugger commands + } + end + end + end + +end diff --git a/cli/ruby-debug/commands/.svn/text-base/stepping.rb.svn-base b/cli/ruby-debug/commands/.svn/text-base/stepping.rb.svn-base new file mode 100644 index 0000000..5b1c3b2 --- /dev/null +++ b/cli/ruby-debug/commands/.svn/text-base/stepping.rb.svn-base @@ -0,0 +1,81 @@ +module Debugger + # Mix-in module to assist in command parsing. + module SteppingFunctions # :nodoc: + def parse_stepping_args(command_name, match) + if match[1].nil? + force = Command.settings[:force_stepping] + elsif match[1] == '+' + force = true + elsif match[1] == '-' + force = false + end + steps = get_int(match[2], command_name, 1) + return [steps, force] + end + end + # Implements debugger "next" command. + class NextCommand < Command + self.allow_in_post_mortem = false + self.need_context = true + + def regexp + /^\s* n(?:ext)? + ([+-])?(?:\s+(\S+))? + \s*$/x + end + + def execute + steps, force = parse_stepping_args("Next", @match) + return unless steps + @state.context.step_over steps, @state.frame_pos, force + @state.proceed + end + + class << self + def help_command + 'next' + end + + def help(cmd) + %{ + n[ext][+-]?[ nnn]\tstep over once or nnn times, + \t\t'+' forces to move to another line. + \t\t'-' is the opposite of '+' and disables the force_stepping setting. + } + end + end + end + + # Implements debugger "step" command. + class StepCommand < Command + self.allow_in_post_mortem = false + self.need_context = true + + def regexp + /^\s* s(?:tep)? + ([+-])?(?:\s+(\S+))? + \s*$/x + end + + def execute + steps, force = parse_stepping_args("Step", @match) + return unless steps + @state.context.step(steps, force) + @state.proceed + end + + class << self + def help_command + 'step' + end + + def help(cmd) + %{ + s[tep][+-]?[ nnn]\tstep (into methods) once or nnn times + \t\t'+' forces to move to another line. + \t\t'-' is the opposite of '+' and disables the force_stepping setting. + } + end + end + end +end diff --git a/cli/ruby-debug/commands/.svn/text-base/threads.rb.svn-base b/cli/ruby-debug/commands/.svn/text-base/threads.rb.svn-base new file mode 100644 index 0000000..c06c8bf --- /dev/null +++ b/cli/ruby-debug/commands/.svn/text-base/threads.rb.svn-base @@ -0,0 +1,189 @@ +module Debugger + module ThreadFunctions # :nodoc: + def display_context(c, show_top_frame=true) + c_flag = c.thread == Thread.current ? '+' : ' ' + c_flag = '$' if c.suspended? + d_flag = c.ignored? ? '!' : ' ' + print "%s%s", c_flag, d_flag + print "%d ", c.thnum + print "%s\t", c.thread.inspect + if c.stack_size > 0 and show_top_frame + print "%s:%d", c.frame_file(0), c.frame_line(0) + end + print "\n" + end + + def parse_thread_num(subcmd, arg) + if '' == arg + errmsg "'%s' needs a thread number\n" % subcmd + nil + else + thread_num = get_int(arg, "thread #{subcmd}", 1) + return nil unless thread_num + get_context(thread_num) + end + end + + def parse_thread_num_for_cmd(subcmd, arg) + c = parse_thread_num(subcmd, arg) + return nil unless c + case + when nil == c + errmsg "No such thread.\n" + when @state.context == c + errmsg "It's the current thread.\n" + when c.ignored? + errmsg "Can't #{subcmd} to the debugger thread #{arg}.\n" + else # Everything is okay + return c + end + return nil + end + end + + class ThreadListCommand < Command # :nodoc: + self.allow_in_control = true + + def regexp + /^\s*th(?:read)?\s+l(?:ist)?\s*$/ + end + + def execute + threads = Debugger.contexts.sort_by{|c| c.thnum}.each do |c| + display_context(c) + end + end + + class << self + def help_command + 'thread' + end + + def help(cmd) + %{ + th[read] l[ist]\t\t\tlist all threads + } + end + end + end + + class ThreadStopCommand < Command # :nodoc: + self.allow_in_control = true + self.allow_in_post_mortem = false + self.need_context = true + + def regexp + /^\s*th(?:read)?\s+stop\s*(\S*)\s*$/ + end + + def execute + c = parse_thread_num_for_cmd("thread stop", @match[1]) + return unless c + c.suspend + display_context(c) + end + + class << self + def help_command + 'thread' + end + + def help(cmd) + %{ + th[read] stop \t\tstop thread nnn + } + end + end + end + + class ThreadResumeCommand < Command # :nodoc: + self.allow_in_post_mortem = false + self.allow_in_control = true + self.need_context = true + + def regexp + /^\s*th(?:read)?\s+resume\s*(\S*)\s*$/ + end + + def execute + c = parse_thread_num_for_cmd("thread resume", @match[1]) + return unless c + if !c.thread.stop? + print "Already running." + return + end + c.resume + display_context(c) + end + + class << self + def help_command + 'thread' + end + + def help(cmd) + %{ + th[read] resume \t\tresume thread nnn + } + end + end + end + + # Thread switch Must come after "Thread resume" because "switch" is + # optional + + class ThreadSwitchCommand < Command # :nodoc: + self.allow_in_control = true + self.allow_in_post_mortem = false + self.need_context = true + + def regexp + /^\s*th(?:read)?\s*(?:sw(?:itch)?)?\s+(\S+)\s*$/ + end + + def execute + c = parse_thread_num_for_cmd("thread switch", @match[1]) + return unless c + display_context(c) + c.stop_next = 1 + c.thread.run + @state.proceed + end + + class << self + def help_command + 'thread' + end + + def help(cmd) + %{ + th[read] [sw[itch]] \tswitch thread context to nnn + } + end + end + end + + class ThreadCurrentCommand < Command # :nodoc: + self.need_context = true + + def regexp + /^\s*th(?:read)?\s*(?:cur(?:rent)?)?\s*$/ + end + + def execute + display_context(@state.context) + end + + class << self + def help_command + 'thread' + end + + def help(cmd) + %{ + th[read] [cur[rent]]\t\tshow current thread + } + end + end + end +end diff --git a/cli/ruby-debug/commands/.svn/text-base/tmate.rb.svn-base b/cli/ruby-debug/commands/.svn/text-base/tmate.rb.svn-base new file mode 100644 index 0000000..060a7d1 --- /dev/null +++ b/cli/ruby-debug/commands/.svn/text-base/tmate.rb.svn-base @@ -0,0 +1,36 @@ +module Debugger + if RUBY_PLATFORM =~ /darwin/ + class TextMateCommand < Command # :nodoc: + def regexp + /^\s*tm(?:ate)?(?:\s*(\d+))?$/ + end + + def execute + if @match[1] + frm_n = @match[1].to_i + if frm_n > @state.context.stack_size || frm_n == 0 + print "Wrong frame number\n" + return + end + file, line = @state.context.frame_file(frm_n-1), @state.context.frame_line(frm_n-1) + else + file, line = @state.file, @state.line + end + %x|open 'txmt://open?url=file://#{File.expand_path(file)}&line=#{line}'| + end + + class << self + def help_command + 'tmate' + end + + def help(cmd) + %{ + tm[ate] n\topens a current file in TextMate. + \t\tIt uses n-th frame if arg (n) is specifed. + } + end + end + end + end +end diff --git a/cli/ruby-debug/commands/.svn/text-base/trace.rb.svn-base b/cli/ruby-debug/commands/.svn/text-base/trace.rb.svn-base new file mode 100644 index 0000000..ed063aa --- /dev/null +++ b/cli/ruby-debug/commands/.svn/text-base/trace.rb.svn-base @@ -0,0 +1,57 @@ +module Debugger + class TraceCommand < Command # :nodoc: + def regexp + /^\s* tr(?:ace)? (?: \s+ (\S+)) # on |off | var(iable) + (?: \s+ (\S+))? # (all | variable-name)? + (?: \s+ (\S+))? \s* # (stop | nostop)? + $/ix + end + + def execute + if @match[1] =~ /on|off/ + onoff = 'on' == @match[1] + if @match[2] + Debugger.current_context.tracing = onoff + print "Tracing %s all threads.\n" % (onoff ? 'on' : 'off') + else + Debugger.tracing = onoff + print "Tracing %s on current thread.\n" % (onoff ? 'on' : 'off') + end + elsif @match[1] =~ /var(?:iable)?/ + varname=@match[2] + if debug_eval("defined?(#{varname})") + if @match[3] && @match[3] !~ /(:?no)?stop/ + errmsg("expecting 'stop' or 'nostop'; got %s\n" % @match[3]) + else + dbg_cmd = if @match[3] && (@match[3] !~ /nostop/) + 'debugger' else '' end + end + eval(" + trace_var(:#{varname}) do |val| + print \"traced variable #{varname} has value \#{val}\n\" + #{dbg_cmd} + end") + else + errmsg "#{varname} is not a global variable.\n" + end + else + errmsg("expecting 'on', 'off', 'var' or 'variable'; got: %s\n" % + @match[1]) + end + end + + class << self + def help_command + 'trace' + end + + def help(cmd) + %{ + tr[ace] (on|off)\tset trace mode of current thread + tr[ace] (on|off) all\tset trace mode of all threads + tr[ace] var(iable) VARNAME [stop|nostop]\tset trace variable on VARNAME + } + end + end + end +end diff --git a/cli/ruby-debug/commands/.svn/text-base/variables.rb.svn-base b/cli/ruby-debug/commands/.svn/text-base/variables.rb.svn-base new file mode 100644 index 0000000..e326e46 --- /dev/null +++ b/cli/ruby-debug/commands/.svn/text-base/variables.rb.svn-base @@ -0,0 +1,199 @@ +module Debugger + module VarFunctions # :nodoc: + def var_list(ary, b = get_binding) + ary.sort! + for v in ary + begin + s = debug_eval(v, b).inspect + rescue + begin + s = debug_eval(v, b).to_s + rescue + s = "*Error in evaluation*" + end + end + if s.size > self.class.settings[:width] + s[self.class.settings[:width]-3 .. -1] = "..." + end + print "%s = %s\n", v, s + end + end + def var_class_self + obj = debug_eval('self') + var_list(obj.class.class_variables, get_binding) + end + end + + # Implements the debugger 'var class' command. + class VarClassVarCommand < Command + def regexp + /^\s*v(?:ar)?\s+cl(?:ass)?/ + end + + def execute + unless @state.context + errmsg "can't get class variables here.\n" + return + end + var_class_self + end + + class << self + def help_command + 'var' + end + + def help(cmd) + %{ + v[ar] cl[ass] \t\t\tshow class variables of self + } + end + end + end + + class VarConstantCommand < Command # :nodoc: + def regexp + /^\s*v(?:ar)?\s+co(?:nst(?:ant)?)?\s+/ + end + + def execute + obj = debug_eval(@match.post_match) + if obj.kind_of? Module + constants = debug_eval("#{@match.post_match}.constants") + constants.sort! + for c in constants + next if c =~ /SCRIPT/ + value = obj.const_get(c) rescue "ERROR: #{$!}" + print " %s => %p\n", c, value + end + else + print "Should be Class/Module: %s\n", @match.post_match + end + end + + class << self + def help_command + 'var' + end + + def help(cmd) + %{ + v[ar] c[onst] \t\tshow constants of object + } + end + end + end + + class VarGlobalCommand < Command # :nodoc: + def regexp + /^\s*v(?:ar)?\s+g(?:lobal)?\s*$/ + end + + def execute + var_list(global_variables) + end + + class << self + def help_command + 'var' + end + + def help(cmd) + %{ + v[ar] g[lobal]\t\t\tshow global variables + } + end + end + end + + class VarInstanceCommand < Command # :nodoc: + def regexp + /^\s*v(?:ar)?\s+ins(?:tance)?\s*/ + end + + def execute + obj = debug_eval(@match.post_match.empty? ? 'self' : @match.post_match) + var_list(obj.instance_variables, obj.instance_eval{binding()}) + end + + class << self + def help_command + 'var' + end + + def help(cmd) + %{ + v[ar] i[nstance] \tshow instance variables of object + } + end + end + end + + # Implements the debugger 'var local' command. + class VarLocalCommand < Command + def regexp + /^\s*v(?:ar)?\s+l(?:ocal)?\s*$/ + end + + def execute + locals = @state.context.frame_locals(@state.frame_pos) + _self = @state.context.frame_self(@state.frame_pos) + locals.keys.sort.each do |name| + print " %s => %p\n", name, locals[name] + end + end + + class << self + def help_command + 'var' + end + + def help(cmd) + %{ + v[ar] l[ocal]\t\t\tshow local variables + } + end + end + end + + # Implements the debugger 'var inherit' command. + begin + require 'classtree' + have_classtree = true + rescue LoadError + have_classtree = false + end + + class VarInheritCommand < Command + def regexp + /^\s*v(?:ar)?\s+ct\s*/ + end + + def execute + unless @state.context + errmsg "can't get object inheritance.\n" + return + end + puts @match.post_match + obj = debug_eval("#{@match.post_match}.classtree") + if obj + print obj + else + errmsg "Trouble getting object #{@match.post_match}\n" + end + end + + class << self + def help_command + 'var' + end + + def help(cmd) + %{ + v[ar] ct\t\t\tshow class heirarchy of object + } + end + end + end if have_classtree + +end diff --git a/cli/ruby-debug/commands/breakpoints.rb b/cli/ruby-debug/commands/breakpoints.rb new file mode 100644 index 0000000..d3b9901 --- /dev/null +++ b/cli/ruby-debug/commands/breakpoints.rb @@ -0,0 +1,153 @@ +module Debugger + + # Implements debugger "break" command. + class AddBreakpoint < Command + self.allow_in_control = true + + def regexp + / ^\s* + b(?:reak)? + (?: \s+ #{Position_regexp})? \s* + (?: \s+ (.*))? \s* + $ + /x + end + + def execute + if @match[1] + line, _, _, expr = @match.captures + else + _, file, line, expr = @match.captures + end + if expr + if expr !~ /^\s*if\s+(.+)/ + if file or line + errmsg "Expecting 'if' in breakpoint condition; got: #{expr}.\n" + else + errmsg "Invalid breakpoint location: #{expr}.\n" + end + return + else + expr = $1 + end + end + + brkpt_filename = nil + if file.nil? + unless @state.context + errmsg "We are not in a state that has an associated file.\n" + return + end + brkpt_filename = @state.file + file = File.basename(@state.file) + if line.nil? + # Set breakpoint at current line + line = @state.line.to_s + end + elsif line !~ /^\d+$/ + # See if "line" is a method/function name + klass = debug_silent_eval(file) + if klass && klass.kind_of?(Module) + class_name = klass.name if klass + else + errmsg "Unknown class #{file}.\n" + throw :debug_error + end + else + # FIXME: This should be done in LineCache. + file = File.expand_path(file) if file.index(File::SEPARATOR) || \ + File::ALT_SEPARATOR && file.index(File::ALT_SEPARATOR) + brkpt_filename = file + end + + if line =~ /^\d+$/ + line = line.to_i + if LineCache.cache(brkpt_filename, Command.settings[:reload_source_on_change]) + last_line = LineCache.size(brkpt_filename) + if line > last_line + errmsg("There are only %d lines in file \"%s\".\n", last_line, file) + return + end + unless LineCache.trace_line_numbers(brkpt_filename).member?(line) + errmsg("Line %d is not a stopping point in file \"%s\".\n", line, file) + return + end + else + errmsg("No source file named %s\n" % file) + return unless confirm("Set breakpoint anyway? (y/n) ") + end + + unless @state.context + errmsg "We are not in a state we can add breakpoints.\n" + return + end + b = Debugger.add_breakpoint brkpt_filename, line, expr + print "Breakpoint %d file %s, line %s\n", b.id, brkpt_filename, line.to_s + unless syntax_valid?(expr) + errmsg("Expression \"#{expr}\" syntactically incorrect; breakpoint disabled.\n") + b.enabled = false + end + else + method = line.intern.id2name + b = Debugger.add_breakpoint class_name, method, expr + print "Breakpoint %d at %s::%s\n", b.id, class_name, method.to_s + end + end + + class << self + def help_command + 'break' + end + + def help(cmd) + %{ + b[reak] file:line [if expr] + b[reak] class(.|#)method [if expr] + \tset breakpoint to some position, (optionally) if expr == true + } + end + end + end + + # Implements debugger "delete" command. + class DeleteBreakpointCommand < Command + self.allow_in_control = true + + def regexp + /^\s *del(?:ete)? (?:\s+(.*))?$/ix + end + + def execute + unless @state.context + errmsg "We are not in a state we can delete breakpoints.\n" + return + end + brkpts = @match[1] + unless brkpts + if confirm("Delete all breakpoints? (y or n) ") + Debugger.breakpoints.clear + end + else + brkpts.split(/[ \t]+/).each do |pos| + pos = get_int(pos, "Delete", 1) + return unless pos + unless Debugger.remove_breakpoint(pos) + errmsg "No breakpoint number %d\n", pos + end + end + end + end + + class << self + def help_command + 'delete' + end + + def help(cmd) + %{ + del[ete][ nnn...]\tdelete some or all breakpoints + } + end + end + end +end diff --git a/cli/ruby-debug/commands/catchpoint.rb b/cli/ruby-debug/commands/catchpoint.rb new file mode 100644 index 0000000..964f6ab --- /dev/null +++ b/cli/ruby-debug/commands/catchpoint.rb @@ -0,0 +1,55 @@ +module Debugger + class CatchCommand < Command # :nodoc: + self.allow_in_control = true + + def regexp + /^\s* cat(?:ch)? + (?:\s+ (\S+))? + (?:\s+ (off))? \s* $/ix + end + + def execute + excn = @match[1] + if not excn + # No args given. + info_catch + elsif not @match[2] + # One arg given. + if 'off' == excn + Debugger.catchpoints.clear if + confirm("Delete all catchpoints? (y or n) ") + else + binding = @state.context ? get_binding : TOPLEVEL_BINDING + unless debug_eval("#{excn}.is_a?(Class)", binding) + print "Warning #{excn} is not known to be a Class\n" + end + Debugger.add_catchpoint(excn) + print "Catch exception %s.\n", excn + end + elsif @match[2] != 'off' + errmsg "Off expected. Got %s\n", @match[2] + elsif Debugger.catchpoints.member?(excn) + Debugger.catchpoints.delete(excn) + print "Catch for exception %s removed.\n", excn + else + errmsg "Catch for exception %s not found.\n", excn + end + end + + class << self + def help_command + 'catch' + end + + def help(cmd) + %{ + cat[ch]\t\tsame as "info catch" + cat[ch] [on|off] +\tIntercept when there would otherwise be no handler. +\tWith an "on" or "off", turn handling the exception on or off. + cat[ch] off\tdelete all catchpoints + } + end + end + end +end diff --git a/cli/ruby-debug/commands/condition.rb b/cli/ruby-debug/commands/condition.rb new file mode 100644 index 0000000..322812e --- /dev/null +++ b/cli/ruby-debug/commands/condition.rb @@ -0,0 +1,49 @@ +module Debugger + + class ConditionCommand < Command # :nodoc: + + def regexp + /^\s* cond(?:ition)? (?:\s+(\d+)\s*(.*))?$/ix + end + + def execute + if not @match[1] + errmsg "\"condition\" must be followed a breakpoint number and expression\n" + else + breakpoints = Debugger.breakpoints.sort_by{|b| b.id } + largest = breakpoints.inject(0) do |largest, b| + largest = b.id if b.id > largest + end + if 0 == largest + print "No breakpoints have been set.\n" + return + end + pos = get_int(@match[1], "Condition", 1, largest) + return unless pos + breakpoints.each do |b| + if b.id == pos + b.expr = @match[2].empty? ? nil : @match[2] + break + end + end + + end + end + + class << self + def help_command + 'condition' + end + + def help(cmd) + %{ + Condition breakpoint-number expression +Specify breakpoint number N to break only if COND is true. +N is an integer and COND is an expression to be evaluated whenever +breakpoint N is reached. If the empty string is used, the condition is removed. + } + end + end + end + +end # module Debugger diff --git a/cli/ruby-debug/commands/continue.rb b/cli/ruby-debug/commands/continue.rb new file mode 100644 index 0000000..5bee4b3 --- /dev/null +++ b/cli/ruby-debug/commands/continue.rb @@ -0,0 +1,38 @@ +module Debugger + + # Implements debugger "continue" command. + class ContinueCommand < Command + self.allow_in_post_mortem = true + self.need_context = false + def regexp + /^\s* c(?:ont(?:inue)?)? (?:\s+(.*))? $/x + end + + def execute + if @match[1] && !@state.context.dead? + filename = File.expand_path(@state.file) + line_number = get_int(@match[1], "Continue", 0, nil, 0) + return unless line_number + unless LineCache.trace_line_numbers(filename).member?(line_number) + errmsg("Line %d is not a stopping point in file \"%s\".\n", + line_number, filename) + return + end + @state.context.set_breakpoint(filename, line_number) + end + @state.proceed + end + + class << self + def help_command + 'continue' + end + + def help(cmd) + %{ + c[ont[inue]][ nnn]\trun until program ends, hits a breakpoint or reaches line nnn + } + end + end + end +end diff --git a/cli/ruby-debug/commands/control.rb b/cli/ruby-debug/commands/control.rb new file mode 100644 index 0000000..78e11b5 --- /dev/null +++ b/cli/ruby-debug/commands/control.rb @@ -0,0 +1,107 @@ +module Debugger + class RestartCommand < Command # :nodoc: + self.allow_in_control = true + + def regexp + / ^\s* + (?:restart|R) + (?:\s+ (\S?.*\S))? \s* + $ + /ix + end + + def execute + if not defined? Debugger::PROG_SCRIPT + errmsg "Don't know name of debugged program\n" + return + end + prog_script = Debugger::PROG_SCRIPT + if not defined? Debugger::RDEBUG_SCRIPT + # FIXME? Should ask for confirmation? + print "Debugger was not called from the outset...\n" + rdebug_script = prog_script + else + rdebug_script = Debugger::RDEBUG_SCRIPT + end + begin + Dir.chdir(Debugger::INITIAL_DIR) + rescue + print "Failed to change initial directory #{Debugger::INITIAL_DIR}" + end + if not File.exist?(File.expand_path(prog_script)) + errmsg "Ruby program #{prog_script} doesn't exist\n" + return + end + if not File.executable?(prog_script) and rdebug_script == prog_script + print "Ruby program #{prog_script} doesn't seem to be executable...\n" + print "We'll add a call to Ruby.\n" + ruby = begin defined?(Gem) ? Gem.ruby : "ruby" rescue "ruby" end + rdebug_script = "#{ruby} -I#{$:.join(' -I')} #{prog_script}" + else + rdebug_script += ' ' + end + if @match[1] + argv = [prog_script] + @match[1].split(/[ \t]+/) + else + if not defined? Command.settings[:argv] + errmsg "Arguments have not been set. Use 'set args' to set them.\n" + return + else + argv = Command.settings[:argv] + end + end + args = argv.join(' ') + + # An execv would be preferable to the "exec" below. + cmd = rdebug_script + args + print "Re exec'ing:\n\t#{cmd}\n" + exec cmd + rescue Errno::EOPNOTSUPP + print "Restart command is not available at this time.\n" + end + + class << self + def help_command + 'restart' + end + + def help(cmd) + %{ + restart|R [args] + Restart the program. This is is a re-exec - all debugger state + is lost. If command arguments are passed those are used. + } + end + end + end + + class InterruptCommand < Command # :nodoc: + self.allow_in_control = true + self.allow_in_post_mortem = false + self.event = false + self.need_context = true + + def regexp + /^\s*i(?:nterrupt)?\s*$/ + end + + def execute + unless Debugger.interrupt_last + context = Debugger.thread_context(Thread.main) + context.interrupt + end + end + + class << self + def help_command + 'interrupt' + end + + def help(cmd) + %{ + i[nterrupt]\tinterrupt the program + } + end + end + end +end diff --git a/cli/ruby-debug/commands/display.rb b/cli/ruby-debug/commands/display.rb new file mode 100644 index 0000000..ff82079 --- /dev/null +++ b/cli/ruby-debug/commands/display.rb @@ -0,0 +1,120 @@ +module Debugger + module DisplayFunctions # :nodoc: + def display_expression(exp) + print "%s = %s\n", exp, debug_silent_eval(exp).to_s + end + + def active_display_expressions? + @state.display.select{|d| d[0]}.size > 0 + end + + def print_display_expressions + n = 1 + for d in @state.display + if d[0] + print "%d: ", n + display_expression(d[1]) + end + n += 1 + end + end + end + + class AddDisplayCommand < Command # :nodoc: + def regexp + /^\s*disp(?:lay)?\s+(.+)$/ + end + + def execute + exp = @match[1] + @state.display.push [true, exp] + print "%d: ", @state.display.size + display_expression(exp) + end + + class << self + def help_command + 'display' + end + + def help(cmd) + %{ + disp[lay] \tadd expression into display expression list + } + end + end + end + + class DisplayCommand < Command # :nodoc: + def self.always_run + Debugger.annotate = 0 unless Debugger.annotate + if Debugger.annotate > 1 + 0 + else + 2 + end + end + + def regexp + /^\s*disp(?:lay)?$/ + end + + def execute + print_display_expressions + end + + class << self + def help_command + 'display' + end + + def help(cmd) + %{ + disp[lay]\t\tdisplay expression list + } + end + end + end + + class DeleteDisplayCommand < Command # :nodoc: + + def regexp + /^\s* undisp(?:lay)? \s* (?:(\S+))?$/x + end + + def execute + unless pos = @match[1] + if confirm("Clear all expressions? (y/n) ") + for d in @state.display + d[0] = false + end + end + else + pos = get_int(pos, "Undisplay") + return unless pos + if @state.display[pos-1] + @state.display[pos-1][0] = nil + else + errmsg "Display expression %d is not defined.\n", pos + end + end + end + + class << self + def help_command + 'undisplay' + end + + def help(cmd) + %{ + undisp[lay][ nnn] + Cancel some expressions to be displayed when program stops. + Arguments are the code numbers of the expressions to stop displaying. + No argument means cancel all automatic-display expressions. + "delete display" has the same effect as this command. + Do "info display" to see current list of code numbers. + } + end + end + end +end diff --git a/cli/ruby-debug/commands/edit.rb b/cli/ruby-debug/commands/edit.rb new file mode 100644 index 0000000..ae12887 --- /dev/null +++ b/cli/ruby-debug/commands/edit.rb @@ -0,0 +1,48 @@ +module Debugger + class Edit < Command # :nodoc: + self.allow_in_control = true + def regexp + /^\s* ed(?:it)? (?:\s+(.*))?$/ix + end + + def execute + if not @match[1] or @match[1].strip.empty? + unless @state.context + errmsg "We are not in a state that has an associated file.\n" + return + end + file = @state.file + line_number = @state.line + elsif @pos_match = /([^:]+)[:]([0-9]+)/.match(@match[1]) + file, line_number = @pos_match.captures + else + errmsg "Invalid file/line number specification: #{@match[1]}\n" + return + end + editor = ENV['EDITOR'] || 'ex' + if File.readable?(file) + system("#{editor} +#{line_number} #{file}") + else + errmsg "File \"#{file}\" is not readable.\n" + end + end + + class << self + def help_command + 'edit' + end + + def help(cmd) + %{ + Edit specified file. + +With no argument, edits file containing most recent line listed. +Editing targets can also be specified in this: + FILE:LINENUM, to edit at that line in that file, + } + end + end + end + + +end # module Debugger diff --git a/cli/ruby-debug/commands/enable.rb b/cli/ruby-debug/commands/enable.rb new file mode 100644 index 0000000..d70f343 --- /dev/null +++ b/cli/ruby-debug/commands/enable.rb @@ -0,0 +1,202 @@ +module Debugger + # Mix-in module to assist in command parsing. + module EnableDisableFunctions # :nodoc: + def enable_disable_breakpoints(is_enable, args) + breakpoints = Debugger.breakpoints.sort_by{|b| b.id } + largest = breakpoints.inject(0) do |largest, b| + largest = b.id if b.id > largest + end + if 0 == largest + errmsg "No breakpoints have been set.\n" + return + end + args.each do |pos| + pos = get_int(pos, "#{is_enable} breakpoints", 1, largest) + return nil unless pos + breakpoints.each do |b| + if b.id == pos + enabled = ("Enable" == is_enable) + if enabled + unless syntax_valid?(b.expr) + errmsg("Expression \"#{b.expr}\" syntactically incorrect; breakpoint remains disabled.\n") + break + end + end + b.enabled = ("Enable" == is_enable) + break + end + end + end + end + + def enable_disable_display(is_enable, args) + if 0 == @state.display.size + errmsg "No display expressions have been set.\n" + return + end + args.each do |pos| + pos = get_int(pos, "#{is_enable} display", 1, @state.display.size) + return nil unless pos + @state.display[pos-1][0] = ("Enable" == is_enable) + end + end + + end + + class EnableCommand < Command # :nodoc: + Subcommands = + [ + ['breakpoints', 2, "Enable specified breakpoints", +"Give breakpoint numbers (separated by spaces) as arguments. +This is used to cancel the effect of the \"disable\" command." + ], + ['display', 2, + "Enable some expressions to be displayed when program stops", +"Arguments are the code numbers of the expressions to resume displaying. +Do \"info display\" to see current list of code numbers."], + ].map do |name, min, short_help, long_help| + SubcmdStruct.new(name, min, short_help, long_help) + end unless defined?(Subcommands) + + def regexp + /^\s* en(?:able)? (?:\s+(.*))?$/ix + end + + def execute + if not @match[1] + errmsg "\"enable\" must be followed \"display\", \"breakpoints\"" + + " or breakpoint numbers.\n" + else + args = @match[1].split(/[ \t]+/) + param = args.shift + subcmd = find(Subcommands, param) + if subcmd + send("enable_#{subcmd.name}", args) + else + send("enable_breakpoints", args.unshift(param)) + end + end + end + + def enable_breakpoints(args) + enable_disable_breakpoints("Enable", args) + end + + def enable_display(args) + enable_disable_display("Enable", args) + end + + class << self + def help_command + 'enable' + end + + def help(args) + if args[1] + s = args[1] + subcmd = Subcommands.find do |try_subcmd| + (s.size >= try_subcmd.min) and + (try_subcmd.name[0..s.size-1] == s) + end + if subcmd + str = subcmd.short_help + '.' + str += "\n" + subcmd.long_help if subcmd.long_help + return str + else + return "Invalid 'enable' subcommand '#{args[1]}'." + end + end + s = %{ + Enable some things. + This is used to cancel the effect of the "disable" command. + -- + List of enable subcommands: + -- + } + for subcmd in Subcommands do + s += "enable #{subcmd.name} -- #{subcmd.short_help}\n" + end + return s + end + end + end + + class DisableCommand < Command # :nodoc: + Subcommands = + [ + ['breakpoints', 1, "Disable some breakpoints", +"Arguments are breakpoint numbers with spaces in between. +A disabled breakpoint is not forgotten, but has no effect until reenabled."], + ['display', 1, "Disable some display expressions when program stops", +"Arguments are the code numbers of the expressions to stop displaying. +Do \"info display\" to see current list of code numbers."], + ].map do |name, min, short_help, long_help| + SubcmdStruct.new(name, min, short_help, long_help) + end unless defined?(Subcommands) + + def regexp + /^\s* dis(?:able)? (?:\s+(.*))?$/ix + end + + def execute + if not @match[1] + errmsg "\"disable\" must be followed \"display\", \"breakpoints\"" + + " or breakpoint numbers.\n" + else + args = @match[1].split(/[ \t]+/) + param = args.shift + subcmd = find(Subcommands, param) + if subcmd + send("disable_#{subcmd.name}", args) + else + send("disable_breakpoints", args.unshift(param)) + end + end + end + + def disable_breakpoints(args) + enable_disable_breakpoints("Disable", args) + end + + def disable_display(args) + enable_disable_display("Disable", args) + end + + class << self + def help_command + 'disable' + end + + def help(args) + if args[1] + s = args[1] + subcmd = Subcommands.find do |try_subcmd| + (s.size >= try_subcmd.min) and + (try_subcmd.name[0..s.size-1] == s) + end + if subcmd + str = subcmd.short_help + '.' + str += "\n" + subcmd.long_help if subcmd.long_help + return str + else + return "Invalid 'disable' subcommand '#{args[1]}'." + end + end + s = %{ + Disable some things. + + A disabled item is not forgotten, but has no effect until reenabled. + Use the "enable" command to have it take effect again. + -- + List of disable subcommands: + -- + } + for subcmd in Subcommands do + s += "disable #{subcmd.name} -- #{subcmd.short_help}\n" + end + return s + end + end + end + +end # module Debugger diff --git a/cli/ruby-debug/commands/eval.rb b/cli/ruby-debug/commands/eval.rb new file mode 100644 index 0000000..f752047 --- /dev/null +++ b/cli/ruby-debug/commands/eval.rb @@ -0,0 +1,176 @@ +module Debugger + module EvalFunctions # :nodoc: + def run_with_binding + binding = @state.context ? get_binding : TOPLEVEL_BINDING + $__dbg_interface = @state.interface + eval(<<-EOC, binding) + __dbg_verbose_save=$VERBOSE; $VERBOSE=false + def dbg_print(*args) + $__dbg_interface.print(*args) + end + remove_method :puts if self.respond_to?(:puts) && + defined?(remove_method) + def dbg_puts(*args) + $__dbg_interface.print(*args) + $__dbg_interface.print("\n") + end + $VERBOSE=__dbg_verbose_save + EOC + yield binding + ensure + $__dbg_interface = nil + end + end + + class EvalCommand < Command # :nodoc: + self.allow_in_control = true + + register_setting_get(:autoeval) do + EvalCommand.unknown + end + register_setting_set(:autoeval) do |value| + EvalCommand.unknown = value + end + + def match(input) + @input = input + super + end + + def regexp + /^\s*(p|e(?:val)?)\s+/ + end + + def execute + expr = @match ? @match.post_match : @input + run_with_binding do |b| + print "%s\n", debug_eval(expr, b).inspect + end + end + + class << self + def help_command + %w|p eval| + end + + def help(cmd) + if cmd == 'p' + %{ + p expression\tevaluate expression and print its value + } + else + %{ + e[val] expression\tevaluate expression and print its value, + \t\t\talias for p. + * NOTE - to turn on autoeval, use 'set autoeval' + } + end + end + end + end + + class PPCommand < Command # :nodoc: + self.allow_in_control = true + + def regexp + /^\s*pp\s+/ + end + + def execute + out = StringIO.new + run_with_binding do |b| + PP.pp(debug_eval(@match.post_match, b), out) + end + print out.string + rescue + out.puts $!.message + end + + class << self + def help_command + 'pp' + end + + def help(cmd) + %{ + pp expression\tevaluate expression and pretty-print its value + } + end + end + end + + class PutLCommand < Command # :nodoc: + self.allow_in_control = true + + def regexp + /^\s*putl\s+/ + end + + def execute + out = StringIO.new + run_with_binding do |b| + vals = debug_eval(@match.post_match, b) + if vals.is_a?(Array) + vals = vals.map{|item| item.to_s} + print "%s\n", columnize(vals, self.class.settings[:width]) + else + PP.pp(vals, out) + print out.string + end + end + rescue + out.puts $!.message + end + + class << self + def help_command + 'putl' + end + + def help(cmd) + %{ + putl expression\t\tevaluate expression, an array, and columnize its value + } + end + end + end + + class PSCommand < Command # :nodoc: + self.allow_in_control = true + + include EvalFunctions + + def regexp + /^\s*ps\s+/ + end + + def execute + out = StringIO.new + run_with_binding do |b| + vals = debug_eval(@match.post_match, b) + if vals.is_a?(Array) + vals = vals.map{|item| item.to_s} + print "%s\n", columnize(vals.sort!, self.class.settings[:width]) + else + PP.pp(vals, out) + print out.string + end + end + rescue + out.puts $!.message + end + + class << self + def help_command + 'ps' + end + + def help(cmd) + %{ + ps expression\tevaluate expression, an array, sort, and columnize its value + } + end + end + end + +end diff --git a/cli/ruby-debug/commands/finish.rb b/cli/ruby-debug/commands/finish.rb new file mode 100644 index 0000000..c7b77ff --- /dev/null +++ b/cli/ruby-debug/commands/finish.rb @@ -0,0 +1,42 @@ +module Debugger + # Implements the debugger 'finish' command. + class FinishCommand < Command + self.allow_in_post_mortem = false + self.need_context = true + + def regexp + /^\s*fin(?:ish)? (?:\s+(.*))?$/x + end + + def execute + max_frame = @state.context.stack_size - @state.frame_pos + if !@match[1] or @match[1].empty? + frame_pos = @state.frame_pos + else + frame_pos = get_int(@match[1], "Finish", 0, max_frame-1, 0) + return nil unless frame_pos + end + @state.context.stop_frame = frame_pos + @state.frame_pos = 0 + @state.proceed + end + + class << self + def help_command + 'finish' + end + + def help(cmd) + %{ + fin[ish] [frame-number]\tExecute until selected stack frame returns. + +If no frame number is given, we run until the currently selected frame +returns. The currently selected frame starts out the most-recent +frame or 0 if no frame positioning (e.g "up", "down" or "frame") has +been performed. If a frame number is given we run until that frame +returns. + } + end + end + end +end diff --git a/cli/ruby-debug/commands/frame.rb b/cli/ruby-debug/commands/frame.rb new file mode 100644 index 0000000..f9b6f26 --- /dev/null +++ b/cli/ruby-debug/commands/frame.rb @@ -0,0 +1,301 @@ +module Debugger + # Mix-in module to assist in command parsing. + module FrameFunctions # :nodoc: + def adjust_frame(frame_pos, absolute, context=@state.context) + @state.frame_pos = 0 if context != @state.context + if absolute + if frame_pos < 0 + abs_frame_pos = context.stack_size + frame_pos + else + abs_frame_pos = frame_pos + end + else + abs_frame_pos = @state.frame_pos + frame_pos + end + + if abs_frame_pos >= context.stack_size then + errmsg "Adjusting would put us beyond the oldest (initial) frame.\n" + return + elsif abs_frame_pos < 0 then + errmsg "Adjusting would put us beyond the newest (innermost) frame.\n" + return + end + if @state.frame_pos != abs_frame_pos then + @state.previous_line = nil + @state.frame_pos = abs_frame_pos + end + + @state.file = context.frame_file(@state.frame_pos) + @state.line = context.frame_line(@state.frame_pos) + + print_frame(@state.frame_pos, true) + end + + def get_frame_call(prefix, pos, context) + id = context.frame_method(pos) + klass = context.frame_class(pos) + call_str = "" + if id + args = context.frame_args(pos) + locals = context.frame_locals(pos) + if Command.settings[:callstyle] != :short && klass + if Command.settings[:callstyle] == :tracked + arg_info = context.frame_args_info(pos) + end + call_str << "#{klass}." + end + call_str << id.id2name + if args.any? + call_str << "(" + args.each_with_index do |name, i| + case Command.settings[:callstyle] + when :short + call_str += "%s, " % [name] + when :last + klass = locals[name].class + if klass.inspect.size > 20+3 + klass = klass.inspect[0..20]+"..." + end + call_str += "%s#%s, " % [name, klass] + when :tracked + if arg_info && arg_info.size > i + call_str += "#{name}: #{arg_info[i].inspect}, " + else + call_str += "%s, " % name + end + end + if call_str.size > self.class.settings[:width] - prefix.size + # Strip off trailing ', ' if any but add stuff for later trunc + call_str[-2..-1] = ",...XX" + break + end + end + call_str[-2..-1] = ")" # Strip off trailing ', ' if any + end + end + return call_str + end + + def print_frame(pos, adjust = false, context=@state.context) + file = context.frame_file(pos) + line = context.frame_line(pos) + klass = context.frame_class(pos) + + unless Command.settings[:full_path] + path_components = file.split(/[\\\/]/) + if path_components.size > 3 + path_components[0...-3] = '...' + file = path_components.join(File::ALT_SEPARATOR || File::SEPARATOR) + end + end + + frame_num = "#%d " % pos + call_str = get_frame_call(frame_num, pos, context) + file_line = "at line %s:%d\n" % [CommandProcessor.canonic_file(file), line] + print frame_num + unless call_str.empty? + print call_str + print ' ' + if call_str.size + frame_num.size + file_line.size > self.class.settings[:width] + print "\n " + end + end + print file_line + if ENV['EMACS'] && adjust + fmt = (Debugger.annotate.to_i > 1 ? + "\032\032source %s:%d\n" : "\032\032%s:%d\n") + print fmt % [CommandProcessor.canonic_file(file), line] + end + end + + # Check if call stack is truncated. This can happen if + # Debugger.start is not called low enough in the call stack. An + # array of additional callstack lines from caller is returned if + # definitely truncated, false if not, and nil if we don't know. + # + # We determine truncation based on a passed in sentinal set via + # caller which can be nil. + # + # First we see if we can find our position in caller. If so, then + # we compare context position to that in caller using sentinal + # as a place to start ignoring additional caller entries. sentinal + # is set by rdebug, but if it's not set, i.e. nil then additional + # entries are presumably ones that we haven't recorded in context + def truncated_callstack?(context, sentinal=nil, cs=caller) + recorded_size = context.stack_size + to_find_fl = "#{context.frame_file(0)}:#{context.frame_line(0)}" + top_discard = false + cs.each_with_index do |fl, i| + fl.gsub!(/in `.*'$/, '') + fl.gsub!(/:$/, '') + if fl == to_find_fl + top_discard = i + break + end + end + if top_discard + cs = cs[top_discard..-1] + return false unless cs + return cs unless sentinal + if cs.size > recorded_size+2 && cs[recorded_size+2] != sentinal + # caller seems to truncate recursive calls and we don't. + # See if we can find sentinal in the first 0..recorded_size+1 entries + return false if cs[0..recorded_size+1].any?{ |f| f==sentinal } + return cs + end + return false + end + return nil + end + + + end + + # Implements debugger "where" or "backtrace" command. + class WhereCommand < Command + def regexp + /^\s*(?:w(?:here)?|bt|backtrace)$/ + end + + def execute + (0...@state.context.stack_size).each do |idx| + if idx == @state.frame_pos + print "--> " + else + print " " + end + print_frame(idx) + + end + if truncated_callstack?(@state.context, Debugger.start_sentinal) + print "Warning: saved frames may be incomplete; compare with caller(0).\n" + end + end + + class << self + def help_command + %w|where backtrace| + end + + def help(cmd) + s = if cmd == 'where' + %{ + w[here]\tdisplay stack frames + } + else + %{ + bt|backtrace\t\talias for where - display stack frames + } + end + s += %{ +Print the entire stack frame. Each frame is numbered, the most recent +frame is 0. frame number can be referred to in the "frame" command; +"up" and "down" add or subtract respectively to frame numbers shown. +The position of the current frame is marked with -->. } + end + end + end + + class UpCommand < Command # :nodoc: + def regexp + /^\s* u(?:p)? (?:\s+(.*))?$/x + end + + def execute + pos = get_int(@match[1], "Up") + return unless pos + adjust_frame(pos, false) + end + + class << self + def help_command + 'up' + end + + def help(cmd) + %{ + up[count]\tmove to higher frame + } + end + end + end + + class DownCommand < Command # :nodoc: + def regexp + /^\s* down (?:\s+(.*))? .*$/x + end + + def execute + pos = get_int(@match[1], "Down") + return unless pos + adjust_frame(-pos, false) + end + + class << self + def help_command + 'down' + end + + def help(cmd) + %{ + down[count]\tmove to lower frame + } + end + end + end + + class FrameCommand < Command # :nodoc: + def regexp + / ^\s* + f(?:rame)? + (?: \s+ (\S+))? \s* + (?: thread \s+ (.*))? \s* + $/x + end + + def execute + if not @match[1] + pos = 0 + else + pos = get_int(@match[1], "Frame") + return unless pos + end + if @match[2] + context = parse_thread_num('frame', @match[2]) + unless context + errmsg "Thread #{@match[2]} doesn't exist.\n" + return + end + else + context = @state.context + end + adjust_frame(pos, true, context) + end + + class << self + def help_command + 'frame' + end + + def help(cmd) + %{ + f[rame] [frame-number [thread thread-number]] + Move the current frame to the specified frame number, or the + 0 if no frame-number has been given. + + A negative number indicates position from the other end. So + 'frame -1' moves to the oldest frame, and 'frame 0' moves to + the newest frame. + + Without an argument, the command prints the current stack + frame. Since the current position is redisplayed, it may trigger a + resyncronization if there is a front end also watching over + things. + + If a thread number is given then we set the context for evaluating + expressions to that frame of that thread. + } + end + end + end +end diff --git a/cli/ruby-debug/commands/help.rb b/cli/ruby-debug/commands/help.rb new file mode 100644 index 0000000..1144621 --- /dev/null +++ b/cli/ruby-debug/commands/help.rb @@ -0,0 +1,56 @@ +module Debugger + + # Implements debugger "help" command. + class HelpCommand < Command + self.allow_in_control = true + + def regexp + /^\s* h(?:elp)? (?:\s+(.+))? $/x + end + + def execute + if @match[1] + args = @match[1].split + cmds = @state.commands.select do |cmd| + [cmd.help_command].flatten.include?(args[0]) + end + else + args = @match[1] + cmds = [] + end + unless cmds.empty? + help = cmds.map{ |cmd| cmd.help(args) }.join + help = help.split("\n").map{|l| l.gsub(/^ +/, '')} + help.shift if help.first && help.first.empty? + help.pop if help.last && help.last.empty? + print help.join("\n") + else + if args and args[0] + errmsg "Undefined command: \"#{args[0]}\". Try \"help\"." + else + print "ruby-debug help v#{Debugger::VERSION}\n" unless + self.class.settings[:debuggertesting] + print "Type 'help ' for help on a specific command\n\n" + print "Available commands:\n" + cmds = @state.commands.map{ |cmd| cmd.help_command } + cmds = cmds.flatten.uniq.sort + print columnize(cmds, self.class.settings[:width]) + end + end + print "\n" + end + + class << self + def help_command + 'help' + end + + def help(cmd) + %{ + h[elp]\t\tprint this help + h[elp] command\tprint help on command + } + end + end + end +end diff --git a/cli/ruby-debug/commands/info.rb b/cli/ruby-debug/commands/info.rb new file mode 100644 index 0000000..3fac50c --- /dev/null +++ b/cli/ruby-debug/commands/info.rb @@ -0,0 +1,469 @@ +module Debugger + module InfoFunctions # :nodoc: + def info_catch(*args) + unless @state.context + print "No frame selected.\n" + return + end + if Debugger.catchpoints and not Debugger.catchpoints.empty? + # FIXME: show whether Exception is valid or not + # print "Exception: is_a?(Class)\n" + Debugger.catchpoints.each do |exception, hits| + # print "#{exception}: #{exception.is_a?(Class)}\n" + print "#{exception}\n" + end + else + print "No exceptions set to be caught.\n" + end + end + end + + # Implements debugger "info" command. + class InfoCommand < Command + self.allow_in_control = true + Subcommands = + [ + ['args', 1, 'Argument variables of current stack frame'], + ['breakpoints', 1, 'Status of user-settable breakpoints', + 'Without argument, list info about all breakpoints. With an +integer argument, list info on that breakpoint.'], + ['catch', 3, 'Exceptions that can be caught in the current stack frame'], + ['display', 2, 'Expressions to display when program stops'], + ['file', 4, 'Info about a particular file read in', +' +After the file name is supplied, you can list file attributes that +you wish to see. + +Attributes include: "all", "basic", "breakpoint", "lines", "mtime", "path" +and "sha1".'], + ['files', 5, 'File names and timestamps of files read in'], + ['global_variables', 2, 'Global variables'], + ['instance_variables', 2, + 'Instance variables of the current stack frame'], + ['line', 2, + 'Line number and file name of current position in source file'], + ['locals', 2, 'Local variables of the current stack frame'], + ['program', 2, 'Execution status of the program'], + ['stack', 2, 'Backtrace of the stack'], + ['thread', 6, 'List info about thread NUM', ' +If no thread number is given, we list info for all threads. \'terse\' and \'verbose\' +options are possible. If terse, just give summary thread name information. See +"help info threads" for more detail about this summary information. + +If \'verbose\' appended to the end of the command, then the entire +stack trace is given for each thread.'], + ['threads', 7, 'information of currently-known threads', ' +This information includes whether the thread is current (+), if it is +suspended ($), or ignored (!). The thread number and the top stack +item. If \'verbose\' is given then the entire stack frame is shown.'], + ['variables', 1, + 'Local and instance variables of the current stack frame'] + ].map do |name, min, short_help, long_help| + SubcmdStruct.new(name, min, short_help, long_help) + end unless defined?(Subcommands) + + InfoFileSubcommands = + [ + ['all', 1, + 'All file information available - breakpoints, lines, mtime, path, and sha1'], + ['basic', 2, + 'basic information - path, number of lines'], + ['breakpoints', 2, 'Show trace line numbers', + 'These are the line number where a breakpoint can be set.'], + ['lines', 1, 'Show number of lines in the file'], + ['mtime', 1, 'Show modification time of file'], + ['path', 4, 'Show full file path name for file'], + ['sha1', 1, 'Show SHA1 hash of contents of the file'] + ].map do |name, min, short_help, long_help| + SubcmdStruct.new(name, min, short_help, long_help) + end unless defined?(InfoFileSubcommands) + + InfoThreadSubcommands = + [ + ['terse', 1, 'summary information'], + ['verbose', 1, 'summary information and stack frame info'], + ].map do |name, min, short_help, long_help| + SubcmdStruct.new(name, min, short_help, long_help) + end unless defined?(InfoThreadSubcommands) + + def regexp + /^\s* i(?:nfo)? (?:\s+(.*))?$/ix + end + + def execute + if @match[1].empty? + errmsg "\"info\" must be followed by the name of an info command:\n" + print "List of info subcommands:\n\n" + for subcmd in Subcommands do + print "info #{subcmd.name} -- #{subcmd.short_help}\n" + end + else + args = @match[1].split(/[ \t]+/) + param = args.shift + subcmd = find(Subcommands, param) + if subcmd + send("info_#{subcmd.name}", *args) + else + errmsg "Unknown info command #{param}\n" + end + end + end + + def info_args(*args) + unless @state.context + print "No frame selected.\n" + return + end + locals = @state.context.frame_locals(@state.frame_pos) + args = @state.context.frame_args(@state.frame_pos) + args.each do |name| + s = "#{name} = #{locals[name].inspect}" + if s.size > self.class.settings[:width] + s[self.class.settings[:width]-3 .. -1] = "..." + end + print "#{s}\n" + end + end + + def info_breakpoints(*args) + unless @state.context + print "info breakpoints not available here.\n" + return + end + unless Debugger.breakpoints.empty? + brkpts = Debugger.breakpoints.sort_by{|b| b.id} + unless args.empty? + a = args.map{|a| a.to_i} + brkpts = brkpts.select{|b| a.member?(b.id)} + if brkpts.empty? + errmsg "No breakpoints found among list given.\n" + return + end + end + print "Num Enb What\n" + brkpts.each do |b| + if b.expr.nil? + print "%3d %s at %s:%s\n", + b.id, (b.enabled? ? 'y' : 'n'), b.source, b.pos + else + print "%3d %s at %s:%s if %s\n", + b.id, (b.enabled? ? 'y' : 'n'), b.source, b.pos, b.expr + end + hits = b.hit_count + if hits > 0 + s = (hits > 1) ? 's' : '' + print "\tbreakpoint already hit #{hits} time#{s}\n" + end + end + else + print "No breakpoints.\n" + end + end + + def info_display(*args) + unless @state.context + print "info display not available here.\n" + return + end + if @state.display.find{|d| d[0]} + print "Auto-display expressions now in effect:\n" + print "Num Enb Expression\n" + n = 1 + for d in @state.display + print "%3d: %s %s\n", n, (d[0] ? 'y' : 'n'), d[1] if + d[0] != nil + n += 1 + end + else + print "There are no auto-display expressions now.\n" + end + end + + def info_file(*args) + unless args[0] + info_files + return + end + file = args[0] + param = args[1] + + param = 'basic' unless param + subcmd = find(InfoFileSubcommands, param) + unless subcmd + errmsg "Invalid parameter #{param}\n" + return + end + + unless LineCache::cached?(file) + unless LineCache::cached_script?(file) + print "File #{file} is not cached\n" + return + end + LineCache::cache(file, Command.settings[:reload_source_on_change]) + end + + print "File %s", file + path = LineCache.path(file) + if %w(all basic path).member?(subcmd.name) and path != file + print " - %s\n", path + else + print "\n" + end + + if %w(all basic lines).member?(subcmd.name) + lines = LineCache.size(file) + print "\t %d lines\n", lines if lines + end + + if %w(all breakpoints).member?(subcmd.name) + breakpoints = LineCache.trace_line_numbers(file) + if breakpoints + print "\tbreakpoint line numbers:\n" + print columnize(breakpoints.to_a.sort, self.class.settings[:width]) + end + end + + if %w(all mtime).member?(subcmd.name) + stat = LineCache.stat(file) + print "\t%s\n", stat.mtime if stat + end + if %w(all sha1).member?(subcmd.name) + print "\t%s\n", LineCache.sha1(file) + end + end + + def info_files(*args) + files = LineCache::cached_files + files += SCRIPT_LINES__.keys unless 'stat' == args[0] + files.uniq.sort.each do |file| + stat = LineCache::stat(file) + path = LineCache::path(file) + print "File %s", file + if path and path != file + print " - %s\n", path + else + print "\n" + end + print "\t%s\n", stat.mtime if stat + end + end + + def info_instance_variables(*args) + unless @state.context + print "info instance_variables not available here.\n" + return + end + obj = debug_eval('self') + var_list(obj.instance_variables) + end + + def info_line(*args) + unless @state.context + errmsg "info line not available here.\n" + return + end + print "Line %d of \"%s\"\n", @state.line, @state.file + end + + def info_locals(*args) + unless @state.context + errmsg "info line not available here.\n" + return + end + locals = @state.context.frame_locals(@state.frame_pos) + locals.keys.sort.each do |name| + ### FIXME: make a common routine + begin + s = "#{name} = #{locals[name].inspect}" + rescue + begin + s = "#{name} = #{locals[name].to_s}" + rescue + s = "*Error in evaluation*" + end + end + if s.size > self.class.settings[:width] + s[self.class.settings[:width]-3 .. -1] = "..." + end + print "#{s}\n" + end + end + + def info_program(*args) + if not @state.context + print "The program being debugged is not being run.\n" + return + elsif @state.context.dead? + print "The program crashed.\n" + if Debugger.last_exception + print("Exception: #{Debugger.last_exception.inspect}\n") + end + return + end + + print "Program stopped. " + case @state.context.stop_reason + when :step + print "It stopped after stepping, next'ing or initial start.\n" + when :breakpoint + print("It stopped at a breakpoint.\n") + when :catchpoint + print("It stopped at a catchpoint.\n") + when :catchpoint + print("It stopped at a catchpoint.\n") + else + print "unknown reason: %s\n" % @state.context.stop_reason.to_s + end + end + + def info_stack(*args) + if not @state.context + errmsg "info stack not available here.\n" + return + end + (0...@state.context.stack_size).each do |idx| + if idx == @state.frame_pos + print "--> " + else + print " " + end + print_frame(idx) + end + end + + def info_thread_preamble(arg) + if not @state.context + errmsg "info threads not available here.\n" + return false, false + end + verbose = if arg + subcmd = find(InfoThreadSubcommands, arg) + unless subcmd + errmsg "'terse' or 'verbose' expected. Got '#{arg}'\n" + return false, false + end + 'verbose' == subcmd.name + else + false + end + return true, verbose + end + private :info_thread_preamble + + def info_threads(*args) + ok, verbose = info_thread_preamble(args[0]) + return unless ok + threads = Debugger.contexts.sort_by{|c| c.thnum}.each do |c| + display_context(c, !verbose) + if verbose and not c.ignored? + (0...c.stack_size).each do |idx| + print "\t" + print_frame(idx, false, c) + end + end + end + end + + def info_thread(*args) + unless args[0] + info_threads(args[0]) + return + end + ok, verbose = info_thread_preamble(args[1]) + return unless ok + c = parse_thread_num("info thread" , args[0]) + return unless c + display_context(c, !verbose) + if verbose and not c.ignored? + (0...c.stack_size).each do |idx| + print "\t" + print_frame(idx, false, c) + end + end + end + + def info_global_variables(*args) + unless @state.context + errmsg "info global_variables not available here.\n" + return + end + var_list(global_variables) + end + + def info_variables(*args) + if not @state.context + errmsg "info variables not available here.\n" + return + end + obj = debug_eval('self') + locals = @state.context.frame_locals(@state.frame_pos) + locals['self'] = @state.context.frame_self(@state.frame_pos) + locals.keys.sort.each do |name| + next if name =~ /^__dbg_/ # skip debugger pollution + ### FIXME: make a common routine + begin + s = "#{name} = #{locals[name].inspect}" + rescue + begin + s = "#{name} = #{locals[name].to_s}" + rescue + s = "#{name} = *Error in evaluation*" + end + end + if s.size > self.class.settings[:width] + s[self.class.settings[:width]-3 .. -1] = "..." + end + s.gsub!('%', '%%') # protect against printf format strings + print "#{s}\n" + end + var_list(obj.instance_variables, obj.instance_eval{binding()}) + var_class_self + end + + class << self + def help_command + 'info' + end + + def help(args) + if args[1] + s = args[1] + subcmd = Subcommands.find do |try_subcmd| + (s.size >= try_subcmd.min) and + (try_subcmd.name[0..s.size-1] == s) + end + if subcmd + str = subcmd.short_help + '.' + if 'file' == subcmd.name and args[2] + s = args[2] + subsubcmd = InfoFileSubcommands.find do |try_subcmd| + (s.size >= try_subcmd.min) and + (try_subcmd.name[0..s.size-1] == s) + end + if subsubcmd + str += "\n" + subsubcmd.short_help + '.' + else + str += "\nInvalid file attribute #{args[2]}." + end + else + str += "\n" + subcmd.long_help if subcmd.long_help + end + return str + else + return "Invalid 'info' subcommand '#{args[1]}'." + end + end + s = %{ + Generic command for showing things about the program being debugged. + -- + List of info subcommands: + -- + } + for subcmd in Subcommands do + s += "info #{subcmd.name} -- #{subcmd.short_help}\n" + end + return s + end + end + end +end diff --git a/cli/ruby-debug/commands/irb.rb b/cli/ruby-debug/commands/irb.rb new file mode 100644 index 0000000..2493e80 --- /dev/null +++ b/cli/ruby-debug/commands/irb.rb @@ -0,0 +1,123 @@ +require 'irb' + +module IRB # :nodoc: + module ExtendCommand # :nodoc: + class Continue # :nodoc: + def self.execute(conf) + throw :IRB_EXIT, :cont + end + end + class Next # :nodoc: + def self.execute(conf) + throw :IRB_EXIT, :next + end + end + class Step # :nodoc: + def self.execute(conf) + throw :IRB_EXIT, :step + end + end + end + ExtendCommandBundle.def_extend_command "cont", :Continue + ExtendCommandBundle.def_extend_command "n", :Next + ExtendCommandBundle.def_extend_command "step", :Step + + def self.start_session(binding) + unless @__initialized + args = ARGV.dup + ARGV.replace([]) + IRB.setup(nil) + ARGV.replace(args) + @__initialized = true + end + + workspace = WorkSpace.new(binding) + + irb = Irb.new(workspace) + + @CONF[:IRB_RC].call(irb.context) if @CONF[:IRB_RC] + @CONF[:MAIN_CONTEXT] = irb.context + + catch(:IRB_EXIT) do + irb.eval_input + end + end +end + +module Debugger + + # Implements debugger "irb" command. + class IRBCommand < Command + + register_setting_get(:autoirb) do + IRBCommand.always_run + end + register_setting_set(:autoirb) do |value| + IRBCommand.always_run = value + end + + def regexp + /^\s* irb + (?:\s+(-d))? + \s*$/x + end + + def execute + unless @state.interface.kind_of?(LocalInterface) + print "Command is available only in local mode.\n" + throw :debug_error + end + + save_trap = trap("SIGINT") do + throw :IRB_EXIT, :cont if $rdebug_in_irb + end + + add_debugging = @match.is_a?(Array) && '-d' == @match[1] + $rdebug_state = @state if add_debugging + $rdebug_in_irb = true + cont = IRB.start_session(get_binding) + case cont + when :cont + @state.proceed + when :step + force = Command.settings[:force_stepping] + @state.context.step(1, force) + @state.proceed + when :next + force = Command.settings[:force_stepping] + @state.context.step_over(1, @state.frame_pos, force) + @state.proceed + else + file = @state.context.frame_file(0) + line = @state.context.frame_line(0) + CommandProcessor.print_location_and_text(file, line) + @state.previous_line = nil + end + + ensure + $rdebug_in_irb = nil + $rdebug_state = nil if add_debugging + trap("SIGINT", save_trap) if save_trap + end + + class << self + def help_command + 'irb' + end + + def help(cmd) + %{ + irb [-d]\tstarts an Interactive Ruby (IRB) session. + +If -d is added you can get access to debugger state via the global variable +$RDEBUG_state. + +irb is extended with methods "cont", "n" and "step" which +run the corresponding debugger commands. In contrast to the real debugger +commands these commands don't allow command arguments. + } + end + end + end +end + diff --git a/cli/ruby-debug/commands/kill.rb b/cli/ruby-debug/commands/kill.rb new file mode 100644 index 0000000..da5d05e --- /dev/null +++ b/cli/ruby-debug/commands/kill.rb @@ -0,0 +1,51 @@ +module Debugger + + # Implements debugger "kill" command + class KillCommand < Command + self.allow_in_control = true + + def regexp + / ^\s* + (?:kill) \s* + (?:\s+(\S+))?\s* + $ + /ix + end + + def execute + puts @match[1] + if @match[1] + signame = @match[1] + unless Signal.list.member?(signame) + errmsg("signal name #{signame} is not a signal I know about\n") + return false + end + if 'KILL' == signame: + @state.interface.finalize + end + else + if not confirm("Really kill? (y/n) ") + return + else + signame = 'KILL' + end + end + Process.kill(signame, Process.pid) + end + + class << self + def help_command + %w[kill] + end + + def help(cmd) + %{ + kill [SIGNAL] + + Send [signal] to Process.pid +Equivalent of Process.kill(Process.pid) + } + end + end + end +end diff --git a/cli/ruby-debug/commands/list.rb b/cli/ruby-debug/commands/list.rb new file mode 100644 index 0000000..165732f --- /dev/null +++ b/cli/ruby-debug/commands/list.rb @@ -0,0 +1,94 @@ +module Debugger + # Implements debugger "list" command. + class ListCommand < Command + + register_setting_get(:autolist) do + ListCommand.always_run + end + register_setting_set(:autolist) do |value| + ListCommand.always_run = value + end + + def regexp + /^\s* l(?:ist)? (?:\s*([-=])|\s+(.+))? $/x + end + + def execute + listsize = Command.settings[:listsize] + if !@match || !(@match[1] || @match[2]) + b = @state.previous_line ? + @state.previous_line + listsize : @state.line - (listsize/2) + e = b + listsize - 1 + elsif @match[1] == '-' + b = if @state.previous_line + if @state.previous_line > 0 + @state.previous_line - listsize + else + @state.previous_line + end + else + @state.line - (listsize/2) + end + e = b + listsize - 1 + elsif @match[1] == '=' + @state.previous_line = nil + b = @state.line - (listsize/2) + e = b + listsize -1 + else + b, e = @match[2].split(/[-,]/) + if e + b = b.to_i + e = e.to_i + else + b = b.to_i - (listsize/2) + e = b + listsize - 1 + end + end + @state.previous_line = display_list(b, e, @state.file, @state.line) + end + + class << self + def help_command + 'list' + end + + def help(cmd) + %{ + l[ist]\t\tlist forward + l[ist] -\tlist backward + l[ist] =\tlist current line + l[ist] nn-mm\tlist given lines + * NOTE - to turn on autolist, use 'set autolist' + } + end + end + + private + + # Show FILE from line B to E where CURRENT is the current line number. + # If we can show from B to E then we return B, otherwise we return the + # previous line @state.previous_line. + def display_list(b, e, file, current) + print "[%d, %d] in %s\n", b, e, file + lines = LineCache::getlines(file, + Command.settings[:reload_source_on_change]) + if lines + return @state.previous_line if b >= lines.size + e = lines.size if lines.size < e + [b, 1].max.upto(e) do |n| + if n > 0 && lines[n-1] + if n == current + print "=> %d %s\n", n, lines[n-1].chomp + else + print " %d %s\n", n, lines[n-1].chomp + end + end + end + else + errmsg "No sourcefile available for %s\n", file + return @state.previous_line + end + return e == lines.size ? @state.previous_line : b + end + end +end diff --git a/cli/ruby-debug/commands/method.rb b/cli/ruby-debug/commands/method.rb new file mode 100644 index 0000000..1d31ead --- /dev/null +++ b/cli/ruby-debug/commands/method.rb @@ -0,0 +1,84 @@ +module Debugger + + begin + require 'methodsig' + have_methodsig = true + rescue LoadError + have_methodsig = false + end + + # Implements the debugger 'method sig' command. + class MethodSigCommand < Command + def regexp + /^\s*m(?:ethod)?\s+sig(?:nature)?\s+(\S+)\s*$/ + end + + def execute + obj = debug_eval('method(:%s)' % @match[1]) + if obj.is_a?(Method) + begin + print "%s\n", obj.signature.to_s + rescue + errmsg("Can't get signature for '#{@match[1]}'\n") + end + else + errmsg("Can't make method out of '#{@match[1]}'\n") + end + end + + class << self + def help_command + 'method' + end + + def help(cmd) + %{ + m[ethod] sig[nature] \tshow the signature of a method + } + end + end + end if have_methodsig + + # Implements the debugger 'method' command. + class MethodCommand < Command + def regexp + /^\s*m(?:ethod)?\s+((iv)|(i(:?nstance\s+)?)\s+)?/ + end + + def execute + if @match[1] == "iv" + obj = debug_eval(@match.post_match) + obj.instance_variables.sort.each do |v| + print "%s = %s\n", v, obj.instance_variable_get(v).inspect + end + elsif @match[1] + obj = debug_eval(@match.post_match) + print "%s\n", columnize(obj.methods.sort(), + self.class.settings[:width]) + else + obj = debug_eval(@match.post_match) + unless obj.kind_of? Module + print "Should be Class/Module: %s\n", @match.post_match + else + print "%s\n", columnize(obj.instance_methods(false).sort(), + self.class.settings[:width]) + end + end + end + + class << self + def help_command + 'method' + end + + def help(cmd) + %{ + m[ethod] i[nstance] \tshow methods of object + m[ethod] iv \t\tshow instance variables of object + m[ethod] \t\tshow instance methods of class or module + } + end + end + end + +end diff --git a/cli/ruby-debug/commands/quit.rb b/cli/ruby-debug/commands/quit.rb new file mode 100644 index 0000000..767fedb --- /dev/null +++ b/cli/ruby-debug/commands/quit.rb @@ -0,0 +1,39 @@ +module Debugger + + # Implements debugger "quit" command + class QuitCommand < Command + self.allow_in_control = true + + def regexp + / ^\s* + (?:q(?:uit)?|exit) \s* + (!|\s+unconditionally)? \s* + $ + /ix + end + + def execute + if @match[1] or confirm("Really quit? (y/n) ") + @state.interface.finalize + exit! # exit -> exit!: No graceful way to stop threads... + end + end + + class << self + def help_command + %w[quit exit] + end + + def help(cmd) + %{ + q[uit] [!|unconditionally]\texit from debugger. + exit[!]\talias to quit + + Normally we prompt before exiting. However if the parameter + "unconditionally" or is given or suffixed with !, we stop + without asking further questions. + } + end + end + end +end diff --git a/cli/ruby-debug/commands/reload.rb b/cli/ruby-debug/commands/reload.rb new file mode 100644 index 0000000..822d5e6 --- /dev/null +++ b/cli/ruby-debug/commands/reload.rb @@ -0,0 +1,40 @@ +module Debugger + # Implements debugger "reload" command. + class ReloadCommand < Command + self.allow_in_control = true + + register_setting_get(:reload_source_on_change) do + Debugger.reload_source_on_change + end + register_setting_set(:reload_source_on_change) do |value| + Debugger.reload_source_on_change = value + end + + def regexp + /^\s*r(?:eload)?$/ + end + + def execute + Debugger.source_reload + print "Source code is reloaded. Automatic reloading is #{source_reloading}.\n" + end + + private + + def source_reloading + Debugger.reload_source_on_change ? 'on' : 'off' + end + + class << self + def help_command + 'reload' + end + + def help(cmd) + %{ + r[eload]\tforces source code reloading + } + end + end + end +end diff --git a/cli/ruby-debug/commands/save.rb b/cli/ruby-debug/commands/save.rb new file mode 100644 index 0000000..d039201 --- /dev/null +++ b/cli/ruby-debug/commands/save.rb @@ -0,0 +1,90 @@ +module Debugger + module SaveFunctions # :nodoc: + + # Create a temporary file to write in if file is nil + def open_save + require "tempfile" + file = Tempfile.new("rdebug-save") + # We want close to not unlink, so redefine. + def file.close + @tmpfile.close if @tmpfile + end + return file + end + end + + class SaveCommand < Command # :nodoc: + self.allow_in_control = true + + def save_breakpoints(file) + Debugger.breakpoints.each do |b| + file.puts "break #{b.source}:#{b.pos}#{" if #{b.expr}" if b.expr}" + end + end + + def save_catchpoints(file) + Debugger.catchpoints.keys.each do |c| + file.puts "catch #{c}" + end + end + + def save_displays(file) + for d in @state.display + if d[0] + file.puts "display #{d[1]}" + end + end + end + + def save_settings(file) + # FIXME put routine in set + %w(autoeval basename debuggertesting).each do |setting| + on_off = show_onoff(Command.settings[setting.to_sym]) + file.puts "set #{setting} #{on_off}" + end + %w(autolist autoirb).each do |setting| + on_off = show_onoff(Command.settings[setting.to_sym] > 0) + file.puts "set #{setting} #{on_off}" + end + end + + def regexp + /^\s* sa(?:ve)? + (?:\s+(.+))? + \s*$/ix + end + + def execute + if not @match[1] or @match[1].strip.empty? + file = open_save() + else + file = open(@match[1], 'w') + end + save_breakpoints(file) + save_catchpoints(file) + # save_displays(file) + save_settings(file) + print "Saved to '#{file.path}'\n" + if @state and @state.interface + @state.interface.restart_file = file.path + end + file.close + end + + class << self + def help_command + 'save' + end + + def help(cmd) + %{ +save [FILE] +Saves current debugger state to FILE as a script file. +This includes breakpoints, catchpoints, display expressions and some settings. +If no filename is given, we will fabricate one. + +Use the 'source' command in another debug session to restore them.} + end + end + end +end diff --git a/cli/ruby-debug/commands/set.rb b/cli/ruby-debug/commands/set.rb new file mode 100644 index 0000000..df9bcfb --- /dev/null +++ b/cli/ruby-debug/commands/set.rb @@ -0,0 +1,237 @@ +module Debugger + # Implements debugger "set" command. + class SetCommand < Command + SubcmdStruct2=Struct.new(:name, :min, :is_bool, :short_help, + :long_help) unless defined?(SubcmdStruct2) + Subcommands = + [ + ['annotate', 2, false, + "Set annotation level", +"0 == normal; +2 == output annotated suitably for use by programs that control +ruby-debug."], + ['args', 2, false, + "Set argument list to give program being debugged when it is started", +"Follow this command with any number of args, to be passed to the program."], + ['autoeval', 4, true, + "Evaluate every unrecognized command"], + ['autolist', 4, true, + "Execute 'list' command on every breakpoint"], + ['autoirb', 4, true, + "Invoke IRB on every stop"], + ['autoreload', 4, true, + "Reload source code when changed"], + ['basename', 1, true, + "Report file basename only showing file names"], + ['callstyle', 2, false, + "Set how you want call parameters displayed"], + ['debuggertesting', 8, false, + "Used when testing the debugger"], + ['forcestep', 2, true, + "Make sure 'next/step' commands always move to a new line"], + ['fullpath', 2, true, + "Display full file names in frames"], + ['history', 2, false, + "Generic command for setting command history parameters", +"set history filename -- Set the filename in which to record the command history +set history save -- Set saving of the history record on exit +set history size -- Set the size of the command history"], + ['keep-frame-bindings', 1, true, + "Save frame binding on each call"], + ['linetrace+', 10, true, + "Set line execution tracing to show different lines"], + ['linetrace', 3, true, + "Set line execution tracing"], + ['listsize', 3, false, + "Set number of source lines to list by default"], +# ['post-mortem', 3, true, +# "Set whether we do post-mortem handling on an uncaught exception"], + ['trace', 1, true, + "Display stack trace when 'eval' raises exception"], + ['width', 1, false, + "Number of characters the debugger thinks are in a line"], + ].map do |name, min, is_bool, short_help, long_help| + SubcmdStruct2.new(name, min, is_bool, short_help, long_help) + end unless defined?(Subcommands) + + self.allow_in_control = true + + def regexp + /^set (?: \s+ (.*) )?$/ix + end + + def execute + if not @match[1] + print "\"set\" must be followed by the name of an set command:\n" + print "List of set subcommands:\n\n" + for subcmd in Subcommands do + print "set #{subcmd.name} -- #{subcmd.short_help}\n" + end + else + args = @match[1].split(/[ \t]+/) + subcmd = args.shift + subcmd.downcase! + if subcmd =~ /^no/i + set_on = false + subcmd = subcmd[2..-1] + else + set_on = true + end + for try_subcmd in Subcommands do + if (subcmd.size >= try_subcmd.min) and + (try_subcmd.name[0..subcmd.size-1] == subcmd) + begin + if try_subcmd.is_bool + if args.size > 0 + set_on = get_onoff(args[0]) + end + end + case try_subcmd.name + when /^annotate$/ + level = get_int(args[0], "Set annotate", 0, 3, 0) + if level + Debugger.annotate = level + else + return + end + if defined?(Debugger::RDEBUG_SCRIPT) + # rdebug was called initially. 1st arg is script name. + Command.settings[:argv][1..-1] = args + else + # rdebug wasn't called initially. 1st arg is not script name. + Command.settings[:argv] = args + end + when /^args$/ + Command.settings[:argv][1..-1] = args + when /^autolist$/ + Command.settings[:autolist] = (set_on ? 1 : 0) + when /^autoeval$/ + Command.settings[:autoeval] = set_on + when /^basename$/ + Command.settings[:basename] = set_on + when /^callstyle$/ + if args[0] + arg = args[0].downcase.to_sym + case arg + when :short, :last, :tracked + Command.settings[:callstyle] = arg + Debugger.track_frame_args = arg == :tracked ? true : false + print "%s\n" % show_setting(try_subcmd.name) + return + end + end + print "Invalid call style #{arg}. Should be one of: " + + "'short', 'last', or 'tracked'.\n" + when /^trace$/ + Command.settings[:stack_trace_on_error] = set_on + when /^fullpath$/ + Command.settings[:full_path] = set_on + when /^autoreload$/ + Command.settings[:reload_source_on_change] = set_on + when /^autoirb$/ + Command.settings[:autoirb] = (set_on ? 1 : 0) + when /^debuggertesting$/ + Command.settings[:debuggertesting] = set_on + if set_on + Command.settings[:basename] = true + end + when /^forcestep$/ + self.class.settings[:force_stepping] = set_on + when /^history$/ + if 2 == args.size + interface = @state.interface + case args[0] + when /^save$/ + interface.history_save = get_onoff(args[1]) + when /^size$/ + interface.history_length = get_int(args[1], + "Set history size") + else + print "Invalid history parameter #{args[0]}. Should be 'save' or 'size'.\n" + end + else + print "Need two parameters for 'set history'; got #{args.size}.\n" + return + end + when /^keep-frame-bindings$/ + Debugger.keep_frame_binding = set_on + when /^linetrace\+$/ + self.class.settings[:tracing_plus] = set_on + when /^linetrace$/ + Debugger.tracing = set_on + when /^listsize$/ + listsize = get_int(args[0], "Set listsize", 1, nil, 10) + if listsize + self.class.settings[:listsize] = listsize + else + return + end +# when /^post-mortem$/ +# unless Debugger.post_mortem? == set_on +# if set_on +# Debugger.post_mortem +# else +# errmsg "Can't turn off post-mortem once it is on.\n" +# return +# end +# end + when /^width$/ + width = get_int(args[0], "Set width", 10, nil, 80) + if width + self.class.settings[:width] = width + ENV['COLUMNS'] = width.to_s + else + return + end + else + print "Unknown setting #{@match[1]}.\n" + return + end + print "%s\n" % show_setting(try_subcmd.name) + return + rescue RuntimeError + return + end + end + end + print "Unknown set command #{subcmd}\n" + end + end + + class << self + def help_command + "set" + end + + def help(args) + if args[1] + s = args[1] + subcmd = Subcommands.find do |try_subcmd| + (s.size >= try_subcmd.min) and + (try_subcmd.name[0..s.size-1] == s) + end + if subcmd + str = subcmd.short_help + '.' + str += "\n" + subcmd.long_help if subcmd.long_help + return str + else + return "Invalid 'set' subcommand '#{args[1]}'." + end + end + s = %{ + Modifies parts of the ruby-debug environment. Boolean values take + on, off, 1 or 0. + You can see these environment settings with the \"show\" command. + + -- + List of set subcommands: + -- + } + for subcmd in Subcommands do + s += "set #{subcmd.name} -- #{subcmd.short_help}\n" + end + return s + end + end + end +end diff --git a/cli/ruby-debug/commands/show.rb b/cli/ruby-debug/commands/show.rb new file mode 100644 index 0000000..f2992ad --- /dev/null +++ b/cli/ruby-debug/commands/show.rb @@ -0,0 +1,253 @@ +module Debugger + # Mix-in module to showing settings + module ShowFunctions # :nodoc: + def show_setting(setting_name) + case setting_name + when /^annotate$/ + Debugger.annotate ||= 0 + return ("Annotation level is #{Debugger.annotate}") + when /^args$/ + if Command.settings[:argv] and Command.settings[:argv].size > 0 + if defined?(Debugger::RDEBUG_SCRIPT) + # rdebug was called initially. 1st arg is script name. + args = Command.settings[:argv][1..-1].join(' ') + else + # rdebug wasn't called initially. 1st arg is not script name. + args = Command.settings[:argv].join(' ') + end + else + args = '' + end + return "Argument list to give program being debugged when it is started is \"#{args}\"." + when /^autolist$/ + on_off = Command.settings[:autolist] > 0 + return "autolist is #{show_onoff(on_off)}." + when /^autoeval$/ + on_off = Command.settings[:autoeval] + return "autoeval is #{show_onoff(on_off)}." + when /^autoreload$/ + on_off = Command.settings[:reload_source_on_change] + return "autoreload is #{show_onoff(on_off)}." + when /^autoirb$/ + on_off = Command.settings[:autoirb] > 0 + return "autoirb is #{show_onoff(on_off)}." + when /^basename$/ + on_off = Command.settings[:basename] + return "basename is #{show_onoff(on_off)}." + when /^callstyle$/ + style = Command.settings[:callstyle] + return "Frame call-display style is #{style}." + when /^commands(:?\s+(\d+))?$/ + if @state.interface.readline_support? + s = ''; + args = @match[1].split + if args[1] + first_line = args[1].to_i - 4 + last_line = first_line + 10 - 1 + if first_line > Readline::HISTORY.length + first_line = last_line = Readline::HISTORY.length + elsif first_line <= 0 + first_line = 1 + end + if last_line > Readline::HISTORY.length + last_line = Readline::HISTORY.length + end + i = first_line + commands = Readline::HISTORY.to_a[first_line..last_line] + else + if Readline::HISTORY.length > 10 + commands = Readline::HISTORY.to_a[-10..-1] + i = Readline::HISTORY.length - 10 + else + commands = Readline::HISTORY.to_a + i = 1 + end + end + commands.each do |cmd| + s += ("%5d %s\n" % [i, cmd]) + i += 1 + end + else + s='No readline suport' + end + return s + when /^debuggertesting$/ + on_off = Command.settings[:debuggertesting] + return "Currently testing the debugger is #{show_onoff(on_off)}." + when /^forcestep$/ + on_off = self.class.settings[:force_stepping] + return "force-stepping is #{show_onoff(on_off)}." + when /^fullpath$/ + on_off = Command.settings[:full_path] + return "Displaying frame's full file names is #{show_onoff(on_off)}." + when /^history(:?\s+(filename|save|size))?$/ + args = @match[1].split + interface = @state.interface + if args[1] + show_save = show_size = show_filename = false + prefix = false + if args[1] == "save" + show_save = true + elsif args[1] == "size" + show_size = true + elsif args[1] == "filename" + show_filename = true + end + else + show_save = show_size = show_filename = true + prefix = true + end + s = [] + if show_filename + msg = (prefix ? "filename: " : "") + + "The filename in which to record the command history is " + + "#{interface.histfile.inspect}" + s << msg + end + if show_save + msg = (prefix ? "save: " : "") + + "Saving of history save is #{show_onoff(interface.history_save)}." + s << msg + end + if show_size + msg = (prefix ? "size: " : "") + + "Debugger history size is #{interface.history_length}" + s << msg + end + return s.join("\n") + when /^keep-frame-bindings$/ + on_off = Debugger.keep_frame_binding? + return "keep-frame-bindings is #{show_onoff(on_off)}." + when /^linetrace$/ + on_off = Debugger.tracing + return "line tracing is #{show_onoff(on_off)}." + when /^linetrace\+$/ + on_off = Command.settings[:tracing_plus] + if on_off + return "line tracing style is different consecutive lines." + else + return "line tracing style is every line." + end + when /^listsize$/ + listlines = Command.settings[:listsize] + return "Number of source lines to list by default is #{listlines}." + when /^port$/ + return "server port is #{Debugger::PORT}." + when /^post-mortem$/ + on_off = Debugger.post_mortem? + return "post-mortem handling is #{show_onoff(on_off)}." + when /^trace$/ + on_off = Command.settings[:stack_trace_on_error] + return "Displaying stack trace is #{show_onoff(on_off)}." + when /^version$/ + return "ruby-debug #{Debugger::VERSION}" + when /^width$/ + return "width is #{self.class.settings[:width]}." + else + return "Unknown show subcommand #{setting_name}." + end + end + end + + # Implements debugger "show" command. + class ShowCommand < Command + + Subcommands = + [ + ['annotate', 2, "Show annotation level", +"0 == normal; 2 == output annotated suitably for use by programs that control +ruby-debug."], + ['args', 2, + "Show argument list to give program being debugged when it is started", +"Follow this command with any number of args, to be passed to the program."], + ['autoeval', 4, "Show if unrecognized command are evaluated"], + ['autolist', 4, "Show if 'list' commands is run on breakpoints"], + ['autoirb', 4, "Show if IRB is invoked on debugger stops"], + ['autoreload', 4, "Show if source code is reloaded when changed"], + ['basename', 1, "Show if basename used in reporting files"], + ['callstyle', 2, "Show paramater style used showing call frames"], + ['commands', 2, "Show the history of commands you typed", +"You can supply a command number to start with."], + ['forcestep', 1, "Show if sure 'next/step' forces move to a new line"], + ['fullpath', 2, "Show if full file names are displayed in frames"], + ['history', 2, "Generic command for showing command history parameters", +"show history filename -- Show the filename in which to record the command history +show history save -- Show saving of the history record on exit +show history size -- Show the size of the command history"], + ['keep-frame-bindings', 1, "Save frame binding on each call"], + ['linetrace', 3, "Show line execution tracing"], + ['linetrace+', 10, + "Show if consecutive lines should be different are shown in tracing"], + ['listsize', 3, "Show number of source lines to list by default"], + ['port', 3, "Show server port"], + ['post-mortem', 3, "Show whether we go into post-mortem debugging on an uncaught exception"], + ['trace', 1, + "Show if a stack trace is displayed when 'eval' raises exception"], + ['version', 1, + "Show what version of the debugger this is"], + ['width', 1, + "Show the number of characters the debugger thinks are in a line"], + ].map do |name, min, short_help, long_help| + SubcmdStruct.new(name, min, short_help, long_help) + end unless defined?(Subcommands) + + self.allow_in_control = true + + def regexp + /^show (?: \s+ (.+) )?$/xi + end + + def execute + if not @match[1] + print "\"show\" must be followed by the name of an show command:\n" + print "List of show subcommands:\n\n" + for subcmd in Subcommands do + print "show #{subcmd.name} -- #{subcmd.short_help}\n" + end + else + args = @match[1].split(/[ \t]+/) + param = args.shift + subcmd = find(Subcommands, param) + if subcmd + print "%s\n" % show_setting(subcmd.name) + else + print "Unknown show command #{param}\n" + end + end + end + + class << self + def help_command + "show" + end + + def help(args) + if args[1] + s = args[1] + subcmd = Subcommands.find do |try_subcmd| + (s.size >= try_subcmd.min) and + (try_subcmd.name[0..s.size-1] == s) + end + if subcmd + str = subcmd.short_help + '.' + str += "\n" + subcmd.long_help if subcmd.long_help + return str + else + return "Invalid 'show' subcommand '#{args[1]}'." + end + end + s = " + Generic command for showing things about the debugger. + + -- + List of show subcommands: + -- + " + for subcmd in Subcommands do + s += "show #{subcmd.name} -- #{subcmd.short_help}\n" + end + return s + end + end + end +end diff --git a/cli/ruby-debug/commands/source.rb b/cli/ruby-debug/commands/source.rb new file mode 100644 index 0000000..a5e7179 --- /dev/null +++ b/cli/ruby-debug/commands/source.rb @@ -0,0 +1,36 @@ +module Debugger + # Implements debugger "source" command. + class SourceCommand < Command + self.allow_in_control = true + + def regexp + /^\s* so(?:urce)? \s+ (.+) $/x + end + + def execute + file = File.expand_path(@match[1]).strip + unless File.exist?(file) + errmsg "Command file '#{file}' is not found\n" + return + end + if @state and @state.interface + @state.interface.command_queue += File.open(file).readlines + else + Debugger.run_script(file, @state) + end + end + + class << self + def help_command + 'source' + end + + def help(cmd) + %{ + source FILE\texecutes a file containing debugger commands + } + end + end + end + +end diff --git a/cli/ruby-debug/commands/stepping.rb b/cli/ruby-debug/commands/stepping.rb new file mode 100644 index 0000000..5b1c3b2 --- /dev/null +++ b/cli/ruby-debug/commands/stepping.rb @@ -0,0 +1,81 @@ +module Debugger + # Mix-in module to assist in command parsing. + module SteppingFunctions # :nodoc: + def parse_stepping_args(command_name, match) + if match[1].nil? + force = Command.settings[:force_stepping] + elsif match[1] == '+' + force = true + elsif match[1] == '-' + force = false + end + steps = get_int(match[2], command_name, 1) + return [steps, force] + end + end + # Implements debugger "next" command. + class NextCommand < Command + self.allow_in_post_mortem = false + self.need_context = true + + def regexp + /^\s* n(?:ext)? + ([+-])?(?:\s+(\S+))? + \s*$/x + end + + def execute + steps, force = parse_stepping_args("Next", @match) + return unless steps + @state.context.step_over steps, @state.frame_pos, force + @state.proceed + end + + class << self + def help_command + 'next' + end + + def help(cmd) + %{ + n[ext][+-]?[ nnn]\tstep over once or nnn times, + \t\t'+' forces to move to another line. + \t\t'-' is the opposite of '+' and disables the force_stepping setting. + } + end + end + end + + # Implements debugger "step" command. + class StepCommand < Command + self.allow_in_post_mortem = false + self.need_context = true + + def regexp + /^\s* s(?:tep)? + ([+-])?(?:\s+(\S+))? + \s*$/x + end + + def execute + steps, force = parse_stepping_args("Step", @match) + return unless steps + @state.context.step(steps, force) + @state.proceed + end + + class << self + def help_command + 'step' + end + + def help(cmd) + %{ + s[tep][+-]?[ nnn]\tstep (into methods) once or nnn times + \t\t'+' forces to move to another line. + \t\t'-' is the opposite of '+' and disables the force_stepping setting. + } + end + end + end +end diff --git a/cli/ruby-debug/commands/threads.rb b/cli/ruby-debug/commands/threads.rb new file mode 100644 index 0000000..c06c8bf --- /dev/null +++ b/cli/ruby-debug/commands/threads.rb @@ -0,0 +1,189 @@ +module Debugger + module ThreadFunctions # :nodoc: + def display_context(c, show_top_frame=true) + c_flag = c.thread == Thread.current ? '+' : ' ' + c_flag = '$' if c.suspended? + d_flag = c.ignored? ? '!' : ' ' + print "%s%s", c_flag, d_flag + print "%d ", c.thnum + print "%s\t", c.thread.inspect + if c.stack_size > 0 and show_top_frame + print "%s:%d", c.frame_file(0), c.frame_line(0) + end + print "\n" + end + + def parse_thread_num(subcmd, arg) + if '' == arg + errmsg "'%s' needs a thread number\n" % subcmd + nil + else + thread_num = get_int(arg, "thread #{subcmd}", 1) + return nil unless thread_num + get_context(thread_num) + end + end + + def parse_thread_num_for_cmd(subcmd, arg) + c = parse_thread_num(subcmd, arg) + return nil unless c + case + when nil == c + errmsg "No such thread.\n" + when @state.context == c + errmsg "It's the current thread.\n" + when c.ignored? + errmsg "Can't #{subcmd} to the debugger thread #{arg}.\n" + else # Everything is okay + return c + end + return nil + end + end + + class ThreadListCommand < Command # :nodoc: + self.allow_in_control = true + + def regexp + /^\s*th(?:read)?\s+l(?:ist)?\s*$/ + end + + def execute + threads = Debugger.contexts.sort_by{|c| c.thnum}.each do |c| + display_context(c) + end + end + + class << self + def help_command + 'thread' + end + + def help(cmd) + %{ + th[read] l[ist]\t\t\tlist all threads + } + end + end + end + + class ThreadStopCommand < Command # :nodoc: + self.allow_in_control = true + self.allow_in_post_mortem = false + self.need_context = true + + def regexp + /^\s*th(?:read)?\s+stop\s*(\S*)\s*$/ + end + + def execute + c = parse_thread_num_for_cmd("thread stop", @match[1]) + return unless c + c.suspend + display_context(c) + end + + class << self + def help_command + 'thread' + end + + def help(cmd) + %{ + th[read] stop \t\tstop thread nnn + } + end + end + end + + class ThreadResumeCommand < Command # :nodoc: + self.allow_in_post_mortem = false + self.allow_in_control = true + self.need_context = true + + def regexp + /^\s*th(?:read)?\s+resume\s*(\S*)\s*$/ + end + + def execute + c = parse_thread_num_for_cmd("thread resume", @match[1]) + return unless c + if !c.thread.stop? + print "Already running." + return + end + c.resume + display_context(c) + end + + class << self + def help_command + 'thread' + end + + def help(cmd) + %{ + th[read] resume \t\tresume thread nnn + } + end + end + end + + # Thread switch Must come after "Thread resume" because "switch" is + # optional + + class ThreadSwitchCommand < Command # :nodoc: + self.allow_in_control = true + self.allow_in_post_mortem = false + self.need_context = true + + def regexp + /^\s*th(?:read)?\s*(?:sw(?:itch)?)?\s+(\S+)\s*$/ + end + + def execute + c = parse_thread_num_for_cmd("thread switch", @match[1]) + return unless c + display_context(c) + c.stop_next = 1 + c.thread.run + @state.proceed + end + + class << self + def help_command + 'thread' + end + + def help(cmd) + %{ + th[read] [sw[itch]] \tswitch thread context to nnn + } + end + end + end + + class ThreadCurrentCommand < Command # :nodoc: + self.need_context = true + + def regexp + /^\s*th(?:read)?\s*(?:cur(?:rent)?)?\s*$/ + end + + def execute + display_context(@state.context) + end + + class << self + def help_command + 'thread' + end + + def help(cmd) + %{ + th[read] [cur[rent]]\t\tshow current thread + } + end + end + end +end diff --git a/cli/ruby-debug/commands/tmate.rb b/cli/ruby-debug/commands/tmate.rb new file mode 100644 index 0000000..060a7d1 --- /dev/null +++ b/cli/ruby-debug/commands/tmate.rb @@ -0,0 +1,36 @@ +module Debugger + if RUBY_PLATFORM =~ /darwin/ + class TextMateCommand < Command # :nodoc: + def regexp + /^\s*tm(?:ate)?(?:\s*(\d+))?$/ + end + + def execute + if @match[1] + frm_n = @match[1].to_i + if frm_n > @state.context.stack_size || frm_n == 0 + print "Wrong frame number\n" + return + end + file, line = @state.context.frame_file(frm_n-1), @state.context.frame_line(frm_n-1) + else + file, line = @state.file, @state.line + end + %x|open 'txmt://open?url=file://#{File.expand_path(file)}&line=#{line}'| + end + + class << self + def help_command + 'tmate' + end + + def help(cmd) + %{ + tm[ate] n\topens a current file in TextMate. + \t\tIt uses n-th frame if arg (n) is specifed. + } + end + end + end + end +end diff --git a/cli/ruby-debug/commands/trace.rb b/cli/ruby-debug/commands/trace.rb new file mode 100644 index 0000000..ed063aa --- /dev/null +++ b/cli/ruby-debug/commands/trace.rb @@ -0,0 +1,57 @@ +module Debugger + class TraceCommand < Command # :nodoc: + def regexp + /^\s* tr(?:ace)? (?: \s+ (\S+)) # on |off | var(iable) + (?: \s+ (\S+))? # (all | variable-name)? + (?: \s+ (\S+))? \s* # (stop | nostop)? + $/ix + end + + def execute + if @match[1] =~ /on|off/ + onoff = 'on' == @match[1] + if @match[2] + Debugger.current_context.tracing = onoff + print "Tracing %s all threads.\n" % (onoff ? 'on' : 'off') + else + Debugger.tracing = onoff + print "Tracing %s on current thread.\n" % (onoff ? 'on' : 'off') + end + elsif @match[1] =~ /var(?:iable)?/ + varname=@match[2] + if debug_eval("defined?(#{varname})") + if @match[3] && @match[3] !~ /(:?no)?stop/ + errmsg("expecting 'stop' or 'nostop'; got %s\n" % @match[3]) + else + dbg_cmd = if @match[3] && (@match[3] !~ /nostop/) + 'debugger' else '' end + end + eval(" + trace_var(:#{varname}) do |val| + print \"traced variable #{varname} has value \#{val}\n\" + #{dbg_cmd} + end") + else + errmsg "#{varname} is not a global variable.\n" + end + else + errmsg("expecting 'on', 'off', 'var' or 'variable'; got: %s\n" % + @match[1]) + end + end + + class << self + def help_command + 'trace' + end + + def help(cmd) + %{ + tr[ace] (on|off)\tset trace mode of current thread + tr[ace] (on|off) all\tset trace mode of all threads + tr[ace] var(iable) VARNAME [stop|nostop]\tset trace variable on VARNAME + } + end + end + end +end diff --git a/cli/ruby-debug/commands/variables.rb b/cli/ruby-debug/commands/variables.rb new file mode 100644 index 0000000..e326e46 --- /dev/null +++ b/cli/ruby-debug/commands/variables.rb @@ -0,0 +1,199 @@ +module Debugger + module VarFunctions # :nodoc: + def var_list(ary, b = get_binding) + ary.sort! + for v in ary + begin + s = debug_eval(v, b).inspect + rescue + begin + s = debug_eval(v, b).to_s + rescue + s = "*Error in evaluation*" + end + end + if s.size > self.class.settings[:width] + s[self.class.settings[:width]-3 .. -1] = "..." + end + print "%s = %s\n", v, s + end + end + def var_class_self + obj = debug_eval('self') + var_list(obj.class.class_variables, get_binding) + end + end + + # Implements the debugger 'var class' command. + class VarClassVarCommand < Command + def regexp + /^\s*v(?:ar)?\s+cl(?:ass)?/ + end + + def execute + unless @state.context + errmsg "can't get class variables here.\n" + return + end + var_class_self + end + + class << self + def help_command + 'var' + end + + def help(cmd) + %{ + v[ar] cl[ass] \t\t\tshow class variables of self + } + end + end + end + + class VarConstantCommand < Command # :nodoc: + def regexp + /^\s*v(?:ar)?\s+co(?:nst(?:ant)?)?\s+/ + end + + def execute + obj = debug_eval(@match.post_match) + if obj.kind_of? Module + constants = debug_eval("#{@match.post_match}.constants") + constants.sort! + for c in constants + next if c =~ /SCRIPT/ + value = obj.const_get(c) rescue "ERROR: #{$!}" + print " %s => %p\n", c, value + end + else + print "Should be Class/Module: %s\n", @match.post_match + end + end + + class << self + def help_command + 'var' + end + + def help(cmd) + %{ + v[ar] c[onst] \t\tshow constants of object + } + end + end + end + + class VarGlobalCommand < Command # :nodoc: + def regexp + /^\s*v(?:ar)?\s+g(?:lobal)?\s*$/ + end + + def execute + var_list(global_variables) + end + + class << self + def help_command + 'var' + end + + def help(cmd) + %{ + v[ar] g[lobal]\t\t\tshow global variables + } + end + end + end + + class VarInstanceCommand < Command # :nodoc: + def regexp + /^\s*v(?:ar)?\s+ins(?:tance)?\s*/ + end + + def execute + obj = debug_eval(@match.post_match.empty? ? 'self' : @match.post_match) + var_list(obj.instance_variables, obj.instance_eval{binding()}) + end + + class << self + def help_command + 'var' + end + + def help(cmd) + %{ + v[ar] i[nstance] \tshow instance variables of object + } + end + end + end + + # Implements the debugger 'var local' command. + class VarLocalCommand < Command + def regexp + /^\s*v(?:ar)?\s+l(?:ocal)?\s*$/ + end + + def execute + locals = @state.context.frame_locals(@state.frame_pos) + _self = @state.context.frame_self(@state.frame_pos) + locals.keys.sort.each do |name| + print " %s => %p\n", name, locals[name] + end + end + + class << self + def help_command + 'var' + end + + def help(cmd) + %{ + v[ar] l[ocal]\t\t\tshow local variables + } + end + end + end + + # Implements the debugger 'var inherit' command. + begin + require 'classtree' + have_classtree = true + rescue LoadError + have_classtree = false + end + + class VarInheritCommand < Command + def regexp + /^\s*v(?:ar)?\s+ct\s*/ + end + + def execute + unless @state.context + errmsg "can't get object inheritance.\n" + return + end + puts @match.post_match + obj = debug_eval("#{@match.post_match}.classtree") + if obj + print obj + else + errmsg "Trouble getting object #{@match.post_match}\n" + end + end + + class << self + def help_command + 'var' + end + + def help(cmd) + %{ + v[ar] ct\t\t\tshow class heirarchy of object + } + end + end + end if have_classtree + +end diff --git a/cli/ruby-debug/debugger.rb b/cli/ruby-debug/debugger.rb new file mode 100644 index 0000000..d581c05 --- /dev/null +++ b/cli/ruby-debug/debugger.rb @@ -0,0 +1,5 @@ +# Module/Package to do the most-common thing: get into the debugger with +# minimal fuss. Compare with: require "debug" +require "ruby-debug" +Debugger.start +debugger \ No newline at end of file diff --git a/cli/ruby-debug/helper.rb b/cli/ruby-debug/helper.rb new file mode 100644 index 0000000..f159c3c --- /dev/null +++ b/cli/ruby-debug/helper.rb @@ -0,0 +1,69 @@ +module Debugger + + module ParseFunctions + Position_regexp = '(?:(\d+)|(.+?)[:.#]([^.:\s]+))' + + # Parse 'str' of command 'cmd' as an integer between + # min and max. If either min or max is nil, that + # value has no bound. + def get_int(str, cmd, min=nil, max=nil, default=1) + return default unless str + begin + int = Integer(str) + if min and int < min + print "%s argument '%s' needs to at least %s.\n" % [cmd, str, min] + return nil + elsif max and int > max + print "%s argument '%s' needs to at most %s.\n" % [cmd, str, max] + return nil + end + return int + rescue + print "%s argument '%s' needs to be a number.\n" % [cmd, str] + return nil + end + end + + # Return true if arg is 'on' or 1 and false arg is 'off' or 0. + # Any other value raises RuntimeError. + def get_onoff(arg, default=nil, print_error=true) + if arg.nil? or arg == '' + if default.nil? + if print_error + print "Expecting 'on', 1, 'off', or 0. Got nothing.\n" + raise RuntimeError + end + return default + end + end + case arg.downcase + when '1', 'on' + return true + when '0', 'off' + return false + else + if print_error + print "Expecting 'on', 1, 'off', or 0. Got: %s.\n" % arg.to_s + raise RuntimeError + end + end + end + + # Return 'on' or 'off' for supplied parameter. The parmeter should + # be true, false or nil. + def show_onoff(bool) + if not [TrueClass, FalseClass, NilClass].member?(bool.class) + return "??" + end + return bool ? 'on' : 'off' + end + + # Return true if code is syntactically correct for Ruby. + def syntax_valid?(code) + eval("BEGIN {return true}\n#{code}", nil, "", 0) + rescue Exception + false + end + + end +end diff --git a/cli/ruby-debug/interface.rb b/cli/ruby-debug/interface.rb new file mode 100644 index 0000000..63feea1 --- /dev/null +++ b/cli/ruby-debug/interface.rb @@ -0,0 +1,232 @@ +module Debugger + class Interface # :nodoc: + attr_writer :have_readline # true if Readline is available + + def initialize + @have_readline = false + end + + # Common routine for reporting debugger error messages. + # Derived classed may want to override this to capture output. + def errmsg(*args) + if Debugger.annotate.to_i > 2 + aprint 'error-begin' + print(*args) + aprint '' + else + print '*** ' + print(*args) + end + end + + # Format msg with gdb-style annotation header + def afmt(msg, newline="\n") + "\032\032#{msg}#{newline}" + end + + def aprint(msg) + print afmt(msg) + end + + end + + class LocalInterface < Interface # :nodoc: + attr_accessor :command_queue + attr_accessor :histfile + attr_accessor :history_save + attr_accessor :history_length + attr_accessor :restart_file + + unless defined?(FILE_HISTORY) + FILE_HISTORY = ".rdebug_hist" + end + def initialize() + super + @command_queue = [] + @have_readline = false + @history_save = true + # take gdb's default + @history_length = ENV["HISTSIZE"] ? ENV["HISTSIZE"].to_i : 256 + @histfile = File.join(ENV["HOME"]||ENV["HOMEPATH"]||".", + FILE_HISTORY) + open(@histfile, 'r') do |file| + file.each do |line| + line.chomp! + Readline::HISTORY << line + end + end if File.exist?(@histfile) + @restart_file = nil + end + + def read_command(prompt) + readline(prompt, true) + end + + def confirm(prompt) + readline(prompt, false) + end + + def print(*args) + STDOUT.printf(*args) + end + + def close + end + + # Things to do before quitting + def finalize + if Debugger.method_defined?("annotate") and Debugger.annotate.to_i > 2 + print "\032\032exited\n\n" + end + if Debugger.respond_to?(:save_history) + Debugger.save_history + end + end + + def readline_support? + @have_readline + end + + private + begin + require 'readline' + class << Debugger + @have_readline = true + define_method(:save_history) do + iface = self.handler.interface + iface.histfile ||= File.join(ENV["HOME"]||ENV["HOMEPATH"]||".", + FILE_HISTORY) + open(iface.histfile, 'w') do |file| + Readline::HISTORY.to_a.last(iface.history_length).each do |line| + file.puts line unless line.strip.empty? + end if defined?(iface.history_save) and iface.history_save + end rescue nil + end + public :save_history + end + Debugger.debug_at_exit do + finalize if respond_to?(:finalize) + end + + def readline(prompt, hist) + Readline::readline(prompt, hist) + end + rescue LoadError + def readline(prompt, hist) + @histfile = '' + @hist_save = false + STDOUT.print prompt + STDOUT.flush + line = STDIN.gets + exit unless line + line.chomp! + line + end + end + end + + class RemoteInterface < Interface # :nodoc: + attr_accessor :command_queue + attr_accessor :histfile + attr_accessor :history_save + attr_accessor :history_length + attr_accessor :restart_file + + def initialize(socket) + @command_queue = [] + @socket = socket + @history_save = false + @history_length = 256 + @histfile = '' + # Do we read the histfile? +# open(@histfile, 'r') do |file| +# file.each do |line| +# line.chomp! +# Readline::HISTORY << line +# end +# end if File.exist?(@histfile) + @restart_file = nil + end + + def close + @socket.close + rescue Exception + end + + def confirm(prompt) + send_command "CONFIRM #{prompt}" + end + + def finalize + end + + def read_command(prompt) + send_command "PROMPT #{prompt}" + end + + def readline_support? + false + end + + def print(*args) + @socket.printf(*args) + end + + private + + def send_command(msg) + @socket.puts msg + result = @socket.gets + raise IOError unless result + result.chomp + end + end + + class ScriptInterface < Interface # :nodoc: + attr_accessor :command_queue + attr_accessor :histfile + attr_accessor :history_save + attr_accessor :history_length + attr_accessor :restart_file + def initialize(file, out, verbose=false) + super() + @command_queue = [] + @file = file.respond_to?(:gets) ? file : open(file) + @out = out + @verbose = verbose + @history_save = false + @history_length = 256 # take gdb default + @histfile = '' + end + + def finalize + end + + def read_command(prompt) + while result = @file.gets + puts "# #{result}" if @verbose + next if result =~ /^\s*#/ + next if result.strip.empty? + break + end + raise IOError unless result + result.chomp! + end + + def readline_support? + false + end + + def confirm(prompt) + 'y' + end + + def print(*args) + @out.printf(*args) + end + + def close + @file.close + end + end +end diff --git a/cli/ruby-debug/processor.rb b/cli/ruby-debug/processor.rb new file mode 100644 index 0000000..dbb85a2 --- /dev/null +++ b/cli/ruby-debug/processor.rb @@ -0,0 +1,474 @@ +require 'ruby-debug/interface' +require 'ruby-debug/command' + +module Debugger + + # Should this be a mixin? + class Processor # :nodoc + attr_accessor :interface + + # Format msg with gdb-style annotation header + def afmt(msg, newline="\n") + "\032\032#{msg}#{newline}" + end + + def aprint(msg) + print afmt(msg) if Debugger.annotate.to_i > 2 + end + + # FIXME: use delegate? + def errmsg(*args) + @interface.errmsg(*args) + end + + # Callers of this routine should make sure to use comma to + # separate format argments rather than %. Otherwise it seems that + # if the string you want to print has format specifier, which + # could happen if you are trying to show say a source-code line + # with "puts" or "print" in it, this print routine will give an + # error saying it is looking for more arguments. + def print(*args) + @interface.print(*args) + end + + end + + class CommandProcessor < Processor # :nodoc: + attr_reader :display + + # FIXME: get from Command regexp method. + @@Show_breakpoints_postcmd = [ + /^\s*b(?:reak)?/, + /^\s* cond(?:ition)? (?:\s+(\d+)\s*(.*))?$/ix, + /^\s*del(?:ete)?(?:\s+(.*))?$/ix, + /^\s* dis(?:able)? (?:\s+(.*))?$/ix, + /^\s* en(?:able)? (?:\s+(.*))?$/ix, + # "tbreak", "clear", + ] + @@Show_annotations_run = [ + /^\s*c(?:ont(?:inue)?)?(?:\s+(.*))?$/, + /^\s*fin(?:ish)?$/, + /^\s*n(?:ext)?([+-])?(?:\s+(.*))?$/, + /^\s*s(?:tep)?([+-])?(?:\s+(.*))?$/ + ] + + @@Show_annotations_postcmd = [ + /^\s* down (?:\s+(.*))? .*$/x, + /^\s* f(?:rame)? (?:\s+ (.*))? \s*$/x, + /^\s* u(?:p)? (?:\s+(.*))?$/x + ] + + def initialize(interface = LocalInterface.new) + @interface = interface + @display = [] + + @mutex = Mutex.new + @last_cmd = nil + @last_file = nil # Filename the last time we stopped + @last_line = nil # line number the last time we stopped + @debugger_breakpoints_were_empty = false # Show breakpoints 1st time + @debugger_displays_were_empty = true # No display 1st time + @debugger_context_was_dead = true # Assume we haven't started. + end + + def interface=(interface) + @mutex.synchronize do + @interface.close if @interface + @interface = interface + end + end + + require 'pathname' # For cleanpath + + # Regularize file name. + # This is also used as a common funnel place if basename is + # desired or if we are working remotely and want to change the + # basename. Or we are eliding filenames. + def self.canonic_file(filename) + # For now we want resolved filenames + if Command.settings[:basename] + File.basename(filename) + else + # Cache this? + Pathname.new(filename).cleanpath.to_s + end + end + + def self.print_location_and_text(file, line) + file_line = "%s:%s\n%s" % [canonic_file(file), line, + Debugger.line_at(file, line)] + # FIXME: use annotations routines + if Debugger.annotate.to_i > 2 + file_line = "\032\032source #{file_line}" + elsif ENV['EMACS'] + file_line = "\032\032#{file_line}" + end + print file_line + end + + def self.protect(mname) + alias_method "__#{mname}", mname + module_eval %{ + def #{mname}(*args) + @mutex.synchronize do + return unless @interface + __#{mname}(*args) + end + rescue IOError, Errno::EPIPE + self.interface = nil + rescue SignalException + raise + rescue Exception + print "INTERNAL ERROR!!! #\{$!\}\n" rescue nil + print $!.backtrace.map{|l| "\t#\{l\}"}.join("\n") rescue nil + end + } + end + + def at_breakpoint(context, breakpoint) + aprint 'stopped' if Debugger.annotate.to_i > 2 + n = Debugger.breakpoints.index(breakpoint) + 1 + file = CommandProcessor.canonic_file(breakpoint.source) + line = breakpoint.pos + if Debugger.annotate.to_i > 2 + print afmt("source #{file}:#{line}") + end + print "Breakpoint %d at %s:%s\n", n, file, line + end + protect :at_breakpoint + + def at_catchpoint(context, excpt) + aprint 'stopped' if Debugger.annotate.to_i > 2 + file = CommandProcessor.canonic_file(context.frame_file(0)) + line = context.frame_line(0) + print afmt("%s:%d" % [file, line]) if ENV['EMACS'] + print "Catchpoint at %s:%d: `%s' (%s)\n", file, line, excpt, excpt.class + fs = context.stack_size + tb = caller(0)[-fs..-1] + if tb + for i in tb + print "\tfrom %s\n", i + end + end + end + protect :at_catchpoint + + def at_tracing(context, file, line) + return if defined?(Debugger::RDEBUG_FILE) && + Debugger::RDEBUG_FILE == file # Don't trace ourself + @last_file = CommandProcessor.canonic_file(file) + file = CommandProcessor.canonic_file(file) + unless file == @last_file and @last_line == line and + Command.settings[:tracing_plus] + print "Tracing(%d):%s:%s %s", + context.thnum, file, line, Debugger.line_at(file, line) + @last_file = file + @last_line = line + end + always_run(context, file, line, 2) + end + protect :at_tracing + + def at_line(context, file, line) + process_commands(context, file, line) + end + protect :at_line + + def at_return(context, file, line) + context.stop_frame = -1 + process_commands(context, file, line) + end + + private + + # The prompt shown before reading a command. + def prompt(context) + p = '(rdb:%s) ' % (context.dead? ? 'post-mortem' : context.thnum) + p = afmt("pre-prompt")+p+"\n"+afmt("prompt") if + Debugger.annotate.to_i > 2 + return p + end + + # Run these commands, for example display commands or possibly + # the list or irb in an "autolist" or "autoirb". + # We return a list of commands that are acceptable to run bound + # to the current state. + def always_run(context, file, line, run_level) + event_cmds = Command.commands.select{|cmd| cmd.event } + + # Remove some commands in post-mortem + event_cmds = event_cmds.find_all do |cmd| + cmd.allow_in_post_mortem + end if context.dead? + + state = State.new do |s| + s.context = context + s.file = file + s.line = line + s.binding = context.frame_binding(0) + s.display = display + s.interface = interface + s.commands = event_cmds + end + @interface.state = state if @interface.respond_to?('state=') + + # Bind commands to the current state. + commands = event_cmds.map{|cmd| cmd.new(state)} + + commands.select do |cmd| + cmd.class.always_run >= run_level + end.each {|cmd| cmd.execute} + return state, commands + end + + # Handle debugger commands + def process_commands(context, file, line) + state, commands = always_run(context, file, line, 1) + $rdebug_state = state if Command.settings[:debuggertesting] + splitter = lambda do |str| + str.split(/;/).inject([]) do |m, v| + if m.empty? + m << v + else + if m.last[-1] == ?\\ + m.last[-1,1] = '' + m.last << ';' << v + else + m << v + end + end + m + end + end + + preloop(commands, context) + CommandProcessor.print_location_and_text(file, line) + while !state.proceed? + input = if @interface.command_queue.empty? + @interface.read_command(prompt(context)) + else + @interface.command_queue.shift + end + break unless input + catch(:debug_error) do + if input == "" + next unless @last_cmd + input = @last_cmd + else + @last_cmd = input + end + splitter[input].each do |cmd| + one_cmd(commands, context, cmd) + postcmd(commands, context, cmd) + end + end + end + postloop(commands, context) + end # process_commands + + def one_cmd(commands, context, input) + if cmd = commands.find{ |c| c.match(input) } + if context.dead? && cmd.class.need_context + p cmd + print "Command is unavailable\n" + else + cmd.execute + end + else + unknown_cmd = commands.find{|cmd| cmd.class.unknown } + if unknown_cmd + unknown_cmd.execute + else + errmsg "Unknown command: \"#{input}\". Try \"help\".\n" + end + end + end + + def preloop(commands, context) + aprint('stopped') if Debugger.annotate.to_i > 2 + if context.dead? + unless @debugger_context_was_dead + if Debugger.annotate.to_i > 2 + aprint('exited') + print "The program finished.\n" + end + @debugger_context_was_dead = true + end + end + + if Debugger.annotate.to_i > 2 + # if we are here, the stack frames have changed outside the + # command loop (e.g. after a "continue" command), so we show + # the annotations again + breakpoint_annotations(commands, context) + display_annotations(commands, context) + annotation('stack', commands, context, "where") + annotation('variables', commands, context, "info variables") unless + context.dead? + end + end + + def postcmd(commands, context, cmd) + if Debugger.annotate.to_i > 0 + cmd = @last_cmd unless cmd + breakpoint_annotations(commands, context) if + @@Show_breakpoints_postcmd.find{|pat| cmd =~ pat} + display_annotations(commands, context) + if @@Show_annotations_postcmd.find{|pat| cmd =~ pat} + annotation('stack', commands, context, "where") if + context.stack_size > 0 + annotation('variables', commands, context, "info variables") unless + context.dead? + end + if not context.dead? and @@Show_annotations_run.find{|pat| cmd =~ pat} + aprint 'starting' if Debugger.annotate.to_i > 2 + + @debugger_context_was_dead = false + end + end + end + + def postloop(commands, context) + end + + def annotation(label, commands, context, cmd) + print afmt(label) + one_cmd(commands, context, cmd) + ### FIXME ANNOTATE: the following line should be deleted + print "\032\032\n" + end + + def breakpoint_annotations(commands, context) + unless Debugger.breakpoints.empty? and @debugger_breakpoints_were_empty + annotation('breakpoints', commands, context, "info breakpoints") + @debugger_breakpoints_were_empty = Debugger.breakpoints.empty? + end + end + + def display_annotations(commands, context) + return if display.empty? +# have_display = display.find{|d| d[0]} +# return unless have_display and @debugger_displays_were_empty +# @debugger_displays_were_empty = have_display + annotation('display', commands, context, "display") + end + + class State # :nodoc: + attr_accessor :context, :file, :line, :binding + attr_accessor :frame_pos, :previous_line, :display + attr_accessor :interface, :commands + + def initialize + super() + @frame_pos = 0 + @previous_line = nil + @proceed = false + yield self + end + + # FIXME: use delegate? + def errmsg(*args) + @interface.errmsg(*args) + end + + def print(*args) + @interface.print(*args) + end + + def confirm(*args) + @interface.confirm(*args) + end + + def proceed? + @proceed + end + + def proceed + @proceed = true + end + end + end + + class ControlCommandProcessor < Processor # :nodoc: + def initialize(interface) + super() + @interface = interface + @debugger_context_was_dead = true # Assume we haven't started. + end + + def process_commands(verbose=false) + control_cmds = Command.commands.select do |cmd| + cmd.allow_in_control + end + state = State.new(@interface, control_cmds) + commands = control_cmds.map{|cmd| cmd.new(state) } + + unless @debugger_context_was_dead + if Debugger.annotate.to_i > 2 + aprint 'exited' + print "The program finished.\n" + end + @debugger_context_was_dead = true + end + + while input = @interface.read_command(prompt(nil)) + print "+#{input}" if verbose + catch(:debug_error) do + if cmd = commands.find{|c| c.match(input) } + cmd.execute + else + errmsg "Unknown command\n" + end + end + end + rescue IOError, Errno::EPIPE + rescue Exception + print "INTERNAL ERROR!!! #{$!}\n" rescue nil + print $!.backtrace.map{|l| "\t#{l}"}.join("\n") rescue nil + ensure + @interface.close + end + + # The prompt shown before reading a command. + # Note: have an unused 'context' parameter to match the local interface. + def prompt(context) + p = '(rdb:ctrl) ' + p = afmt("pre-prompt")+p+"\n"+afmt("prompt") if + Debugger.annotate.to_i > 2 + return p + end + + class State # :nodoc: + attr_reader :commands, :interface + + def initialize(interface, commands) + @interface = interface + @commands = commands + end + + def proceed + end + + def errmsg(*args) + @interface.print(*args) + end + + def print(*args) + @interface.print(*args) + end + + def confirm(*args) + 'y' + end + + def context + nil + end + + def file + errmsg "No filename given.\n" + throw :debug_error + end + end # State + end +end diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..eb825b8 --- /dev/null +++ b/configure.ac @@ -0,0 +1,12 @@ +AC_INIT(ruby-debug-extra, 0.10.4vc,) +AC_CONFIG_SRCDIR(doc/ruby-debug.texi) +AM_INIT_AUTOMAKE + +## +## Find out where to install the debugger emacs lisp files +## +AM_PATH_LISPDIR +AM_CONDITIONAL(INSTALL_EMACS_LISP, test "x$lispdir" != "x") + +AC_CONFIG_FILES([doc/Makefile emacs/Makefile Makefile]) +AC_OUTPUT diff --git a/doc/.cvsignore b/doc/.cvsignore new file mode 100644 index 0000000..5260245 --- /dev/null +++ b/doc/.cvsignore @@ -0,0 +1,42 @@ +Makefile +Makefile.in +mdate-sh +missing +rdebug-emacs.aux +rdebug-emacs.cp +rdebug-emacs.cps +rdebug-emacs.fn +rdebug-emacs.fns +rdebug-emacs.html +rdebug-emacs.info +rdebug-emacs.ky +rdebug-emacs.log +rdebug-emacs.pdf +rdebug-emacs.pg +rdebug-emacs.pgs +rdebug-emacs.toc +rdebug-emacs.tp +rdebug-emacs.vr +rdoc +ruby-debug.aux +ruby-debug.cp +ruby-debug.cps +ruby-debug.fn +ruby-debug.fns +ruby-debug.html +ruby-debug.info +ruby-debug.ky +ruby-debug.kys +ruby-debug.log +ruby-debug.pdf +ruby-debug.pg +ruby-debug.pgs +ruby-debug.toc +ruby-debug.tp +ruby-debug.vr +ruby-debug.vrs +stamp-1 +stamp-vti +texinfo.tex +version-rdebug-emacs.texi +version.texi diff --git a/doc/.svn/README.txt b/doc/.svn/README.txt new file mode 100644 index 0000000..271a8ce --- /dev/null +++ b/doc/.svn/README.txt @@ -0,0 +1,2 @@ +This is a Subversion working copy administrative directory. +Visit http://subversion.tigris.org/ for more information. diff --git a/doc/.svn/dir-prop-base b/doc/.svn/dir-prop-base new file mode 100644 index 0000000..361f890 --- /dev/null +++ b/doc/.svn/dir-prop-base @@ -0,0 +1,47 @@ +K 10 +svn:ignore +V 614 +Makefile +Makefile.in +mdate-sh +missing +rdebug-emacs.aux +rdebug-emacs.cp +rdebug-emacs.cps +rdebug-emacs.fn +rdebug-emacs.fns +rdebug-emacs.html +rdebug-emacs.info +rdebug-emacs.ky +rdebug-emacs.log +rdebug-emacs.pdf +rdebug-emacs.pg +rdebug-emacs.pgs +rdebug-emacs.toc +rdebug-emacs.tp +rdebug-emacs.vr +rdoc +ruby-debug.aux +ruby-debug.cp +ruby-debug.cps +ruby-debug.fn +ruby-debug.fns +ruby-debug.html +ruby-debug.info +ruby-debug.ky +ruby-debug.kys +ruby-debug.log +ruby-debug.pdf +ruby-debug.pg +ruby-debug.pgs +ruby-debug.toc +ruby-debug.tp +ruby-debug.vr +ruby-debug.vrs +stamp-1 +stamp-vti +texinfo.tex +version-rdebug-emacs.texi +version.texi + +END diff --git a/doc/.svn/dir-props b/doc/.svn/dir-props new file mode 100644 index 0000000..361f890 --- /dev/null +++ b/doc/.svn/dir-props @@ -0,0 +1,47 @@ +K 10 +svn:ignore +V 614 +Makefile +Makefile.in +mdate-sh +missing +rdebug-emacs.aux +rdebug-emacs.cp +rdebug-emacs.cps +rdebug-emacs.fn +rdebug-emacs.fns +rdebug-emacs.html +rdebug-emacs.info +rdebug-emacs.ky +rdebug-emacs.log +rdebug-emacs.pdf +rdebug-emacs.pg +rdebug-emacs.pgs +rdebug-emacs.toc +rdebug-emacs.tp +rdebug-emacs.vr +rdoc +ruby-debug.aux +ruby-debug.cp +ruby-debug.cps +ruby-debug.fn +ruby-debug.fns +ruby-debug.html +ruby-debug.info +ruby-debug.ky +ruby-debug.kys +ruby-debug.log +ruby-debug.pdf +ruby-debug.pg +ruby-debug.pgs +ruby-debug.toc +ruby-debug.tp +ruby-debug.vr +ruby-debug.vrs +stamp-1 +stamp-vti +texinfo.tex +version-rdebug-emacs.texi +version.texi + +END diff --git a/doc/.svn/empty-file b/doc/.svn/empty-file new file mode 100644 index 0000000..e69de29 diff --git a/doc/.svn/entries b/doc/.svn/entries new file mode 100644 index 0000000..d3e5d42 --- /dev/null +++ b/doc/.svn/entries @@ -0,0 +1,113 @@ + + + + + + + + + + + + + + + diff --git a/doc/.svn/format b/doc/.svn/format new file mode 100644 index 0000000..b8626c4 --- /dev/null +++ b/doc/.svn/format @@ -0,0 +1 @@ +4 diff --git a/doc/.svn/prop-base/.cvsignore.svn-base b/doc/.svn/prop-base/.cvsignore.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/doc/.svn/prop-base/.cvsignore.svn-base @@ -0,0 +1 @@ +END diff --git a/doc/.svn/prop-base/Makefile.am.svn-base b/doc/.svn/prop-base/Makefile.am.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/doc/.svn/prop-base/Makefile.am.svn-base @@ -0,0 +1 @@ +END diff --git a/doc/.svn/prop-base/emacs-notes.txt.svn-base b/doc/.svn/prop-base/emacs-notes.txt.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/doc/.svn/prop-base/emacs-notes.txt.svn-base @@ -0,0 +1 @@ +END diff --git a/doc/.svn/prop-base/hanoi.rb.svn-base b/doc/.svn/prop-base/hanoi.rb.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/doc/.svn/prop-base/hanoi.rb.svn-base @@ -0,0 +1 @@ +END diff --git a/doc/.svn/prop-base/primes.rb.svn-base b/doc/.svn/prop-base/primes.rb.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/doc/.svn/prop-base/primes.rb.svn-base @@ -0,0 +1 @@ +END diff --git a/doc/.svn/prop-base/rdebug-emacs.texi.svn-base b/doc/.svn/prop-base/rdebug-emacs.texi.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/doc/.svn/prop-base/rdebug-emacs.texi.svn-base @@ -0,0 +1 @@ +END diff --git a/doc/.svn/prop-base/rdebug.1.svn-base b/doc/.svn/prop-base/rdebug.1.svn-base new file mode 100644 index 0000000..92c8ad7 --- /dev/null +++ b/doc/.svn/prop-base/rdebug.1.svn-base @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 2 +Id +END diff --git a/doc/.svn/prop-base/ruby-debug.texi.svn-base b/doc/.svn/prop-base/ruby-debug.texi.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/doc/.svn/prop-base/ruby-debug.texi.svn-base @@ -0,0 +1 @@ +END diff --git a/doc/.svn/prop-base/test-tri2.rb.svn-base b/doc/.svn/prop-base/test-tri2.rb.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/doc/.svn/prop-base/test-tri2.rb.svn-base @@ -0,0 +1 @@ +END diff --git a/doc/.svn/prop-base/tri3.rb.svn-base b/doc/.svn/prop-base/tri3.rb.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/doc/.svn/prop-base/tri3.rb.svn-base @@ -0,0 +1 @@ +END diff --git a/doc/.svn/prop-base/triangle.rb.svn-base b/doc/.svn/prop-base/triangle.rb.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/doc/.svn/prop-base/triangle.rb.svn-base @@ -0,0 +1 @@ +END diff --git a/doc/.svn/props/.cvsignore.svn-work b/doc/.svn/props/.cvsignore.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/doc/.svn/props/.cvsignore.svn-work @@ -0,0 +1 @@ +END diff --git a/doc/.svn/props/Makefile.am.svn-work b/doc/.svn/props/Makefile.am.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/doc/.svn/props/Makefile.am.svn-work @@ -0,0 +1 @@ +END diff --git a/doc/.svn/props/emacs-notes.txt.svn-work b/doc/.svn/props/emacs-notes.txt.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/doc/.svn/props/emacs-notes.txt.svn-work @@ -0,0 +1 @@ +END diff --git a/doc/.svn/props/hanoi.rb.svn-work b/doc/.svn/props/hanoi.rb.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/doc/.svn/props/hanoi.rb.svn-work @@ -0,0 +1 @@ +END diff --git a/doc/.svn/props/primes.rb.svn-work b/doc/.svn/props/primes.rb.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/doc/.svn/props/primes.rb.svn-work @@ -0,0 +1 @@ +END diff --git a/doc/.svn/props/rdebug-emacs.texi.svn-work b/doc/.svn/props/rdebug-emacs.texi.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/doc/.svn/props/rdebug-emacs.texi.svn-work @@ -0,0 +1 @@ +END diff --git a/doc/.svn/props/rdebug.1.svn-work b/doc/.svn/props/rdebug.1.svn-work new file mode 100644 index 0000000..92c8ad7 --- /dev/null +++ b/doc/.svn/props/rdebug.1.svn-work @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 2 +Id +END diff --git a/doc/.svn/props/ruby-debug.texi.svn-work b/doc/.svn/props/ruby-debug.texi.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/doc/.svn/props/ruby-debug.texi.svn-work @@ -0,0 +1 @@ +END diff --git a/doc/.svn/props/test-tri2.rb.svn-work b/doc/.svn/props/test-tri2.rb.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/doc/.svn/props/test-tri2.rb.svn-work @@ -0,0 +1 @@ +END diff --git a/doc/.svn/props/tri3.rb.svn-work b/doc/.svn/props/tri3.rb.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/doc/.svn/props/tri3.rb.svn-work @@ -0,0 +1 @@ +END diff --git a/doc/.svn/props/triangle.rb.svn-work b/doc/.svn/props/triangle.rb.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/doc/.svn/props/triangle.rb.svn-work @@ -0,0 +1 @@ +END diff --git a/doc/.svn/text-base/.cvsignore.svn-base b/doc/.svn/text-base/.cvsignore.svn-base new file mode 100644 index 0000000..5260245 --- /dev/null +++ b/doc/.svn/text-base/.cvsignore.svn-base @@ -0,0 +1,42 @@ +Makefile +Makefile.in +mdate-sh +missing +rdebug-emacs.aux +rdebug-emacs.cp +rdebug-emacs.cps +rdebug-emacs.fn +rdebug-emacs.fns +rdebug-emacs.html +rdebug-emacs.info +rdebug-emacs.ky +rdebug-emacs.log +rdebug-emacs.pdf +rdebug-emacs.pg +rdebug-emacs.pgs +rdebug-emacs.toc +rdebug-emacs.tp +rdebug-emacs.vr +rdoc +ruby-debug.aux +ruby-debug.cp +ruby-debug.cps +ruby-debug.fn +ruby-debug.fns +ruby-debug.html +ruby-debug.info +ruby-debug.ky +ruby-debug.kys +ruby-debug.log +ruby-debug.pdf +ruby-debug.pg +ruby-debug.pgs +ruby-debug.toc +ruby-debug.tp +ruby-debug.vr +ruby-debug.vrs +stamp-1 +stamp-vti +texinfo.tex +version-rdebug-emacs.texi +version.texi diff --git a/doc/.svn/text-base/Makefile.am.svn-base b/doc/.svn/text-base/Makefile.am.svn-base new file mode 100644 index 0000000..477fc7e --- /dev/null +++ b/doc/.svn/text-base/Makefile.am.svn-base @@ -0,0 +1,63 @@ +############################################################################## +# $Id: Makefile.am,v 1.3 2006/12/28 12:34:25 rockyb Exp $ +# Copyright (C) 2007 Rocky Bernstein +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +############################################################################## + +EXT=1 +man1_MANS = rdebug.$(EXT) + +EXTRA_DIST = $(man1_MANS) \ + hanoi.rb primes.rb test-tri2.rb tri3.rb triangle.rb \ + ruby-debug.info ruby-debug.html ruby-debug.pdf + +info_TEXINFOS = ruby-debug.texi rdebug-emacs.texi + +all: $(INFO_DEPS) $(man1_MANS) html pdf + +pdf: ruby-debug.pdf rdebug-emacs.pdf + +txt: ruby-debug.txt rdebug-emacs.txt + +ps: ruby-debug.ps rdebug-emacs.ps + +man: $(man1_MANS) + +html: ruby-debug.html rdebug-emacs.html + +ruby-debug.html: ruby-debug.texi + texi2html $(srcdir)/ruby-debug.texi || true + +rdebug-emacs.html: rdebug-emacs.texi + texi2html $(srcdir)/rdebug-emacs.texi || true + +%.ps.gz: %.ps + gzip -9c $< > $@ + +# Our `texinfo.tex' must reside in the current directory, otherwise +# texi2dvi will use the default. +.texi.pdf: + $(TEXI2PDF) -I $(srcdir) $< + +.texi.dvi: + $(TEXI2DVI) -I $(srcdir) $< + +.dvi.ps: + test -d $(docdir) || mkdir $(docdir) + $(DVIPS) $< -o $@ + +all-formats: pdf dvi txt ps html + +MOSTLYCLEANFILES = rubydb.tgs rubydb.ps.gz rubydb.pdf rubydb.html rubydb_toc.html rubydb_foot.html rubydb-man.html diff --git a/doc/.svn/text-base/emacs-notes.txt.svn-base b/doc/.svn/text-base/emacs-notes.txt.svn-base new file mode 100644 index 0000000..4568791 --- /dev/null +++ b/doc/.svn/text-base/emacs-notes.txt.svn-base @@ -0,0 +1,38 @@ +* rdebug.el is loaded by the user when Emacs is launched. (Should +Rdebug ever be part of Emacs, this should be the items autoloaded by +Emacs.) + +There is a command buffer which is the gud process. There are a number +of "secondary" buffers have in gud-comint-buffer the gud process. The +way we go the other direction from gud process to secondary buffer is +by buffer name. Source buffers don't seem to have a local +gud-comint-buffer variable set but use the global value. Perhaps +source buffer should have their own buffer-local value(s)? + +For each secondary buffer we have things for that specific buffer. In particular: +* frames (rdebug-frames.el) +* output (rdebug-output.el) +* variables (rdebug-varbuf.el) +* watch or display-expressions - (rdebug-watch.el +* breakpoints (rdebug-breaks.el) + +Each specific secondary buffer includes + - setting the buffer up, + - specific commands for that buffer + - the kinds of functions that buffer deals with (e.g. frame + things for the "frame" buffer or breakpoints for the "breakpoints" buffer.) + +* rdebug-gud.el contains things that interface to gdb. Possibly also +things that interface to gdb-ui should be there as well. + +* rdebug-shortkey.el has all the magic that needs to be done to make + shortkey mode work. + +* rdebug-track is all the things to make rdebug-track mode work. + +I have some additions, which deals with *when* certain files are loaded. + +* rdebug-source.el is loaded when the first Ruby source file is loaded +Of course, the name rdebug-source.el is not important, we could rename +it to something else and reuse the name for other source-related +things. diff --git a/doc/.svn/text-base/hanoi.rb.svn-base b/doc/.svn/text-base/hanoi.rb.svn-base new file mode 100644 index 0000000..99c4c10 --- /dev/null +++ b/doc/.svn/text-base/hanoi.rb.svn-base @@ -0,0 +1,35 @@ +#!/usr/bin/ruby + +def hanoi(n,a,b,c) + if n-1 > 0 + hanoi(n-1, a, c, b) + end + puts "Move disk %s to %s" % [a, b] + if n-1 > 0 + hanoi(n-1, c, b, a) + end +end + +i_args=ARGV.length +if i_args > 1 + puts "*** Need number of disks or no parameter" + exit 1 +end + +n=3 + +if i_args > 0 + begin + n = ARGV[0].to_i + rescue ValueError, msg: + print "** Expecting an integer, got: %s" % ARGV[0].to_s + exit 2 + end +end + +if n < 1 or n > 100 + puts "*** number of disks should be between 1 and 100" + exit 2 +end + +hanoi(n, :a, :b, :c) diff --git a/doc/.svn/text-base/primes.rb.svn-base b/doc/.svn/text-base/primes.rb.svn-base new file mode 100644 index 0000000..e94219c --- /dev/null +++ b/doc/.svn/text-base/primes.rb.svn-base @@ -0,0 +1,28 @@ +#!/usr/bin/env ruby +# Enumerator for primes +class SievePrime + @@odd_primes = [] + def self.next_prime(&block) + candidate = 2 + yield candidate + not_prime = false + candidate += 1 + while true do + @@odd_primes.each do |p| + not_prime = (0 == (candidate % p)) + break if not_prime + end + unless not_prime + @@odd_primes << candidate + yield candidate + end + candidate += 2 + end + end +end +SievePrime.next_prime do |prime| + puts prime + break if prime > 10 +end + + diff --git a/doc/.svn/text-base/rdebug-emacs.texi.svn-base b/doc/.svn/text-base/rdebug-emacs.texi.svn-base new file mode 100644 index 0000000..89a5cab --- /dev/null +++ b/doc/.svn/text-base/rdebug-emacs.texi.svn-base @@ -0,0 +1,1030 @@ +\input texinfo @c -*-texinfo-*- +@setfilename rdebug-emacs.info + +@set DBG ruby-debug +@set ttrdebug @code{rdebug} +@set ttDBG @code{@value{DBG}} +@set Emacs @sc{gnu} Emacs + +@set RDEBUG_EMACS_VERSION 0.1 +@include version-rdebug-emacs.texi +@finalout + +@c Karl Berry informs me that this will add straight quotes in +@c typewriter text. +@c See the "Inserting Quote Characters" node in the Texinfo manual +@set txicodequoteundirected +@set txicodequotebacktick + +@c THIS MANUAL REQUIRES TEXINFO 4.0 OR LATER. + +@c This is a dir.info fragment to support semi-automated addition of +@c manuals to an info tree. +@dircategory Programming & development tools. +@direntry +* ruby-debug-emacs: (ruby-debug). Ruby Debugger for GNU Emacs +@end direntry + +@titlepage +@title Debugging with @code{ruby-debug} inside GNU Emacs Version @value{RDEBUG_EMACS_VERSION} +@sp 1 +@subtitle @value{EDITION} Edition +@subtitle @value{UPDATED-MONTH} +@author Rocky Bernstein and Anders Lindgren +@page +@ifset WHERETO +@tex +{\parskip=0pt +\hfill (Send bugs and comments on ruby-debug to fill in...)\par +\hfill {\it Debugging with {\tt ruby-debug}\par +\hfill \TeX{}info \texinfoversion\par +} +@end tex +@end ifset +@end titlepage +@page + +@node Top, Getting started, (dir), (dir) +@top Debugging with ruby-debug under GNU Emacs + +@menu +* Getting started:: +* The Multi-window Mode:: +* Debugger Buffers:: +* Emacs Debugger Commands:: Indexes (nodes containing large menus) +* Emacs Command Index:: An item for each GNU/Emacs command name. +* Emacs Function Index:: An item for each Emacs Function. +* Emacs Key Binding Index:: An item for each Emacs Debugger Command. + +@detailmenu + --- The Detailed Node Listing --- + +Getting started + +* Installation:: How to install this package +* Emacs rdebug:: Invoke the ruby debugger initially +* Emacs shell tracking mode:: Entering rdebug from an existing shell buffer + +Debugger Buffers + +* Debugger Command Buffer:: +* Emacs Source:: Commands from the source script + +Emacs Debugger Commands + +* Emacs Debugger Common Commands:: +* Emacs Debugger Breakpoint Buffer Commands:: +* Emacs Debugger Stack Buffer Commands:: +* Emacs Debugger Variable Buffer Commands:: +* Emacs Debugger Watch Buffer Commands:: +* Emacs GUD Commands:: + +@end detailmenu +@end menu + +This file describes ruby-debug, the Ruby Debugger, +version @value{RDEBUG_EMACS_VERSION} + +This is the @value{EDITION} Edition, @value{UPDATED} +@c Copyright (C) 2007 ... + +@c @node GNU Emacs +@c @chapter Using @code{ruby-debug} from GNU Emacs + + +@cindex @value{Emacs} +A special interface which comes with Ruby that allows you to use +@value{Emacs} to view (and edit) the source files for the program you +are debugging with @value{DBG}. However you must be using at least +version 21 of @value{Emacs}, but with @value{Emacs} version 22 or 23 +there are even more debugging features available. @code{M-x +show-emacs-version} inside @value{Emacs} will tell you what version you +are running. + +This package provide a full-fledged debugging environment, on par with +modern integrated development environments. Once the debugger has been +activated, the Emacs frame is divided into a number of dedicated +debugger windows.@footnote{If you are an @value{Emacs} traditionalist, +you can, of course, run this package with only a shell and source +buffer} + +This package comes with a number of predefined window layouts. It is +fully customizable so you can create your own. + +@c ------------------------------------------------------------------- + + +@node Getting started, The Multi-window Mode, Top, Top +@chapter Getting started + +@menu +* Installation:: How to install this package +* Emacs rdebug:: Invoke the ruby debugger initially +* Emacs shell tracking mode:: Entering rdebug from an existing shell buffer +* Configurating this package:: Introducing the configure system +@end menu + +@node Installation, Emacs rdebug, Getting started, Getting started +@section Installation + +To use this interface, load the file @code{rdebug.el}. This file is a +light-weight file, basically it only contains a handful of +@code{autoload} directives. + +For example, you can place the following in your @code{~/.emacs} file: + +@smallexample + (require 'rdebug) +@end smallexample + +In addition, you must have Ruby and ruby-debug installed. + + +@node Emacs rdebug, Emacs shell tracking mode, Installation, Getting started +@section Emacs rdebug + +Use the command @kbd{M-x rdebug} in @sc{gnu} Emacs to start debugging. +Give the executable file you want to debug as an argument. Make sure +to use the version that comes with this package as this is newer than +that supplied with @value{Emacs}. + +The @kbd{rdebug} command starts @value{DBG} as a subprocess of Emacs, +with input and output through a newly created Emacs buffer. + +Using @value{DBG} under Emacs is just like using @value{DBG} +normally except for two things: + +@itemize @bullet +@item +All ``terminal'' input and output goes through the GNU Emacs buffer. +@end itemize + +This applies both to @value{DBG} commands and their output, and to the input +and output done by the program you are debugging. + +This is useful because it means that you can copy the text of previous +commands and input them again; you can even use parts of the output +in this way. + +All the facilities of GNU Emacs' Shell mode are available for interacting +with your script. In particular, you can send signals the usual +way---for example, @kbd{C-c C-c} for an interrupt, @kbd{C-c C-z} for a +stop. + +@node Emacs shell tracking mode, Configurating this package, Emacs rdebug, Getting started +@section Entering rdebug from an existing shell buffer + +Many times it's not feasible to enter the debugger from the outset. +Instead a call to the debugger is put inside the program. + +@c See @xref{Unit Testing Session}. + +It is also possible in GNU emacs to use a (``comint'') shell and set a +mode to watch for @value{DBG} prompts and track the source code in +another window. @xref{Interactive Shell, , Shell, Emacs, The @value{Emacs} +Manual}. + +To enable, this run @kbd{M-x turn-on-rdebug-track-mode}. There is some +overhead involved in scanning output, so if you are not debugging Ruby +programs you probably want to turn this off which can be done via the +@code{M-x turn-off-rdebugtrack} command. + + +@node Configurating this package, , Emacs shell tracking mode, Getting started +@section Configurating this package + +In this manual we present a number of @value{Emacs} lisp variables and +functions that you can use to configure the debugger interface. In +addition, you can use the @value{Emacs} @emph{customize} system, see the +@kbd{ } menu item. + +@c ------------------------------------------------------------------- + +@node The Multi-window Mode, Debugger Buffers, Getting started, Top +@chapter Multi-window + +In the multi-window debugger mode, a number of buffers are visible when +the debugger starts. This chapter will describe each of them, in +addition it will describe the features associated with the multi-window +mode. + +The default multi-window layout looks like the following: + +@verbatim ++----------------------------------------------------------------------+ +| Toolbar | ++-----------------------------------+----------------------------------+ +| | | +| Debugger shell | Variables buffer | +| | | ++-----------------------------------+----------------------------------+ +| | | +| Source buffer | Output buffer | +| | | ++-----------------------------------+----------------------------------+ +| | | +| Stack buffer | Breakpoints buffer | +| | | ++-----------------------------------+----------------------------------+ +@end verbatim + +@section Activating Multi-window mode + +The variable @code{rdebug-many-windows} controls if multi-window mode +should be used, it is enabled by default. When starting the debugger +using the @code{M-x rdebug} mode the command line option @code{--emacs +3} must be specified (this is also the default). + +When attaching to an already running debugger process, you must give the +debugger command @kbd{set annotate 3}. + +@section Window Layouts + +When the debugger is started, the original window layout of +@value{Emacs} is replaced with the window layout of the debugger. You +can switch back and forth between the original window layout and the +debugger layout using +@kbd{M-x rdebug-display-original-window-configuration} and +@kbd{M-x rdebug-display-debugger-window-configuration}. + +If, for some reason, the debugger layout has been garbled you can +restore it to the original state using @kbd{M-x +rdebug-restore-debugger-window-layout}. + +The debugger provides a number of different window layouts. The easies +way to try them out is to use the menu @kbd{ +} and select any in the section starting with @code{Standard}. + + +@section The buffers + +All buffers in this section share a set of commands for common debugger +operations and for switching between buffers. In addition, each buffer +has got a set of dedicated commands. + +All debugger buffers, with the exception of source and the debugger +shell window, are called @emph{secondary buffers}. + +@subsection Keybindings for all Debugger Windows + +The debugger provides key-bindings that work in all debugger windows, +including Ruby source buffers. The key bindings are designed to match +keys of commonly used debugger environments. + +The variable @code{rdebug-populate-common-keys-function} can be assigned +to a function that should bind the keys use. Three functions are +provided @code{rdebug-populate-common-keys-standard}, +@code{...-eclipse}, and @code{...-netbeans}. + +@multitable @columnfractions 0.4 0.2 0.2 0.2 +@headitem Command @tab Standard @tab Eclipse @tab Netbeans +@item Run @tab f5 @tab @tab +@item Quit @tab S-f5 @tab @tab +@item Toggle Breakpoint @tab f9 @tab @tab +@item Enable/Disable Breakpoint @tab C-f9 @tab S-C-b @tab S-f8 +@item Step over @tab f10 @tab f6 @tab f8 +@item Step into @tab f11 @tab f5 @tab f7 +@item Step out @tab S-f11 @tab f7 @tab M-S-f7 + +@end multitable + + + +@subsection Keybindings for Secondary Buffers + +The following commands are available in all secondary windows. + +Capital letters move between secondary buffers as mentioned above (jump +to if visible or replace a secondary if not). + +@table @kbd +@item SPACE +step (edebug compatible) +@item < +Up in the stack trace +@item > +Down in the stack trace +@item ? +Help +@item B +Display breakpoints buffer +@item C +Display command buffer +@item O +Display program output +@item S +Display source window +@item T +Display stack trace buffer +@item V +display variables buffer +@item W +display watch buffer +@item b +Set breakpoint +@item c +Continue (i.e. run) +@item d +Remove breakpoint +@item f +Finish (i.e. step out of the current function) +@item n +Next (i.e. step into function) +@item p +print +@item q +Quit +@item r +Restart +@item s +Step (i.e. step over function) +@end table + +You can use the same commands in the source buffer if you enable +@code{rdebug-short-key-mode}. The best way to do this is to add the +following to your init file: + +@smallexample + (add-hook 'rdebug-mode-hook 'rdebug-turn-on-short-key-mode) +@end smallexample + + + +@subsection The Debugger Shell Buffer + +The @emph{debugger shell window} is the main communication channel +between @value{DBG} and @value{Emacs}. You can use the shell to issue +debugger commands directly. In addition, any @value{Emacs} debugger +command you issue will be translated into shell commands, and the output +will be parsed. + +It is the ambition that the @value{Emacs} debugger interface should be +in a state where the debugger shell window would not need to be visible. + +@subsection The Source Buffer + +The @emph{source buffers} (or buffers) contains the actual Ruby source +code that is being debugged. A small arrow in the left fringe displays +the current line. Active breakpoints are displayed as red dots and +passive as grey. + +@subsection The Output Buffer + +The @emph{output buffer} displays any output the debugged program emits. + +The option @code{rdebug-use-separate-io-buffer} controls if the output +buffer should be used, or if the output would go into the debugger shell +buffer. + +@subsection The Variables Buffer + +In this buffer, local and object variables are displayed. The values of +the variables can be edited. + +@table @kbd +@item RET +Edit the value +@item e +Print the value +@item x +Pretty-print the value +@end table + +@subsection The Stack Trace Buffer + +The @emph{stack trace} buffer displays the function that is currently +being debugger, the function that called it, etc., all the way up to the +originally called function. + +You can navigate in the stack trace buffer in order to see the source of +any function in the call chain. The Variables buffer will also be +updated to reflect the local variables of that function. + +@table @kbd +@item RET +Select a function to display +@item +Go to a stack frame +@end table + +@subsection The Watch Buffer + +The @emph{Watch Buffer} can display arbitrary expressions, including, +but not limited to, global variables. + +@table @kbd +@item a +Add a watch expression +@item C-d, d +Delete a watch expression +@item RET, e +Edit a watch expression +@item +Go to the expression +@end table + +@subsection The Breakpoints Buffer + +The @emph{Breakpoints Buffer} displays all breakpoints that currently are +defined and shows if they are enabled or disabled. + +@table @kbd +@item t +Toggle a breakpoint between enabled and disabled +@item i +Add a breakpoint condition +@item ret +Goto a breakpoint +@item C-d +Delete a breakpoint +@item +Go to the expression +@end table + +@subsection The Help Buffer + +The @emph{Help Buffer} is displayed whenever you press @code{?}. It will +display a help text on the available debugger commands and commands to +navigate between the buffers. + + +@c ------------------------------------------------------------------- + +@node Debugger Buffers, Emacs Debugger Commands, The Multi-window Mode, Top +@chapter Debugger Buffers + +@menu +* Debugger Command Buffer:: +* Emacs Source:: Commands from the source script +@end menu + +@node Debugger Command Buffer, Emacs Source, Debugger Buffers, Debugger Buffers +@section Emacs Debugger Command buffer + +Each time @value{DBG} displays a stack frame, Emacs automatically finds the +source file for that frame and puts an arrow (@samp{=>}) at the +left margin of the current line. Emacs uses a separate buffer for +source display, and splits the screen to show both your @value{DBG} session +and the source. + +Explicit @value{DBG} @code{list} or search commands still produce output as +usual, but you probably have no reason to use them from GNU Emacs. + +@quotation +@emph{Warning:} If the directory where your script resides is not your +current directory, it can be easy to confuse Emacs about the location of +the source files, in which case the auxiliary display buffer does not +appear to show your source. @value{DBG} can find programs by searching your +environment's @code{PATH} variable, so the @value{DBG} input and output +session proceeds normally; but Emacs does not get enough information +back from @value{DBG} to locate the source files in this situation. To +avoid this problem, either start @value{DBG} mode from the directory where +your script resides, or specify an absolute file name when prompted for the +@kbd{M-x gdb} argument. + +A similar confusion can result if you use the @value{DBG} @code{file} command to +switch to debugging a program in some other location, from an existing +@value{DBG} buffer in Emacs. +@end quotation + +@noindent +(preceded by @kbd{M-:} or @kbd{ESC :}, or typed in the @code{*scratch*} buffer, or +in your @file{.emacs} file). + +In the @value{DBG} I/O buffer, you can use the Emacs commands listed +below in addition to the standard Shell mode commands. The I/O buffer +name name is usually @code{*gud-}@emph{script-name}@code{*}, where +@emph{script-name} is the name of the script you are debugging. + +Many of the commands listed below are also bound to a second key +sequence which also can be used in the also be used in the source +script. These are listed in @ref{Emacs Source}. + +In secondary buffers many commands are available the corresponding +final keystroke. For example @code{C-c n} in a secondary buffer is +@code{n}. + +@table @kbd +@item C-h m +Describe the features of Emacs' @value{DBG} Mode. + +@item C-x C-a C-b (gud-break) +@pindex C-x C-a C-b (gud-break) +Set breakpoint at current line. + +@item C-x C-a C-d (gud-remove) +@pindex C-x C-a C-d (gud-remove) +Remove breakpoint at current line. + +@item C-x C-a C-l (gud-refresh) +@pindex C-x C-a C-d (gud-refresh) +Fix up a possibly garbled display, and redraw the arrow. + +@item C-c RET (comint-copy-old-input) +@pindex C-c RET (comint-copy-old-input) +Insert after prompt old input at point as new input to be edited. +Calls `comint-get-old-input' to get old input. + +@item C-c n (gud-next) +@pindex C-c n (gud-next) +Step one line, skipping functions. (Step over). + +@item C-x C-a C-o (comint-delete-output) +@pindex C-c n (comint-delete-output) +Delete all output from interpreter since last input. Does not delete +the prompt. + +@item C-x C-a C-r (gud-cont) + +@item C-c SPC (gud-step @var{arg}) +@pindex C-c SPC (gud-step @var{arg}) +@itemx C-x C-a C-s (gud-step @var{arg}) +@pindex C-x C-a C-s (gud-step @var{arg}) +Step one source line. Same as @value{DBG} @code{step} command. The +@value{Emacs} command name is @code{gud-step} and @code{C-x C-a C-s} +is an alternate binding which can be used in the source +script. +@c @xref{Step}. + +With a numeric argument, run that many times. +@xref{Arguments, , Numeric Arguments, Emacs, The @value{Emacs} +Manual}. + + +@item C-x C-a C-t (gud-tbreak @var{arg}) +Set temporary breakpoint at current line. + +@item C-x C-a C-w (backward-kill-word) +@item C-x C-a C-x (comint-get-next-from-history) +@item C-x C-a C-z (comint-stop-subjob) +Stop the current subjob. +This command also kills the pending input +between the process mark and point. + +WARNING: if there is no current subjob, you can end up suspending +the top-level process running in the buffer. If you accidentally do +this, use M-x comint-continue-subjob to resume the process. (This +is not a problem with most shells, since they ignore this signal.) + +@item C-x C-a C-\ (comint-quit-subjob) +Send quit signal to the current subjob. +This command also kills the pending input +between the process mark and point. + +@item C-c + (gud-step-plus) +Run @code{step+}. + +@item C-c . (comint-insert-previous-argument @var{index}) +Insert the @emph{index-th} argument from the previous Comint command-line at point. +Spaces are added at beginning and/or end of the inserted string if +necessary to ensure that it's separated from adjacent arguments. +Interactively, if no prefix argument is given, the last argument is inserted. +Repeated interactive invocations will cycle through the same argument +from progressively earlier commands (using the value of index specified +with the first command). + +@item C-c < (gud-up) +Go up a stack frame. With a numeric argument, go up that many +stack frames. Same @value{DBG} @code{up} command. +@xref{Arguments, , Numeric Arguments, Emacs, The @value{Emacs} +Manual}. + +@item C-c > (gud-down) +Go down a stack frame. Same as @value{DBG} @code{down}. +With a numeric argument, go down that many stack frames. +@xref{Arguments, , Numeric Arguments, Emacs, The @value{Emacs} +Manual}. + +@item C-c ? (rdebug-display-secondary-window-help-buffer) +Display the rdebug help buffer. + +@item C-c B (rdebug-display-breakpoints-buffer) +Display the rdebug breakpoints buffer. + +@item C-x C-a C (rdebug-display-cmd-buffer) +Display the rdebug command buffer. + +@item C-c O (rdebug-display-output-buffer) +Display the rdebug output buffer. + +@item C-c R (gud-run) +@itemx C-c r (gud run) +Restart or run the script. Same as @value{DBG} @code{run} command. + +@item C-c S (gud-source-resync) +@item C-c T (rdebug-display-stack-buffer) +Display the rdebug stack buffer. +@item C-c V (rdebug-display-variables-buffer) +Display the rdebug variables buffer. + +@item C-c W (rdebug-display-watch-buffer) +Display the rdebug watch buffer. + +@item C-c f (gud-finish @var{arg}) +@pindex C-c f (gud-finish @var{arg}) +Finish executing current function. + +@itemx C-x C-a C-f (gud-finish) +@pindex C-x C-a C-f (gud-finish) +Finish executing current function. The same as @value{DBG} +@code{finish} command. +@c @xref{Finish}. + +@item C-c n (gud-next) +@pindex C-c n (gud-next) +Execute to next source line in this function, skipping all function +calls. Same as @value{DBG} @code{next} command. +@c @xref{Next}. + +With a numeric argument, run that many times. +@c @xref{Arguments, , Numeric Arguments, Emacs, The @value{Emacs} Manual}. + +@item C-c q (gud-quit) + +@item C-x C-a C-l +Resynchronize the current position with the source window. The +@value{Emacs} command name is @code{gud-refresh} and @code{C-x C-a +C-l} is an alternate binding which also can be used in the source script. + +@item C-c a +Shows argument variables (e.g.@: @code{$1}, @code{$2}) of the current +stack frame. Same as @value{DBG} @code{info args} command. The +@value{Emacs} command name is @code{gud-args} and @code{C-x C-a a} is +an alternate binding which also can be used in the source script. + +@item C-c T +Show stack trace. Same as @value{DBG} @code{where} command. The +@value{Emacs} command name is @code{gud-where} and @code{C-x C-a T} is +an alternate binding which can be used in the source +script. +@c @xref{Backtrace}. + +@end table + +In any source file, the Emacs command @kbd{C-x SPC} (@code{gud-break}) +tells @value{DBG} to set a breakpoint on the source line point is on. + +If you accidentally delete the source-display buffer, an easy way to get +it back is to type the command @code{frame} in the @value{DBG} buffer, to +request a frame display; when you run under Emacs, this recreates +the source buffer if necessary to show you the context of the current +frame. + +The source files displayed in Emacs are in ordinary Emacs buffers +which are visiting the source files in the usual way. You can edit +the files with these buffers if you wish; but keep in mind that @value{DBG} +communicates with Emacs in terms of line numbers. If you add or +delete lines from the text, the line numbers that @value{DBG} knows cease +to correspond properly with the code. + +@xref{Debugger Operation, , , Emacs, The @value{Emacs} +Manual}. + +@node Emacs Source, , Debugger Command Buffer, Debugger Buffers +@section Commands from the source script + +@table @kbd +@item C-x SPC + +tells @value{DBG} to set a breakpoint on the source +line point is on. (@code{gud-break}) + +@item C-x C-a t + +@code{gud-linetrace} + +@item C-x C-a C-f +Restart or run the script. Same as @value{DBG} @code{run} command. The +@value{Emacs} command name is @code{gud-finish}. In the corresponding +I/O buffer, @code{C-c R} is an alternate binding. + +@item C-x C-a T +Show stack trace. Same as @value{DBG} @code{where} command. In the +corresponding I/O buffer, @code{C-c T} is an alternate +binding. +@c @xref{Backtrace}. + +@item C-x C-a < + +Go up a stack frame. With a numeric argument, go up that many +stack frames. Same @value{DBG} @code{up} command. +@xref{Arguments, , Numeric Arguments, Emacs, The @value{Emacs} Manual}. + +The @value{Emacs} command name is @code{gud-up}. In the corresponding +I/O buffer, @code{C-c <} is an alternate binding. + +@item C-x C-a > + +Go down a stack frame. Same as @value{DBG} @code{down}. +With a numeric argument, go down that many stack frames. +@xref{Arguments, , Numeric Arguments, Emacs, The @value{Emacs} +Manual}. + +The @value{Emacs} command name is @code{gud-down}. In the +corresponding I/O buffer, @code{C-c >} is an alternate binding. + +@item C-x C-a C-t + +@code{gud-tbreak} + +@item C-x C-a C-s + +Step one source line. Same as @value{DBG} @code{step} +command. +@c @xref{Step}. + +With a numeric argument, run that many times. +@xref{Arguments, , Numeric Arguments, Emacs, The @value{Emacs} +Manual}. + +The @value{Emacs} command name is @code{gud-step}. In the +corresponding I/O buffer, @code{C-x C-a C-s} is an alternate binding. + +@item C-x C-a C-e + +@code{gud-statement} + +@item C-x C-a R +Restart or run the script. Same as @value{DBG} @code{run} command. The +@value{Emacs} command name is @code{gud-run}. In the corresponding I/O +buffer, @code{C-c R} is an alternate binding. + +@item C-x C-a C-d +Delete breakpoint. @code{gud-remove} + +@item C-x C-a C-p + +@code{gud-print} + +@item C-x C-a C-n + +Execute to next source line in this function, skipping all function +calls. Same as @value{DBG} @code{next} command. With a numeric +argument, run that many times. @xref{Arguments, , Numeric Arguments, +Emacs, The @value{Emacs} Manual}. + +The @value{Emacs} command name is @code{gud-next}. In the +corresponding I/O buffer, @code{C-x C-a C-n} is an alternate binding. + +@item C-x C-a f C-f + +@code{gud-finish} + +@item C-x C-a C-r +Continue execution of your script Same as @value{DBG} @code{continue} +command. The @value{Emacs} command name is @code{gud-cont}. In the +corresponding I/O buffer, @code{C-x C-a C-r} is an alternate binding. +@c See @ref{Continue}. + +@item C-x C-a C-b + +@code{gud-break} + +@item C-x C-a a + +@code{gud-args} +Shows argument variables (e.g.@: @code{$1}, @code{$2}) of the current +stack frame. Same as @value{DBG} @code{info args} command. The +@value{Emacs} command name is @code{gud-args}. In the corresponding +I/O buffer, @code{C-c a} is an alternate binding which also can be +used in the source script. + +@item C-x C-a C-l +Move to current position in this source window. The @value{Emacs} +command name is @code{gud-refresh}. In the corresponding I/O buffer, +@code{C-x C-a C-l} is an alternate binding. + +@end table + +@node Emacs Debugger Commands, Emacs Command Index, Debugger Buffers, Top +@chapter Emacs Debugger Commands + +@menu +* Emacs Debugger Common Commands:: +* Emacs Debugger Breakpoint Buffer Commands:: +* Emacs Debugger Stack Buffer Commands:: +* Emacs Debugger Variable Buffer Commands:: +* Emacs Debugger Watch Buffer Commands:: +* Emacs GUD Commands:: +@end menu + +@node Emacs Debugger Common Commands, Emacs Debugger Breakpoint Buffer Commands, Emacs Debugger Commands, Emacs Debugger Commands +@section Emacs Debugger Common Commands + +The commands in this section are used to make a secondary buffer +visible. If the buffer doesn't exist, nothing is done. +The way the buffer is made visible is follows the following +rules tried in order: + +@enumerate +@item +If the buffer doesn't exist, do nothing. +@item +If the buffer is already displayed, switch to it. +@item +If the current buffer is a +secondary buffer, bury it replacing with the requested +buffer. +@item +If there is secondary buffer visible, that +is replaced instead. +@item +Just pick a visible buffer to bury and replace. + @end enumerate + +The commands are also have key bindings that end in an uppercase +letter. This letter is given in parenthesis. When in one of the +secondary buffers, the uppercase letter is bound to the command as well. + +@table @kbd + +@item (rdebug-display-breakpoints-buffer) (@kbd{B}) +@findex rdebug-display-breakpoints-buffer (@kbd{B}) +Display the rdebug breakpoints buffer. Bound to: @kbd{C-x C-a B}, +@kbd{ }. Secondary buffers: +@kbd{O}. + +@item (rdebug-display-cmd-buffer) (@kbd{C}) +@findex rdebug-display-cmd-buffer (@kbd{C}) +Display the debugger command buffer. + +Bound to: @kbd{C-x C-a C}, @kbd{ }. + +@item (rdebug-display-output-buffer) (@kbd{O}) +@findex rdebug-display-output-buffer (@kbd{?}) +Display the debugger output buffer. + +Bound to: @kbd{C-x C-a O}, @kbd{ +}. Secondary buffers: @kbd{O}. + +@item (rdebug-display-secondary-window-help-buffer) (@kbd{?}) +@findex rdebug-display-secondary-window-help-buffer (@kbd{?}) + +@item (rdebug-display-stack-buffer) (@kbd{T}) +@findex rdebug-display-stack-buffer (@kbd{T}) +Display the debugger stack buffer. Bound to: @kbd{C-x C-a T}, +@kbd{ }. Secondary buffers: @kbd{T}. + +@item (rdebug-display-variables-buffer) (@kbd{V}) +@findex rdebug-display-variables-buffer (@kbd{V}) +Display the debugger variables buffer. Bound to: @kbd{C-x C-a V}, +@kbd{ }. Secondary buffers: +@kbd{V}. + +@item (rdebug-display-watch-buffer) (@kbd{W}) +@findex rdebug-display-watch-buffer (@kbd{W}) +Display the debugger variables buffer. Bound to: @kbd{C-x C-a W}, +@kbd{ }. Secondary buffers: @kbd{V}. + +@item (rdebug-display-debugger-window-configuration) +@findex rdebug-display-debugger-window-configuration +Display the current layout of windows of the rdebug Ruby debugger. +@item (rdebug-display-original-window-configuration) +@findex rdebug-display-original-window-configuration +Display the layout of windows prior to starting the rdebug Ruby +debugger. This function is called upon quitting the debugger and +@var{rdebug-many-windows} is not nil. +@item (rdebug-goto-entry-n) +@findex rdebug-goto-entry-n +Breakpoints, Display expressions and Stack Frames all have +numbers associated with them which are distinct from line +numbers. In a secondary buffer, this function is usually bound to +a numeric key. which will position you at that entry number. To +go to an entry above 9, just keep entering the number. For +example, if you press 1 and then 9, you should jump to entry +1 (if it exists) and then 19 (if that exists). Entering any +non-digit will start entry number from the beginning again. +@item (rdebug-quit) - q +@findex rdebug-quit (q) +Kill the debugger process associated with the buffer. + +When @var{rdebug-many-windows} is active, the original window layout is +restored. +@item (rdebug-restore-windows) +@findex rdebug-restore-windows +Display the initial ruby debugger window layout. + +@end table + + +@node Emacs Debugger Breakpoint Buffer Commands, Emacs Debugger Stack Buffer Commands, Emacs Debugger Common Commands, Emacs Debugger Commands +@section Emacs Debugger Breakpoint Buffer Commands + +@table @kbd +@item (rdebug-goto-breakpoint) +@findex rdebug-goto-breakpoint +@item (rdebug-goto-breakpoint-mouse) +@findex rdebug-goto-breakpoint-mouse +@item (rdebug-breakpoints-mode) +@findex rdebug-breakpoints-mode +Major mode for displaying breakpoints in a secondary window. Uses +@var{rdebug-breakpoints-mode-map}. +@end table + +@node Emacs Debugger Stack Buffer Commands, Emacs Debugger Variable Buffer Commands, Emacs Debugger Breakpoint Buffer Commands, Emacs Debugger Commands +@section Emacs Debugger Stack Buffer Commands + +@table @kbd +@item (rdebug-goto-stack-frame) +@findex rdebug-goto-stack-frame +@item (rdebug-frames-mode) +@findex rdebug-frames-mode +Major mode for displaying the stack trace. Uses +@var{rdebug-frames-mode-map}. +@end table + +@node Emacs Debugger Variable Buffer Commands, Emacs Debugger Watch Buffer Commands, Emacs Debugger Stack Buffer Commands, Emacs Debugger Commands +@section Emacs Debugger Variable Buffer Commands + +@table @kbd +@item (rdebug-variables-edit) +@findex rdebug-variables-edit +@end table + +@node Emacs Debugger Watch Buffer Commands, Emacs GUD Commands, Emacs Debugger Variable Buffer Commands, Emacs Debugger Commands +@section Emacs Debugger Watch Buffer Commands + +@table @kbd +@item (rdebug-watch-add) +@findex rdebug-watch-add +Add a display expression. +@item (rdebug-watch-delete) +@findex rdebug-watch-delete +Delete a display expression. +@item (rdebug-watch-edit) +@findex rdebug-watch-edit +Edit a display expression. +@item (rdebug-watch-mode) +@findex rdebug-watch-mode +Major mode for displaying the display expressions. Uses +@var{rdebug-watch-mode-map}. +@end table + +@node Emacs GUD Commands, , Emacs Debugger Watch Buffer Commands, Emacs Debugger Commands +@section Emacs Debugger GUD Commands + +@table @kbd +@item (comint-copy-old-input) +@findex comint-copy-old-input +Insert after prompt old input at point as new input to be edited. +Calls `comint-get-old-input' to get old input. +@item (comint-delete-output) +@findex comint-delete-output +Delete all output from interpreter since last input. +Does not delete the prompt. +@item (gud-break) +@findex gud-break +Set a breakpoint on the source line point is on. +@item (gud-cont) - c +@findex gud-cont (c) +Continue execution. +@item (gud-next) - n +@findex gud-next (n) +Step one line, skipping functions. (Step over). +@item (gud-refresh) +@findex gud-refresh +Fix up a possibly garbled display, and redraw the arrow. +@item (gud-remove) +@findex gud-remove +Remove breakpoint at current line. +@item (gud-step) - s +@findex gud-step (s) +Step one statement. (Step into) +@item (gud-step-plus) - + +@findex gud-step-plus (+) +Run @code{step+}---like @code{gud-step} but ensure we go to a new +line. +@item (gud-tbreak @var{arg}) +@findex gud-tbreak +Set temporary breakpoint at current line. +@end table + +@node Emacs Command Index, Emacs Function Index, Emacs Debugger Commands, Top +@unnumbered Emacs Command Index +@printindex pg + +@node Emacs Function Index, Emacs Key Binding Index, Emacs Command Index, Top +@unnumbered Emacs Function Index +@printindex fn + +@node Emacs Key Binding Index, , Emacs Function Index, Top +@unnumbered Key Binding Index +@printindex ky + +@tex +% I think something like @colophon should be in texinfo. In the +% meantime: +\long\def\colophon{\hbox to0pt{}\vfill +\centerline{The body of this manual is set in} +\centerline{\fontname\tenrm,} +\centerline{with headings in {\bf\fontname\tenbf}} +\centerline{and examples in {\tt\fontname\tentt}.} +\centerline{{\it\fontname\tenit\/},} +\centerline{{\bf\fontname\tenbf}, and} +\centerline{{\sl\fontname\tensl\/}} +\centerline{are used for emphasis.}\vfill} +\page\colophon +% Blame: doc@cygnus.com, 1991. +@end tex + +@bye diff --git a/doc/.svn/text-base/rdebug.1.svn-base b/doc/.svn/text-base/rdebug.1.svn-base new file mode 100644 index 0000000..e004166 --- /dev/null +++ b/doc/.svn/text-base/rdebug.1.svn-base @@ -0,0 +1,241 @@ +.\" $Id$ +.TH rdebug 1 +.SH NAME +rdebug \- Fast Ruby debugger +.SH SYNOPSIS +.B rdebug +[debugger-options] +rdebug +[script-options...] +.SH "DESCRIPTION" +This manual page documents briefly the +.BR rdebug +command. +.PP +.B rdebug +is a fast implementation of the standard Ruby debugger debug.rb. It +is implemented by utilizing a Ruby C API hook, allows for remote +debugging and can be used as the Ruby debugger backend interface for a +development environment. +.PP +The commands generally follow gdb's command set unless there's good +reason not to. + +.PP +rdebug can do four main kinds of things (plus other things in support of +these) to help you catch bugs in the act: + +.TP +\ \ \ \(bu +Start or restart your Ruby script, specifying arguments that might +affect its behavior. + +.TP +\ \ \ \(bu +Make your program stop at various points possibly determined by +specified conditions. + +.TP +\ \ \ \(bu +Examine what has happened when your program has stopped. + +.TP +\ \ \ \(bu +Change things in your program, so you can experiment with correcting the +effects of one bug and go on to learn about another. +.PP + +Here are some of the most frequently-needed commands: +.TP +.B break \fR[\|\fIfile\fB:\fIline\fR\fR|\fIclass.method\fR] \fR[if \fIexpr\fR] +\& +Set a breakpoint at \c +.I class.method\c +\& or at the specified file and line. +.TP +.B continue \fR[\fIline\fR] +Continue running your program (after stopping, e.g. at a +breakpoint). If a line is given a one-time breakpoint is set there. +.TP +.B delete \fR[\fIbreakpoint-numbers\fR] +\& +Delete breakpoints by number. If no number is given delete all breakpoints. +.TP +.B down \fR[\|\fIcount\fR\|] +Move down one block frame. If count is given move up that many frames. A negative number +goes the other direction and is like the up command +.TP +.B finish +Run until the completion of the current function or method. +.TP +.BI frame " frame-number" +Set the stack frame to \fIframe-number\fR for purposes of examinine local variables. For positioning relative to the current frame, use +.B up +or +.B down. A negative number starts counting from the other end. +.TP +.B help \fR[\|\fIname\fR\|] +Show information about rdebug command \c +.I name\c +\&, or general information +about using rdebug. +.TP +.B info \fR[\|\fIname\fR\|] +Get the various information usually about the debugged program. +.TP +.B irb \fIcommand\fR +Run an interactive ruby shell (irb) using the current environment. +.TP +.B list \fR[\|\fIfile\fB:\fIline\fR|\fIfunction] +type the text of the program in the vicinity of where it is presently stopped +or at the specified function or file and line. +.TP +.B next \fR[\|\fIcount\fR\|] +Execute next program line(s) (after stopping); step \c +.I over\c +\& any +function calls in the line. +.TP +.BI pp " expr"\c +\& +Pretty print the value of an expression. +.TP +.BI print " expr"\c +\& +Display the value of an expression. +.TP +.BI ps " expr"\c +\& +Print an array as a columized sorted list. +.TP +.B quit +Exit from the debugger. +.TP +.B run \fR[\|\fIarglist\fR\|] +(Re)start your program (with \c +.I arglist\c +\&, if specified). If you want the debugger to get reloaded, use +.B restart +instead. +.TP +.B set +Modify parts of the debugger environment. +.TP +.B show +See the debugger environment settings +.TP +.BI source " filename"\c +\& +Read and execute the lines in file \fIfilename\fR as a series of debugger +commands. +.TP +.B step \fR[\|\fIcount\fR\|] +Execute next program line(s) (after stopping); step \c +.I into\c +\& any +function calls in the line. +.TP +.B up \fR[\|\fIcount\fR\|] +Move up one block frame. If count is given move up that many frames. A negative number +goes the other direction and is like the down command +.TP +.B where \fR[\|\fIcount\fR\|] +Display all or \fIcount\fR items of the program stack. +.PP +For full details on rdebug, see \c +http://rubyforge.org/projects/ruby-debug/ +.SH OPTIONS +.PP +.TP 10 +.TP +.B \-A | \-\-annotate LEVEL +Set gdb-style annotation to LEVEL, a number. Additional information is output +automatically when program state is changed. This can be used by +front-ends such as GNU Emacs to post this updated information without +having to poll for it. +.TP +.B \-\-client +Connect to a remote debugger. Used with another rdebug invocation using \-\-server. +See also \-\-host and \-\-cport options +.TP +.B \-\-cport=PORT +Port used for control commands. +.TP +.B \-d | \-\-debug +Set $DEBUG true. +.TP +.B \-\-emacs +Activates full GNU Emacs mode. Is the equivalent of setting the +options \-\-emacs\-basic, \-\-annotate=3, \-\-no-stop, \-\-no\-control +and \-\-post\-mortem. +.TP +.B \-\-emacs-basic +Activates GNU Emacs mode. Debugger prompts are prefaced with two octal +032 characters. +.TP +.B \-h | \-\-host=HOST +Host name used for remote debugging. +.TP +.B \-I | \-\-include PATH +Add PATH to $LOAD_PATH +.TP +.B \-m | \-\-post-mortem +Activate post-mortem mode. +.TP +.B \-\-no-control +Do not automatically start control thread. +.TP +.B \-\-no\-stop +Do not stop when script is loaded. +.TP +.B \-p | \-\-port=PORT +Host name used for remote debugging. +.TP +.B \-r | \-\-require SCRIPT +Require the library, before executing your script. +.TP +.B \-\-script FILE +Name of the script file to run. +.TP +.B \-x | \-\-trace +Show lines before executing them. +.TP +.B \-\-no\-quit +Do not quit when script terminates. Instead rerun the program. +.TP +.B \-\-version +Show the version number and exit. +.TP +.B \-\-verbose +Turn on verbose mode. +.TP +.B \-\-v +Print the version number, then turn on verbose mode if a script name +is given. If no script name is given just exit after printing the +version number. +.TP +.B \-\-nx +Don't execute commands found in any initialization files, e.g. .rdebugrc. +.TP +.B \-\-keep-frame-binding +Keep frame bindings. +.TP +.B \-\-script=FILE +Name of the script file to run +.B \-s | \-\-server +Listen for remote connections. Another rdebug session accesses using the \-\-client option. +See also the \-\-host, \-\-port and +\-\-cport options +.TP +.B \-w | \-\-wait +Wait for a client connection, implies -s option. +.TP +.B \-\-help +Show invocation help and exit. +.PD +.SH "SEE ALSO" +.Sp +http://rubyforge.org/projects/ruby-debug/ +.SH AUTHOR +rdebug was written by Kent Siblev. This manual page was written by +Rocky Bernstein diff --git a/doc/.svn/text-base/ruby-debug.texi.svn-base b/doc/.svn/text-base/ruby-debug.texi.svn-base new file mode 100644 index 0000000..c50ae37 --- /dev/null +++ b/doc/.svn/text-base/ruby-debug.texi.svn-base @@ -0,0 +1,3982 @@ +\input texinfo @c -*-texinfo-*- +@setfilename ruby-debug.info + +@set DBG ruby-debug +@set ttrdebug @code{rdebug} +@set ttDBG @code{@value{DBG}} +@set Emacs @sc{gnu} Emacs + +@c Karl Berry informs me that this will add straight quotes in +@c typewriter text. +@c See the "Inserting Quote Characters" node in the Texinfo manual +@set txicodequoteundirected +@set txicodequotebacktick +@set RDEBUG_VERSION 0.10.4 + +@macro Example {} +@iftex +@cartouche +@end iftex +@smallexample +@end macro + +@macro EndExample {} +@iftex +@end cartouche +@end iftex +@end smallexample +@end macro + +@macro DBG {} +@value{DBG} +@end macro + +@macro ttDBG {} +@value{ttrdebug} +@end macro + +@c How to show optional variables. +@macro ovar{varname} +@r{[}@var{\varname\}@r{]} +@end macro + +@settitle ruby-debug +@setchapternewpage odd +@c %**end of header + +@include version.texi + +@finalout + +@c THIS MANUAL REQUIRES TEXINFO 4.0 OR LATER. + +@c This is a dir.info fragment to support semi-automated addition of +@c manuals to an info tree. +@dircategory Programming & development tools. +@direntry +* ruby-debug: (ruby-debug). Ruby Debugger +@end direntry + +@titlepage +@title Debugging with @code{ruby-debug} +@sp 1 +@subtitle @value{EDITION} Edition +@subtitle @value{UPDATED-MONTH} +@author Rocky Bernstein and Kent Sibilev +@page +@ifset WHERETO +@tex +{\parskip=0pt +\hfill (Send bugs and comments on ruby-debug to fill in...)\par +\hfill {\it Debugging with {\tt ruby-debug}\par +\hfill \TeX{}info \texinfoversion\par +} +@end tex +@end ifset +@end titlepage +@page + +@ifnottex +@node Top, Summary, (dir), (dir) +@top Debugging with ruby-debug + +This file describes ruby-debug, the Ruby Debugger, +version @value{RDEBUG_VERSION} + +This is the @value{EDITION} Edition, @value{UPDATED} +@c Copyright (C) 2007 ... + +@menu +* Summary:: Overview of Debugger with sample sessions +* Invocation:: Getting in and out +* Debugger Command Reference:: rdebug command reference +* Post-Mortem Debugging:: Debugging on an uncaught exception +* Debugger Module and Class:: ruby-debug's Debugger module and class + +Appendix +* Using from Subversion:: + +Indexes (nodes containing large menus) +* Class Module Index:: An item for Class, Module, and Methods. +* Command Index:: An item for each command name. +* General Index:: An item for each concept. +@end menu + +@end ifnottex + +@contents + +@node Summary +@chapter Summary of @code{ruby-debug} + +The purpose of a debugger such as @DBG{} is to allow you to see what is +going on ``inside'' a Ruby program while it executes. + +@ttDBG{} can do four main kinds of things (plus other things in support of +these) to help you catch bugs in the act: + +@itemize @bullet +@item +Start your script, specifying anything that might affect its behavior. + +@item +Make your script stop on specified conditions. + +@item +Examine what has happened, when your script has stopped. + +@item +Change things in your script, so you can experiment with correcting the +effects of one bug and go on to learn about another. +@end itemize + +Although you can use @value{ttrdebug} to invoke your Ruby programs via +a debugger at the outset, there are other ways to use and enter the +debugger. + +@menu +* First Sample Session:: A Simple Sample @code{rdebug} session +* Second Sample Session:: Second Session Delving a little deeper @code{rdebug} session +* Unit Testing Session:: Using the debugger in unit testing +* Debugger.start with a block:: Using the Debugger.start with a block +* Debugging Oddities:: How debugging Ruby may be different... +@end menu + +@node First Sample Session +@section The First Sample @code{rdebug} Session (@code{list}, @code{display}, @code{print}, and @code{quit}) + +You can use this manual at your leisure to read all about @value{ttDBG}. +However, a handful of commands are enough to get started using the +debugger. The following sections illustrates these commands. + +@iftex +In this sample session, we emphasize user input like this: @b{input}, +to make it easier to pick out from the surrounding output. +@end iftex + +Below is Ruby code to compute a triangle number of a given +length.@footnote{There are of course shorter ways to define @code{triangle} +such as: +@smallexample + def triangle(n) (n * (n+1)) / 2 end +@end smallexample +The code we use in this example and the next is more for pedagogical +purposes than how to write short Ruby code.} + + +@smallexample +$ @b{rdebug triangle.rb} +triangle.rb:4 def hanoi(n,a,b,c) +(rdb:1) @b{list} +[-1, 8] in ./triangle.rb + 1 #!/usr/bin/env ruby + 2 # Compute the n'th triangle number - the hard way + 3 # triangle(n) == (n * (n+1)) / 2 +=> 4 def triangle(n) + 5 tri = 0 + 6 0.upto(n) do |i| + 7 tri += i + 8 end +(rdb:1) @b{l} +[9, 18] in ./triangle.rb + 9 return tri + 10 end + 11 + 12 puts triangle(3) +(rdb:1) @b{list 1,100} +[1, 100] in ./triangle.rb + 1 #!/usr/bin/env ruby + 2 # Compute the n'th triangle number - the hard way + 3 # triangle(n) == (n * (n+1)) / 2 +=> 4 def triangle(n) + 5 tri = 0 + 6 0.upto(n) do |i| + 7 tri += i + 8 end + 9 return tri + 10 end + 11 + 12 puts triangle(3) +(rdb:1) +@end smallexample + +@noindent + +There are lots of command options, but we don't need them for now. See +@ref{rdebug command-line options} for a full list of command options. + +Position information consists of a filename and line number, +e.g.@: @code{triangle.rb:4}. We are currently stopped before the first +executable line of the program; this is line 4 of +@code{triangle.rb}. If you are used to less dynamic languages and have +used debuggers for more statically compiled languages like C, C++, or +Java, it may seem odd to be stopped before a function definition. But +in Ruby line 4 is executed, the name @code{triangle} (probably) does +not exist so issuing a method call of @code{triangle} will raise a +``method not found'' error. + +@DBG{}'s prompt is @code{(rdb:@emph{n})}. The @emph{n} is the thread +number. Here it is 1 which is usually the case for the main thread. If +the program has died and you are in post-mortem debugging, there is no +thread number. In this situation, the string @code{post-mortem} is +used in place of a thread number. If the program has terminated +normally, the string this position will be @code{ctrl}. The commands +which are available change depending on the program state. + +The first command, @code{list} (@pxref{List}), prints 10 lines +centered around the current line; the current line here is line 4 and +is marked by @code{=>}, so the range the debugger would like to show +is -1..8. However since there aren't 5 lines before the current line, +those additional lines---``lines'' -1 and 0---are dropped and we print +the remaining 8 lines. The @code{list} command can be abbreviated +with @code{l} which is what we use next. Notice that when we use this +a second time, we continue listing from the place we last left +off. The desired range of lines this time is lines 9 to 18; but since +the program ends as line 12, only the remaining 4 lines are shown. + +If you want to set how many lines to print by default rather than use +the initial number of lines, 10, use the @code{set listsize} command +(@pxref{Listsize}). To see the entire program in one shot, we gave an +explicit starting and ending line number. + +If you use a front-end to the debugger such as the Emacs interface, +@c (@pxref{GNU Emacs}) +you probably won't use @code{list} all that much. + +Now let us step through the program. + +@smallexample +(rdb:1) @b{step} +triangle.rb:12 +puts triangle(3) +(rdb:1) @b{@key{}} +triangle.rb:5 +tri = 0 +(rdb:1) @b{p tri} +nil +(rdb:1) @b{step} +triangle.rb:6 +0.upto(n) do |i| +(rdb:1) @b{p tri} +0 +@end smallexample + +The first @kbd{step} command (@pxref{Step}) runs the script one +executable unit. The second command we entered was just hitting the +return key; @ttDBG{} remembers the last command you entered was +@code{step}, so it runs that last command again. + +One way to print the values of variables uses @code{p}. (Of course, +there are of course lots of other ways too.). When we look at the +value of @code{tri} the first time, we see it is @code{nil}. Again we +are stopped @emph{before} the assignment on line 5, and this variable +hasn't been set previously. However after issuing another ``step'' +command we see that the value is 0 as expected. You could issue the +step and print comman in one shot: + +However if every time we stop we want to see the value of @code{tri} +to see how things are going stop, there is a better way by setting a +display expression (@pxref{DisplayCommands}). + +@smallexample +(rdb:1) display tri +1: tri = 0 +@end smallexample + +Now let us run the program until we return from the function. However +we'll want to see which lines get run. + +@smallexample +(rdb:1) @b{display i} +2: i = +(rdb:1) @b{set linetrace on} +line tracing is on. +(rdb:1) @b{finish} +Tracing(1):triangle.rb:7 tri += i +1: tri = 0 +2: i = 0 +Tracing(1):triangle.rb:7 tri += i +1: tri = 0 +2: i = 1 +Tracing(1):triangle.rb:7 tri += i +1: tri = 1 +2: i = 2 +Tracing(1):triangle.rb:7 tri += i +1: tri = 3 +2: i = 3 +Tracing(1):triangle.rb:9 return tri +1: tri = 6 +2: i = +(rdb:1) @b{quit} +Really quit? (y/n) y +@end smallexample + +So far, so good. A you can see from the above to get out of the +debugger, one can issue a @code{quit} command. (@code{q} and +@code{exit} are just as good. If you want to quit without being +prompted, suffix the command with an exclamation mark, e.g.\@code{q!}. + +@node Second Sample Session +@section Sample Session 2: Delving Deeper (@code{where}, @code{frame}, @code{restart}, @code{autoeval}, @code{break}, @code{ps}) + +In this section we'll introduce breakpoints, the call stack and +restarting. So far we've been doing pretty good in that we've not +encountered a bug to fix. Let's try another simple example. Okay +here's the program. + +Below we will debug a simple Ruby program to solve the classic Towers +of Hanoi puzzle. It is augmented by the bane of programming: some +command-parameter processing with error checking. + +@smallexample +$ @b{rdebug hanoi.rb} +hanoi.rb:3 def hanoi(n,a,b,c) +(rdb:1) @b{list 1,100} +[1, 100] in ./hanoi.rb + 1 #!/usr/bin/ruby + 2 +=> 3 def hanoi(n,a,b,c) + 4 if n-1 > 0 + 5 hanoi(n-1, a, c, b) + 6 end + 7 puts "Move disk %s to %s" % [a, b] + 8 if n-1 > 0 + 9 hanoi(n-1, c, b, a) + 10 end + 11 end + 12 + 13 i_args=ARGV.length + 14 if i_args > 1 + 15 puts "*** Need number of disks or no parameter" + 16 exit 1 + 17 end + 18 + 19 n=3 + 20 + 21 if i_args > 0 + 22 begin + 23 n = ARGV[0].to_i + 24 rescue ValueError, msg: + 25 print "** Expecting an integer, got: %s" % ARGV[0].to_s + 26 exit 2 + 27 end + 28 end + 29 + 30 if n < 1 or n > 100 + 31 puts "*** number of disks should be between 1 and 100" + 32 exit 2 + 33 end + 34 + 35 hanoi(n, :a, :b, :c) +(rdb:1) +@end smallexample + +Recall in the first section I said that before the @code{def} is run +the method it names is undefined. Let's check that out. First let's +see what private methods we can call before running @code{def hanoi} + +@smallexample +(rdb:1) @b{set autoeval on} +autoeval is on. +(rdb:1) @b{private_methods} +["select", "URI", "local_variables", "lambda", "chomp", ... +@end smallexample + +The @code{set autoeval} (@pxref{Autoeval}) command causes any commands +that are not normally understood to be debugger commands to get +evaluated as though they were Ruby commands. I use this a lot, so I +set this by putting it the command file @code{.rdebugrc}, +@pxref{Command Files}, that gets read when @code{ruby-debug} starts. + +As showing the list output of @code{private_methods}, I find this kind +of list unwieldy. What you are supposed to notice here is that +method @code{hanoi} is not in this list. When you ask +@code{ruby-debug} for a list of method names via @code{method +instance}, it doesn't show output in this way; @code{ruby-debug} can +sort and put into columns lists like this using the print command, @code{ps}. + + +@smallexample +(rdb:1) @b{ps private_methods} +Array exit! puts warn +Float fail raise y +Integer fork rand +Rational format readline +String gem_original_require readlines +URI getc remove_instance_variable +` gets scan +abort global_variables select +active_gem_with_options gsub set_trace_func +at_exit gsub! singleton_method_added +autoload initialize singleton_method_removed +autoload? initialize_copy singleton_method_undefined +binding iterator? sleep +block_given? lambda split +callcc load sprintf +caller local_variables srand +catch location_of_caller sub +chomp loop sub! +chomp! method_missing syscall +chop open system +chop! p test +dbg_print pp throw +dbg_puts print timeout +eval printf trace_var +exec proc trap +exit putc untrace_var +@end smallexample + +Now let's see what happens after stepping + +@smallexample +(rdb:1) @b{private.methods.member?("hanoi")} +false +(rdb:1) @b{step} +hanoi.rb:13 +i_args=ARGV.length +(rdb:1) @b{private_methods.member?("hanoi")} +true +(rdb:1) +@end smallexample + +Okay, now where were we? + +@smallexample +(rdb:1) @b{list} +[8, 17] in ./hanoi.rb + 8 if n-1 > 0 + 9 hanoi(n-1, c, b, a) + 10 end + 11 end + 12 +=> 13 i_args=ARGV.length + 14 if i_args > 1 + 15 puts "*** Need number of disks or no parameter" + 16 exit 1 + 17 end +(rdb:1) @b{ARGV} +[] +@end smallexample + +Ooops. We forgot to specify any parameters to this program. Let's try +again. We can use the @code{restart} command here. + +@smallexample +(rdb:1) @b{restart 3} +Re exec'ing: + /usr/bin/rdebug hanoi.rb 3 +hanoi.rb:3 +def hanoi(n,a,b,c) +(rdb:1) @b{break 4} +Breakpoint 1 file hanoi.rb, line 4 +(rdb:1) @b{continue} +Breakpoint 1 at hanoi.rb:4 +./hanoi.rb:4 if n-1 > 0 +(rdb:1) @b{display n} +1: n = 3 +(rdb:1) @b{display a} +2: a = a +(rdb:1) @b{undisplay 2} +(rdb:1) @b{display a.inspect} +3: a.inspect = :a +(rdb:1) @b{display b.inspect} +4: b.inspect = :b +(rdb:1) @b{continue} +Breakpoint 1 at hanoi.rb:4 +./hanoi.rb:4 +if n-1 > 0 +1: n = 2 +3: a.inspect = :a +4: b.inspect = :c +(rdb:1) @b{c} +Breakpoint 1 at hanoi.rb:4 +./hanoi.rb:4 +if n-1 > 0 +1: n = 1 +3: a.inspect = :a +4: b.inspect = :b +(rdb:1) @b{where} +--> #0 Object.hanoi(n#Fixnum, a#Symbol, b#Symbol, c#Symbol) at line hanoi.rb:4 + #1 Object.-(n#Fixnum, a#Symbol, b#Symbol, c#Symbol) at line hanoi.rb:5 + #2 Object.-(n#Fixnum, a#Symbol, b#Symbol, c#Symbol) at line hanoi.rb:5 + #3 at line hanoi.rb:35 +(rdb:1) +@end smallexample + +In the above we added a new command, @code{break} +(@pxref{Breakpoints}) which indicates to go into the debugger just +before that line of code is run. And @code{continue} resumes +execution. Notice the difference between @code{display a} and +@code{display a.inspect}. An implied string conversion is performed on +the expression after it is evaluated. To remove a display expression +we used @code{undisplay} is used. If we give a display number, just +that display expression is removed. + +Above we also used a new command @code{where} (@pxref{Backtrace} to +show the call stack. In the above situation, starting from the bottom +line we see we called the hanoi from line 35 of the file +@code{hanoi.rb} and the hanoi method called itself two more times at +line 5. + +In the call stack we show the file line position in the same format +when we stop at a line. Also we see the names of the parameters and +the types that those parameters @emph{currently} have. It's possible +that when the program was called the parameter had a different type, +since the types of variables can change dynamically. You alter the +style of what to show in the trace (@pxref{Callstyle}). + +Let's explore a little more. Now were were we? + +@smallexample +(rdb:1) @b{list} + 1 #!/usr/bin/ruby + 2 + 3 def hanoi(n,a,b,c) +=> 4 if n-1 > 0 + 5 hanoi(n-1, a, c, b) + 6 end + 7 puts "Move disk %s to %s" % [a, b] + 8 if n-1 > 0 +(rdb:1) @b{undisplay} +Clear all expressions? (y/n) @b{y} +(rdb:1) @b{i_args} +NameError Exception: undefined local variable or method `i_args' for main:Object +(rdb:1) @b{frame -1} +#3 at line hanoi.rb:35 +(rdb:1) @b{i_args} +1 +(rdb:1) @b{p n} +3 +(rdb:1) @b{down 2} +#2 Object.-(n#Fixnum, a#Symbol, b#Symbol, c#Symbol) at line hanoi.rb:5 +(rdb:1) @b{p n} +2 +@end smallexample + +Notice in the above to get the value of variable @code{n}, I have to +use a print command like @code{p n}; If I entered just @code{n}, that +would be taken to mean the debugger command ``next''. In the current +scope, variable @code{i_args} is not defined. However I can change to +the top-most frame by using the @code{frame} command. Just as with +arrays, -1 means the last one. Alternatively using frame number 3 +would have been the same thing; so would issuing @code{up 3}. + +Note that in the outside frame 3, the value of @code{i_args} can be +shown. Also note that the value of variable @code{n} is different. + +@node Unit Testing Session +@section Using the debugger in unit testing (@code{ruby-debug/debugger}, @code{Debugger.start}) + +In the previous sessions we've been calling the debugger right at the +outset. I confess that this mode of operation is usually not how I use +the debugger. + +There are a number of situations where calling the debugger at the outset is +impractical for a couple of reasons. + +@enumerate +@item +The debugger just doesn't work when run at the outset. By necessity +any debugging changes to the behavior or the program in slight and +subtle ways, and sometimes this can hinder finding the bugs. +@item +There's a lot of code which that needs to get run before the part you +want to inspect. Running this code takes time and you don't the +overhead of the debugger in this first part. +@end enumerate + +In this section we'll delve show how to enter the code in the middle +of your program, while delving more into the debugger operation. + +In this section we will also use unit testing. Using unit tests will +greatly reduce the amount of debugging needed while at the same time +increase the quality of your program. + +What we'll do is take the @code{triangle} code from the first session +and write a unit test for that. In a sense we did write a mini-test +for the program which was basically the last line where we printed the +value of triangle(3). This test however wasn't automated: the +implication is that someone would look at the output and verify that +what was printed is what was expected. + +And before we can turn that into something that can be +@code{required}, we probably want to remove that output. However I +like to keep in that line so that when I look at the file, I have an +example of how to run it. Therefore we will conditionally run this +line if that file is invoked directly, but skip it if it is +not.@footnote{@code{rdebug} resets @code{$0} to try to make things +like this work.} +@smallexample + if __FILE__ == $0 + puts triangle(3) + end +@end smallexample + +Let's call this file @code{tri2.rb}. + +Okay, we're now ready to write our unit test. We'll use +@code{"test/unit"} which comes with the standard Ruby distribution. +Here's the test code: + +@smallexample + #!/usr/bin/env ruby + require 'test/unit' + require 'tri2.rb' + + class TestTri < Test::Unit::TestCase + def test_basic + solutions = [] + 0.upto(5) do |i| + solutions << triangle(i) + end + assert_equal([0, 1, 3, 6, 10, 15], solutions, + 'Testing the first 5 triangle numbers') + end + end +@end smallexample + +If you run it will work. However if you run @code{rdebug} initially, +you will not get into the test, because @code{test/unit} wants to be +the main program. So here is a situation where one may need to modify +the program to add an explicit @emph{entry} into the +debugger.@footnote{For some versions of rake and @code{rdebug} you can +in fact set a breakpoint after running @code{rdebug} +initially. Personally though I find it much simpler and more reliable +to modify the code as shown here.} + +One way to do this is to add the following before the place you want +to stop: +@smallexample + require 'rubygems' + require 'ruby-debug/debugger' +@end smallexample +The line @code{require "rubygems"} is needed if @code{ruby-debug} is +installed as a Ruby gem. + +Let's add this code just after entering @code{test_basic}: +@smallexample + ... + def test_basic + @b{require "rubygems"} + @b{require "ruby-debug/debugger"} + solutions = [] + ... +@end smallexample + +Now we run the program.. +@smallexample + $ @b{ruby test-tri.rb} + Loaded suite test-tri + Started + test-tri.rb:9 + solutions = [] + (rdb:1) +@end smallexample +and we see that we are stopped at line 9 just before the +initialization of the list @code{solutions}. + +Now let's see where we are... + +@smallexample +(rdb:1) @b{where} +--> #0 TestTri.test_basic at line /home/rocky/ruby/test-tri.rb:9 +(rdb:1) +@end smallexample + +Something seems wrong here; @code{TestTri.test_basic} indicates that +we are in class @code{TestTri} in method @code{test_basic}. However we +don't see the call to this like we did in the last example when we +used the @code{where} command. This is because the debugger really +didn't spring into existence until after we already entered that +method, and Ruby doesn't keep call stack information around in a +way that will give the information we show when running @code{where}. + +If we want call stack information, we have to turn call-stack tracking +on @emph{beforehand}. This is done by adding @code{Debugger.start}. + +Here's what our test program looks like so after we modify it to start +tracking calls from the outset + +@smallexample +#!/usr/bin/env ruby +require 'test/unit' +require 'tri2.rb' +require 'rubygems' +@b{Debugger.start} + +class TestTri < Test::Unit::TestCase + def test_basic + @b{debugger} + solutions = [] + 0.upto(5) do |i| + solutions << triangle(i) + end + assert_equal([0, 1, 3, 6, 10, 15], solutions, + "Testing the first 5 triangle numbers") + end +end +@end smallexample + +Now when we run this: +@smallexample +$ @b{ruby test-tri2.rb} +Loaded suite test-tri2 +Started +test-tri2.rb:11 +solutions = [] +(rdb:1) @b{where} +--> #0 TestTri.test_basic at line test-tri2.rb:11 + #1 Kernel.__send__(result#Test::Unit::TestResult) + at line /usr/lib/ruby/1.8/test/unit/testcase.rb:70 + #2 Test::Unit::TestCase.run(result#Test::Unit::TestResult) + at line /usr/lib/ruby/1.8/test/unit/testcase.rb:70 +... + #11 Test::Unit::AutoRunner.run + at line /usr/lib/ruby/1.8/test/unit/autorunner.rb:200 + #12 Test::Unit::AutoRunner.run(force_standalone#FalseClass, ... + at line /usr/lib/ruby/1.8/test/unit/autorunner.rb:13 + #13 at line /usr/lib/ruby/1.8/test/unit.rb:285 +(rdb:1) +@end smallexample + +Much better. But again let me emphasize that the parameter types are +those of the corresponding variables that @emph{currently} exist, and +this might have changed since the time when the call was made. Even so +and even though we only have @emph{types} listed, it's a pretty good +bet that when @code{Test::Unit} was first called, shown above as frame +12, that the values of its two parameters were @code{false} and +@code{nil}. + +@node Debugger.start with a block +@section Using the @code{Debugger.start} with a block + +We saw that @code{Debugger.start()} and @code{Debugger.stop()} allow +fine-grain control over where the debugger tracking should occur. + +Rather than use an explicit @code{stop()}, you can also pass a block +to the @code{start()} method. This causes @code{start()} to run and +then @code{yield} to that block. When the block is finished, +@code{stop()} is run. In other words, this wraps a +@code{Debugger.start()} and @code{Debugger.stop()} around the block of +code. But it also has a side benefit of ensuring that in the presence +of an uncaught exception @code{stop} is run, without having to +explicitly use @code{begin} ... @code{ensure Debugger.stop() end}. + +For example, in Ruby Rails you might want to debug code in one of the +controllers without causing any slowdown to any other code. And +this can be done by wrapping the controller in a @code{start()} with a +block; when the method wrapped this way finishes the debugger is +turned off, and the application proceeds at regular speed. + +Of course, inside the block you will probably want to enter the +debugger using @code{Debugger.debugger()}, otherwise there would +little point in using the @code{start}. For example, you can do this +in @code{irb}: + +@smallexample +$ @b{irb} +irb(main):001:0> @b{require 'rubygems'; require 'ruby-debug'} +=> true +irb(main):002:0> @b{def foo} +irb(main):003:1> @b{x=1} +irb(main):004:1> @b{puts 'foo'} +irb(main):005:1> @b{end} +=> nil +irb(main):006:0> @b{Debugger.start@{debugger; foo@}} +(irb):6 +(rdb:1) @b{s} +(irb):3 +(rdb:1) @b{p x} +nil +(rdb:1) @b{s} +(irb):4 +(rdb:1) @b{p x} +1 +(rdb:1) @b{s} +foo +=> true +irb(main):007:0> +@end smallexample + +There is a counter inside of @code{Debugger.start} method to make sure +that this works when another @code{Debugger.start} method is called +inside of outer one. However if you are stopped inside the debugger, +issuing another @code{debugger} call will not have any effect even if +it is nested inside another @code{Debugger.start}. + +@node Debugging Oddities +@section How debugging Ruby may be different than debugging other Languages + +If you are used to debugging in other languages like C, C++, Perl, +Java or even Bash@footnote{this is just an excuse to put in a +shameless plug for my bash debugger @url{http://bashdb.sf.net}}, there +may be a number of things that seem or feel a little bit different and +may confuse you. A number of these things aren't oddities of the +debugger per see, so much as a difference in how Ruby works compared to +those other languages. Because Ruby works a little differently from +those other languages, writing a debugger has to also be a little +different as well if it is to be useful. + +In this respect, using the debugger may help you understand Ruby +better. + +We've already seen two examples of such differences. One difference is +the fact that we stop on method definitions or @code{def}'s and that's +because these are in fact executable statements. In other compiled +languages this would not happen because that's already been done when +you compile the program (or in Perl when it scans in the program). The +other difference we saw was in our inability to show call stack parameter +types without having made arrangements for the debugger to track +this. In other languages call stack information is usually available +without asking assistance of the debugger.@footnote{However in C, and +C++ generally you have to ask the compiler to add such information.} + +In this section we'll consider some other things that might throw +off new users to Ruby who are familiar with other languages and +debugging in them. + +@menu +* Stack Shows Scope Nesting:: +* More Frequent Evaluations per Line:: +* Bouncing Around in Blocks (e.g. Iterators):: +* No Parameter Values in a Call Stack:: +* Lines You Can Stop At:: +@end menu + +@node Stack Shows Scope Nesting +@subsection Stack Shows Scope Nesting +In a backtrace, you will find more stack frames than you might in say +C. + +Consider another way to write the triangle program of @pxref{First +Sample Session}. + +@smallexample + 1 #!/usr/bin/env ruby + 2 def triangle(n) + 3 (0..n).inject do |sum, i| + 4 sum +=i + 5 end + 6 end + 7 puts triangle(3) +@end smallexample + +Let's stop inside the @code{inject} block: + +@smallexample +$ @b{rdebug tri3.rb} +(rdb:1) @b{c 4} +tri3.rb:4 +sum +=i +(rdb:1) @b{where} +--> #0 Range.triangle at line tri3.rb:4 + #1 Enumerable.inject at line tri3.rb:3 + #2 Object.triangle(n#Fixnum) at line tri3.rb:3 + #3 at line tri3.rb:7 +(rdb:1) +@end smallexample +Because a new scope was entered, it appears as a stack frame. Probably +``scope'' frame would be a more appropriate name. + +@node More Frequent Evaluations per Line +@subsection More Frequent Evaluations per Line +Consider this simple program to compute the Greatest Common Divisor of +two numbers: +@smallexample + 1 #!/usr/bin/env ruby + 2 # GCD. We assume positive numbers + 3 + 4 def gcd(a, b) + 5 # Make: a <= b + 6 if a > b + 7 a, b = [b, a] + 8 end + 9 +10 return nil if a <= 0 +11 +12 if a == 1 or b-a == 0 +13 return a +14 end +15 return gcd(b-a, a) +16 end +17 +18 a, b = ARGV[0..1].map @{|arg| arg.to_i@} +19 puts "The GCD of %d and %d is %d" % [a, b, gcd(a, b)] +@end smallexample + +Now let's try tracing a portion of the program to see what we get. +@smallexample +$ @b{rdebug gcd.rb 3 5} +gcd.rb:4 +def gcd(a, b) +(rdb:1) @b{step} +gcd.rb:18 +a, b = ARGV[0..1].map @{|arg| arg.to_i@} +(rdb:1) @b{step} +gcd.rb:18 +a, b = ARGV[0..1].map @{|arg| arg.to_i@} +(rdb:1) @b{step} +gcd.rb:18 +a, b = ARGV[0..1].map @{|arg| arg.to_i@} +(rdb:1) @b{step} +(rdb:1) @b{break Object.gcd} +Breakpoint 1 at Object::gcd +(rdb:1) @b{continue} +Breakpoint 1 at Object:gcd +gcd.rb:4 +def gcd(a, b) +(rdb:1) @b{set linetrace on} +line tracing is on. +(rdb:1) @b{continue} +Tracing(1):gcd.rb:6 if a > b +Tracing(1):gcd.rb:6 if a > b +Tracing(1):gcd.rb:10 return nil if a <= 0 +Tracing(1):gcd.rb:10 return nil if a <= 0 +Tracing(1):gcd.rb:12 if a == 1 or b-a == 0 +Tracing(1):gcd.rb:12 if a == 1 or b-a == 0 +Tracing(1):gcd.rb:15 return gcd(b-a, a) +Breakpoint 1 at Object:gcd +gcd.rb:4 +def gcd(a, b) +(rdb:1) +@end smallexample + +The thing to note here is that we see lots of lines duplicated. For +example, the first line: +@smallexample +Tracing(1):gcd.rb:18 a, b = ARGV[0..1].map @{|arg| arg.to_i@} +@end smallexample +appears three times. If we were to break this line into the equivalent +multi-line expression: +@smallexample +a, b = ARGV[0..1].map do |arg| + arg.to_i +end +@end smallexample +we would find one stop at the first line before running @code{map} and +two listings of @code{arg.to_i}, once for each value of arg which here +is 0 and then 1. Perhaps this is is not surprising because we have a +loop here which gets run in this situation 3 times. A similar command +@code{next}, can also be used to skip over loops and method +calls. + +But what about all the duplicated @code{if} statements in @code{gcd}? +Each one is listed twice whether or not we put the @code{if} at the +beginning or the end. You will find this to be the case for any +conditional statement such as @code{until} or @code{while}. + +Each statement appears twice because we stop once before the +expression is evaluated and once after the expression is evaluated but +before the if statement takes hold. There is a bug in Ruby up to +version 1.8.6 in that we stop a second time before the evaluation, so +examining values that may have changed during the expression +evaluation doesn't work in these versions. + +If you are issuing a @code{step} command one at a time, the repetitive +nature can be little cumbersome if not annoying. So @value{DBG} offers +a variant called @code{step+} which forces a new line on every +step. Let's try that. +@smallexample +(rdb:1) @b{R} +Re exec'ing: + /usr/bin/rdebug gcd.rb 3 5 +gcd.rb:4 +def gcd(a, b) +(rdb:1) @b{step+} +gcd.rb:18 +a, b = ARGV[0..1].map @{|arg| arg.to_i@} +(rdb:1) @b{step+} +gcd.rb:19 +puts "The GCD of %d and %d is %d" % [a, b, gcd(a, b)] +(rdb:1) @b{break Object.gcd} +Breakpoint 1 at Object:gcd +(rdb:1) @b{c} +Breakpoint 1 at Object:gcd +gcd.rb:4 +def gcd(a, b) +(rdb:1) @b{set linetrace+} +line tracing style is different consecutive lines. +(rdb:1) @b{set linetrace on} +line tracing is on. +(rdb:1) @b{c} +Tracing(1):gcd.rb:6 if a > b +Tracing(1):gcd.rb:10 return nil if a <= 0 +Tracing(1):gcd.rb:12 if a == 1 or b-a == 0 +Tracing(1):gcd.rb:15 return gcd(b-a, a) +Breakpoint 1 at Object:gcd +gcd.rb:4 +def gcd(a, b) +@end smallexample + +If you want @code{step+} to be the default behavior when stepping, +issue the command @code{set forcestep on}, (@pxref{Forcestep}). I +generally put this in my start-up file @code{.rdebugrc}. + +Similar to the difference between @code{step+} and @code{step} is +@code{set linetrace+}. This removes duplicate consecutive line tracing. + +One last thing to note above is the use of a method name to set a +breakpoint position, rather than a file and line number. Because +method @code{gcd} is in the outermost scope, we use @code{Object} as the +class name. + +@node Bouncing Around in Blocks (e.g. Iterators) +@subsection Bouncing Around in Blocks (e.g.@: Iterators) + +When debugging languages with coroutines like Python and Ruby, a +method call may not necessarily go to the first statement after the +method header. It's possible the call will continue after a +@code{yield} statement from a prior call. + +@smallexample + 1 #!/usr/bin/env ruby + 2 # Enumerator for primes + 3 class SievePrime + 4 @@@@odd_primes = [] + 5 def self.next_prime(&block) + 6 candidate = 2 + 7 yield candidate + 8 not_prime = false + 9 candidate += 1 +10 while true do +11 @@@@odd_primes.each do |p| +12 not_prime = (0 == (candidate % p)) +13 break if not_prime +14 end +15 unless not_prime +16 @@@@odd_primes << candidate +17 yield candidate +18 end +19 candidate += 2 +20 end +21 end +22 end +23 SievePrime.next_prime do |prime| +24 puts prime +25 break if prime > 10 +26 end +@end smallexample + +@smallexample +$ @b{rdebug primes.rb} +primes.rb:3 +class SievePrime +(rdb:1) @b{set linetrace on} +line tracing is on. +(rdb:1) @b{step 10} +Tracing(1):primes.rb:4 @@odd_primes = [] +Tracing(1):primes.rb:5 def self.next_prime(&block) +Tracing(1):primes.rb:23 SievePrime.next_prime do |prime| +Tracing(1):primes.rb:6 candidate = 2 +Tracing(1):primes.rb:7 yield candidate +Tracing(1):primes.rb:24 puts prime +2 +Tracing(1):primes.rb:25 break if prime > 10 +Tracing(1):primes.rb:25 break if prime > 10 +Tracing(1):primes.rb:8 not_prime = false +Tracing(1):primes.rb:9 candidate += 1 +primes.rb:9 +candidate += 1 +(rdb:1) +@end smallexample + +The loop between lines 23--26 gets interleaved between those of +@code{Sieve::next_prime}, lines 6--19 above. + +A similar kind of thing can occur in debugging programs with many threads. + +@node No Parameter Values in a Call Stack +@subsection No Parameter Values in a Call Stack +In traditional debuggers in a call stack you can generally see the +names of the parameters and the values that were passed in. + +Ruby is a very dynamic language and it tries to be efficient within +the confines of the language definition. Values generally aren't taken +out of a variable or expression and pushed onto a stack. Instead a new +scope created and the parameters are given initial values. Parameter +passing is by @emph{reference}, not by value as it is say Algol, C, or +Perl. During the execution of a method, parameter values can +change---and often do. In fact even the @emph{class} of the object can +change. + +So at present, the name of the parameter shown. The call-style setting +@pxref{Callstyle} can be used to set whether the name is shown or the +name and the @emph{current} class of the object. + +It has been contemplated that a style might be added which saves on +call shorter ``scalar'' types of values and the class name. + +@node Lines You Can Stop At +@subsection Lines You Can Stop At +As with the duplicate stops per control (e.g.@: @code{if} statement), +until tools like debuggers get more traction among core ruby +developers there are going to be weirdness. Here we describe the +stopping locations which effects the breakpoint line numbers you can +stop at. + +Consider the following little Ruby program. + +@smallexample +'Yes it does' =~ / +(Yes) \s+ +it \s+ +does +/ix +puts $1 +@end smallexample + +The stopping points that Ruby records are the last two lines, lines 5 +and 6. If you run @code{ruby -rtracer} on this file you'll see that +this is so: + +@smallexample +$ ruby -rtracer lines.rb +#0:lines.rb:5::-: /ix +#0:lines.rb:6::-: puts $1 +#0:lines.rb:6:Kernel:>: puts $1 +#0:lines.rb:6:IO:>: puts $1 +Yes#0:lines.rb:6:IO:<: puts $1 +#0:lines.rb:6:IO:>: puts $1 + +#0:lines.rb:6:IO:<: puts $1 +#0:lines.rb:6:Kernel:<: puts $1 +@end smallexample + +Inside @code{ruby-debug} you an get a list of stoppable lines for a +file using the @code{info file} command with the attribute +@code{breakpoints}. + +@ifset FINISHED +To be continued... + +@itemize @bullet +@item more complex example with objects, pretty printing and irb. +@item line tracing and non-interactive tracing. +@item mixing in Debugger.debug with rdebug +@item post-mortem debugging and setting up for that +@item threading? +@item references to videos +@end itemize +@end ifset + +@node Invocation +@chapter Getting in and out + +@menu +* Starting the debugger:: How to enter the debugger +* Command Files:: Command files +* Quitting the debugger:: How to leave the debugger (quit, kill) +* Calling from Program:: Calling the debugger from inside your program +@end menu + +It is also possible to enter the debugger when you have an uncaught +exception. See See also @ref{Post-Mortem Debugging}. + +@node Starting the debugger +@section Starting the debugger + +Although one can enter @DBG{} via Emacs (described in a later section) +and possibly others interfaces, probably the most familiar thing to do +is invoke the debugger from a command line. + +A wrapper shell script called @code{rdebug} basically @code{require}'s +the gem package @code{ruby-debug} and then loads @code{rdebug}. + +@smallexample +rdebug [rdebug-options] [--] @var{ruby-script} @var{ruby-script-arguments...} +@end smallexample + +If you don't need to pass dash options to your program which might get +confused with the debugger options, then you don't need to add the +@option{--}. + +To get a brief list of options and descriptions, use the @code{--help} +option. + +@smallexample +$ @b{rdebug --help} +rdebug @value{RDEBUG_VERSION} +Usage: rdebug [options] -- + +Options: + -A, --annotate LEVEL Set annotation level + -c, --client Connect to remote debugger + --cport PORT Port used for control commands + -d, --debug Set $DEBUG=true + --emacs Activates full Emacs support + --emacs-basic Activates basic Emacs mode + -h, --host HOST Host name used for remote debugging + -I, --include PATH Add PATH to $LOAD_PATH + --keep-frame-binding Keep frame bindings + -m, --post-mortem Activate post-mortem mode + --no-control Do not automatically start control thread + --no-quit Do not quit when script finishes + --no-rewrite-program Do not set $0 to the program being debugged + --no-stop Do not stop when script is loaded + -p, --port PORT Port used for remote debugging + -r, --require SCRIPT Require the library, before executing your script + --script FILE Name of the script file to run + -s, --server Listen for remote connections + -w, --wait Wait for a client connection, implies -s option + -x, --trace Turn on line tracing + +Common options: + --verbose Turn on verbose mode + --help Show this message + --version Print the version + -v Print version number, then turn on verbose mode +@end smallexample + +Options for the @code{rdebug} are shown in the following list. + +@menu +* rdebug command-line options:: Options you can pass to rdebug +* rdebug default options:: How to Set Default Command-Line Options +@end menu + +@node rdebug command-line options +@subsection Options you can pass to rdebug + +You can run @DBG{} in various alternative modes---for example, as a +program that interacts directly with the program in the same process +on the same computer or via a socket to another process possibly on a +different computer. + +Many options appear as a long option name, such as @option{--help}, and +a short one letter option name, such as @option{-h}. A double dash +(@option{--} is used to separate options which go to @code{rdebug} from +options that are intended to go to your Ruby script. Options (if any) +to @code{rdebug} should come first. If there is no possibility of the +Ruby script to be debugged getting confused with @code{rdebug}'s +option the double dash can be omitted. + +@table @code +@item --help +@cindex @option{-h} +@cindex @option{--help} +This option causes @ttDBG{} to print some basic help and exit. + +@item -v | --version +@cindex @option{-v} +This option causes @ttDBG{} to print its version number and exit. + +@item -A | --annotate @var{level} +@cindex @option{-A} +@cindex @option{--annotation} @var{level} +Set gdb-style annotation @var{level}, a number. Additional information is output +automatically when program state is changed. This can be used by +front-ends such as GNU Emacs to post this updated information without +having to poll for it. +@item -c | --client +@cindex @option{-c} +@cindex @option{--client} +Connect to remote debugger. The remote debugger should have been set +up previously our you will get a connection error and @code{rdebug} +will terminate. + +@item --cport @var{port} +@cindex @option{--cport} @var{port} +Port used for control commands. + +@item --debug +@cindex @option{--debug} +Set @code{$DEBUG} to @code{true}. This option is compatible with +Ruby's. + +@item --emacs +Activates GNU Emacs mode. +@c @pxref{GNU Emacs}. +Debugger output is tagged in such a way to allow GNU Emacs to track +where you are in the code. + +@item --emacs-basic +Activates full GNU Emacs mode. +@c (@pxref{GNU Emacs}). +This is the equivalent of setting the options @option{--emacs-basic}, +@code{annotate=3}, @option{--no-stop}, @option{-no-control} and +@option{--post-mortem}. + +@item -h | --host @var{host-address} +Connect host address for remote debugging. + +@item -I --include @var{PATH} +@cindex @option{-I} @var{PATH} +@cindex @option{--include} @var{PATH} +Add @var{PATH} to @code{$LOAD_PATH} + +@item --keep-frame-binding +@cindex @option{--keep-frame-binding} +Bindings are used to set the proper environment in evaluating +expression inside the debugger. Under normal circumstances, I don't +believe most people will ever need this option. + +By default, the debugger doesn't create binding object for each frame +when the frame is created, i.e. when a call is performed. Creating a +binding is an expensive operation and has been a major source of +performance problems. + +Instead, the debugger creates a binding when there is a need to +evaluate expressions. The artificial binding that is created might be +different from the real one. In particular, in performing constant +and module name resolution. + +However it's still possible to restore the old, slower behavior by +using this option or by setting @code{Debugger.keep_frame_binding = +true}. There are two possibilities for which you might want to use +this option. + +First, if you think there's a bug in the evaluation of variables, you +might want to set this to see if this corrects things. + +Second, since the internal structures that are used here @code{FRAME} +and @code{SCOPE} are not part of the Ruby specification, it is +possible they can change with newer releases; so here this option this +may offer a remedy. (But you'll probably also have to hack the C code +since it's likely under this scenario that ruby-debug will no longer +compile.) In fact, in Ruby 1.9 these structures have changed and that +is partly why this debugger doesn't work on Ruby 1.9. + +@item -m | --post-mortem +@cindex @option{-m} +@cindex @option{--post-mortem} +If your program raises an exception that isn't caught you can enter +the debugger for inspection of what went wrong. You may also want to +use this option in conjunction with @option{--no-stop}. See also +@ref{Post-Mortem Debugging}. + +@item --no-control +@cindex @option{--no-control} +Do not automatically start control thread. + +@item --no-quit +@cindex @option{--no-quit} +Restart the debugger when your program terminates normally. + +@item --no-rewrite-program +@cindex @option{--no-rewrite-program} +Normally @code{rdebug} will reset the program name @code{$0} from its +name to the debugged program, and set the its name in variable +@code{$RDEBUG_0}. In the unlikely even you don't want this use this option. + +@item --no-stop +@cindex @option{--no-stop} +Normally the @code{rdebug} stops before executing the first +statement. If instead you want it to start running initially and will +perhaps break it later in the running, use this options. + +@item -p | --port @var{port} +@cindex @option{-p} @var{port} +@cindex @option{--port} @var{port} +Port used for remote debugging. + +@item -r | --require @var{library} +@cindex @option{-r} +@cindex @option{--require} +Require the library, before executing your script. However if the +library happened to be @code{debug}, we'll just ignore the require +(since we're already a debugger). This option is compatible with Ruby's. + +@item --script @var{file} +@cindex @option{--script} +Require the library, before executing your script. However if the +library hap-pend to be @code{debug}, we'll just ignore the require +(since we're already a debugger). This option is compatible with Ruby's. + +@item -s | --server +@cindex @option{-s} +@cindex @option{--server} +Debug the program but listen for remote connections on the default +port or port set up via the @option{--port} option. See also @option{--wait}. + +@item -w | --wait +@cindex @option{-w} +@cindex @option{--wait} +Debug the program but stop waiting for a client connection first. This +option automatically sets @option{--server} option. + +@item -x | --trace +@cindex @option{-x} +@cindex @option{--trace} +Turn on line tracing. Running @command{rdebug --trace @emph{rubyscript.rb}} +is much like running: @command{ruby -rtracer @emph{rubyscript.rb}} + +If all you want to do however is get a linetrace, @code{tracer}, not +@code{rdebug}, may be faster: +@smallexample +$ @b{time ruby -rtracer gcd.rb 34 21 > /dev/null} + +real 0m0.266s +user 0m0.008s +sys 0m0.000s +$ @b{time rdebug --trace gcd.rb 34 21 > /dev/null} + +real 0m0.875s +user 0m0.448s +sys 0m0.056s +$ +@end smallexample + +@end table + +@node rdebug default options +@subsection How to Set Default Command-Line Options + +@DBG{} has many command-line options; it seems that some people want +to set them differently from the our defaults. For example, some +people may want @option{--no-quit --no-control} to be the default +behavior. One could write a wrapper script or set a shell alias to +handle this. @DBG{} has another way to do this as well. Before +processing command options if the file @code{$HOME/.rdboptrc} is found +it is loaded. If you want to set the defaults in some other way, you +can put Ruby code here and set variable @code{options} which is an +OpenStruct. For example here's how you'd set @option{-no-quit} and +change the default control port to 5000. + +@smallexample +# This file contains how you want the default options to ruby-debug +# to be set. Any Ruby code can be put here. +# +# debugger # Uncomment if you want to debug rdebug! +options.control = false +options.port = 5000 +puts "rocky's rdboptrc run" +@end smallexample + +Here are the default values in @code{options} +@smallexample +# +@end smallexample + + +@node Command Files +@section Command files + +@cindex command files +A command file for @DBG{} is a file of lines that are @DBG{} +commands. Comments (lines starting with @kbd{#}) may also be included. +An empty line in a command file does nothing; it does not mean to repeat +the last command, as it would from the terminal. + +@cindex init file +@cindex @file{.rdebugrc} +When you start @value{DBG}, it automatically executes commands from its +@dfn{init files}, normally called @file{.rdebugrc}. + +On some configurations of @value{DBG}, the init file may be known by a +different name. In particular on MS-Windows (but not cygwin) +@file{rdebug.ini} is used. + +During startup, @DBG{} does the following: + +@enumerate +@item +Processes command line options and operands. + +@item +Reads the init file in your current directory, if any, and failing +that the home directory. The home directory is the directory named in +the @code{HOME} or @code{HOMEPATH} environment variable. + +Thus, you can have more than one init file, one generic in your home +directory, and another, specific to the program you are debugging, in +the directory where you invoke @DBG{}. + +@item +Reads command files specified by the @samp{--script} option. +@end enumerate + +You can also request the execution of a command file with the +@code{source} command, @pxref{Source}. + +@node Quitting the debugger +@section Quitting the debugger + +@cindex interrupt +An interrupt (often @kbd{C-c}) does not exit from @value{DBG}, but +rather terminates the action of any @DBG command that is in +progress and returns to @value{DBG} command level. Inside a debugger +command interpreter, use @code{quit} command (@pxref{Control, ,Quitting +the debugger}). + +There way to terminate the debugger is to use the @code{kill} +command. This does more forceful @code{kill -9}. It can be used in +cases where @code{quit} doesn't work. + +@node Calling from Program +@section Calling the debugger from inside your Ruby program + +Running a program from the debugger adds a bit of overhead and slows +down your program a little. + +Furthermore, by necessity, debuggers change the operation of the +program they are debugging. And this can lead to unexpected and +unwanted differences. It has happened so often that the term +``Heisenbugs'' (see @url{http://en.wikipedia.org/wiki/Heisenbug}) was +coined to describe the situation where the addition of the use of a +debugger (among other possibilities) changes behavior of the program +so that the bug doesn't manifest itself anymore. + +There is another way to get into the debugger which adds no overhead +or slowdown until you reach the point at which you want to start +debugging. However here you must change the script and make an +explicit call to the debugger. Because the debugger isn't involved +before the first call, there is no overhead and the script will run +at the same speed as if there were no debugger. + +There are three parts to calling the debugger from inside the script, +``requiring'' the debugger code, telling the debugger to start +tracking things and then making the call calling the debugger to +stop. + +To get the debugger class accessible from your Ruby program: + +@smallexample +require 'rubygems' +require 'ruby-debug' +@end smallexample +(It is very likely that you've already require'd rubygems. If so, you +don't have to do that again.) These commands need to be done only +once. + +After @code{require 'ruby-debug'}, it's possible to set some of the +debugger variables influence preferences. For example if you want to +have @ttDBG run a @code{list} command every time it stops you set the +variable @code{Debugger.settings[:autolist]}. @pxref{Debugger.settings} has a +list of variable settings and the default values. Debugger settings +can also be set in @code{.rdebugrc} as debugger +commands. @pxref{Command Files} + +To tell the debugger to start tracking things: + +@smallexample +Debugger.start +@end smallexample + +There is also a @code{Debugger.stop} to turn off debugger tracking. If +speed is crucial, you may want to start and stop this around certain +sections of code. Alternatively, instead of issuing an explicit +@code{Debugger.stop} you can add a block to the @code{Debugger.start} +and debugging is turned on for that block. If the block of code raises +an uncaught exception that would cause the block to terminate, the +@code{stop} will occur. See @ref{Debugger.start with a block}. + +And finally to enter the debugger: + +@smallexample +debugger +@end smallexample + +As indicated above, when @code{debugger} is run a @code{.rdebugrc} +profile is read if that file exists. + +You may want to do enter the debugger at several points in the program +where there is a problem you want to investigate. And since +@code{debugger} is just a method call it's possible enclose it in a +conditional expression, for example: +@smallexample +debugger if 'bar' == foo and 20 == iter_count +@end smallexample + +Although each step does a very specific thing which offers great +flexibility, in order to make getting into the debugger easier the +three steps have been rolled into one command: +@smallexample +require "ruby-debug/debugger" +@end smallexample + +@node Debugger Command Reference +@chapter @code{ruby-debug} Command Reference + +@menu +* Command Interfaces:: The kinds of interface used to interact with ruby-debug +* Command Syntax:: How to give commands to the ruby-debug +* Command Output:: How rdebug presents its output +* Help:: How to ask for help (help) +* Control:: Controlling the debugger (quit, restart, interrupt) +* DisplayCommands:: Executing expressions on stop (display, undisplay) +* PrintCommands:: Evaluating and Printing Expressions (p, pp, ps, pp, irb) +* PrintVars:: Printing Variables (var) +* List:: Examining Program Source Files (list) +* Edit:: Editing source files (edit) +* FrameCommands:: Examining the stack frame (where, up, down, frame) +* Stopping:: Stopping and continuing (break, watch, step, cont...) +* ruby-debug settings:: rdebug-settings (set args, set autoeval, ...) +* Program Information:: Program Status (info) +@end menu + +@node Command Interfaces +@section Command Interfaces +There are several ways one can talk to @code{ruby-debug} and get +results. The simplest way is via a command-line interface directly +talking to the debugger. This is referred to below as a ``Local +Interface''. It's also possible to run the debugger and set up a port +by which some other process can connect and control the debug +session. This is called a ``Remote Interface''. When you want to gain +access to a remote interface you need to run @code{ruby-debug} using a +``Control Interface''. This interface might not be the same process as +the process running the debugged program and might not even be +running on the same computer. + +Other front-ends may use one of these and build on top and provide +other (richer) interfaces. Although many of the commands are available +on all interfaces some are not. Most of the time in this manual when +we talk about issuing commands describing the responses elicited, +we'll assume we are working with the local interface. + +@node Command Syntax +@section Command Syntax +Usually a command is put on a single line. There is no limit on how long +it can be. It starts with a command name, which is followed by +arguments whose meaning depends on the command name. For example, the +command @code{step} accepts an argument which is the number of times to +step, as in @code{step 5}. You can also use the @code{step} command with no +arguments. Some commands do not allow any arguments. + +Multiple commands can be put on a line by separating each with a +semicolon (@code{;}). You can disable the meaning of a semicolon to +separate commands by escaping it with a backslash. + +For example, if you have @code{autoeval} (@ref{Autoeval}) set, you +might want to enter the following code to compute the 5th Fibonacci +number: +@smallexample +# Compute the 5 Fibonaci number +(rdb:1) set autoeval on +(rdb:1) fib1=0; fib2=1; 5.times @{|temp| temp=fib1; fib1=fib2; fib2 += temp @} +SyntaxError Exception: compile error +/usr/bin/irb:10: syntax error, unexpected $end, expecting '@}' + 5.times @{|temp| temp=fib1 + ^ +(rdb:1) fib1=0\; fib2=1\; 5.times @{|temp| temp=fib1\; fib1=fib2\; fib2 += temp @} +5 +(rdb:1) fib2 +fib2 +8 +@end smallexample +You might also consider using the @code{irb} command, @ref{irb}, and +then you won't have to escape semicolons. + +A blank line as input (typing just @key{}) means to repeat the +previous command. + +In the ``local'' interface, the Ruby Readline module is used. It +handles line editing and retrieval of previous commands. Up arrow, for +example moves to the previous debugger command; down arrow moves to +the next more recent command (provided you are not already at the last +command). Command history is saved in file @code{.rdebug_hist}. A +limit is put on the history size. You can see this with the @code{show +history size} command. See @ref{History} for history parameters. + +@node Command Output +@section Command Output + +In the command-line interface, when @code{ruby-debug} is waiting for +input it presents a prompt of the form +@code{(rdb:}@emph{x}@code{)}. If debugging locally, @emph{x} will be +the thread number. Usual the main thread is 1, so often you'll see +@code{(rdb:1)}. In the control interface though @emph{x} will be +@code{ctrl} and in post-mortem debugging @code{post-mortem}. + +In the local interface, whenever @code{ruby-debug} gives an error +message such as for an invalid command, or an invalid location +position, it will generally preface the message with +@code{***}. However if annotation mode is on that the message is put +in a @code{begin-error} annotation and no @code{***} appears. + +@node Help +@section Getting help (@samp{help}) +@cindex on-line documentation +@menu +* Help for Subcommands:: +@end menu + +Once inside @code{ruby-debug} you can always ask it for information on +its commands, using the command @code{help}. + +@table @code +@kindex h @r{(@code{help})} +@kindex help @ovar{command-name} +@item help +@itemx h +You can use @code{help} (abbreviated @code{h}) with no arguments to +display a short list of named classes of commands: + +@flushleft +@smallexample +(rdb:1) @b{help} +ruby-debug help v@value{RDEBUG_VERSION} +Type 'help ' for help on a specific command + +Available commands: +backtrace delete enable help next quit show undisplay +break disable eval info p reload source up +catch display exit irb pp restart step var +condition down finish list ps save thread where +continue edit frame method putl set trace +@end smallexample +@end flushleft +@c the above line break eliminates huge line overfull... + +@end table + +@table @code +@item help @var{command} +With a command name as @code{help} argument, @DBG displays short +information on how to use that command. + +@smallexample +(rdb:1) @b{help list} +ruby-debug help v@value{RDEBUG_VERSION} +l[ist] list forward +l[ist] - list backward +l[ist] = list current line +l[ist] nn-mm list given lines +* NOTE - to turn on autolist, use 'set autolist' +(rdb:1) +@end smallexample +@end table + +@node Help for Subcommands +@subsection Help on Subcommands +A number of commands have many sub-parameters or +@emph{subcommands}. These include @code{info}, @code{set}, +@code{show}, @code{enable} and @code{disable}. + +When you ask for help for one of these commands, you will get help for +all of the subcommands that that command offers. Sometimes you may +want help that subcommand and to do this just follow the command with +its subcommand name. For example @code{help set annotate} will just +give help about the annotate command. Furthermore it will give longer +help than the summary information that appears when you ask for +help. You don't need to list the full subcommand name, but just enough +of the letters to make that subcommand distinct from others will +do. For example, @code{help set an} is the same as @code{help set annotate}. + +Some examples follow. +@example +(rdb:1) @b{help info} +Generic command for showing things about the program being debugged. +-- +List of info subcommands: +-- +info args -- Argument variables of current stack frame +info breakpoints -- Status of user-settable breakpoints +info catch -- Exceptions that can be caught in the current stack frame +info display -- Expressions to display when program stops +info file -- Info about a particular file read in +info files -- File names and timestamps of files read in +info global_variables -- Global variables +info instance_variables -- Instance variables of the current stack frame +info line -- Line number and file name of current position in source file +info locals -- Local variables of the current stack frame +info program -- Execution status of the program +info stack -- Backtrace of the stack +info thread -- List info about thread NUM +info threads -- information of currently-known threads +info variables -- Local and instance variables of the current stack frame +@end example + +@example +(rdb:1) @b{help info breakpoints} +Status of user-settable breakpoints. +Without argument, list info about all breakpoints. With an +integer argument, list info on that breakpoint. +@end example + +@example +(rdb:1) @b{help info br} +Status of user-settable breakpoints. +Without argument, list info about all breakpoints. With an +integer argument, list info on that breakpoint. +@end example + +@node Control +@section Controlling the debugger (@samp{quit}, @samp{restart}, @samp{interrupt}, @samp{source}) + +@menu +* Quit:: Quitting the debugger (quit) +* Restart:: Restarting Script execution (restart) +* Interrupt:: Interrupting the debugger (interrupt) +* Source:: Running Debugger commands (source) +@end menu + +@node Quit +@subsection Quit (@samp{quit}) +@table @code +@kindex quit @r{[}unconditionally@r{]} +@kindex q @r{(@code{quit})} +@item quit @r{[}unconditionally@r{]} +@item exit +@itemx q + +To exit @value{DBG}, use the @code{quit} command (abbreviated +@code{q}), or alias @code{exit}. + +A simple @code{quit} tries to terminate all threads in effect. + +Normally if you are in an interactive session, this command will +prompt to ask if you really want to quit. If you don't want any +questions asked, enter the ``unconditionally''. + +@end table + +@node Restart +@subsection Restart (@samp{restart}) +@table @code +@kindex restart @r{[}@var{program args}@r{]} +@kindex R @r{(@code{restart})} +@item restart +@itemx R + +Restart the program. This is is a re-exec - all debugger state is +lost. If command arguments are passed those are used. Otherwise the +last program arguments used in the last invocation are used. + +In not all cases will you be able to restart the program. First, the +program should have been invoked at the outset rather than having been +called from inside your program or invoked as a result of post-mortem +handling. + +Also, since this relies on the the OS @code{exec} call, this command +is available only if your OS supports that @code{exec}; OSX for +example does not (yet). +@end table + +@node Interrupt +@subsection Interrupt (@samp{interrupt}) +@table @code +@kindex interrupt +@kindex i +@item interrupt +@itemx i +Interrupt the program. Useful if there are multiple threads running. +@end table + +@node Source +@subsection Running Debugger Commands (@samp{source}) +@table @code +@kindex source @var{filename} +@item source @var{filename} +Execute the command file @var{filename}. + +The lines in a command file are executed sequentially. They are not +printed as they are executed. If there is an error, execution +proceeds to the next command in the file. For information about +command files that get run automatically on startup, @pxref{Command Files}. +@end table + +@node DisplayCommands +@section Executing expressions on stop (@samp{display}, @samp{undisplay}) +@cindex automatic display +@cindex display of expressions + +If you find that you want to print the value of an expression +frequently (to see how it changes), you might want to add it to the +@dfn{automatic display list} so that @value{DBG} evaluates a statement +each time your program stops or the statement is shown in line tracing. +Each expression added to the list is given a number to identify it; to +remove an expression from the list, you specify that number. The +automatic display looks like this: + +@smallexample +(rdb:1) display n +1: n = 3 +@end smallexample + +@noindent +This display shows item numbers, expressions and their current values. +If the expression is undefined or illegal the expression will be +printed but no value will appear. + +@smallexample +(rdb:1) display undefined_variable +2: undefined_variable = +(rdb:1) display 1/0 +3: 1/0 = +@end smallexample + +Note: this command uses @code{to_s} to in expressions; for example an +array @code{[1, 2]} will appear as @code{12}. For some datatypes like +an Array, you may want to call the @code{inspect} method, for example +@code{display ARGV.inspect} rather than @code{display ARGV}. + +@table @code +@kindex display @ovar{expr} +@item display @var{expr} +Add the expression @var{expr} to the list of expressions to display +each time your program stops or a line is printed when linetracing is +on (@pxref{DisplayCommands}). + +@item display +Display the current values of the expressions on the list, just as is +done when your program stops. + +@kindex undisplay @ovar{num} +@item undisplay @ovar{num} +@itemx delete display @var{num} +Remove item number @var{num} from the list of expressions to display. + +@kindex info display +@item info display +Show all display expressions + +@ifset GDB_COMPLETED +@code{undisplay} does not repeat if you press @key{RET} after using it. +(Otherwise you would just get the error @samp{No display number @dots{}}.) +@end ifset + +@kindex disable display +@item disable display @var{dnums}@dots{} +Disable the display of item numbers @var{dnums}. A disabled display +item is not printed automatically, but is not forgotten. It may be +enabled again later. + +@kindex enable display +@item enable display @var{dnums}@dots{} +Enable display of item numbers @var{dnums}. It becomes effective once +again in auto display of its expression, until you specify otherwise. + +@end table + +@node PrintCommands +@section Evaluating and Printing Expressions (@samp{p}, @samp{pp}, @samp{putl}, @samp{ps}, @samp{irb}) + +One way to examine and change data in your script is with the +@code{eval} command (abbreviated @code{p}). A similar command is +@code{pp} which tries to pretty print the result. Finally @code{irb} is +useful when you anticipate examining or changing a number of things, +and prefer not to have to preface each command, but rather work as one +does in @code{irb}. + +@menu +* eval:: eval or print an expression (eval, p) +* pp:: pretty print an expression (pp, ps, putl) +* irb:: running irb using the current context +@end menu + +@node eval +@subsection Printing an expression (@samp{eval}, @samp{p}) +@table @code +@kindex eval @var{expr} +@kindex p @r{(@code{eval})} +@item eval @var{expr} +@itemx p @var{expr} + +Use @code{eval} or @code{p} to evaluate a Ruby expression, @var{expr}, +same as you would if you were in @code{irb}. If there are many expressions +you want to look at, you may want to go into irb from the debugger. +@smallexample +@group +(rdb:p) p n +3 +(rdb:1) p "the value of n is #@{n@}" +"the value of n is 3" +(rdb:1) +@end group +@end smallexample +@end table + +@node pp +@subsection Pretty-Printing an expression (@samp{pp}, @samp{putl}, @samp{ps})) +@table @code +@item pp +@kindex pp @var{expr} +Evaluates and pretty-prints @var{expr} +@smallexample +@group +(rdb:1) @b{p $LOAD_PATH} +["/home/rocky/lib/ruby", "/usr/lib/ruby/site_ruby/1.8", "/usr/lib/ruby/site_ruby/1.8/i586-linux", "/usr/lib/ruby/1.8"] +(rdb:1) @b{pp $LOAD_PATH} +["/home/rocky/lib/ruby", + "/usr/lib/ruby/site_ruby/1.8", + "/usr/lib/ruby/site_ruby/1.8/i586-linux", + "/usr/lib/ruby/1.8"] +@end group +@end smallexample +@kindex putl +@item putl +If the value you want to print is an array, sometimes a columnized +list looks nicer: +@smallexample +@group +(rdb:1) @b{putl $LOAD_PATH} +/home/rocky/lib/ruby /usr/lib/ruby/site_ruby/1.8 +/usr/lib/ruby/site_ruby/1.8/i586-linux /usr/lib/ruby/1.8 +@end group +@end smallexample + +Note however that entries are sorted to run down first rather than +across. So in the example above the second entry in the list is +@code{/usr/lib/ruby/site_ruby/1.8/i586-linux} and the @emph{third} entry is +@code{/usr/lib/ruby/site_ruby/1.8}. + +If the value is not an array @code{putl} will just call pretty-print. +@kindex ps +@item ps +Sometimes you may want to print the array not only columnized, but +sorted as well. The list of debugger help commands appears this way, +and so does the output of the @code{method} commands. + +@smallexample +@group +(rdb:1) ps Kernel.private_methods +Digest initialize y +Pathname initialize_copy +Rational location_of_caller +active_gem_with_options method_added +alias_method method_removed +append_features method_undefined +attr module_function +attr_accessor private +attr_reader protected +attr_writer public +class_variable_get remove_class_variable +class_variable_set remove_const +define_method remove_instance_variable +extend_object remove_method +extended singleton_method_added +gcd singleton_method_removed +gem_original_require singleton_method_undefined +include timeout +included undef_method +@end group +@end smallexample + +If the value is not an array, @code{ps} will just call pretty-print. +See also the @code{methods}. +@end table + +@node irb +@subsection Run irb (@samp{irb}) +@table @code +@kindex irb +@item irb +Run an interactive ruby session (@code{irb}) with the bindings +environment set to the state you are in the program. + +When you leave irb and go back to the debugger command prompt we show +again the file, line and text position of the program in the same way +as when entered the debugger. If you issue a @command{list} without +location information, the default location used is the current line +rather than the position may have gotten updated via a prior +@command{list} command. +@smallexample +triangle.rb:4 +def triangle(n) +(rdb:1) @b{list} +[-1, 8] in /home/rocky/ruby/triangle.rb + 1 #!/usr/bin/env ruby + 2 # Compute the n'th triangle number - the hard way + 3 # triangle(n) == (n * (n+1)) / 2 +=> 4 def triangle(n) + 5 tri = 0 + 6 0.upto(n) do |i| + 7 tri += i + 8 end +@b{irb} +>> @b{(0..6).inject@{|sum, i| sum +=i@}} +=> 21 +>> @b{exit} +triangle.rb:4 +def triangle(n) +(rdb:1) @b{list # Note we get the same line range as before going into irb} +[-1, 8] in /home/rocky/ruby/triangle.rb + 1 #!/usr/bin/env ruby + 2 # Compute the n'th triangle number - the hard way + 3 # triangle(n) == (n * (n+1)) / 2 +=> 4 def triangle(n) + 5 tri = 0 + 6 0.upto(n) do |i| + 7 tri += i + 8 end +@end smallexample + +@end table + +@node PrintVars +@section Printing Variables (@samp{var}, @samp{method}) + +@table @code +@item var const @var{object} +@kindex var const @var{expr} +Show the constants of @var{object}. This is basically listing +variables and their values in @var{object}@code{.constant}. +@item var instance @var{object} +@kindex var instance @var{expr} +Show the instance variables of @var{object}. This is basically listing +@var{object}@code{.instance_variables}. +@item info instance_variables +@kindex info instance_variables +Show instance_variables of @code{@@self} +@item info locals +@kindex info locals +Show local variables +@item info globals +@kindex info globals +Show global variables +@item info variables +@kindex info variables +Show local and instance variables of @code{@@self} +@item method instance @var{object} +@kindex method instance @var{object} +Show methods of @var{object}. Basically this is the same as running +@code{ps object.instance_methods(false)} on @var{object}. +@item method iv @var{object} +@kindex method iv @var{object} +Show method instance variables of @var{object}. Basically this is the same as running +@smallexample + obj.instance_variables.each do |v| + puts "%s = %s\n" % [v, obj.instance_variable_get(v)] + end +@end smallexample +on @var{object}. +@item signature @var{object} +@kindex method signature @var{object} +Show procedure signature of method @var{object}. +@emph{This command is available only if the nodewrap is installed.} +@smallexample + def mymethod(a, b=5, &bock) + end + (rdb:1) @b{method sig mymethod} + Mine#mymethod(a, b=5, &bock) +@end smallexample +on @var{object}. +@item method @var{class-or-module} +@kindex method @var{class-or-module} +Show methods of the class or module, @var{class-or-module}. Basically +this is the same as running @code{ps object.methods} on @var{class-or-module}. +on @var{class-or-module}. +@end table + +@node List +@section Examining Program Source Files (@samp{list}) + +@cindex current line +@value{DBG} can print parts of your script's source. When your script +stops, @value{DBG} spontaneously prints the line where it stopped and +the text of that line. Likewise, when you select a stack frame +(@pxref{Selection}) @value{DBG} prints the line where execution in +that frame has stopped. Implicitly there is a default line +location. Each time a list command is run that implicit location is +updated, so that running several list commands in succession shows a +contiguous block of program text. + +You can print other portions of source files by giving an explicit +position as a parameter to the list command. + +If you use @value{DBG} through its Emacs interface, you may prefer to +use Emacs facilities to view source. +@c @pxref{GNU Emacs}. + +@kindex list @ovar{line-number} +@kindex l @r{(@code{list})} +To print lines from a source file, use the @code{list} command +(abbreviated @code{l}). By default, ten lines are printed. Fewer may +appear if there fewer lines before or after the current line to center +the listing around. + +There are several ways to specify what part of the file you want to print. +Here are the forms of the @code{list} command. + +@table @code +@item list @var{line-number} +@itemx l @var{line-number} +Print lines centered around line number @var{line-number} in the +current source file. + +@item list +@itemx l +Print more lines. If the last lines printed were printed with a +@code{list} command, this prints lines following the last lines +printed; however, if the last line printed was a solitary line printed +as part of displaying a stack frame (@pxref{Frames}), this prints lines +centered around that line. + +@item list - +@itemx l - +Print lines just before the lines last printed. +@item list @var{first}-@var{last} +Print lines between @var{first} and @var{last} inclusive. + +@item list = +Print lines centered around where the script is stopped. +@end table + +Repeating a @code{list} command with @key{RET} discards the argument, +so it is equivalent to typing just @code{list}. This is more useful +than listing the same lines again. An exception is made for an +argument of @samp{-}; that argument is preserved in repetition so that +each repetition moves up in the source file. + +@node Edit +@section Editing Source files (@samp{edit}) + +To edit the lines in a source file, use the @code{edit} command. The +editing program of your choice is invoked with the current line set to +the active line in the program. Alternatively, you can give a line +specification to specify what part of the file you want to print if +you want to see other parts of the program. + +You can customize to use any editor you want by using the +@code{EDITOR} environment variable. The only restriction is that your +editor (say @code{ex}), recognizes the following command-line syntax: +@smallexample +ex +@var{number} file +@end smallexample +The optional numeric value +@var{number} specifies the number of the +line in the file where to start editing. For example, to configure +@value{DBG} to use the @code{vi} editor, you could use these commands +with the @code{sh} shell: +@smallexample +EDITOR=/usr/bin/vi +export EDITOR +gdb @dots{} +@end smallexample +or in the @code{csh} shell, +@smallexample +setenv EDITOR /usr/bin/vi +gdb @dots{} +@end smallexample + +@table @code +@kindex edit @ovar{line-specification} +@item edit @ovar{line specification} +Edit line specification using the editor specified by the +@code{EDITOR} environment variable. +@end table + +@node FrameCommands +@section Examining the Stack Frame (@samp{where}, @samp{up}, @samp{down}, @samp{frame}) + +When your script has stopped, one thing you'll probably want to know +is where it stopped and some idea of how it got there. + +@cindex call stack +Each time your script performs a function or sends a message to a +method, or enters a block, information about this action is saved. +The frame stack then is this a history of the blocks that got you to +the point that you are currently stopped at.@footnote{More accurately +we should call this a ``block stack''; but we'll use the name that is +more commonly used. And internally in Ruby, there is ``FRAME'' +structure which is yet slightly different.} + +@cindex selected block +One entry in call stack is @dfn{selected} by @DBG{} and many +@DBG commands refer implicitly to the selected block. In +particular, whenever you ask @DBG to list lines without giving +a line number or location the value is found in the selected frame. +There are special @DBG commands to select whichever frame you +are interested in. @xref{Selection, ,Selecting a frame}. + +When your program stops, @DBG{} automatically selects the +currently executing frame and describes it briefly, similar to the +@code{frame} command. + +After switching frames, when you issue a @code{list} command without +any position information, the position used is location in the frame +that you just switched between, rather than a location that got +updated via a prior @code{list} command. + +@menu +* Frames:: Stack frames +* Backtrace:: Backtraces (where) +* Selection:: Selecting a frame (up, down, frame) + +@end menu + +@node Frames +@subsection Stack frames + +@cindex frame, definition +@cindex stack frame +The block stack is divided up into contiguous pieces called @dfn{stack +frames}, @dfn{frames}, or @dfn{blocks} for short; each frame/block has +a scope associated with it; It contains a line number and the +source-file name that the line refers. If the frame/block is the beginning +of a method or function it also contains the function name. + +@cindex initial frame +@cindex outermost frame +@cindex innermost frame +When your script is started, the stack has only one frame, that of the +function @code{main}. This is called the @dfn{initial} frame or the +@dfn{outermost} frame. Each time a function is called, a new frame is +made. Each time a function returns, the frame for that function invocation +is eliminated. If a function is recursive, there can be many frames for +the same function. The frame for the function in which execution is +actually occurring is called the @dfn{innermost} frame. This is the most +recently created of all the stack frames that still exist. + +@cindex frame number +@value{DBG} assigns numbers to all existing stack frames, starting with +zero for the innermost frame, one for the frame that called it, +and so on upward. These numbers do not really exist in your script; +they are assigned by @value{DBG} to give you a way of designating stack +frames in @value{DBG} commands. + +@node Backtrace +@subsection Backtraces (@samp{where}) + +@cindex backtraces +@cindex tracebacks +@cindex stack traces +A backtrace is essentially the same as the call stack: a summary of +how your script got where it is. It shows one line per frame, for +many frames, starting with the place that you are stopped at (frame +zero), followed by its caller (frame one), and on up the stack. + +@table @code +@kindex where +@kindex w @r{(@code{where})} +@itemx where +Print the entire stack frame; @code{info stack} is an alias for this command. +Each frame is numbered and can be referred to in the @code{frame} +command; @code{up} and @code{down} add or subtract respectively to +frame numbers shown. The position of the current frame is marked with +@code{-->}. + +@smallexample +(rdb:1) where +--> #0 Object.gcd(a#Fixnum, b#Fixnum) at line /tmp/gcd.rb:6 + #1 at line /tmp/gcd.rb:19 +@end smallexample + +@ifset FINISHED +@item backtrace @var{n} +@itemx bt @var{n} +@itemx where @var{n} +@itemx T @var{n} +Similar, but print only the innermost @var{n} frames. + +@item backtrace -@var{n} +@itemx bt -@var{n} +@itemx where -@var{n} +@itemx T -@var{n} +Similar, but print only the outermost @var{n} frames. +@end ifset +@end table + +@node Selection +@subsection Selecting a frame (@samp{up}, @samp{down}, @samp{frame}) + +Commands for listing source code in your script work on whichever +stack frame is selected at the moment. Here are the commands for +selecting a stack frame; all of them finish by printing a brief +description of the stack frame just selected. + +@table @code +@kindex up @ovar{n} +@item up @ovar{n} +Move @var{n} frames up the stack. For positive numbers @var{n}, this +advances toward the outermost frame, to higher frame numbers, to +frames that have existed longer. Using a negative @var{n} is the same thing +as issuing a @code{down} command of the absolute value of the @var{n}. +Using zero for @var{n} does no frame adjustment, but since the current +position is redisplayed, it may trigger a resynchronization if there is +a front end also watching over things. + +@var{n} defaults to one. You may abbreviate @code{up} as @code{u}. + +@kindex down @ovar{n} +@item down @ovar{n} +Move @var{n} frames down the stack. For positive numbers @var{n}, this +advances toward the innermost frame, to lower frame numbers, to frames +that were created more recently. Using a negative @var{n} is the same +as issuing a @code{up} command of the absolute value of the @var{n}. +Using zero for @var{n} does no frame adjustment, but since the current +position is redisplayed, it may trigger a resynchronization if there is +a front end also watching over things. + +@var{n} defaults to one. +@end table + +@table @code +@kindex frame @r{[}@ovar{n} @r{[}thread @var{thread-num}@r{]}@r{]} +@cindex current stack frame +@item frame @ovar{n} @r{[}thread @var{thread-num}@r{]} +The @code{frame} command allows you to move from one stack frame to +another, and to print the stack frame you select. @var{n} is the the +stack frame number or 0 if no frame number is given; @code{frame 0} +then will always show the current and most recent stack frame. + +If a negative number is given, counting is from the other end of the +stack frame, so @code{frame -1} shows the least-recent, outermost or +most ``main'' stack frame. + +Without an argument, @code{frame} prints the current stack +frame. Since the current position is redisplayed, it may trigger a +resynchronization if there is a front end also watching over +things. + +If a thread number is given then we set the context for evaluating +expressions to that frame of that thread. +@end table + +@node Stopping +@section Stopping and Resuming Execution + +One important use of a debugger is to stop your program @emph{before} +it terminates, so that if your script runs into trouble you can +investigate and find out why. However should your script accidentally +continue to termination, it can be arranged for @DBG to not to leave +the debugger without your explicit instruction. That way, you can +restart the program using the same command arguments. + +Inside @value{DBG}, your script may stop for any of several reasons, +such as a signal, a breakpoint, or reaching a new line after a +debugger command such as @code{step}. You may then examine and +change variables, set new breakpoints or remove old ones, and then +continue execution. + +@menu +* Breakpoints:: Breakpoints (break, catch, delete) +* Disabling:: Disabling breakpoints (disable, enable) +* Conditions:: Break conditions (condition) +* Resuming Execution:: Resuming execution (continue, step, next, finish) +@end menu + +@node Breakpoints +@subsection Breakpoints (@samp{break}, @samp{catch}, @samp{delete}) + +@cindex breakpoints +A @dfn{breakpoint} makes your script stop whenever a certain point in +the program is reached. For each breakpoint, you can add conditions to +control in finer detail whether your script stops. + +You specify the place where your script should stop with the +@code{break} command and its variants. + +@cindex breakpoint numbers +@cindex numbers for breakpoints +@value{ttDBG} assigns a number to each breakpoint when +you create it; these numbers are successive integers starting with +one. In many of the commands for controlling various features of +breakpoints you use the breakpoint number to say which breakpoint you +want to change. Each breakpoint may be @dfn{enabled} or +@dfn{disabled}; if disabled, it has no effect on your script until you +enable it again. + + +@table @code +@kindex break @ovar{location} +@kindex b @r{(@code{break})} +@item break +Set a breakpoint at the current line. + +@item break @var{linenum} +Set a breakpoint at line @var{linenum} in the current source file. +The current source file is the last file whose source text was printed. +The breakpoint will stop your script just before it executes any of the +code on that line. + +@item break @var{filename}:@var{linenum} +Set a breakpoint at line @var{linenum} in source file @var{filename}. + +What may be a little tricky when specifying the filename is getting +the name recognized by the debugger. If you get a message the message +``@code{No source file named ...}'', then you may need to qualify the +name more fully. To see what files are loaded you can use the @code{info +files} or @code{info file} commands. If you want the name @code{rdebug} thinks +of as the current file, use @code{info line}. + +Here's an example: +@example +$ @b{rdebug ~/ruby/gcd.rb 3 5} +/home/rocky/ruby/gcd.rb:4 # Note this is the file name +def gcd(a, b) +(rdb:1) @b{break gcd.rb:6} +*** No source file named gcd.rb +(rdb:1) @b{info line} +Line 4 of "/home/rocky/ruby/gcd.rb" +(rdb:1) @b{break /home/rocky/ruby/gcd.rb:6} +Breakpoint 1 file /home/rocky/ruby/gcd.rb, line 6 +(rdb:1) @b{break ~/ruby/gcd.rb:10} # tilde expansion also works +Breakpoint 2 file /home/rocky/ruby/gcd.rb, line 10 +(rdb:1) @b{info file gcd.rb} +File gcd.rb is not cached +(rdb:1) @b{info file /home/rocky/ruby/gcd.rb} +File /home/rocky/ruby/gcd.rb + 19 lines +@end example + +@item break @var{class}:@var{method} +Set a breakpoint in class @var{class} method @var{method}. You can +also use a period @code{.} instead of a colon @code{:}. Note that two +colons @code{::} are not used. Also note a class @emph{must} be +specified here. If the method you want to stop in is in the main class +(i.e. the class that @code{self} belongs to at the start of the +program), then use the name @code{Object}. + +@kindex catch @ovar{exception} @r{[} on | 1 | off | 0 @r{]} +@kindex cat @r{(@code{catch})} +@item catch @ovar{exception} @r{[} on | 1 | off | 0 @r{]} +Set catchpoint to an exception. Without an exception name show catchpoints. + +With an ``on'' or ``off'' parameter, turn handling the exception on or +off. To delete all exceptions type ``catch off''. + +@cindex delete breakpoints +@kindex delete @ovar{breakpoints} +@kindex del @r{(@code{delete})} +@item delete @ovar{breakpoints} +Delete the breakpoints specified as arguments. + +If no argument is specified, delete all breakpoints (@DBG asks +confirmation. You can abbreviate this command as @code{del}. +@kindex info breakpoints +@cindex @code{$_} and @code{info breakpoints} +@item info breakpoints @ovar{n} +@itemx info break @ovar{n} +Print a table of all breakpoints set and not deleted, with the +following columns for each breakpoint: + +@table @emph +@item Breakpoint Numbers (@samp{Num}) +@item Enabled or Disabled (@samp{Enb}) +Enabled breakpoints are marked with @samp{1}. @samp{0} marks breakpoints +that are disabled (not enabled). +@item File and Line (@samp{file:line}) +The filename and line number inside that file where of breakpoint in +the script. The file and line are separated with a colon. +@item Condition +A condition (an arithmetic expression) which when true causes the +breakpoint to take effect. +@end table +@noindent +If a breakpoint is conditional, @code{info break} shows the condition on +the line following the affected breakpoint; breakpoint commands, if any, +are listed after that. + +@code{info break} with a breakpoint number @var{n} as argument lists +only that breakpoint. + +Examples: +@example +(rdb:1) @b{info break} +Breakpoints at following places: +Num Enb What +1 y gcd.rb:3 +2 y gcb.rb:28 if n > 1 +(rdb:1) @b{info break 2} +2 y gcb.rb:28 if n > 1 +@end example +@end table + +@node Disabling +@subsection Disabling breakpoints (@samp{disable}, @samp{enable}) + +Rather than deleting a breakpoint, you might +prefer to @dfn{disable} it. This makes the breakpoint inoperative as if +it had been deleted, but remembers the information on the breakpoint so +that you can @dfn{enable} it again later. + +You disable and enable breakpoints and catchpoints with the +@code{enable} and @code{disable} commands, optionally specifying one +or more breakpoint numbers as arguments. Use @code{info break} to +print a list of breakpoints and catchpoints if you do not know which +numbers to use. + +A breakpoint or catchpoint can have any different +states of enablement: + +@itemize @bullet +@item +Enabled. The breakpoint stops your program. A breakpoint set +with the @code{break} command starts out in this state. +@item +Disabled. The breakpoint has no effect on your program. +@end itemize + +You can use the following commands to enable or disable breakpoints +and catchpoints: + +@table @code +@kindex disable breakpoints +@item disable @var{breakpoints} +Disable the specified breakpoints---or all breakpoints, if none are +listed. A disabled breakpoint has no effect but is not forgotten. All +options such as ignore-counts, conditions and commands are remembered in +case the breakpoint is enabled again later. You may abbreviate +@code{disable} as @code{dis}. + +@kindex enable breakpoints +@item enable @var{breakpoints} +Enable the specified breakpoints (or all defined breakpoints). They +become effective once again in stopping your program. + +@end table + +Breakpoints that you set are initially enabled; subsequently, they +become disabled or enabled only when you use one of the commands +above. (The command @code{until} can set and delete a breakpoint of +its own, but it does not change the state of your other breakpoints; +see @ref{Resuming Execution, ,Resuming Execution}.) + +@node Conditions +@subsection Break conditions (@samp{condition}) +@cindex conditional breakpoints +@cindex breakpoint conditions + +The simplest sort of breakpoint breaks every time your script reaches +a specified place. You can also specify a @dfn{condition} for a +breakpoint. A condition is just a Ruby expression. + +Break conditions can be specified when a breakpoint is set, by using +@samp{if} in the arguments to the @code{break} command. A breakpoint +with a condition evaluates the expression each time your script +reaches it, and your script stops only if the condition is +@emph{true}. They can also be changed at any time +with the @code{condition} command. + +@ifset FINISHED +You can also use the @code{if} keyword with the @code{watch} command. +The @code{catch} command does not recognize the @code{if} keyword; +@code{condition} is the only way to impose a further condition on a +catchpoint. +@end ifset + +@table @code +@kindex condition +@item condition @var{bnum} @var{expression} +Specify @var{expression} as the break condition for breakpoint +@var{bnum}. After you set a condition, breakpoint @var{bnum} stops +your program only if the value of @var{expression} is true (nonzero). + +@item condition @var{bnum} +Remove the condition from breakpoint number @var{bnum}. It becomes +an ordinary unconditional breakpoint. +@end table + +@ifset FINISHED +When you use @code{condition}, @DBG checks @var{expression} +immediately for syntactic correctness, and to determine whether +symbols in it have referents in the context of your breakpoint. If +@var{expression} uses symbols not referenced in the context of the +breakpoint, @DBG prints an error message: + +@example +No symbol "foo" in current context. +@end example +@end ifset + +@noindent +The debugger does not actually evaluate @var{expression} at the time +the @code{condition} command (or a command that sets a breakpoint with +a condition, like @code{break if @dots{}}) is given, however. + +Examples; +@example +condition 1 x>5 # Stop on breakpoint 0 only if x>5 is true. +condition 1 # Change that! Unconditionally stop on breakpoint 1. +@end example + +@node Resuming Execution +@subsection Resuming Execution (@samp{step}, @samp{next}, @samp{finish}, @samp{continue}) + +A typical technique for using stepping is to set a breakpoint +(@pxref{Breakpoints}) at the beginning of the function or the section +of your script where a problem is believed to lie, run your script +until it stops at that breakpoint, and then step through the suspect +area, examining the variables that are interesting, until you see the +problem happen. + +@cindex stepping +@cindex continuing +@cindex resuming execution +@dfn{Continuing} means resuming program execution until your script +completes normally. In contrast, @dfn{stepping} means executing just +one more ``step'' of your script, where ``step'' may mean either one +line of source code. Either when continuing or when stepping, +your script may stop even sooner, due to a breakpoint or a signal. + +@menu +* Step:: running the next statement (step) +* Next:: running the next statement skipping over functions (next) +* Finish:: running until the return of a function or ``source'' (finish) +* Continue:: continuing execution (continue) +@end menu + +@node Step +@subsubsection Step (@samp{step}) +@table @code +@kindex step @r{[}+@r{]} @ovar{count} +@kindex s @r{(@code{step})} +@item step @r{[}+-@r{]} @ovar{count} +Continue running your program until the next logical stopping point +and return control to @value{DBG}. This command is abbreviated +@code{s}. + +Like, the programming Lisp, Ruby tends implemented in a highly +expression-oriented manner. Therefore things that in other languages +that may appear to be a single statement are implemented in Ruby as +several expressions. For example, in an ``if'' statement or looping +statements a stop is made after the expression is evaluated but before +the test on the expression is made. + +So it is common that a lines in the program will have several stopping +points where in other debuggers of other languages there would be only +one. Or you may have several statements listed on a line. + +When stepping it is not uncommon to want to go to a different line on +each step. If you want to make sure that on a step you go to a +@emph{different} position, add a plus sign (@samp{+}). + +@emph{Note: step+ with a number count is not the same as issuing +count step+ commands. Instead it uses count-1 step commands followed +by a step+ command. For example, @code{step+ 3} is the +same as @code{step; step; step+}, not @code{step+; step+; step+}} + +If you find yourself generally wanting to use @code{step+} rather +than @code{step}, you may want to consider using @code{set +forcestep}, (@pxref{Forcestep}). + +If you have @code{forcestep} set on but want to temporarily disable it +for the next step command, append a minus, or @code{step-}. + +With a count, @code{step} will continue running as normal, but do so +@var{count} times. If a breakpoint is reached, or a signal not +related to stepping occurs before @var{count} steps, stepping stops +right away. +@end table + +@node Next +@subsubsection Next (@samp{next}) +@table @code +@kindex next @r{[}+-@r{]} @ovar{count} +@kindex n @r{(@code{next})} +@item next @r{[}+@r{]} @ovar{count} +This is similar to @code{step}, but function or method calls that +appear within the line of code are executed without stopping. As with +step, if you want to make sure that on a step you go to a +@emph{different} position, add a plus sign (@samp{+}). Similarly, +appending a minus disables a @code{forcestep} temporarily, and an +argument @var{count} is a repeat count, as for @code{step}. +@end table + +@node Finish +@subsubsection Finish (@samp{finish}) +@table @code +@kindex finish @ovar{frame-number} +@item finish @ovar{frame-number} +Execute until selected stack frame returns. If no frame number is +given, we run until the currently selected frame returns. The +currently selected frame starts out the most-recent frame or 0 if no +frame positioning (e.g@: @code{up}, @code{down} or @code{frame}) has +been performed. If a frame number is given we run until @var{frame} frames +returns. + +If you want instead to terminate the program and debugger entirely, +use @code{quit} (@pxref{Quitting the debugger, ,Quitting the debugger}). + +@emph{Note:} Releases before Ruby version 1.8.7 show the return line +as the first line of the method. Starting with version 1.8.7, the last +line executed will be shown as the return +line. @url{http://rubyforge.org/tracker/?func=detail&atid=22040&aid=18749&group_id=426} + +@end table + +@node Continue +@subsubsection Continue (@samp{continue}) +@table @code +@kindex continue @ovar{line-specification} +@kindex c @r{(@code{continue})} +@item continue @ovar{line-specification} +@itemx c @ovar{line-specification} +Resume program execution, at the address where your script last +stopped; any breakpoints set at that address are bypassed. + +The optional argument @var{line-specification} allows you to specify a +line number to set a one-time breakpoint which is deleted when that +breakpoint is reached. + +Should the program stop before that breakpoint is reached, for +example, perhaps another breakpoint is reached first, in +a listing of the breakpoints you won't see this entry in the list of +breakpoints. +@end table + +@node ruby-debug settings +@section ruby-debug settings (@samp{set args}, @samp{set autoeval}..) + +You can alter the way ruby-debug interacts with you using @code{set} +commands. + +The various parameters to @code{set} are given below. Each parameter +name needs to to be only enough to make it unique. For example +@code{set force} is a suitable abbreviation for @code{set forcestep}. +The letter case is not important, so @code{set FORCE} or @code{set +Force} are also suitable abbreviations. + +Many @code{set} commands are either ``on'' or ``off'', and you can +indicate which way you want set by supplying the corresponding +word. The number 1 can be used for ``on'' and 0 for ``off''. If none +of these is given, we will assume ``on''. A deprecated way of turning +something off is by prefacing it with ``no''. + +Each @code{set} command has a corresponding @code{show} command which +allows you to see the current value. + +@menu +* Args:: Annotation Level +* Autoeval:: Evaluate unrecognized commands +* Autolist:: Execute ``list'' command on every breakpoint +* Autoirb:: Invoke IRB on every stop +* Autoreload:: Reload source code when changed +* Basename:: Report file basename only showing file names +* Callstyle:: Show Report file basename only showing file names +* Forcestep:: Make sure 'next/step' commands always move to a new line +* Fullpath:: Display full file names in frames +* History:: Generic command for showing command history parameters. +* Keepframebindings:: Save frame binding on each call +* Linetrace:: line execution tracing +* Linetrace+:: line tracing style +* Listsize:: Number of lines to try to show in a 'list' command +* Post-mortem:: Whether post-mortem handling is in effect. +* Trace:: Display stack trace when 'eval' raises exception +* Width:: Number of characters the debugger thinks are in a line +@end menu + +@node Args +@subsection Set/Show args + +@table @code +@kindex set args @ovar{parameters} +@item set args @ovar{parameters} +Specify the arguments to be used if your program is rerun. If +@code{set args} has no arguments, @code{restart} executes your program +with no arguments. Once you have run your program with arguments, +using @code{set args} before the next @code{restart} is the only way to run +it again without arguments. + +@kindex show args +@item show args +Show the arguments to give your program when it is started. +@end table + +@node Autoeval +@subsection Set/Show auto-eval + +@table @code +@kindex set autoeval @r{[} on | 1 | off | 0 @r{]} +@item set autoeval @r{[} on | 1 | off | 0 @r{]} +Specify that debugger input that isn't recognized as a command should +be passed to Ruby for evaluation (using the current debugged program +namespace). Note however that we @emph{first} check input to see if it +is a debugger command and @emph{only} if it is not do we consider it +as Ruby code. This means for example that if you have variable called +@code{n} and you want to see its value, you could use @code{p n}, +because just entering @code{n} will be interpreted as the debugger +``next'' command. + +See also @ref{irb} and @ref{Autoirb}. + +When autoeval is set on, you'll get a different error message when you +invalid commands are encountered. Here's a session fragment to show +the difference +@smallexample +(rdb:1) @b{stepp} +Unknown command +(rdb:1) @b{set autoeval on} +autoeval is on. +(rdb:1) @b{stepp} +NameError Exception: undefined local variable or method `stepp' for ... +@end smallexample + +@kindex show autoeval +@item show args +Shows whether Ruby evaluation of debugger input should occur or not. +@end table + +@node Autolist +@subsection Execute ``list'' command on every breakpoint + +@node Autoirb +@subsection Set/Show auto-irb + +@table @code +@kindex set autoirb @r{[} on | 1 | off | 0 @r{]} +@item set autoirb @r{[} on | 1 | off | 0 @r{]} + +When your program stops, normally you go into a debugger command loop +looking for debugger commands. If instead you would like to directly +go into an irb shell, set this on. See also @ref{Autoeval} or +@ref{irb} if you tend to use debugger commands but still want Ruby +evaluation occasionally. + +@kindex show autoirb +@item show autoirb +Shows whether the debugger will go into irb on stop or not. +@end table + +@node Autoreload +@subsection Set/Show auto-reload +@table @code +@kindex set autoreload @r{[} on | 1 | off | 0 @r{]} +Set this on if the debugger should check to see if the source has +changed since the last time it reread in the file if it has. +@end table + +@node Basename +@subsection Set/Show basename + +@table @code +@kindex set basename @r{[} on | 1 | off | 0 @r{]} +@item set basename @r{[} on | 1 | off | 0 @r{]} +Source filenames are shown as the shorter ``basename'' +only. (Directory paths are omitted). This is useful in running the +regression tests and may useful in showing debugger examples as in +this text. You may also just want less verbose filename display. + +By default filenames are shown as with their full path. + +@kindex show basename +@item show basename +Shows the whether filename display shows just the file basename or not. +@end table + +@node Callstyle +@subsection Set/Show call style + +@table @code +@ifset FINISHED +@kindex set callstyle @r{[} short | last | tracked @r{]} +@item set forcestep @r{[} short | last | tracked @r{]} +@else +@kindex set callstyle @r{[} short | last +@item set forcestep @r{[} short | last +@end ifset + +Sets how you want call parameters displayed; @code{short} shows just +the parameter names; +@ifset FINISHED +@code{last} shows the parameter names and the +class of these variables as they currently exist. Note the type could +have changed between when the call and its current +values. +@end ifset +@code{tracked} is the most accurate but this adds +overhead. On every call, scalar values of the parameters get +saved. For non-scalar values the class is saved. +@end table + +@node Forcestep +@subsection Set/Show Forces Different Line Step/Next + +@table @code +@kindex set forcestep @r{[} on | 1 | off | 0 @r{]} +@item set forcestep @r{[} on | 1 | off | 0 @r{]} + +Due to the interpretive, expression-oriented nature of the Ruby +Language and implementation, each line often contains many possible +stopping points, while in a debugger it is often desired to treat each +line as an individual stepping unit. + +Setting forcestep on will cause each @code{step} or @code{next} +command to stop at a different line number. See also @ref{Step} and +@ref{Next}. + +@kindex show forcestep +@item show forcestep +Shows whether forcestep is in effect or not. +@end table + +@node Fullpath +@subsection Set/Show Frame full path + +@node History +@subsection Command History Parameters +@table @code +@item show commands +@kindex show commands +Display the last ten commands in the command history. + +@item show commands @var{n} +@kindex show commands @var{n} +Print ten commands centered on command number @var{n}. + +@item show history filename +@kindex show history filename +Show the filename in which to record the command history +(the list of previous commands of which a record is kept). + +@item set history save @r{[} on | 1 | off | 0 @r{]} +@kindex set history save @r{[} on | 1 | off | 0 @r{]} +Set whether to save the history on exit. + +@item show history save +@kindex show history save +Show saving of the history record on exit. + +@item set history size @var{number} +@kindex set history size @var{number} +Set the maximum number of commands to save in the history. + +@item show history size +@kindex show history size +Show the size of the command history, i.e. the number of previous +commands to keep a record of. +@end table + +@node Keepframebindings +@subsection Save frame binding on each call + +@node Linetrace +@subsection Set/Show Line tracing + +@table @code +@kindex set linetrace @r{[} on | 1 | off | 0 @r{]} +@item set linetrace @r{[} on | 1 | off | 0 @r{]} + +Setting linetrace on will cause lines to be shown before run. + +@kindex show linetrace +@item show linetrace +Shows whether line tracing is in effect or not. +@end table + +@node Linetrace+ +@subsection Set/Show Line tracing style + +@table @code +@kindex set linetrace+ @r{[} on | 1 | off | 0 @r{]} +@item set linetrace+ @r{[} on | 1 | off | 0 @r{]} + +Setting linetrace+ on will cause consecutive trace lines not to be a +duplicate of the preceding line-trace line. Note however that this +setting doesn't by itself turn on or off line tracing. + +@kindex show linetrace+ +@item show linetrace +Shows whether the line tracing style is to show all lines or remove +duplicates linetrace lines when it is a repeat of the previous line. +@end table + +@node Listsize +@subsection Set/Show lines in a List command + +@table @code +@kindex set listsize @var{number-of-lines} +@item set listsize @var{number-of-lines} +Set number of lines to try to show in a @code{list} command. +@kindex show listsize +@item show listsize +Shows the list-size setting. +@end table + +@node Post-mortem +@subsection Show Post-mortem handling +@table @code +@kindex show post-mortem +Shows wither post-mortem debugging is in effect. Right now we don't +have the ability to change the state inside the debugger. +@end table + +@node Trace +@subsection Display stack trace when 'eval' raises exception + +@node Width +@subsection Set/Show Line width + +@table @code +@kindex set width @var{column-width} +@item set width @var{column-width} +Set number of characters the debugger thinks are in a line. +We also change OS environment variable @code{COLUMNS}. +@kindex show width +@item show width +Shows the current width setting. +@end table + +@node Program Information +@section Program Information (@samp{info}) + +This @code{info} command (abbreviated @code{i}) is for describing the +state of your program. For example, you can list the current +parameters with @code{info args}, or list the breakpoints you have set +with @code{info breakpoints} or @code{info watchpoints}. You can get +a complete list of the @code{info} sub-commands with @w{@code{help +info}}. + +@table @code +@kindex info args + +@item info args +Method arguments of the current stack frame. +@kindex info breakpoints + +@item info breakpoints +Status of user-settable breakpoints +@kindex info display + +@item info display +All display expressions. +@kindex info files + +@item info files +Source files in the program. +@kindex info file + +@item info file @var{filename} @ovar{all|lines|mtime|sha1} +Information about a specific file. Parameter @code{lines} gives the +number of lines in the file, @code{mtime} shows the modification time +of the file (if available), @code{sha1} computes a SHA1 has of the +data of the file. @code{all} gives all of the above information. + +@kindex info line +@item info line +Line number and file name of current position in source. +@kindex info locals +@item info locals +Local variables of the current stack frame. +@kindex info program +@item info program +Display information about the status of your program: whether it is +running or not and why it stopped. If an unhandled exception occurred, +the exception class and @code{to_s} method is called. +@kindex info stack +@item info stack +Backtrace of the stack. An alias for @code{where}. @xref{Backtrace}. +@kindex info thread +@item info thread @ovar{thread-number} @r{[} terse | verbose@r{]} +If no thread number is given, we list info for all +threads. @code{terse} and @code{verbose} options are possible. If terse, +just give summary thread name information. See information under @code{info threads} for +more detail about this summary information. + +If @code{verbose} is appended to the end of the command, then the entire +stack trace is given for each thread. + +@kindex info threads @r{[} terse | verbose@r{]} +@item info threads + +List information about currently-known threads. This information +includes whether the thread is current (+), if it is suspended ($), or +ignored (!); the thread number and the top stack item. If +@code{verbose} is given then the entire stack frame is shown. Here is +an example: + +@smallexample +(rdb:7) info threads + 1 # ./test/thread1.rb:27 + !2 # + 3 # ./test/thread1.rb:11 + 4 # ./test/thread1.rb:11 + 5 # ./test/thread1.rb:11 + 6 # ./test/thread1.rb:11 ++ 7 # ./test/thread1.rb:14 +(rdb:1) +@end smallexample + +Thread 7 is the current thread since it has a plus sign in front. Thread 2 is +ignored since it has a @code{!}. A ``verbose'' listing of the above: + +@smallexample +(rdb:7) info threads verbose + 1 # + #0 Integer.join at line test/thread1.rb:27 + #1 at line test/thread1.rb:27 + !2 # + 3 # + #0 sleep(count#Fixnum) at line test/thread1.rb:11 + #1 Object.fn(count#Fixnum, i#Fixnum) at line test/thread1.rb:11 + #2 at line test/thread1.rb:23 + 4 # + #0 sleep(count#Fixnum) at line test/thread1.rb:11 + #1 Object.fn(count#Fixnum, i#Fixnum) at line test/thread1.rb:11 + #2 at line test/thread1.rb:23 + 5 # + #0 sleep(count#Fixnum) at line test/thread1.rb:11 + #1 Object.fn(count#Fixnum, i#Fixnum) at line test/thread1.rb:11 + #2 at line test/thread1.rb:23 + 6 # + #0 sleep(count#Fixnum) at line test/thread1.rb:11 + #1 Object.fn(count#Fixnum, i#Fixnum) at line test/thread1.rb:11 + #2 at line test/thread1.rb:23 ++ 7 # + #0 Object.fn(count#Fixnum, i#Fixnum) at line test/thread1.rb:14 + #1 at line test/thread1.rb:23 +@end smallexample + +@kindex info variables +@item info variables +Local and instance variables. +@end table + +@node Post-Mortem Debugging +@chapter Post-Mortem Debugging +@cindex post-mortem debugging + +It is also to possible enter the debugger when you have an uncaught +exception that is about to terminate our program. This is called +@emph{post-mortem debugging}. In this state many, of the debugger commands +for examining variables and moving around in the stack still +work. However some commands, such as those which imply a continuation +of running code, no longer work. + +The most reliable way to set up post-mortem debugging is to use the +@option{--post-mortem} option in invoking @code{rdebug}. See @ref{rdebug +command-line options}. This traps/wraps at the debugger ``load'' of +your Ruby script. When this is done, your program is stopped after +the exception takes place, but before the stack has been +unraveled. (Alas, it would be nice to if one could allow resetting the +exception and continuing, but details of code in Ruby 1.8's +@code{eval.c} prevent this.) + +If however you haven't invoked @code{rdebug} at the outset, but +instead call @code{ruby-debug} from inside your program, to set up +post-mortem debugging set the @code{post_mortem} key in +@code{Debugger.start}. Here's an example modified from +@url{http://www.datanoise.com/articles/2006/12/20/post-mortem-debugging}: + +@smallexample + $ @b{cat t.rb } + require 'rubygems' + require 'ruby-debug' ; Debugger.start(:post_mortem => true) + + def t1 + raise 'test' + end + def t2 + t1 + end + t2 + + $ @b{ruby t.rb } + t.rb:8: raise 'test' + (rdb:post-mortem) @b{l=} + [3, 12] in t.rb + 3 + 4 Debugger.start + 5 Debugger.post_mortem + 6 + 7 def t1 + => 8 raise 'test' + 9 end + 10 def t2 + 11 t1 + 12 end + (rdb:post-mortem) +@end smallexample + +Alternatively you can call @code{Debugger.post_mortem()} after rdebug has +been started. The @code{post_mortem()} method can be called in two +ways. Called without a block, it installs a global @code{at_exit()} hook +that intercepts exceptions not handled by your Ruby script. In +contrast to using the @option{--post-mortem} option, when this hook +occurs after the call stack has been rolled back. (I'm not sure if +this in fact makes any difference operationally; I'm just stating it +because that's how it works.) + +If you know that a particular block of code raises an exception you +can enable post-mortem mode by wrapping this block inside a +@code{Debugger.post_mortem} block + +@smallexample +def offender + 1/0 +end +... +require "ruby-gems" +require "ruby-debug" +Debugger.post_mortem do + ... + offender + ... +end +@end smallexample + +Once inside the debugger in post-mortem debugging, the prompt should +be @code{(rdb:post-mortem)}. + +@node Debugger Module and Class +@chapter The Debugger Module and Class + +@menu +* Debugger Module:: ruby-debug's Debugger module +* Debugger Class:: Debugger class +* Kernel routines:: Routines added to Kernel +@end menu + +@node Debugger Module +@section The Debugger Module + +@menu +* Debugger.run:: +@ifset LATER +* Debugger.post-mortem:: +@end ifset +* Debugger.context:: +* Debugger.settings:: +@end menu + +@node Debugger.run +@subsection @code{Debugger.start}, @code{Debugger.started?}, @code{Debugger.stop}, @code{Debugger.run_script} + +In order to provide better debugging information regarding the stack +frame(s) across all threads, ruby-debug has to intercept each call, +save some information and on return remove it. Possibly, in Ruby 1.9 +possibly this will not be needed. Therefore one has to issue call to +indicate start saving information and another call to stop. Of course, +If you call ruby-debug from the outset via @code{rdebug} this is done +for you. + +@table @code +@item Debugger.start(@ovar{options}) @ovar{block} +@vindex @code{Debugger.start(options)} +@vindex @code{Debugger.start(block)} +Turn on add additional instrumentation code to facilitate debugging. A +system even table hook is installed and some variables are set up to +access thread frames. + +This needs to be done before entering the debugger; therefore a call +to the debugger issue a @code{Debugger.start} call if necessary. + +If called without a block, @code{Debugger.start} returns @code{true} if +the debugger was already started. But if you want to know if the +debugger has already been started @code{Debugger.started?} can tell +you. + +If a block is given, the debugger is started and @code{yields} to +block. When the block is finished executing, the debugger stopped with +the @code{Debugger.stop method}. You will probably want to put a call +to @code{debugger} somwhere inside that block + +But if you want to completely stop debugger, you must call +@code{Debugger.stop} as many times as you called Debugger.start +method. + +The first time Debugger.start is called there is also some additional +setup to make the @code{restart} command work. In particular, @code{$0} and +@code{ARGV} are used to set internal debugger variables. + +Therefore you should make try to make sure that when +@code{Debugger.start} is called neither of these variables has been +modified. If instead you don't want this behavior you can pass an +options has and set the @code{:init} key to @code{false}. That is +@smallexample + Debugger.start(:init => false) # or Debugger.start(@{:init => false@}) +@end smallexample + +If you want post-mortem debugging, you can also supply +@code{:post_mortem => true} in @code{Debugger.start}. + +@item Debugger.started? +@vindex @code{Debugger.started?} +Boolean. Return @code{true} if debugger has been started. + +@item Debugger.stop +@vindex @code{Debugger.stop} +Turn off instrumentation to allow debugging. Return @code{true} is returned +if the debugger is disabled, otherwise it returns @code{false}. +@emph{Note that if you want to stop debugger, you must call Debugger.stop +as many times as you called the @code{Debugger.start} method.} + +@item Debugger.run_script(@var{debugger-command-file}, out = handler.interface) +@vindex @code{Debugger.run_script} +Reads/runs the given file containing debugger commands. @code{.rdebugrc} is run this way. + +@item Debugger.last_exception +@vindex @code{Debugger.last_exception} +If not @code{nil}, this contains @code{$!} from the last exception. + +@end table + +@node Debugger.context +@subsection @code{Debugger.context} +As mentioned previously, @code{Debugger.start} instruments additional +information to be obtained about the current block/frame stack. Here +we describe these additional @code{Debugger.context} methods. + +Were a frame position is indicated, it is optional. The top or current frame +position (position zero) is used if none is given. + +@table @code +@item Debugger.context.frame_args @ovar{frame-position=0} +@vindex @code{Debugger.context.frame_args} +If track_frame_args? is true, return information saved about call +arguments (if any saved) for the given frame position. + +@item Debugger.context.frame_args_info @ovar{frame-position=0} +@vindex @code{Debugger.context.frame_args_info} + +@item Debugger.context.frame_class @ovar{frame-position=0} +@vindex @code{Debugger.context.frame_args_info} +Return the class of the current frame stack. + +@item Debugger.context.frame_file @ovar{frame-position=0} +@vindex @code{Debugger.context.frame_file} +Return the filename of the location of the indicated frame position. + +@item Debugger.context.frame_id @ovar{frame-position=0} +@vindex @code{Debugger.context.frame_id} +Same as @code{Debugger.context.method}. + +@item Debugger.context.frame_line @ovar{frame-position=0} +@vindex @code{Debugger.context.frame_line} +Return the filename of the location of the indicated frame position. + +@item Debugger.context.frame_method @ovar{frame-position=0} +@vindex @code{Debugger.context.frame_method} +Symbol of the method name of the indicated frame position. + +@item Debugger.context.stack_size +@vindex @code{Debugger.context.stack_size} +Return the number the size of the frame stack. Note this may be less +that the actual frame stack size if debugger recording +(@code{Debugger.start}) was turned on at after some blocks were added +and not finished when the @code{Debugger.start} was issued. +@end table + +@node Debugger.settings +@subsection @code{Debugger.settings} +@vindex @code{Debugger.settings} +Symbols listed here are keys into the Array @code{Debugger.settings}. +These can be set any time after the @code{ruby-debug} is loaded. For example: +@smallexample + require "ruby-debug/debugger" + Debugger.settings[:autoeval] = true # try eval on unknown debugger commands + Debugger.listsize = 20 # Show 20 lines in a list command +@end smallexample + +@table @code +@item :argv +Array of String. @code{argv[0]} is the debugged program name and +@code{argv[1..-1]} are the command arguments to it. +@item :autoeval +Boolean. True if auto autoeval on. @xref{Autoeval}. +@item :autoirb +Fixnum: 1 if on or 0 if off. @xref{Autoirb}. +@item :autolist +Fixnum: 1 if on or 0 if off. +@item :basename +Boolean. True if basename on. @xref{Basename}. +@item :callstyle +Symbol: @code{:short} or @code{:last}. @xref{Callstyle}. +@item :debuggertesting +Boolean. True if currently testing the debugger. +@item :force_stepping +Boolean. True if stepping should go to a line different from the last +step. @xref{Forcestep}. +@item :full_path +Boolean. @xref{Fullpath}. +@item :listsize +Fixnum. Number of lines to show in a @code{list} command. @xref{Listsize}. +@item :reload_source_on_change +Boolean. True if we should reread the source every time it changes. @xref{Autoreload}. +@item :stack_trace_on_error +Boolean. True if we should produce a stack trace on error. @xref{Trace}. +@item :width +Fixnum. Number of characters the debugger thinks are in a line. @xref{Width}. +@end table + +@node Debugger Class +@section The @code{Debugger} Class +@menu +* Debugger.Breakpoint:: Debugger::Breakpoint +* Debugger.Context:: Debugger::Context +* Debugger.Command:: Debugger::Command +@end menu + +@table @code +@item add_breakpoint(file, line, expr) +@vindex @code{Debugger.add_breakpoint} +Adds a breakpoint in file @var{file}, at line @var{line}. If +@var{expr} is not nil, it is evaluated and a breakpoint takes effect +at the indicated position when that expression is true. You should +verify that @var{expr} is syntactically valid or a @code{SyntaxError} +exception, and unless your code handles this the debugged program may +terminate. + +@item remove_breakpoint(bpnum) +@vindex @code{Debugger.remove_breakpoint} +When a breakpoint is added, it is assigned a number as a way to +uniquely identify it. (There can be more than one breakpoint on a +given line.) To remove a breakpoint, use @code{remove_breakpoint} with +breakpoint number @var{bpnum}. + +@item breakpoints +@vindex @code{Debugger.breakpoints} +Return a list of the breakpoints that have been added but not removed. +@end table + +@node Debugger.Breakpoint +@subsection The @code{Debugger::Breakpoint} Class +Breakpoint are objects in the @code{Debugger::Breakpoint} class. +@table @code +@item enabled? +@vindex @code{Debugger::Breakpoints.enabled?} +Returns whether breakpoint is enabled or not. + +@item enabled= +@vindex @code{Debugger::Breakpoints.enabled=} +Sets whether breakpoint is enabled or not. + +@item expr +@vindex @code{Debugger::Breakpoints.expr} +Expression which has to be true at the point where the breakpoint is +set before we stop. + +@item expr= +@vindex @code{Debugger::Breakpoints.expr=} + +@item hit_condition +@item hit_condition= +@vindex @code{Debugger::Breakpoints.condition} +@vindex @code{Debugger::Breakpoints.condition=} + +@item hit_count +@vindex @code{Debugger::Breakpoints.hit_count} +Returns the hit count of the breakpoint. + +@item hit_value +@vindex @code{Debugger::Breakpoints.hit_value} +Returns the hit value of the breakpoint. + +@item hit_value= +@vindex @code{Debugger::Breakpoints.hit_value=} +Sets the hit value of the breakpoint. + +@item id +@cindex @code{Debugger::Breakpoints.id} +A numeric name for the breakpoint which is used in listing breakpoints +and removing, enabling or disabling the breakpoint + +@item pos +@vindex @code{Debugger::Breakpoints.pos=} +Returns the line number of this breakpoint. +@item pos= +@vindex @code{Debugger::Breakpoints.pos=} +Sets the line number of this breakpoint. + +@item source +@vindex @code{Debugger::Breakpoints.source} +Returns the file name in which the breakpoint occurs. + +@item source= +@vindex @code{Debugger::Breakpoints.source=} +Sets the file name in which the breakpoint occurs. +@end table + +@node Debugger.Context +@subsection The @code{Debugger::Context} Class +Callbacks in @code{Debugger:Context} get called when a stopping point +or an event is reached. It has information about the suspended program +which enable a debugger to inspect the frame stack, evaluate variables +from the perspective of the debugged program, and contains information +about the place the debugged program is stopped. + +@table @code +@item at_line(@var{file}, @var{line}) +@vindex Debugger::Context::at_line(@var{file}, @var{line}) +This routine is called when the debugger encounters a ``line'' event for +which it has been indicated we want to stop at, such as by hitting a +breakpoint or by some sort of stepping. + +@item at_return(@var{file}, @var{line}) +@vindex Debugger::Context::at_return(@var{file}, @var{line}) +This routine is called when the debugger encounters a ``return'' event for +which it has been indicated we want to stop at, such as by hitting a +@code{finish} statement. + +@item debug_load(@var{file}, @var{stop-initially}) +@vindex Debugger::Context::debug_load(@var{file}, @var{stop-initially}) +This method should be used to debug a file. If the file terminates +normally, @code{nil} is returned. If not a backtrace is returned. + +The @var{stop-initially} parameter indicates whether the program +should stop after loading. If an explicit call to the debugger is in +the debugged program, you may want to set this @code{false}. +@end table + +@node Debugger.Command +@subsection The @code{Debugger::Command} Class + +Each command you run is in fact its own class. Should you want to extend +ruby-debug, it's pretty easy to do since after all ruby-debug is Ruby. + +Each @code{Debugger#Command} class should have the a @code{regexp} +method. This method returns regular expression for command-line +strings that match your command. It's up to you to make sure this +regular expression doesn't conflict with another one. If it does, it's +undefined which one will get matched and run + +In addition the instance needs these methods: +@table @code +@item execute +Code which gets run when you type a command (string) that matches the +commands regular expression. +@item help +A string which gets displayed when folks as for help on that command +@item help_command +A name used the help system uses to show what commands are available. +@end table + +Here's a small example of a new command: +@smallexample +module Debugger + class MyCommand < Command + def regexp + /^\s*me$/ # Regexp that will match your command + end + + def execute + puts "hi" # What you want to happen when your command runs + end + class << self + def help_command + 'me' # String name of command + end + def help(cmd) + # Some sort of help text. + %@{This does whatever it is I want to do@} + end + end +end +@end smallexample + +Now here's an example of how you can load/use it: +@smallexample + require 'rubygems' + require 'ruby-debug' + require '/tmp/mycmd.rb' # or wherever + Debugger.start + x=1 + debugger + y=2 +@end smallexample + +And now an example of invoking it: +@smallexample +ruby /tmp/testit.rb: +/tmp/testit.rb:7 +y=2 +(rdb:1) help +ruby-debug help v0.10.3 +Type 'help ' for help on a specific command +Available commands: +backtrace delete enable help method putl set trace +break disable eval info next quit show undisplay +catch display exit irb p reload source up +condition down finish list pp restart step var +continue edit frame me ps save thread where + ^^ This is you + +(rdb:1) help me +This does whatever it is I want to do +(rdb:1) me +hi +(rdb:1) +@end smallexample + +@node Kernel routines +@section Additions to @code{Kernel} + +@table @code + +@item debugger @ovar{steps=1} +@vindex @code{Kernel::debugger} +Enters the debugger in the current thread after a stepping @var{steps} line-event steps. +Before entering the debugger startup script is read. + +Setting @var{steps} to 0 will cause a break in the debugger subroutine +and not wait for eany line event to occur. This could be useful you +want to stop right after the last statement in some scope. + +Consider this example: +@smallexample +$ cat scope-test.rb + +require 'rubygems' +require 'ruby-debug' ; Debugger.start +1.times do + a = 1 + debugger # implied steps=1 + end +y = 1 + +$ scope-test.rb:8 +y = 1 +(rdb:1) p a +NameError Exception: undefined local variable or method `a' for main:Object +(rdb:1) +@end smallexample +The debugger will get at the line event which follows @samp{a=1}. This +is outside the @code{do} block scope where @var{a} is defined. If +instead you want to stop before leaving the @code{do} loop it is +possibly to stop right inside the @code{debugger}; call with 0 zero parameter: +@smallexample +$ cat scope-test.rb + +require 'rubygems' +require 'ruby-debug' ; Debugger.start +1.times do + a = 1 + debugger(0) +end +y = 1 + +$ scope-test.rb:8 +../lib/ruby-debug-base.rb:175 +Debugger.current_context.stop_frame = 0 +(rdb:1) where +--> #0 Kernel.debugger(steps#Fixnum) at line ../lib/ruby-debug-base.rb:175 + #1 at line scope-test.rb:6 + #2 at line scope-test.rb:4 +(rdb:1) up +#1 at line scope-test.rb:6 +(rdb:1) p a +1 +(rdb:1) +@end smallexample +As seen above you will have to position the frame up one to be back in +your debugged program rather than in the debugger. + +@item breakpoint @ovar{steps=1} +@vindex @code{Kernel::breakpoint} +An alias for debugger. + +@item binding_n @ovar{n=0} +@vindex @code{Kernel::binding_n} +Returns a @samp{binding()} for the @var{n}-th call frame. Note however +that you need to first call @samp{Debugger.start} before issuing this +call. + +@end table + +@node Using from Subversion +@appendix Building and Installing from rubyforge's Subversion Repository + +Here are Unix-centric instructions. If you have Microsoft Windows or +OSX some of the below may need adjusting. + +@menu +* Prerequisites:: +* Package Checkout:: +* Trying Out:: +* Running Regression Tests:: +* Building the Documentation and Emacs files:: +* Building for Microsoft Windows:: +@end menu + +@node Prerequisites +@section Prerequisites: To build the package you'll need at a minimum: + +@itemize @bullet +@item +Ruby (of course). Currently only version 1.8.6 and above but not +version 1.9.@emph{x} work. +@item +Ruby development headers. This typically includes a file called @file{ruby.h} +@item +A C compiler like GNU C (@code{gcc}) +@item +Rake +@item +Subversion (@code{svn}). +@end itemize + +If you want to build the documentation and install Emacs files, you'll +also need: + +@itemize @bullet +@item + a POSIX shell like bash +@item + autoconf +@item + automake +@item + GNU Make +@item + texinfo +@end itemize + +@node Package Checkout +@section Basic Package Checkout and Installation + +Check out the trunk of repository following the instructions at +@url{http://rubyforge.org/scm/?group_id=1900} For example on a Unixy system, +this may work: + +@smallexample + mkdir ruby-debug + cd ruby-debug + svn checkout svn://rubyforge.org/var/svn/ruby-debug/trunk trunk +@end smallexample + +In order to make the Ruby gems, @code{ruby-debug} and +@code{ruby-debug-base}, get yourself into the trunk directory after +the code has been checked out and run: + +@smallexample + cd trunk # This is the same trunk checked out above. + rake package +@end smallexample + +If all goes well you should have some gem files put in the directory +@code{pkg}. Use the gem command to install that. + +@smallexample + sudo gem install ruby-debug-*.gem # See gem help for other possibilities +@end smallexample + +If all goes well the rdebug script has been installed ruby-debug is +now ready to run. But if everything goes well you might want to run +the built-in regression tests to make sure everything is okay. +See step 3 below. + +If the gem install didn't work,'t there may be a problem with your C +compiler or the Ruby headers are not installed. + +@node Trying Out +@section Trying Out without Installing + +You don't have to build a gem file to try out ruby debug. In fact when +developing new features for ruby-debug, developers often you want to +try it out @emph{before} installing. If you have a problem in the latter +part of step 1 you may want to try this approach since we go into a +little more detail as to what happens under the covers when you do the +gem install. + +Run (from trunk) +@smallexample + rake lib +@end smallexample + +This creates a Makefile and builds the ruby-debug shared library. (On +Unix the name is @code{ruby_debug.so}). + +Once this is done you can run the debugger as you would rdebug using the +script @code{runner.sh}. For example (again from trunk) + +@smallexample + ./runner.sh ~/my-ruby-program.rb +@end smallexample + +@node Running Regression Tests +@section Running the Regression Tests + +We've put together some basic tests to make sure ruby-debug is doing +what we think it should do. To run these (from @code{trunk}): + +@smallexample + rake test +@end smallexample + +If you didn't build the ruby-debug shared library and skipped step 2, +don't worry @code{rake test} will do step 2 for you. You should see a +line that ends something like: + +@smallexample + Finished in 2.767579 seconds. + + 12 tests, 35 assertions, 0 failures, 0 errors +@end smallexample + +The number of seconds, tests, and assertions may be different from the +above. However you @emph{should} see exactly ``0 failures, 0 errors.'' + +@node Building the Documentation and Emacs files +@section Building the Documentation and Testing/Installing Emacs Files + +Of course, I recommend you read the ruby-debug manual that comes with +the package. If you have the prerequisites described above, run this +once: +@smallexample + sh ./autogen.sh +@end smallexample + +Then run: +@smallexample + ./configure + make + make test # Runs Emacs regression tests + sudo make install # Or arrange to do this as root +@end smallexample + +@node Building for Microsoft Windows +@section Building for Microsoft Windows + +Microsoft Windows is ``special'' and building @code{ruby-debug-base} +on it requires extra care. A problem here seems to be that the +``One-click'' install is compiled using Microsoft Visual Studio C, version 6 +which is not sold anymore and is rather old. + +Instead I suggest building via mingw/msys. +@url{http://eigenclass.org/hiki.rb?cmd=view&p=cross+compiling+rcovrt&key=mingw} +has instructions on how to do. Some amendments to these instructions. + +First, those instructions are a little GNU/Linux centric. If you are +using Ubuntu or Debian, then this should be the easiest to follow the +instructions. On Ubuntu or Debian there is a mingw3 Debian +package. Installing that will give you the cross compiler that is a +prerequisite. Alternatively if you are running MS Windows I notice +that cygwin also has a mingw package. Or possibly you could use MinGW +directly. For other OS's you might have to build a cross-compiler, +i.e. gcc which emits win32 code and can create a win32 DLL. + +After you have a cross compiler you need to download the Ruby source +and basically build a ruby interpreter. The cross-compile.sh script +works although when I downloaded it, it had lots of blank space at the +beginning which will mess up the Unix magic interpretation. That is +remove the blanks in front of @code{#/bin/sh}. + +On my system, this script fails in running @code{make ruby} because the +fake.rb that got created needed to have a small change: + +@smallexample + + ALT_SEPARATOR = "\"; \ +@end smallexample +should be: +@smallexample + ALT_SEPARATOR = "\\"; \ +@end smallexample + +After fixing this, run @code{make ruby}. Also, I needed to run +@code{make rubyw}. + +And then @code{make install} as indicated. + +Once all of that's in place, the place you want be is in +@code{ruby-debug/trunk/ext/win32}, not @code{ruby-debug/ext}. + +So let's say you've installed the cross-compiled install ruby in +@code{/usr/local/ruby-mingw32/}. Here then are the commands to build @code{ruby-debug-base-}@emph{xxx}@code{-mswin32.gem}: +@smallexample + cd .../ruby-debug/trunk/ext/win32 + ruby -I /usr/local/ruby-mingw32/lib/ruby/1.8/i386-mingw32 ../extconf.rb + make # Not rake + cd ../.. # back in ruby-debug/trunk + rake win32_gem +@end smallexample + +@node Class Module Index +@unnumbered Class, Module Method Index +@printindex vr + +@node Command Index +@unnumbered Command Index +@printindex ky + +@node General Index +@unnumbered General Index +@printindex cp + +@tex +% I think something like @colophon should be in texinfo. In the +% meantime: +\long\def\colophon{\hbox to0pt{}\vfill +\centerline{The body of this manual is set in} +\centerline{\fontname\tenrm,} +\centerline{with headings in {\bf\fontname\tenbf}} +\centerline{and examples in {\tt\fontname\tentt}.} +\centerline{{\it\fontname\tenit\/},} +\centerline{{\bf\fontname\tenbf}, and} +\centerline{{\sl\fontname\tensl\/}} +\centerline{are used for emphasis.}\vfill} +\page\colophon +% Blame: doc@cygnus.com, 1991. +@end tex + +@bye diff --git a/doc/.svn/text-base/test-tri2.rb.svn-base b/doc/.svn/text-base/test-tri2.rb.svn-base new file mode 100644 index 0000000..2be90bc --- /dev/null +++ b/doc/.svn/text-base/test-tri2.rb.svn-base @@ -0,0 +1,18 @@ +#!/usr/bin/env ruby +require "test/unit" +require "tri2.rb" +require "rubygems" +require "ruby-debug" +Debugger.start + +class TestTri < Test::Unit::TestCase + def test_basic + debugger + solutions = [] + 0.upto(5) do |i| + solutions << triangle(i) + end + assert_equal([0, 1, 3, 6, 10, 15], solutions, + "Testing the first 5 triangle numbers") + end +end diff --git a/doc/.svn/text-base/tri3.rb.svn-base b/doc/.svn/text-base/tri3.rb.svn-base new file mode 100644 index 0000000..0564847 --- /dev/null +++ b/doc/.svn/text-base/tri3.rb.svn-base @@ -0,0 +1,8 @@ +#!/usr/bin/env ruby +def triangle(n) + (0..n).inject do |sum, i| + sum +=i + end +end +puts triangle(3) + diff --git a/doc/.svn/text-base/triangle.rb.svn-base b/doc/.svn/text-base/triangle.rb.svn-base new file mode 100644 index 0000000..39f038c --- /dev/null +++ b/doc/.svn/text-base/triangle.rb.svn-base @@ -0,0 +1,12 @@ +#!/usr/bin/env ruby +# Compute the n'th triangle number - the hard way +# triangle(n) == (n * (n+1)) / 2 +def triangle(n) + tri = 0 + 0.upto(n) do |i| + tri += i + end + return tri + end + +puts triangle(3) diff --git a/doc/Makefile.am b/doc/Makefile.am new file mode 100644 index 0000000..477fc7e --- /dev/null +++ b/doc/Makefile.am @@ -0,0 +1,63 @@ +############################################################################## +# $Id: Makefile.am,v 1.3 2006/12/28 12:34:25 rockyb Exp $ +# Copyright (C) 2007 Rocky Bernstein +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +############################################################################## + +EXT=1 +man1_MANS = rdebug.$(EXT) + +EXTRA_DIST = $(man1_MANS) \ + hanoi.rb primes.rb test-tri2.rb tri3.rb triangle.rb \ + ruby-debug.info ruby-debug.html ruby-debug.pdf + +info_TEXINFOS = ruby-debug.texi rdebug-emacs.texi + +all: $(INFO_DEPS) $(man1_MANS) html pdf + +pdf: ruby-debug.pdf rdebug-emacs.pdf + +txt: ruby-debug.txt rdebug-emacs.txt + +ps: ruby-debug.ps rdebug-emacs.ps + +man: $(man1_MANS) + +html: ruby-debug.html rdebug-emacs.html + +ruby-debug.html: ruby-debug.texi + texi2html $(srcdir)/ruby-debug.texi || true + +rdebug-emacs.html: rdebug-emacs.texi + texi2html $(srcdir)/rdebug-emacs.texi || true + +%.ps.gz: %.ps + gzip -9c $< > $@ + +# Our `texinfo.tex' must reside in the current directory, otherwise +# texi2dvi will use the default. +.texi.pdf: + $(TEXI2PDF) -I $(srcdir) $< + +.texi.dvi: + $(TEXI2DVI) -I $(srcdir) $< + +.dvi.ps: + test -d $(docdir) || mkdir $(docdir) + $(DVIPS) $< -o $@ + +all-formats: pdf dvi txt ps html + +MOSTLYCLEANFILES = rubydb.tgs rubydb.ps.gz rubydb.pdf rubydb.html rubydb_toc.html rubydb_foot.html rubydb-man.html diff --git a/doc/emacs-notes.txt b/doc/emacs-notes.txt new file mode 100644 index 0000000..4568791 --- /dev/null +++ b/doc/emacs-notes.txt @@ -0,0 +1,38 @@ +* rdebug.el is loaded by the user when Emacs is launched. (Should +Rdebug ever be part of Emacs, this should be the items autoloaded by +Emacs.) + +There is a command buffer which is the gud process. There are a number +of "secondary" buffers have in gud-comint-buffer the gud process. The +way we go the other direction from gud process to secondary buffer is +by buffer name. Source buffers don't seem to have a local +gud-comint-buffer variable set but use the global value. Perhaps +source buffer should have their own buffer-local value(s)? + +For each secondary buffer we have things for that specific buffer. In particular: +* frames (rdebug-frames.el) +* output (rdebug-output.el) +* variables (rdebug-varbuf.el) +* watch or display-expressions - (rdebug-watch.el +* breakpoints (rdebug-breaks.el) + +Each specific secondary buffer includes + - setting the buffer up, + - specific commands for that buffer + - the kinds of functions that buffer deals with (e.g. frame + things for the "frame" buffer or breakpoints for the "breakpoints" buffer.) + +* rdebug-gud.el contains things that interface to gdb. Possibly also +things that interface to gdb-ui should be there as well. + +* rdebug-shortkey.el has all the magic that needs to be done to make + shortkey mode work. + +* rdebug-track is all the things to make rdebug-track mode work. + +I have some additions, which deals with *when* certain files are loaded. + +* rdebug-source.el is loaded when the first Ruby source file is loaded +Of course, the name rdebug-source.el is not important, we could rename +it to something else and reuse the name for other source-related +things. diff --git a/doc/hanoi.rb b/doc/hanoi.rb new file mode 100644 index 0000000..99c4c10 --- /dev/null +++ b/doc/hanoi.rb @@ -0,0 +1,35 @@ +#!/usr/bin/ruby + +def hanoi(n,a,b,c) + if n-1 > 0 + hanoi(n-1, a, c, b) + end + puts "Move disk %s to %s" % [a, b] + if n-1 > 0 + hanoi(n-1, c, b, a) + end +end + +i_args=ARGV.length +if i_args > 1 + puts "*** Need number of disks or no parameter" + exit 1 +end + +n=3 + +if i_args > 0 + begin + n = ARGV[0].to_i + rescue ValueError, msg: + print "** Expecting an integer, got: %s" % ARGV[0].to_s + exit 2 + end +end + +if n < 1 or n > 100 + puts "*** number of disks should be between 1 and 100" + exit 2 +end + +hanoi(n, :a, :b, :c) diff --git a/doc/primes.rb b/doc/primes.rb new file mode 100644 index 0000000..e94219c --- /dev/null +++ b/doc/primes.rb @@ -0,0 +1,28 @@ +#!/usr/bin/env ruby +# Enumerator for primes +class SievePrime + @@odd_primes = [] + def self.next_prime(&block) + candidate = 2 + yield candidate + not_prime = false + candidate += 1 + while true do + @@odd_primes.each do |p| + not_prime = (0 == (candidate % p)) + break if not_prime + end + unless not_prime + @@odd_primes << candidate + yield candidate + end + candidate += 2 + end + end +end +SievePrime.next_prime do |prime| + puts prime + break if prime > 10 +end + + diff --git a/doc/rdebug-emacs.texi b/doc/rdebug-emacs.texi new file mode 100644 index 0000000..89a5cab --- /dev/null +++ b/doc/rdebug-emacs.texi @@ -0,0 +1,1030 @@ +\input texinfo @c -*-texinfo-*- +@setfilename rdebug-emacs.info + +@set DBG ruby-debug +@set ttrdebug @code{rdebug} +@set ttDBG @code{@value{DBG}} +@set Emacs @sc{gnu} Emacs + +@set RDEBUG_EMACS_VERSION 0.1 +@include version-rdebug-emacs.texi +@finalout + +@c Karl Berry informs me that this will add straight quotes in +@c typewriter text. +@c See the "Inserting Quote Characters" node in the Texinfo manual +@set txicodequoteundirected +@set txicodequotebacktick + +@c THIS MANUAL REQUIRES TEXINFO 4.0 OR LATER. + +@c This is a dir.info fragment to support semi-automated addition of +@c manuals to an info tree. +@dircategory Programming & development tools. +@direntry +* ruby-debug-emacs: (ruby-debug). Ruby Debugger for GNU Emacs +@end direntry + +@titlepage +@title Debugging with @code{ruby-debug} inside GNU Emacs Version @value{RDEBUG_EMACS_VERSION} +@sp 1 +@subtitle @value{EDITION} Edition +@subtitle @value{UPDATED-MONTH} +@author Rocky Bernstein and Anders Lindgren +@page +@ifset WHERETO +@tex +{\parskip=0pt +\hfill (Send bugs and comments on ruby-debug to fill in...)\par +\hfill {\it Debugging with {\tt ruby-debug}\par +\hfill \TeX{}info \texinfoversion\par +} +@end tex +@end ifset +@end titlepage +@page + +@node Top, Getting started, (dir), (dir) +@top Debugging with ruby-debug under GNU Emacs + +@menu +* Getting started:: +* The Multi-window Mode:: +* Debugger Buffers:: +* Emacs Debugger Commands:: Indexes (nodes containing large menus) +* Emacs Command Index:: An item for each GNU/Emacs command name. +* Emacs Function Index:: An item for each Emacs Function. +* Emacs Key Binding Index:: An item for each Emacs Debugger Command. + +@detailmenu + --- The Detailed Node Listing --- + +Getting started + +* Installation:: How to install this package +* Emacs rdebug:: Invoke the ruby debugger initially +* Emacs shell tracking mode:: Entering rdebug from an existing shell buffer + +Debugger Buffers + +* Debugger Command Buffer:: +* Emacs Source:: Commands from the source script + +Emacs Debugger Commands + +* Emacs Debugger Common Commands:: +* Emacs Debugger Breakpoint Buffer Commands:: +* Emacs Debugger Stack Buffer Commands:: +* Emacs Debugger Variable Buffer Commands:: +* Emacs Debugger Watch Buffer Commands:: +* Emacs GUD Commands:: + +@end detailmenu +@end menu + +This file describes ruby-debug, the Ruby Debugger, +version @value{RDEBUG_EMACS_VERSION} + +This is the @value{EDITION} Edition, @value{UPDATED} +@c Copyright (C) 2007 ... + +@c @node GNU Emacs +@c @chapter Using @code{ruby-debug} from GNU Emacs + + +@cindex @value{Emacs} +A special interface which comes with Ruby that allows you to use +@value{Emacs} to view (and edit) the source files for the program you +are debugging with @value{DBG}. However you must be using at least +version 21 of @value{Emacs}, but with @value{Emacs} version 22 or 23 +there are even more debugging features available. @code{M-x +show-emacs-version} inside @value{Emacs} will tell you what version you +are running. + +This package provide a full-fledged debugging environment, on par with +modern integrated development environments. Once the debugger has been +activated, the Emacs frame is divided into a number of dedicated +debugger windows.@footnote{If you are an @value{Emacs} traditionalist, +you can, of course, run this package with only a shell and source +buffer} + +This package comes with a number of predefined window layouts. It is +fully customizable so you can create your own. + +@c ------------------------------------------------------------------- + + +@node Getting started, The Multi-window Mode, Top, Top +@chapter Getting started + +@menu +* Installation:: How to install this package +* Emacs rdebug:: Invoke the ruby debugger initially +* Emacs shell tracking mode:: Entering rdebug from an existing shell buffer +* Configurating this package:: Introducing the configure system +@end menu + +@node Installation, Emacs rdebug, Getting started, Getting started +@section Installation + +To use this interface, load the file @code{rdebug.el}. This file is a +light-weight file, basically it only contains a handful of +@code{autoload} directives. + +For example, you can place the following in your @code{~/.emacs} file: + +@smallexample + (require 'rdebug) +@end smallexample + +In addition, you must have Ruby and ruby-debug installed. + + +@node Emacs rdebug, Emacs shell tracking mode, Installation, Getting started +@section Emacs rdebug + +Use the command @kbd{M-x rdebug} in @sc{gnu} Emacs to start debugging. +Give the executable file you want to debug as an argument. Make sure +to use the version that comes with this package as this is newer than +that supplied with @value{Emacs}. + +The @kbd{rdebug} command starts @value{DBG} as a subprocess of Emacs, +with input and output through a newly created Emacs buffer. + +Using @value{DBG} under Emacs is just like using @value{DBG} +normally except for two things: + +@itemize @bullet +@item +All ``terminal'' input and output goes through the GNU Emacs buffer. +@end itemize + +This applies both to @value{DBG} commands and their output, and to the input +and output done by the program you are debugging. + +This is useful because it means that you can copy the text of previous +commands and input them again; you can even use parts of the output +in this way. + +All the facilities of GNU Emacs' Shell mode are available for interacting +with your script. In particular, you can send signals the usual +way---for example, @kbd{C-c C-c} for an interrupt, @kbd{C-c C-z} for a +stop. + +@node Emacs shell tracking mode, Configurating this package, Emacs rdebug, Getting started +@section Entering rdebug from an existing shell buffer + +Many times it's not feasible to enter the debugger from the outset. +Instead a call to the debugger is put inside the program. + +@c See @xref{Unit Testing Session}. + +It is also possible in GNU emacs to use a (``comint'') shell and set a +mode to watch for @value{DBG} prompts and track the source code in +another window. @xref{Interactive Shell, , Shell, Emacs, The @value{Emacs} +Manual}. + +To enable, this run @kbd{M-x turn-on-rdebug-track-mode}. There is some +overhead involved in scanning output, so if you are not debugging Ruby +programs you probably want to turn this off which can be done via the +@code{M-x turn-off-rdebugtrack} command. + + +@node Configurating this package, , Emacs shell tracking mode, Getting started +@section Configurating this package + +In this manual we present a number of @value{Emacs} lisp variables and +functions that you can use to configure the debugger interface. In +addition, you can use the @value{Emacs} @emph{customize} system, see the +@kbd{ } menu item. + +@c ------------------------------------------------------------------- + +@node The Multi-window Mode, Debugger Buffers, Getting started, Top +@chapter Multi-window + +In the multi-window debugger mode, a number of buffers are visible when +the debugger starts. This chapter will describe each of them, in +addition it will describe the features associated with the multi-window +mode. + +The default multi-window layout looks like the following: + +@verbatim ++----------------------------------------------------------------------+ +| Toolbar | ++-----------------------------------+----------------------------------+ +| | | +| Debugger shell | Variables buffer | +| | | ++-----------------------------------+----------------------------------+ +| | | +| Source buffer | Output buffer | +| | | ++-----------------------------------+----------------------------------+ +| | | +| Stack buffer | Breakpoints buffer | +| | | ++-----------------------------------+----------------------------------+ +@end verbatim + +@section Activating Multi-window mode + +The variable @code{rdebug-many-windows} controls if multi-window mode +should be used, it is enabled by default. When starting the debugger +using the @code{M-x rdebug} mode the command line option @code{--emacs +3} must be specified (this is also the default). + +When attaching to an already running debugger process, you must give the +debugger command @kbd{set annotate 3}. + +@section Window Layouts + +When the debugger is started, the original window layout of +@value{Emacs} is replaced with the window layout of the debugger. You +can switch back and forth between the original window layout and the +debugger layout using +@kbd{M-x rdebug-display-original-window-configuration} and +@kbd{M-x rdebug-display-debugger-window-configuration}. + +If, for some reason, the debugger layout has been garbled you can +restore it to the original state using @kbd{M-x +rdebug-restore-debugger-window-layout}. + +The debugger provides a number of different window layouts. The easies +way to try them out is to use the menu @kbd{ +} and select any in the section starting with @code{Standard}. + + +@section The buffers + +All buffers in this section share a set of commands for common debugger +operations and for switching between buffers. In addition, each buffer +has got a set of dedicated commands. + +All debugger buffers, with the exception of source and the debugger +shell window, are called @emph{secondary buffers}. + +@subsection Keybindings for all Debugger Windows + +The debugger provides key-bindings that work in all debugger windows, +including Ruby source buffers. The key bindings are designed to match +keys of commonly used debugger environments. + +The variable @code{rdebug-populate-common-keys-function} can be assigned +to a function that should bind the keys use. Three functions are +provided @code{rdebug-populate-common-keys-standard}, +@code{...-eclipse}, and @code{...-netbeans}. + +@multitable @columnfractions 0.4 0.2 0.2 0.2 +@headitem Command @tab Standard @tab Eclipse @tab Netbeans +@item Run @tab f5 @tab @tab +@item Quit @tab S-f5 @tab @tab +@item Toggle Breakpoint @tab f9 @tab @tab +@item Enable/Disable Breakpoint @tab C-f9 @tab S-C-b @tab S-f8 +@item Step over @tab f10 @tab f6 @tab f8 +@item Step into @tab f11 @tab f5 @tab f7 +@item Step out @tab S-f11 @tab f7 @tab M-S-f7 + +@end multitable + + + +@subsection Keybindings for Secondary Buffers + +The following commands are available in all secondary windows. + +Capital letters move between secondary buffers as mentioned above (jump +to if visible or replace a secondary if not). + +@table @kbd +@item SPACE +step (edebug compatible) +@item < +Up in the stack trace +@item > +Down in the stack trace +@item ? +Help +@item B +Display breakpoints buffer +@item C +Display command buffer +@item O +Display program output +@item S +Display source window +@item T +Display stack trace buffer +@item V +display variables buffer +@item W +display watch buffer +@item b +Set breakpoint +@item c +Continue (i.e. run) +@item d +Remove breakpoint +@item f +Finish (i.e. step out of the current function) +@item n +Next (i.e. step into function) +@item p +print +@item q +Quit +@item r +Restart +@item s +Step (i.e. step over function) +@end table + +You can use the same commands in the source buffer if you enable +@code{rdebug-short-key-mode}. The best way to do this is to add the +following to your init file: + +@smallexample + (add-hook 'rdebug-mode-hook 'rdebug-turn-on-short-key-mode) +@end smallexample + + + +@subsection The Debugger Shell Buffer + +The @emph{debugger shell window} is the main communication channel +between @value{DBG} and @value{Emacs}. You can use the shell to issue +debugger commands directly. In addition, any @value{Emacs} debugger +command you issue will be translated into shell commands, and the output +will be parsed. + +It is the ambition that the @value{Emacs} debugger interface should be +in a state where the debugger shell window would not need to be visible. + +@subsection The Source Buffer + +The @emph{source buffers} (or buffers) contains the actual Ruby source +code that is being debugged. A small arrow in the left fringe displays +the current line. Active breakpoints are displayed as red dots and +passive as grey. + +@subsection The Output Buffer + +The @emph{output buffer} displays any output the debugged program emits. + +The option @code{rdebug-use-separate-io-buffer} controls if the output +buffer should be used, or if the output would go into the debugger shell +buffer. + +@subsection The Variables Buffer + +In this buffer, local and object variables are displayed. The values of +the variables can be edited. + +@table @kbd +@item RET +Edit the value +@item e +Print the value +@item x +Pretty-print the value +@end table + +@subsection The Stack Trace Buffer + +The @emph{stack trace} buffer displays the function that is currently +being debugger, the function that called it, etc., all the way up to the +originally called function. + +You can navigate in the stack trace buffer in order to see the source of +any function in the call chain. The Variables buffer will also be +updated to reflect the local variables of that function. + +@table @kbd +@item RET +Select a function to display +@item +Go to a stack frame +@end table + +@subsection The Watch Buffer + +The @emph{Watch Buffer} can display arbitrary expressions, including, +but not limited to, global variables. + +@table @kbd +@item a +Add a watch expression +@item C-d, d +Delete a watch expression +@item RET, e +Edit a watch expression +@item +Go to the expression +@end table + +@subsection The Breakpoints Buffer + +The @emph{Breakpoints Buffer} displays all breakpoints that currently are +defined and shows if they are enabled or disabled. + +@table @kbd +@item t +Toggle a breakpoint between enabled and disabled +@item i +Add a breakpoint condition +@item ret +Goto a breakpoint +@item C-d +Delete a breakpoint +@item +Go to the expression +@end table + +@subsection The Help Buffer + +The @emph{Help Buffer} is displayed whenever you press @code{?}. It will +display a help text on the available debugger commands and commands to +navigate between the buffers. + + +@c ------------------------------------------------------------------- + +@node Debugger Buffers, Emacs Debugger Commands, The Multi-window Mode, Top +@chapter Debugger Buffers + +@menu +* Debugger Command Buffer:: +* Emacs Source:: Commands from the source script +@end menu + +@node Debugger Command Buffer, Emacs Source, Debugger Buffers, Debugger Buffers +@section Emacs Debugger Command buffer + +Each time @value{DBG} displays a stack frame, Emacs automatically finds the +source file for that frame and puts an arrow (@samp{=>}) at the +left margin of the current line. Emacs uses a separate buffer for +source display, and splits the screen to show both your @value{DBG} session +and the source. + +Explicit @value{DBG} @code{list} or search commands still produce output as +usual, but you probably have no reason to use them from GNU Emacs. + +@quotation +@emph{Warning:} If the directory where your script resides is not your +current directory, it can be easy to confuse Emacs about the location of +the source files, in which case the auxiliary display buffer does not +appear to show your source. @value{DBG} can find programs by searching your +environment's @code{PATH} variable, so the @value{DBG} input and output +session proceeds normally; but Emacs does not get enough information +back from @value{DBG} to locate the source files in this situation. To +avoid this problem, either start @value{DBG} mode from the directory where +your script resides, or specify an absolute file name when prompted for the +@kbd{M-x gdb} argument. + +A similar confusion can result if you use the @value{DBG} @code{file} command to +switch to debugging a program in some other location, from an existing +@value{DBG} buffer in Emacs. +@end quotation + +@noindent +(preceded by @kbd{M-:} or @kbd{ESC :}, or typed in the @code{*scratch*} buffer, or +in your @file{.emacs} file). + +In the @value{DBG} I/O buffer, you can use the Emacs commands listed +below in addition to the standard Shell mode commands. The I/O buffer +name name is usually @code{*gud-}@emph{script-name}@code{*}, where +@emph{script-name} is the name of the script you are debugging. + +Many of the commands listed below are also bound to a second key +sequence which also can be used in the also be used in the source +script. These are listed in @ref{Emacs Source}. + +In secondary buffers many commands are available the corresponding +final keystroke. For example @code{C-c n} in a secondary buffer is +@code{n}. + +@table @kbd +@item C-h m +Describe the features of Emacs' @value{DBG} Mode. + +@item C-x C-a C-b (gud-break) +@pindex C-x C-a C-b (gud-break) +Set breakpoint at current line. + +@item C-x C-a C-d (gud-remove) +@pindex C-x C-a C-d (gud-remove) +Remove breakpoint at current line. + +@item C-x C-a C-l (gud-refresh) +@pindex C-x C-a C-d (gud-refresh) +Fix up a possibly garbled display, and redraw the arrow. + +@item C-c RET (comint-copy-old-input) +@pindex C-c RET (comint-copy-old-input) +Insert after prompt old input at point as new input to be edited. +Calls `comint-get-old-input' to get old input. + +@item C-c n (gud-next) +@pindex C-c n (gud-next) +Step one line, skipping functions. (Step over). + +@item C-x C-a C-o (comint-delete-output) +@pindex C-c n (comint-delete-output) +Delete all output from interpreter since last input. Does not delete +the prompt. + +@item C-x C-a C-r (gud-cont) + +@item C-c SPC (gud-step @var{arg}) +@pindex C-c SPC (gud-step @var{arg}) +@itemx C-x C-a C-s (gud-step @var{arg}) +@pindex C-x C-a C-s (gud-step @var{arg}) +Step one source line. Same as @value{DBG} @code{step} command. The +@value{Emacs} command name is @code{gud-step} and @code{C-x C-a C-s} +is an alternate binding which can be used in the source +script. +@c @xref{Step}. + +With a numeric argument, run that many times. +@xref{Arguments, , Numeric Arguments, Emacs, The @value{Emacs} +Manual}. + + +@item C-x C-a C-t (gud-tbreak @var{arg}) +Set temporary breakpoint at current line. + +@item C-x C-a C-w (backward-kill-word) +@item C-x C-a C-x (comint-get-next-from-history) +@item C-x C-a C-z (comint-stop-subjob) +Stop the current subjob. +This command also kills the pending input +between the process mark and point. + +WARNING: if there is no current subjob, you can end up suspending +the top-level process running in the buffer. If you accidentally do +this, use M-x comint-continue-subjob to resume the process. (This +is not a problem with most shells, since they ignore this signal.) + +@item C-x C-a C-\ (comint-quit-subjob) +Send quit signal to the current subjob. +This command also kills the pending input +between the process mark and point. + +@item C-c + (gud-step-plus) +Run @code{step+}. + +@item C-c . (comint-insert-previous-argument @var{index}) +Insert the @emph{index-th} argument from the previous Comint command-line at point. +Spaces are added at beginning and/or end of the inserted string if +necessary to ensure that it's separated from adjacent arguments. +Interactively, if no prefix argument is given, the last argument is inserted. +Repeated interactive invocations will cycle through the same argument +from progressively earlier commands (using the value of index specified +with the first command). + +@item C-c < (gud-up) +Go up a stack frame. With a numeric argument, go up that many +stack frames. Same @value{DBG} @code{up} command. +@xref{Arguments, , Numeric Arguments, Emacs, The @value{Emacs} +Manual}. + +@item C-c > (gud-down) +Go down a stack frame. Same as @value{DBG} @code{down}. +With a numeric argument, go down that many stack frames. +@xref{Arguments, , Numeric Arguments, Emacs, The @value{Emacs} +Manual}. + +@item C-c ? (rdebug-display-secondary-window-help-buffer) +Display the rdebug help buffer. + +@item C-c B (rdebug-display-breakpoints-buffer) +Display the rdebug breakpoints buffer. + +@item C-x C-a C (rdebug-display-cmd-buffer) +Display the rdebug command buffer. + +@item C-c O (rdebug-display-output-buffer) +Display the rdebug output buffer. + +@item C-c R (gud-run) +@itemx C-c r (gud run) +Restart or run the script. Same as @value{DBG} @code{run} command. + +@item C-c S (gud-source-resync) +@item C-c T (rdebug-display-stack-buffer) +Display the rdebug stack buffer. +@item C-c V (rdebug-display-variables-buffer) +Display the rdebug variables buffer. + +@item C-c W (rdebug-display-watch-buffer) +Display the rdebug watch buffer. + +@item C-c f (gud-finish @var{arg}) +@pindex C-c f (gud-finish @var{arg}) +Finish executing current function. + +@itemx C-x C-a C-f (gud-finish) +@pindex C-x C-a C-f (gud-finish) +Finish executing current function. The same as @value{DBG} +@code{finish} command. +@c @xref{Finish}. + +@item C-c n (gud-next) +@pindex C-c n (gud-next) +Execute to next source line in this function, skipping all function +calls. Same as @value{DBG} @code{next} command. +@c @xref{Next}. + +With a numeric argument, run that many times. +@c @xref{Arguments, , Numeric Arguments, Emacs, The @value{Emacs} Manual}. + +@item C-c q (gud-quit) + +@item C-x C-a C-l +Resynchronize the current position with the source window. The +@value{Emacs} command name is @code{gud-refresh} and @code{C-x C-a +C-l} is an alternate binding which also can be used in the source script. + +@item C-c a +Shows argument variables (e.g.@: @code{$1}, @code{$2}) of the current +stack frame. Same as @value{DBG} @code{info args} command. The +@value{Emacs} command name is @code{gud-args} and @code{C-x C-a a} is +an alternate binding which also can be used in the source script. + +@item C-c T +Show stack trace. Same as @value{DBG} @code{where} command. The +@value{Emacs} command name is @code{gud-where} and @code{C-x C-a T} is +an alternate binding which can be used in the source +script. +@c @xref{Backtrace}. + +@end table + +In any source file, the Emacs command @kbd{C-x SPC} (@code{gud-break}) +tells @value{DBG} to set a breakpoint on the source line point is on. + +If you accidentally delete the source-display buffer, an easy way to get +it back is to type the command @code{frame} in the @value{DBG} buffer, to +request a frame display; when you run under Emacs, this recreates +the source buffer if necessary to show you the context of the current +frame. + +The source files displayed in Emacs are in ordinary Emacs buffers +which are visiting the source files in the usual way. You can edit +the files with these buffers if you wish; but keep in mind that @value{DBG} +communicates with Emacs in terms of line numbers. If you add or +delete lines from the text, the line numbers that @value{DBG} knows cease +to correspond properly with the code. + +@xref{Debugger Operation, , , Emacs, The @value{Emacs} +Manual}. + +@node Emacs Source, , Debugger Command Buffer, Debugger Buffers +@section Commands from the source script + +@table @kbd +@item C-x SPC + +tells @value{DBG} to set a breakpoint on the source +line point is on. (@code{gud-break}) + +@item C-x C-a t + +@code{gud-linetrace} + +@item C-x C-a C-f +Restart or run the script. Same as @value{DBG} @code{run} command. The +@value{Emacs} command name is @code{gud-finish}. In the corresponding +I/O buffer, @code{C-c R} is an alternate binding. + +@item C-x C-a T +Show stack trace. Same as @value{DBG} @code{where} command. In the +corresponding I/O buffer, @code{C-c T} is an alternate +binding. +@c @xref{Backtrace}. + +@item C-x C-a < + +Go up a stack frame. With a numeric argument, go up that many +stack frames. Same @value{DBG} @code{up} command. +@xref{Arguments, , Numeric Arguments, Emacs, The @value{Emacs} Manual}. + +The @value{Emacs} command name is @code{gud-up}. In the corresponding +I/O buffer, @code{C-c <} is an alternate binding. + +@item C-x C-a > + +Go down a stack frame. Same as @value{DBG} @code{down}. +With a numeric argument, go down that many stack frames. +@xref{Arguments, , Numeric Arguments, Emacs, The @value{Emacs} +Manual}. + +The @value{Emacs} command name is @code{gud-down}. In the +corresponding I/O buffer, @code{C-c >} is an alternate binding. + +@item C-x C-a C-t + +@code{gud-tbreak} + +@item C-x C-a C-s + +Step one source line. Same as @value{DBG} @code{step} +command. +@c @xref{Step}. + +With a numeric argument, run that many times. +@xref{Arguments, , Numeric Arguments, Emacs, The @value{Emacs} +Manual}. + +The @value{Emacs} command name is @code{gud-step}. In the +corresponding I/O buffer, @code{C-x C-a C-s} is an alternate binding. + +@item C-x C-a C-e + +@code{gud-statement} + +@item C-x C-a R +Restart or run the script. Same as @value{DBG} @code{run} command. The +@value{Emacs} command name is @code{gud-run}. In the corresponding I/O +buffer, @code{C-c R} is an alternate binding. + +@item C-x C-a C-d +Delete breakpoint. @code{gud-remove} + +@item C-x C-a C-p + +@code{gud-print} + +@item C-x C-a C-n + +Execute to next source line in this function, skipping all function +calls. Same as @value{DBG} @code{next} command. With a numeric +argument, run that many times. @xref{Arguments, , Numeric Arguments, +Emacs, The @value{Emacs} Manual}. + +The @value{Emacs} command name is @code{gud-next}. In the +corresponding I/O buffer, @code{C-x C-a C-n} is an alternate binding. + +@item C-x C-a f C-f + +@code{gud-finish} + +@item C-x C-a C-r +Continue execution of your script Same as @value{DBG} @code{continue} +command. The @value{Emacs} command name is @code{gud-cont}. In the +corresponding I/O buffer, @code{C-x C-a C-r} is an alternate binding. +@c See @ref{Continue}. + +@item C-x C-a C-b + +@code{gud-break} + +@item C-x C-a a + +@code{gud-args} +Shows argument variables (e.g.@: @code{$1}, @code{$2}) of the current +stack frame. Same as @value{DBG} @code{info args} command. The +@value{Emacs} command name is @code{gud-args}. In the corresponding +I/O buffer, @code{C-c a} is an alternate binding which also can be +used in the source script. + +@item C-x C-a C-l +Move to current position in this source window. The @value{Emacs} +command name is @code{gud-refresh}. In the corresponding I/O buffer, +@code{C-x C-a C-l} is an alternate binding. + +@end table + +@node Emacs Debugger Commands, Emacs Command Index, Debugger Buffers, Top +@chapter Emacs Debugger Commands + +@menu +* Emacs Debugger Common Commands:: +* Emacs Debugger Breakpoint Buffer Commands:: +* Emacs Debugger Stack Buffer Commands:: +* Emacs Debugger Variable Buffer Commands:: +* Emacs Debugger Watch Buffer Commands:: +* Emacs GUD Commands:: +@end menu + +@node Emacs Debugger Common Commands, Emacs Debugger Breakpoint Buffer Commands, Emacs Debugger Commands, Emacs Debugger Commands +@section Emacs Debugger Common Commands + +The commands in this section are used to make a secondary buffer +visible. If the buffer doesn't exist, nothing is done. +The way the buffer is made visible is follows the following +rules tried in order: + +@enumerate +@item +If the buffer doesn't exist, do nothing. +@item +If the buffer is already displayed, switch to it. +@item +If the current buffer is a +secondary buffer, bury it replacing with the requested +buffer. +@item +If there is secondary buffer visible, that +is replaced instead. +@item +Just pick a visible buffer to bury and replace. + @end enumerate + +The commands are also have key bindings that end in an uppercase +letter. This letter is given in parenthesis. When in one of the +secondary buffers, the uppercase letter is bound to the command as well. + +@table @kbd + +@item (rdebug-display-breakpoints-buffer) (@kbd{B}) +@findex rdebug-display-breakpoints-buffer (@kbd{B}) +Display the rdebug breakpoints buffer. Bound to: @kbd{C-x C-a B}, +@kbd{ }. Secondary buffers: +@kbd{O}. + +@item (rdebug-display-cmd-buffer) (@kbd{C}) +@findex rdebug-display-cmd-buffer (@kbd{C}) +Display the debugger command buffer. + +Bound to: @kbd{C-x C-a C}, @kbd{ }. + +@item (rdebug-display-output-buffer) (@kbd{O}) +@findex rdebug-display-output-buffer (@kbd{?}) +Display the debugger output buffer. + +Bound to: @kbd{C-x C-a O}, @kbd{ +}. Secondary buffers: @kbd{O}. + +@item (rdebug-display-secondary-window-help-buffer) (@kbd{?}) +@findex rdebug-display-secondary-window-help-buffer (@kbd{?}) + +@item (rdebug-display-stack-buffer) (@kbd{T}) +@findex rdebug-display-stack-buffer (@kbd{T}) +Display the debugger stack buffer. Bound to: @kbd{C-x C-a T}, +@kbd{ }. Secondary buffers: @kbd{T}. + +@item (rdebug-display-variables-buffer) (@kbd{V}) +@findex rdebug-display-variables-buffer (@kbd{V}) +Display the debugger variables buffer. Bound to: @kbd{C-x C-a V}, +@kbd{ }. Secondary buffers: +@kbd{V}. + +@item (rdebug-display-watch-buffer) (@kbd{W}) +@findex rdebug-display-watch-buffer (@kbd{W}) +Display the debugger variables buffer. Bound to: @kbd{C-x C-a W}, +@kbd{ }. Secondary buffers: @kbd{V}. + +@item (rdebug-display-debugger-window-configuration) +@findex rdebug-display-debugger-window-configuration +Display the current layout of windows of the rdebug Ruby debugger. +@item (rdebug-display-original-window-configuration) +@findex rdebug-display-original-window-configuration +Display the layout of windows prior to starting the rdebug Ruby +debugger. This function is called upon quitting the debugger and +@var{rdebug-many-windows} is not nil. +@item (rdebug-goto-entry-n) +@findex rdebug-goto-entry-n +Breakpoints, Display expressions and Stack Frames all have +numbers associated with them which are distinct from line +numbers. In a secondary buffer, this function is usually bound to +a numeric key. which will position you at that entry number. To +go to an entry above 9, just keep entering the number. For +example, if you press 1 and then 9, you should jump to entry +1 (if it exists) and then 19 (if that exists). Entering any +non-digit will start entry number from the beginning again. +@item (rdebug-quit) - q +@findex rdebug-quit (q) +Kill the debugger process associated with the buffer. + +When @var{rdebug-many-windows} is active, the original window layout is +restored. +@item (rdebug-restore-windows) +@findex rdebug-restore-windows +Display the initial ruby debugger window layout. + +@end table + + +@node Emacs Debugger Breakpoint Buffer Commands, Emacs Debugger Stack Buffer Commands, Emacs Debugger Common Commands, Emacs Debugger Commands +@section Emacs Debugger Breakpoint Buffer Commands + +@table @kbd +@item (rdebug-goto-breakpoint) +@findex rdebug-goto-breakpoint +@item (rdebug-goto-breakpoint-mouse) +@findex rdebug-goto-breakpoint-mouse +@item (rdebug-breakpoints-mode) +@findex rdebug-breakpoints-mode +Major mode for displaying breakpoints in a secondary window. Uses +@var{rdebug-breakpoints-mode-map}. +@end table + +@node Emacs Debugger Stack Buffer Commands, Emacs Debugger Variable Buffer Commands, Emacs Debugger Breakpoint Buffer Commands, Emacs Debugger Commands +@section Emacs Debugger Stack Buffer Commands + +@table @kbd +@item (rdebug-goto-stack-frame) +@findex rdebug-goto-stack-frame +@item (rdebug-frames-mode) +@findex rdebug-frames-mode +Major mode for displaying the stack trace. Uses +@var{rdebug-frames-mode-map}. +@end table + +@node Emacs Debugger Variable Buffer Commands, Emacs Debugger Watch Buffer Commands, Emacs Debugger Stack Buffer Commands, Emacs Debugger Commands +@section Emacs Debugger Variable Buffer Commands + +@table @kbd +@item (rdebug-variables-edit) +@findex rdebug-variables-edit +@end table + +@node Emacs Debugger Watch Buffer Commands, Emacs GUD Commands, Emacs Debugger Variable Buffer Commands, Emacs Debugger Commands +@section Emacs Debugger Watch Buffer Commands + +@table @kbd +@item (rdebug-watch-add) +@findex rdebug-watch-add +Add a display expression. +@item (rdebug-watch-delete) +@findex rdebug-watch-delete +Delete a display expression. +@item (rdebug-watch-edit) +@findex rdebug-watch-edit +Edit a display expression. +@item (rdebug-watch-mode) +@findex rdebug-watch-mode +Major mode for displaying the display expressions. Uses +@var{rdebug-watch-mode-map}. +@end table + +@node Emacs GUD Commands, , Emacs Debugger Watch Buffer Commands, Emacs Debugger Commands +@section Emacs Debugger GUD Commands + +@table @kbd +@item (comint-copy-old-input) +@findex comint-copy-old-input +Insert after prompt old input at point as new input to be edited. +Calls `comint-get-old-input' to get old input. +@item (comint-delete-output) +@findex comint-delete-output +Delete all output from interpreter since last input. +Does not delete the prompt. +@item (gud-break) +@findex gud-break +Set a breakpoint on the source line point is on. +@item (gud-cont) - c +@findex gud-cont (c) +Continue execution. +@item (gud-next) - n +@findex gud-next (n) +Step one line, skipping functions. (Step over). +@item (gud-refresh) +@findex gud-refresh +Fix up a possibly garbled display, and redraw the arrow. +@item (gud-remove) +@findex gud-remove +Remove breakpoint at current line. +@item (gud-step) - s +@findex gud-step (s) +Step one statement. (Step into) +@item (gud-step-plus) - + +@findex gud-step-plus (+) +Run @code{step+}---like @code{gud-step} but ensure we go to a new +line. +@item (gud-tbreak @var{arg}) +@findex gud-tbreak +Set temporary breakpoint at current line. +@end table + +@node Emacs Command Index, Emacs Function Index, Emacs Debugger Commands, Top +@unnumbered Emacs Command Index +@printindex pg + +@node Emacs Function Index, Emacs Key Binding Index, Emacs Command Index, Top +@unnumbered Emacs Function Index +@printindex fn + +@node Emacs Key Binding Index, , Emacs Function Index, Top +@unnumbered Key Binding Index +@printindex ky + +@tex +% I think something like @colophon should be in texinfo. In the +% meantime: +\long\def\colophon{\hbox to0pt{}\vfill +\centerline{The body of this manual is set in} +\centerline{\fontname\tenrm,} +\centerline{with headings in {\bf\fontname\tenbf}} +\centerline{and examples in {\tt\fontname\tentt}.} +\centerline{{\it\fontname\tenit\/},} +\centerline{{\bf\fontname\tenbf}, and} +\centerline{{\sl\fontname\tensl\/}} +\centerline{are used for emphasis.}\vfill} +\page\colophon +% Blame: doc@cygnus.com, 1991. +@end tex + +@bye diff --git a/doc/rdebug.1 b/doc/rdebug.1 new file mode 100644 index 0000000..81241cf --- /dev/null +++ b/doc/rdebug.1 @@ -0,0 +1,241 @@ +.\" $Id: rdebug.1 516 2007-12-31 05:55:24Z rockyb $ +.TH rdebug 1 +.SH NAME +rdebug \- Fast Ruby debugger +.SH SYNOPSIS +.B rdebug +[debugger-options] +rdebug +[script-options...] +.SH "DESCRIPTION" +This manual page documents briefly the +.BR rdebug +command. +.PP +.B rdebug +is a fast implementation of the standard Ruby debugger debug.rb. It +is implemented by utilizing a Ruby C API hook, allows for remote +debugging and can be used as the Ruby debugger backend interface for a +development environment. +.PP +The commands generally follow gdb's command set unless there's good +reason not to. + +.PP +rdebug can do four main kinds of things (plus other things in support of +these) to help you catch bugs in the act: + +.TP +\ \ \ \(bu +Start or restart your Ruby script, specifying arguments that might +affect its behavior. + +.TP +\ \ \ \(bu +Make your program stop at various points possibly determined by +specified conditions. + +.TP +\ \ \ \(bu +Examine what has happened when your program has stopped. + +.TP +\ \ \ \(bu +Change things in your program, so you can experiment with correcting the +effects of one bug and go on to learn about another. +.PP + +Here are some of the most frequently-needed commands: +.TP +.B break \fR[\|\fIfile\fB:\fIline\fR\fR|\fIclass.method\fR] \fR[if \fIexpr\fR] +\& +Set a breakpoint at \c +.I class.method\c +\& or at the specified file and line. +.TP +.B continue \fR[\fIline\fR] +Continue running your program (after stopping, e.g. at a +breakpoint). If a line is given a one-time breakpoint is set there. +.TP +.B delete \fR[\fIbreakpoint-numbers\fR] +\& +Delete breakpoints by number. If no number is given delete all breakpoints. +.TP +.B down \fR[\|\fIcount\fR\|] +Move down one block frame. If count is given move up that many frames. A negative number +goes the other direction and is like the up command +.TP +.B finish +Run until the completion of the current function or method. +.TP +.BI frame " frame-number" +Set the stack frame to \fIframe-number\fR for purposes of examinine local variables. For positioning relative to the current frame, use +.B up +or +.B down. A negative number starts counting from the other end. +.TP +.B help \fR[\|\fIname\fR\|] +Show information about rdebug command \c +.I name\c +\&, or general information +about using rdebug. +.TP +.B info \fR[\|\fIname\fR\|] +Get the various information usually about the debugged program. +.TP +.B irb \fIcommand\fR +Run an interactive ruby shell (irb) using the current environment. +.TP +.B list \fR[\|\fIfile\fB:\fIline\fR|\fIfunction] +type the text of the program in the vicinity of where it is presently stopped +or at the specified function or file and line. +.TP +.B next \fR[\|\fIcount\fR\|] +Execute next program line(s) (after stopping); step \c +.I over\c +\& any +function calls in the line. +.TP +.BI pp " expr"\c +\& +Pretty print the value of an expression. +.TP +.BI print " expr"\c +\& +Display the value of an expression. +.TP +.BI ps " expr"\c +\& +Print an array as a columized sorted list. +.TP +.B quit +Exit from the debugger. +.TP +.B run \fR[\|\fIarglist\fR\|] +(Re)start your program (with \c +.I arglist\c +\&, if specified). If you want the debugger to get reloaded, use +.B restart +instead. +.TP +.B set +Modify parts of the debugger environment. +.TP +.B show +See the debugger environment settings +.TP +.BI source " filename"\c +\& +Read and execute the lines in file \fIfilename\fR as a series of debugger +commands. +.TP +.B step \fR[\|\fIcount\fR\|] +Execute next program line(s) (after stopping); step \c +.I into\c +\& any +function calls in the line. +.TP +.B up \fR[\|\fIcount\fR\|] +Move up one block frame. If count is given move up that many frames. A negative number +goes the other direction and is like the down command +.TP +.B where \fR[\|\fIcount\fR\|] +Display all or \fIcount\fR items of the program stack. +.PP +For full details on rdebug, see \c +http://rubyforge.org/projects/ruby-debug/ +.SH OPTIONS +.PP +.TP 10 +.TP +.B \-A | \-\-annotate LEVEL +Set gdb-style annotation to LEVEL, a number. Additional information is output +automatically when program state is changed. This can be used by +front-ends such as GNU Emacs to post this updated information without +having to poll for it. +.TP +.B \-\-client +Connect to a remote debugger. Used with another rdebug invocation using \-\-server. +See also \-\-host and \-\-cport options +.TP +.B \-\-cport=PORT +Port used for control commands. +.TP +.B \-d | \-\-debug +Set $DEBUG true. +.TP +.B \-\-emacs +Activates full GNU Emacs mode. Is the equivalent of setting the +options \-\-emacs\-basic, \-\-annotate=3, \-\-no-stop, \-\-no\-control +and \-\-post\-mortem. +.TP +.B \-\-emacs-basic +Activates GNU Emacs mode. Debugger prompts are prefaced with two octal +032 characters. +.TP +.B \-h | \-\-host=HOST +Host name used for remote debugging. +.TP +.B \-I | \-\-include PATH +Add PATH to $LOAD_PATH +.TP +.B \-m | \-\-post-mortem +Activate post-mortem mode. +.TP +.B \-\-no-control +Do not automatically start control thread. +.TP +.B \-\-no\-stop +Do not stop when script is loaded. +.TP +.B \-p | \-\-port=PORT +Host name used for remote debugging. +.TP +.B \-r | \-\-require SCRIPT +Require the library, before executing your script. +.TP +.B \-\-script FILE +Name of the script file to run. +.TP +.B \-x | \-\-trace +Show lines before executing them. +.TP +.B \-\-no\-quit +Do not quit when script terminates. Instead rerun the program. +.TP +.B \-\-version +Show the version number and exit. +.TP +.B \-\-verbose +Turn on verbose mode. +.TP +.B \-\-v +Print the version number, then turn on verbose mode if a script name +is given. If no script name is given just exit after printing the +version number. +.TP +.B \-\-nx +Don't execute commands found in any initialization files, e.g. .rdebugrc. +.TP +.B \-\-keep-frame-binding +Keep frame bindings. +.TP +.B \-\-script=FILE +Name of the script file to run +.B \-s | \-\-server +Listen for remote connections. Another rdebug session accesses using the \-\-client option. +See also the \-\-host, \-\-port and +\-\-cport options +.TP +.B \-w | \-\-wait +Wait for a client connection, implies -s option. +.TP +.B \-\-help +Show invocation help and exit. +.PD +.SH "SEE ALSO" +.Sp +http://rubyforge.org/projects/ruby-debug/ +.SH AUTHOR +rdebug was written by Kent Siblev. This manual page was written by +Rocky Bernstein diff --git a/doc/ruby-debug.texi b/doc/ruby-debug.texi new file mode 100644 index 0000000..c50ae37 --- /dev/null +++ b/doc/ruby-debug.texi @@ -0,0 +1,3982 @@ +\input texinfo @c -*-texinfo-*- +@setfilename ruby-debug.info + +@set DBG ruby-debug +@set ttrdebug @code{rdebug} +@set ttDBG @code{@value{DBG}} +@set Emacs @sc{gnu} Emacs + +@c Karl Berry informs me that this will add straight quotes in +@c typewriter text. +@c See the "Inserting Quote Characters" node in the Texinfo manual +@set txicodequoteundirected +@set txicodequotebacktick +@set RDEBUG_VERSION 0.10.4 + +@macro Example {} +@iftex +@cartouche +@end iftex +@smallexample +@end macro + +@macro EndExample {} +@iftex +@end cartouche +@end iftex +@end smallexample +@end macro + +@macro DBG {} +@value{DBG} +@end macro + +@macro ttDBG {} +@value{ttrdebug} +@end macro + +@c How to show optional variables. +@macro ovar{varname} +@r{[}@var{\varname\}@r{]} +@end macro + +@settitle ruby-debug +@setchapternewpage odd +@c %**end of header + +@include version.texi + +@finalout + +@c THIS MANUAL REQUIRES TEXINFO 4.0 OR LATER. + +@c This is a dir.info fragment to support semi-automated addition of +@c manuals to an info tree. +@dircategory Programming & development tools. +@direntry +* ruby-debug: (ruby-debug). Ruby Debugger +@end direntry + +@titlepage +@title Debugging with @code{ruby-debug} +@sp 1 +@subtitle @value{EDITION} Edition +@subtitle @value{UPDATED-MONTH} +@author Rocky Bernstein and Kent Sibilev +@page +@ifset WHERETO +@tex +{\parskip=0pt +\hfill (Send bugs and comments on ruby-debug to fill in...)\par +\hfill {\it Debugging with {\tt ruby-debug}\par +\hfill \TeX{}info \texinfoversion\par +} +@end tex +@end ifset +@end titlepage +@page + +@ifnottex +@node Top, Summary, (dir), (dir) +@top Debugging with ruby-debug + +This file describes ruby-debug, the Ruby Debugger, +version @value{RDEBUG_VERSION} + +This is the @value{EDITION} Edition, @value{UPDATED} +@c Copyright (C) 2007 ... + +@menu +* Summary:: Overview of Debugger with sample sessions +* Invocation:: Getting in and out +* Debugger Command Reference:: rdebug command reference +* Post-Mortem Debugging:: Debugging on an uncaught exception +* Debugger Module and Class:: ruby-debug's Debugger module and class + +Appendix +* Using from Subversion:: + +Indexes (nodes containing large menus) +* Class Module Index:: An item for Class, Module, and Methods. +* Command Index:: An item for each command name. +* General Index:: An item for each concept. +@end menu + +@end ifnottex + +@contents + +@node Summary +@chapter Summary of @code{ruby-debug} + +The purpose of a debugger such as @DBG{} is to allow you to see what is +going on ``inside'' a Ruby program while it executes. + +@ttDBG{} can do four main kinds of things (plus other things in support of +these) to help you catch bugs in the act: + +@itemize @bullet +@item +Start your script, specifying anything that might affect its behavior. + +@item +Make your script stop on specified conditions. + +@item +Examine what has happened, when your script has stopped. + +@item +Change things in your script, so you can experiment with correcting the +effects of one bug and go on to learn about another. +@end itemize + +Although you can use @value{ttrdebug} to invoke your Ruby programs via +a debugger at the outset, there are other ways to use and enter the +debugger. + +@menu +* First Sample Session:: A Simple Sample @code{rdebug} session +* Second Sample Session:: Second Session Delving a little deeper @code{rdebug} session +* Unit Testing Session:: Using the debugger in unit testing +* Debugger.start with a block:: Using the Debugger.start with a block +* Debugging Oddities:: How debugging Ruby may be different... +@end menu + +@node First Sample Session +@section The First Sample @code{rdebug} Session (@code{list}, @code{display}, @code{print}, and @code{quit}) + +You can use this manual at your leisure to read all about @value{ttDBG}. +However, a handful of commands are enough to get started using the +debugger. The following sections illustrates these commands. + +@iftex +In this sample session, we emphasize user input like this: @b{input}, +to make it easier to pick out from the surrounding output. +@end iftex + +Below is Ruby code to compute a triangle number of a given +length.@footnote{There are of course shorter ways to define @code{triangle} +such as: +@smallexample + def triangle(n) (n * (n+1)) / 2 end +@end smallexample +The code we use in this example and the next is more for pedagogical +purposes than how to write short Ruby code.} + + +@smallexample +$ @b{rdebug triangle.rb} +triangle.rb:4 def hanoi(n,a,b,c) +(rdb:1) @b{list} +[-1, 8] in ./triangle.rb + 1 #!/usr/bin/env ruby + 2 # Compute the n'th triangle number - the hard way + 3 # triangle(n) == (n * (n+1)) / 2 +=> 4 def triangle(n) + 5 tri = 0 + 6 0.upto(n) do |i| + 7 tri += i + 8 end +(rdb:1) @b{l} +[9, 18] in ./triangle.rb + 9 return tri + 10 end + 11 + 12 puts triangle(3) +(rdb:1) @b{list 1,100} +[1, 100] in ./triangle.rb + 1 #!/usr/bin/env ruby + 2 # Compute the n'th triangle number - the hard way + 3 # triangle(n) == (n * (n+1)) / 2 +=> 4 def triangle(n) + 5 tri = 0 + 6 0.upto(n) do |i| + 7 tri += i + 8 end + 9 return tri + 10 end + 11 + 12 puts triangle(3) +(rdb:1) +@end smallexample + +@noindent + +There are lots of command options, but we don't need them for now. See +@ref{rdebug command-line options} for a full list of command options. + +Position information consists of a filename and line number, +e.g.@: @code{triangle.rb:4}. We are currently stopped before the first +executable line of the program; this is line 4 of +@code{triangle.rb}. If you are used to less dynamic languages and have +used debuggers for more statically compiled languages like C, C++, or +Java, it may seem odd to be stopped before a function definition. But +in Ruby line 4 is executed, the name @code{triangle} (probably) does +not exist so issuing a method call of @code{triangle} will raise a +``method not found'' error. + +@DBG{}'s prompt is @code{(rdb:@emph{n})}. The @emph{n} is the thread +number. Here it is 1 which is usually the case for the main thread. If +the program has died and you are in post-mortem debugging, there is no +thread number. In this situation, the string @code{post-mortem} is +used in place of a thread number. If the program has terminated +normally, the string this position will be @code{ctrl}. The commands +which are available change depending on the program state. + +The first command, @code{list} (@pxref{List}), prints 10 lines +centered around the current line; the current line here is line 4 and +is marked by @code{=>}, so the range the debugger would like to show +is -1..8. However since there aren't 5 lines before the current line, +those additional lines---``lines'' -1 and 0---are dropped and we print +the remaining 8 lines. The @code{list} command can be abbreviated +with @code{l} which is what we use next. Notice that when we use this +a second time, we continue listing from the place we last left +off. The desired range of lines this time is lines 9 to 18; but since +the program ends as line 12, only the remaining 4 lines are shown. + +If you want to set how many lines to print by default rather than use +the initial number of lines, 10, use the @code{set listsize} command +(@pxref{Listsize}). To see the entire program in one shot, we gave an +explicit starting and ending line number. + +If you use a front-end to the debugger such as the Emacs interface, +@c (@pxref{GNU Emacs}) +you probably won't use @code{list} all that much. + +Now let us step through the program. + +@smallexample +(rdb:1) @b{step} +triangle.rb:12 +puts triangle(3) +(rdb:1) @b{@key{}} +triangle.rb:5 +tri = 0 +(rdb:1) @b{p tri} +nil +(rdb:1) @b{step} +triangle.rb:6 +0.upto(n) do |i| +(rdb:1) @b{p tri} +0 +@end smallexample + +The first @kbd{step} command (@pxref{Step}) runs the script one +executable unit. The second command we entered was just hitting the +return key; @ttDBG{} remembers the last command you entered was +@code{step}, so it runs that last command again. + +One way to print the values of variables uses @code{p}. (Of course, +there are of course lots of other ways too.). When we look at the +value of @code{tri} the first time, we see it is @code{nil}. Again we +are stopped @emph{before} the assignment on line 5, and this variable +hasn't been set previously. However after issuing another ``step'' +command we see that the value is 0 as expected. You could issue the +step and print comman in one shot: + +However if every time we stop we want to see the value of @code{tri} +to see how things are going stop, there is a better way by setting a +display expression (@pxref{DisplayCommands}). + +@smallexample +(rdb:1) display tri +1: tri = 0 +@end smallexample + +Now let us run the program until we return from the function. However +we'll want to see which lines get run. + +@smallexample +(rdb:1) @b{display i} +2: i = +(rdb:1) @b{set linetrace on} +line tracing is on. +(rdb:1) @b{finish} +Tracing(1):triangle.rb:7 tri += i +1: tri = 0 +2: i = 0 +Tracing(1):triangle.rb:7 tri += i +1: tri = 0 +2: i = 1 +Tracing(1):triangle.rb:7 tri += i +1: tri = 1 +2: i = 2 +Tracing(1):triangle.rb:7 tri += i +1: tri = 3 +2: i = 3 +Tracing(1):triangle.rb:9 return tri +1: tri = 6 +2: i = +(rdb:1) @b{quit} +Really quit? (y/n) y +@end smallexample + +So far, so good. A you can see from the above to get out of the +debugger, one can issue a @code{quit} command. (@code{q} and +@code{exit} are just as good. If you want to quit without being +prompted, suffix the command with an exclamation mark, e.g.\@code{q!}. + +@node Second Sample Session +@section Sample Session 2: Delving Deeper (@code{where}, @code{frame}, @code{restart}, @code{autoeval}, @code{break}, @code{ps}) + +In this section we'll introduce breakpoints, the call stack and +restarting. So far we've been doing pretty good in that we've not +encountered a bug to fix. Let's try another simple example. Okay +here's the program. + +Below we will debug a simple Ruby program to solve the classic Towers +of Hanoi puzzle. It is augmented by the bane of programming: some +command-parameter processing with error checking. + +@smallexample +$ @b{rdebug hanoi.rb} +hanoi.rb:3 def hanoi(n,a,b,c) +(rdb:1) @b{list 1,100} +[1, 100] in ./hanoi.rb + 1 #!/usr/bin/ruby + 2 +=> 3 def hanoi(n,a,b,c) + 4 if n-1 > 0 + 5 hanoi(n-1, a, c, b) + 6 end + 7 puts "Move disk %s to %s" % [a, b] + 8 if n-1 > 0 + 9 hanoi(n-1, c, b, a) + 10 end + 11 end + 12 + 13 i_args=ARGV.length + 14 if i_args > 1 + 15 puts "*** Need number of disks or no parameter" + 16 exit 1 + 17 end + 18 + 19 n=3 + 20 + 21 if i_args > 0 + 22 begin + 23 n = ARGV[0].to_i + 24 rescue ValueError, msg: + 25 print "** Expecting an integer, got: %s" % ARGV[0].to_s + 26 exit 2 + 27 end + 28 end + 29 + 30 if n < 1 or n > 100 + 31 puts "*** number of disks should be between 1 and 100" + 32 exit 2 + 33 end + 34 + 35 hanoi(n, :a, :b, :c) +(rdb:1) +@end smallexample + +Recall in the first section I said that before the @code{def} is run +the method it names is undefined. Let's check that out. First let's +see what private methods we can call before running @code{def hanoi} + +@smallexample +(rdb:1) @b{set autoeval on} +autoeval is on. +(rdb:1) @b{private_methods} +["select", "URI", "local_variables", "lambda", "chomp", ... +@end smallexample + +The @code{set autoeval} (@pxref{Autoeval}) command causes any commands +that are not normally understood to be debugger commands to get +evaluated as though they were Ruby commands. I use this a lot, so I +set this by putting it the command file @code{.rdebugrc}, +@pxref{Command Files}, that gets read when @code{ruby-debug} starts. + +As showing the list output of @code{private_methods}, I find this kind +of list unwieldy. What you are supposed to notice here is that +method @code{hanoi} is not in this list. When you ask +@code{ruby-debug} for a list of method names via @code{method +instance}, it doesn't show output in this way; @code{ruby-debug} can +sort and put into columns lists like this using the print command, @code{ps}. + + +@smallexample +(rdb:1) @b{ps private_methods} +Array exit! puts warn +Float fail raise y +Integer fork rand +Rational format readline +String gem_original_require readlines +URI getc remove_instance_variable +` gets scan +abort global_variables select +active_gem_with_options gsub set_trace_func +at_exit gsub! singleton_method_added +autoload initialize singleton_method_removed +autoload? initialize_copy singleton_method_undefined +binding iterator? sleep +block_given? lambda split +callcc load sprintf +caller local_variables srand +catch location_of_caller sub +chomp loop sub! +chomp! method_missing syscall +chop open system +chop! p test +dbg_print pp throw +dbg_puts print timeout +eval printf trace_var +exec proc trap +exit putc untrace_var +@end smallexample + +Now let's see what happens after stepping + +@smallexample +(rdb:1) @b{private.methods.member?("hanoi")} +false +(rdb:1) @b{step} +hanoi.rb:13 +i_args=ARGV.length +(rdb:1) @b{private_methods.member?("hanoi")} +true +(rdb:1) +@end smallexample + +Okay, now where were we? + +@smallexample +(rdb:1) @b{list} +[8, 17] in ./hanoi.rb + 8 if n-1 > 0 + 9 hanoi(n-1, c, b, a) + 10 end + 11 end + 12 +=> 13 i_args=ARGV.length + 14 if i_args > 1 + 15 puts "*** Need number of disks or no parameter" + 16 exit 1 + 17 end +(rdb:1) @b{ARGV} +[] +@end smallexample + +Ooops. We forgot to specify any parameters to this program. Let's try +again. We can use the @code{restart} command here. + +@smallexample +(rdb:1) @b{restart 3} +Re exec'ing: + /usr/bin/rdebug hanoi.rb 3 +hanoi.rb:3 +def hanoi(n,a,b,c) +(rdb:1) @b{break 4} +Breakpoint 1 file hanoi.rb, line 4 +(rdb:1) @b{continue} +Breakpoint 1 at hanoi.rb:4 +./hanoi.rb:4 if n-1 > 0 +(rdb:1) @b{display n} +1: n = 3 +(rdb:1) @b{display a} +2: a = a +(rdb:1) @b{undisplay 2} +(rdb:1) @b{display a.inspect} +3: a.inspect = :a +(rdb:1) @b{display b.inspect} +4: b.inspect = :b +(rdb:1) @b{continue} +Breakpoint 1 at hanoi.rb:4 +./hanoi.rb:4 +if n-1 > 0 +1: n = 2 +3: a.inspect = :a +4: b.inspect = :c +(rdb:1) @b{c} +Breakpoint 1 at hanoi.rb:4 +./hanoi.rb:4 +if n-1 > 0 +1: n = 1 +3: a.inspect = :a +4: b.inspect = :b +(rdb:1) @b{where} +--> #0 Object.hanoi(n#Fixnum, a#Symbol, b#Symbol, c#Symbol) at line hanoi.rb:4 + #1 Object.-(n#Fixnum, a#Symbol, b#Symbol, c#Symbol) at line hanoi.rb:5 + #2 Object.-(n#Fixnum, a#Symbol, b#Symbol, c#Symbol) at line hanoi.rb:5 + #3 at line hanoi.rb:35 +(rdb:1) +@end smallexample + +In the above we added a new command, @code{break} +(@pxref{Breakpoints}) which indicates to go into the debugger just +before that line of code is run. And @code{continue} resumes +execution. Notice the difference between @code{display a} and +@code{display a.inspect}. An implied string conversion is performed on +the expression after it is evaluated. To remove a display expression +we used @code{undisplay} is used. If we give a display number, just +that display expression is removed. + +Above we also used a new command @code{where} (@pxref{Backtrace} to +show the call stack. In the above situation, starting from the bottom +line we see we called the hanoi from line 35 of the file +@code{hanoi.rb} and the hanoi method called itself two more times at +line 5. + +In the call stack we show the file line position in the same format +when we stop at a line. Also we see the names of the parameters and +the types that those parameters @emph{currently} have. It's possible +that when the program was called the parameter had a different type, +since the types of variables can change dynamically. You alter the +style of what to show in the trace (@pxref{Callstyle}). + +Let's explore a little more. Now were were we? + +@smallexample +(rdb:1) @b{list} + 1 #!/usr/bin/ruby + 2 + 3 def hanoi(n,a,b,c) +=> 4 if n-1 > 0 + 5 hanoi(n-1, a, c, b) + 6 end + 7 puts "Move disk %s to %s" % [a, b] + 8 if n-1 > 0 +(rdb:1) @b{undisplay} +Clear all expressions? (y/n) @b{y} +(rdb:1) @b{i_args} +NameError Exception: undefined local variable or method `i_args' for main:Object +(rdb:1) @b{frame -1} +#3 at line hanoi.rb:35 +(rdb:1) @b{i_args} +1 +(rdb:1) @b{p n} +3 +(rdb:1) @b{down 2} +#2 Object.-(n#Fixnum, a#Symbol, b#Symbol, c#Symbol) at line hanoi.rb:5 +(rdb:1) @b{p n} +2 +@end smallexample + +Notice in the above to get the value of variable @code{n}, I have to +use a print command like @code{p n}; If I entered just @code{n}, that +would be taken to mean the debugger command ``next''. In the current +scope, variable @code{i_args} is not defined. However I can change to +the top-most frame by using the @code{frame} command. Just as with +arrays, -1 means the last one. Alternatively using frame number 3 +would have been the same thing; so would issuing @code{up 3}. + +Note that in the outside frame 3, the value of @code{i_args} can be +shown. Also note that the value of variable @code{n} is different. + +@node Unit Testing Session +@section Using the debugger in unit testing (@code{ruby-debug/debugger}, @code{Debugger.start}) + +In the previous sessions we've been calling the debugger right at the +outset. I confess that this mode of operation is usually not how I use +the debugger. + +There are a number of situations where calling the debugger at the outset is +impractical for a couple of reasons. + +@enumerate +@item +The debugger just doesn't work when run at the outset. By necessity +any debugging changes to the behavior or the program in slight and +subtle ways, and sometimes this can hinder finding the bugs. +@item +There's a lot of code which that needs to get run before the part you +want to inspect. Running this code takes time and you don't the +overhead of the debugger in this first part. +@end enumerate + +In this section we'll delve show how to enter the code in the middle +of your program, while delving more into the debugger operation. + +In this section we will also use unit testing. Using unit tests will +greatly reduce the amount of debugging needed while at the same time +increase the quality of your program. + +What we'll do is take the @code{triangle} code from the first session +and write a unit test for that. In a sense we did write a mini-test +for the program which was basically the last line where we printed the +value of triangle(3). This test however wasn't automated: the +implication is that someone would look at the output and verify that +what was printed is what was expected. + +And before we can turn that into something that can be +@code{required}, we probably want to remove that output. However I +like to keep in that line so that when I look at the file, I have an +example of how to run it. Therefore we will conditionally run this +line if that file is invoked directly, but skip it if it is +not.@footnote{@code{rdebug} resets @code{$0} to try to make things +like this work.} +@smallexample + if __FILE__ == $0 + puts triangle(3) + end +@end smallexample + +Let's call this file @code{tri2.rb}. + +Okay, we're now ready to write our unit test. We'll use +@code{"test/unit"} which comes with the standard Ruby distribution. +Here's the test code: + +@smallexample + #!/usr/bin/env ruby + require 'test/unit' + require 'tri2.rb' + + class TestTri < Test::Unit::TestCase + def test_basic + solutions = [] + 0.upto(5) do |i| + solutions << triangle(i) + end + assert_equal([0, 1, 3, 6, 10, 15], solutions, + 'Testing the first 5 triangle numbers') + end + end +@end smallexample + +If you run it will work. However if you run @code{rdebug} initially, +you will not get into the test, because @code{test/unit} wants to be +the main program. So here is a situation where one may need to modify +the program to add an explicit @emph{entry} into the +debugger.@footnote{For some versions of rake and @code{rdebug} you can +in fact set a breakpoint after running @code{rdebug} +initially. Personally though I find it much simpler and more reliable +to modify the code as shown here.} + +One way to do this is to add the following before the place you want +to stop: +@smallexample + require 'rubygems' + require 'ruby-debug/debugger' +@end smallexample +The line @code{require "rubygems"} is needed if @code{ruby-debug} is +installed as a Ruby gem. + +Let's add this code just after entering @code{test_basic}: +@smallexample + ... + def test_basic + @b{require "rubygems"} + @b{require "ruby-debug/debugger"} + solutions = [] + ... +@end smallexample + +Now we run the program.. +@smallexample + $ @b{ruby test-tri.rb} + Loaded suite test-tri + Started + test-tri.rb:9 + solutions = [] + (rdb:1) +@end smallexample +and we see that we are stopped at line 9 just before the +initialization of the list @code{solutions}. + +Now let's see where we are... + +@smallexample +(rdb:1) @b{where} +--> #0 TestTri.test_basic at line /home/rocky/ruby/test-tri.rb:9 +(rdb:1) +@end smallexample + +Something seems wrong here; @code{TestTri.test_basic} indicates that +we are in class @code{TestTri} in method @code{test_basic}. However we +don't see the call to this like we did in the last example when we +used the @code{where} command. This is because the debugger really +didn't spring into existence until after we already entered that +method, and Ruby doesn't keep call stack information around in a +way that will give the information we show when running @code{where}. + +If we want call stack information, we have to turn call-stack tracking +on @emph{beforehand}. This is done by adding @code{Debugger.start}. + +Here's what our test program looks like so after we modify it to start +tracking calls from the outset + +@smallexample +#!/usr/bin/env ruby +require 'test/unit' +require 'tri2.rb' +require 'rubygems' +@b{Debugger.start} + +class TestTri < Test::Unit::TestCase + def test_basic + @b{debugger} + solutions = [] + 0.upto(5) do |i| + solutions << triangle(i) + end + assert_equal([0, 1, 3, 6, 10, 15], solutions, + "Testing the first 5 triangle numbers") + end +end +@end smallexample + +Now when we run this: +@smallexample +$ @b{ruby test-tri2.rb} +Loaded suite test-tri2 +Started +test-tri2.rb:11 +solutions = [] +(rdb:1) @b{where} +--> #0 TestTri.test_basic at line test-tri2.rb:11 + #1 Kernel.__send__(result#Test::Unit::TestResult) + at line /usr/lib/ruby/1.8/test/unit/testcase.rb:70 + #2 Test::Unit::TestCase.run(result#Test::Unit::TestResult) + at line /usr/lib/ruby/1.8/test/unit/testcase.rb:70 +... + #11 Test::Unit::AutoRunner.run + at line /usr/lib/ruby/1.8/test/unit/autorunner.rb:200 + #12 Test::Unit::AutoRunner.run(force_standalone#FalseClass, ... + at line /usr/lib/ruby/1.8/test/unit/autorunner.rb:13 + #13 at line /usr/lib/ruby/1.8/test/unit.rb:285 +(rdb:1) +@end smallexample + +Much better. But again let me emphasize that the parameter types are +those of the corresponding variables that @emph{currently} exist, and +this might have changed since the time when the call was made. Even so +and even though we only have @emph{types} listed, it's a pretty good +bet that when @code{Test::Unit} was first called, shown above as frame +12, that the values of its two parameters were @code{false} and +@code{nil}. + +@node Debugger.start with a block +@section Using the @code{Debugger.start} with a block + +We saw that @code{Debugger.start()} and @code{Debugger.stop()} allow +fine-grain control over where the debugger tracking should occur. + +Rather than use an explicit @code{stop()}, you can also pass a block +to the @code{start()} method. This causes @code{start()} to run and +then @code{yield} to that block. When the block is finished, +@code{stop()} is run. In other words, this wraps a +@code{Debugger.start()} and @code{Debugger.stop()} around the block of +code. But it also has a side benefit of ensuring that in the presence +of an uncaught exception @code{stop} is run, without having to +explicitly use @code{begin} ... @code{ensure Debugger.stop() end}. + +For example, in Ruby Rails you might want to debug code in one of the +controllers without causing any slowdown to any other code. And +this can be done by wrapping the controller in a @code{start()} with a +block; when the method wrapped this way finishes the debugger is +turned off, and the application proceeds at regular speed. + +Of course, inside the block you will probably want to enter the +debugger using @code{Debugger.debugger()}, otherwise there would +little point in using the @code{start}. For example, you can do this +in @code{irb}: + +@smallexample +$ @b{irb} +irb(main):001:0> @b{require 'rubygems'; require 'ruby-debug'} +=> true +irb(main):002:0> @b{def foo} +irb(main):003:1> @b{x=1} +irb(main):004:1> @b{puts 'foo'} +irb(main):005:1> @b{end} +=> nil +irb(main):006:0> @b{Debugger.start@{debugger; foo@}} +(irb):6 +(rdb:1) @b{s} +(irb):3 +(rdb:1) @b{p x} +nil +(rdb:1) @b{s} +(irb):4 +(rdb:1) @b{p x} +1 +(rdb:1) @b{s} +foo +=> true +irb(main):007:0> +@end smallexample + +There is a counter inside of @code{Debugger.start} method to make sure +that this works when another @code{Debugger.start} method is called +inside of outer one. However if you are stopped inside the debugger, +issuing another @code{debugger} call will not have any effect even if +it is nested inside another @code{Debugger.start}. + +@node Debugging Oddities +@section How debugging Ruby may be different than debugging other Languages + +If you are used to debugging in other languages like C, C++, Perl, +Java or even Bash@footnote{this is just an excuse to put in a +shameless plug for my bash debugger @url{http://bashdb.sf.net}}, there +may be a number of things that seem or feel a little bit different and +may confuse you. A number of these things aren't oddities of the +debugger per see, so much as a difference in how Ruby works compared to +those other languages. Because Ruby works a little differently from +those other languages, writing a debugger has to also be a little +different as well if it is to be useful. + +In this respect, using the debugger may help you understand Ruby +better. + +We've already seen two examples of such differences. One difference is +the fact that we stop on method definitions or @code{def}'s and that's +because these are in fact executable statements. In other compiled +languages this would not happen because that's already been done when +you compile the program (or in Perl when it scans in the program). The +other difference we saw was in our inability to show call stack parameter +types without having made arrangements for the debugger to track +this. In other languages call stack information is usually available +without asking assistance of the debugger.@footnote{However in C, and +C++ generally you have to ask the compiler to add such information.} + +In this section we'll consider some other things that might throw +off new users to Ruby who are familiar with other languages and +debugging in them. + +@menu +* Stack Shows Scope Nesting:: +* More Frequent Evaluations per Line:: +* Bouncing Around in Blocks (e.g. Iterators):: +* No Parameter Values in a Call Stack:: +* Lines You Can Stop At:: +@end menu + +@node Stack Shows Scope Nesting +@subsection Stack Shows Scope Nesting +In a backtrace, you will find more stack frames than you might in say +C. + +Consider another way to write the triangle program of @pxref{First +Sample Session}. + +@smallexample + 1 #!/usr/bin/env ruby + 2 def triangle(n) + 3 (0..n).inject do |sum, i| + 4 sum +=i + 5 end + 6 end + 7 puts triangle(3) +@end smallexample + +Let's stop inside the @code{inject} block: + +@smallexample +$ @b{rdebug tri3.rb} +(rdb:1) @b{c 4} +tri3.rb:4 +sum +=i +(rdb:1) @b{where} +--> #0 Range.triangle at line tri3.rb:4 + #1 Enumerable.inject at line tri3.rb:3 + #2 Object.triangle(n#Fixnum) at line tri3.rb:3 + #3 at line tri3.rb:7 +(rdb:1) +@end smallexample +Because a new scope was entered, it appears as a stack frame. Probably +``scope'' frame would be a more appropriate name. + +@node More Frequent Evaluations per Line +@subsection More Frequent Evaluations per Line +Consider this simple program to compute the Greatest Common Divisor of +two numbers: +@smallexample + 1 #!/usr/bin/env ruby + 2 # GCD. We assume positive numbers + 3 + 4 def gcd(a, b) + 5 # Make: a <= b + 6 if a > b + 7 a, b = [b, a] + 8 end + 9 +10 return nil if a <= 0 +11 +12 if a == 1 or b-a == 0 +13 return a +14 end +15 return gcd(b-a, a) +16 end +17 +18 a, b = ARGV[0..1].map @{|arg| arg.to_i@} +19 puts "The GCD of %d and %d is %d" % [a, b, gcd(a, b)] +@end smallexample + +Now let's try tracing a portion of the program to see what we get. +@smallexample +$ @b{rdebug gcd.rb 3 5} +gcd.rb:4 +def gcd(a, b) +(rdb:1) @b{step} +gcd.rb:18 +a, b = ARGV[0..1].map @{|arg| arg.to_i@} +(rdb:1) @b{step} +gcd.rb:18 +a, b = ARGV[0..1].map @{|arg| arg.to_i@} +(rdb:1) @b{step} +gcd.rb:18 +a, b = ARGV[0..1].map @{|arg| arg.to_i@} +(rdb:1) @b{step} +(rdb:1) @b{break Object.gcd} +Breakpoint 1 at Object::gcd +(rdb:1) @b{continue} +Breakpoint 1 at Object:gcd +gcd.rb:4 +def gcd(a, b) +(rdb:1) @b{set linetrace on} +line tracing is on. +(rdb:1) @b{continue} +Tracing(1):gcd.rb:6 if a > b +Tracing(1):gcd.rb:6 if a > b +Tracing(1):gcd.rb:10 return nil if a <= 0 +Tracing(1):gcd.rb:10 return nil if a <= 0 +Tracing(1):gcd.rb:12 if a == 1 or b-a == 0 +Tracing(1):gcd.rb:12 if a == 1 or b-a == 0 +Tracing(1):gcd.rb:15 return gcd(b-a, a) +Breakpoint 1 at Object:gcd +gcd.rb:4 +def gcd(a, b) +(rdb:1) +@end smallexample + +The thing to note here is that we see lots of lines duplicated. For +example, the first line: +@smallexample +Tracing(1):gcd.rb:18 a, b = ARGV[0..1].map @{|arg| arg.to_i@} +@end smallexample +appears three times. If we were to break this line into the equivalent +multi-line expression: +@smallexample +a, b = ARGV[0..1].map do |arg| + arg.to_i +end +@end smallexample +we would find one stop at the first line before running @code{map} and +two listings of @code{arg.to_i}, once for each value of arg which here +is 0 and then 1. Perhaps this is is not surprising because we have a +loop here which gets run in this situation 3 times. A similar command +@code{next}, can also be used to skip over loops and method +calls. + +But what about all the duplicated @code{if} statements in @code{gcd}? +Each one is listed twice whether or not we put the @code{if} at the +beginning or the end. You will find this to be the case for any +conditional statement such as @code{until} or @code{while}. + +Each statement appears twice because we stop once before the +expression is evaluated and once after the expression is evaluated but +before the if statement takes hold. There is a bug in Ruby up to +version 1.8.6 in that we stop a second time before the evaluation, so +examining values that may have changed during the expression +evaluation doesn't work in these versions. + +If you are issuing a @code{step} command one at a time, the repetitive +nature can be little cumbersome if not annoying. So @value{DBG} offers +a variant called @code{step+} which forces a new line on every +step. Let's try that. +@smallexample +(rdb:1) @b{R} +Re exec'ing: + /usr/bin/rdebug gcd.rb 3 5 +gcd.rb:4 +def gcd(a, b) +(rdb:1) @b{step+} +gcd.rb:18 +a, b = ARGV[0..1].map @{|arg| arg.to_i@} +(rdb:1) @b{step+} +gcd.rb:19 +puts "The GCD of %d and %d is %d" % [a, b, gcd(a, b)] +(rdb:1) @b{break Object.gcd} +Breakpoint 1 at Object:gcd +(rdb:1) @b{c} +Breakpoint 1 at Object:gcd +gcd.rb:4 +def gcd(a, b) +(rdb:1) @b{set linetrace+} +line tracing style is different consecutive lines. +(rdb:1) @b{set linetrace on} +line tracing is on. +(rdb:1) @b{c} +Tracing(1):gcd.rb:6 if a > b +Tracing(1):gcd.rb:10 return nil if a <= 0 +Tracing(1):gcd.rb:12 if a == 1 or b-a == 0 +Tracing(1):gcd.rb:15 return gcd(b-a, a) +Breakpoint 1 at Object:gcd +gcd.rb:4 +def gcd(a, b) +@end smallexample + +If you want @code{step+} to be the default behavior when stepping, +issue the command @code{set forcestep on}, (@pxref{Forcestep}). I +generally put this in my start-up file @code{.rdebugrc}. + +Similar to the difference between @code{step+} and @code{step} is +@code{set linetrace+}. This removes duplicate consecutive line tracing. + +One last thing to note above is the use of a method name to set a +breakpoint position, rather than a file and line number. Because +method @code{gcd} is in the outermost scope, we use @code{Object} as the +class name. + +@node Bouncing Around in Blocks (e.g. Iterators) +@subsection Bouncing Around in Blocks (e.g.@: Iterators) + +When debugging languages with coroutines like Python and Ruby, a +method call may not necessarily go to the first statement after the +method header. It's possible the call will continue after a +@code{yield} statement from a prior call. + +@smallexample + 1 #!/usr/bin/env ruby + 2 # Enumerator for primes + 3 class SievePrime + 4 @@@@odd_primes = [] + 5 def self.next_prime(&block) + 6 candidate = 2 + 7 yield candidate + 8 not_prime = false + 9 candidate += 1 +10 while true do +11 @@@@odd_primes.each do |p| +12 not_prime = (0 == (candidate % p)) +13 break if not_prime +14 end +15 unless not_prime +16 @@@@odd_primes << candidate +17 yield candidate +18 end +19 candidate += 2 +20 end +21 end +22 end +23 SievePrime.next_prime do |prime| +24 puts prime +25 break if prime > 10 +26 end +@end smallexample + +@smallexample +$ @b{rdebug primes.rb} +primes.rb:3 +class SievePrime +(rdb:1) @b{set linetrace on} +line tracing is on. +(rdb:1) @b{step 10} +Tracing(1):primes.rb:4 @@odd_primes = [] +Tracing(1):primes.rb:5 def self.next_prime(&block) +Tracing(1):primes.rb:23 SievePrime.next_prime do |prime| +Tracing(1):primes.rb:6 candidate = 2 +Tracing(1):primes.rb:7 yield candidate +Tracing(1):primes.rb:24 puts prime +2 +Tracing(1):primes.rb:25 break if prime > 10 +Tracing(1):primes.rb:25 break if prime > 10 +Tracing(1):primes.rb:8 not_prime = false +Tracing(1):primes.rb:9 candidate += 1 +primes.rb:9 +candidate += 1 +(rdb:1) +@end smallexample + +The loop between lines 23--26 gets interleaved between those of +@code{Sieve::next_prime}, lines 6--19 above. + +A similar kind of thing can occur in debugging programs with many threads. + +@node No Parameter Values in a Call Stack +@subsection No Parameter Values in a Call Stack +In traditional debuggers in a call stack you can generally see the +names of the parameters and the values that were passed in. + +Ruby is a very dynamic language and it tries to be efficient within +the confines of the language definition. Values generally aren't taken +out of a variable or expression and pushed onto a stack. Instead a new +scope created and the parameters are given initial values. Parameter +passing is by @emph{reference}, not by value as it is say Algol, C, or +Perl. During the execution of a method, parameter values can +change---and often do. In fact even the @emph{class} of the object can +change. + +So at present, the name of the parameter shown. The call-style setting +@pxref{Callstyle} can be used to set whether the name is shown or the +name and the @emph{current} class of the object. + +It has been contemplated that a style might be added which saves on +call shorter ``scalar'' types of values and the class name. + +@node Lines You Can Stop At +@subsection Lines You Can Stop At +As with the duplicate stops per control (e.g.@: @code{if} statement), +until tools like debuggers get more traction among core ruby +developers there are going to be weirdness. Here we describe the +stopping locations which effects the breakpoint line numbers you can +stop at. + +Consider the following little Ruby program. + +@smallexample +'Yes it does' =~ / +(Yes) \s+ +it \s+ +does +/ix +puts $1 +@end smallexample + +The stopping points that Ruby records are the last two lines, lines 5 +and 6. If you run @code{ruby -rtracer} on this file you'll see that +this is so: + +@smallexample +$ ruby -rtracer lines.rb +#0:lines.rb:5::-: /ix +#0:lines.rb:6::-: puts $1 +#0:lines.rb:6:Kernel:>: puts $1 +#0:lines.rb:6:IO:>: puts $1 +Yes#0:lines.rb:6:IO:<: puts $1 +#0:lines.rb:6:IO:>: puts $1 + +#0:lines.rb:6:IO:<: puts $1 +#0:lines.rb:6:Kernel:<: puts $1 +@end smallexample + +Inside @code{ruby-debug} you an get a list of stoppable lines for a +file using the @code{info file} command with the attribute +@code{breakpoints}. + +@ifset FINISHED +To be continued... + +@itemize @bullet +@item more complex example with objects, pretty printing and irb. +@item line tracing and non-interactive tracing. +@item mixing in Debugger.debug with rdebug +@item post-mortem debugging and setting up for that +@item threading? +@item references to videos +@end itemize +@end ifset + +@node Invocation +@chapter Getting in and out + +@menu +* Starting the debugger:: How to enter the debugger +* Command Files:: Command files +* Quitting the debugger:: How to leave the debugger (quit, kill) +* Calling from Program:: Calling the debugger from inside your program +@end menu + +It is also possible to enter the debugger when you have an uncaught +exception. See See also @ref{Post-Mortem Debugging}. + +@node Starting the debugger +@section Starting the debugger + +Although one can enter @DBG{} via Emacs (described in a later section) +and possibly others interfaces, probably the most familiar thing to do +is invoke the debugger from a command line. + +A wrapper shell script called @code{rdebug} basically @code{require}'s +the gem package @code{ruby-debug} and then loads @code{rdebug}. + +@smallexample +rdebug [rdebug-options] [--] @var{ruby-script} @var{ruby-script-arguments...} +@end smallexample + +If you don't need to pass dash options to your program which might get +confused with the debugger options, then you don't need to add the +@option{--}. + +To get a brief list of options and descriptions, use the @code{--help} +option. + +@smallexample +$ @b{rdebug --help} +rdebug @value{RDEBUG_VERSION} +Usage: rdebug [options] -- + +Options: + -A, --annotate LEVEL Set annotation level + -c, --client Connect to remote debugger + --cport PORT Port used for control commands + -d, --debug Set $DEBUG=true + --emacs Activates full Emacs support + --emacs-basic Activates basic Emacs mode + -h, --host HOST Host name used for remote debugging + -I, --include PATH Add PATH to $LOAD_PATH + --keep-frame-binding Keep frame bindings + -m, --post-mortem Activate post-mortem mode + --no-control Do not automatically start control thread + --no-quit Do not quit when script finishes + --no-rewrite-program Do not set $0 to the program being debugged + --no-stop Do not stop when script is loaded + -p, --port PORT Port used for remote debugging + -r, --require SCRIPT Require the library, before executing your script + --script FILE Name of the script file to run + -s, --server Listen for remote connections + -w, --wait Wait for a client connection, implies -s option + -x, --trace Turn on line tracing + +Common options: + --verbose Turn on verbose mode + --help Show this message + --version Print the version + -v Print version number, then turn on verbose mode +@end smallexample + +Options for the @code{rdebug} are shown in the following list. + +@menu +* rdebug command-line options:: Options you can pass to rdebug +* rdebug default options:: How to Set Default Command-Line Options +@end menu + +@node rdebug command-line options +@subsection Options you can pass to rdebug + +You can run @DBG{} in various alternative modes---for example, as a +program that interacts directly with the program in the same process +on the same computer or via a socket to another process possibly on a +different computer. + +Many options appear as a long option name, such as @option{--help}, and +a short one letter option name, such as @option{-h}. A double dash +(@option{--} is used to separate options which go to @code{rdebug} from +options that are intended to go to your Ruby script. Options (if any) +to @code{rdebug} should come first. If there is no possibility of the +Ruby script to be debugged getting confused with @code{rdebug}'s +option the double dash can be omitted. + +@table @code +@item --help +@cindex @option{-h} +@cindex @option{--help} +This option causes @ttDBG{} to print some basic help and exit. + +@item -v | --version +@cindex @option{-v} +This option causes @ttDBG{} to print its version number and exit. + +@item -A | --annotate @var{level} +@cindex @option{-A} +@cindex @option{--annotation} @var{level} +Set gdb-style annotation @var{level}, a number. Additional information is output +automatically when program state is changed. This can be used by +front-ends such as GNU Emacs to post this updated information without +having to poll for it. +@item -c | --client +@cindex @option{-c} +@cindex @option{--client} +Connect to remote debugger. The remote debugger should have been set +up previously our you will get a connection error and @code{rdebug} +will terminate. + +@item --cport @var{port} +@cindex @option{--cport} @var{port} +Port used for control commands. + +@item --debug +@cindex @option{--debug} +Set @code{$DEBUG} to @code{true}. This option is compatible with +Ruby's. + +@item --emacs +Activates GNU Emacs mode. +@c @pxref{GNU Emacs}. +Debugger output is tagged in such a way to allow GNU Emacs to track +where you are in the code. + +@item --emacs-basic +Activates full GNU Emacs mode. +@c (@pxref{GNU Emacs}). +This is the equivalent of setting the options @option{--emacs-basic}, +@code{annotate=3}, @option{--no-stop}, @option{-no-control} and +@option{--post-mortem}. + +@item -h | --host @var{host-address} +Connect host address for remote debugging. + +@item -I --include @var{PATH} +@cindex @option{-I} @var{PATH} +@cindex @option{--include} @var{PATH} +Add @var{PATH} to @code{$LOAD_PATH} + +@item --keep-frame-binding +@cindex @option{--keep-frame-binding} +Bindings are used to set the proper environment in evaluating +expression inside the debugger. Under normal circumstances, I don't +believe most people will ever need this option. + +By default, the debugger doesn't create binding object for each frame +when the frame is created, i.e. when a call is performed. Creating a +binding is an expensive operation and has been a major source of +performance problems. + +Instead, the debugger creates a binding when there is a need to +evaluate expressions. The artificial binding that is created might be +different from the real one. In particular, in performing constant +and module name resolution. + +However it's still possible to restore the old, slower behavior by +using this option or by setting @code{Debugger.keep_frame_binding = +true}. There are two possibilities for which you might want to use +this option. + +First, if you think there's a bug in the evaluation of variables, you +might want to set this to see if this corrects things. + +Second, since the internal structures that are used here @code{FRAME} +and @code{SCOPE} are not part of the Ruby specification, it is +possible they can change with newer releases; so here this option this +may offer a remedy. (But you'll probably also have to hack the C code +since it's likely under this scenario that ruby-debug will no longer +compile.) In fact, in Ruby 1.9 these structures have changed and that +is partly why this debugger doesn't work on Ruby 1.9. + +@item -m | --post-mortem +@cindex @option{-m} +@cindex @option{--post-mortem} +If your program raises an exception that isn't caught you can enter +the debugger for inspection of what went wrong. You may also want to +use this option in conjunction with @option{--no-stop}. See also +@ref{Post-Mortem Debugging}. + +@item --no-control +@cindex @option{--no-control} +Do not automatically start control thread. + +@item --no-quit +@cindex @option{--no-quit} +Restart the debugger when your program terminates normally. + +@item --no-rewrite-program +@cindex @option{--no-rewrite-program} +Normally @code{rdebug} will reset the program name @code{$0} from its +name to the debugged program, and set the its name in variable +@code{$RDEBUG_0}. In the unlikely even you don't want this use this option. + +@item --no-stop +@cindex @option{--no-stop} +Normally the @code{rdebug} stops before executing the first +statement. If instead you want it to start running initially and will +perhaps break it later in the running, use this options. + +@item -p | --port @var{port} +@cindex @option{-p} @var{port} +@cindex @option{--port} @var{port} +Port used for remote debugging. + +@item -r | --require @var{library} +@cindex @option{-r} +@cindex @option{--require} +Require the library, before executing your script. However if the +library happened to be @code{debug}, we'll just ignore the require +(since we're already a debugger). This option is compatible with Ruby's. + +@item --script @var{file} +@cindex @option{--script} +Require the library, before executing your script. However if the +library hap-pend to be @code{debug}, we'll just ignore the require +(since we're already a debugger). This option is compatible with Ruby's. + +@item -s | --server +@cindex @option{-s} +@cindex @option{--server} +Debug the program but listen for remote connections on the default +port or port set up via the @option{--port} option. See also @option{--wait}. + +@item -w | --wait +@cindex @option{-w} +@cindex @option{--wait} +Debug the program but stop waiting for a client connection first. This +option automatically sets @option{--server} option. + +@item -x | --trace +@cindex @option{-x} +@cindex @option{--trace} +Turn on line tracing. Running @command{rdebug --trace @emph{rubyscript.rb}} +is much like running: @command{ruby -rtracer @emph{rubyscript.rb}} + +If all you want to do however is get a linetrace, @code{tracer}, not +@code{rdebug}, may be faster: +@smallexample +$ @b{time ruby -rtracer gcd.rb 34 21 > /dev/null} + +real 0m0.266s +user 0m0.008s +sys 0m0.000s +$ @b{time rdebug --trace gcd.rb 34 21 > /dev/null} + +real 0m0.875s +user 0m0.448s +sys 0m0.056s +$ +@end smallexample + +@end table + +@node rdebug default options +@subsection How to Set Default Command-Line Options + +@DBG{} has many command-line options; it seems that some people want +to set them differently from the our defaults. For example, some +people may want @option{--no-quit --no-control} to be the default +behavior. One could write a wrapper script or set a shell alias to +handle this. @DBG{} has another way to do this as well. Before +processing command options if the file @code{$HOME/.rdboptrc} is found +it is loaded. If you want to set the defaults in some other way, you +can put Ruby code here and set variable @code{options} which is an +OpenStruct. For example here's how you'd set @option{-no-quit} and +change the default control port to 5000. + +@smallexample +# This file contains how you want the default options to ruby-debug +# to be set. Any Ruby code can be put here. +# +# debugger # Uncomment if you want to debug rdebug! +options.control = false +options.port = 5000 +puts "rocky's rdboptrc run" +@end smallexample + +Here are the default values in @code{options} +@smallexample +# +@end smallexample + + +@node Command Files +@section Command files + +@cindex command files +A command file for @DBG{} is a file of lines that are @DBG{} +commands. Comments (lines starting with @kbd{#}) may also be included. +An empty line in a command file does nothing; it does not mean to repeat +the last command, as it would from the terminal. + +@cindex init file +@cindex @file{.rdebugrc} +When you start @value{DBG}, it automatically executes commands from its +@dfn{init files}, normally called @file{.rdebugrc}. + +On some configurations of @value{DBG}, the init file may be known by a +different name. In particular on MS-Windows (but not cygwin) +@file{rdebug.ini} is used. + +During startup, @DBG{} does the following: + +@enumerate +@item +Processes command line options and operands. + +@item +Reads the init file in your current directory, if any, and failing +that the home directory. The home directory is the directory named in +the @code{HOME} or @code{HOMEPATH} environment variable. + +Thus, you can have more than one init file, one generic in your home +directory, and another, specific to the program you are debugging, in +the directory where you invoke @DBG{}. + +@item +Reads command files specified by the @samp{--script} option. +@end enumerate + +You can also request the execution of a command file with the +@code{source} command, @pxref{Source}. + +@node Quitting the debugger +@section Quitting the debugger + +@cindex interrupt +An interrupt (often @kbd{C-c}) does not exit from @value{DBG}, but +rather terminates the action of any @DBG command that is in +progress and returns to @value{DBG} command level. Inside a debugger +command interpreter, use @code{quit} command (@pxref{Control, ,Quitting +the debugger}). + +There way to terminate the debugger is to use the @code{kill} +command. This does more forceful @code{kill -9}. It can be used in +cases where @code{quit} doesn't work. + +@node Calling from Program +@section Calling the debugger from inside your Ruby program + +Running a program from the debugger adds a bit of overhead and slows +down your program a little. + +Furthermore, by necessity, debuggers change the operation of the +program they are debugging. And this can lead to unexpected and +unwanted differences. It has happened so often that the term +``Heisenbugs'' (see @url{http://en.wikipedia.org/wiki/Heisenbug}) was +coined to describe the situation where the addition of the use of a +debugger (among other possibilities) changes behavior of the program +so that the bug doesn't manifest itself anymore. + +There is another way to get into the debugger which adds no overhead +or slowdown until you reach the point at which you want to start +debugging. However here you must change the script and make an +explicit call to the debugger. Because the debugger isn't involved +before the first call, there is no overhead and the script will run +at the same speed as if there were no debugger. + +There are three parts to calling the debugger from inside the script, +``requiring'' the debugger code, telling the debugger to start +tracking things and then making the call calling the debugger to +stop. + +To get the debugger class accessible from your Ruby program: + +@smallexample +require 'rubygems' +require 'ruby-debug' +@end smallexample +(It is very likely that you've already require'd rubygems. If so, you +don't have to do that again.) These commands need to be done only +once. + +After @code{require 'ruby-debug'}, it's possible to set some of the +debugger variables influence preferences. For example if you want to +have @ttDBG run a @code{list} command every time it stops you set the +variable @code{Debugger.settings[:autolist]}. @pxref{Debugger.settings} has a +list of variable settings and the default values. Debugger settings +can also be set in @code{.rdebugrc} as debugger +commands. @pxref{Command Files} + +To tell the debugger to start tracking things: + +@smallexample +Debugger.start +@end smallexample + +There is also a @code{Debugger.stop} to turn off debugger tracking. If +speed is crucial, you may want to start and stop this around certain +sections of code. Alternatively, instead of issuing an explicit +@code{Debugger.stop} you can add a block to the @code{Debugger.start} +and debugging is turned on for that block. If the block of code raises +an uncaught exception that would cause the block to terminate, the +@code{stop} will occur. See @ref{Debugger.start with a block}. + +And finally to enter the debugger: + +@smallexample +debugger +@end smallexample + +As indicated above, when @code{debugger} is run a @code{.rdebugrc} +profile is read if that file exists. + +You may want to do enter the debugger at several points in the program +where there is a problem you want to investigate. And since +@code{debugger} is just a method call it's possible enclose it in a +conditional expression, for example: +@smallexample +debugger if 'bar' == foo and 20 == iter_count +@end smallexample + +Although each step does a very specific thing which offers great +flexibility, in order to make getting into the debugger easier the +three steps have been rolled into one command: +@smallexample +require "ruby-debug/debugger" +@end smallexample + +@node Debugger Command Reference +@chapter @code{ruby-debug} Command Reference + +@menu +* Command Interfaces:: The kinds of interface used to interact with ruby-debug +* Command Syntax:: How to give commands to the ruby-debug +* Command Output:: How rdebug presents its output +* Help:: How to ask for help (help) +* Control:: Controlling the debugger (quit, restart, interrupt) +* DisplayCommands:: Executing expressions on stop (display, undisplay) +* PrintCommands:: Evaluating and Printing Expressions (p, pp, ps, pp, irb) +* PrintVars:: Printing Variables (var) +* List:: Examining Program Source Files (list) +* Edit:: Editing source files (edit) +* FrameCommands:: Examining the stack frame (where, up, down, frame) +* Stopping:: Stopping and continuing (break, watch, step, cont...) +* ruby-debug settings:: rdebug-settings (set args, set autoeval, ...) +* Program Information:: Program Status (info) +@end menu + +@node Command Interfaces +@section Command Interfaces +There are several ways one can talk to @code{ruby-debug} and get +results. The simplest way is via a command-line interface directly +talking to the debugger. This is referred to below as a ``Local +Interface''. It's also possible to run the debugger and set up a port +by which some other process can connect and control the debug +session. This is called a ``Remote Interface''. When you want to gain +access to a remote interface you need to run @code{ruby-debug} using a +``Control Interface''. This interface might not be the same process as +the process running the debugged program and might not even be +running on the same computer. + +Other front-ends may use one of these and build on top and provide +other (richer) interfaces. Although many of the commands are available +on all interfaces some are not. Most of the time in this manual when +we talk about issuing commands describing the responses elicited, +we'll assume we are working with the local interface. + +@node Command Syntax +@section Command Syntax +Usually a command is put on a single line. There is no limit on how long +it can be. It starts with a command name, which is followed by +arguments whose meaning depends on the command name. For example, the +command @code{step} accepts an argument which is the number of times to +step, as in @code{step 5}. You can also use the @code{step} command with no +arguments. Some commands do not allow any arguments. + +Multiple commands can be put on a line by separating each with a +semicolon (@code{;}). You can disable the meaning of a semicolon to +separate commands by escaping it with a backslash. + +For example, if you have @code{autoeval} (@ref{Autoeval}) set, you +might want to enter the following code to compute the 5th Fibonacci +number: +@smallexample +# Compute the 5 Fibonaci number +(rdb:1) set autoeval on +(rdb:1) fib1=0; fib2=1; 5.times @{|temp| temp=fib1; fib1=fib2; fib2 += temp @} +SyntaxError Exception: compile error +/usr/bin/irb:10: syntax error, unexpected $end, expecting '@}' + 5.times @{|temp| temp=fib1 + ^ +(rdb:1) fib1=0\; fib2=1\; 5.times @{|temp| temp=fib1\; fib1=fib2\; fib2 += temp @} +5 +(rdb:1) fib2 +fib2 +8 +@end smallexample +You might also consider using the @code{irb} command, @ref{irb}, and +then you won't have to escape semicolons. + +A blank line as input (typing just @key{}) means to repeat the +previous command. + +In the ``local'' interface, the Ruby Readline module is used. It +handles line editing and retrieval of previous commands. Up arrow, for +example moves to the previous debugger command; down arrow moves to +the next more recent command (provided you are not already at the last +command). Command history is saved in file @code{.rdebug_hist}. A +limit is put on the history size. You can see this with the @code{show +history size} command. See @ref{History} for history parameters. + +@node Command Output +@section Command Output + +In the command-line interface, when @code{ruby-debug} is waiting for +input it presents a prompt of the form +@code{(rdb:}@emph{x}@code{)}. If debugging locally, @emph{x} will be +the thread number. Usual the main thread is 1, so often you'll see +@code{(rdb:1)}. In the control interface though @emph{x} will be +@code{ctrl} and in post-mortem debugging @code{post-mortem}. + +In the local interface, whenever @code{ruby-debug} gives an error +message such as for an invalid command, or an invalid location +position, it will generally preface the message with +@code{***}. However if annotation mode is on that the message is put +in a @code{begin-error} annotation and no @code{***} appears. + +@node Help +@section Getting help (@samp{help}) +@cindex on-line documentation +@menu +* Help for Subcommands:: +@end menu + +Once inside @code{ruby-debug} you can always ask it for information on +its commands, using the command @code{help}. + +@table @code +@kindex h @r{(@code{help})} +@kindex help @ovar{command-name} +@item help +@itemx h +You can use @code{help} (abbreviated @code{h}) with no arguments to +display a short list of named classes of commands: + +@flushleft +@smallexample +(rdb:1) @b{help} +ruby-debug help v@value{RDEBUG_VERSION} +Type 'help ' for help on a specific command + +Available commands: +backtrace delete enable help next quit show undisplay +break disable eval info p reload source up +catch display exit irb pp restart step var +condition down finish list ps save thread where +continue edit frame method putl set trace +@end smallexample +@end flushleft +@c the above line break eliminates huge line overfull... + +@end table + +@table @code +@item help @var{command} +With a command name as @code{help} argument, @DBG displays short +information on how to use that command. + +@smallexample +(rdb:1) @b{help list} +ruby-debug help v@value{RDEBUG_VERSION} +l[ist] list forward +l[ist] - list backward +l[ist] = list current line +l[ist] nn-mm list given lines +* NOTE - to turn on autolist, use 'set autolist' +(rdb:1) +@end smallexample +@end table + +@node Help for Subcommands +@subsection Help on Subcommands +A number of commands have many sub-parameters or +@emph{subcommands}. These include @code{info}, @code{set}, +@code{show}, @code{enable} and @code{disable}. + +When you ask for help for one of these commands, you will get help for +all of the subcommands that that command offers. Sometimes you may +want help that subcommand and to do this just follow the command with +its subcommand name. For example @code{help set annotate} will just +give help about the annotate command. Furthermore it will give longer +help than the summary information that appears when you ask for +help. You don't need to list the full subcommand name, but just enough +of the letters to make that subcommand distinct from others will +do. For example, @code{help set an} is the same as @code{help set annotate}. + +Some examples follow. +@example +(rdb:1) @b{help info} +Generic command for showing things about the program being debugged. +-- +List of info subcommands: +-- +info args -- Argument variables of current stack frame +info breakpoints -- Status of user-settable breakpoints +info catch -- Exceptions that can be caught in the current stack frame +info display -- Expressions to display when program stops +info file -- Info about a particular file read in +info files -- File names and timestamps of files read in +info global_variables -- Global variables +info instance_variables -- Instance variables of the current stack frame +info line -- Line number and file name of current position in source file +info locals -- Local variables of the current stack frame +info program -- Execution status of the program +info stack -- Backtrace of the stack +info thread -- List info about thread NUM +info threads -- information of currently-known threads +info variables -- Local and instance variables of the current stack frame +@end example + +@example +(rdb:1) @b{help info breakpoints} +Status of user-settable breakpoints. +Without argument, list info about all breakpoints. With an +integer argument, list info on that breakpoint. +@end example + +@example +(rdb:1) @b{help info br} +Status of user-settable breakpoints. +Without argument, list info about all breakpoints. With an +integer argument, list info on that breakpoint. +@end example + +@node Control +@section Controlling the debugger (@samp{quit}, @samp{restart}, @samp{interrupt}, @samp{source}) + +@menu +* Quit:: Quitting the debugger (quit) +* Restart:: Restarting Script execution (restart) +* Interrupt:: Interrupting the debugger (interrupt) +* Source:: Running Debugger commands (source) +@end menu + +@node Quit +@subsection Quit (@samp{quit}) +@table @code +@kindex quit @r{[}unconditionally@r{]} +@kindex q @r{(@code{quit})} +@item quit @r{[}unconditionally@r{]} +@item exit +@itemx q + +To exit @value{DBG}, use the @code{quit} command (abbreviated +@code{q}), or alias @code{exit}. + +A simple @code{quit} tries to terminate all threads in effect. + +Normally if you are in an interactive session, this command will +prompt to ask if you really want to quit. If you don't want any +questions asked, enter the ``unconditionally''. + +@end table + +@node Restart +@subsection Restart (@samp{restart}) +@table @code +@kindex restart @r{[}@var{program args}@r{]} +@kindex R @r{(@code{restart})} +@item restart +@itemx R + +Restart the program. This is is a re-exec - all debugger state is +lost. If command arguments are passed those are used. Otherwise the +last program arguments used in the last invocation are used. + +In not all cases will you be able to restart the program. First, the +program should have been invoked at the outset rather than having been +called from inside your program or invoked as a result of post-mortem +handling. + +Also, since this relies on the the OS @code{exec} call, this command +is available only if your OS supports that @code{exec}; OSX for +example does not (yet). +@end table + +@node Interrupt +@subsection Interrupt (@samp{interrupt}) +@table @code +@kindex interrupt +@kindex i +@item interrupt +@itemx i +Interrupt the program. Useful if there are multiple threads running. +@end table + +@node Source +@subsection Running Debugger Commands (@samp{source}) +@table @code +@kindex source @var{filename} +@item source @var{filename} +Execute the command file @var{filename}. + +The lines in a command file are executed sequentially. They are not +printed as they are executed. If there is an error, execution +proceeds to the next command in the file. For information about +command files that get run automatically on startup, @pxref{Command Files}. +@end table + +@node DisplayCommands +@section Executing expressions on stop (@samp{display}, @samp{undisplay}) +@cindex automatic display +@cindex display of expressions + +If you find that you want to print the value of an expression +frequently (to see how it changes), you might want to add it to the +@dfn{automatic display list} so that @value{DBG} evaluates a statement +each time your program stops or the statement is shown in line tracing. +Each expression added to the list is given a number to identify it; to +remove an expression from the list, you specify that number. The +automatic display looks like this: + +@smallexample +(rdb:1) display n +1: n = 3 +@end smallexample + +@noindent +This display shows item numbers, expressions and their current values. +If the expression is undefined or illegal the expression will be +printed but no value will appear. + +@smallexample +(rdb:1) display undefined_variable +2: undefined_variable = +(rdb:1) display 1/0 +3: 1/0 = +@end smallexample + +Note: this command uses @code{to_s} to in expressions; for example an +array @code{[1, 2]} will appear as @code{12}. For some datatypes like +an Array, you may want to call the @code{inspect} method, for example +@code{display ARGV.inspect} rather than @code{display ARGV}. + +@table @code +@kindex display @ovar{expr} +@item display @var{expr} +Add the expression @var{expr} to the list of expressions to display +each time your program stops or a line is printed when linetracing is +on (@pxref{DisplayCommands}). + +@item display +Display the current values of the expressions on the list, just as is +done when your program stops. + +@kindex undisplay @ovar{num} +@item undisplay @ovar{num} +@itemx delete display @var{num} +Remove item number @var{num} from the list of expressions to display. + +@kindex info display +@item info display +Show all display expressions + +@ifset GDB_COMPLETED +@code{undisplay} does not repeat if you press @key{RET} after using it. +(Otherwise you would just get the error @samp{No display number @dots{}}.) +@end ifset + +@kindex disable display +@item disable display @var{dnums}@dots{} +Disable the display of item numbers @var{dnums}. A disabled display +item is not printed automatically, but is not forgotten. It may be +enabled again later. + +@kindex enable display +@item enable display @var{dnums}@dots{} +Enable display of item numbers @var{dnums}. It becomes effective once +again in auto display of its expression, until you specify otherwise. + +@end table + +@node PrintCommands +@section Evaluating and Printing Expressions (@samp{p}, @samp{pp}, @samp{putl}, @samp{ps}, @samp{irb}) + +One way to examine and change data in your script is with the +@code{eval} command (abbreviated @code{p}). A similar command is +@code{pp} which tries to pretty print the result. Finally @code{irb} is +useful when you anticipate examining or changing a number of things, +and prefer not to have to preface each command, but rather work as one +does in @code{irb}. + +@menu +* eval:: eval or print an expression (eval, p) +* pp:: pretty print an expression (pp, ps, putl) +* irb:: running irb using the current context +@end menu + +@node eval +@subsection Printing an expression (@samp{eval}, @samp{p}) +@table @code +@kindex eval @var{expr} +@kindex p @r{(@code{eval})} +@item eval @var{expr} +@itemx p @var{expr} + +Use @code{eval} or @code{p} to evaluate a Ruby expression, @var{expr}, +same as you would if you were in @code{irb}. If there are many expressions +you want to look at, you may want to go into irb from the debugger. +@smallexample +@group +(rdb:p) p n +3 +(rdb:1) p "the value of n is #@{n@}" +"the value of n is 3" +(rdb:1) +@end group +@end smallexample +@end table + +@node pp +@subsection Pretty-Printing an expression (@samp{pp}, @samp{putl}, @samp{ps})) +@table @code +@item pp +@kindex pp @var{expr} +Evaluates and pretty-prints @var{expr} +@smallexample +@group +(rdb:1) @b{p $LOAD_PATH} +["/home/rocky/lib/ruby", "/usr/lib/ruby/site_ruby/1.8", "/usr/lib/ruby/site_ruby/1.8/i586-linux", "/usr/lib/ruby/1.8"] +(rdb:1) @b{pp $LOAD_PATH} +["/home/rocky/lib/ruby", + "/usr/lib/ruby/site_ruby/1.8", + "/usr/lib/ruby/site_ruby/1.8/i586-linux", + "/usr/lib/ruby/1.8"] +@end group +@end smallexample +@kindex putl +@item putl +If the value you want to print is an array, sometimes a columnized +list looks nicer: +@smallexample +@group +(rdb:1) @b{putl $LOAD_PATH} +/home/rocky/lib/ruby /usr/lib/ruby/site_ruby/1.8 +/usr/lib/ruby/site_ruby/1.8/i586-linux /usr/lib/ruby/1.8 +@end group +@end smallexample + +Note however that entries are sorted to run down first rather than +across. So in the example above the second entry in the list is +@code{/usr/lib/ruby/site_ruby/1.8/i586-linux} and the @emph{third} entry is +@code{/usr/lib/ruby/site_ruby/1.8}. + +If the value is not an array @code{putl} will just call pretty-print. +@kindex ps +@item ps +Sometimes you may want to print the array not only columnized, but +sorted as well. The list of debugger help commands appears this way, +and so does the output of the @code{method} commands. + +@smallexample +@group +(rdb:1) ps Kernel.private_methods +Digest initialize y +Pathname initialize_copy +Rational location_of_caller +active_gem_with_options method_added +alias_method method_removed +append_features method_undefined +attr module_function +attr_accessor private +attr_reader protected +attr_writer public +class_variable_get remove_class_variable +class_variable_set remove_const +define_method remove_instance_variable +extend_object remove_method +extended singleton_method_added +gcd singleton_method_removed +gem_original_require singleton_method_undefined +include timeout +included undef_method +@end group +@end smallexample + +If the value is not an array, @code{ps} will just call pretty-print. +See also the @code{methods}. +@end table + +@node irb +@subsection Run irb (@samp{irb}) +@table @code +@kindex irb +@item irb +Run an interactive ruby session (@code{irb}) with the bindings +environment set to the state you are in the program. + +When you leave irb and go back to the debugger command prompt we show +again the file, line and text position of the program in the same way +as when entered the debugger. If you issue a @command{list} without +location information, the default location used is the current line +rather than the position may have gotten updated via a prior +@command{list} command. +@smallexample +triangle.rb:4 +def triangle(n) +(rdb:1) @b{list} +[-1, 8] in /home/rocky/ruby/triangle.rb + 1 #!/usr/bin/env ruby + 2 # Compute the n'th triangle number - the hard way + 3 # triangle(n) == (n * (n+1)) / 2 +=> 4 def triangle(n) + 5 tri = 0 + 6 0.upto(n) do |i| + 7 tri += i + 8 end +@b{irb} +>> @b{(0..6).inject@{|sum, i| sum +=i@}} +=> 21 +>> @b{exit} +triangle.rb:4 +def triangle(n) +(rdb:1) @b{list # Note we get the same line range as before going into irb} +[-1, 8] in /home/rocky/ruby/triangle.rb + 1 #!/usr/bin/env ruby + 2 # Compute the n'th triangle number - the hard way + 3 # triangle(n) == (n * (n+1)) / 2 +=> 4 def triangle(n) + 5 tri = 0 + 6 0.upto(n) do |i| + 7 tri += i + 8 end +@end smallexample + +@end table + +@node PrintVars +@section Printing Variables (@samp{var}, @samp{method}) + +@table @code +@item var const @var{object} +@kindex var const @var{expr} +Show the constants of @var{object}. This is basically listing +variables and their values in @var{object}@code{.constant}. +@item var instance @var{object} +@kindex var instance @var{expr} +Show the instance variables of @var{object}. This is basically listing +@var{object}@code{.instance_variables}. +@item info instance_variables +@kindex info instance_variables +Show instance_variables of @code{@@self} +@item info locals +@kindex info locals +Show local variables +@item info globals +@kindex info globals +Show global variables +@item info variables +@kindex info variables +Show local and instance variables of @code{@@self} +@item method instance @var{object} +@kindex method instance @var{object} +Show methods of @var{object}. Basically this is the same as running +@code{ps object.instance_methods(false)} on @var{object}. +@item method iv @var{object} +@kindex method iv @var{object} +Show method instance variables of @var{object}. Basically this is the same as running +@smallexample + obj.instance_variables.each do |v| + puts "%s = %s\n" % [v, obj.instance_variable_get(v)] + end +@end smallexample +on @var{object}. +@item signature @var{object} +@kindex method signature @var{object} +Show procedure signature of method @var{object}. +@emph{This command is available only if the nodewrap is installed.} +@smallexample + def mymethod(a, b=5, &bock) + end + (rdb:1) @b{method sig mymethod} + Mine#mymethod(a, b=5, &bock) +@end smallexample +on @var{object}. +@item method @var{class-or-module} +@kindex method @var{class-or-module} +Show methods of the class or module, @var{class-or-module}. Basically +this is the same as running @code{ps object.methods} on @var{class-or-module}. +on @var{class-or-module}. +@end table + +@node List +@section Examining Program Source Files (@samp{list}) + +@cindex current line +@value{DBG} can print parts of your script's source. When your script +stops, @value{DBG} spontaneously prints the line where it stopped and +the text of that line. Likewise, when you select a stack frame +(@pxref{Selection}) @value{DBG} prints the line where execution in +that frame has stopped. Implicitly there is a default line +location. Each time a list command is run that implicit location is +updated, so that running several list commands in succession shows a +contiguous block of program text. + +You can print other portions of source files by giving an explicit +position as a parameter to the list command. + +If you use @value{DBG} through its Emacs interface, you may prefer to +use Emacs facilities to view source. +@c @pxref{GNU Emacs}. + +@kindex list @ovar{line-number} +@kindex l @r{(@code{list})} +To print lines from a source file, use the @code{list} command +(abbreviated @code{l}). By default, ten lines are printed. Fewer may +appear if there fewer lines before or after the current line to center +the listing around. + +There are several ways to specify what part of the file you want to print. +Here are the forms of the @code{list} command. + +@table @code +@item list @var{line-number} +@itemx l @var{line-number} +Print lines centered around line number @var{line-number} in the +current source file. + +@item list +@itemx l +Print more lines. If the last lines printed were printed with a +@code{list} command, this prints lines following the last lines +printed; however, if the last line printed was a solitary line printed +as part of displaying a stack frame (@pxref{Frames}), this prints lines +centered around that line. + +@item list - +@itemx l - +Print lines just before the lines last printed. +@item list @var{first}-@var{last} +Print lines between @var{first} and @var{last} inclusive. + +@item list = +Print lines centered around where the script is stopped. +@end table + +Repeating a @code{list} command with @key{RET} discards the argument, +so it is equivalent to typing just @code{list}. This is more useful +than listing the same lines again. An exception is made for an +argument of @samp{-}; that argument is preserved in repetition so that +each repetition moves up in the source file. + +@node Edit +@section Editing Source files (@samp{edit}) + +To edit the lines in a source file, use the @code{edit} command. The +editing program of your choice is invoked with the current line set to +the active line in the program. Alternatively, you can give a line +specification to specify what part of the file you want to print if +you want to see other parts of the program. + +You can customize to use any editor you want by using the +@code{EDITOR} environment variable. The only restriction is that your +editor (say @code{ex}), recognizes the following command-line syntax: +@smallexample +ex +@var{number} file +@end smallexample +The optional numeric value +@var{number} specifies the number of the +line in the file where to start editing. For example, to configure +@value{DBG} to use the @code{vi} editor, you could use these commands +with the @code{sh} shell: +@smallexample +EDITOR=/usr/bin/vi +export EDITOR +gdb @dots{} +@end smallexample +or in the @code{csh} shell, +@smallexample +setenv EDITOR /usr/bin/vi +gdb @dots{} +@end smallexample + +@table @code +@kindex edit @ovar{line-specification} +@item edit @ovar{line specification} +Edit line specification using the editor specified by the +@code{EDITOR} environment variable. +@end table + +@node FrameCommands +@section Examining the Stack Frame (@samp{where}, @samp{up}, @samp{down}, @samp{frame}) + +When your script has stopped, one thing you'll probably want to know +is where it stopped and some idea of how it got there. + +@cindex call stack +Each time your script performs a function or sends a message to a +method, or enters a block, information about this action is saved. +The frame stack then is this a history of the blocks that got you to +the point that you are currently stopped at.@footnote{More accurately +we should call this a ``block stack''; but we'll use the name that is +more commonly used. And internally in Ruby, there is ``FRAME'' +structure which is yet slightly different.} + +@cindex selected block +One entry in call stack is @dfn{selected} by @DBG{} and many +@DBG commands refer implicitly to the selected block. In +particular, whenever you ask @DBG to list lines without giving +a line number or location the value is found in the selected frame. +There are special @DBG commands to select whichever frame you +are interested in. @xref{Selection, ,Selecting a frame}. + +When your program stops, @DBG{} automatically selects the +currently executing frame and describes it briefly, similar to the +@code{frame} command. + +After switching frames, when you issue a @code{list} command without +any position information, the position used is location in the frame +that you just switched between, rather than a location that got +updated via a prior @code{list} command. + +@menu +* Frames:: Stack frames +* Backtrace:: Backtraces (where) +* Selection:: Selecting a frame (up, down, frame) + +@end menu + +@node Frames +@subsection Stack frames + +@cindex frame, definition +@cindex stack frame +The block stack is divided up into contiguous pieces called @dfn{stack +frames}, @dfn{frames}, or @dfn{blocks} for short; each frame/block has +a scope associated with it; It contains a line number and the +source-file name that the line refers. If the frame/block is the beginning +of a method or function it also contains the function name. + +@cindex initial frame +@cindex outermost frame +@cindex innermost frame +When your script is started, the stack has only one frame, that of the +function @code{main}. This is called the @dfn{initial} frame or the +@dfn{outermost} frame. Each time a function is called, a new frame is +made. Each time a function returns, the frame for that function invocation +is eliminated. If a function is recursive, there can be many frames for +the same function. The frame for the function in which execution is +actually occurring is called the @dfn{innermost} frame. This is the most +recently created of all the stack frames that still exist. + +@cindex frame number +@value{DBG} assigns numbers to all existing stack frames, starting with +zero for the innermost frame, one for the frame that called it, +and so on upward. These numbers do not really exist in your script; +they are assigned by @value{DBG} to give you a way of designating stack +frames in @value{DBG} commands. + +@node Backtrace +@subsection Backtraces (@samp{where}) + +@cindex backtraces +@cindex tracebacks +@cindex stack traces +A backtrace is essentially the same as the call stack: a summary of +how your script got where it is. It shows one line per frame, for +many frames, starting with the place that you are stopped at (frame +zero), followed by its caller (frame one), and on up the stack. + +@table @code +@kindex where +@kindex w @r{(@code{where})} +@itemx where +Print the entire stack frame; @code{info stack} is an alias for this command. +Each frame is numbered and can be referred to in the @code{frame} +command; @code{up} and @code{down} add or subtract respectively to +frame numbers shown. The position of the current frame is marked with +@code{-->}. + +@smallexample +(rdb:1) where +--> #0 Object.gcd(a#Fixnum, b#Fixnum) at line /tmp/gcd.rb:6 + #1 at line /tmp/gcd.rb:19 +@end smallexample + +@ifset FINISHED +@item backtrace @var{n} +@itemx bt @var{n} +@itemx where @var{n} +@itemx T @var{n} +Similar, but print only the innermost @var{n} frames. + +@item backtrace -@var{n} +@itemx bt -@var{n} +@itemx where -@var{n} +@itemx T -@var{n} +Similar, but print only the outermost @var{n} frames. +@end ifset +@end table + +@node Selection +@subsection Selecting a frame (@samp{up}, @samp{down}, @samp{frame}) + +Commands for listing source code in your script work on whichever +stack frame is selected at the moment. Here are the commands for +selecting a stack frame; all of them finish by printing a brief +description of the stack frame just selected. + +@table @code +@kindex up @ovar{n} +@item up @ovar{n} +Move @var{n} frames up the stack. For positive numbers @var{n}, this +advances toward the outermost frame, to higher frame numbers, to +frames that have existed longer. Using a negative @var{n} is the same thing +as issuing a @code{down} command of the absolute value of the @var{n}. +Using zero for @var{n} does no frame adjustment, but since the current +position is redisplayed, it may trigger a resynchronization if there is +a front end also watching over things. + +@var{n} defaults to one. You may abbreviate @code{up} as @code{u}. + +@kindex down @ovar{n} +@item down @ovar{n} +Move @var{n} frames down the stack. For positive numbers @var{n}, this +advances toward the innermost frame, to lower frame numbers, to frames +that were created more recently. Using a negative @var{n} is the same +as issuing a @code{up} command of the absolute value of the @var{n}. +Using zero for @var{n} does no frame adjustment, but since the current +position is redisplayed, it may trigger a resynchronization if there is +a front end also watching over things. + +@var{n} defaults to one. +@end table + +@table @code +@kindex frame @r{[}@ovar{n} @r{[}thread @var{thread-num}@r{]}@r{]} +@cindex current stack frame +@item frame @ovar{n} @r{[}thread @var{thread-num}@r{]} +The @code{frame} command allows you to move from one stack frame to +another, and to print the stack frame you select. @var{n} is the the +stack frame number or 0 if no frame number is given; @code{frame 0} +then will always show the current and most recent stack frame. + +If a negative number is given, counting is from the other end of the +stack frame, so @code{frame -1} shows the least-recent, outermost or +most ``main'' stack frame. + +Without an argument, @code{frame} prints the current stack +frame. Since the current position is redisplayed, it may trigger a +resynchronization if there is a front end also watching over +things. + +If a thread number is given then we set the context for evaluating +expressions to that frame of that thread. +@end table + +@node Stopping +@section Stopping and Resuming Execution + +One important use of a debugger is to stop your program @emph{before} +it terminates, so that if your script runs into trouble you can +investigate and find out why. However should your script accidentally +continue to termination, it can be arranged for @DBG to not to leave +the debugger without your explicit instruction. That way, you can +restart the program using the same command arguments. + +Inside @value{DBG}, your script may stop for any of several reasons, +such as a signal, a breakpoint, or reaching a new line after a +debugger command such as @code{step}. You may then examine and +change variables, set new breakpoints or remove old ones, and then +continue execution. + +@menu +* Breakpoints:: Breakpoints (break, catch, delete) +* Disabling:: Disabling breakpoints (disable, enable) +* Conditions:: Break conditions (condition) +* Resuming Execution:: Resuming execution (continue, step, next, finish) +@end menu + +@node Breakpoints +@subsection Breakpoints (@samp{break}, @samp{catch}, @samp{delete}) + +@cindex breakpoints +A @dfn{breakpoint} makes your script stop whenever a certain point in +the program is reached. For each breakpoint, you can add conditions to +control in finer detail whether your script stops. + +You specify the place where your script should stop with the +@code{break} command and its variants. + +@cindex breakpoint numbers +@cindex numbers for breakpoints +@value{ttDBG} assigns a number to each breakpoint when +you create it; these numbers are successive integers starting with +one. In many of the commands for controlling various features of +breakpoints you use the breakpoint number to say which breakpoint you +want to change. Each breakpoint may be @dfn{enabled} or +@dfn{disabled}; if disabled, it has no effect on your script until you +enable it again. + + +@table @code +@kindex break @ovar{location} +@kindex b @r{(@code{break})} +@item break +Set a breakpoint at the current line. + +@item break @var{linenum} +Set a breakpoint at line @var{linenum} in the current source file. +The current source file is the last file whose source text was printed. +The breakpoint will stop your script just before it executes any of the +code on that line. + +@item break @var{filename}:@var{linenum} +Set a breakpoint at line @var{linenum} in source file @var{filename}. + +What may be a little tricky when specifying the filename is getting +the name recognized by the debugger. If you get a message the message +``@code{No source file named ...}'', then you may need to qualify the +name more fully. To see what files are loaded you can use the @code{info +files} or @code{info file} commands. If you want the name @code{rdebug} thinks +of as the current file, use @code{info line}. + +Here's an example: +@example +$ @b{rdebug ~/ruby/gcd.rb 3 5} +/home/rocky/ruby/gcd.rb:4 # Note this is the file name +def gcd(a, b) +(rdb:1) @b{break gcd.rb:6} +*** No source file named gcd.rb +(rdb:1) @b{info line} +Line 4 of "/home/rocky/ruby/gcd.rb" +(rdb:1) @b{break /home/rocky/ruby/gcd.rb:6} +Breakpoint 1 file /home/rocky/ruby/gcd.rb, line 6 +(rdb:1) @b{break ~/ruby/gcd.rb:10} # tilde expansion also works +Breakpoint 2 file /home/rocky/ruby/gcd.rb, line 10 +(rdb:1) @b{info file gcd.rb} +File gcd.rb is not cached +(rdb:1) @b{info file /home/rocky/ruby/gcd.rb} +File /home/rocky/ruby/gcd.rb + 19 lines +@end example + +@item break @var{class}:@var{method} +Set a breakpoint in class @var{class} method @var{method}. You can +also use a period @code{.} instead of a colon @code{:}. Note that two +colons @code{::} are not used. Also note a class @emph{must} be +specified here. If the method you want to stop in is in the main class +(i.e. the class that @code{self} belongs to at the start of the +program), then use the name @code{Object}. + +@kindex catch @ovar{exception} @r{[} on | 1 | off | 0 @r{]} +@kindex cat @r{(@code{catch})} +@item catch @ovar{exception} @r{[} on | 1 | off | 0 @r{]} +Set catchpoint to an exception. Without an exception name show catchpoints. + +With an ``on'' or ``off'' parameter, turn handling the exception on or +off. To delete all exceptions type ``catch off''. + +@cindex delete breakpoints +@kindex delete @ovar{breakpoints} +@kindex del @r{(@code{delete})} +@item delete @ovar{breakpoints} +Delete the breakpoints specified as arguments. + +If no argument is specified, delete all breakpoints (@DBG asks +confirmation. You can abbreviate this command as @code{del}. +@kindex info breakpoints +@cindex @code{$_} and @code{info breakpoints} +@item info breakpoints @ovar{n} +@itemx info break @ovar{n} +Print a table of all breakpoints set and not deleted, with the +following columns for each breakpoint: + +@table @emph +@item Breakpoint Numbers (@samp{Num}) +@item Enabled or Disabled (@samp{Enb}) +Enabled breakpoints are marked with @samp{1}. @samp{0} marks breakpoints +that are disabled (not enabled). +@item File and Line (@samp{file:line}) +The filename and line number inside that file where of breakpoint in +the script. The file and line are separated with a colon. +@item Condition +A condition (an arithmetic expression) which when true causes the +breakpoint to take effect. +@end table +@noindent +If a breakpoint is conditional, @code{info break} shows the condition on +the line following the affected breakpoint; breakpoint commands, if any, +are listed after that. + +@code{info break} with a breakpoint number @var{n} as argument lists +only that breakpoint. + +Examples: +@example +(rdb:1) @b{info break} +Breakpoints at following places: +Num Enb What +1 y gcd.rb:3 +2 y gcb.rb:28 if n > 1 +(rdb:1) @b{info break 2} +2 y gcb.rb:28 if n > 1 +@end example +@end table + +@node Disabling +@subsection Disabling breakpoints (@samp{disable}, @samp{enable}) + +Rather than deleting a breakpoint, you might +prefer to @dfn{disable} it. This makes the breakpoint inoperative as if +it had been deleted, but remembers the information on the breakpoint so +that you can @dfn{enable} it again later. + +You disable and enable breakpoints and catchpoints with the +@code{enable} and @code{disable} commands, optionally specifying one +or more breakpoint numbers as arguments. Use @code{info break} to +print a list of breakpoints and catchpoints if you do not know which +numbers to use. + +A breakpoint or catchpoint can have any different +states of enablement: + +@itemize @bullet +@item +Enabled. The breakpoint stops your program. A breakpoint set +with the @code{break} command starts out in this state. +@item +Disabled. The breakpoint has no effect on your program. +@end itemize + +You can use the following commands to enable or disable breakpoints +and catchpoints: + +@table @code +@kindex disable breakpoints +@item disable @var{breakpoints} +Disable the specified breakpoints---or all breakpoints, if none are +listed. A disabled breakpoint has no effect but is not forgotten. All +options such as ignore-counts, conditions and commands are remembered in +case the breakpoint is enabled again later. You may abbreviate +@code{disable} as @code{dis}. + +@kindex enable breakpoints +@item enable @var{breakpoints} +Enable the specified breakpoints (or all defined breakpoints). They +become effective once again in stopping your program. + +@end table + +Breakpoints that you set are initially enabled; subsequently, they +become disabled or enabled only when you use one of the commands +above. (The command @code{until} can set and delete a breakpoint of +its own, but it does not change the state of your other breakpoints; +see @ref{Resuming Execution, ,Resuming Execution}.) + +@node Conditions +@subsection Break conditions (@samp{condition}) +@cindex conditional breakpoints +@cindex breakpoint conditions + +The simplest sort of breakpoint breaks every time your script reaches +a specified place. You can also specify a @dfn{condition} for a +breakpoint. A condition is just a Ruby expression. + +Break conditions can be specified when a breakpoint is set, by using +@samp{if} in the arguments to the @code{break} command. A breakpoint +with a condition evaluates the expression each time your script +reaches it, and your script stops only if the condition is +@emph{true}. They can also be changed at any time +with the @code{condition} command. + +@ifset FINISHED +You can also use the @code{if} keyword with the @code{watch} command. +The @code{catch} command does not recognize the @code{if} keyword; +@code{condition} is the only way to impose a further condition on a +catchpoint. +@end ifset + +@table @code +@kindex condition +@item condition @var{bnum} @var{expression} +Specify @var{expression} as the break condition for breakpoint +@var{bnum}. After you set a condition, breakpoint @var{bnum} stops +your program only if the value of @var{expression} is true (nonzero). + +@item condition @var{bnum} +Remove the condition from breakpoint number @var{bnum}. It becomes +an ordinary unconditional breakpoint. +@end table + +@ifset FINISHED +When you use @code{condition}, @DBG checks @var{expression} +immediately for syntactic correctness, and to determine whether +symbols in it have referents in the context of your breakpoint. If +@var{expression} uses symbols not referenced in the context of the +breakpoint, @DBG prints an error message: + +@example +No symbol "foo" in current context. +@end example +@end ifset + +@noindent +The debugger does not actually evaluate @var{expression} at the time +the @code{condition} command (or a command that sets a breakpoint with +a condition, like @code{break if @dots{}}) is given, however. + +Examples; +@example +condition 1 x>5 # Stop on breakpoint 0 only if x>5 is true. +condition 1 # Change that! Unconditionally stop on breakpoint 1. +@end example + +@node Resuming Execution +@subsection Resuming Execution (@samp{step}, @samp{next}, @samp{finish}, @samp{continue}) + +A typical technique for using stepping is to set a breakpoint +(@pxref{Breakpoints}) at the beginning of the function or the section +of your script where a problem is believed to lie, run your script +until it stops at that breakpoint, and then step through the suspect +area, examining the variables that are interesting, until you see the +problem happen. + +@cindex stepping +@cindex continuing +@cindex resuming execution +@dfn{Continuing} means resuming program execution until your script +completes normally. In contrast, @dfn{stepping} means executing just +one more ``step'' of your script, where ``step'' may mean either one +line of source code. Either when continuing or when stepping, +your script may stop even sooner, due to a breakpoint or a signal. + +@menu +* Step:: running the next statement (step) +* Next:: running the next statement skipping over functions (next) +* Finish:: running until the return of a function or ``source'' (finish) +* Continue:: continuing execution (continue) +@end menu + +@node Step +@subsubsection Step (@samp{step}) +@table @code +@kindex step @r{[}+@r{]} @ovar{count} +@kindex s @r{(@code{step})} +@item step @r{[}+-@r{]} @ovar{count} +Continue running your program until the next logical stopping point +and return control to @value{DBG}. This command is abbreviated +@code{s}. + +Like, the programming Lisp, Ruby tends implemented in a highly +expression-oriented manner. Therefore things that in other languages +that may appear to be a single statement are implemented in Ruby as +several expressions. For example, in an ``if'' statement or looping +statements a stop is made after the expression is evaluated but before +the test on the expression is made. + +So it is common that a lines in the program will have several stopping +points where in other debuggers of other languages there would be only +one. Or you may have several statements listed on a line. + +When stepping it is not uncommon to want to go to a different line on +each step. If you want to make sure that on a step you go to a +@emph{different} position, add a plus sign (@samp{+}). + +@emph{Note: step+ with a number count is not the same as issuing +count step+ commands. Instead it uses count-1 step commands followed +by a step+ command. For example, @code{step+ 3} is the +same as @code{step; step; step+}, not @code{step+; step+; step+}} + +If you find yourself generally wanting to use @code{step+} rather +than @code{step}, you may want to consider using @code{set +forcestep}, (@pxref{Forcestep}). + +If you have @code{forcestep} set on but want to temporarily disable it +for the next step command, append a minus, or @code{step-}. + +With a count, @code{step} will continue running as normal, but do so +@var{count} times. If a breakpoint is reached, or a signal not +related to stepping occurs before @var{count} steps, stepping stops +right away. +@end table + +@node Next +@subsubsection Next (@samp{next}) +@table @code +@kindex next @r{[}+-@r{]} @ovar{count} +@kindex n @r{(@code{next})} +@item next @r{[}+@r{]} @ovar{count} +This is similar to @code{step}, but function or method calls that +appear within the line of code are executed without stopping. As with +step, if you want to make sure that on a step you go to a +@emph{different} position, add a plus sign (@samp{+}). Similarly, +appending a minus disables a @code{forcestep} temporarily, and an +argument @var{count} is a repeat count, as for @code{step}. +@end table + +@node Finish +@subsubsection Finish (@samp{finish}) +@table @code +@kindex finish @ovar{frame-number} +@item finish @ovar{frame-number} +Execute until selected stack frame returns. If no frame number is +given, we run until the currently selected frame returns. The +currently selected frame starts out the most-recent frame or 0 if no +frame positioning (e.g@: @code{up}, @code{down} or @code{frame}) has +been performed. If a frame number is given we run until @var{frame} frames +returns. + +If you want instead to terminate the program and debugger entirely, +use @code{quit} (@pxref{Quitting the debugger, ,Quitting the debugger}). + +@emph{Note:} Releases before Ruby version 1.8.7 show the return line +as the first line of the method. Starting with version 1.8.7, the last +line executed will be shown as the return +line. @url{http://rubyforge.org/tracker/?func=detail&atid=22040&aid=18749&group_id=426} + +@end table + +@node Continue +@subsubsection Continue (@samp{continue}) +@table @code +@kindex continue @ovar{line-specification} +@kindex c @r{(@code{continue})} +@item continue @ovar{line-specification} +@itemx c @ovar{line-specification} +Resume program execution, at the address where your script last +stopped; any breakpoints set at that address are bypassed. + +The optional argument @var{line-specification} allows you to specify a +line number to set a one-time breakpoint which is deleted when that +breakpoint is reached. + +Should the program stop before that breakpoint is reached, for +example, perhaps another breakpoint is reached first, in +a listing of the breakpoints you won't see this entry in the list of +breakpoints. +@end table + +@node ruby-debug settings +@section ruby-debug settings (@samp{set args}, @samp{set autoeval}..) + +You can alter the way ruby-debug interacts with you using @code{set} +commands. + +The various parameters to @code{set} are given below. Each parameter +name needs to to be only enough to make it unique. For example +@code{set force} is a suitable abbreviation for @code{set forcestep}. +The letter case is not important, so @code{set FORCE} or @code{set +Force} are also suitable abbreviations. + +Many @code{set} commands are either ``on'' or ``off'', and you can +indicate which way you want set by supplying the corresponding +word. The number 1 can be used for ``on'' and 0 for ``off''. If none +of these is given, we will assume ``on''. A deprecated way of turning +something off is by prefacing it with ``no''. + +Each @code{set} command has a corresponding @code{show} command which +allows you to see the current value. + +@menu +* Args:: Annotation Level +* Autoeval:: Evaluate unrecognized commands +* Autolist:: Execute ``list'' command on every breakpoint +* Autoirb:: Invoke IRB on every stop +* Autoreload:: Reload source code when changed +* Basename:: Report file basename only showing file names +* Callstyle:: Show Report file basename only showing file names +* Forcestep:: Make sure 'next/step' commands always move to a new line +* Fullpath:: Display full file names in frames +* History:: Generic command for showing command history parameters. +* Keepframebindings:: Save frame binding on each call +* Linetrace:: line execution tracing +* Linetrace+:: line tracing style +* Listsize:: Number of lines to try to show in a 'list' command +* Post-mortem:: Whether post-mortem handling is in effect. +* Trace:: Display stack trace when 'eval' raises exception +* Width:: Number of characters the debugger thinks are in a line +@end menu + +@node Args +@subsection Set/Show args + +@table @code +@kindex set args @ovar{parameters} +@item set args @ovar{parameters} +Specify the arguments to be used if your program is rerun. If +@code{set args} has no arguments, @code{restart} executes your program +with no arguments. Once you have run your program with arguments, +using @code{set args} before the next @code{restart} is the only way to run +it again without arguments. + +@kindex show args +@item show args +Show the arguments to give your program when it is started. +@end table + +@node Autoeval +@subsection Set/Show auto-eval + +@table @code +@kindex set autoeval @r{[} on | 1 | off | 0 @r{]} +@item set autoeval @r{[} on | 1 | off | 0 @r{]} +Specify that debugger input that isn't recognized as a command should +be passed to Ruby for evaluation (using the current debugged program +namespace). Note however that we @emph{first} check input to see if it +is a debugger command and @emph{only} if it is not do we consider it +as Ruby code. This means for example that if you have variable called +@code{n} and you want to see its value, you could use @code{p n}, +because just entering @code{n} will be interpreted as the debugger +``next'' command. + +See also @ref{irb} and @ref{Autoirb}. + +When autoeval is set on, you'll get a different error message when you +invalid commands are encountered. Here's a session fragment to show +the difference +@smallexample +(rdb:1) @b{stepp} +Unknown command +(rdb:1) @b{set autoeval on} +autoeval is on. +(rdb:1) @b{stepp} +NameError Exception: undefined local variable or method `stepp' for ... +@end smallexample + +@kindex show autoeval +@item show args +Shows whether Ruby evaluation of debugger input should occur or not. +@end table + +@node Autolist +@subsection Execute ``list'' command on every breakpoint + +@node Autoirb +@subsection Set/Show auto-irb + +@table @code +@kindex set autoirb @r{[} on | 1 | off | 0 @r{]} +@item set autoirb @r{[} on | 1 | off | 0 @r{]} + +When your program stops, normally you go into a debugger command loop +looking for debugger commands. If instead you would like to directly +go into an irb shell, set this on. See also @ref{Autoeval} or +@ref{irb} if you tend to use debugger commands but still want Ruby +evaluation occasionally. + +@kindex show autoirb +@item show autoirb +Shows whether the debugger will go into irb on stop or not. +@end table + +@node Autoreload +@subsection Set/Show auto-reload +@table @code +@kindex set autoreload @r{[} on | 1 | off | 0 @r{]} +Set this on if the debugger should check to see if the source has +changed since the last time it reread in the file if it has. +@end table + +@node Basename +@subsection Set/Show basename + +@table @code +@kindex set basename @r{[} on | 1 | off | 0 @r{]} +@item set basename @r{[} on | 1 | off | 0 @r{]} +Source filenames are shown as the shorter ``basename'' +only. (Directory paths are omitted). This is useful in running the +regression tests and may useful in showing debugger examples as in +this text. You may also just want less verbose filename display. + +By default filenames are shown as with their full path. + +@kindex show basename +@item show basename +Shows the whether filename display shows just the file basename or not. +@end table + +@node Callstyle +@subsection Set/Show call style + +@table @code +@ifset FINISHED +@kindex set callstyle @r{[} short | last | tracked @r{]} +@item set forcestep @r{[} short | last | tracked @r{]} +@else +@kindex set callstyle @r{[} short | last +@item set forcestep @r{[} short | last +@end ifset + +Sets how you want call parameters displayed; @code{short} shows just +the parameter names; +@ifset FINISHED +@code{last} shows the parameter names and the +class of these variables as they currently exist. Note the type could +have changed between when the call and its current +values. +@end ifset +@code{tracked} is the most accurate but this adds +overhead. On every call, scalar values of the parameters get +saved. For non-scalar values the class is saved. +@end table + +@node Forcestep +@subsection Set/Show Forces Different Line Step/Next + +@table @code +@kindex set forcestep @r{[} on | 1 | off | 0 @r{]} +@item set forcestep @r{[} on | 1 | off | 0 @r{]} + +Due to the interpretive, expression-oriented nature of the Ruby +Language and implementation, each line often contains many possible +stopping points, while in a debugger it is often desired to treat each +line as an individual stepping unit. + +Setting forcestep on will cause each @code{step} or @code{next} +command to stop at a different line number. See also @ref{Step} and +@ref{Next}. + +@kindex show forcestep +@item show forcestep +Shows whether forcestep is in effect or not. +@end table + +@node Fullpath +@subsection Set/Show Frame full path + +@node History +@subsection Command History Parameters +@table @code +@item show commands +@kindex show commands +Display the last ten commands in the command history. + +@item show commands @var{n} +@kindex show commands @var{n} +Print ten commands centered on command number @var{n}. + +@item show history filename +@kindex show history filename +Show the filename in which to record the command history +(the list of previous commands of which a record is kept). + +@item set history save @r{[} on | 1 | off | 0 @r{]} +@kindex set history save @r{[} on | 1 | off | 0 @r{]} +Set whether to save the history on exit. + +@item show history save +@kindex show history save +Show saving of the history record on exit. + +@item set history size @var{number} +@kindex set history size @var{number} +Set the maximum number of commands to save in the history. + +@item show history size +@kindex show history size +Show the size of the command history, i.e. the number of previous +commands to keep a record of. +@end table + +@node Keepframebindings +@subsection Save frame binding on each call + +@node Linetrace +@subsection Set/Show Line tracing + +@table @code +@kindex set linetrace @r{[} on | 1 | off | 0 @r{]} +@item set linetrace @r{[} on | 1 | off | 0 @r{]} + +Setting linetrace on will cause lines to be shown before run. + +@kindex show linetrace +@item show linetrace +Shows whether line tracing is in effect or not. +@end table + +@node Linetrace+ +@subsection Set/Show Line tracing style + +@table @code +@kindex set linetrace+ @r{[} on | 1 | off | 0 @r{]} +@item set linetrace+ @r{[} on | 1 | off | 0 @r{]} + +Setting linetrace+ on will cause consecutive trace lines not to be a +duplicate of the preceding line-trace line. Note however that this +setting doesn't by itself turn on or off line tracing. + +@kindex show linetrace+ +@item show linetrace +Shows whether the line tracing style is to show all lines or remove +duplicates linetrace lines when it is a repeat of the previous line. +@end table + +@node Listsize +@subsection Set/Show lines in a List command + +@table @code +@kindex set listsize @var{number-of-lines} +@item set listsize @var{number-of-lines} +Set number of lines to try to show in a @code{list} command. +@kindex show listsize +@item show listsize +Shows the list-size setting. +@end table + +@node Post-mortem +@subsection Show Post-mortem handling +@table @code +@kindex show post-mortem +Shows wither post-mortem debugging is in effect. Right now we don't +have the ability to change the state inside the debugger. +@end table + +@node Trace +@subsection Display stack trace when 'eval' raises exception + +@node Width +@subsection Set/Show Line width + +@table @code +@kindex set width @var{column-width} +@item set width @var{column-width} +Set number of characters the debugger thinks are in a line. +We also change OS environment variable @code{COLUMNS}. +@kindex show width +@item show width +Shows the current width setting. +@end table + +@node Program Information +@section Program Information (@samp{info}) + +This @code{info} command (abbreviated @code{i}) is for describing the +state of your program. For example, you can list the current +parameters with @code{info args}, or list the breakpoints you have set +with @code{info breakpoints} or @code{info watchpoints}. You can get +a complete list of the @code{info} sub-commands with @w{@code{help +info}}. + +@table @code +@kindex info args + +@item info args +Method arguments of the current stack frame. +@kindex info breakpoints + +@item info breakpoints +Status of user-settable breakpoints +@kindex info display + +@item info display +All display expressions. +@kindex info files + +@item info files +Source files in the program. +@kindex info file + +@item info file @var{filename} @ovar{all|lines|mtime|sha1} +Information about a specific file. Parameter @code{lines} gives the +number of lines in the file, @code{mtime} shows the modification time +of the file (if available), @code{sha1} computes a SHA1 has of the +data of the file. @code{all} gives all of the above information. + +@kindex info line +@item info line +Line number and file name of current position in source. +@kindex info locals +@item info locals +Local variables of the current stack frame. +@kindex info program +@item info program +Display information about the status of your program: whether it is +running or not and why it stopped. If an unhandled exception occurred, +the exception class and @code{to_s} method is called. +@kindex info stack +@item info stack +Backtrace of the stack. An alias for @code{where}. @xref{Backtrace}. +@kindex info thread +@item info thread @ovar{thread-number} @r{[} terse | verbose@r{]} +If no thread number is given, we list info for all +threads. @code{terse} and @code{verbose} options are possible. If terse, +just give summary thread name information. See information under @code{info threads} for +more detail about this summary information. + +If @code{verbose} is appended to the end of the command, then the entire +stack trace is given for each thread. + +@kindex info threads @r{[} terse | verbose@r{]} +@item info threads + +List information about currently-known threads. This information +includes whether the thread is current (+), if it is suspended ($), or +ignored (!); the thread number and the top stack item. If +@code{verbose} is given then the entire stack frame is shown. Here is +an example: + +@smallexample +(rdb:7) info threads + 1 # ./test/thread1.rb:27 + !2 # + 3 # ./test/thread1.rb:11 + 4 # ./test/thread1.rb:11 + 5 # ./test/thread1.rb:11 + 6 # ./test/thread1.rb:11 ++ 7 # ./test/thread1.rb:14 +(rdb:1) +@end smallexample + +Thread 7 is the current thread since it has a plus sign in front. Thread 2 is +ignored since it has a @code{!}. A ``verbose'' listing of the above: + +@smallexample +(rdb:7) info threads verbose + 1 # + #0 Integer.join at line test/thread1.rb:27 + #1 at line test/thread1.rb:27 + !2 # + 3 # + #0 sleep(count#Fixnum) at line test/thread1.rb:11 + #1 Object.fn(count#Fixnum, i#Fixnum) at line test/thread1.rb:11 + #2 at line test/thread1.rb:23 + 4 # + #0 sleep(count#Fixnum) at line test/thread1.rb:11 + #1 Object.fn(count#Fixnum, i#Fixnum) at line test/thread1.rb:11 + #2 at line test/thread1.rb:23 + 5 # + #0 sleep(count#Fixnum) at line test/thread1.rb:11 + #1 Object.fn(count#Fixnum, i#Fixnum) at line test/thread1.rb:11 + #2 at line test/thread1.rb:23 + 6 # + #0 sleep(count#Fixnum) at line test/thread1.rb:11 + #1 Object.fn(count#Fixnum, i#Fixnum) at line test/thread1.rb:11 + #2 at line test/thread1.rb:23 ++ 7 # + #0 Object.fn(count#Fixnum, i#Fixnum) at line test/thread1.rb:14 + #1 at line test/thread1.rb:23 +@end smallexample + +@kindex info variables +@item info variables +Local and instance variables. +@end table + +@node Post-Mortem Debugging +@chapter Post-Mortem Debugging +@cindex post-mortem debugging + +It is also to possible enter the debugger when you have an uncaught +exception that is about to terminate our program. This is called +@emph{post-mortem debugging}. In this state many, of the debugger commands +for examining variables and moving around in the stack still +work. However some commands, such as those which imply a continuation +of running code, no longer work. + +The most reliable way to set up post-mortem debugging is to use the +@option{--post-mortem} option in invoking @code{rdebug}. See @ref{rdebug +command-line options}. This traps/wraps at the debugger ``load'' of +your Ruby script. When this is done, your program is stopped after +the exception takes place, but before the stack has been +unraveled. (Alas, it would be nice to if one could allow resetting the +exception and continuing, but details of code in Ruby 1.8's +@code{eval.c} prevent this.) + +If however you haven't invoked @code{rdebug} at the outset, but +instead call @code{ruby-debug} from inside your program, to set up +post-mortem debugging set the @code{post_mortem} key in +@code{Debugger.start}. Here's an example modified from +@url{http://www.datanoise.com/articles/2006/12/20/post-mortem-debugging}: + +@smallexample + $ @b{cat t.rb } + require 'rubygems' + require 'ruby-debug' ; Debugger.start(:post_mortem => true) + + def t1 + raise 'test' + end + def t2 + t1 + end + t2 + + $ @b{ruby t.rb } + t.rb:8: raise 'test' + (rdb:post-mortem) @b{l=} + [3, 12] in t.rb + 3 + 4 Debugger.start + 5 Debugger.post_mortem + 6 + 7 def t1 + => 8 raise 'test' + 9 end + 10 def t2 + 11 t1 + 12 end + (rdb:post-mortem) +@end smallexample + +Alternatively you can call @code{Debugger.post_mortem()} after rdebug has +been started. The @code{post_mortem()} method can be called in two +ways. Called without a block, it installs a global @code{at_exit()} hook +that intercepts exceptions not handled by your Ruby script. In +contrast to using the @option{--post-mortem} option, when this hook +occurs after the call stack has been rolled back. (I'm not sure if +this in fact makes any difference operationally; I'm just stating it +because that's how it works.) + +If you know that a particular block of code raises an exception you +can enable post-mortem mode by wrapping this block inside a +@code{Debugger.post_mortem} block + +@smallexample +def offender + 1/0 +end +... +require "ruby-gems" +require "ruby-debug" +Debugger.post_mortem do + ... + offender + ... +end +@end smallexample + +Once inside the debugger in post-mortem debugging, the prompt should +be @code{(rdb:post-mortem)}. + +@node Debugger Module and Class +@chapter The Debugger Module and Class + +@menu +* Debugger Module:: ruby-debug's Debugger module +* Debugger Class:: Debugger class +* Kernel routines:: Routines added to Kernel +@end menu + +@node Debugger Module +@section The Debugger Module + +@menu +* Debugger.run:: +@ifset LATER +* Debugger.post-mortem:: +@end ifset +* Debugger.context:: +* Debugger.settings:: +@end menu + +@node Debugger.run +@subsection @code{Debugger.start}, @code{Debugger.started?}, @code{Debugger.stop}, @code{Debugger.run_script} + +In order to provide better debugging information regarding the stack +frame(s) across all threads, ruby-debug has to intercept each call, +save some information and on return remove it. Possibly, in Ruby 1.9 +possibly this will not be needed. Therefore one has to issue call to +indicate start saving information and another call to stop. Of course, +If you call ruby-debug from the outset via @code{rdebug} this is done +for you. + +@table @code +@item Debugger.start(@ovar{options}) @ovar{block} +@vindex @code{Debugger.start(options)} +@vindex @code{Debugger.start(block)} +Turn on add additional instrumentation code to facilitate debugging. A +system even table hook is installed and some variables are set up to +access thread frames. + +This needs to be done before entering the debugger; therefore a call +to the debugger issue a @code{Debugger.start} call if necessary. + +If called without a block, @code{Debugger.start} returns @code{true} if +the debugger was already started. But if you want to know if the +debugger has already been started @code{Debugger.started?} can tell +you. + +If a block is given, the debugger is started and @code{yields} to +block. When the block is finished executing, the debugger stopped with +the @code{Debugger.stop method}. You will probably want to put a call +to @code{debugger} somwhere inside that block + +But if you want to completely stop debugger, you must call +@code{Debugger.stop} as many times as you called Debugger.start +method. + +The first time Debugger.start is called there is also some additional +setup to make the @code{restart} command work. In particular, @code{$0} and +@code{ARGV} are used to set internal debugger variables. + +Therefore you should make try to make sure that when +@code{Debugger.start} is called neither of these variables has been +modified. If instead you don't want this behavior you can pass an +options has and set the @code{:init} key to @code{false}. That is +@smallexample + Debugger.start(:init => false) # or Debugger.start(@{:init => false@}) +@end smallexample + +If you want post-mortem debugging, you can also supply +@code{:post_mortem => true} in @code{Debugger.start}. + +@item Debugger.started? +@vindex @code{Debugger.started?} +Boolean. Return @code{true} if debugger has been started. + +@item Debugger.stop +@vindex @code{Debugger.stop} +Turn off instrumentation to allow debugging. Return @code{true} is returned +if the debugger is disabled, otherwise it returns @code{false}. +@emph{Note that if you want to stop debugger, you must call Debugger.stop +as many times as you called the @code{Debugger.start} method.} + +@item Debugger.run_script(@var{debugger-command-file}, out = handler.interface) +@vindex @code{Debugger.run_script} +Reads/runs the given file containing debugger commands. @code{.rdebugrc} is run this way. + +@item Debugger.last_exception +@vindex @code{Debugger.last_exception} +If not @code{nil}, this contains @code{$!} from the last exception. + +@end table + +@node Debugger.context +@subsection @code{Debugger.context} +As mentioned previously, @code{Debugger.start} instruments additional +information to be obtained about the current block/frame stack. Here +we describe these additional @code{Debugger.context} methods. + +Were a frame position is indicated, it is optional. The top or current frame +position (position zero) is used if none is given. + +@table @code +@item Debugger.context.frame_args @ovar{frame-position=0} +@vindex @code{Debugger.context.frame_args} +If track_frame_args? is true, return information saved about call +arguments (if any saved) for the given frame position. + +@item Debugger.context.frame_args_info @ovar{frame-position=0} +@vindex @code{Debugger.context.frame_args_info} + +@item Debugger.context.frame_class @ovar{frame-position=0} +@vindex @code{Debugger.context.frame_args_info} +Return the class of the current frame stack. + +@item Debugger.context.frame_file @ovar{frame-position=0} +@vindex @code{Debugger.context.frame_file} +Return the filename of the location of the indicated frame position. + +@item Debugger.context.frame_id @ovar{frame-position=0} +@vindex @code{Debugger.context.frame_id} +Same as @code{Debugger.context.method}. + +@item Debugger.context.frame_line @ovar{frame-position=0} +@vindex @code{Debugger.context.frame_line} +Return the filename of the location of the indicated frame position. + +@item Debugger.context.frame_method @ovar{frame-position=0} +@vindex @code{Debugger.context.frame_method} +Symbol of the method name of the indicated frame position. + +@item Debugger.context.stack_size +@vindex @code{Debugger.context.stack_size} +Return the number the size of the frame stack. Note this may be less +that the actual frame stack size if debugger recording +(@code{Debugger.start}) was turned on at after some blocks were added +and not finished when the @code{Debugger.start} was issued. +@end table + +@node Debugger.settings +@subsection @code{Debugger.settings} +@vindex @code{Debugger.settings} +Symbols listed here are keys into the Array @code{Debugger.settings}. +These can be set any time after the @code{ruby-debug} is loaded. For example: +@smallexample + require "ruby-debug/debugger" + Debugger.settings[:autoeval] = true # try eval on unknown debugger commands + Debugger.listsize = 20 # Show 20 lines in a list command +@end smallexample + +@table @code +@item :argv +Array of String. @code{argv[0]} is the debugged program name and +@code{argv[1..-1]} are the command arguments to it. +@item :autoeval +Boolean. True if auto autoeval on. @xref{Autoeval}. +@item :autoirb +Fixnum: 1 if on or 0 if off. @xref{Autoirb}. +@item :autolist +Fixnum: 1 if on or 0 if off. +@item :basename +Boolean. True if basename on. @xref{Basename}. +@item :callstyle +Symbol: @code{:short} or @code{:last}. @xref{Callstyle}. +@item :debuggertesting +Boolean. True if currently testing the debugger. +@item :force_stepping +Boolean. True if stepping should go to a line different from the last +step. @xref{Forcestep}. +@item :full_path +Boolean. @xref{Fullpath}. +@item :listsize +Fixnum. Number of lines to show in a @code{list} command. @xref{Listsize}. +@item :reload_source_on_change +Boolean. True if we should reread the source every time it changes. @xref{Autoreload}. +@item :stack_trace_on_error +Boolean. True if we should produce a stack trace on error. @xref{Trace}. +@item :width +Fixnum. Number of characters the debugger thinks are in a line. @xref{Width}. +@end table + +@node Debugger Class +@section The @code{Debugger} Class +@menu +* Debugger.Breakpoint:: Debugger::Breakpoint +* Debugger.Context:: Debugger::Context +* Debugger.Command:: Debugger::Command +@end menu + +@table @code +@item add_breakpoint(file, line, expr) +@vindex @code{Debugger.add_breakpoint} +Adds a breakpoint in file @var{file}, at line @var{line}. If +@var{expr} is not nil, it is evaluated and a breakpoint takes effect +at the indicated position when that expression is true. You should +verify that @var{expr} is syntactically valid or a @code{SyntaxError} +exception, and unless your code handles this the debugged program may +terminate. + +@item remove_breakpoint(bpnum) +@vindex @code{Debugger.remove_breakpoint} +When a breakpoint is added, it is assigned a number as a way to +uniquely identify it. (There can be more than one breakpoint on a +given line.) To remove a breakpoint, use @code{remove_breakpoint} with +breakpoint number @var{bpnum}. + +@item breakpoints +@vindex @code{Debugger.breakpoints} +Return a list of the breakpoints that have been added but not removed. +@end table + +@node Debugger.Breakpoint +@subsection The @code{Debugger::Breakpoint} Class +Breakpoint are objects in the @code{Debugger::Breakpoint} class. +@table @code +@item enabled? +@vindex @code{Debugger::Breakpoints.enabled?} +Returns whether breakpoint is enabled or not. + +@item enabled= +@vindex @code{Debugger::Breakpoints.enabled=} +Sets whether breakpoint is enabled or not. + +@item expr +@vindex @code{Debugger::Breakpoints.expr} +Expression which has to be true at the point where the breakpoint is +set before we stop. + +@item expr= +@vindex @code{Debugger::Breakpoints.expr=} + +@item hit_condition +@item hit_condition= +@vindex @code{Debugger::Breakpoints.condition} +@vindex @code{Debugger::Breakpoints.condition=} + +@item hit_count +@vindex @code{Debugger::Breakpoints.hit_count} +Returns the hit count of the breakpoint. + +@item hit_value +@vindex @code{Debugger::Breakpoints.hit_value} +Returns the hit value of the breakpoint. + +@item hit_value= +@vindex @code{Debugger::Breakpoints.hit_value=} +Sets the hit value of the breakpoint. + +@item id +@cindex @code{Debugger::Breakpoints.id} +A numeric name for the breakpoint which is used in listing breakpoints +and removing, enabling or disabling the breakpoint + +@item pos +@vindex @code{Debugger::Breakpoints.pos=} +Returns the line number of this breakpoint. +@item pos= +@vindex @code{Debugger::Breakpoints.pos=} +Sets the line number of this breakpoint. + +@item source +@vindex @code{Debugger::Breakpoints.source} +Returns the file name in which the breakpoint occurs. + +@item source= +@vindex @code{Debugger::Breakpoints.source=} +Sets the file name in which the breakpoint occurs. +@end table + +@node Debugger.Context +@subsection The @code{Debugger::Context} Class +Callbacks in @code{Debugger:Context} get called when a stopping point +or an event is reached. It has information about the suspended program +which enable a debugger to inspect the frame stack, evaluate variables +from the perspective of the debugged program, and contains information +about the place the debugged program is stopped. + +@table @code +@item at_line(@var{file}, @var{line}) +@vindex Debugger::Context::at_line(@var{file}, @var{line}) +This routine is called when the debugger encounters a ``line'' event for +which it has been indicated we want to stop at, such as by hitting a +breakpoint or by some sort of stepping. + +@item at_return(@var{file}, @var{line}) +@vindex Debugger::Context::at_return(@var{file}, @var{line}) +This routine is called when the debugger encounters a ``return'' event for +which it has been indicated we want to stop at, such as by hitting a +@code{finish} statement. + +@item debug_load(@var{file}, @var{stop-initially}) +@vindex Debugger::Context::debug_load(@var{file}, @var{stop-initially}) +This method should be used to debug a file. If the file terminates +normally, @code{nil} is returned. If not a backtrace is returned. + +The @var{stop-initially} parameter indicates whether the program +should stop after loading. If an explicit call to the debugger is in +the debugged program, you may want to set this @code{false}. +@end table + +@node Debugger.Command +@subsection The @code{Debugger::Command} Class + +Each command you run is in fact its own class. Should you want to extend +ruby-debug, it's pretty easy to do since after all ruby-debug is Ruby. + +Each @code{Debugger#Command} class should have the a @code{regexp} +method. This method returns regular expression for command-line +strings that match your command. It's up to you to make sure this +regular expression doesn't conflict with another one. If it does, it's +undefined which one will get matched and run + +In addition the instance needs these methods: +@table @code +@item execute +Code which gets run when you type a command (string) that matches the +commands regular expression. +@item help +A string which gets displayed when folks as for help on that command +@item help_command +A name used the help system uses to show what commands are available. +@end table + +Here's a small example of a new command: +@smallexample +module Debugger + class MyCommand < Command + def regexp + /^\s*me$/ # Regexp that will match your command + end + + def execute + puts "hi" # What you want to happen when your command runs + end + class << self + def help_command + 'me' # String name of command + end + def help(cmd) + # Some sort of help text. + %@{This does whatever it is I want to do@} + end + end +end +@end smallexample + +Now here's an example of how you can load/use it: +@smallexample + require 'rubygems' + require 'ruby-debug' + require '/tmp/mycmd.rb' # or wherever + Debugger.start + x=1 + debugger + y=2 +@end smallexample + +And now an example of invoking it: +@smallexample +ruby /tmp/testit.rb: +/tmp/testit.rb:7 +y=2 +(rdb:1) help +ruby-debug help v0.10.3 +Type 'help ' for help on a specific command +Available commands: +backtrace delete enable help method putl set trace +break disable eval info next quit show undisplay +catch display exit irb p reload source up +condition down finish list pp restart step var +continue edit frame me ps save thread where + ^^ This is you + +(rdb:1) help me +This does whatever it is I want to do +(rdb:1) me +hi +(rdb:1) +@end smallexample + +@node Kernel routines +@section Additions to @code{Kernel} + +@table @code + +@item debugger @ovar{steps=1} +@vindex @code{Kernel::debugger} +Enters the debugger in the current thread after a stepping @var{steps} line-event steps. +Before entering the debugger startup script is read. + +Setting @var{steps} to 0 will cause a break in the debugger subroutine +and not wait for eany line event to occur. This could be useful you +want to stop right after the last statement in some scope. + +Consider this example: +@smallexample +$ cat scope-test.rb + +require 'rubygems' +require 'ruby-debug' ; Debugger.start +1.times do + a = 1 + debugger # implied steps=1 + end +y = 1 + +$ scope-test.rb:8 +y = 1 +(rdb:1) p a +NameError Exception: undefined local variable or method `a' for main:Object +(rdb:1) +@end smallexample +The debugger will get at the line event which follows @samp{a=1}. This +is outside the @code{do} block scope where @var{a} is defined. If +instead you want to stop before leaving the @code{do} loop it is +possibly to stop right inside the @code{debugger}; call with 0 zero parameter: +@smallexample +$ cat scope-test.rb + +require 'rubygems' +require 'ruby-debug' ; Debugger.start +1.times do + a = 1 + debugger(0) +end +y = 1 + +$ scope-test.rb:8 +../lib/ruby-debug-base.rb:175 +Debugger.current_context.stop_frame = 0 +(rdb:1) where +--> #0 Kernel.debugger(steps#Fixnum) at line ../lib/ruby-debug-base.rb:175 + #1 at line scope-test.rb:6 + #2 at line scope-test.rb:4 +(rdb:1) up +#1 at line scope-test.rb:6 +(rdb:1) p a +1 +(rdb:1) +@end smallexample +As seen above you will have to position the frame up one to be back in +your debugged program rather than in the debugger. + +@item breakpoint @ovar{steps=1} +@vindex @code{Kernel::breakpoint} +An alias for debugger. + +@item binding_n @ovar{n=0} +@vindex @code{Kernel::binding_n} +Returns a @samp{binding()} for the @var{n}-th call frame. Note however +that you need to first call @samp{Debugger.start} before issuing this +call. + +@end table + +@node Using from Subversion +@appendix Building and Installing from rubyforge's Subversion Repository + +Here are Unix-centric instructions. If you have Microsoft Windows or +OSX some of the below may need adjusting. + +@menu +* Prerequisites:: +* Package Checkout:: +* Trying Out:: +* Running Regression Tests:: +* Building the Documentation and Emacs files:: +* Building for Microsoft Windows:: +@end menu + +@node Prerequisites +@section Prerequisites: To build the package you'll need at a minimum: + +@itemize @bullet +@item +Ruby (of course). Currently only version 1.8.6 and above but not +version 1.9.@emph{x} work. +@item +Ruby development headers. This typically includes a file called @file{ruby.h} +@item +A C compiler like GNU C (@code{gcc}) +@item +Rake +@item +Subversion (@code{svn}). +@end itemize + +If you want to build the documentation and install Emacs files, you'll +also need: + +@itemize @bullet +@item + a POSIX shell like bash +@item + autoconf +@item + automake +@item + GNU Make +@item + texinfo +@end itemize + +@node Package Checkout +@section Basic Package Checkout and Installation + +Check out the trunk of repository following the instructions at +@url{http://rubyforge.org/scm/?group_id=1900} For example on a Unixy system, +this may work: + +@smallexample + mkdir ruby-debug + cd ruby-debug + svn checkout svn://rubyforge.org/var/svn/ruby-debug/trunk trunk +@end smallexample + +In order to make the Ruby gems, @code{ruby-debug} and +@code{ruby-debug-base}, get yourself into the trunk directory after +the code has been checked out and run: + +@smallexample + cd trunk # This is the same trunk checked out above. + rake package +@end smallexample + +If all goes well you should have some gem files put in the directory +@code{pkg}. Use the gem command to install that. + +@smallexample + sudo gem install ruby-debug-*.gem # See gem help for other possibilities +@end smallexample + +If all goes well the rdebug script has been installed ruby-debug is +now ready to run. But if everything goes well you might want to run +the built-in regression tests to make sure everything is okay. +See step 3 below. + +If the gem install didn't work,'t there may be a problem with your C +compiler or the Ruby headers are not installed. + +@node Trying Out +@section Trying Out without Installing + +You don't have to build a gem file to try out ruby debug. In fact when +developing new features for ruby-debug, developers often you want to +try it out @emph{before} installing. If you have a problem in the latter +part of step 1 you may want to try this approach since we go into a +little more detail as to what happens under the covers when you do the +gem install. + +Run (from trunk) +@smallexample + rake lib +@end smallexample + +This creates a Makefile and builds the ruby-debug shared library. (On +Unix the name is @code{ruby_debug.so}). + +Once this is done you can run the debugger as you would rdebug using the +script @code{runner.sh}. For example (again from trunk) + +@smallexample + ./runner.sh ~/my-ruby-program.rb +@end smallexample + +@node Running Regression Tests +@section Running the Regression Tests + +We've put together some basic tests to make sure ruby-debug is doing +what we think it should do. To run these (from @code{trunk}): + +@smallexample + rake test +@end smallexample + +If you didn't build the ruby-debug shared library and skipped step 2, +don't worry @code{rake test} will do step 2 for you. You should see a +line that ends something like: + +@smallexample + Finished in 2.767579 seconds. + + 12 tests, 35 assertions, 0 failures, 0 errors +@end smallexample + +The number of seconds, tests, and assertions may be different from the +above. However you @emph{should} see exactly ``0 failures, 0 errors.'' + +@node Building the Documentation and Emacs files +@section Building the Documentation and Testing/Installing Emacs Files + +Of course, I recommend you read the ruby-debug manual that comes with +the package. If you have the prerequisites described above, run this +once: +@smallexample + sh ./autogen.sh +@end smallexample + +Then run: +@smallexample + ./configure + make + make test # Runs Emacs regression tests + sudo make install # Or arrange to do this as root +@end smallexample + +@node Building for Microsoft Windows +@section Building for Microsoft Windows + +Microsoft Windows is ``special'' and building @code{ruby-debug-base} +on it requires extra care. A problem here seems to be that the +``One-click'' install is compiled using Microsoft Visual Studio C, version 6 +which is not sold anymore and is rather old. + +Instead I suggest building via mingw/msys. +@url{http://eigenclass.org/hiki.rb?cmd=view&p=cross+compiling+rcovrt&key=mingw} +has instructions on how to do. Some amendments to these instructions. + +First, those instructions are a little GNU/Linux centric. If you are +using Ubuntu or Debian, then this should be the easiest to follow the +instructions. On Ubuntu or Debian there is a mingw3 Debian +package. Installing that will give you the cross compiler that is a +prerequisite. Alternatively if you are running MS Windows I notice +that cygwin also has a mingw package. Or possibly you could use MinGW +directly. For other OS's you might have to build a cross-compiler, +i.e. gcc which emits win32 code and can create a win32 DLL. + +After you have a cross compiler you need to download the Ruby source +and basically build a ruby interpreter. The cross-compile.sh script +works although when I downloaded it, it had lots of blank space at the +beginning which will mess up the Unix magic interpretation. That is +remove the blanks in front of @code{#/bin/sh}. + +On my system, this script fails in running @code{make ruby} because the +fake.rb that got created needed to have a small change: + +@smallexample + + ALT_SEPARATOR = "\"; \ +@end smallexample +should be: +@smallexample + ALT_SEPARATOR = "\\"; \ +@end smallexample + +After fixing this, run @code{make ruby}. Also, I needed to run +@code{make rubyw}. + +And then @code{make install} as indicated. + +Once all of that's in place, the place you want be is in +@code{ruby-debug/trunk/ext/win32}, not @code{ruby-debug/ext}. + +So let's say you've installed the cross-compiled install ruby in +@code{/usr/local/ruby-mingw32/}. Here then are the commands to build @code{ruby-debug-base-}@emph{xxx}@code{-mswin32.gem}: +@smallexample + cd .../ruby-debug/trunk/ext/win32 + ruby -I /usr/local/ruby-mingw32/lib/ruby/1.8/i386-mingw32 ../extconf.rb + make # Not rake + cd ../.. # back in ruby-debug/trunk + rake win32_gem +@end smallexample + +@node Class Module Index +@unnumbered Class, Module Method Index +@printindex vr + +@node Command Index +@unnumbered Command Index +@printindex ky + +@node General Index +@unnumbered General Index +@printindex cp + +@tex +% I think something like @colophon should be in texinfo. In the +% meantime: +\long\def\colophon{\hbox to0pt{}\vfill +\centerline{The body of this manual is set in} +\centerline{\fontname\tenrm,} +\centerline{with headings in {\bf\fontname\tenbf}} +\centerline{and examples in {\tt\fontname\tentt}.} +\centerline{{\it\fontname\tenit\/},} +\centerline{{\bf\fontname\tenbf}, and} +\centerline{{\sl\fontname\tensl\/}} +\centerline{are used for emphasis.}\vfill} +\page\colophon +% Blame: doc@cygnus.com, 1991. +@end tex + +@bye diff --git a/doc/test-tri2.rb b/doc/test-tri2.rb new file mode 100644 index 0000000..2be90bc --- /dev/null +++ b/doc/test-tri2.rb @@ -0,0 +1,18 @@ +#!/usr/bin/env ruby +require "test/unit" +require "tri2.rb" +require "rubygems" +require "ruby-debug" +Debugger.start + +class TestTri < Test::Unit::TestCase + def test_basic + debugger + solutions = [] + 0.upto(5) do |i| + solutions << triangle(i) + end + assert_equal([0, 1, 3, 6, 10, 15], solutions, + "Testing the first 5 triangle numbers") + end +end diff --git a/doc/tri3.rb b/doc/tri3.rb new file mode 100644 index 0000000..0564847 --- /dev/null +++ b/doc/tri3.rb @@ -0,0 +1,8 @@ +#!/usr/bin/env ruby +def triangle(n) + (0..n).inject do |sum, i| + sum +=i + end +end +puts triangle(3) + diff --git a/doc/triangle.rb b/doc/triangle.rb new file mode 100644 index 0000000..39f038c --- /dev/null +++ b/doc/triangle.rb @@ -0,0 +1,12 @@ +#!/usr/bin/env ruby +# Compute the n'th triangle number - the hard way +# triangle(n) == (n * (n+1)) / 2 +def triangle(n) + tri = 0 + 0.upto(n) do |i| + tri += i + end + return tri + end + +puts triangle(3) diff --git a/emacs/.svn/README.txt b/emacs/.svn/README.txt new file mode 100644 index 0000000..271a8ce --- /dev/null +++ b/emacs/.svn/README.txt @@ -0,0 +1,2 @@ +This is a Subversion working copy administrative directory. +Visit http://subversion.tigris.org/ for more information. diff --git a/emacs/.svn/dir-prop-base b/emacs/.svn/dir-prop-base new file mode 100644 index 0000000..f28ed7f --- /dev/null +++ b/emacs/.svn/dir-prop-base @@ -0,0 +1,10 @@ +K 10 +svn:ignore +V 48 +.cvsignore +*.elc +Makefile.in +elc-stamp +Makefile + +END diff --git a/emacs/.svn/dir-props b/emacs/.svn/dir-props new file mode 100644 index 0000000..f28ed7f --- /dev/null +++ b/emacs/.svn/dir-props @@ -0,0 +1,10 @@ +K 10 +svn:ignore +V 48 +.cvsignore +*.elc +Makefile.in +elc-stamp +Makefile + +END diff --git a/emacs/.svn/empty-file b/emacs/.svn/empty-file new file mode 100644 index 0000000..e69de29 diff --git a/emacs/.svn/entries b/emacs/.svn/entries new file mode 100644 index 0000000..2d9dc45 --- /dev/null +++ b/emacs/.svn/entries @@ -0,0 +1,233 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/emacs/.svn/format b/emacs/.svn/format new file mode 100644 index 0000000..b8626c4 --- /dev/null +++ b/emacs/.svn/format @@ -0,0 +1 @@ +4 diff --git a/emacs/.svn/prop-base/Makefile.am.svn-base b/emacs/.svn/prop-base/Makefile.am.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/emacs/.svn/prop-base/Makefile.am.svn-base @@ -0,0 +1 @@ +END diff --git a/emacs/.svn/prop-base/rdebug-annotate.el.svn-base b/emacs/.svn/prop-base/rdebug-annotate.el.svn-base new file mode 100644 index 0000000..92c8ad7 --- /dev/null +++ b/emacs/.svn/prop-base/rdebug-annotate.el.svn-base @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 2 +Id +END diff --git a/emacs/.svn/prop-base/rdebug-breaks.el.svn-base b/emacs/.svn/prop-base/rdebug-breaks.el.svn-base new file mode 100644 index 0000000..92c8ad7 --- /dev/null +++ b/emacs/.svn/prop-base/rdebug-breaks.el.svn-base @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 2 +Id +END diff --git a/emacs/.svn/prop-base/rdebug-cmd.el.svn-base b/emacs/.svn/prop-base/rdebug-cmd.el.svn-base new file mode 100644 index 0000000..92c8ad7 --- /dev/null +++ b/emacs/.svn/prop-base/rdebug-cmd.el.svn-base @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 2 +Id +END diff --git a/emacs/.svn/prop-base/rdebug-core.el.svn-base b/emacs/.svn/prop-base/rdebug-core.el.svn-base new file mode 100644 index 0000000..92c8ad7 --- /dev/null +++ b/emacs/.svn/prop-base/rdebug-core.el.svn-base @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 2 +Id +END diff --git a/emacs/.svn/prop-base/rdebug-dbg.el.svn-base b/emacs/.svn/prop-base/rdebug-dbg.el.svn-base new file mode 100644 index 0000000..92c8ad7 --- /dev/null +++ b/emacs/.svn/prop-base/rdebug-dbg.el.svn-base @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 2 +Id +END diff --git a/emacs/.svn/prop-base/rdebug-error.el.svn-base b/emacs/.svn/prop-base/rdebug-error.el.svn-base new file mode 100644 index 0000000..92c8ad7 --- /dev/null +++ b/emacs/.svn/prop-base/rdebug-error.el.svn-base @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 2 +Id +END diff --git a/emacs/.svn/prop-base/rdebug-fns.el.svn-base b/emacs/.svn/prop-base/rdebug-fns.el.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/emacs/.svn/prop-base/rdebug-fns.el.svn-base @@ -0,0 +1 @@ +END diff --git a/emacs/.svn/prop-base/rdebug-frames.el.svn-base b/emacs/.svn/prop-base/rdebug-frames.el.svn-base new file mode 100644 index 0000000..92c8ad7 --- /dev/null +++ b/emacs/.svn/prop-base/rdebug-frames.el.svn-base @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 2 +Id +END diff --git a/emacs/.svn/prop-base/rdebug-gud.el.svn-base b/emacs/.svn/prop-base/rdebug-gud.el.svn-base new file mode 100644 index 0000000..92c8ad7 --- /dev/null +++ b/emacs/.svn/prop-base/rdebug-gud.el.svn-base @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 2 +Id +END diff --git a/emacs/.svn/prop-base/rdebug-help.el.svn-base b/emacs/.svn/prop-base/rdebug-help.el.svn-base new file mode 100644 index 0000000..92c8ad7 --- /dev/null +++ b/emacs/.svn/prop-base/rdebug-help.el.svn-base @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 2 +Id +END diff --git a/emacs/.svn/prop-base/rdebug-info.el.svn-base b/emacs/.svn/prop-base/rdebug-info.el.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/emacs/.svn/prop-base/rdebug-info.el.svn-base @@ -0,0 +1 @@ +END diff --git a/emacs/.svn/prop-base/rdebug-layouts.el.svn-base b/emacs/.svn/prop-base/rdebug-layouts.el.svn-base new file mode 100644 index 0000000..92c8ad7 --- /dev/null +++ b/emacs/.svn/prop-base/rdebug-layouts.el.svn-base @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 2 +Id +END diff --git a/emacs/.svn/prop-base/rdebug-locring.el.svn-base b/emacs/.svn/prop-base/rdebug-locring.el.svn-base new file mode 100644 index 0000000..92c8ad7 --- /dev/null +++ b/emacs/.svn/prop-base/rdebug-locring.el.svn-base @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 2 +Id +END diff --git a/emacs/.svn/prop-base/rdebug-output.el.svn-base b/emacs/.svn/prop-base/rdebug-output.el.svn-base new file mode 100644 index 0000000..92c8ad7 --- /dev/null +++ b/emacs/.svn/prop-base/rdebug-output.el.svn-base @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 2 +Id +END diff --git a/emacs/.svn/prop-base/rdebug-regexp.el.svn-base b/emacs/.svn/prop-base/rdebug-regexp.el.svn-base new file mode 100644 index 0000000..92c8ad7 --- /dev/null +++ b/emacs/.svn/prop-base/rdebug-regexp.el.svn-base @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 2 +Id +END diff --git a/emacs/.svn/prop-base/rdebug-secondary.el.svn-base b/emacs/.svn/prop-base/rdebug-secondary.el.svn-base new file mode 100644 index 0000000..92c8ad7 --- /dev/null +++ b/emacs/.svn/prop-base/rdebug-secondary.el.svn-base @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 2 +Id +END diff --git a/emacs/.svn/prop-base/rdebug-shortkey.el.svn-base b/emacs/.svn/prop-base/rdebug-shortkey.el.svn-base new file mode 100644 index 0000000..92c8ad7 --- /dev/null +++ b/emacs/.svn/prop-base/rdebug-shortkey.el.svn-base @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 2 +Id +END diff --git a/emacs/.svn/prop-base/rdebug-source.el.svn-base b/emacs/.svn/prop-base/rdebug-source.el.svn-base new file mode 100644 index 0000000..92c8ad7 --- /dev/null +++ b/emacs/.svn/prop-base/rdebug-source.el.svn-base @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 2 +Id +END diff --git a/emacs/.svn/prop-base/rdebug-track.el.svn-base b/emacs/.svn/prop-base/rdebug-track.el.svn-base new file mode 100644 index 0000000..92c8ad7 --- /dev/null +++ b/emacs/.svn/prop-base/rdebug-track.el.svn-base @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 2 +Id +END diff --git a/emacs/.svn/prop-base/rdebug-varbuf.el.svn-base b/emacs/.svn/prop-base/rdebug-varbuf.el.svn-base new file mode 100644 index 0000000..92c8ad7 --- /dev/null +++ b/emacs/.svn/prop-base/rdebug-varbuf.el.svn-base @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 2 +Id +END diff --git a/emacs/.svn/prop-base/rdebug-vars.el.svn-base b/emacs/.svn/prop-base/rdebug-vars.el.svn-base new file mode 100644 index 0000000..92c8ad7 --- /dev/null +++ b/emacs/.svn/prop-base/rdebug-vars.el.svn-base @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 2 +Id +END diff --git a/emacs/.svn/prop-base/rdebug-watch.el.svn-base b/emacs/.svn/prop-base/rdebug-watch.el.svn-base new file mode 100644 index 0000000..92c8ad7 --- /dev/null +++ b/emacs/.svn/prop-base/rdebug-watch.el.svn-base @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 2 +Id +END diff --git a/emacs/.svn/prop-base/rdebug.el.svn-base b/emacs/.svn/prop-base/rdebug.el.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/emacs/.svn/prop-base/rdebug.el.svn-base @@ -0,0 +1 @@ +END diff --git a/emacs/.svn/props/Makefile.am.svn-work b/emacs/.svn/props/Makefile.am.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/emacs/.svn/props/Makefile.am.svn-work @@ -0,0 +1 @@ +END diff --git a/emacs/.svn/props/rdebug-annotate.el.svn-work b/emacs/.svn/props/rdebug-annotate.el.svn-work new file mode 100644 index 0000000..92c8ad7 --- /dev/null +++ b/emacs/.svn/props/rdebug-annotate.el.svn-work @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 2 +Id +END diff --git a/emacs/.svn/props/rdebug-breaks.el.svn-work b/emacs/.svn/props/rdebug-breaks.el.svn-work new file mode 100644 index 0000000..92c8ad7 --- /dev/null +++ b/emacs/.svn/props/rdebug-breaks.el.svn-work @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 2 +Id +END diff --git a/emacs/.svn/props/rdebug-cmd.el.svn-work b/emacs/.svn/props/rdebug-cmd.el.svn-work new file mode 100644 index 0000000..92c8ad7 --- /dev/null +++ b/emacs/.svn/props/rdebug-cmd.el.svn-work @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 2 +Id +END diff --git a/emacs/.svn/props/rdebug-core.el.svn-work b/emacs/.svn/props/rdebug-core.el.svn-work new file mode 100644 index 0000000..92c8ad7 --- /dev/null +++ b/emacs/.svn/props/rdebug-core.el.svn-work @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 2 +Id +END diff --git a/emacs/.svn/props/rdebug-dbg.el.svn-work b/emacs/.svn/props/rdebug-dbg.el.svn-work new file mode 100644 index 0000000..92c8ad7 --- /dev/null +++ b/emacs/.svn/props/rdebug-dbg.el.svn-work @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 2 +Id +END diff --git a/emacs/.svn/props/rdebug-error.el.svn-work b/emacs/.svn/props/rdebug-error.el.svn-work new file mode 100644 index 0000000..92c8ad7 --- /dev/null +++ b/emacs/.svn/props/rdebug-error.el.svn-work @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 2 +Id +END diff --git a/emacs/.svn/props/rdebug-fns.el.svn-work b/emacs/.svn/props/rdebug-fns.el.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/emacs/.svn/props/rdebug-fns.el.svn-work @@ -0,0 +1 @@ +END diff --git a/emacs/.svn/props/rdebug-frames.el.svn-work b/emacs/.svn/props/rdebug-frames.el.svn-work new file mode 100644 index 0000000..92c8ad7 --- /dev/null +++ b/emacs/.svn/props/rdebug-frames.el.svn-work @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 2 +Id +END diff --git a/emacs/.svn/props/rdebug-gud.el.svn-work b/emacs/.svn/props/rdebug-gud.el.svn-work new file mode 100644 index 0000000..92c8ad7 --- /dev/null +++ b/emacs/.svn/props/rdebug-gud.el.svn-work @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 2 +Id +END diff --git a/emacs/.svn/props/rdebug-help.el.svn-work b/emacs/.svn/props/rdebug-help.el.svn-work new file mode 100644 index 0000000..92c8ad7 --- /dev/null +++ b/emacs/.svn/props/rdebug-help.el.svn-work @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 2 +Id +END diff --git a/emacs/.svn/props/rdebug-info.el.svn-work b/emacs/.svn/props/rdebug-info.el.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/emacs/.svn/props/rdebug-info.el.svn-work @@ -0,0 +1 @@ +END diff --git a/emacs/.svn/props/rdebug-layouts.el.svn-work b/emacs/.svn/props/rdebug-layouts.el.svn-work new file mode 100644 index 0000000..92c8ad7 --- /dev/null +++ b/emacs/.svn/props/rdebug-layouts.el.svn-work @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 2 +Id +END diff --git a/emacs/.svn/props/rdebug-locring.el.svn-work b/emacs/.svn/props/rdebug-locring.el.svn-work new file mode 100644 index 0000000..92c8ad7 --- /dev/null +++ b/emacs/.svn/props/rdebug-locring.el.svn-work @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 2 +Id +END diff --git a/emacs/.svn/props/rdebug-output.el.svn-work b/emacs/.svn/props/rdebug-output.el.svn-work new file mode 100644 index 0000000..92c8ad7 --- /dev/null +++ b/emacs/.svn/props/rdebug-output.el.svn-work @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 2 +Id +END diff --git a/emacs/.svn/props/rdebug-regexp.el.svn-work b/emacs/.svn/props/rdebug-regexp.el.svn-work new file mode 100644 index 0000000..92c8ad7 --- /dev/null +++ b/emacs/.svn/props/rdebug-regexp.el.svn-work @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 2 +Id +END diff --git a/emacs/.svn/props/rdebug-secondary.el.svn-work b/emacs/.svn/props/rdebug-secondary.el.svn-work new file mode 100644 index 0000000..92c8ad7 --- /dev/null +++ b/emacs/.svn/props/rdebug-secondary.el.svn-work @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 2 +Id +END diff --git a/emacs/.svn/props/rdebug-shortkey.el.svn-work b/emacs/.svn/props/rdebug-shortkey.el.svn-work new file mode 100644 index 0000000..92c8ad7 --- /dev/null +++ b/emacs/.svn/props/rdebug-shortkey.el.svn-work @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 2 +Id +END diff --git a/emacs/.svn/props/rdebug-source.el.svn-work b/emacs/.svn/props/rdebug-source.el.svn-work new file mode 100644 index 0000000..92c8ad7 --- /dev/null +++ b/emacs/.svn/props/rdebug-source.el.svn-work @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 2 +Id +END diff --git a/emacs/.svn/props/rdebug-track.el.svn-work b/emacs/.svn/props/rdebug-track.el.svn-work new file mode 100644 index 0000000..92c8ad7 --- /dev/null +++ b/emacs/.svn/props/rdebug-track.el.svn-work @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 2 +Id +END diff --git a/emacs/.svn/props/rdebug-varbuf.el.svn-work b/emacs/.svn/props/rdebug-varbuf.el.svn-work new file mode 100644 index 0000000..92c8ad7 --- /dev/null +++ b/emacs/.svn/props/rdebug-varbuf.el.svn-work @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 2 +Id +END diff --git a/emacs/.svn/props/rdebug-vars.el.svn-work b/emacs/.svn/props/rdebug-vars.el.svn-work new file mode 100644 index 0000000..92c8ad7 --- /dev/null +++ b/emacs/.svn/props/rdebug-vars.el.svn-work @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 2 +Id +END diff --git a/emacs/.svn/props/rdebug-watch.el.svn-work b/emacs/.svn/props/rdebug-watch.el.svn-work new file mode 100644 index 0000000..92c8ad7 --- /dev/null +++ b/emacs/.svn/props/rdebug-watch.el.svn-work @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 2 +Id +END diff --git a/emacs/.svn/props/rdebug.el.svn-work b/emacs/.svn/props/rdebug.el.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/emacs/.svn/props/rdebug.el.svn-work @@ -0,0 +1 @@ +END diff --git a/emacs/.svn/text-base/Makefile.am.svn-base b/emacs/.svn/text-base/Makefile.am.svn-base new file mode 100644 index 0000000..2bbc81e --- /dev/null +++ b/emacs/.svn/text-base/Makefile.am.svn-base @@ -0,0 +1,130 @@ +# Copyright (C) 2007, 2008 Rocky Bernstein rocky@gnu.org +# +# This program is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 2, or (at your option) any later +# version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License along +# with Bash; see the file COPYING. If not, write to the Free Software +# Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. +#$Id: Makefile.am,v 1.10 2007/04/13 00:59:33 rockyb Exp $ + +lisp_files = rdebug.el \ + rdebug-annotate.el \ + rdebug-breaks.el \ + rdebug-cmd.el \ + rdebug-core.el \ + rdebug-dbg.el \ + rdebug-error.el \ + rdebug-fns.el \ + rdebug-frames.el \ + rdebug-gud.el \ + rdebug-help.el \ + rdebug-info.el \ + rdebug-layouts.el \ + rdebug-locring.el \ + rdebug-output.el \ + rdebug-regexp.el \ + rdebug-secondary.el\ + rdebug-shortkey.el \ + rdebug-source.el \ + rdebug-track.el \ + rdebug-varbuf.el \ + rdebug-vars.el \ + rdebug-watch.el +check_DATA = test/elk-test.el \ + test/test-annotate.el \ + test/test-cmd.el \ + test/test-core.el \ + test/test-fns.el \ + test/test-gud.el \ + test/test-indent.el \ + test/test-regexp.el \ + test/test-shortkey.el + +EXTRA_DIST = $(lisp_files) $(check_DATA) +ELCFILES = rdebug.elc \ + rdebug-annotate.elc \ + rdebug-breaks.elc \ + rdebug-cmd.elc \ + rdebug-core.elc \ + rdebug-dbg.elc \ + rdebug-error.elc \ + rdebug-fns.elc \ + rdebug-gud.elc \ + rdebug-frames.elc \ + rdebug-help.elc \ + rdebug-info.elc \ + rdebug-layouts.elc \ + rdebug-locring.elc \ + rdebug-output.elc \ + rdebug-regexp.elc \ + rdebug-secondary.elc \ + rdebug-shortkey.elc \ + rdebug-source.elc \ + rdebug-track.elc \ + rdebug-varbuf.elc \ + rdebug-vars.elc \ + rdebug-watch.elc +if INSTALL_EMACS_LISP +lisp_LISP = $(lisp_files) +CHECK_FILES = \ + check-annotate \ + check-cmd \ + check-core \ + check-fns \ + check-frames \ + check-gud \ + check-indent \ + check-regexp \ + check-shortkey + +check: $(CHECK_FILES) + +check-annotate: rdebug-annotate.el + (cd $(srcdir)/test && \ + $(EMACS) -batch -q -l test-annotate.el ) + +check-cmd: rdebug-gud.el + (cd $(srcdir)/test && \ + $(EMACS) -batch -q -l test-cmd.el ) + +check-core: rdebug-core.el + (cd $(srcdir)/test && \ + $(EMACS) -batch -q -l test-core.el ) + +check-fns: rdebug-fns.el + (cd $(srcdir)/test && \ + $(EMACS) -batch -q -l test-fns.el ) + +check-frames: rdebug-frames.el + (cd $(srcdir)/test && \ + $(EMACS) -batch -q -l test-frames.el ) + +check-gud: rdebug-gud.el + (cd $(srcdir)/test && \ + $(EMACS) -batch -q -l test-gud.el ) + +check-indent: $(lisp_files) + (cd $(srcdir)/test && \ + $(EMACS) -batch -q -l test-indent.el ) + +check-regexp: rdebug-regexp.el + (cd $(srcdir)/test && \ + $(EMACS) -batch -q -l test-regexp.el ) + +check-shortkey: rdebug-shortkey.el + (cd $(srcdir)/test && \ + $(EMACS) -batch -q -l test-shortkey.el ) +endif + +PHONY = $(CHECK_FILES) + +test: check + diff --git a/emacs/.svn/text-base/rdebug-annotate.el.svn-base b/emacs/.svn/text-base/rdebug-annotate.el.svn-base new file mode 100644 index 0000000..eba89b0 --- /dev/null +++ b/emacs/.svn/text-base/rdebug-annotate.el.svn-base @@ -0,0 +1,385 @@ +;;; rdebug-annotate.el --- Ruby debugger output filtering - which +;;; includes annotation handling. + +;; Copyright (C) 2008 Rocky Bernstein (rocky@gnu.org) +;; Copyright (C) 2008 Anders Lindgren + +;; $Id$ + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; This file contains code dealing with filter of debugger output a large +;; part of which may contain annotations. + +;;; Code: + +(require 'gud) +(require 'gdb-ui) +(require 'rdebug-dbg) +(require 'rdebug-error) +(require 'rdebug-fns) +(require 'rdebug-info) +(require 'rdebug-layouts) +(require 'rdebug-locring) +(require 'rdebug-regexp) +(require 'rdebug-shortkey) +(require 'rdebug-source) +(require 'rdebug-vars) + +(defvar rdebug-non-annotated-text-kind nil + "Represent what non-annotated text is. + +This can be: + * nil -- plain shell output + * :output -- output from the command being debugged + * :info -- text for the \"info\" secondary window. + * :message -- message the text to the echo area. + * :cmd -- a command + result, which might go into the \"info\" window. + +See the function `rdebug-cmd-process' for details on :cmd.") + +(defvar rdebug-annotation-setup-map + (progn + (define-hash-table-test 'str-hash 'string= 'sxhash) + (let ((map (make-hash-table :test 'str-hash))) + (puthash "breakpoints" 'rdebug-setup-breakpoints-buffer map) + ;;(puthash "error" 'rdebug-setup-error-buffer map) + (puthash "frame" 'rdebug-setup-frame-buffer map) + (puthash "variables" 'rdebug-setup-variables-buffer map) + (puthash "watch" 'rdebug-setup-watch-buffer map) + (puthash "output" 'rdebug-setup-output-buffer map) + (puthash "info" 'rdebug-setup-info-buffer map) + (puthash "help" 'rdebug-setup-secondary-window-help-buffer map) + map))) + +(defun rdebug-temp-show (text) + "Arrange to show string as in sort of temporary way. Perhaps like a tooltip" + (tooltip-show text)) + +(defun rdebug-marker-filter-next-item (string) + "The next item for the rdebug marker filter to process. + +Return (item . rest) or nil." + (rdebug-debug-message "ACC: %S" string) + (cond + ;; Empty line, we're done. + ((equal (length string) 0) + nil) + ;; A single ^Z, this could become a new annotation, so lets stop here. + ((string= string "\032") + nil) + ;; A half-baked annotation, lets stop here. + ((and (string-match "^\032\032" string) + (not (string-match "\n" string))) + nil) + (t + (let ((split-point + (cond ((string-match "\032\032" string) + (let ((beg (match-beginning 0))) + (if (equal beg 0) + (if (string-match "^\032\032" string 2) + (match-beginning 0) + (length string)) + beg))) + ((eq (elt string (- (length string) 1)) ?\32) + -1) + (t + (length string))))) + (cons (substring string 0 split-point) (substring string split-point)))))) + +;; There's no guarantee that Emacs will hand the filter the entire +;; marker at once; it could be broken up across several strings. We +;; might even receive a big chunk with several markers in it. If we +;; receive a chunk of text which looks like it might contain the +;; beginning of a marker, we save it here between calls to the +;; filter. +(defun gud-rdebug-marker-filter (string) + "Filter function for process output of the rdebug Ruby debugger." + (rdebug-debug-enter "gud-rdebug-marker-filter:" + (rdebug-debug-message "GOT: %S" string) + (if rdebug-non-annotated-text-kind + (rdebug-debug-message " Text is %S" rdebug-non-annotated-text-kind)) + (setq gud-marker-acc (concat gud-marker-acc string)) + (rdebug-debug-message "TOT: %S" gud-marker-acc) + (let ((shell-output "") ; Output to debugger shell window. + (done nil) + item) + ;; The following loop peels of one "item" at a time. An item is + ;; a un-annotated section or an annotation. (This is taken care + ;; of by the `rdebug-marker-filter-next-item' function.) + ;; + ;; An Annotation can be a one-liner (where anything following + ;; the annotation is treated as un-annotated text) or a full + ;; annotation (which stretches to the next annotation). + ;; + ;; The concept of one-liners (no phun intended) is to allow + ;; continuous output, a "starting" annotation simply sets up the + ;; environment for sending lines to the output window, any text + ;; following it right now, or in later chunks of data, is + ;; redirected to the output window. + (while (and (not done) + (let ((pair (rdebug-marker-filter-next-item gud-marker-acc))) + (rdebug-debug-message "Next item: %S" pair) + (and pair + (progn + (setq item (car pair)) + (setq gud-marker-acc (cdr pair)) + t)))) + ;; Note: Regexp:s are greedy, i.e. the char parts wins over + ;; the .* part. + (if (not (string-match "^\032\032\\([-a-z]*\\).*\n" item)) + ;; Non-annotated text (or the content of one-liners) goes + ;; straight into the debugger shell window, or to the + ;; output window. + (cond ((and (eq rdebug-non-annotated-text-kind :output) + rdebug-use-separate-io-buffer) + (rdebug-process-annotation "starting" item)) + ((eq rdebug-non-annotated-text-kind :info) + (rdebug-process-annotation "info" item)) + (t + (if (eq rdebug-non-annotated-text-kind :cmd) + (rdebug-cmd-process item)) + (setq shell-output (concat shell-output item)))) + ;; Handle annotation. + (let* ((line-end (match-end 0)) + (name (match-string 1 item)) + ;; "prompt" is needed to handle "quit" in the shell correctly. + (one-liner + (member name + '("" "exited" "source" "prompt" "starting"))) + (next-annotation (string-match "\032\032" + gud-marker-acc))) + ;; For one-liners, shuffle some text back to the accumulator. + (when one-liner + (setq gud-marker-acc (concat (substring item line-end) + gud-marker-acc)) + (setq item (substring item 0 line-end))) + (if (or next-annotation + one-liner) + ;; ok, annotation complete, process it and remove it + (let* ((contents (substring item line-end)) + (old-kind rdebug-non-annotated-text-kind)) + (rdebug-debug-message "Name: %S Content: %S Kind: %S" + name contents + rdebug-non-annotated-text-kind) + + ;; This is a global state flag, this allows us to + ;; redirect any further text to the output buffer. + (set + (make-local-variable 'rdebug-non-annotated-text-kind) + (cond ((string= name "starting") + :output) + ((string= name "prompt") + (rdebug-cmd-clear) + :cmd) + ((string= name "exited") + ;; Create a fake command whose output we + ;; handle in the cmd system. (We might not + ;; receive all of the message at once, we we + ;; need some kind of accumukator, which the + ;; cmd system provides.) + (setq rdebug-inferior-status "exited") + (rdebug-cmd-clear) + (setq rdebug-call-queue + (cons '("***exited***" :message) + rdebug-call-queue)) + :cmd) + (t nil))) + + (when (and (eq old-kind :cmd) + (not (eq rdebug-non-annotated-text-kind :cmd))) + (rdebug-debug-message + "New kind: %S" rdebug-non-annotated-text-kind) + (rdebug-cmd-done)) + + ;; Process the annotation. + (cond ((string= name "starting") + (setq rdebug-inferior-status "running")) + ((string= name "stopped") + (setq rdebug-inferior-status "stopped")) + ((string= name "exited") + (setq rdebug-inferior-status "exited")) + ((string= name "pre-prompt") + ;; Strip of the trailing \n (this is probably + ;; a bug in processor.rb). + (if (string= (substring contents -1) "\n") + (setq contents (substring contents 0 -1))) + (if (string-match "post-mortem" contents) + (setq rdebug-inferior-status "crashed")) + (setq shell-output (concat shell-output contents))) + ((string= name "source") + (if (string-match gud-rdebug-marker-regexp item) + ;; Extract the frame position from the marker. + (setq gud-last-frame + (cons (match-string 1 item) + (string-to-number + (match-string 2 item)))))) + (t (rdebug-process-annotation name contents)))) + ;; This is not a one-liner, and we haven't seen the next + ;; annotation, so we have to treat this as a partial + ;; annotation. Save it and hope that the we can process + ;; it the next time we're called. + (setq gud-marker-acc (concat item gud-marker-acc)) + (setq done t))))) + + (when gud-last-frame + ;; Display the source file where we want it, gud will only pick + ;; an arbitrary window. + (rdebug-pick-source-window) + (rdebug-set-frame-arrow (gud-find-file (car gud-last-frame))) + (if (equal 0 rdebug-frames-current-frame-number) + (rdebug-locring-add gud-last-frame + rdebug-source-location-ring))) + (rdebug-short-key-mode-maybe-activate) + + (unless (string= shell-output "") + (rdebug-debug-message "Output: %S" shell-output)) + (rdebug-debug-message "REM: %S" gud-marker-acc) + + shell-output))) + +(defun rdebug-process-annotation (name contents) + "Called after `gud-rdebug-marker-filter' found a complete +`name' annotation with string `contents'. Send it to the right +place for processing." + (rdebug-debug-enter (format "rdebug-process-annotation %s" name) + ;; Ruby-debug uses the name "starting" for process output (just like + ;; GDB). However, it's better to present the buffer as "output" to + ;; the user. Ditto for "display" and "watch". + (cond ((string= name "starting") + (setq name "output")) + ((string= name "display") + (setq name "watch")) + ((string= name "stack") + (setq name "frame")) + ((string= name "error-begin") + (setq name "error"))) + ;; New "info" + (if (string= name "exited") + (setq name "info")) + (if (string= name "error") + (rdebug-errmsg contents)) + (let ((setup-func (gethash name rdebug-annotation-setup-map))) + (when setup-func + (let ((buf (rdebug-get-buffer name gud-target-name)) + ;; Buffer local, doesn't survive the buffer change. + (comint-buffer gud-comint-buffer)) + (with-current-buffer buf + (setq buffer-read-only t) + (let ((inhibit-read-only t)) + (set (make-local-variable 'rdebug-current-line-number) + (line-number-at-pos)) + (set (make-local-variable 'gud-last-frame) gud-last-frame) + (if rdebug-accumulative-buffer + (goto-char (point-max)) + (erase-buffer)) + (insert contents) + (funcall setup-func buf comint-buffer)))))) + (cond ((and (string= name "info") + (not (string= contents ""))) + (save-selected-window + (rdebug-display-info-buffer)))))) + + +;; ------------------------------------------------------------ +;; Mode line displayer. +;; + +;; The variable rdebug-mode-line-process uses this to generate the +;; actual string to display. +(defun rdebug-display-inferior-status () + "Return a (propertized) string, or nil, to be displayed in the mode line." + (if (and gud-comint-buffer + (buffer-name gud-comint-buffer) + (get-buffer-process gud-comint-buffer) + rdebug-inferior-status) + (let ((s rdebug-inferior-status)) + (cond ((string= rdebug-inferior-status "running") + (setq s (propertize s 'face font-lock-type-face))) + (t + (setq s (propertize s 'face font-lock-warning-face)))) + (concat ":" s)) + ;; No process, don't display anything. + nil)) + +;; ------------------------------------------------------------ +;; Command output parser. +;; + +(defvar rdebug-cmd-acc "" + "The accumulated output of the current command. + +Note, on some systems the external process echoes the command, +which is included in the output.") + +;; Called when a new command starts. +(defun rdebug-cmd-clear () + "Called when the Rdebug filter find the start of a new commands." + (rdebug-debug-enter "rdebug-cmd-clear" + (setq rdebug-cmd-acc ""))) + +;; Called with command output, this can be called any number of times. +(defun rdebug-cmd-process (s) + "Called when the Rdebug filter find the command output. +This may be called any number of times." + (rdebug-debug-enter (format "rdebug-cmd-process %S" s) + (setq rdebug-cmd-acc (concat rdebug-cmd-acc s)))) + +;; Called when command has finished. +(defun rdebug-cmd-done () + "Called when the Rdebug filter find the end of a commands." + (rdebug-debug-enter "rdebug-cmd-done" + ;; car-safe is used since rdebug-call-queue can be empty. + (let ((entry (car-safe rdebug-call-queue)) + (text rdebug-cmd-acc)) + (when entry + (rdebug-debug-message "Entry: %S Acc:%S" rdebug-call-queue rdebug-cmd-acc) + (setq rdebug-call-queue (cdr rdebug-call-queue)) + (let ((saved-cmd (car entry)) + (options (cdr entry))) + ;; In cast the external process echoed the actual command, + ;; remove it. + (when (and (>= (length text) + (length saved-cmd)) + (string= saved-cmd (substring text 0 (length saved-cmd)))) + (setq text (substring text (+ 1 (length saved-cmd))))) + (rdebug-debug-message "Text: %S" text) + ;; Optionally display the result. + (if (memq :tooltip options) + (rdebug-temp-show text)) + (if (memq :info options) + (rdebug-process-annotation "info" text)) + (when (memq :message options) + ;; Remove trailing newlines (chomp). + (while (and (> (length text) 0) + (eq (elt text (- (length text) 1)) ?\n)) + (setq text (substring text 0 -1))) + (message text))))))) + + +;; ------------------------------------------------------------------- +;; The end. +;; + +(provide 'rdebug-annotate) + +;;; Local variables: +;;; eval:(put 'rdebug-debug-enter 'lisp-indent-hook 1) +;;; End: + +;;; rdebug-annotate.el ends here diff --git a/emacs/.svn/text-base/rdebug-breaks.el.svn-base b/emacs/.svn/text-base/rdebug-breaks.el.svn-base new file mode 100644 index 0000000..8045aee --- /dev/null +++ b/emacs/.svn/text-base/rdebug-breaks.el.svn-base @@ -0,0 +1,407 @@ +;;; rdebug-breaks.el --- This file contains code dealing with the Ruby +;;; debugger's breakpoints and the breakpoint secondary buffer. + +;; Copyright (C) 2008 Rocky Bernstein (rocky@gnu.org) +;; Copyright (C) 2008 Anders Lindgren + +;; $Id$ + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; This file contains code dealing with the breakpoints and the +;; breakpoints secondary buffer. + +;;; Code: + +(require 'rdebug-dbg) +(require 'rdebug-gud) +(require 'rdebug-regexp) +(require 'rdebug-secondary) +(require 'rdebug-source) +(require 'rdebug-vars) + +(defun rdebug-display-breakpoints-buffer () + "Display the rdebug breakpoints buffer." + (interactive) + (rdebug-display-secondary-buffer "breakpoints")) + +(defvar rdebug-breakpoint-mode-map + (let ((map (make-sparse-keymap))) + (define-key map [double-mouse-1] 'rdebug-goto-breakpoint-mouse) + (define-key map [mouse-2] 'rdebug-goto-breakpoint-mouse) + (define-key map [mouse-3] 'rdebug-goto-breakpoint-mouse) + (define-key map "t" 'rdebug-toggle-breakpoint) + (define-key map "i" 'rdebug-add-breakpoint-condition) + (define-key map [insert] 'rdebug-add-breakpoint-condition) + (rdebug-populate-digit-keys map) + (define-key map [(control m)] 'rdebug-goto-breakpoint) + (define-key map [?d] 'rdebug-delete-breakpoint) + (rdebug-populate-secondary-buffer-map map) + + ;; -------------------- + ;; The "Breakpoints window" submenu. + (let ((submenu (make-sparse-keymap))) + (define-key-after map [menu-bar debugger breakpoints] + (cons "Breakpoints window" submenu) + 'placeholder)) + + (define-key map [menu-bar debugger breakpoints toggle] + '(menu-item "Toggle breakpoint" rdebug-toggle-breakpoint)) + + (define-key map [menu-bar debugger breakpoints goto] + '(menu-item "Goto breakpoint" rdebug-goto-breakpoint)) + + (define-key map [menu-bar debugger breakpoints delete] + '(menu-item "Delete breakpoint" rdebug-delete-breakpoint)) + + map) + "Keymap to navigate/set/enable rdebug breakpoints.") + +;; Here the "anchored match" method is used, see `font-lock-keywords' +;; for details. +(defvar rdebug-breakpoint-font-lock-keywords + '(("\\([0-9]+\\) +\\(\\(n\\)\\|\\(y\\)\\) +at " + (1 font-lock-constant-face) + (3 font-lock-type-face nil t) ; t = ok if not present + (4 font-lock-warning-face nil t) ; ditto. + ;; File name and line + ("\\(.*\\):\\([0-9]+\\)$" + nil ; Preform (not used) + nil ; Postfrom (not used) + (1 font-lock-warning-face) + (2 font-lock-constant-face)) + ;; Class:function + ("\\(.*\\):\\([a-zA-Z_].+\\)$" + nil ; Preform (not used) + nil ; Postfrom (not used) + (1 font-lock-type-face) + (2 font-lock-function-name-face)))) + "Rules for coloring the rdebug breakpoints buffer.") + +(defun rdebug-breakpoint-mode () + "Major mode for displaying breakpoints in the `rdebug' Ruby debugger. + +\\{rdebug-breakpoint-mode-map}" + (kill-all-local-variables) + (setq major-mode 'rdebug-breakpoint-mode) + (setq mode-name "RDEBUG Breakpoints") + (use-local-map rdebug-breakpoint-mode-map) + (setq buffer-read-only t) + (set (make-local-variable 'rdebug-secondary-buffer) t) + (setq mode-line-process 'rdebug-mode-line-process) + (set (make-local-variable 'font-lock-defaults) + '(rdebug-breakpoint-font-lock-keywords)) + (run-mode-hooks 'rdebug-breakpoint-mode-hook)) + + +(defun rdebug-setup-breakpoints-buffer (buf comint-buffer) + "Detect breakpoint lines and set up keymap and mouse navigation. +Argument BUF is the buffer to set up. +Argument COMINT-BUFFER is the assocaited gud process buffer." + (rdebug-debug-enter "rdebug-setup-breakpoints-buffer" + (with-current-buffer buf + (let ((inhibit-read-only t) + (old-line-number (buffer-local-value 'rdebug-current-line-number + buf))) + (rdebug-breakpoint-mode) + (goto-char (point-min)) + (while (not (eobp)) + (let ((b (line-beginning-position)) (e (line-end-position))) + (when (string-match rdebug-breakpoint-regexp + (buffer-substring b e)) + (add-text-properties b e + (list 'mouse-face 'highlight + 'keymap rdebug-breakpoint-mode-map))) + (forward-line))) + (goto-line old-line-number))) + (rdebug-breakpoint-parse-and-update-cache) + (rdebug-breakpoint-update-icons (rdebug-breakpoint-all)))) + + +(defvar rdebug-breakpoint-cache '() + "The cached return value of `rdebug-breakpoint-all'. + +Buffer-local to the debugger shell window.") + + +;; Implementation note: If Emacs could talk directly to the Ruby +;; debugger, this would be roughly "Debugger.breakpoints". Since we +;; currently can't do that we parse the content of the breakpoints +;; window. +;; +;; Note: The :function kind is not yet implemented. +(defun rdebug-breakpoint-parse-and-update-cache () + "Build up the return value of `rdebug-breakpoint-all'." + (save-excursion + (goto-char (point-min)) + (let ((res '())) + (while (not (eobp)) + (when (looking-at rdebug-breakpoint-regexp) + (push (list :file + ;; Break point number + (string-to-number (match-string 1)) + ;; Enabled + (string= (match-string 2) "y") + ;; File name + (file-truename + (match-string-no-properties 3)) + ;; Line number + (string-to-number (match-string 4))) + res)) + (forward-line 1)) + ;; The result goes into a buffer-local variable in the debugger + ;; shell. (This ensures that this would work in a multi-session + ;; environment.) + (if gud-comint-buffer + (with-current-buffer gud-comint-buffer + (set (make-local-variable 'rdebug-breakpoint-cache) + (nreverse res))))))) + + +(defun rdebug-breakpoint-all () + "Return a list of all breakpoints. + +Each entry in the list is on the form: + + (:file number enabled file line) + +or + + (:function number enabled class function)" + (and gud-comint-buffer + (buffer-local-value 'rdebug-breakpoint-cache gud-comint-buffer))) + + +(defun rdebug-file-and-line-arg () + "Return the current file and line number as a list." + (save-excursion + (beginning-of-line) + (list (buffer-file-name) (+ 1 (count-lines (point-min) (point)))))) + +(defun rdebug-breakpoint-on-line (file line) + "Return a list of the breakpoints on the file FILE and current source LINE." + (let ((res '())) + (dolist (entry (rdebug-breakpoint-all)) + (if (and (eq (nth 0 entry) :file) + (string= (nth 3 entry) file) + (equal (nth 4 entry) line)) + (push entry res))) + res)) + + +(defun rdebug-toggle-source-breakpoint (file line) + "Toggle break point in FILE on current source LINE." + (interactive (rdebug-file-and-line-arg)) + (cond ((eq major-mode 'rdebug-breakpoint-mode) + (rdebug-delete-breakpoint)) + ((null file) + ;; Do nothing. + ) + (t + (let ((bps (rdebug-breakpoint-on-line file line))) + (if bps + (gud-call (format "delete %s" (nth 1 (car bps)))) + (gud-call (format "break %s:%d" file line))))))) + + +(defun rdebug-toggle-source-breakpoint-enabled (file line) + "Enable or disable a breakpoint in FILE on the current source LINE." + (interactive (rdebug-file-and-line-arg)) + (cond ((eq major-mode 'rdebug-breakpoint-mode) + (rdebug-toggle-breakpoint)) + ((null file) + ;; Do nothing. + ) + (t + (let ((bps (rdebug-breakpoint-on-line file line))) + (if bps + ;; Note: If the line contains more than one simply use the + ;; first one. + (let ((entry (car bps))) + (if (nth 2 entry) + (gud-call (format "disable %s" (nth 1 entry))) + (gud-call (format "enable %s" (nth 1 entry))))) + (gud-call (format "break %s:%d" file line))))))) + + +;; --------------------------------------------------------- +;; Commands of the rdebug breakpoints buffer. +;; + +(defun rdebug-delete-breakpoint (&optional pt) + "Deletes the breakpoint at PT in the breakpoints buffer." + (interactive "d") + (save-excursion + (if pt + (goto-char pt)) + (let ((s (buffer-substring (line-beginning-position) (line-end-position)))) + (when (string-match rdebug-breakpoint-regexp s) + (let ((bpnum (substring s (match-beginning 1) (match-end 1)))) + (gud-call (format "delete %s" bpnum))))))) + +(defun rdebug-goto-breakpoint (pt) + "Displays the location in a source file of the selected breakpoint. +Argument PT indicates the file and line where the breakpoint should be set." + (interactive "d") + (save-excursion + (goto-char pt) + (let ((s (buffer-substring (line-beginning-position) (line-end-position)))) + (when (string-match rdebug-breakpoint-regexp s) + (rdebug-display-line + (substring s (match-beginning 3) (match-end 3)) + (string-to-number (substring s (match-beginning 4) (match-end 4)))) + )))) + + +(defun rdebug-goto-breakpoint-mouse (event) + "Displays the location in a source file of the selected breakpoint." + (interactive "e") + (with-current-buffer (window-buffer (posn-window (event-end event))) + (rdebug-goto-breakpoint (posn-point (event-end event))))) + + +(defun rdebug-get-breakpoint-number (pt) + "Return the current breakpoint number in the breakpoint secondary window or nil if none found." + (interactive "d") + (save-excursion + (goto-char pt) + (let ((s (buffer-substring (line-beginning-position) (line-end-position)))) + (if (string-match rdebug-breakpoint-regexp s) + (substring s (match-beginning 1) (match-end 1)) + nil)))) + +(defun rdebug-toggle-breakpoint (&optional pt) + "Toggle the breakpoint at PT in the breakpoints buffer." + (interactive "d") + (save-excursion + (if pt + (goto-char pt)) + (let ((s (buffer-substring (line-beginning-position) (line-end-position)))) + (when (string-match rdebug-breakpoint-regexp s) + (let* ((enabled + (string= (substring s (match-beginning 2) (match-end 2)) "y")) + (cmd (if enabled "disable" "enable")) + (bpnum (substring s (match-beginning 1) (match-end 1)))) + (gud-call (format "%s breakpoint %s" cmd bpnum))))))) + +(defun rdebug-add-breakpoint-condition (pt) + "Add an expression as a condition to the break `rdebug' Ruby debugger." + (interactive "d") + (let ((bpnum (rdebug-get-breakpoint-number pt)) + (expr (read-string "Ruby expression for breakpoint condition: "))) + (if bpnum + (gud-call (format "condition %s %s" bpnum expr)) + (message "Breakpoint number not found")))) + + +;; ----------------------------------------------- +;; Breakpoint icon support. +;; + +;; This is a trivial implementation, it has the following shortcomings: +;; +;; * It assumes that the buffer content doesn't change, if it does it +;; will not be able to remove the icon. +;; +;; * No support for displaying an icon in a newly opened file. +;; +;; * It has no support for more than one session. + +;; Note: This is implemented on top of `gdb-ui'. In the future, it +;; would be better if that code is generalized. + +(require 'gdb-ui) + +;; This is a local variable, should not be placed in rdebug-vars.el. +(defvar rdebug-breakpoint-icons-current-state nil) + +(defun rdebug-breakpoint-remove-icon (entry) + "Remove the the source buffer the fringe breakpoint icon breakpoint ENTRY." + (if (eq (nth 0 entry) :file) + (let ((buf (find-buffer-visiting (nth 3 entry)))) + (if buf + (save-current-buffer + (set-buffer buf) + (save-excursion + (goto-line (nth 4 entry)) + (gdb-remove-breakpoint-icons (point) (point)))))))) + +(defun rdebug-breakpoint-remove-all-icons () + "Remove all breakpoint fringe icons." + (interactive) + (dolist (entry rdebug-breakpoint-icons-current-state) + (rdebug-breakpoint-remove-icon entry)) + (setq rdebug-breakpoint-icons-current-state nil)) + + +(defun rdebug-breakpoint-add-icon (entry) + (if (eq (nth 0 entry) :file) + (let ((buf (find-buffer-visiting (nth 3 entry)))) + (if buf + (save-current-buffer + (set-buffer buf) + (save-excursion + (goto-line (nth 4 entry)) + ;; Workaround for bug in `gdb-ui'. (It checks + ;; `left-fringe-width' but it doesn't interpret the + ;; `nil' value correctly. + (let ((gdb-buffer-fringe-width (car (window-fringes)))) + (gdb-put-breakpoint-icon (nth 2 entry) + (number-to-string (nth 1 entry)))))))))) + +(defun rdebug-breakpoint-list-member (file line list) + (let ((res nil)) + (dolist (entry list) + (if (and (equal file (nth 3 entry)) + (equal line (nth 4 entry))) + (setq res t))) + res)) + +;; bpts has the same representation as returned by `rdebug-breakpoint-all'. +(defun rdebug-breakpoint-update-icons (bpts) + ;; Make sure there are is only one reference for each line. + (let ((state '())) + ;; An enabled breakpoint take precedence. + (dolist (enabled '(t nil)) + (dolist (bpt bpts) + (if (and (eq (nth 0 bpt) :file) + (eq (nth 2 bpt) enabled) + (not (rdebug-breakpoint-list-member + (nth 3 bpt) (nth 4 bpt) state))) + (setq state (cons bpt state))))) + (dolist (entry rdebug-breakpoint-icons-current-state) + (unless (member entry state) + (rdebug-breakpoint-remove-icon entry))) + (dolist (entry state) + (unless (member entry rdebug-breakpoint-icons-current-state) + (rdebug-breakpoint-add-icon entry))) + (setq rdebug-breakpoint-icons-current-state state))) + +;; ------------------------------------------------------------------- +;; The end. +;; + +(provide 'rdebug-breaks) + +;;; Local variables: +;;; eval:(put 'rdebug-debug-enter 'lisp-indent-hook 1) +;;; End: + +(provide 'rdebug-breaks) + +;;; rdebug-breaks.el ends here diff --git a/emacs/.svn/text-base/rdebug-cmd.el.svn-base b/emacs/.svn/text-base/rdebug-cmd.el.svn-base new file mode 100644 index 0000000..7a6dfc3 --- /dev/null +++ b/emacs/.svn/text-base/rdebug-cmd.el.svn-base @@ -0,0 +1,92 @@ +;;; rdebug-cmd.el --- Ruby debugger command buffer + +;; Copyright (C) 2008 Rocky Bernstein (rocky@gnu.org) +;; Copyright (C) 2008 Anders Lindgren + +;; $Id$ + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; See the manual and the file `rdebug.el' for more information. + +;; This file contains code dealing primarily with the command buffer. + +;;; Code: + +(require 'ring) +(require 'rdebug-locring) + +(defun rdebug-command-initialization () + "Initialization of command buffer common to `rdebug' and`rdebug-track-attach'." + + ;; This opens up "Gud" menu, which isn't used since we've got our + ;; own "Debugger" menu. + ;; (set (make-local-variable 'gud-minor-mode) 'rdebug) + + (set (make-local-variable 'rdebug-call-queue) '()) + (set (make-local-variable 'rdebug-original-read-only) buffer-read-only) + (make-local-variable 'rdebug-source-location-ring-size) ; ...to global val. + (set (make-local-variable 'rdebug-source-location-ring) + (make-ring rdebug-source-location-ring-size)) + (make-local-variable 'rdebug-source-location-ring-index) + (rdebug-locring-clear) + + (gud-def gud-args "info args" "a" + "Show arguments of current stack frame.") + (gud-def gud-break "break %d%f:%l""\C-b" + "Set breakpoint at current line.") + (gud-def gud-cont "continue" "\C-r" + "Continue with display.") + (gud-def gud-down "down %p" "<" + "Down N stack frames (numeric arg).") + (gud-def gud-finish "finish" "\C-f" + "Finish executing current function.") + (gud-def gud-source-resync "up 0" "\C-l" + "Show current source window") + (gud-def gud-remove "clear %d%f:%l" "\C-d" + "Remove breakpoint at current line") + (gud-def gud-quit "quit" "Q" + "Quit debugger.") + + (gud-def gud-statement "eval %e" "\C-e" + "Execute Ruby statement at point.") + (gud-def gud-tbreak "tbreak %d%f:%l" "\C-t" + "Set temporary breakpoint at current line.") + (gud-def gud-up "up %p" + ">" "Up N stack frames to a newer frame (numeric arg).") + (gud-def gud-where "where" + "T" "Show stack trace.") + + (local-set-key [M-insert] 'rdebug-internal-short-key-mode) + (local-set-key [M-down] 'rdebug-locring-newer) + (local-set-key [M-up] 'rdebug-locring-older) + (local-set-key [M-S-down] 'rdebug-locring-newest) + (local-set-key [M-S-up] 'rdebug-locring-oldest) + ;; (local-set-key "\C-i" 'gud-gdb-complete-command) + (local-set-key "\C-c\C-n" 'comint-next-prompt) + (local-set-key "\C-c\C-p" 'comint-previous-prompt)) + +;; stopping location motion routines. + +(provide 'rdebug-cmd) + +;;; Local variables: +;;; eval:(put 'rdebug-debug-enter 'lisp-indent-hook 1) +;;; End: + +;;; rdebug-cmd.el ends here diff --git a/emacs/.svn/text-base/rdebug-core.el.svn-base b/emacs/.svn/text-base/rdebug-core.el.svn-base new file mode 100644 index 0000000..b31086a --- /dev/null +++ b/emacs/.svn/text-base/rdebug-core.el.svn-base @@ -0,0 +1,502 @@ +;;; rdebug-core.el --- Core parts of the Ruby debugger user +;;; interface. It pulls in other parts of the debugger. + +;; Copyright (C) 2006, 2007, 2008 Rocky Bernstein (rocky@gnu.org) +;; Copyright (C) 2007, 2008 Anders Lindgren + +;; $Id$ + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; See the manual and the file `rdebug.el' for more information. + +;; This file implements the core of the debugger. + +;;; Code: + +;; ------------------------------------------------------------------- +;; Consistency checks. +;; + +(if (< emacs-major-version 22) + (error + "This version of rdebug.el needs at least Emacs 22 or greater - you have version %d" + emacs-major-version)) + + +;; ------------------------------------------------------------------- +;; Dependencies. +;; + +(require 'gud) +(require 'cl) + +(require 'rdebug) +(require 'rdebug-annotate) +(require 'rdebug-dbg) +(require 'rdebug-cmd) +(require 'rdebug-layouts) +(require 'rdebug-source) +(require 'rdebug-regexp) +(require 'rdebug-vars) + +(defun rdebug-get-script-name (args) + "Parse command line ARGS. + +A list containing the script name, and whether the annotate +option was set is returned. + +Initially annotate should be set to nil. Argument ARGS contains +a tokenized list of the command line." + ;; Parse the following: + ;; + ;; [ruby ruby-options] rdebug rdebug-options script-name script-options + (and args + (let ((name nil) + (annotate-p nil)) + ;; Strip of optional "ruby" or "ruby182" etc. + (when (string-match "^ruby[0-9]*$" + (file-name-sans-extension + (file-name-nondirectory (car args)))) + (pop args) + (while (and args + (string-match "^-" (car args))) + (if (member (car args) '("-e" "-r" "-I" "-C" "-F" "-K")) + (pop args)) + (pop args))) + ;; Remove "rdebug" from "rdebug --rdebug-options script + ;; --script-options" + (pop args) + ;; Skip to the first non-option argument. + (while (and args + (not name)) + (let ((arg (pop args))) + (cond + ;; Annotation or emacs option with level number. + ((or (member arg '("--annotate" "-A")) + (equal arg "--emacs")) + (setq annotate-p t) + (pop args)) + ;; Combined annotation and level option. + ((string-match "^--annotate=[0-9]" arg) + (setq annotate-p t)) + ;; Options with arguments. + ((member arg '("-h" "--host" "-p" "--port" + "-I" "--include" "-r" "--require")) + (pop args)) + ((string-match "^-" arg) + nil) + (t + (setq name arg))))) + (and name + (list name annotate-p))))) + +;; ------------------------------------------------------------------- +;; Window configuration state support. +;; + +(defun rdebug-set-window-configuration-state (state &optional dont-restore) + "Change window configuration state. + +Two states are supported, `original' and `debugger'. + +When `dont-restore' is non-nil, the old window layout is not +restored. This is used when a new layout is being drawn, for +example when the debugger starts." + (rdebug-debug-message "Setting state to %s (was %s)" + state rdebug-window-configuration-state) + (when (not (eq state rdebug-window-configuration-state)) + ;; Save the previous state. + (cond ((not (eq rdebug-window-configuration-state 'original)) + (setq rdebug-debugger-window-configuration + (current-window-configuration))) + ((eq rdebug-window-configuration-state 'original) + (setq rdebug-original-window-configuration + (current-window-configuration)))) + (unless dont-restore + ;; Switch to the saved state, + (cond + ((not (eq state 'original)) + (if rdebug-debugger-window-configuration + (set-window-configuration rdebug-debugger-window-configuration))) + ((eq state 'original) + (if rdebug-original-window-configuration + (set-window-configuration rdebug-original-window-configuration))))) + (setq rdebug-window-configuration-state state))) + + +;; have to bind rdebug-file-queue before installing the kill-emacs-hook +(defvar rdebug-file-queue nil + "Queue of Makefile temp files awaiting execution. +Currently-active file is at the head of the list.") + +(defun rdebug-goto-traceback-line (pt) + "Display the location PT in a source file of the Ruby traceback line." + (interactive "d") + (save-excursion + (goto-char pt) + (let ((s (buffer-substring (line-beginning-position) (line-end-position))) + (gud-comint-buffer (current-buffer))) + (when (string-match rdebug-traceback-line-re s) + (rdebug-display-line + (substring s (match-beginning 1) (match-end 1)) + (string-to-number (substring s (match-beginning 2) (match-end 2)))) + )))) + +(defun rdebug-goto-dollarbang-traceback-line (pt) + "Display the location PT in a source file of the Ruby $! traceback line." + (interactive "d") + (save-excursion + (goto-char pt) + (let ((s (buffer-substring (line-beginning-position) (line-end-position))) + (gud-comint-buffer (current-buffer))) + (when (string-match rdebug-dollarbang-traceback-line-re s) + (rdebug-display-line + (substring s (match-beginning 1) (match-end 1)) + (string-to-number (substring s (match-beginning 2) (match-end 2)))) + )))) + +;; ------------------------------------------------------------------- +;; Secondary buffers. +;; + +(require 'rdebug-secondary) +(require 'rdebug-breaks) +(require 'rdebug-frames) +(require 'rdebug-help) +(require 'rdebug-output) +(require 'rdebug-varbuf) +(require 'rdebug-watch) + + +;; ------------------------------------------------------------------- +;; Windows. +;; + +(defun rdebug-setup-windows (&optional erase) + "Create the debugger user interface window layout. + +If ERASE is non-nil, the content of the windows are erased +\(this does not apply to accumulative windows). + +This function displays the source file (or, in some cases, a +buffer list) and creates the window layout. The variable +`rdebug-window-layout-function' controls the function that is +used to perform the actual layout. + +This is only used when `rdebug-many-windows' is non-nil." + (rdebug-debug-enter "rdebug-setup-windows" + (rdebug-set-window-configuration-state 'debugger t) + (pop-to-buffer gud-comint-buffer) + (maphash + (lambda (name func) + (if erase + (let ((buf (rdebug-get-existing-buffer name gud-target-name))) + (if buf + (with-current-buffer buf + (let ((inhibit-read-only t)) + (erase-buffer)))))) + (rdebug-process-annotation name "")) + rdebug-annotation-setup-map) + (let ((buf + (cond (gud-last-last-frame + (gud-find-file (car gud-last-last-frame))) + (gud-target-name + (gud-find-file gud-target-name))))) + ;; Put a buffer in window if we can't find a source file. + (unless buf (setq buf (get-buffer-create "*scratch*"))) + (funcall rdebug-window-layout-function buf gud-target-name)))) + + +(defun rdebug-setup-windows-initially () + "Like `rdebug-setup-windows', but erase the content of accumulative windows. +This is called when the debugger starts." + (rdebug-setup-windows t)) + + +(defun rdebug-restore-debugger-window-layout () + "Restore the initial ruby debugger window layout." + (interactive) + (when rdebug-many-windows + (rdebug-setup-windows))) + +(defun rdebug-display-debugger-window-configuration () + "Switch from the \"original\" to the \"debugger\" window layout. + +The rdebug debugger remembers, and can switch between, two window layouts: + * original -- the window layout when the debugger was started. + * debugger -- the window layout of the debugger, plus all changes made + since the debugger started. + +The check-marks in the \"Window Layout\" menu indicates the +active window layout. + +The function `rdebug-display-original-window-configuration' +switch to the \"original\" window configuration. + +The function `rdebug-restore-debugger-window-layout' restores the +window layout to the state it was when the debugger started." + (interactive) + (rdebug-set-window-configuration-state 'debugger) + (message + "Type `M-x rdebug-display-original-window-configuration RET' to restore.")) + + +;;This function is called upon quitting the debugger and +;;`rdebug-many-windows' is not nil. See also +;;`rdebug-display-debugger-window-configuration'." + +(defun rdebug-display-original-window-configuration () + "Switch from the \"debugger\" to the \"original\" window layout. + +The rdebug debugger remembers, and can switch between, two window layouts: + * original -- the window layout when the debugger was started. + * debugger -- the window layout of the debugger, plus all changes made + since the debugger started. + +The check-marks in the \"Window Layout\" menu indicates the +active window layout. + +The function `rdebug-display-debugger-window-configuration' +switch to the \"debugger\" window configuration." + (interactive) + (rdebug-set-window-configuration-state 'original) + (message + "Type `M-x rdebug-display-debugger-window-configuration RET' to restore.")) + + +;; ------------------------------------------------------------------- +;; The `rdebug' command and support functions. +;; + +(defun rdebug-process-sentinel (process event) + "Restore the original window configuration when the debugger process exits." + (rdebug-debug-enter "rdebug-process-sentinel" + (rdebug-debug-message "status=%S event=%S state=%S" + (process-status process) + event + rdebug-window-configuration-state) + (gud-sentinel process event) + ;; This will "flush" the last annotation. Especially "output" + ;; (a.k.a. "starting") annotations don't have an end markers, if + ;; the last command printed something. + (if (string= event "finished\n") + (gud-rdebug-marker-filter "\032\032\n")) + ;; When the debugger process exited, when the comint buffer has no + ;; buffer process (nil). When the debugger processes is replaced + ;; with another process we should not restore the window + ;; configuration. + (when (and (or (eq rdebug-restore-original-window-configuration t) + (and (eq rdebug-restore-original-window-configuration :many) + rdebug-many-windows)) + (or (rdebug-dead-process-p) + (eq process (get-buffer-process gud-comint-buffer))) + (eq rdebug-window-configuration-state 'debugger) + (not (eq (process-status process) 'run))) + (rdebug-internal-short-key-mode-off) + (rdebug-set-window-configuration-state 'original) + (rdebug-reset-keymaps)))) + + +;; Perform initializations common to all debuggers. +;; The first arg is the specified command line, +;; which starts with the program to debug. +;; The other three args specify the values to use +;; for local variables in the debugger buffer. +(defun rdebug-common-init (rdebug-buffer-name rdebug-cmd-buffer target-name + program args + marker-filter + &optional find-file) + "Perform initializations common to all debuggers. + +RDEBUG-BUFFER-NAME is the specified command line, which starts +with the program to debug. PROGRAM, ARGS and MARKER-FILTER +specify the values to use for local variables in the debugger +buffer." + (if rdebug-cmd-buffer + (progn + (pop-to-buffer rdebug-cmd-buffer) + (when (and rdebug-cmd-buffer (get-buffer-process rdebug-cmd-buffer)) + (error "This program is already being debugged")) + (apply 'make-comint rdebug-buffer-name program nil args) + (or (bolp) (newline))) + (pop-to-buffer (setq rdebug-cmd-buffer + (apply 'make-comint rdebug-buffer-name program nil + args)))) + + ;; Since comint clobbered the mode, we don't set it until now. + (gud-mode) + (set (make-local-variable 'gud-target-name) target-name) + (set (make-local-variable 'gud-marker-filter) marker-filter) + (set (make-local-variable 'gud-minor-mode) 'rdebug) + (set (make-local-variable 'gud-last-frame) nil) + (set (make-local-variable 'gud-last-last-frame) nil) + + (let ((buffer-process (get-buffer-process (current-buffer)))) + (if buffer-process + (progn + (set-process-filter buffer-process 'gud-filter) + (set-process-sentinel buffer-process 'gud-sentinel)))) + (gud-set-buffer)) + +;;;###autoload +(defun rdebug (command-line) + "Invoke the rdebug Ruby debugger and start the Emacs user interface. + +String COMMAND-LINE specifies how to run rdebug. + +By default, the \"standard\" user window layout looks like the following: + ++----------------------------------------------------------------------+ +| Toolbar | ++-----------------------------------+----------------------------------+ +| Debugger shell | Variables buffer | ++-----------------------------------+----------------------------------+ +| | | +| Source buffer | Output buffer | +| | | ++-----------------------------------+----------------------------------+ +| Stack Frame buffer | Breakpoints buffer | ++-----------------------------------+----------------------------------+ + +The variable `rdebug-window-layout-function' can be +customized so that another layout is used. In addition to a +number of predefined layouts it's possible to define a function +to perform a custom layout. + +If `rdebug-many-windows' is nil, only a traditional debugger +shell and source window is opened. + +The directory containing the debugged script becomes the initial +working directory and source-file directory for your debugger. + +The custom variable `gud-rdebug-command-name' sets the command +and options used to invoke rdebug." + (interactive + (let ((init (buffer-file-name))) + (setq init (and init + (file-name-nondirectory init))) + (list (gud-query-cmdline 'rdebug init)))) + (rdebug-debug-enter "rdebug" + (rdebug-set-window-configuration-state 'debugger t) + ;; Parse the command line and pick out the script name and whether + ;; --annotate has been set. + (let* ((words (with-no-warnings + (split-string-and-unquote command-line))) + (script-name-annotate-p (rdebug-get-script-name + (gud-rdebug-massage-args "1" words))) + (target-name (file-name-nondirectory (car script-name-annotate-p))) + (annotate-p (cadr script-name-annotate-p)) + (cmd-buffer-name (format "rdebug-cmd-%s" target-name)) + (rdebug-cmd-buffer-name (format "*%s*" cmd-buffer-name)) + (rdebug-cmd-buffer (get-buffer rdebug-cmd-buffer-name)) + (program (car words)) + (args (cdr words)) + (gud-chdir-before-run nil)) + + ;; `gud-rdebug-massage-args' needs whole `command-line'. + ;; command-line is refered through dynamic scope. + (rdebug-common-init cmd-buffer-name rdebug-cmd-buffer target-name + program args + 'gud-rdebug-marker-filter + 'gud-rdebug-find-file) + (setq comint-process-echoes t) + + (setq rdebug-inferior-status "running") + + (rdebug-command-initialization) + + ;; Setup exit callback so that the original frame configuration + ;; can be restored. + (let ((process (get-buffer-process gud-comint-buffer))) + (when process + (unless (equal rdebug-line-width 120) + (gud-call (format "set width %d" rdebug-line-width))) + (set-process-sentinel process + 'rdebug-process-sentinel))) + + + ;; Add the buffer-displaying commands to the Gud buffer, + ;; FIXME: combine with code in rdebug-track.el; make common + ;; command buffer mode map. + (let ((prefix-map (make-sparse-keymap))) + (define-key (current-local-map) gud-key-prefix prefix-map) + (define-key prefix-map "t" 'rdebug-goto-traceback-line) + (define-key prefix-map "!" 'rdebug-goto-dollarbang-traceback-line) + (rdebug-populate-secondary-buffer-map-plain prefix-map)) + + (rdebug-populate-common-keys (current-local-map)) + (rdebug-populate-debugger-menu (current-local-map)) + + (setq comint-prompt-regexp (concat "^" rdebug-input-prompt-regexp)) + (setq paragraph-start comint-prompt-regexp) + + (setcdr (assq 'rdebug-debugger-support-minor-mode minor-mode-map-alist) + rdebug-debugger-support-minor-mode-map-when-active) + (when rdebug-many-windows + (rdebug-setup-windows-initially)) + + (run-hooks 'rdebug-mode-hook)))) + + +(defadvice gud-reset (before rdebug-reset) + "Rdebug cleanup - remove debugger's internal buffers (frame, breakpoints, etc.)." + (rdebug-breakpoint-remove-all-icons) + (dolist (buffer (buffer-list)) + (when (string-match "\\*rdebug-[a-z]+\\*" (buffer-name buffer)) + (let ((w (get-buffer-window buffer))) + (when w + (delete-window w))) + (kill-buffer buffer)))) +(ad-activate 'gud-reset) + +(defun rdebug-reset () + "Rdebug cleanup - remove debugger's internal buffers (frame, breakpoints, etc.)." + (interactive) + (rdebug-breakpoint-remove-all-icons) + (dolist (buffer (buffer-list)) + (when (string-match "\\*rdebug-[a-z]+\\*" (buffer-name buffer)) + (let ((w (get-buffer-window buffer))) + (when w + (delete-window w))) + (kill-buffer buffer)))) + +(defun rdebug-reset-keymaps() + "This unbinds the special debugger keys of the source buffers." + (interactive) + (setcdr (assq 'rdebug-debugger-support-minor-mode minor-mode-map-alist) + rdebug-debugger-support-minor-mode-map-when-deactive)) + + +(defun rdebug-customize () + "Use `customize' to edit the settings of the `rdebug' debugger." + (interactive) + (customize-group 'rdebug)) + + +;; ------------------------------------------------------------------- +;; The end. +;; + +(provide 'rdebug-core) + +;;; Local variables: +;;; eval:(put 'rdebug-debug-enter 'lisp-indent-hook 1) +;;; End: + +;;; rdebug-core.el ends here diff --git a/emacs/.svn/text-base/rdebug-dbg.el.svn-base b/emacs/.svn/text-base/rdebug-dbg.el.svn-base new file mode 100644 index 0000000..1113b1e --- /dev/null +++ b/emacs/.svn/text-base/rdebug-dbg.el.svn-base @@ -0,0 +1,62 @@ +;;; rdebug-dbg.el --- Ruby debugger frames buffer + +;; Copyright (C) 2008 Rocky Bernstein (rocky@gnu.org) +;; Copyright (C) 2008 Anders Lindgren + +;; $Id$ + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; See the manual and the file `rdebug.el' for more information. + +;; This file contains internal debug trace support. + +;;; Code: + +(require 'rdebug-vars) + +(defun rdebug-debug-message (&rest args) + (if rdebug-debug-active + (let ((buf (get-buffer-create "*Xrdebug*"))) + (with-current-buffer buf + (save-excursion + (goto-char (point-max)) + ;; 32 = space. + (insert (make-string (* 4 rdebug-debug-depth) 32)) + (insert (apply #'format args)) + (insert "\n")))))) + + +(defmacro rdebug-debug-enter (str &rest body) + (declare (indent 1) (debug t)) + `(progn + (rdebug-debug-message "--> %s" ,str) + (setq rdebug-debug-depth (+ rdebug-debug-depth 1)) + (unwind-protect + (progn + ,@body) + (setq rdebug-debug-depth (max 0 (- rdebug-debug-depth 1))) + (rdebug-debug-message "<-- %s" ,str)))) + +(provide 'rdebug-dbg) + +;;; Local variables: +;;; eval:(put 'rdebug-debug-enter 'lisp-indent-hook 1) +;;; End: + +;;; rdebug-dbg.el ends here diff --git a/emacs/.svn/text-base/rdebug-error.el.svn-base b/emacs/.svn/text-base/rdebug-error.el.svn-base new file mode 100644 index 0000000..74b2ef2 --- /dev/null +++ b/emacs/.svn/text-base/rdebug-error.el.svn-base @@ -0,0 +1,79 @@ +;;; rdebug-error.el --- Ruby debugger error buffer + +;; Copyright (C) 2008 Rocky Bernstein (rocky@gnu.org) +;; Copyright (C) 2008 Anders Lindgren + +;; $Id$ + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; See the manual and the file `rdebug.el' for more information. + +;; This file contains code dealing with the error secondary buffer. + +;;; Code: + +(require 'rdebug-dbg) +(require 'rdebug-fns) +(require 'rdebug-secondary) +(require 'rdebug-source) + +(defun rdebug-display-error-buffer () + "Display the rdebug error buffer." + (interactive) + (rdebug-display-secondary-buffer "error")) + +(defvar rdebug-error-mode-map + (let ((map (make-sparse-keymap))) + (rdebug-populate-secondary-buffer-map map) + map) + "Keymap used in the error buffer in the `rdebug' Ruby debugger.") + +(defun rdebug-error-mode () + "Major mode for displaying the script error in the `rdebug' Ruby debugger. + +\\{rdebug-error-mode}" + (interactive) + (kill-all-local-variables) + (setq major-mode 'rdebug-error-mode) + (setq mode-name "RDEBUG Error") + (setq buffer-read-only t) + (set (make-local-variable 'rdebug-secondary-buffer) t) + (setq mode-line-process 'rdebug-mode-line-process) + (use-local-map rdebug-error-mode-map) + (run-mode-hooks 'rdebug-error-mode-hook)) + +(defun rebug-setup-error-buffer (buf comint-buffer) + (rdebug-debug-enter "rebug-setup-error-buffer" + (with-current-buffer buf + (rdebug-error-mode) + (set (make-local-variable 'gud-comint-buffer) comint-buffer)))) + +(defun rdebug-errmsg (msg) +;;; (with-current-buffer (rdebug-get-buffer "error" gud-target-name) +;;; (goto-char (point-max)) +;;; (insert msg)) + (message (chomp msg))) + +(provide 'rdebug-error) + +;;; Local variables: +;;; eval:(put 'rdebug-debug-enter 'lisp-indent-hook 1) +;;; End: + +;;; rdebug-error.el ends here diff --git a/emacs/.svn/text-base/rdebug-fns.el.svn-base b/emacs/.svn/text-base/rdebug-fns.el.svn-base new file mode 100644 index 0000000..ef0c0f1 --- /dev/null +++ b/emacs/.svn/text-base/rdebug-fns.el.svn-base @@ -0,0 +1,111 @@ +;;; rdebug-fns.el --- Ruby debugger miscellaneous functions + +;; Copyright (C) 2008 Rocky Bernstein (rocky@gnu.org) +;; Copyright (C) 2008 Anders Lindgren + +;; $Id: rdebug-frames.el 711 2008-02-20 07:09:17Z andersl $ + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; See the manual and the file `rdebug.el' for more information. + +;; This file contains code dealing with the frames secondary buffer. + +;;; Code: + +(require 'gud) +(require 'rdebug-vars) + +(defun chomp(string &optional multiple) + "Remove trailing \n if it's there" + (if multiple + (progn + (while (and (> (length string) 0) + (eq (elt string (- (length string) 1)) ?\n)) + (setq string (substring string 0 -1))) + string) + (if (> (length string) 0) + (let ((s string)) + (if (string= "\n" (substring s -1)) + (substring s 0 -1) + s)) + ""))) + +(defun rdebug-dead-process-p () + "Return true if the rdebug comint-process is dead or exited." + ;; FIXME? Use a variable in gud-comint-buffer's status? + (or (not gud-comint-buffer) + (null (get-buffer-process gud-comint-buffer)) + (not (member (process-status gud-comint-buffer) '(run open))))) + +(defun rdebug-get-secondary-buffer-name (name) + "Get the rdebug NAME secondary buffer. If none found return nil." + (let ((target-name + (or (and gud-comint-buffer + (buffer-local-value 'gud-target-name + gud-comint-buffer)) + gud-target-name))) + (cond ((and (string= "cmd" name) gud-comint-buffer) + (buffer-name gud-comint-buffer)) + (t (format "*rdebug-%s-%s*" name target-name))))) + +(defun rdebug-set-frame-top-arrow (buf) + "Set the fringe arrow in BUF to indicate the top frame." + (with-current-buffer buf + (setq fringe-indicator-alist + '((overlay-arrow . right-triangle))))) + +(defun rdebug-set-frame-not-top-arrow (buf) + "Set the fringe arrow in BUF to indicate a frame other than the top frame." + (with-current-buffer buf + (setq fringe-indicator-alist + '((overlay-arrow . hollow-right-triangle))))) + +(defun rdebug-set-frame-arrow (buf) + "Set the fringe arrow in buffer BUF." + (if (equal 0 rdebug-frames-current-frame-number) + (rdebug-set-frame-top-arrow buf) + (rdebug-set-frame-not-top-arrow buf))) + +;; From Emacs 23 +(unless (fboundp 'split-string-and-unquote) + (defun split-string-and-unquote (string &optional separator) + "Split the STRING into a list of strings. +It understands Emacs Lisp quoting within STRING, such that + (split-string-and-unquote (combine-and-quote-strings strs)) == strs +The SEPARATOR regexp defaults to \"\\s-+\"." + (let ((sep (or separator "\\s-+")) + (i (string-match "[\"]" string))) + (if (null i) + (split-string string sep t) ; no quoting: easy + (append (unless (eq i 0) (split-string (substring string 0 i) sep t)) + (let ((rfs (read-from-string string i))) + (cons (car rfs) + (with-no-warnings + (split-string-and-unquote (substring string (cdr rfs)) + sep)))))))) + ) + + +(provide 'rdebug-fns) + +;;; Local variables: +;;; eval:(put 'rdebug-debug-enter 'lisp-indent-hook 1) +;;; End: + +;;; rdebug-fns.el ends here diff --git a/emacs/.svn/text-base/rdebug-frames.el.svn-base b/emacs/.svn/text-base/rdebug-frames.el.svn-base new file mode 100644 index 0000000..28ab10d --- /dev/null +++ b/emacs/.svn/text-base/rdebug-frames.el.svn-base @@ -0,0 +1,230 @@ +;;; rdebug-frames.el --- Ruby debugger frames buffer + +;; Copyright (C) 2008 Rocky Bernstein (rocky@gnu.org) +;; Copyright (C) 2008 Anders Lindgren + +;; $Id$ + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; See the manual and the file `rdebug.el' for more information. + +;; This file contains code dealing with the frames secondary buffer. + +;;; Code: + +(require 'rdebug-dbg) +(require 'rdebug-fns) +(require 'rdebug-regexp) +(require 'rdebug-secondary) +(require 'rdebug-source) + +(defun rdebug-display-frame-buffer () + "Display the rdebug stack-frame buffer." + (interactive) + (rdebug-display-secondary-buffer "frame")) + +(defvar rdebug-frames-mode-map + (let ((map (make-sparse-keymap))) + (define-key map [double-mouse-1] 'rdebug-goto-frame-mouse) + (define-key map [mouse-2] 'rdebug-goto-frame-mouse) + (define-key map [mouse-3] 'rdebug-goto-frame-mouse) + (define-key map [(control m)] 'rdebug-goto-frame) + (define-key map "0" 'rdebug-goto-frame-n) + (define-key map "1" 'rdebug-goto-frame-n) + (define-key map "2" 'rdebug-goto-frame-n) + (define-key map "3" 'rdebug-goto-frame-n) + (define-key map "4" 'rdebug-goto-frame-n) + (define-key map "5" 'rdebug-goto-frame-n) + (define-key map "6" 'rdebug-goto-frame-n) + (define-key map "7" 'rdebug-goto-frame-n) + (define-key map "8" 'rdebug-goto-frame-n) + (define-key map "9" 'rdebug-goto-frame-n) + (rdebug-populate-secondary-buffer-map map) + + ;; -------------------- + ;; The "Stack window" submenu. + (let ((submenu (make-sparse-keymap))) + (define-key-after map [menu-bar debugger stack] + (cons "Stack window" submenu) + 'placeholder)) + + (define-key map [menu-bar debugger stack goto] + '(menu-item "Goto frame" rdebug-goto-frame)) + map) + "Keymap to navigate rdebug stack frames.") + +(defun rdebug-goto-frame (pt) + "Show the rdebug stack frame corresponding at PT in the rdebug stack buffer." + (interactive "d") + (save-excursion + (goto-char pt) + (let ((s (concat "-->" (buffer-substring (line-beginning-position) + (line-end-position)))) + (s2 (if (= (line-number-at-pos (line-end-position 2)) + (line-number-at-pos (point-max))) + nil + ;;else + (buffer-substring (line-beginning-position 2) + (line-end-position 2))))) + (when (or (string-match rdebug-stack-frame-regexp s) + ;; need to match 1st line last to get the match position right + (and s2 (string-match rdebug-stack-frame-2nd-regexp s2) + (string-match rdebug-stack-frame-1st-regexp s))) + (let ((frame (substring s (match-beginning 2) (match-end 2)))) + (gud-call (concat "frame " frame))))))) + +(defun rdebug-goto-frame-mouse (event) + "Show the rdebug stack frame under the mouse in the rdebug stack buffer." + (interactive "e") + (with-current-buffer (window-buffer (posn-window (event-end event))) + (rdebug-goto-frame (posn-point (event-end event))))) + +;; The following is split in two to facilitate debugging. +(defun rdebug-goto-frame-n-internal (keys) + (if (and (stringp keys) + (= (length keys) 1)) + (progn + (setq rdebug-goto-entry-acc (concat rdebug-goto-entry-acc keys)) + ;; Try to find the longest suffix. + (let ((acc rdebug-goto-entry-acc)) + (while (not (string= acc "")) + (if (not (rdebug-goto-entry-try acc)) + (setq acc (substring acc 1)) + (gud-call (format "frame %s" acc)) + ;; Break loop. + (setq acc ""))))) + (message "`rdebug-goto-frame-n' must be bound to a number key"))) + +(defun rdebug-goto-frame-n () + "Go to the frame number indicated by the accumulated numeric keys just entered. + +This function is usually bound to a numeric key in a 'frame' +secondary buffer. To go to an entry above 9, just keep entering +the number. For example, if you press 1 and then 9, frame 1 is selected +\(if it exists) and then frame 19 (if that exists). Entering any +non-digit will start entry number from the beginning again." + (interactive) + (if (not (eq last-command 'rdebug-goto-frame-n)) + (setq rdebug-goto-entry-acc "")) + (rdebug-goto-frame-n-internal (this-command-keys))) + +(defun rdebug-frames-match-current-line (limit) + (and rdebug-frames-current-frame-number + (re-search-forward + (concat "^ *#" + (number-to-string rdebug-frames-current-frame-number) + ;; At least one space (so that we don't match #1 when looking for #10). + " +" + ;; The entire line. + ".*" + "\n" + ;; And the next, if this entry was split into two. + "\\( *[^# ].*$\\)?") limit t))) + +(defvar rdebug-frames-current-frame-face 'highlight) + +;; Example of frame buffer content: +;; +;; #0 Integer.under_cover at line test.rb:13 +;; #1 ClassA::Nested::DeepDown.under_cover(p#ClassA::Nested::DeepD...) +;; at line test.rb:12 +;; #2 Object.sune(s#String, i#Fixnum) at line test.rb:24 +;; #3 at line test.rb:27 + +(defvar rdebug-frames-font-lock-keywords + '( + ;; Parameters and first type entry. + ("\\<\\([a-zA-Z_][a-zA-Z0-9_]*\\)#\\([a-zA-Z_][a-zA-Z0-9_]*\\)\\>" + (1 font-lock-variable-name-face) + (2 font-lock-type-face)) + ;; "::Type", which occurs in class name of function and in parameter list. + ("::\\([a-zA-Z_][a-zA-Z0-9_]*\\)" + (1 font-lock-type-face)) + ;; The frame number and first type name, if present. + ("^ *#\\([0-9]+\\) *\\(\\([a-zA-Z_][a-zA-Z0-9_]*\\)[.:]\\)?" + (1 font-lock-constant-face) + (3 font-lock-type-face nil t)) ; t means optional. + ;; File name and line number. + ("at line \\(.*\\):\\([0-9]+\\)$" + (1 font-lock-warning-face) + (2 font-lock-constant-face)) + ;; Function name. + ("\\<\\([a-zA-Z_][a-zA-Z0-9_]*\\)\\.\\([a-zA-Z_][a-zA-Z0-9_]*\\)" + (1 font-lock-type-face) + (2 font-lock-function-name-face)) + (rdebug-frames-match-current-line + (0 rdebug-frames-current-frame-face append))) + "Font-lock rules for the stack frame window in `rdebug'.") + +(defun rdebug-frames-mode () + "Major mode for displaying the stack trace in the `rdebug' Ruby debugger. +\\{rdebug-frames-mode-map}" + (interactive) + (kill-all-local-variables) + (setq major-mode 'rdebug-frames-mode) + (setq mode-name "RDEBUG Stack Frames") + (set (make-local-variable 'rdebug-secondary-buffer) t) + (setq mode-line-process 'rdebug-mode-line-process) + (use-local-map rdebug-frames-mode-map) + (set (make-local-variable 'font-lock-defaults) + '(rdebug-frames-font-lock-keywords)) + (run-mode-hooks 'rdebug-frames-mode-hook)) + +;; Note: This function can't restore the original point alone, since +;; the point is already at the end of the buffer when this is called. +(defun rdebug-setup-frame-buffer (buf comint-buffer) + "Find the current frame and display the corresponding source line. + +Also, cleans the buffer somewhat and sets up help for the font-lock rules." + (rdebug-debug-enter "rdebug-setup-stack-buffer" + (with-current-buffer buf + (let ((inhibit-read-only t) + (current-frame-number 0)) + (rdebug-frames-mode) + (set (make-local-variable 'gud-comint-buffer) comint-buffer) + (goto-char (point-min)) + (when (re-search-forward "-->" nil t) + (beginning-of-line) + (setq overlay-arrow-position (make-marker)) + (set-marker overlay-arrow-position (point)) + (when (looking-at rdebug-stack-frame-1st-regexp) + (setq current-frame-number + (string-to-number + (match-string rdebug-stack-frame-number-group))) + (set (make-local-variable 'rdebug-frames-current-frame-number) + current-frame-number) + (with-current-buffer comint-buffer + (setq rdebug-frames-current-frame-number current-frame-number)) + (when gud-last-frame + (rdebug-set-frame-arrow (gud-find-file (car gud-last-frame)))) + (rdebug-set-frame-arrow buf))) + ;; Remove initial ' ' or '-->'. + (save-excursion + (goto-char (point-max)) + (beginning-of-line) + (if (> (point) 4) + (delete-rectangle 4 (point)))))))) + +(provide 'rdebug-frames) + +;;; Local variables: +;;; eval:(put 'rdebug-debug-enter 'lisp-indent-hook 1) +;;; End: + +;;; rdebug-frames.el ends here diff --git a/emacs/.svn/text-base/rdebug-gud.el.svn-base b/emacs/.svn/text-base/rdebug-gud.el.svn-base new file mode 100644 index 0000000..ab65a41 --- /dev/null +++ b/emacs/.svn/text-base/rdebug-gud.el.svn-base @@ -0,0 +1,242 @@ +;;; rdebug-gud.el --- rdebug interface to gud. + +;; Copyright (C) 2007, 2008 Rocky Bernstein (rocky@gnu.org) +;; Copyright (C) 2007, 2008 Anders Lindgren + +;; $Id$ + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; See the manual and the file `rdebug.el' for more information. + +;; This file contains rdebug Emacs routines which interface with gud. + +;;; Code: + +;; ------------------------------------------------------------------- +;; Dependencies. +;; + +(require 'gud) +(require 'rdebug-error) +(require 'rdebug-fns) +(require 'rdebug-regexp) +(require 'rdebug-vars) + + +(defun gud-rdebug-massage-args (file args) + "Change FILE and list ARGS before running the debugger. + +gud requires this routine to be defined." + args) + + +(defun gud-rdebug-find-file (file) + "`rdebug' and `gud' call this with FILE when they encounter a Ruby program file." + + (find-file-noselect file 'nowarn)) + +(defun rdebug-display-line (file line &optional move-arrow) + "Arrange for marker to appear in at FILE and LINE. +The line marker might appear in the Emacs fringe or as an overlay arroe. +Optional argument MOVE-ARROW indicates whether to move any previous indicator." + (if file + (let ((oldpos (and gud-overlay-arrow-position + (marker-position gud-overlay-arrow-position))) + (oldbuf (and gud-overlay-arrow-position + (marker-buffer gud-overlay-arrow-position)))) + (gud-display-line file line) + (unless move-arrow + (when gud-overlay-arrow-position + (set-marker gud-overlay-arrow-position oldpos oldbuf)))))) + +(defun rdebug-stepping (step-or-next &optional arg) + (or arg (setq arg 1)) + ;;(if (not (member '('rdebug-next 'rdebug-step 'digit-argument) last-command)) + ;; (setq rdebug-stepping-prefix "")) + (unless (member rdebug-stepping-prefix '("" "+" "-")) + (setq rdebug-stepping-prefix "")) + (rdebug-call (format "%s%s %d" step-or-next rdebug-stepping-prefix arg))) + + + +;; ------------------------------------------------------------------- +;; Rdebug commands. +;; + +(defun rdebug-call (cmd) + "Run a debugger command with some error checking." + (if (rdebug-dead-process-p) + (rdebug-errmsg + "Can't find a live debugger process buffer to feed the command to.") + (gud-call cmd))) + +(defun rdebug-call-return (cmd &rest options) + "Register a debugger command whose output should be handled specially. + +OPTIONS is zero or more indicators what should happen with the +output. The following are supported: + * :tooltip -- Show the result in a tool-tip. + * :info -- Show the result in the info secondary buffer." + (if (rdebug-dead-process-p) + (rdebug-errmsg + "Can't find a live debugger process buffer to feed the command to.") + (with-current-buffer gud-comint-buffer + (setq rdebug-call-queue + (append rdebug-call-queue (list (cons cmd options)))) + (gud-call cmd)))) + +(defun rdebug-continue (&optional arg) + "Run a debugger \"continue\" command. + +With a numeric ARG, continue to that line number of the current file." + (interactive "p") + (if arg + (rdebug-call (format "continue %d" arg)) + (rdebug-call (format "continue")))) + + +(defun rdebug-next (&optional arg) + "Run a debugger \"next\" command, respecting `rdebug-stepping-prefix'. + +With a numeric ARG, continue to that line number of the current file." + (interactive "p") + (rdebug-stepping "next" arg)) + +(defvar rdebug-stepping-prefix "" + "The kind of stepping modifier that is desired. + +This variable will have a string value which is either \"\", +\"+\", or \"-\"; this string is be appended to the debugger +stepping commands (\"next\", or \"step\").") + +(defun rdebug-print-cmd (expr &optional cmd) + "Run a debugger print (pl, ps, pp, p) command on `EXPR'; `CMD' is the command to run." + (interactive "s") + (unless cmd (setq cmd "pp")) + (rdebug-call-return (format "%s %s " cmd expr) :tooltip)) + +(defun rdebug-print-list-region (from to) + "Run a debugger \"pl\" command on the marked region." + (interactive "r") + (if (> from to) + (let ((tem to)) + (setq to from from tem))) + (rdebug-print-cmd (buffer-substring from to) "pl")) + +(defun rdebug-print-region (from to) + "Run a debugger \"p\" command on the marked region." + (interactive "r") + (if (> from to) + (let ((tem to)) + (setq to from from tem))) + (rdebug-print-cmd (buffer-substring from to) "p")) + +(defun rdebug-print-sorted-region (from to) + "Run a debugger \"ps\" command on the marked region." + (interactive "r") + (if (> from to) + (let ((tem to)) + (setq to from from tem))) + (rdebug-print-cmd (buffer-substring from to) "ps")) + +(defun rdebug-pretty-print-region (from to) + "Run a debugger \"pp\" command on the marked region." + (interactive "r") + (if (> from to) + (let ((tem to)) + (setq to from from tem))) + (rdebug-print-cmd (buffer-substring from to) "pp")) + + +;; +;; The following two commands should be seen as proof-of-concept +;; functions for the info buffer. +;; + +(defun rdebug-pretty-print-to-buffer (s) + "Pretty print expression to the info buffer." + (interactive "sPretty print: ") + (rdebug-call-return (format "pp %s" s) :info)) + +(defun rdebug-pretty-print-region-to-buffer (from to) + "Pretty print expression in region to the info buffer." + (interactive "r") + (rdebug-call-return (format "pp %s" (buffer-substring from to)) :info)) + + + +(defun rdebug-quit () + "Kill the debugger process associated with the current buffer. + +When `rdebug-many-windows' is active, the original window layout +is restored." + (interactive) + (if (yes-or-no-p "Really quit? ") + (rdebug-call "quit unconditionally"))) + +(defun rdebug-restart () + "Restart the debugged Ruby script. + +An exec restart is used." + (interactive) + (if (yes-or-no-p "Restart? ") + (rdebug-call "restart"))) + +(defun rdebug-set-stepping-prefix () + "Set the granularity of stepping on the subsequent 'next' or 'step' command. +As long as repeated next or step commands are given, they inherit this setting." + (interactive) + (setq rdebug-stepping-prefix (this-command-keys))) + +(defun rdebug-step (&optional arg) + "Run a debugger \"next\" command, respecting `rdebug-stepping-prefix'. + +With a numeric ARG, continue to that line number of the current file." + (interactive "p") + (rdebug-stepping "step" arg)) + +(defun rdebug-newer-frame () + "Run a debugger \"down\" command to an newer frame. + +If we try to go down from frame 0, wrap to the end of the file" + (interactive) + (let* ((buf-name (rdebug-get-secondary-buffer-name "frame")) + (buf (or (get-buffer buf-name) (current-buffer)))) + (with-current-buffer buf + ;; Should we add a mode to disable wrapping? + (if (equal rdebug-frames-current-frame-number 0) + (rdebug-call "frame -1") + (rdebug-call "down 1"))))) + +(defun rdebug-older-frame () + "Run a debugger \"up\" command to an older frame." + (interactive) + (let* ((buf-name (rdebug-get-secondary-buffer-name "frame")) + (buf (or (get-buffer buf-name) (current-buffer)))) + (with-current-buffer buf + ;; Should we add a mode to disable wrapping? + (rdebug-call "up 1")))) + +(provide 'rdebug-gud) + +;;; Local variables: +;;; eval:(put 'rdebug-debug-enter 'lisp-indent-hook 1) +;;; End: + +;;; rdebug-gud.el ends here diff --git a/emacs/.svn/text-base/rdebug-help.el.svn-base b/emacs/.svn/text-base/rdebug-help.el.svn-base new file mode 100644 index 0000000..6b69374 --- /dev/null +++ b/emacs/.svn/text-base/rdebug-help.el.svn-base @@ -0,0 +1,104 @@ +;;; rdebug-help.el --- Ruby debugger help + +;; Copyright (C) 2008 Rocky Bernstein (rocky@gnu.org) +;; Copyright (C) 2008 Anders Lindgren + +;; $Id$ + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; See the manual and the file `rdebug.el' for more information. + +;; This file contains code dealing with the help buffer. + +;;; Code: + +(defvar rdebug-secondary-window-help-mode-map + (let ((map (make-sparse-keymap))) + (suppress-keymap map) + (rdebug-populate-secondary-buffer-map map) + map) + "Keymap used in the help buffer in the `rdebug' Ruby debugger.") + +(defun rdebug-secondary-window-help-mode () + "Major mode for the secondary buffer help text in the `rdebug' Ruby debugger. + +\\{rdebug-secondary-window-help-mode-map}" + (interactive) + (kill-all-local-variables) + (setq major-mode 'rdebug-secondary-window-help-mode) + (setq mode-name "RDEBUG Help") + (setq buffer-read-only t) + (set (make-local-variable 'rdebug-secondary-buffer) t) + (setq mode-line-process 'rdebug-mode-line-process) + (use-local-map rdebug-secondary-window-help-mode-map) + (run-mode-hooks 'rdebug-secondary-window-help-mode-hook)) + +(defun rdebug-display-secondary-window-help-buffer () + "Display the rdebug help buffer." + (interactive) + (rdebug-display-secondary-buffer "help")) + +(defun rdebug-setup-secondary-window-help-buffer (buf comint-buffer) + (rdebug-debug-enter "rdebug-setup-secondary-window-help-buffer" + (with-current-buffer buf + (rdebug-secondary-window-help-mode) + (set (make-local-variable 'gud-comint-buffer) comint-buffer) + (insert "\ + +This is a rdebug secondary window, you can use it to watch a +number of help buffers. Use capital letters to switch between the +available buffers. Lower case letters (and other key +combinations) are used to issue buffer-specific commands. + +Press `C-h m' for more help, when the individual buffers are visible. + + B - Breakpoints buffer. + C - Command buffer (the debugger shell) + O - Output window + S - go to source frame + T - Stack trace buffer + V - Variables buffer + W - Watch buffer + + SPC - step (into) + + - set for step+ and next+ + - - set for step- and next- + _ - set to remove +/- + c - continue + f - finish (step out) + n - next (step over) + p - print + q - quit + r - run (restart) + R - run (restart) + s - step (into) + + > - go down frame (with numeric argument goes down that many frames) + < - go up one frame (with numeric argument goes down that many frames) + + ? - This help text. +")))) + +(provide 'rdebug-help) + +;;; Local variables: +;;; eval:(put 'rdebug-debug-enter 'lisp-indent-hook 1) +;;; End: + +;;; rdebug-help.el ends here diff --git a/emacs/.svn/text-base/rdebug-info.el.svn-base b/emacs/.svn/text-base/rdebug-info.el.svn-base new file mode 100644 index 0000000..af09933 --- /dev/null +++ b/emacs/.svn/text-base/rdebug-info.el.svn-base @@ -0,0 +1,83 @@ +;;; rdebug-info.el --- This file contains code dealing with the Ruby +;;; debugger's info secondary buffer. + +;; Copyright (C) 2008 Rocky Bernstein (rocky@gnu.org) +;; Copyright (C) 2008 Anders Lindgren + +;; $Id: rdebug-breaks.el 670 2008-02-06 18:15:28Z rockyb $ + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; See the manual and the file `rdebug.el' for more information. + + +;;; Code: + +(require 'rdebug-dbg) +(require 'rdebug-gud) +(require 'rdebug-regexp) +(require 'rdebug-secondary) +(require 'rdebug-source) +(require 'rdebug-vars) + +(defun rdebug-display-info-buffer () + "Display the rdebug breakpoints buffer." + (interactive) + (rdebug-display-secondary-buffer "info")) + +(defvar rdebug-info-mode-map + (let ((map (make-sparse-keymap))) + (rdebug-populate-secondary-buffer-map map) + map) + "Keymap for the Rdebug info secondary buffer.") + +(defun rdebug-info-mode () + "Major mode for Ruby debugger info buffer. + +\\{rdebug-info-mode-map}" + (kill-all-local-variables) + (setq major-mode 'rdebug-info-mode) + (setq mode-name "RDEBUG Info") + (use-local-map rdebug-info-mode-map) + (setq buffer-read-only t) + (set (make-local-variable 'rdebug-secondary-buffer) t) + (setq mode-line-process 'rdebug-mode-line-process) + (run-mode-hooks 'rdebug-info-mode-hook)) + +(defun rdebug-setup-info-buffer (buf comint-buffer) + "Setup the Rdebug debugger info buffer." + (rdebug-debug-enter "rdebug-setup-info-buffer" + (with-current-buffer buf + (let ((inhibit-read-only t) + (old-line-number (buffer-local-value 'rdebug-current-line-number + buf))) + (rdebug-info-mode) + (goto-line old-line-number))))) + + +;; ------------------------------------------------------------------- +;; The end. +;; + +(provide 'rdebug-info) + +;;; Local variables: +;;; eval:(put 'rdebug-debug-enter 'lisp-indent-hook 1) +;;; End: + +;;; rdebug-info.el ends here diff --git a/emacs/.svn/text-base/rdebug-layouts.el.svn-base b/emacs/.svn/text-base/rdebug-layouts.el.svn-base new file mode 100644 index 0000000..0b2d998 --- /dev/null +++ b/emacs/.svn/text-base/rdebug-layouts.el.svn-base @@ -0,0 +1,180 @@ +;;; rdebug-layouts.el --- Ruby debugger window layouts. + +;; Copyright (C) 2008 Rocky Bernstein (rocky@gnu.org) +;; Copyright (C) 2008 Anders Lindgren + +;; $Id$ + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; This is file contains the window layouts that come with rdebug; the +;; code where can be consulted as a guide for creating other window +;; layouts. + +;; See the manual and the file `rdebug.el' for overall information on +;; the ruby debugger rdebug. + +;;; Code: + +(defun rdebug-get-buffer (name script-name) + "Return a rdebug buffer for displaying NAME when debugging SCRIPT-NAME. +If the buffer doesn't exists it is created." + (get-buffer-create (format "*rdebug-%s-%s*" name script-name))) + + +(defun rdebug-get-existing-buffer (name script-name) + "Return a rdebug buffer for displaying NAME when debugging SCRIPT-NAME. +Return nil if the buffer doesn't exists." + (get-buffer (format "*rdebug-%s-%s*" name script-name))) + + +(defun rdebug-window-layout-conservative (src-buf name) + "A conservative rdebug window layout with three windows. + +This window layout mimics the traditional debugger shell and +source window layout, it only add one secondary window. +Initially, the secondary window displays output of the debugged +process, but any secondary buffer can be displayed, press `?' in +the window for more details. +Argument SRC-BUF the buffer containing the Ruby source program that was initially run. NAME is the name of that buffer." + (delete-other-windows) + (split-window-horizontally) + (other-window 1) + (switch-to-buffer src-buf) + (other-window 1) + (when rdebug-use-separate-io-buffer + (split-window nil 20) + (set-window-buffer + (selected-window) (rdebug-get-buffer "output" name))) + (other-window 1)) + +(defun rdebug-window-layout-rocky (src-buf name) + "Rocky's window layout. + +3 windows. The source window is on top 4/5 of height. The +bottom is split between the command windows and a stack window. + +See `rdebug' for more information. +Argument SRC-BUF the buffer containing the Ruby source program that was initially run. NAME is the name of that buffer." + (delete-other-windows) + (split-window nil ( / ( * (window-height) 4) 5)) + (set-window-buffer + (selected-window) src-buf) + (other-window 1) + (set-window-buffer + (selected-window) (rdebug-get-buffer "frame" name)) + (split-window-horizontally) + (set-window-buffer + (selected-window) (rdebug-get-buffer "cmd" name)) + (goto-char (point-max))) + +(defun rdebug-window-layout-rocky2 (src-buf name) + "This layout is standard window without the output window, see `rdebug'. +for more information. +Argument SRC-BUF is the NAME of the buffer containing the Ruby source program that was initially run." + (delete-other-windows) + (split-window nil ( / ( * (window-height) 3) 4)) + (set-window-buffer + (selected-window) src-buf) + (split-window nil ( / (window-height) 3)) + (split-window-horizontally) + (set-window-buffer + (selected-window) (rdebug-get-buffer "frame" name)) + (other-window 1) + (set-window-buffer + (selected-window) (rdebug-get-buffer "variables" name)) + (other-window 1) + (switch-to-buffer src-buf) + (other-window 1) + (set-window-buffer + (selected-window) (rdebug-get-buffer "cmd" name)) + (goto-char (point-max))) + +(defun rdebug-window-layout-stack-of-windows (src-buf name) + "A rdebug window layout with several secondary windows to the right. +The debugger shell and the source code window is to the left. +Argument SRC-BUF the buffer containing the Ruby source program that was initially run. NAME is the name of that buffer." + (delete-other-windows) + (split-window-horizontally) + (split-window nil 20) + (set-window-buffer + (selected-window) (rdebug-get-buffer "cmd" name)) + (other-window 1) + (switch-to-buffer src-buf) + (other-window 1) + (split-window) + (split-window) + (set-window-buffer + (selected-window) (rdebug-get-buffer "variables" name)) + (other-window 1) + (set-window-buffer + (selected-window) (rdebug-get-buffer "frame" name)) + (when rdebug-use-separate-io-buffer + (other-window 1) + (split-window) + (set-window-buffer + (selected-window) (rdebug-get-buffer "output" name))) + (other-window 1) + (set-window-buffer + (selected-window) (rdebug-get-buffer "breakpoints" name)) + (other-window 1)) + +;; The default layout +(defun rdebug-window-layout-standard (src-buf name) + "The default rdebug window layout, see `rdebug' for more information. +Argument SRC-BUF the buffer containing the Ruby source program that was initially run. NAME is the name of that buffer." + (delete-other-windows) + (split-window nil ( / ( * (window-height) 3) 4)) + (split-window nil ( / (window-height) 3)) + (split-window-horizontally) + (other-window 1) + (set-window-buffer + (selected-window) (rdebug-get-buffer "variables" name)) + (other-window 1) + (switch-to-buffer src-buf) + (when rdebug-use-separate-io-buffer + (split-window-horizontally) + (other-window 1) + (set-window-buffer + (selected-window) (rdebug-get-buffer "output" name))) + (other-window 1) + (set-window-buffer + (selected-window) (rdebug-get-buffer "frame" name)) + (split-window-horizontally) + (other-window 1) + (set-window-buffer + (selected-window) (rdebug-get-buffer "breakpoints" name)) + (other-window 1) + (goto-char (point-max))) + + +(defun rdebug-window-layout-no-shell (src-buf name) + "A rdebug window layout without a shell window. +Argument SRC-BUF the buffer containing the Ruby source program that was initially run. NAME is the name of that buffer." + (delete-other-windows) + (set-window-buffer + (selected-window) (rdebug-get-buffer "watch" name)) + (rdebug-window-layout-standard src-buf name)) + +(provide 'rdebug-layouts) + +;;; Local variables: +;;; eval:(put 'rdebug-debug-enter 'lisp-indent-hook 1) +;;; End: + +;;; rdebug-layouts.el ends here diff --git a/emacs/.svn/text-base/rdebug-locring.el.svn-base b/emacs/.svn/text-base/rdebug-locring.el.svn-base new file mode 100644 index 0000000..0a36fc2 --- /dev/null +++ b/emacs/.svn/text-base/rdebug-locring.el.svn-base @@ -0,0 +1,118 @@ +;;; rdebug-locring.el --- Ruby debugger location ring + +;; Copyright (C) 2008, 2009 Rocky Bernstein (rocky@gnu.org) +;; Copyright (C) 2008 Anders Lindgren + +;; $Id$ + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; This file manages a ring of (recently stopped) positions to allow +;; the programmer to move back and forth between them. + +;;; Code: + +(defvar rdebug-source-location-ring nil + "Ring of the last `rdebug-source-location-ring-size' positions we've stopped aft.") + +(defvar rdebug-source-location-ring-index -1 + "Position in `rdebug-source-location-ring' of where we are.") + +(defun rdebug-locring-add (frame location-history-ring) + "Add FRAME to LOCATION-HISTORY-RING if we are on the top frame and have a frame to add." + ;; Switching frames shouldn't save a new ring + ;; position. Also make sure no position is different. + ;; Perhaps duplicates should be controlled by an option. + (unless (and (not (ring-empty-p location-history-ring)) + (equal (ring-ref location-history-ring + (ring-length location-history-ring)) frame)) + (ring-insert-at-beginning location-history-ring frame))) + +(defun rdebug-locring-clear () + "Clear out all source locations in `Go to the source location of the first stopping point." + (interactive) + (setq rdebug-source-location-ring-index -1) + (while (not (ring-empty-p rdebug-source-location-ring)) + (ring-remove rdebug-source-location-ring))) + +(defun rdebug-locring-goto (ring-position) + "Go the source position RING-POSITION in the stopping history." + (interactive "NSource location ring position (0 is oldest): ") + (with-current-buffer gud-comint-buffer + (setq rdebug-source-location-ring-index ring-position) + (let* ((frame (ring-ref rdebug-source-location-ring ring-position)) + (file (car frame)) + (line (cdr frame))) + (when file + (rdebug-display-line file line) + (message (format "%d %s:%d" rdebug-source-location-ring-index + file line)))))) + +(defun rdebug-locring-newer () + "Cycle through source location stopping history to get the next newer (more recently visited) location." + (interactive) + (with-current-buffer gud-comint-buffer + (if (equal (+ 1 rdebug-source-location-ring-index) + (ring-length rdebug-source-location-ring)) + (progn + (message "At newest - Will set to wrap to oldest.") + (setq rdebug-source-location-ring-index -1)) + ;; else + (rdebug-locring-goto + (if (> rdebug-source-location-ring-index + (ring-length rdebug-source-location-ring)) + 0 + ;; else + (ring-plus1 rdebug-source-location-ring-index + (ring-length rdebug-source-location-ring))))))) + +(defun rdebug-locring-newest () + "Go to the source location of the first stopping point." + (interactive) + (rdebug-locring-goto (- (ring-length rdebug-source-location-ring) 1))) + +(defun rdebug-locring-older () + "Cycle through source location stopping history to get the next older (least recently visited) location." + (interactive) + (with-current-buffer gud-comint-buffer + (if (equal rdebug-source-location-ring-index 0) + (progn + (message "At oldest - Will set to wrap to newest.") + (setq rdebug-source-location-ring-index + (+ 1 (ring-length rdebug-source-location-ring)))) + ;; else + (rdebug-locring-goto + (if (or (not rdebug-source-location-ring-index) + (< rdebug-source-location-ring-index 0)) + 0 + ;; else + (ring-minus1 rdebug-source-location-ring-index + (ring-length rdebug-source-location-ring))))))) + +(defun rdebug-locring-oldest () + "Go to the oldest source position location." + (interactive) + (ring-ref rdebug-source-location-ring 0)) + +(provide 'rdebug-locring) + +;;; Local variables: +;;; eval:(put 'rdebug-debug-enter 'lisp-indent-hook 1) +;;; End: + +;;; rdebug-locring.el ends here diff --git a/emacs/.svn/text-base/rdebug-output.el.svn-base b/emacs/.svn/text-base/rdebug-output.el.svn-base new file mode 100644 index 0000000..07b945e --- /dev/null +++ b/emacs/.svn/text-base/rdebug-output.el.svn-base @@ -0,0 +1,106 @@ +;;; rdebug-output.el --- Ruby debugger output buffer + +;; Copyright (C) 2008 Rocky Bernstein (rocky@gnu.org) +;; Copyright (C) 2008 Anders Lindgren + +;; $Id$ + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; See the manual and the file `rdebug.el' for more information. + +;; This file contains code dealing with the output secondary buffer. + +;;; Code: + +(require 'rdebug-dbg) +(require 'rdebug-secondary) + +(defun rdebug-display-output-buffer () + "Display the rdebug output buffer." + (interactive) + (rdebug-display-secondary-buffer "output")) + +;; FIXME add a macro to toggle read-only and run command. +(defun rdebug-output-add-divider () + (interactive "") + (save-excursion + (goto-char (point-max)) + (setq buffer-read-only nil) + ;; FIXME Cooler would be to pick up stack position in stack line + ;; and prepend a buffer-local marker number + (insert (format "%d: ============================\n" + rdebug-output-marker-number)) + (setq rdebug-output-marker-number (+ rdebug-output-marker-number 1)) + (setq buffer-read-only t))) + +(defun rdebug-output-delete-output () + (interactive) + (setq buffer-read-only nil) + (delete-region (point-min) (point-max)) + (setq buffer-read-only t)) + +(defun rdebug-output-undo () ;FIXME make more global? + (interactive "") + (setq buffer-read-only nil) + (undo) + (setq buffer-read-only t)) + +(defvar rdebug-output-mode-map + (let ((map (make-sparse-keymap))) + (define-key map "d" 'rdebug-output-delete-output) + (define-key map "t" 'rdebug-goto-traceback-line) + (define-key map "!" 'rdebug-goto-dollarbang-traceback-line) + (define-key map "=" 'rdebug-output-add-divider) + (define-key map "\C-_" 'rdebug-output-undo) ; FIXME get from keymap + (define-key map "u" 'rdebug-output-undo) + (suppress-keymap map) + (rdebug-populate-secondary-buffer-map map) + map) + "Keymap used in the output buffer in the `rdebug' Ruby debugger.") + +(defun rdebug-output-mode () + "Major mode for displaying the script output in the `rdebug' Ruby debugger. + +\\{rdebug-output-mode}" + (interactive) + (let ((old-marker-number rdebug-output-marker-number)) + (kill-all-local-variables) + (setq major-mode 'rdebug-output-mode) + (setq mode-name "RDEBUG Output") + (setq buffer-read-only t) + (set (make-local-variable 'rdebug-secondary-buffer) t) + (setq mode-line-process 'rdebug-mode-line-process) + (set (make-local-variable 'rdebug-accumulative-buffer) t) + (use-local-map rdebug-output-mode-map) + (set (make-local-variable 'rdebug-output-marker-number) old-marker-number) + (run-mode-hooks 'rdebug-output-mode-hook))) + +(defun rdebug-setup-output-buffer (buf comint-buffer) + (rdebug-debug-enter "rdebug-setup-output-buffer" + (with-current-buffer buf + (rdebug-output-mode) + (set (make-local-variable 'gud-comint-buffer) comint-buffer)))) + +(provide 'rdebug-output) + +;;; Local variables: +;;; eval:(put 'rdebug-debug-enter 'lisp-indent-hook 1) +;;; End: + +;;; rdebug-output.el ends here diff --git a/emacs/.svn/text-base/rdebug-regexp.el.svn-base b/emacs/.svn/text-base/rdebug-regexp.el.svn-base new file mode 100644 index 0000000..62e8a83 --- /dev/null +++ b/emacs/.svn/text-base/rdebug-regexp.el.svn-base @@ -0,0 +1,118 @@ +;;; rdebug-regexp.el --- Ruby debugger regular expressions + +;; Copyright (C) 2007, 2008 Rocky Bernstein (rocky@gnu.org) +;; Copyright (C) 2007, 2008 Anders Lindgren + +;; $Id$ + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; See the manual and the file `rdebug.el' for more information. + +;; Here we have regular expressions and names for matched patterns +;; of those regular expressions. + +;;; Code: + +;; ------------------------------------------------------------------- +;; Variables defining regular expressions (regexp:s). +;; + +(defconst gud-rdebug-marker-regexp + "\\(?:source \\)?\\(\\(?:[a-zA-Z]:\\)?[^:\n]*\\):\\([0-9]*\\).*\n" + "Regular expression used to find a file location given by rdebug. + +Program-location lines look like this: + source /tmp/gcd.rb:29: gcd + /tmp/gcd.rb:29: gcd + source /tmp/gcd.rb:29 + source C:/tmp/gcd.rb:29 + source \\sources\\capfilterscanner\\capanalyzer.rb:3: ") + +(defconst rdebug-annotation-end-regexp + "\n" + "Regular expression to match the end of an annotation.") + +;; Examples of annotations: +;; ^Z^Z\n +;; ^Z^Zfoo\n +;; ^Z^Zpre-prompt\n +;; ^Z^Zsource foo.rb:10\n + +(defconst rdebug-annotation-start-regexp + "\\(\\([a-z][-a-z]*\\)?\n\\|source \\)" + "Regular expression to match the start of an annotation.") + +(defconst rdebug-breakpoint-regexp + "^\\ +\\([0-9]+\\) \\([yn]\\) +at +\\(.+\\):\\([0-9]+\\)\\( if .*\\)?$" + "Regexp to recognize breakpoint lines in rdebug breakpoint buffers.") + +(defconst rdebug-marker-regexp-file-group 2 + "Group position in `rdebug-position-regexp' that matches the file name.") + +(defconst rdebug-marker-regexp-line-group 3 + "Group position in `rdebug-position-regexp' that matches the line number.") + +(defconst rdebug-position-regexp + "\\(\\)\\([-a-zA-Z0-9_/.]*\\):\\([0-9]+\\)" + "Regular expression for a rdebug position.") + +(defconst rdebug-traceback-line-re + "^[ \t]+from \\([^:]+\\):\\([0-9]+\\)\\( in `.*'\\)?" + "Regular expression that describes a Ruby traceback line.") + +(defconst rdebug-dollarbang-traceback-line-re + "^[ \t]+[[]?\\([^:]+\\):\\([0-9]+\\):in `.*'" + "Regular expression that describes a Ruby traceback line from $! list.") + +(defconst rdebug-stack-frame-1st-regexp + "^\\(-->\\| \\) +#\\([0-9]+\\)\\(.*\\)" + "Regexp to match the first line of a stack frame in rdebug stack buffers.") + +(defconst rdebug-stack-frame-number-group 2 + "The group position in `rdebug-stack-frame-1st-regexp' that matches the frame number.") + +(defconst rdebug-stack-frame-2nd-regexp + "\s+at line +\\([^:]+\\):\\([0-9]+\\)$" + "Regexp to match the second line of a stack frame in rdebug stack buffers.") + +(defconst rdebug-stack-frame-2nd-file-group 1 + "Group position in `rdebug-stack-frame-2nd-regexp' that matches the file name.") + +(defconst rdebug-stack-frame-2nd-line-group 2 + "Group position in `rdebug-stack-frame-2nd-regexp' that matches the line number.") +(defconst rdebug-stack-frame-regexp + (concat rdebug-stack-frame-1st-regexp rdebug-stack-frame-2nd-regexp) + "Regexp to recognize a stack frame line in rdebug stack buffers.") + +(defconst rdebug-stack-frame-file-group 4 + "Group position in `rdebug-stack-frame-regexp' that matches the file name.") + +(defconst rdebug-stack-frame-line-group 5 + "Group position in `rdebug-stack-frame-regexp' that matches the line number.") + +(defconst rdebug-input-prompt-regexp "(+rdb:\\([0-9]+\\|post-mortem\\)) " + "Regular expression to recognize a rdebug prompt. Some uses may prepend an anchor to the front.") + +(provide 'rdebug-regexp) + +;;; Local variables: +;;; eval:(put 'rdebug-debug-enter 'lisp-indent-hook 1) +;;; End: + +;;; rdebug-regexp.el ends here diff --git a/emacs/.svn/text-base/rdebug-secondary.el.svn-base b/emacs/.svn/text-base/rdebug-secondary.el.svn-base new file mode 100644 index 0000000..3588bd5 --- /dev/null +++ b/emacs/.svn/text-base/rdebug-secondary.el.svn-base @@ -0,0 +1,260 @@ +;;; rdebug-secondary.el --- Rdebug support windows. + +;; Copyright (C) 2008 Rocky Bernstein (rocky@gnu.org) +;; Copyright (C) 2008 Anders Lindgren + +;; $Id$ + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; See the manual and the file `rdebug.el' for more information. + +;; Key bindings and menu for secondary buffers. + +;;; Code: + +(require 'rdebug) + +(defun rdebug-populate-secondary-buffer-map (map) + "Bind all common keys and menu used in the rdebug secondary buffers. +This includes the keys bound to `gud-key-prefix' (typically C-x +C-a)." + (rdebug-populate-secondary-buffer-map-plain map) + (rdebug-populate-common-keys map) + (rdebug-populate-debugger-menu map) + (let ((prefix-map (make-sparse-keymap))) + (rdebug-populate-secondary-buffer-map-plain prefix-map) + (define-key map gud-key-prefix prefix-map))) + + +(defun rdebug-display-cmd-buffer () + "Display the rdebug debugger command buffer." + (interactive) + (rdebug-display-secondary-buffer "cmd")) + +(defun rdebug-pick-secondary-window-categorize (win name orig-win) + "Return how suiteable this window is to display the a secondary buffer. +The higher score the better." + (let ((buffer (window-buffer win))) + (save-current-buffer + (set-buffer buffer) + (cond (rdebug-secondary-buffer + (cond ((eq win orig-win) + ;; If the user issued the command inside a + ;; secondary window, use that window. + 5) + ((and (member name '("variables" "watch")) + (memq major-mode '(rdebug-variables-mode + rdebug-watch-mode))) + ;; Let "Watch" and "Variables" switch content. + 4) + (t + ;; Any other secondary window. + 3))) + ((eq major-mode 'ruby-mode) + ;; Avoid source windows. + 0) + ((eq major-mode 'gud-mode) + ;; Avoid the debugger shell window. + 1) + (t + ;; Just any other window. + 2))))) + + +(defun rdebug-display-secondary-buffer (name) + "Display one of the rdebug secondary buffers. +If the buffer doesn't exist, do nothing. If the buffer is already +displayed, switch to it. Otherwise if the current buffer is a +secondary buffer, bury it replacing with the requested +buffer. Failing that, if there is secondary buffer visible, that +is replaced instead. And finally failing all of the preceding, +we'll just pick a visible buffer to bury and replace." + (let* ((buf-name (rdebug-get-secondary-buffer-name name)) + (buf (get-buffer buf-name)) + (orig-win (selected-window))) + (if (null buf) + (message "Buffer %s not found" buf-name) + ;; Find a suitable window to display the buffer in. + (let ((win (get-buffer-window buf (selected-frame)))) + (if win + ;; Buffer already displayed, switch to it. + (select-window win) + ;; + (let ((candidate nil) + (candidate-score -1)) + (dolist (win (window-list (selected-frame))) + (let ((score (rdebug-pick-secondary-window-categorize + win name orig-win))) + (if (> score candidate-score) + (progn + (setq candidate win) + (setq candidate-score score))))) + (select-window candidate))))) + (switch-to-buffer buf))) + + +;; Note: The generic `gud' framework contains special code to handle +;; this for GDB (see `gud-display-line') which we, unfortuately can't +;; use. Instead, we call `rdebug-pick-source-window' from +;; `gud-rdebug-marker-filter'. When gud becomes more generic we could +;; hopefully solve this in another way. +;; +;; The machanism is that `rdebug-pick-source-window' displays the +;; source file in the window of our choice, and gud kindly re-uses +;; that window. + + +(defun rdebug-display-source-window-categorize (win) + "Return how suitable this window WIN is to display the source buffer. +The higher score the better." + (let ((buffer (window-buffer win))) + (cond ((eq buffer gud-comint-buffer) + 0) + ((buffer-local-value 'rdebug-secondary-buffer buffer) + 1) + ((eq (buffer-local-value 'major-mode buffer) 'ruby-mode) + 3) ; Pick me! Pick me! + (t + 2)))) + +(defun rdebug-display-pick-source-window () + "Return the window that should get replaced by the source window." + (rdebug-debug-enter "rdebug-display-pick-source-window" + (let ((candidate nil) + (candidate-score -1)) + (dolist (win (window-list (selected-frame))) + (let ((score + (rdebug-display-source-window-categorize win))) + (if (> score candidate-score) + (progn + (setq candidate win) + (setq candidate-score score))))) + candidate))) + +(defun rdebug-frame-source-buffer (frame) + "Return the buffer corresponding to the source file given in FRAME, or nil if none." + (and frame + gud-comint-buffer + (save-current-buffer + (set-buffer gud-comint-buffer) + (gud-find-file (car frame))))) + + +(defun rdebug-current-source-buffer () + "Return the latest source buffer, or nil." + (or (rdebug-frame-source-buffer gud-last-frame) + (rdebug-frame-source-buffer gud-last-last-frame))) + + +(defun rdebug-display-source-buffer () + "Display the current source buffer." + (interactive) + (rdebug-debug-enter "rdebug-display-source-buffer" + (let ((buffer (rdebug-current-source-buffer)) + (last-buffer (rdebug-frame-source-buffer gud-last-last-frame))) + (if buffer + (let ((window + (or + ;; Buffer is already visible, re-use the window. + (get-buffer-window buffer) + ;; Re-use the last window + (and last-buffer + (get-buffer-window last-buffer)) + ;; Find a non-rdebug window. + (rdebug-display-pick-source-window)))) + (select-window window) + (switch-to-buffer buffer)))))) + + +(defun rdebug-pick-source-window () + "Display the source file, but do not switch window." + (save-selected-window + (rdebug-display-source-buffer))) + + +(defun rdebug-display-source-buffer-resync () + "Resync output and display the source buffer." + (interactive) + (call-interactively 'gud-source-resync) + (rdebug-display-source-buffer)) + + +(defun rdebug-delete-frame-or-window () + "Delete frame if there is only one window. Otherwise delete the window." + (interactive) + (if (one-window-p) (delete-frame) + (delete-window))) + +(defun rdebug-goto-entry-try (str) + "See if thre is an entry with number STR. If not return nil." + (goto-char (point-min)) + (if (re-search-forward (concat "^[^0-9]*\\(" str "\\)[^0-9]") nil t) + (progn + (goto-char (match-end 1)) + t) + nil)) + + +;; The following is split in two to facilitate debugging. +(defun rdebug-goto-entry-n-internal (keys) + (if (and (stringp keys) + (= (length keys) 1)) + (progn + (setq rdebug-goto-entry-acc (concat rdebug-goto-entry-acc keys)) + ;; Try to find the longest suffix. + (let ((acc rdebug-goto-entry-acc) + (p (point))) + (while (not (string= acc "")) + (if (not (rdebug-goto-entry-try acc)) + (setq acc (substring acc 1)) + (setq p (point)) + ;; Break loop. + (setq acc ""))) + (goto-char p))) + (message "`rdebug-goto-entry-n' must be bound to a number key"))) + + +(defun rdebug-goto-entry-n () + "Go to an entry number. + +Breakpoints, Display expressions and Stack Frames all have +numbers associated with them which are distinct from line +numbers. In a secondary buffer, this function is usually bound to +a numeric key which will position you at that entry number. To +go to an entry above 9, just keep entering the number. For +example, if you press 1 and then 9, you should jump to entry +1 (if it exists) and then 19 (if that exists). Entering any +non-digit will start entry number from the beginning again." + (interactive) + (if (not (eq last-command 'rdebug-goto-entry-n)) + (setq rdebug-goto-entry-acc "")) + (rdebug-goto-entry-n-internal (this-command-keys))) + + +;; ------------------------------------------------------------------- +;; The end. +;; + +(provide 'rdebug-secondary) + +;;; Local variables: +;;; eval:(put 'rdebug-debug-enter 'lisp-indent-hook 1) +;;; End: + +;;; rdebug-secondary.el ends here diff --git a/emacs/.svn/text-base/rdebug-shortkey.el.svn-base b/emacs/.svn/text-base/rdebug-shortkey.el.svn-base new file mode 100644 index 0000000..42bbbb7 --- /dev/null +++ b/emacs/.svn/text-base/rdebug-shortkey.el.svn-base @@ -0,0 +1,175 @@ +;;; rdebug-watch.el --- Ruby debugger (short and simple) key bindings +;;; and minor mode. + +;; Copyright (C) 2008 Rocky Bernstein (rocky@gnu.org) +;; Copyright (C) 2008 Anders Lindgren + +;; $Id$ + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; This file contains code which add short simple key bindings to buffers +;; which are part of an part of an rdebug session. It also handles +;; minor mode setting of these buffers. + +;;; Code: +;; ------------------------------------------------------------------- +;; Source short key mode. +;; +;; When this minor mode is active and the debugger is running, the +;; source window displaying the current debugger frame is marked as +;; read-only and the short keys of the secondary windows can be used, +;; for example, you can use the space-bar to single-step the program. + +;; Implementation note: +;; +;; This is presented to the user as one global minor mode. However, +;; under the surface the real work is done by another, non-global, +;; minor mode named "local short key mode". This is activated and +;; deactivated appropriately by the Rdebug filter functions. + +;; Implementation note: This is the user-level command. It only +;; controls if `rdebug-internal-short-key-mode' should be activated or +;; not. + +(require 'rdebug-source) + +(define-minor-mode rdebug-short-key-mode + "When enabled, short keys can be used in source buffers in `rdebug'." + :group 'rdebug + :global t + :init-value nil + ;; Unless the debugger is running, activating this doesn't do + ;; anything. + (if (featurep 'rdebug-core) + (with-no-warnings + (rdebug-short-key-mode-maybe-activate)))) + +(defvar rdebug-internal-short-key-mode-map + (let ((map (make-sparse-keymap))) + (define-key map "b" 'gud-break) + (define-key map "t" 'rdebug-toggle-source-breakpoint-enabled) + (define-key map [insert] 'rdebug-short-key-mode) + ;;(define-key map "p" 'gud-print) + (rdebug-populate-secondary-buffer-map-plain map) + map) + "Keymap used in `rdebug-internal-short-key-mode'.") + +(defvar rdebug-original-read-only nil + "The value `buffer-read-only' should be restored to after short key mode.") + +;; `define-minor-mode' does not set if the mode was on or off prior to being called. +(defvar rdebug-internal-short-key-mode-previous-state nil + "Used to determine when 'rdebug-internal-short-key-mode' changed state.") + +;; Implementation note: This is the mode that does all the work, it's +;; local to the buffer that is affected. +(define-minor-mode rdebug-internal-short-key-mode + "Minor mode with short keys for source buffers for the `rdebug' debugger. +The buffer is read-only when the minor mode is active. + +Note that this is for internal use only, please use the global +mode `rdebug-short-key-mode'. + +\\{rdebug-internal-short-key-mode-map}" + :group 'rdebug + :global nil + :init-value nil + :lighter " ShortKeys" + :keymap rdebug-internal-short-key-mode-map + (make-local-variable 'rdebug-original-read-only) + (make-local-variable 'rdebug-internal-short-key-mode-previous-state) + ;; Ensure action only is performed when the state actually is toggled. + (unless (eq rdebug-internal-short-key-mode-previous-state + rdebug-internal-short-key-mode) + (if rdebug-internal-short-key-mode + ;; Mode is being turned on. + (progn + (setq rdebug-original-read-only buffer-read-only) + (setq buffer-read-only t)) + ;; Mode is being turned off. + (setq buffer-read-only rdebug-original-read-only)) + ;; Save the current state, so we can determine when the state is + ;; toggled in the future. + (setq rdebug-internal-short-key-mode-previous-state + rdebug-internal-short-key-mode))) + +(defun rdebug-buffer-killed-p (buffer) + "Return t if BUFFER is killed." + (not (buffer-name buffer))) + +(defun rdebug-internal-short-key-mode-on () + "Turn on `rdebug-internal-short-key-mode' in the current debugger frame." + (rdebug-debug-enter "rdebug-internal-short-key-mode-on" + (save-current-buffer + (if (and gud-comint-buffer + (not (rdebug-buffer-killed-p gud-comint-buffer))) + (set-buffer gud-comint-buffer)) + (let ((frame (or gud-last-frame + gud-last-last-frame))) + (if (and frame + rdebug-short-key-mode) + (ignore-errors + ;; `gud-find-file' calls `error' if it doesn't find the file. + (let ((buffer (gud-find-file (car frame)))) + (save-current-buffer + (set-buffer buffer) + ;; Make gud-comint-buffer local + (if gud-comint-buffer + (make-local-variable 'gud-comint-buffer)) + (rdebug-internal-short-key-mode 1))))))))) + + +(defun rdebug-turn-on-short-key-mode () + "Turn on `rdebug-short-key-mode'. + +This function is designed to be used in a user hook, for example: + + (add-hook 'rdebug-mode-hook 'rdebug-turn-on-short-key-mode)" + (interactive) + (rdebug-short-key-mode 1)) + + +(defun rdebug-turn-off-short-key-mode () + "Turn off `rdebug-short-key-mode'." + (interactive) + (rdebug-short-key-mode -1)) + + +(defun rdebug-short-key-mode-maybe-activate () + (if rdebug-short-key-mode + (rdebug-internal-short-key-mode-on) + (rdebug-internal-short-key-mode-off))) + + +(defun rdebug-internal-short-key-mode-off () + "Turn off `rdebug-internal-short-key-mode' in all buffers." + (rdebug-debug-enter "rdebug-internal-short-key-mode-off" + (save-current-buffer + (dolist (buf (buffer-list)) + (set-buffer buf) + (when rdebug-internal-short-key-mode + (rdebug-internal-short-key-mode -1)))))) + +(provide 'rdebug-shortkey) + +;;; Local variables: +;;; eval:(put 'rdebug-debug-enter 'lisp-indent-hook 1) +;;; End: + +;;; rdebug-shortkey.el ends here diff --git a/emacs/.svn/text-base/rdebug-source.el.svn-base b/emacs/.svn/text-base/rdebug-source.el.svn-base new file mode 100644 index 0000000..b3cb7e9 --- /dev/null +++ b/emacs/.svn/text-base/rdebug-source.el.svn-base @@ -0,0 +1,568 @@ +;;; rdebug-source.el --- Ruby debugger user interface. + +;; Copyright (C) 2006, 2007, 2008 Rocky Bernstein (rocky@gnu.org) +;; Copyright (C) 2007, 2008 Anders Lindgren + +;; $Id$ + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; See the manual and the file `rdebug.el' for more information. + +;; This file is loaded when a Ruby source buffer is loaded. It +;; contains, among else, the Debugger menu. + +;;; Code: + +;; ------------------------------------------------------------------- +;; Consistency checks. +;; + +(if (< emacs-major-version 22) + (error + "Rdebug needs at least Emacs 22 or greater - you have version %d." + emacs-major-version)) + + +;; ------------------------------------------------------------------- +;; Dependencies. +;; + +(require 'cl) + +(require 'gud) ; For gud-key-prefix, sigh... +(require 'rdebug) +(require 'rdebug-vars) + + +;; ------------------------------------------------------------------- +;; Key bindings +;; + +(defun rdebug-populate-common-keys-standard (map) + "Bind the basic debugger key layout used by many debuggers. + +\\{rdebug-example-map-standard}" + (define-key map [f5] 'gud-cont) + (define-key map [S-f5] 'rdebug-quit) + (define-key map [f9] 'rdebug-toggle-source-breakpoint) + (define-key map [C-f9] 'rdebug-toggle-source-breakpoint-enabled) + (define-key map [f10] 'rdebug-next) + (define-key map [f11] 'rdebug-step) + (define-key map [S-f11] 'gud-finish)) + + +;; TODO: Verify and complement. +(defun rdebug-populate-common-keys-eclipse (map) + "Bind the basic debugger key layout used by Eclipse. + +\\{rdebug-example-map-eclipse}" + ;;(define-key map [] 'gud-cont) + ;;(define-key map [] 'rdebug-quit) + (define-key map [S-C-b] 'rdebug-toggle-source-breakpoint) + (define-key map [f6] 'rdebug-next) + (define-key map [f5] 'rdebug-step) + (define-key map [f7] 'gud-finish)) + + +;; TODO: Verify and complement. +(defun rdebug-populate-common-keys-netbeans (map) + "Bind the basic debugger key layout used by NetBeans. + +\\{rdebug-example-map-netbeans}" + ;;(define-key map [] 'gud-cont) + ;;(define-key map [] 'rdebug-quit) + ;; F4 - Run to cursor. + (define-key map [S-f8] 'rdebug-toggle-source-breakpoint) + (define-key map [f8] 'rdebug-next) + (define-key map [f7] 'rdebug-step) + (define-key map [M-S-f7] 'gud-finish)) + + +;; Note: This is only used in doc-strings. +(defvar rdebug-example-map-standard + (let ((map (make-sparse-keymap))) + (rdebug-populate-common-keys-standard map) + map) + "Rdebug Standard common keymap used only in doc-string.") + + +(defvar rdebug-example-map-eclipse + (let ((map (make-sparse-keymap))) + (rdebug-populate-common-keys-eclipse map) + map) + "Rdebug Eclipse compatibility common keymap used only in doc-string.") + + +(defvar rdebug-example-map-netbeans + (let ((map (make-sparse-keymap))) + (rdebug-populate-common-keys-netbeans map) + map) + "Rdebug NetBeans compatibility common keymap used only in doc-string.") + + +(defun rdebug-populate-common-keys (map) + "Define the keys that are used by all debugger windows, even by the source. + +The variable `rdebug-populate-common-keys-function' controls the layout." + (define-key map "\C-x\C-a\C-q" 'rdebug-short-key-mode) + (if rdebug-populate-common-keys-function + (funcall rdebug-populate-common-keys-function map))) + + +(defun rdebug-populate-digit-keys (map) + (define-key map "0" 'rdebug-goto-entry-n) + (define-key map "1" 'rdebug-goto-entry-n) + (define-key map "2" 'rdebug-goto-entry-n) + (define-key map "3" 'rdebug-goto-entry-n) + (define-key map "4" 'rdebug-goto-entry-n) + (define-key map "5" 'rdebug-goto-entry-n) + (define-key map "6" 'rdebug-goto-entry-n) + (define-key map "7" 'rdebug-goto-entry-n) + (define-key map "8" 'rdebug-goto-entry-n) + (define-key map "9" 'rdebug-goto-entry-n)) + + +;; ------------------------------------------------------------------- +;; Menu support. +;; + + +;; Note: We want the key binding to show in the menu. However, our +;; situation is a little bit complex: +;; +;; 1) We want the binding of the `common' man (i.e. the function key +;; the user has selected.) +;; +;; 2) We want this even when the menu is disabled and the key isn't +;; bound, typically when the debugger isn't running. +;; +;; This has been solved by setting up an explicit ":keys" properly. +(defun rdebug-menu-item (common-map name cmd &rest args) + "Return a menu item entry with the correct key bindings. + +A command can be bound to a number of different key sequences. If +the rdebug common map contains a binding it is displayed in the +menu. (The common map typically contains function key bindings.)" + (let ((key-binding (where-is-internal cmd (list common-map) t)) + (hint '())) + (if key-binding + (setq hint (list :keys (key-description key-binding)))) + (append (list 'menu-item name cmd) + hint + args))) + + +;; Note, we re-populate the menus of the different minor and major +;; modes. The reason is that Emacs caches the key bindings, which +;; means that wrong ones are shown when buffers are changed. + +;; Remember, all menu items are added in the reverse order! + +(defun rdebug-populate-debugger-menu (map) + "Populate the Rdebug 'Debugger' menu." + (let ((menu (make-sparse-keymap)) + (common-map (make-sparse-keymap))) + ;; Use a simple common map to find the best key sequence to + ;; display in menu. + (rdebug-populate-common-keys common-map) + + (define-key map [menu-bar debugger] (cons "Debugger" menu)) + + (define-key menu [break-delete] + (rdebug-menu-item common-map "Enable/disable breakpoint" + 'rdebug-toggle-source-breakpoint-enabled + :enable '(get-buffer-process gud-comint-buffer))) + + (define-key menu [break] + (rdebug-menu-item common-map "Toggle breakpoint" + 'rdebug-toggle-source-breakpoint + :enable '(get-buffer-process gud-comint-buffer))) + + (define-key menu [finish] + (rdebug-menu-item common-map "Step out" 'gud-finish + :enable '(get-buffer-process gud-comint-buffer))) + + (define-key menu [step] + (rdebug-menu-item common-map "Step into" 'rdebug-step + :enable '(get-buffer-process gud-comint-buffer))) + + (define-key menu [next] + (rdebug-menu-item common-map "Step over" 'rdebug-next + :enable '(get-buffer-process gud-comint-buffer))) + + (define-key menu [cont] + (rdebug-menu-item common-map "Continue" 'rdebug-continue + :enable '(get-buffer-process gud-comint-buffer))) + + (define-key map [menu-bar debugger line1] '(menu-item "--")) + + (define-key menu [stop] + (rdebug-menu-item + common-map "Stop the debugger" 'rdebug-quit + :enable '(get-buffer-process gud-comint-buffer))) + + (define-key menu [start] + (rdebug-menu-item common-map "Start the debugger" 'rdebug)) + + (define-key map [menu-bar debugger line2] '(menu-item "--")) + + ;; -------------------- + ;; The "Options" submenu. + + (let ((submenu (make-sparse-keymap))) + (define-key menu [options] (cons "Options" submenu))) + + (define-key map [menu-bar debugger options customize] + (rdebug-menu-item common-map + "Customize Rdebug" 'rdebug-customize)) + + (define-key map [menu-bar debugger options line1] '(menu-item "--")) + + + + ;; ---------------- + ;; The "short key" toggle. + + (define-key map [menu-bar debugger options short-key-mode] + (rdebug-menu-item common-map + "Short keys in source" 'rdebug-short-key-mode + :button + '(:toggle + . rdebug-short-key-mode))) + + (define-key map [menu-bar debugger options line2] '(menu-item "--")) + + ;; ---------------- + ;; Separate I/O buffer. + + (define-key map [menu-bar debugger options io-buffer] + (rdebug-menu-item common-map + "Separate I/O buffer" + 'rdebug-toggle-use-separate-io-buffer + :button + '(:toggle + . rdebug-use-separate-io-buffer))) + + ;; -------------------- + ;; The optional secondary windows submenu. + + + ;; Placeholder used when populating the menu of the secondary buffers. + (define-key menu [placeholder] nil) + + ;; -------------------- + ;; The "Window Layout" submenu. + (let ((submenu (make-sparse-keymap))) + (define-key menu [layout] (cons "Window Layout" submenu))) + + ;; ---------------- + ;; The "Window Layout" submenu. + + + ;; TODO: The following is a somewhat clumsy implementation. Maybe we can + ;; automatically generate the entries, or use the `dynamic' menu kind? + ;; + ;; Also, there might be other situations where the list might be + ;; handy, e.g. completion. + (let ((predefined '(rdebug-window-layout-standard + rdebug-window-layout-no-shell + rdebug-window-layout-conservative + rdebug-window-layout-stack-of-windows + rdebug-window-layout-rocky + rdebug-window-layout-rocky2))) + + (define-key map [menu-bar debugger layout other] + (rdebug-menu-item + common-map + "Other" + 'rdebug-set-window-layout + :button + `(:radio + . (not (memq rdebug-window-layout-function (quote ,predefined)))))) + + (define-key map [menu-bar debugger layout rocky] + (rdebug-menu-item + common-map + "Rocky's Own" + (lambda () + (interactive) + (rdebug-set-window-layout 'rdebug-window-layout-rocky)) + :button + '(:radio + . (eq rdebug-window-layout-function + 'rdebug-window-layout-rocky)))) + + (define-key map [menu-bar debugger layout rocky2] + (rdebug-menu-item + common-map + "Rocky II" + (lambda () + (interactive) + (rdebug-set-window-layout 'rdebug-window-layout-rocky2)) + :button + '(:radio + . (eq rdebug-window-layout-function + 'rdebug-window-layout-rocky2)))) + + (define-key map [menu-bar debugger layout stack] + (rdebug-menu-item + common-map + "Stack of Windows" + (lambda () + (interactive) + (rdebug-set-window-layout 'rdebug-window-layout-stack-of-windows)) + :button + '(:radio + . (eq rdebug-window-layout-function + 'rdebug-window-layout-stack-of-windows)))) + + (define-key map [menu-bar debugger layout conservative] + (rdebug-menu-item + common-map + "Conservative" + (lambda () + (interactive) + (rdebug-set-window-layout 'rdebug-window-layout-conservative)) + :button + '(:radio + . (eq rdebug-window-layout-function + 'rdebug-window-layout-conservative)))) + + (define-key map [menu-bar debugger layout no-shell] + (rdebug-menu-item + common-map + "No Shell" + (lambda () + (interactive) + (rdebug-set-window-layout 'rdebug-window-layout-no-shell)) + :button + '(:radio + . (eq rdebug-window-layout-function + 'rdebug-window-layout-no-shell)))) + + (define-key map [menu-bar debugger layout standard] + (rdebug-menu-item + common-map + "Standard" + (lambda () + (interactive) + (rdebug-set-window-layout 'rdebug-window-layout-standard)) + :button + '(:radio + . (eq rdebug-window-layout-function + 'rdebug-window-layout-standard))))) + + (define-key map [menu-bar debugger layout line3] '(menu-item "--")) + + (define-key map [menu-bar debugger layout initial] + (rdebug-menu-item common-map + "Restore Debugger Layout" + 'rdebug-restore-debugger-window-layout + :enable '(fboundp 'rdebug-restore-debugger-window-layout))) + + (define-key map [menu-bar debugger layout line1] '(menu-item "--")) + + ;; Note: It seems as though :enable doesn't work when :button is used. + (define-key map [menu-bar debugger layout debugger] + (rdebug-menu-item common-map "Current Debugger Layout" + 'rdebug-display-debugger-window-configuration + :button + '(:radio + . (eq rdebug-window-configuration-state 'debugger)))) + + (define-key map [menu-bar debugger layout original] + (rdebug-menu-item common-map "Original Layout" + 'rdebug-display-original-window-configuration + :button + '(:radio + . (eq rdebug-window-configuration-state 'original)))) + + ;; -------------------- + ;; The "View" submenu. + (let ((submenu (make-sparse-keymap))) + (define-key menu [view] (cons "View" submenu))) + + (define-key map [menu-bar debugger view output] + (rdebug-menu-item common-map "Output" 'rdebug-display-output-buffer + :enable '(get-buffer-process gud-comint-buffer))) + + (define-key map [menu-bar debugger view watch] + (rdebug-menu-item common-map "Watch" 'rdebug-display-watch-buffer + :enable '(get-buffer-process gud-comint-buffer))) + + (define-key map [menu-bar debugger view stack] + (rdebug-menu-item common-map "Stack-Frame trace" + 'rdebug-display-frame-buffer + :enable '(get-buffer-process gud-comint-buffer))) + + (define-key map [menu-bar debugger view shell] + (rdebug-menu-item common-map "Debugger Shell" 'rdebug-display-cmd-buffer + :enable '(get-buffer-process gud-comint-buffer))) + + (define-key map [menu-bar debugger view variables] + (rdebug-menu-item common-map "Variables" 'rdebug-display-variables-buffer + :enable '(get-buffer-process gud-comint-buffer))) + + (define-key map [menu-bar debugger view breakpoints] + (rdebug-menu-item common-map + "Breakpoints" 'rdebug-display-breakpoints-buffer + :enable '(get-buffer-process gud-comint-buffer))) + + (define-key map [menu-bar debugger view source] + (rdebug-menu-item common-map + "Source" 'rdebug-display-source-buffer + :enable '(get-buffer-process gud-comint-buffer))) + menu)) + + +;; ----------------------------------------------- +;; Key bindings and menu for secondary buffers. +;; + +(defun rdebug-populate-secondary-buffer-map-plain (map) + "Bind the plain keys used in rdebug secondary buffers. + +This does not menus or prefix keys." + ;; Keys to view other buffers. + (let ((prefix-map (make-sparse-keymap))) + (define-key map "?" 'rdebug-display-secondary-window-help-buffer) + (define-key map "B" 'rdebug-display-breakpoints-buffer) + (define-key map "C" 'rdebug-display-cmd-buffer) + (define-key map "E" 'rdebug-display-error-buffer) + (define-key map "F" 'rdebug-display-frame-buffer) + (define-key map "I" 'rdebug-display-info-buffer) + (define-key map "O" 'rdebug-display-output-buffer) + (define-key map "S" 'rdebug-display-source-buffer) + (define-key map "V" 'rdebug-display-variables-buffer) + (define-key map "W" 'rdebug-display-watch-buffer) + ;; Common debugger commands. + (define-key map " " 'rdebug-step) + (define-key map "_" 'rdebug-set-stepping-prefix) + (define-key map "+" 'rdebug-set-stepping-prefix) + (define-key map "-" 'rdebug-set-stepping-prefix) + (define-key map "<" 'rdebug-newer-frame) + (define-key map ">" 'rdebug-older-frame) + ;; (define-key map "a" 'gud-args) + ;; (define-key map "b" 'gud-break) + (define-key map "c" 'rdebug-continue) + ;; (define-key map "d" 'gud-remove) + (define-key map "f" 'gud-finish) + (define-key map "n" 'rdebug-next) + (define-key map "p" prefix-map) + (define-key map "q" 'rdebug-quit) + (define-key map "r" 'rdebug-restart) + (define-key map "R" 'rdebug-restart) + (define-key map "s" 'rdebug-step) + (define-key map [M-down] 'rdebug-locring-newer) + (define-key map [M-up] 'rdebug-locring-older) + (define-key map [M-S-down] 'rdebug-locring-newest) + (define-key map [M-S-up] 'rdebug-locring-oldest) + (define-key map [mouse-3] 'rdebug-variables-pretty-print-mouse) + (define-key prefix-map "l" 'rdebug-print-list-region) + (define-key prefix-map "p" 'rdebug-pretty-print-region) + (define-key prefix-map "s" 'rdebug-print-sorted-region) + )) + + +;; ------------------------------------------------------------------- +;; Window layout. +;; + +;; This function is intended for the Options submenu. +(defun rdebug-set-window-layout (func) + "Set and, if the debugger is running, display the window layout." + (interactive "aWindow layout function: ") + (setq rdebug-window-layout-function func) + (if gud-comint-buffer + (with-no-warnings + (rdebug-setup-windows)))) + + +;; ------------------------------------------------------------------- +;; The source buffer rdebug support mode. +;; +;; This is a minor mode that is active in Ruby source buffers. It +;; provides the menu and, when the debugger is active, the debugger +;; key bindings. + +(defvar rdebug-debugger-support-minor-mode-map-when-deactive + (let ((map (make-sparse-keymap)) + (prefix-map (make-sparse-keymap))) + (rdebug-populate-debugger-menu map) + (rdebug-populate-secondary-buffer-map-plain prefix-map) + (define-key map gud-key-prefix prefix-map) + map) + "Keymap used by rdebugs support minor mode when the debugger is active.") + +(defvar rdebug-debugger-support-minor-mode-map-when-active + (let ((map (make-sparse-keymap)) + (prefix-map (make-sparse-keymap))) + (rdebug-populate-debugger-menu map) + (rdebug-populate-secondary-buffer-map-plain prefix-map) + (define-key prefix-map [insert] 'rdebug-short-key-mode) + (define-key map gud-key-prefix prefix-map) + (rdebug-populate-common-keys map) + map) + "Keymap used by rdebugs support minor mode when the debugger not active.") + + +(define-minor-mode rdebug-debugger-support-minor-mode + "Minor mode active in source buffers that use the `rdebug' Ruby debugger." + :group rdebug + :global nil + :init-value nil + :keymap rdebug-debugger-support-minor-mode-map-when-deactive + (setq mode-line-process (and rdebug-debugger-support-minor-mode + 'rdebug-mode-line-process))) + + +;;;###autoload +(defun rdebug-turn-on-debugger-support () + "Enable extra source buffer support for the `rdebug' Ruby debugger. + +This includes a 'Debugger' menu and special key bindings when the +debugger is active." + (rdebug-debugger-support-minor-mode 1)) + + +;; ------------------------------------------------------------------- +;; Use separate I/O buffer +;; + +(defun rdebug-toggle-use-separate-io-buffer () + "Toggle `rdebug-use-separate-io-buffer'. +This is used by the menu." + (interactive) + (setq rdebug-use-separate-io-buffer (not rdebug-use-separate-io-buffer)) + (if (interactive-p) + (message "Issue M-x rdebug-restore-debugger-window-layout \ +RET to update display."))) + + +;; ------------------------------------------------------------------- +;; The end. +;; + +(provide 'rdebug-source) + +;;; Local variables: +;;; eval:(put 'rdebug-debug-enter 'lisp-indent-hook 1) +;;; End: + +;;; rdebug-source.el ends here diff --git a/emacs/.svn/text-base/rdebug-track.el.svn-base b/emacs/.svn/text-base/rdebug-track.el.svn-base new file mode 100644 index 0000000..78b0523 --- /dev/null +++ b/emacs/.svn/text-base/rdebug-track.el.svn-base @@ -0,0 +1,392 @@ +;;; rdebug-track.el --- Tracking the Ruby debugger from a shell +;; $Id$ + +;; Copyright (C) 2006, 2007, 2008 Rocky Bernstein (rocky@gnu.org) +;; Copyright (C) 2007, 2008 Anders Lindgren +;; Modified from python-mode in particular the part: +;; pdbtrack support contributed by Ken Manheimer, April 2001. + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; See the manual and the file `rdebug.el' for more information. + +;; `rdebug-track-mode' allows access to full debugger user interface +;; for Ruby debugger sessions started in a standard shell window. +;; `turn-on-rdebug-track-mode' turns the mode on and +;; `turn-off-rdebug-track-mode' turns it off. +;; +;;; Customization: +;; `rdebug-track' sets whether file tracking is done by the shell prompt. +;; `rdebug-track-minor-mode-string' sets the mode indicator to show that +;; tracking is in effect. +;; + +;;; Code: + +;; ------------------------------------------------------------------- +;; Customizable variables. +;; + +(defgroup rdebug-track nil + "Ruby debug and rdebug file tracking by watching the shell prompt." + :prefix "rdebug-track" + :group 'shell) + +(defcustom rdebug-track-do-tracking-p nil + "*Controls whether the rdebug-track feature is enabled or not. +When non-nil, rdebug-track is enabled in all comint-based buffers, +e.g. shell buffers and the *Ruby* buffer. When using rdebug to debug a +Ruby program, rdebug-track notices the rdebug prompt and displays the +source file and line that the program is stopped at, much the same way +as gud-mode does for debugging C programs with gdb." + :type 'boolean + :group 'rdebug) +(make-variable-buffer-local 'rdebug-track-do-tracking-p) + +(defcustom rdebug-track-minor-mode-string " rdebug" + "*String to use in the minor mode list when rdebug-track is enabled." + :type 'string + :group 'rdebug) + + +;; ------------------------------------------------------------------- +;; Variables. +;; + +(defvar gud-rdebug-history nil + "History of argument lists passed to rdebug.") + +;; rdebug-track constants +(defconst rdebug-track-stack-entry-regexp + "^(\\([-a-zA-Z0-9_/.]*\\):\\([0-9]+\\)):[ \t]?\\(.*\n\\)" + "Regular expression rdebug-track uses to find a stack trace entry.") + +(defconst rdebug-track-track-range 10000 + "Max number of characters from end of buffer to search for stack entry.") + + +;; ------------------------------------------------------------------- +;; Dependencies. +;; + +(require 'comint) +(require 'custom) +(require 'cl) +(require 'compile) +(require 'gud) +(require 'shell) +(require 'rdebug-breaks) +(require 'rdebug-cmd) +(require 'rdebug-core) + + +;; ------------------------------------------------------------------- +;; Rdebug track -- support for attaching the `rdebug' ruby debugger to +;; a process running in a shell buffer. +;; + +(defvar rdebug-track-is-tracking-p t) + +(defun rdebug-track-overlay-arrow (activation) + "Activate or de arrow at beginning-of-line in current buffer." + ;; This was derived/simplified from edebug-overlay-arrow + (cond (activation + (setq overlay-arrow-position (make-marker)) + (setq overlay-arrow-string "=>") + (set-marker overlay-arrow-position (point) (current-buffer)) + (setq rdebug-track-is-tracking-p t)) + (rdebug-track-is-tracking-p + (setq overlay-arrow-position nil) + (setq rdebug-track-is-tracking-p nil)) + )) + +(defun rdebug-track-track-stack-file (text) + "Show the file indicated by the rdebug stack entry line, in a separate window. +Activity is disabled if the buffer-local variable +`rdebug-track-do-tracking-p' is nil. + +We depend on the rdebug input prompt matching `rdebug-input-prompt-regexp' +at the beginning of the line." + ;; Instead of trying to piece things together from partial text + ;; (which can be almost useless depending on Emacs version), we + ;; monitor to the point where we have the next rdebug prompt, and then + ;; check all text from comint-last-input-end to process-mark. + ;; + ;; Also, we're very conservative about clearing the overlay arrow, + ;; to minimize residue. This means, for instance, that executing + ;; other rdebug commands wipe out the highlight. You can always do a + ;; 'where' (aka 'w') command to reveal the overlay arrow. + (rdebug-debug-enter "rdebug-track-track-stack-file" + (let* ((origbuf (current-buffer)) + (currproc (get-buffer-process origbuf))) + + (if (not (and currproc rdebug-track-do-tracking-p)) + (rdebug-track-overlay-arrow nil) + ;;else + (let* ((procmark (process-mark currproc)) + (block-start (max comint-last-input-end + (- procmark rdebug-track-track-range))) + (block-str (buffer-substring block-start procmark)) + target target_fname target_lineno target_buffer) + + (if (not (string-match rdebug-input-prompt-regexp block-str)) + (rdebug-track-overlay-arrow nil) + ;;else + (setq target (rdebug-track-get-source-buffer block-str)) + + (if (stringp target) + (rdebug-debug-message "rdebug-track: %s" target) + ;;else + (gud-rdebug-marker-filter block-str) + (setq target_lineno (car target)) + (setq target_buffer (cadr target)) + (setq target_fname (buffer-file-name target_buffer)) + (setq gud-last-frame (cons target_fname target_lineno)) + (switch-to-buffer-other-window target_buffer) + (goto-line target_lineno) + (rdebug-debug-message "rdebug-track: line %s, file %s" + target_lineno target_fname) + (rdebug-track-overlay-arrow t) + (rdebug-set-frame-top-arrow (current-buffer)) + (set (make-local-variable 'gud-comint-buffer) origbuf) + (set (make-local-variable 'gud-delete-prompt-marker) + (make-marker)) + (pop-to-buffer origbuf t) + (rdebug-locring-add gud-last-frame + rdebug-source-location-ring)) + + ;; Delete processed annotations from buffer. + (save-excursion + (let ((annotate-start) + (annotate-end (point-max))) + (goto-char block-start) + (while (re-search-forward + rdebug-annotation-start-regexp annotate-end t) + (let* ((start (match-beginning 0)) + (end (match-end 0)) + (name (or (match-string 1) "source"))) + (cond ((string= name "prompt\n") + (delete-region (- start 1) end)) + ((string= name "pre-prompt\n") + (delete-region start end)) + ((string= name "error-begin\n") + (delete-region start end)) + ((re-search-forward rdebug-annotation-end-regexp + annotate-end t) + (delete-region start (point))) + (t (forward-line))))))) + )))))) + +(defun rdebug-track-get-source-buffer (block-str) + "Return line and buffer of code indicated by block-str's traceback text. + +We look first to visit the file indicated in the trace. + +Failing that, we look for the most recently visited ruby-mode buffer +with the same name or having having the named function. + +If we're unable find the source code we return a string describing the +problem as best as we can determine." + + (if (not (string-match rdebug-position-regexp block-str)) + "line number cue not found" + ;;else + (let* ((filename (match-string rdebug-marker-regexp-file-group block-str)) + (lineno (string-to-number + (match-string rdebug-marker-regexp-line-group block-str))) + funcbuffer) + + (cond ((file-exists-p filename) + (list lineno (find-file-noselect filename))) + + ((= (elt filename 0) ?\<) + (format "(Non-file source: '%s')" filename)) + + (t (format "Not found: %s" filename)))))) + + + +;; ----------------------------------------------- +;; Rdebug track mode +;; + + +(defcustom rdebug-track-mode-text " rdebug" + "*String to display in the mode line when rdebug-track mode is active. + +\(When the string is not empty, make sure that it has a leading space.)" + :tag "rdebug mode text" ; To separate it from `global-...' + :group 'rdebug + :type 'string) + +(define-minor-mode rdebug-track-mode + "Minor mode for tracking ruby debugging inside a process shell." + :init-value nil + ;; The indicator for the mode line. + :lighter rdebug-track-mode-text + ;; The minor mode bindings. + :global nil + :group 'rdebug + (rdebug-track-toggle-stack-tracking 1) + (setq rdebug-track-is-tracking-p t) + (local-set-key "\C-cg" 'rdebug-goto-traceback-line) + (local-set-key "\C-cG" 'rdebug-goto-dollarbang-traceback-line) + + (add-hook 'comint-output-filter-functions 'rdebug-track-track-stack-file) + (run-mode-hooks 'rdebug-track-mode-hook)) + + +(defun rdebug-track-toggle-stack-tracking (arg) + (interactive "P") + (if (not (get-buffer-process (current-buffer))) + (message "No process associated with buffer '%s'" (current-buffer)) + ;;else + ;; missing or 0 is toggle, >0 turn on, <0 turn off + (if (or (not arg) + (zerop (setq arg (prefix-numeric-value arg)))) + (setq rdebug-track-do-tracking-p (not rdebug-track-do-tracking-p)) + (setq rdebug-track-do-tracking-p (> arg 0))) + (message "%sabled rdebug's rdebug-track" + (if rdebug-track-do-tracking-p "En" "Dis")))) + + +;;;###autoload +(defun turn-on-rdebug-track-mode () + "Turn on rdebug-track mode. + +This function is designed to be added to hooks, for example: + (add-hook 'comint-mode-hook 'turn-on-rdebug-track-mode)" + (interactive) + (set (make-local-variable 'gud-last-last-frame) nil) + (set (make-local-variable 'gud-last-frame) nil) + (set (make-local-variable 'gud-comint-buffer) (current-buffer)) + + (set (make-local-variable 'gud-marker-filter) 'gud-rdebug-marker-filter) + (set (make-local-variable 'gud-minor-mode) 'rdebug) + (set (make-local-variable 'comint-prompt-regexp) (concat "^" rdebug-input-prompt-regexp)) + + (set (make-local-variable 'gud-find-file) 'gud-rdebug-find-file) + + (rdebug-command-initialization) + + (rdebug-track-mode 1)) + + +(defun turn-off-rdebug-track-mode () + "Turn off rdebug-track mode." + (interactive) + (setq rdebug-track-is-tracking-p nil) + + (rdebug-track-toggle-stack-tracking 0) + (if (local-variable-p 'gud-last-frame) + (setq gud-last-frame nil)) + (while (not (ring-empty-p rdebug-source-location-ring)) + (ring-remove rdebug-source-location-ring)) + (remove-hook 'comint-output-filter-functions + 'rdebug-track-track-stack-file)) + + +;; ----------------------------------------------- +;; The `attach' function. +;; + +(defun rdebug-track-attach (&optional name rename-shell) + "Do things to make the current process buffer work like a +rdebug command buffer. In particular, the buffer is renamed, +gud-mode is set, and rdebug-track-mode is turned on, among other +things. When `rdebug-many-windows' is non-nil, the initial debugger +window layout is used." + (interactive "sProgram name: ") + (rdebug-debug-enter "rdebug-set-windows" + (rdebug-set-window-configuration-state 'debugger t) + + ;; from rdebug-common-init + (gud-mode) + (set (make-local-variable 'gud-marker-filter) 'gud-rdebug-marker-filter) + (set (make-local-variable 'gud-minor-mode) 'rdebug) + (set (make-local-variable 'gud-last-frame) nil) + (set (make-local-variable 'gud-last-last-frame) nil) + + (set (make-local-variable 'gud-find-file) 'gud-rdebug-find-file) + (set-process-filter (get-buffer-process (current-buffer)) 'gud-filter) + (gud-set-buffer) + ;; + + (rdebug-track-mode 1) + (rdebug-command-initialization) + + (when name + (if rename-shell + (rename-buffer (format "*rdebug-cmd-%s*" gud-target-name))) + (setq gud-target-name name) + (setq gud-comint-buffer (current-buffer))) + + ;; Setup exit callback so that the original frame configuration + ;; can be restored. + (let ((process (get-buffer-process gud-comint-buffer))) + (when process + (unless (equal rdebug-line-width 120) + (gud-call (format "set width %d" rdebug-line-width))) + (set-process-sentinel process + 'rdebug-process-sentinel))) + + (when gud-last-frame + (setq gud-last-last-frame gud-last-frame)) + + ;; Add the buffer-displaying commands to the Gud buffer, + ;; FIXME: combine with code in rdebug-track.el; make common + ;; command buffer mode map. + (let ((prefix-map (make-sparse-keymap)) + (map (current-local-map))) + (define-key map [M-down] 'rdebug-locring-newer) + (define-key map [M-up] 'rdebug-locring-older) + (define-key map [M-S-down] 'rdebug-locring-newest) + (define-key map [M-S-up] 'rdebug-locring-oldest) + (define-key map gud-key-prefix prefix-map) + (define-key prefix-map "t" 'rdebug-goto-traceback-line) + (define-key prefix-map "!" 'rdebug-goto-dollarbang-traceback-line) + + (rdebug-populate-secondary-buffer-map-plain prefix-map)) + + (rdebug-populate-common-keys (current-local-map)) + (rdebug-populate-debugger-menu (current-local-map)) + + (set (make-local-variable 'comint-prompt-regexp) (concat "^" rdebug-input-prompt-regexp)) + (setq paragraph-start comint-prompt-regexp) + + (setcdr (assq 'rdebug-debugger-support-minor-mode minor-mode-map-alist) + rdebug-debugger-support-minor-mode-map-when-active) + + (gud-call "set annotate 3") + (gud-call "frame 0") + (when rdebug-many-windows + (rdebug-setup-windows)) + (run-hooks 'rdebug-mode-hook))) + + +;; ------------------------------------------------------------------- +;; The end. +;; + +(provide 'rdebug-track) + +;;; Local variables: +;;; eval:(put 'rdebug-debug-enter 'lisp-indent-hook 1) +;;; End: + +;;; rdebug-track.el ends here diff --git a/emacs/.svn/text-base/rdebug-varbuf.el.svn-base b/emacs/.svn/text-base/rdebug-varbuf.el.svn-base new file mode 100644 index 0000000..e94a8e7 --- /dev/null +++ b/emacs/.svn/text-base/rdebug-varbuf.el.svn-base @@ -0,0 +1,150 @@ +;;; rdebug-varbuf.el --- This file contains code dealing with the Ruby +;;; debugger's "variables" secondary buffer. + +;; Copyright (C) 2008 Rocky Bernstein (rocky@gnu.org) +;; Copyright (C) 2008 Anders Lindgren + +;; $Id$ + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; See the manual and the file `rdebug.el' for more information. + +;;; Code: + +(defvar rdebug-variables-mode-map + (let ((map (make-sparse-keymap))) + (suppress-keymap map) + (define-key map "\r" 'rdebug-variables-edit) + ;; (define-key map "e" 'rdebug-edit-variables-value) + (define-key map [mouse-2] 'rdebug-variables-edit-mouse) + (define-key map "e" 'rdebug-variables-print) + (define-key map "x" 'rdebug-variables-pretty-print) + (rdebug-populate-secondary-buffer-map map) + + ;; -------------------- + ;; The "Variables window" submenu. + + (let ((submenu (make-sparse-keymap))) + (define-key-after map [menu-bar debugger variables] + (cons "Variables window" submenu) + 'placeholder)) + + (define-key map [menu-bar debugger variables edit] + '(menu-item "Edit" rdebug-variables-edit + :enable (eq major-mode 'rdebug-variables-mode))) + + map) + "Keymap used in the variables buffer in the `rdebug' Ruby debugger.") + +(defvar rdebug-variables-font-lock-keywords + '(("@[a-zA-Z0-9_]+" 0 font-lock-variable-name-face) + ("\\<\\(nil\\|true\\|false\\)\\>" 0 font-lock-constant-face) + ("#<\\([a-zA-Z0-9_]+\\):\\([0-9a-fx]*\\)" + (1 font-lock-type-face) + (2 font-lock-constant-face))) + "Font-lock rules for the variables and watch windows in `rdebug'.") + +(defun rdebug-display-variables-buffer () + "Display the rdebug variables buffer." + (interactive) + (rdebug-display-secondary-buffer "variables")) + +(defun rdebug-variables-mode () + "Major mode for the variables buffer in the `rdebug' Ruby debugger. + +\\{rdebug-variables-mode-map}" + (interactive) + (kill-all-local-variables) + (setq major-mode 'rdebug-variables-mode) + (setq mode-name "RDEBUG Variables") + (setq buffer-read-only t) + (setq truncate-lines t) + (set (make-local-variable 'rdebug-secondary-buffer) t) + (setq mode-line-process 'rdebug-mode-line-process) + (set (make-local-variable 'font-lock-defaults) + '(rdebug-variables-font-lock-keywords)) + (use-local-map rdebug-variables-mode-map) + (run-mode-hooks 'rdebug-variables-mode-hook)) + +(defun rdebug-setup-variables-buffer (buf comint-buffer) + (rdebug-debug-enter "rdebug-setup-variables-buffer" + (with-current-buffer buf + (rdebug-variables-mode) + (set (make-local-variable 'gud-comint-buffer) comint-buffer)))) + +(defun rdebug-variables-edit-mouse (&optional event) + "Assign a value to a variable displayed in the variables buffer. +This function is intended to be bound to a mouse key" + (interactive (list last-input-event)) + (save-excursion + (if event (posn-set-point (event-end event))) + (call-interactively 'rdebug-variables-edit))) + +(defun rdebug-variables-edit (var value) + "Assign a value to a variable displayed in the variables buffer." + (interactive + (let ((var nil) + (value nil)) + (save-excursion + (beginning-of-line) + (when (looking-at "^\\(@?[a-zA-Z_0-9]+\\) *= *\\(.*\\)$") + (setq var (match-string 1)) + (setq value (match-string 2)) + (setq value (read-from-minibuffer + (format "New value (%s): " var) value))) + (list var value)))) + (gud-call (format "p %s=%s" var value))) + +(defun rdebug-variables-pretty-print (var) + "Pretty print a variable in the variables buffer." + (interactive + (let ((var nil)) + (save-excursion + (beginning-of-line) + (when (looking-at "^\\(@?[a-zA-Z_0-9]+\\) *= *\\(.*\\)$") + (setq var (match-string 1))) + (list var)))) + (rdebug-print-cmd var "pp")) + +(defun rdebug-variables-pretty-print-mouse (&optional event) + "Assign a value to a variable displayed in the variables buffer. +This function is intended to be bound to a mouse key" + (interactive (list last-input-event)) + (save-excursion + (if event (posn-set-point (event-end event))) + (call-interactively 'rdebug-variables-pretty-print))) + +(defun rdebug-variables-print (var) + "Print a variable in the variables buffer." + (interactive + (let ((var nil)) + (save-excursion + (beginning-of-line) + (when (looking-at "^\\(@?[a-zA-Z_0-9]+\\) *= *\\(.*\\)$") + (setq var (match-string 1))) + (list var)))) + (rdebug-print-cmd var "p")) + +(provide 'rdebug-varbuf) + +;;; Local variables: +;;; eval:(put 'rdebug-debug-enter 'lisp-indent-hook 1) +;;; End: + +;;; rdebug-varbuf.el ends here diff --git a/emacs/.svn/text-base/rdebug-vars.el.svn-base b/emacs/.svn/text-base/rdebug-vars.el.svn-base new file mode 100644 index 0000000..7688562 --- /dev/null +++ b/emacs/.svn/text-base/rdebug-vars.el.svn-base @@ -0,0 +1,125 @@ +;;; rdebug-var.el --- Ruby debugger variables (other than regexps) + +;; Copyright (C) 2007 Rocky Bernstein (rocky@gnu.org) +;; Copyright (C) 2007 Anders Lindgren + +;; $Id$ + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; See the manual and the file `rdebug.el' for more information. + +;; +;; Introduction: +;; +;; This is a full-blown debugger user interface to the Ruby rdebug +;; debugger shell. +;; +;; Internal debug support. When `rdebug-debug-active' is non-nil, +;; internal debug messages are placed in the buffer *Xrdebug*. +;; Functions can be annotated with `rdebug-debug-enter' to display a +;; call trace. +;; + +;;; Code: + +(defvar rdebug-current-line-number 1 + "The line number in a secondary window that you were in. We need to save + this value because secondary windows get recreated a lot") + +(defvar rdebug-debug-active nil + "Non-nil when rdebug should emit internal debug output to *Xrdebug*.") + +;; Indentation depth of `rdebug-debug-enter'. +(defvar rdebug-debug-depth 0) + +(defvar rdebug-debugger-window-configuration nil + "The saved window layout of the debugger.") + +(defvar rdebug-frames-current-frame-number nil + "The frame number of the selected frame.") + +(defvar rdebug-goto-entry-acc "") + +(defvar rdebug-output-marker-number 0 + "Number to be used when `rdebug-output-add-divider' is next + called on the secondary output buffer.") + +(defvar rdebug-original-window-configuration nil + "The window layout rdebug should restore when the debugger exits.") + +;; Terminology: a "secondary buffer" is the physical emacs buffer, +;; which can be visible or invisible. A "secondary window", is a window +;; that rdebug is reusing to display different secondary buffers. +;; +;; For example, the "secondary-window-help" buffer is named the way it +;; is since it gives help on how the secondary window is used. +(defvar rdebug-secondary-buffer nil + "Non-nil for rdebug secondary buffers (e.g. the breakpoints buffer).") + +;; Currently, this is the "output" and "info" buffers. +(defvar rdebug-accumulative-buffer nil + "Non-nil for Rdebug secondary buffers that grow.") + +;; This is used to ensure that the original frame configuration is +;; restored even when the user re-starts the debugger several times. +(defvar rdebug-window-configuration-state 'original + "Represent the window layout that currently is in use. +Can be `original' or `debugger'.") + +;; FIXME instead of just a list of commands it should a list of pairs +;; command and lambda callback routine to call with the shell output. +(defvar rdebug-call-queue '() + "List of commands queued up for results of a `rdebug-call'. + +Each entry is a list of the following form: + + (name ... options ...) + +Name is the actual command string. Options are zero or more tags +describing what should happen with the output. + +This is buffer local variable to the rdebug shell buffer.") + +;; TODO: Make this buffer-local to the shell buffer. +(defvar rdebug-inferior-status nil + "The status of the Ruby program debugged under RDebug.") + +;; Unlike the gdb implementation, we don't have to actively update the +;; mode line. +(defvar rdebug-mode-line-process + '(:eval + (and (fboundp 'rdebug-display-inferior-status) + (rdebug-display-inferior-status))) + "A string representing the current debugger state, or nil. +The mode line is displayed in all source and secondary buffers.") +;; Needed to get :eval to work. +(put 'rdebug-mode-line-process 'risky-local-variable t) + + +;; ------------------------------------------------------------------- +;; The end. +;; + +(provide 'rdebug-vars) + +;;; Local variables: +;;; eval:(put 'rdebug-debug-enter 'lisp-indent-hook 1) +;;; End: + +;;; rdebug-vars.el ends here diff --git a/emacs/.svn/text-base/rdebug-watch.el.svn-base b/emacs/.svn/text-base/rdebug-watch.el.svn-base new file mode 100644 index 0000000..b5a6e9b --- /dev/null +++ b/emacs/.svn/text-base/rdebug-watch.el.svn-base @@ -0,0 +1,132 @@ +;;; rdebug-watch.el --- This file contains code dealing with the Ruby +;;; debugger's watch (AKA display) secondary buffer. + +;; Copyright (C) 2008 Rocky Bernstein (rocky@gnu.org) +;; Copyright (C) 2008 Anders Lindgren + +;; $Id$ + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: +;; See the manual and the file `rdebug.el' for more information. + +;;; Code: + +(require 'rdebug-dbg) + +(defvar rdebug-watch-mode-map + (let ((map (make-sparse-keymap))) + (suppress-keymap map) + (define-key map "a" 'rdebug-watch-add) + (define-key map "\C-d" 'rdebug-watch-delete) + (define-key map "d" 'rdebug-watch-delete) + (define-key map "e" 'rdebug-watch-edit) + (define-key map "\r" 'rdebug-watch-edit) + (rdebug-populate-digit-keys map) + (rdebug-populate-secondary-buffer-map map) + + ;; -------------------- + ;; The "Watch window" submenu. + (let ((submenu (make-sparse-keymap))) + (define-key-after map [menu-bar debugger watch] + (cons "Watch window" submenu) + 'placeholder)) + + (define-key map [menu-bar debugger watch delete] + '(menu-item "Delete" rdebug-watch-delete + :enable (eq major-mode 'rdebug-watch-mode))) + (define-key map [menu-bar debugger watch goto] + '(menu-item "Edit" rdebug-watch-edit + :enable (eq major-mode 'rdebug-watch-mode))) + (define-key map [menu-bar debugger watch add] + '(menu-item "Add" rdebug-watch-add)) + + map) + "Keymap used in the watch buffer in the `rdebug' Ruby debugger.") + +(defun rdebug-display-watch-buffer () + "Display the rdebug watch buffer." + (interactive) + (rdebug-display-secondary-buffer "watch")) + +(defun rdebug-watch-mode () + "Major mode for displaying watched expressions in the `rdebug' Ruby debugger. + +\\{rdebug-watch-mode}" + (interactive) + (kill-all-local-variables) + (setq major-mode 'rdebug-watch-mode) + (setq mode-name "RDEBUG Watch") + (setq buffer-read-only t) + (setq truncate-lines t) + (set (make-local-variable 'rdebug-secondary-buffer) t) + (setq mode-line-process 'rdebug-mode-line-process) + (set (make-local-variable 'font-lock-defaults) + '(rdebug-variables-font-lock-keywords)) + (use-local-map rdebug-watch-mode-map) + (run-mode-hooks 'rdebug-watch-mode-hook)) + +(defun rdebug-setup-watch-buffer (buf comint-buffer) + "Set up the rdebug debugger watch secondary buffer. + +This buffer contains display expressions. BUF is the buffer to set up and COMINT-BUFFER be the assocated gud process buffer." + (rdebug-debug-enter "rdebug-setup-watch-buffer" + (with-current-buffer buf + (rdebug-watch-mode) + (set (make-local-variable 'gud-comint-buffer) comint-buffer)))) + +(defun rdebug-watch-add (expr) + "Add EXPR to watch in the `rdebug' Ruby debugger." + (interactive "sRuby expression: ") + (if (not (string= expr "")) + (gud-call (format "display %s" expr)))) + + +(defun rdebug-watch-delete () + "Delete a display expression in the `rdebug' Ruby debugger." + (interactive) + (save-excursion + (beginning-of-line) + (if (looking-at "^\\([0-9]+\\):") + (gud-call (format "undisplay %s" (match-string 1)))))) + +(defun rdebug-watch-edit (number expr) + "Edit a display expression in the `rdebug' Ruby debugger. +Argument NUMBER is the display expression number. +Argument EXPR is the expression for display number NUMBER." + (interactive + (let ((number nil) + (expr nil)) + (save-excursion + (beginning-of-line) + (when (looking-at "^\\([0-9]+\\): *\\([^=]*[^= ]\\) *=") + (setq number (match-string 1)) + (setq expr (match-string 2)) + (setq expr (read-from-minibuffer "Ruby expression: " expr))) + (list number expr)))) + (when expr + (gud-call (format "undisplay %s" number)) + (gud-call (format "display %s" expr)))) + + +(provide 'rdebug-watch) + +;;; Local variables: +;;; eval:(put 'rdebug-debug-enter 'lisp-indent-hook 1) +;;; End: + +;;; rdebug-watch.el ends here diff --git a/emacs/.svn/text-base/rdebug.el.svn-base b/emacs/.svn/text-base/rdebug.el.svn-base new file mode 100644 index 0000000..2a326a1 --- /dev/null +++ b/emacs/.svn/text-base/rdebug.el.svn-base @@ -0,0 +1,326 @@ +;;; rdebug.el --- Ruby debugger user interface, startup file. + +;; Copyright (C) 2006, 2007, 2008 Rocky Bernstein (rocky@gnu.org) +;; Copyright (C) 2007, 2008 Anders Lindgren + +;; $Id: rdebug.el 409 2007-12-14 02:36:37Z rockyb $ + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; +;; Introduction: +;; +;; This is a full-blown debugger user interface to the Ruby rdebug +;; debugger shell. +;; +;; The main features are: +;; +;; * Window layout with dedicated windows for: +;; + Local and member variables +;; + Stack trace +;; + Display expressions +;; + Breakpoints +;; + Output +;; + Debugger Shell +;; +;; * Source-level debugging: +;; + The current source file is shown and current line is marked. +;; + Function keys bindings for effective stepping in the source code. +;; + A "Debugger" menu for easy access to all features. +;; +;; * A number of predefined window layouts and key bindings are +;; supplied, including binding that emulate Eclipse and NetBeans. +;; The user can easily provide their own window layout and +;; settings. +;; +;; The default window layout looks like the following: +;; +;; +----------------------------------------------------------------------+ +;; | Toolbar | +;; +-----------------------------------+----------------------------------+ +;; | Debugger shell | Variables buffer | +;; +-----------------------------------+----------------------------------+ +;; | | | +;; | Source buffer | Output buffer | +;; | | | +;; +-----------------------------------+----------------------------------+ +;; | Stack buffer | Breakpoints buffer | +;; +-----------------------------------+----------------------------------+ +;; + +;; +;; Installation: +;; +;; To use this package, place the following line in an appropriate +;; init file (for example ~/.emacs): +;; +;; (require 'rdebug) +;; + +;; +;; History and Future: +;; +;; The design of this debugger user interface was inspired by +;; `gdb-ui', a similar user interface to GDB. +;; +;; Hopefully, rdebug, gdb-ui, and other emacs user interfaces could +;; join forces to create a common user-level look and feel, and a +;; battery of underlying support functions. +;; + +;; +;; This file contains only user-customizable variables and code to +;; load the other files when needed. +;; + +;;; Code: + +;; ------------------------------------------------------------------- +;; Consistency checks. +;; + +(if (< emacs-major-version 22) + (error + "This version of rdebug.el needs at least Emacs 22 or greater - you have version %d." + emacs-major-version)) + + +;; ------------------------------------------------------------------- +;; Support functions. +;; + +(defun rdebug-directory () + "The directory of this file, or nil." + (let ((file-name (or load-file-name + (symbol-file 'rdebug-directory)))) + (if file-name + (file-name-directory file-name) + nil))) + + +(defun rdebug-compare-filenames (f1 f2) + "Canonicalize and compare file names." + ;; Canonicalize by: + ;; 1) file-truename ensures that the file has got the correct case, + ;; and that "..":s in the path are eliminated. + ;; 2) file-name-as-directory ensures "/foo" and "/foo/" becomes equal. + + ;; Note: for some reason, when the `comp-elisp' external program is + ;; used, `nil' is part of `load-path'. + (if f1 + (setq f1 (file-name-as-directory (file-truename f1)))) + (if f2 + (setq f2 (file-name-as-directory (file-truename f2)))) + (equal f1 f2)) + + +;; Add the directory of `rdebug.el' to the load-path. This ensures +;; that all the user have do to use this package is to load this file. +(let ((dir (rdebug-directory))) + (if dir + (add-to-list 'load-path dir nil 'rdebug-compare-filenames))) + + +;; ------------------------------------------------------------------- +;; Autoloads. +;; + +(autoload 'rdebug "rdebug-core" + "Run the rdebug Ruby debugger and start the Emacs user interface. + +By default, the \"standard\" user window layout looks like the following: + ++----------------------------------------------------------------------+ +| Toolbar | ++-----------------------------------+----------------------------------+ +| Debugger shell | Variables buffer | ++-----------------------------------+----------------------------------+ +| | | +| Source buffer | Output buffer | +| | | ++-----------------------------------+----------------------------------+ +| Stack buffer | Breakpoints buffer | ++-----------------------------------+----------------------------------+ + +The variable `rdebug-many-windows-layout-function' can be +customized so that another layout is used. In addition to a +number of predefined layouts it's possible to define a function +to perform a custom layout. + +If `rdebug-many-windows' is nil, only a traditional debugger +shell and source window is opened. + +The directory containing the debugged script becomes the initial +working directory and source-file directory for your debugger. + +The custom variable `gud-rdebug-command-name' sets the command +and options used to invoke rdebug." t) + + +(autoload 'rdebug-turn-on-debugger-support "rdebug-source" + "Enable extra source buffer support for the `rdebug' Ruby debugger. + +This includes a 'Debugger' menu and special key bindings when the +debugger is active." + t) + + +(autoload 'rdebug-track-attach "rdebug-track" + "Do things to make the current process buffer work like a +rdebug command buffer." t) + +(autoload 'turn-on-rdebug-track-mode "rdebug-track" + "Turn on rdebugtrack mode. + +This function is designed to be added to hooks, for example: + (add-hook 'comint-mode-hook 'turn-on-rdebugtrack-mode)" + t) + + +(add-hook 'ruby-mode-hook 'rdebug-turn-on-debugger-support) + +;; This is needed, or at least the docstring part of it is needed to +;; get the customization menu to work in Emacs 23. +(defgroup rdebug nil + "The Ruby debugger" + :group 'processes + :group 'tools) + +;; ------------------------------------------------------------------- +;; User definable variables +;; + +(defcustom gud-rdebug-command-name + "rdebug --emacs 3" + "File name for executing the Ruby debugger and command options. +This should be an executable on your path, or an absolute file name." + :type 'string + :group 'gud) + +(defcustom rdebug-line-width 120 + "Length of line before truncation occurs. +This value limits output in secondary buffers." + :type 'integer + :group 'rdebug) + +(defcustom rdebug-many-windows t + "*If non-nil, use the full debugger user interface, see `rdebug'. + +However only set to the multi-window display if the rdebug +command invocation has an annotate options (\"--annotate 3\")." + :type 'boolean + :group 'rdebug) + +(defcustom rdebug-use-separate-io-buffer t + "*If non-nil, output goes to a dedicated windows. + +This only applies when `rdebug-many-windows' is non-nil." + :type 'boolean + :group 'rdebug) + +(defcustom rdebug-populate-common-keys-function + 'rdebug-populate-common-keys-standard + "The function to call to populate key bindings common to all rdebug windows. +This includes the secondary windows, the debugger shell, and all +Ruby source buffers when the debugger is active. + +This variable can be bound to the following: + +* nil -- Don't bind any keys. + +* `rdebug-populate-common-keys-standard' -- Bind according to a widely used + debugger convention: + +\\{rdebug-example-map-standard} + +* `rdebug-populate-common-keys-eclipse' -- Bind according to Eclipse. + +\\{rdebug-example-map-eclipse} + +* `rdebug-populate-common-keys-netbeans' -- Bind according to NetBeans. + +\\{rdebug-example-map-netbeans} + +* Any other value is expected to be a callable function that takes one + argument, the keymap, and populates it with suitable keys." + :type 'function + :group 'rdebug) + +(defcustom rdebug-restore-original-window-configuration :many + "*Control if the original window layout is restored when the debugger exits. +The value can be t, nil, or :many. + +A value of t means that the original layout is always restored, +nil means that it's never restored. + +:many means that the original layout is restored only when +`rdebug-many-windows' is used." + :type '(choice (const :tag "Always restore" t) + (const :tag "Never restore" nil) + (const :tag "Restore in many windows mode" :many)) + :group 'rdebug) + +(defcustom rdebug-use-separate-io-buffer t + "Non-nil means display output from the debugged program in a separate buffer." + :type 'boolean + :group 'gud) + + +(defcustom rdebug-window-layout-function + 'rdebug-window-layout-standard + "*A function that performs the window layout of `rdebug'. + +This is only used in `rdebug-many-windows' mode. This should be +bound to a function that performs the actual window layout. The +function should takes two arguments, the first is the source +buffer and the second the name of the script to debug. + +Rdebug provides the following predefined layout functions: + +* `rdebug-window-layout-standard' -- See `rdebug' + +* `rdebug-window-layout-no-shell' -- Standard + Display, no Shell + +* `rdebug-window-layout-conservative' -- Source + Shell + Output + +* `rdebug-window-layout-stack-of-windows' -- Extra windows to the right + +* `rdebug-window-layout-rocky' -- Rocky's own layout" + :type + '(choice + (function :tag "Standard" rdebug-window-layout-standard) + (function :tag "Conservative" rdebug-window-layout-conservative) + (function :tag "Stack of windows" rdebug-window-layout-stack-of-windows) + (function :tag "Rocky's own" rdebug-window-layout-rocky) + (function :tag "Rocky's II" rdebug-window-layout-rocky2) + (function :tag "Other" function)) + :group 'rdebug) + +(defcustom rdebug-source-location-ring-size 150 + "Size of rdebug position history ring." + :type 'integer + :group 'rdebug) + + +;; ------------------------------------------------------------------- +;; The end. +;; + +(provide 'rdebug) + +;;; rdebug.el ends here diff --git a/emacs/Makefile.am b/emacs/Makefile.am new file mode 100644 index 0000000..2bbc81e --- /dev/null +++ b/emacs/Makefile.am @@ -0,0 +1,130 @@ +# Copyright (C) 2007, 2008 Rocky Bernstein rocky@gnu.org +# +# This program is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 2, or (at your option) any later +# version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License along +# with Bash; see the file COPYING. If not, write to the Free Software +# Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. +#$Id: Makefile.am,v 1.10 2007/04/13 00:59:33 rockyb Exp $ + +lisp_files = rdebug.el \ + rdebug-annotate.el \ + rdebug-breaks.el \ + rdebug-cmd.el \ + rdebug-core.el \ + rdebug-dbg.el \ + rdebug-error.el \ + rdebug-fns.el \ + rdebug-frames.el \ + rdebug-gud.el \ + rdebug-help.el \ + rdebug-info.el \ + rdebug-layouts.el \ + rdebug-locring.el \ + rdebug-output.el \ + rdebug-regexp.el \ + rdebug-secondary.el\ + rdebug-shortkey.el \ + rdebug-source.el \ + rdebug-track.el \ + rdebug-varbuf.el \ + rdebug-vars.el \ + rdebug-watch.el +check_DATA = test/elk-test.el \ + test/test-annotate.el \ + test/test-cmd.el \ + test/test-core.el \ + test/test-fns.el \ + test/test-gud.el \ + test/test-indent.el \ + test/test-regexp.el \ + test/test-shortkey.el + +EXTRA_DIST = $(lisp_files) $(check_DATA) +ELCFILES = rdebug.elc \ + rdebug-annotate.elc \ + rdebug-breaks.elc \ + rdebug-cmd.elc \ + rdebug-core.elc \ + rdebug-dbg.elc \ + rdebug-error.elc \ + rdebug-fns.elc \ + rdebug-gud.elc \ + rdebug-frames.elc \ + rdebug-help.elc \ + rdebug-info.elc \ + rdebug-layouts.elc \ + rdebug-locring.elc \ + rdebug-output.elc \ + rdebug-regexp.elc \ + rdebug-secondary.elc \ + rdebug-shortkey.elc \ + rdebug-source.elc \ + rdebug-track.elc \ + rdebug-varbuf.elc \ + rdebug-vars.elc \ + rdebug-watch.elc +if INSTALL_EMACS_LISP +lisp_LISP = $(lisp_files) +CHECK_FILES = \ + check-annotate \ + check-cmd \ + check-core \ + check-fns \ + check-frames \ + check-gud \ + check-indent \ + check-regexp \ + check-shortkey + +check: $(CHECK_FILES) + +check-annotate: rdebug-annotate.el + (cd $(srcdir)/test && \ + $(EMACS) -batch -q -l test-annotate.el ) + +check-cmd: rdebug-gud.el + (cd $(srcdir)/test && \ + $(EMACS) -batch -q -l test-cmd.el ) + +check-core: rdebug-core.el + (cd $(srcdir)/test && \ + $(EMACS) -batch -q -l test-core.el ) + +check-fns: rdebug-fns.el + (cd $(srcdir)/test && \ + $(EMACS) -batch -q -l test-fns.el ) + +check-frames: rdebug-frames.el + (cd $(srcdir)/test && \ + $(EMACS) -batch -q -l test-frames.el ) + +check-gud: rdebug-gud.el + (cd $(srcdir)/test && \ + $(EMACS) -batch -q -l test-gud.el ) + +check-indent: $(lisp_files) + (cd $(srcdir)/test && \ + $(EMACS) -batch -q -l test-indent.el ) + +check-regexp: rdebug-regexp.el + (cd $(srcdir)/test && \ + $(EMACS) -batch -q -l test-regexp.el ) + +check-shortkey: rdebug-shortkey.el + (cd $(srcdir)/test && \ + $(EMACS) -batch -q -l test-shortkey.el ) +endif + +PHONY = $(CHECK_FILES) + +test: check + diff --git a/emacs/rdebug-annotate.el b/emacs/rdebug-annotate.el new file mode 100644 index 0000000..04a3905 --- /dev/null +++ b/emacs/rdebug-annotate.el @@ -0,0 +1,385 @@ +;;; rdebug-annotate.el --- Ruby debugger output filtering - which +;;; includes annotation handling. + +;; Copyright (C) 2008 Rocky Bernstein (rocky@gnu.org) +;; Copyright (C) 2008 Anders Lindgren + +;; $Id: rdebug-annotate.el 786 2008-04-02 00:50:27Z rockyb $ + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; This file contains code dealing with filter of debugger output a large +;; part of which may contain annotations. + +;;; Code: + +(require 'gud) +(require 'gdb-ui) +(require 'rdebug-dbg) +(require 'rdebug-error) +(require 'rdebug-fns) +(require 'rdebug-info) +(require 'rdebug-layouts) +(require 'rdebug-locring) +(require 'rdebug-regexp) +(require 'rdebug-shortkey) +(require 'rdebug-source) +(require 'rdebug-vars) + +(defvar rdebug-non-annotated-text-kind nil + "Represent what non-annotated text is. + +This can be: + * nil -- plain shell output + * :output -- output from the command being debugged + * :info -- text for the \"info\" secondary window. + * :message -- message the text to the echo area. + * :cmd -- a command + result, which might go into the \"info\" window. + +See the function `rdebug-cmd-process' for details on :cmd.") + +(defvar rdebug-annotation-setup-map + (progn + (define-hash-table-test 'str-hash 'string= 'sxhash) + (let ((map (make-hash-table :test 'str-hash))) + (puthash "breakpoints" 'rdebug-setup-breakpoints-buffer map) + ;;(puthash "error" 'rdebug-setup-error-buffer map) + (puthash "frame" 'rdebug-setup-frame-buffer map) + (puthash "variables" 'rdebug-setup-variables-buffer map) + (puthash "watch" 'rdebug-setup-watch-buffer map) + (puthash "output" 'rdebug-setup-output-buffer map) + (puthash "info" 'rdebug-setup-info-buffer map) + (puthash "help" 'rdebug-setup-secondary-window-help-buffer map) + map))) + +(defun rdebug-temp-show (text) + "Arrange to show string as in sort of temporary way. Perhaps like a tooltip" + (tooltip-show text)) + +(defun rdebug-marker-filter-next-item (string) + "The next item for the rdebug marker filter to process. + +Return (item . rest) or nil." + (rdebug-debug-message "ACC: %S" string) + (cond + ;; Empty line, we're done. + ((equal (length string) 0) + nil) + ;; A single ^Z, this could become a new annotation, so lets stop here. + ((string= string "\032") + nil) + ;; A half-baked annotation, lets stop here. + ((and (string-match "^\032\032" string) + (not (string-match "\n" string))) + nil) + (t + (let ((split-point + (cond ((string-match "\032\032" string) + (let ((beg (match-beginning 0))) + (if (equal beg 0) + (if (string-match "^\032\032" string 2) + (match-beginning 0) + (length string)) + beg))) + ((eq (elt string (- (length string) 1)) ?\32) + -1) + (t + (length string))))) + (cons (substring string 0 split-point) (substring string split-point)))))) + +;; There's no guarantee that Emacs will hand the filter the entire +;; marker at once; it could be broken up across several strings. We +;; might even receive a big chunk with several markers in it. If we +;; receive a chunk of text which looks like it might contain the +;; beginning of a marker, we save it here between calls to the +;; filter. +(defun gud-rdebug-marker-filter (string) + "Filter function for process output of the rdebug Ruby debugger." + (rdebug-debug-enter "gud-rdebug-marker-filter:" + (rdebug-debug-message "GOT: %S" string) + (if rdebug-non-annotated-text-kind + (rdebug-debug-message " Text is %S" rdebug-non-annotated-text-kind)) + (setq gud-marker-acc (concat gud-marker-acc string)) + (rdebug-debug-message "TOT: %S" gud-marker-acc) + (let ((shell-output "") ; Output to debugger shell window. + (done nil) + item) + ;; The following loop peels of one "item" at a time. An item is + ;; a un-annotated section or an annotation. (This is taken care + ;; of by the `rdebug-marker-filter-next-item' function.) + ;; + ;; An Annotation can be a one-liner (where anything following + ;; the annotation is treated as un-annotated text) or a full + ;; annotation (which stretches to the next annotation). + ;; + ;; The concept of one-liners (no phun intended) is to allow + ;; continuous output, a "starting" annotation simply sets up the + ;; environment for sending lines to the output window, any text + ;; following it right now, or in later chunks of data, is + ;; redirected to the output window. + (while (and (not done) + (let ((pair (rdebug-marker-filter-next-item gud-marker-acc))) + (rdebug-debug-message "Next item: %S" pair) + (and pair + (progn + (setq item (car pair)) + (setq gud-marker-acc (cdr pair)) + t)))) + ;; Note: Regexp:s are greedy, i.e. the char parts wins over + ;; the .* part. + (if (not (string-match "^\032\032\\([-a-z]*\\).*\n" item)) + ;; Non-annotated text (or the content of one-liners) goes + ;; straight into the debugger shell window, or to the + ;; output window. + (cond ((and (eq rdebug-non-annotated-text-kind :output) + rdebug-use-separate-io-buffer) + (rdebug-process-annotation "starting" item)) + ((eq rdebug-non-annotated-text-kind :info) + (rdebug-process-annotation "info" item)) + (t + (if (eq rdebug-non-annotated-text-kind :cmd) + (rdebug-cmd-process item)) + (setq shell-output (concat shell-output item)))) + ;; Handle annotation. + (let* ((line-end (match-end 0)) + (name (match-string 1 item)) + ;; "prompt" is needed to handle "quit" in the shell correctly. + (one-liner + (member name + '("" "exited" "source" "prompt" "starting"))) + (next-annotation (string-match "\032\032" + gud-marker-acc))) + ;; For one-liners, shuffle some text back to the accumulator. + (when one-liner + (setq gud-marker-acc (concat (substring item line-end) + gud-marker-acc)) + (setq item (substring item 0 line-end))) + (if (or next-annotation + one-liner) + ;; ok, annotation complete, process it and remove it + (let* ((contents (substring item line-end)) + (old-kind rdebug-non-annotated-text-kind)) + (rdebug-debug-message "Name: %S Content: %S Kind: %S" + name contents + rdebug-non-annotated-text-kind) + + ;; This is a global state flag, this allows us to + ;; redirect any further text to the output buffer. + (set + (make-local-variable 'rdebug-non-annotated-text-kind) + (cond ((string= name "starting") + :output) + ((string= name "prompt") + (rdebug-cmd-clear) + :cmd) + ((string= name "exited") + ;; Create a fake command whose output we + ;; handle in the cmd system. (We might not + ;; receive all of the message at once, we we + ;; need some kind of accumukator, which the + ;; cmd system provides.) + (setq rdebug-inferior-status "exited") + (rdebug-cmd-clear) + (setq rdebug-call-queue + (cons '("***exited***" :message) + rdebug-call-queue)) + :cmd) + (t nil))) + + (when (and (eq old-kind :cmd) + (not (eq rdebug-non-annotated-text-kind :cmd))) + (rdebug-debug-message + "New kind: %S" rdebug-non-annotated-text-kind) + (rdebug-cmd-done)) + + ;; Process the annotation. + (cond ((string= name "starting") + (setq rdebug-inferior-status "running")) + ((string= name "stopped") + (setq rdebug-inferior-status "stopped")) + ((string= name "exited") + (setq rdebug-inferior-status "exited")) + ((string= name "pre-prompt") + ;; Strip of the trailing \n (this is probably + ;; a bug in processor.rb). + (if (string= (substring contents -1) "\n") + (setq contents (substring contents 0 -1))) + (if (string-match "post-mortem" contents) + (setq rdebug-inferior-status "crashed")) + (setq shell-output (concat shell-output contents))) + ((string= name "source") + (if (string-match gud-rdebug-marker-regexp item) + ;; Extract the frame position from the marker. + (setq gud-last-frame + (cons (match-string 1 item) + (string-to-number + (match-string 2 item)))))) + (t (rdebug-process-annotation name contents)))) + ;; This is not a one-liner, and we haven't seen the next + ;; annotation, so we have to treat this as a partial + ;; annotation. Save it and hope that the we can process + ;; it the next time we're called. + (setq gud-marker-acc (concat item gud-marker-acc)) + (setq done t))))) + + (when gud-last-frame + ;; Display the source file where we want it, gud will only pick + ;; an arbitrary window. + (rdebug-pick-source-window) + (rdebug-set-frame-arrow (gud-find-file (car gud-last-frame))) + (if (equal 0 rdebug-frames-current-frame-number) + (rdebug-locring-add gud-last-frame + rdebug-source-location-ring))) + (rdebug-short-key-mode-maybe-activate) + + (unless (string= shell-output "") + (rdebug-debug-message "Output: %S" shell-output)) + (rdebug-debug-message "REM: %S" gud-marker-acc) + + shell-output))) + +(defun rdebug-process-annotation (name contents) + "Called after `gud-rdebug-marker-filter' found a complete +`name' annotation with string `contents'. Send it to the right +place for processing." + (rdebug-debug-enter (format "rdebug-process-annotation %s" name) + ;; Ruby-debug uses the name "starting" for process output (just like + ;; GDB). However, it's better to present the buffer as "output" to + ;; the user. Ditto for "display" and "watch". + (cond ((string= name "starting") + (setq name "output")) + ((string= name "display") + (setq name "watch")) + ((string= name "stack") + (setq name "frame")) + ((string= name "error-begin") + (setq name "error"))) + ;; New "info" + (if (string= name "exited") + (setq name "info")) + (if (string= name "error") + (rdebug-errmsg contents)) + (let ((setup-func (gethash name rdebug-annotation-setup-map))) + (when setup-func + (let ((buf (rdebug-get-buffer name gud-target-name)) + ;; Buffer local, doesn't survive the buffer change. + (comint-buffer gud-comint-buffer)) + (with-current-buffer buf + (setq buffer-read-only t) + (let ((inhibit-read-only t)) + (set (make-local-variable 'rdebug-current-line-number) + (line-number-at-pos)) + (set (make-local-variable 'gud-last-frame) gud-last-frame) + (if rdebug-accumulative-buffer + (goto-char (point-max)) + (erase-buffer)) + (insert contents) + (funcall setup-func buf comint-buffer)))))) + (cond ((and (string= name "info") + (not (string= contents ""))) + (save-selected-window + (rdebug-display-info-buffer)))))) + + +;; ------------------------------------------------------------ +;; Mode line displayer. +;; + +;; The variable rdebug-mode-line-process uses this to generate the +;; actual string to display. +(defun rdebug-display-inferior-status () + "Return a (propertized) string, or nil, to be displayed in the mode line." + (if (and gud-comint-buffer + (buffer-name gud-comint-buffer) + (get-buffer-process gud-comint-buffer) + rdebug-inferior-status) + (let ((s rdebug-inferior-status)) + (cond ((string= rdebug-inferior-status "running") + (setq s (propertize s 'face font-lock-type-face))) + (t + (setq s (propertize s 'face font-lock-warning-face)))) + (concat ":" s)) + ;; No process, don't display anything. + nil)) + +;; ------------------------------------------------------------ +;; Command output parser. +;; + +(defvar rdebug-cmd-acc "" + "The accumulated output of the current command. + +Note, on some systems the external process echoes the command, +which is included in the output.") + +;; Called when a new command starts. +(defun rdebug-cmd-clear () + "Called when the Rdebug filter find the start of a new commands." + (rdebug-debug-enter "rdebug-cmd-clear" + (setq rdebug-cmd-acc ""))) + +;; Called with command output, this can be called any number of times. +(defun rdebug-cmd-process (s) + "Called when the Rdebug filter find the command output. +This may be called any number of times." + (rdebug-debug-enter (format "rdebug-cmd-process %S" s) + (setq rdebug-cmd-acc (concat rdebug-cmd-acc s)))) + +;; Called when command has finished. +(defun rdebug-cmd-done () + "Called when the Rdebug filter find the end of a commands." + (rdebug-debug-enter "rdebug-cmd-done" + ;; car-safe is used since rdebug-call-queue can be empty. + (let ((entry (car-safe rdebug-call-queue)) + (text rdebug-cmd-acc)) + (when entry + (rdebug-debug-message "Entry: %S Acc:%S" rdebug-call-queue rdebug-cmd-acc) + (setq rdebug-call-queue (cdr rdebug-call-queue)) + (let ((saved-cmd (car entry)) + (options (cdr entry))) + ;; In cast the external process echoed the actual command, + ;; remove it. + (when (and (>= (length text) + (length saved-cmd)) + (string= saved-cmd (substring text 0 (length saved-cmd)))) + (setq text (substring text (+ 1 (length saved-cmd))))) + (rdebug-debug-message "Text: %S" text) + ;; Optionally display the result. + (if (memq :tooltip options) + (rdebug-temp-show text)) + (if (memq :info options) + (rdebug-process-annotation "info" text)) + (when (memq :message options) + ;; Remove trailing newlines (chomp). + (while (and (> (length text) 0) + (eq (elt text (- (length text) 1)) ?\n)) + (setq text (substring text 0 -1))) + (message text))))))) + + +;; ------------------------------------------------------------------- +;; The end. +;; + +(provide 'rdebug-annotate) + +;;; Local variables: +;;; eval:(put 'rdebug-debug-enter 'lisp-indent-hook 1) +;;; End: + +;;; rdebug-annotate.el ends here diff --git a/emacs/rdebug-breaks.el b/emacs/rdebug-breaks.el new file mode 100644 index 0000000..5346fd1 --- /dev/null +++ b/emacs/rdebug-breaks.el @@ -0,0 +1,407 @@ +;;; rdebug-breaks.el --- This file contains code dealing with the Ruby +;;; debugger's breakpoints and the breakpoint secondary buffer. + +;; Copyright (C) 2008 Rocky Bernstein (rocky@gnu.org) +;; Copyright (C) 2008 Anders Lindgren + +;; $Id: rdebug-breaks.el 780 2008-03-21 19:04:12Z rockyb $ + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; This file contains code dealing with the breakpoints and the +;; breakpoints secondary buffer. + +;;; Code: + +(require 'rdebug-dbg) +(require 'rdebug-gud) +(require 'rdebug-regexp) +(require 'rdebug-secondary) +(require 'rdebug-source) +(require 'rdebug-vars) + +(defun rdebug-display-breakpoints-buffer () + "Display the rdebug breakpoints buffer." + (interactive) + (rdebug-display-secondary-buffer "breakpoints")) + +(defvar rdebug-breakpoint-mode-map + (let ((map (make-sparse-keymap))) + (define-key map [double-mouse-1] 'rdebug-goto-breakpoint-mouse) + (define-key map [mouse-2] 'rdebug-goto-breakpoint-mouse) + (define-key map [mouse-3] 'rdebug-goto-breakpoint-mouse) + (define-key map "t" 'rdebug-toggle-breakpoint) + (define-key map "i" 'rdebug-add-breakpoint-condition) + (define-key map [insert] 'rdebug-add-breakpoint-condition) + (rdebug-populate-digit-keys map) + (define-key map [(control m)] 'rdebug-goto-breakpoint) + (define-key map [?d] 'rdebug-delete-breakpoint) + (rdebug-populate-secondary-buffer-map map) + + ;; -------------------- + ;; The "Breakpoints window" submenu. + (let ((submenu (make-sparse-keymap))) + (define-key-after map [menu-bar debugger breakpoints] + (cons "Breakpoints window" submenu) + 'placeholder)) + + (define-key map [menu-bar debugger breakpoints toggle] + '(menu-item "Toggle breakpoint" rdebug-toggle-breakpoint)) + + (define-key map [menu-bar debugger breakpoints goto] + '(menu-item "Goto breakpoint" rdebug-goto-breakpoint)) + + (define-key map [menu-bar debugger breakpoints delete] + '(menu-item "Delete breakpoint" rdebug-delete-breakpoint)) + + map) + "Keymap to navigate/set/enable rdebug breakpoints.") + +;; Here the "anchored match" method is used, see `font-lock-keywords' +;; for details. +(defvar rdebug-breakpoint-font-lock-keywords + '(("\\([0-9]+\\) +\\(\\(n\\)\\|\\(y\\)\\) +at " + (1 font-lock-constant-face) + (3 font-lock-type-face nil t) ; t = ok if not present + (4 font-lock-warning-face nil t) ; ditto. + ;; File name and line + ("\\(.*\\):\\([0-9]+\\)$" + nil ; Preform (not used) + nil ; Postfrom (not used) + (1 font-lock-warning-face) + (2 font-lock-constant-face)) + ;; Class:function + ("\\(.*\\):\\([a-zA-Z_].+\\)$" + nil ; Preform (not used) + nil ; Postfrom (not used) + (1 font-lock-type-face) + (2 font-lock-function-name-face)))) + "Rules for coloring the rdebug breakpoints buffer.") + +(defun rdebug-breakpoint-mode () + "Major mode for displaying breakpoints in the `rdebug' Ruby debugger. + +\\{rdebug-breakpoint-mode-map}" + (kill-all-local-variables) + (setq major-mode 'rdebug-breakpoint-mode) + (setq mode-name "RDEBUG Breakpoints") + (use-local-map rdebug-breakpoint-mode-map) + (setq buffer-read-only t) + (set (make-local-variable 'rdebug-secondary-buffer) t) + (setq mode-line-process 'rdebug-mode-line-process) + (set (make-local-variable 'font-lock-defaults) + '(rdebug-breakpoint-font-lock-keywords)) + (run-mode-hooks 'rdebug-breakpoint-mode-hook)) + + +(defun rdebug-setup-breakpoints-buffer (buf comint-buffer) + "Detect breakpoint lines and set up keymap and mouse navigation. +Argument BUF is the buffer to set up. +Argument COMINT-BUFFER is the assocaited gud process buffer." + (rdebug-debug-enter "rdebug-setup-breakpoints-buffer" + (with-current-buffer buf + (let ((inhibit-read-only t) + (old-line-number (buffer-local-value 'rdebug-current-line-number + buf))) + (rdebug-breakpoint-mode) + (goto-char (point-min)) + (while (not (eobp)) + (let ((b (line-beginning-position)) (e (line-end-position))) + (when (string-match rdebug-breakpoint-regexp + (buffer-substring b e)) + (add-text-properties b e + (list 'mouse-face 'highlight + 'keymap rdebug-breakpoint-mode-map))) + (forward-line))) + (goto-line old-line-number))) + (rdebug-breakpoint-parse-and-update-cache) + (rdebug-breakpoint-update-icons (rdebug-breakpoint-all)))) + + +(defvar rdebug-breakpoint-cache '() + "The cached return value of `rdebug-breakpoint-all'. + +Buffer-local to the debugger shell window.") + + +;; Implementation note: If Emacs could talk directly to the Ruby +;; debugger, this would be roughly "Debugger.breakpoints". Since we +;; currently can't do that we parse the content of the breakpoints +;; window. +;; +;; Note: The :function kind is not yet implemented. +(defun rdebug-breakpoint-parse-and-update-cache () + "Build up the return value of `rdebug-breakpoint-all'." + (save-excursion + (goto-char (point-min)) + (let ((res '())) + (while (not (eobp)) + (when (looking-at rdebug-breakpoint-regexp) + (push (list :file + ;; Break point number + (string-to-number (match-string 1)) + ;; Enabled + (string= (match-string 2) "y") + ;; File name + (file-truename + (match-string-no-properties 3)) + ;; Line number + (string-to-number (match-string 4))) + res)) + (forward-line 1)) + ;; The result goes into a buffer-local variable in the debugger + ;; shell. (This ensures that this would work in a multi-session + ;; environment.) + (if gud-comint-buffer + (with-current-buffer gud-comint-buffer + (set (make-local-variable 'rdebug-breakpoint-cache) + (nreverse res))))))) + + +(defun rdebug-breakpoint-all () + "Return a list of all breakpoints. + +Each entry in the list is on the form: + + (:file number enabled file line) + +or + + (:function number enabled class function)" + (and gud-comint-buffer + (buffer-local-value 'rdebug-breakpoint-cache gud-comint-buffer))) + + +(defun rdebug-file-and-line-arg () + "Return the current file and line number as a list." + (save-excursion + (beginning-of-line) + (list (buffer-file-name) (+ 1 (count-lines (point-min) (point)))))) + +(defun rdebug-breakpoint-on-line (file line) + "Return a list of the breakpoints on the file FILE and current source LINE." + (let ((res '())) + (dolist (entry (rdebug-breakpoint-all)) + (if (and (eq (nth 0 entry) :file) + (string= (nth 3 entry) file) + (equal (nth 4 entry) line)) + (push entry res))) + res)) + + +(defun rdebug-toggle-source-breakpoint (file line) + "Toggle break point in FILE on current source LINE." + (interactive (rdebug-file-and-line-arg)) + (cond ((eq major-mode 'rdebug-breakpoint-mode) + (rdebug-delete-breakpoint)) + ((null file) + ;; Do nothing. + ) + (t + (let ((bps (rdebug-breakpoint-on-line file line))) + (if bps + (gud-call (format "delete %s" (nth 1 (car bps)))) + (gud-call (format "break %s:%d" file line))))))) + + +(defun rdebug-toggle-source-breakpoint-enabled (file line) + "Enable or disable a breakpoint in FILE on the current source LINE." + (interactive (rdebug-file-and-line-arg)) + (cond ((eq major-mode 'rdebug-breakpoint-mode) + (rdebug-toggle-breakpoint)) + ((null file) + ;; Do nothing. + ) + (t + (let ((bps (rdebug-breakpoint-on-line file line))) + (if bps + ;; Note: If the line contains more than one simply use the + ;; first one. + (let ((entry (car bps))) + (if (nth 2 entry) + (gud-call (format "disable %s" (nth 1 entry))) + (gud-call (format "enable %s" (nth 1 entry))))) + (gud-call (format "break %s:%d" file line))))))) + + +;; --------------------------------------------------------- +;; Commands of the rdebug breakpoints buffer. +;; + +(defun rdebug-delete-breakpoint (&optional pt) + "Deletes the breakpoint at PT in the breakpoints buffer." + (interactive "d") + (save-excursion + (if pt + (goto-char pt)) + (let ((s (buffer-substring (line-beginning-position) (line-end-position)))) + (when (string-match rdebug-breakpoint-regexp s) + (let ((bpnum (substring s (match-beginning 1) (match-end 1)))) + (gud-call (format "delete %s" bpnum))))))) + +(defun rdebug-goto-breakpoint (pt) + "Displays the location in a source file of the selected breakpoint. +Argument PT indicates the file and line where the breakpoint should be set." + (interactive "d") + (save-excursion + (goto-char pt) + (let ((s (buffer-substring (line-beginning-position) (line-end-position)))) + (when (string-match rdebug-breakpoint-regexp s) + (rdebug-display-line + (substring s (match-beginning 3) (match-end 3)) + (string-to-number (substring s (match-beginning 4) (match-end 4)))) + )))) + + +(defun rdebug-goto-breakpoint-mouse (event) + "Displays the location in a source file of the selected breakpoint." + (interactive "e") + (with-current-buffer (window-buffer (posn-window (event-end event))) + (rdebug-goto-breakpoint (posn-point (event-end event))))) + + +(defun rdebug-get-breakpoint-number (pt) + "Return the current breakpoint number in the breakpoint secondary window or nil if none found." + (interactive "d") + (save-excursion + (goto-char pt) + (let ((s (buffer-substring (line-beginning-position) (line-end-position)))) + (if (string-match rdebug-breakpoint-regexp s) + (substring s (match-beginning 1) (match-end 1)) + nil)))) + +(defun rdebug-toggle-breakpoint (&optional pt) + "Toggle the breakpoint at PT in the breakpoints buffer." + (interactive "d") + (save-excursion + (if pt + (goto-char pt)) + (let ((s (buffer-substring (line-beginning-position) (line-end-position)))) + (when (string-match rdebug-breakpoint-regexp s) + (let* ((enabled + (string= (substring s (match-beginning 2) (match-end 2)) "y")) + (cmd (if enabled "disable" "enable")) + (bpnum (substring s (match-beginning 1) (match-end 1)))) + (gud-call (format "%s breakpoint %s" cmd bpnum))))))) + +(defun rdebug-add-breakpoint-condition (pt) + "Add an expression as a condition to the break `rdebug' Ruby debugger." + (interactive "d") + (let ((bpnum (rdebug-get-breakpoint-number pt)) + (expr (read-string "Ruby expression for breakpoint condition: "))) + (if bpnum + (gud-call (format "condition %s %s" bpnum expr)) + (message "Breakpoint number not found")))) + + +;; ----------------------------------------------- +;; Breakpoint icon support. +;; + +;; This is a trivial implementation, it has the following shortcomings: +;; +;; * It assumes that the buffer content doesn't change, if it does it +;; will not be able to remove the icon. +;; +;; * No support for displaying an icon in a newly opened file. +;; +;; * It has no support for more than one session. + +;; Note: This is implemented on top of `gdb-ui'. In the future, it +;; would be better if that code is generalized. + +(require 'gdb-ui) + +;; This is a local variable, should not be placed in rdebug-vars.el. +(defvar rdebug-breakpoint-icons-current-state nil) + +(defun rdebug-breakpoint-remove-icon (entry) + "Remove the the source buffer the fringe breakpoint icon breakpoint ENTRY." + (if (eq (nth 0 entry) :file) + (let ((buf (find-buffer-visiting (nth 3 entry)))) + (if buf + (save-current-buffer + (set-buffer buf) + (save-excursion + (goto-line (nth 4 entry)) + (gdb-remove-breakpoint-icons (point) (point)))))))) + +(defun rdebug-breakpoint-remove-all-icons () + "Remove all breakpoint fringe icons." + (interactive) + (dolist (entry rdebug-breakpoint-icons-current-state) + (rdebug-breakpoint-remove-icon entry)) + (setq rdebug-breakpoint-icons-current-state nil)) + + +(defun rdebug-breakpoint-add-icon (entry) + (if (eq (nth 0 entry) :file) + (let ((buf (find-buffer-visiting (nth 3 entry)))) + (if buf + (save-current-buffer + (set-buffer buf) + (save-excursion + (goto-line (nth 4 entry)) + ;; Workaround for bug in `gdb-ui'. (It checks + ;; `left-fringe-width' but it doesn't interpret the + ;; `nil' value correctly. + (let ((gdb-buffer-fringe-width (car (window-fringes)))) + (gdb-put-breakpoint-icon (nth 2 entry) + (number-to-string (nth 1 entry)))))))))) + +(defun rdebug-breakpoint-list-member (file line list) + (let ((res nil)) + (dolist (entry list) + (if (and (equal file (nth 3 entry)) + (equal line (nth 4 entry))) + (setq res t))) + res)) + +;; bpts has the same representation as returned by `rdebug-breakpoint-all'. +(defun rdebug-breakpoint-update-icons (bpts) + ;; Make sure there are is only one reference for each line. + (let ((state '())) + ;; An enabled breakpoint take precedence. + (dolist (enabled '(t nil)) + (dolist (bpt bpts) + (if (and (eq (nth 0 bpt) :file) + (eq (nth 2 bpt) enabled) + (not (rdebug-breakpoint-list-member + (nth 3 bpt) (nth 4 bpt) state))) + (setq state (cons bpt state))))) + (dolist (entry rdebug-breakpoint-icons-current-state) + (unless (member entry state) + (rdebug-breakpoint-remove-icon entry))) + (dolist (entry state) + (unless (member entry rdebug-breakpoint-icons-current-state) + (rdebug-breakpoint-add-icon entry))) + (setq rdebug-breakpoint-icons-current-state state))) + +;; ------------------------------------------------------------------- +;; The end. +;; + +(provide 'rdebug-breaks) + +;;; Local variables: +;;; eval:(put 'rdebug-debug-enter 'lisp-indent-hook 1) +;;; End: + +(provide 'rdebug-breaks) + +;;; rdebug-breaks.el ends here diff --git a/emacs/rdebug-cmd.el b/emacs/rdebug-cmd.el new file mode 100644 index 0000000..ada316c --- /dev/null +++ b/emacs/rdebug-cmd.el @@ -0,0 +1,92 @@ +;;; rdebug-cmd.el --- Ruby debugger command buffer + +;; Copyright (C) 2008 Rocky Bernstein (rocky@gnu.org) +;; Copyright (C) 2008 Anders Lindgren + +;; $Id: rdebug-cmd.el 822 2008-04-27 08:28:29Z rockyb $ + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; See the manual and the file `rdebug.el' for more information. + +;; This file contains code dealing primarily with the command buffer. + +;;; Code: + +(require 'ring) +(require 'rdebug-locring) + +(defun rdebug-command-initialization () + "Initialization of command buffer common to `rdebug' and`rdebug-track-attach'." + + ;; This opens up "Gud" menu, which isn't used since we've got our + ;; own "Debugger" menu. + ;; (set (make-local-variable 'gud-minor-mode) 'rdebug) + + (set (make-local-variable 'rdebug-call-queue) '()) + (set (make-local-variable 'rdebug-original-read-only) buffer-read-only) + (make-local-variable 'rdebug-source-location-ring-size) ; ...to global val. + (set (make-local-variable 'rdebug-source-location-ring) + (make-ring rdebug-source-location-ring-size)) + (make-local-variable 'rdebug-source-location-ring-index) + (rdebug-locring-clear) + + (gud-def gud-args "info args" "a" + "Show arguments of current stack frame.") + (gud-def gud-break "break %d%f:%l""\C-b" + "Set breakpoint at current line.") + (gud-def gud-cont "continue" "\C-r" + "Continue with display.") + (gud-def gud-down "down %p" "<" + "Down N stack frames (numeric arg).") + (gud-def gud-finish "finish" "\C-f" + "Finish executing current function.") + (gud-def gud-source-resync "up 0" "\C-l" + "Show current source window") + (gud-def gud-remove "clear %d%f:%l" "\C-d" + "Remove breakpoint at current line") + (gud-def gud-quit "quit" "Q" + "Quit debugger.") + + (gud-def gud-statement "eval %e" "\C-e" + "Execute Ruby statement at point.") + (gud-def gud-tbreak "tbreak %d%f:%l" "\C-t" + "Set temporary breakpoint at current line.") + (gud-def gud-up "up %p" + ">" "Up N stack frames to a newer frame (numeric arg).") + (gud-def gud-where "where" + "T" "Show stack trace.") + + (local-set-key [M-insert] 'rdebug-internal-short-key-mode) + (local-set-key [M-down] 'rdebug-locring-newer) + (local-set-key [M-up] 'rdebug-locring-older) + (local-set-key [M-S-down] 'rdebug-locring-newest) + (local-set-key [M-S-up] 'rdebug-locring-oldest) + ;; (local-set-key "\C-i" 'gud-gdb-complete-command) + (local-set-key "\C-c\C-n" 'comint-next-prompt) + (local-set-key "\C-c\C-p" 'comint-previous-prompt)) + +;; stopping location motion routines. + +(provide 'rdebug-cmd) + +;;; Local variables: +;;; eval:(put 'rdebug-debug-enter 'lisp-indent-hook 1) +;;; End: + +;;; rdebug-cmd.el ends here diff --git a/emacs/rdebug-core.el b/emacs/rdebug-core.el new file mode 100644 index 0000000..c8c43b7 --- /dev/null +++ b/emacs/rdebug-core.el @@ -0,0 +1,502 @@ +;;; rdebug-core.el --- Core parts of the Ruby debugger user +;;; interface. It pulls in other parts of the debugger. + +;; Copyright (C) 2006, 2007, 2008 Rocky Bernstein (rocky@gnu.org) +;; Copyright (C) 2007, 2008 Anders Lindgren + +;; $Id: rdebug-core.el 909 2009-03-11 18:57:08Z rockyb $ + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; See the manual and the file `rdebug.el' for more information. + +;; This file implements the core of the debugger. + +;;; Code: + +;; ------------------------------------------------------------------- +;; Consistency checks. +;; + +(if (< emacs-major-version 22) + (error + "This version of rdebug.el needs at least Emacs 22 or greater - you have version %d" + emacs-major-version)) + + +;; ------------------------------------------------------------------- +;; Dependencies. +;; + +(require 'gud) +(require 'cl) + +(require 'rdebug) +(require 'rdebug-annotate) +(require 'rdebug-dbg) +(require 'rdebug-cmd) +(require 'rdebug-layouts) +(require 'rdebug-source) +(require 'rdebug-regexp) +(require 'rdebug-vars) + +(defun rdebug-get-script-name (args) + "Parse command line ARGS. + +A list containing the script name, and whether the annotate +option was set is returned. + +Initially annotate should be set to nil. Argument ARGS contains +a tokenized list of the command line." + ;; Parse the following: + ;; + ;; [ruby ruby-options] rdebug rdebug-options script-name script-options + (and args + (let ((name nil) + (annotate-p nil)) + ;; Strip of optional "ruby" or "ruby182" etc. + (when (string-match "^ruby[0-9]*$" + (file-name-sans-extension + (file-name-nondirectory (car args)))) + (pop args) + (while (and args + (string-match "^-" (car args))) + (if (member (car args) '("-e" "-r" "-I" "-C" "-F" "-K")) + (pop args)) + (pop args))) + ;; Remove "rdebug" from "rdebug --rdebug-options script + ;; --script-options" + (pop args) + ;; Skip to the first non-option argument. + (while (and args + (not name)) + (let ((arg (pop args))) + (cond + ;; Annotation or emacs option with level number. + ((or (member arg '("--annotate" "-A")) + (equal arg "--emacs")) + (setq annotate-p t) + (pop args)) + ;; Combined annotation and level option. + ((string-match "^--annotate=[0-9]" arg) + (setq annotate-p t)) + ;; Options with arguments. + ((member arg '("-h" "--host" "-p" "--port" + "-I" "--include" "-r" "--require")) + (pop args)) + ((string-match "^-" arg) + nil) + (t + (setq name arg))))) + (and name + (list name annotate-p))))) + +;; ------------------------------------------------------------------- +;; Window configuration state support. +;; + +(defun rdebug-set-window-configuration-state (state &optional dont-restore) + "Change window configuration state. + +Two states are supported, `original' and `debugger'. + +When `dont-restore' is non-nil, the old window layout is not +restored. This is used when a new layout is being drawn, for +example when the debugger starts." + (rdebug-debug-message "Setting state to %s (was %s)" + state rdebug-window-configuration-state) + (when (not (eq state rdebug-window-configuration-state)) + ;; Save the previous state. + (cond ((not (eq rdebug-window-configuration-state 'original)) + (setq rdebug-debugger-window-configuration + (current-window-configuration))) + ((eq rdebug-window-configuration-state 'original) + (setq rdebug-original-window-configuration + (current-window-configuration)))) + (unless dont-restore + ;; Switch to the saved state, + (cond + ((not (eq state 'original)) + (if rdebug-debugger-window-configuration + (set-window-configuration rdebug-debugger-window-configuration))) + ((eq state 'original) + (if rdebug-original-window-configuration + (set-window-configuration rdebug-original-window-configuration))))) + (setq rdebug-window-configuration-state state))) + + +;; have to bind rdebug-file-queue before installing the kill-emacs-hook +(defvar rdebug-file-queue nil + "Queue of Makefile temp files awaiting execution. +Currently-active file is at the head of the list.") + +(defun rdebug-goto-traceback-line (pt) + "Display the location PT in a source file of the Ruby traceback line." + (interactive "d") + (save-excursion + (goto-char pt) + (let ((s (buffer-substring (line-beginning-position) (line-end-position))) + (gud-comint-buffer (current-buffer))) + (when (string-match rdebug-traceback-line-re s) + (rdebug-display-line + (substring s (match-beginning 1) (match-end 1)) + (string-to-number (substring s (match-beginning 2) (match-end 2)))) + )))) + +(defun rdebug-goto-dollarbang-traceback-line (pt) + "Display the location PT in a source file of the Ruby $! traceback line." + (interactive "d") + (save-excursion + (goto-char pt) + (let ((s (buffer-substring (line-beginning-position) (line-end-position))) + (gud-comint-buffer (current-buffer))) + (when (string-match rdebug-dollarbang-traceback-line-re s) + (rdebug-display-line + (substring s (match-beginning 1) (match-end 1)) + (string-to-number (substring s (match-beginning 2) (match-end 2)))) + )))) + +;; ------------------------------------------------------------------- +;; Secondary buffers. +;; + +(require 'rdebug-secondary) +(require 'rdebug-breaks) +(require 'rdebug-frames) +(require 'rdebug-help) +(require 'rdebug-output) +(require 'rdebug-varbuf) +(require 'rdebug-watch) + + +;; ------------------------------------------------------------------- +;; Windows. +;; + +(defun rdebug-setup-windows (&optional erase) + "Create the debugger user interface window layout. + +If ERASE is non-nil, the content of the windows are erased +\(this does not apply to accumulative windows). + +This function displays the source file (or, in some cases, a +buffer list) and creates the window layout. The variable +`rdebug-window-layout-function' controls the function that is +used to perform the actual layout. + +This is only used when `rdebug-many-windows' is non-nil." + (rdebug-debug-enter "rdebug-setup-windows" + (rdebug-set-window-configuration-state 'debugger t) + (pop-to-buffer gud-comint-buffer) + (maphash + (lambda (name func) + (if erase + (let ((buf (rdebug-get-existing-buffer name gud-target-name))) + (if buf + (with-current-buffer buf + (let ((inhibit-read-only t)) + (erase-buffer)))))) + (rdebug-process-annotation name "")) + rdebug-annotation-setup-map) + (let ((buf + (cond (gud-last-last-frame + (gud-find-file (car gud-last-last-frame))) + (gud-target-name + (gud-find-file gud-target-name))))) + ;; Put a buffer in window if we can't find a source file. + (unless buf (setq buf (get-buffer-create "*scratch*"))) + (funcall rdebug-window-layout-function buf gud-target-name)))) + + +(defun rdebug-setup-windows-initially () + "Like `rdebug-setup-windows', but erase the content of accumulative windows. +This is called when the debugger starts." + (rdebug-setup-windows t)) + + +(defun rdebug-restore-debugger-window-layout () + "Restore the initial ruby debugger window layout." + (interactive) + (when rdebug-many-windows + (rdebug-setup-windows))) + +(defun rdebug-display-debugger-window-configuration () + "Switch from the \"original\" to the \"debugger\" window layout. + +The rdebug debugger remembers, and can switch between, two window layouts: + * original -- the window layout when the debugger was started. + * debugger -- the window layout of the debugger, plus all changes made + since the debugger started. + +The check-marks in the \"Window Layout\" menu indicates the +active window layout. + +The function `rdebug-display-original-window-configuration' +switch to the \"original\" window configuration. + +The function `rdebug-restore-debugger-window-layout' restores the +window layout to the state it was when the debugger started." + (interactive) + (rdebug-set-window-configuration-state 'debugger) + (message + "Type `M-x rdebug-display-original-window-configuration RET' to restore.")) + + +;;This function is called upon quitting the debugger and +;;`rdebug-many-windows' is not nil. See also +;;`rdebug-display-debugger-window-configuration'." + +(defun rdebug-display-original-window-configuration () + "Switch from the \"debugger\" to the \"original\" window layout. + +The rdebug debugger remembers, and can switch between, two window layouts: + * original -- the window layout when the debugger was started. + * debugger -- the window layout of the debugger, plus all changes made + since the debugger started. + +The check-marks in the \"Window Layout\" menu indicates the +active window layout. + +The function `rdebug-display-debugger-window-configuration' +switch to the \"debugger\" window configuration." + (interactive) + (rdebug-set-window-configuration-state 'original) + (message + "Type `M-x rdebug-display-debugger-window-configuration RET' to restore.")) + + +;; ------------------------------------------------------------------- +;; The `rdebug' command and support functions. +;; + +(defun rdebug-process-sentinel (process event) + "Restore the original window configuration when the debugger process exits." + (rdebug-debug-enter "rdebug-process-sentinel" + (rdebug-debug-message "status=%S event=%S state=%S" + (process-status process) + event + rdebug-window-configuration-state) + (gud-sentinel process event) + ;; This will "flush" the last annotation. Especially "output" + ;; (a.k.a. "starting") annotations don't have an end markers, if + ;; the last command printed something. + (if (string= event "finished\n") + (gud-rdebug-marker-filter "\032\032\n")) + ;; When the debugger process exited, when the comint buffer has no + ;; buffer process (nil). When the debugger processes is replaced + ;; with another process we should not restore the window + ;; configuration. + (when (and (or (eq rdebug-restore-original-window-configuration t) + (and (eq rdebug-restore-original-window-configuration :many) + rdebug-many-windows)) + (or (rdebug-dead-process-p) + (eq process (get-buffer-process gud-comint-buffer))) + (eq rdebug-window-configuration-state 'debugger) + (not (eq (process-status process) 'run))) + (rdebug-internal-short-key-mode-off) + (rdebug-set-window-configuration-state 'original) + (rdebug-reset-keymaps)))) + + +;; Perform initializations common to all debuggers. +;; The first arg is the specified command line, +;; which starts with the program to debug. +;; The other three args specify the values to use +;; for local variables in the debugger buffer. +(defun rdebug-common-init (rdebug-buffer-name rdebug-cmd-buffer target-name + program args + marker-filter + &optional find-file) + "Perform initializations common to all debuggers. + +RDEBUG-BUFFER-NAME is the specified command line, which starts +with the program to debug. PROGRAM, ARGS and MARKER-FILTER +specify the values to use for local variables in the debugger +buffer." + (if rdebug-cmd-buffer + (progn + (pop-to-buffer rdebug-cmd-buffer) + (when (and rdebug-cmd-buffer (get-buffer-process rdebug-cmd-buffer)) + (error "This program is already being debugged")) + (apply 'make-comint rdebug-buffer-name program nil args) + (or (bolp) (newline))) + (pop-to-buffer (setq rdebug-cmd-buffer + (apply 'make-comint rdebug-buffer-name program nil + args)))) + + ;; Since comint clobbered the mode, we don't set it until now. + (gud-mode) + (set (make-local-variable 'gud-target-name) target-name) + (set (make-local-variable 'gud-marker-filter) marker-filter) + (set (make-local-variable 'gud-minor-mode) 'rdebug) + (set (make-local-variable 'gud-last-frame) nil) + (set (make-local-variable 'gud-last-last-frame) nil) + + (let ((buffer-process (get-buffer-process (current-buffer)))) + (if buffer-process + (progn + (set-process-filter buffer-process 'gud-filter) + (set-process-sentinel buffer-process 'gud-sentinel)))) + (gud-set-buffer)) + +;;;###autoload +(defun rdebug (command-line) + "Invoke the rdebug Ruby debugger and start the Emacs user interface. + +String COMMAND-LINE specifies how to run rdebug. + +By default, the \"standard\" user window layout looks like the following: + ++----------------------------------------------------------------------+ +| Toolbar | ++-----------------------------------+----------------------------------+ +| Debugger shell | Variables buffer | ++-----------------------------------+----------------------------------+ +| | | +| Source buffer | Output buffer | +| | | ++-----------------------------------+----------------------------------+ +| Stack Frame buffer | Breakpoints buffer | ++-----------------------------------+----------------------------------+ + +The variable `rdebug-window-layout-function' can be +customized so that another layout is used. In addition to a +number of predefined layouts it's possible to define a function +to perform a custom layout. + +If `rdebug-many-windows' is nil, only a traditional debugger +shell and source window is opened. + +The directory containing the debugged script becomes the initial +working directory and source-file directory for your debugger. + +The custom variable `gud-rdebug-command-name' sets the command +and options used to invoke rdebug." + (interactive + (let ((init (buffer-file-name))) + (setq init (and init + (file-name-nondirectory init))) + (list (gud-query-cmdline 'rdebug init)))) + (rdebug-debug-enter "rdebug" + (rdebug-set-window-configuration-state 'debugger t) + ;; Parse the command line and pick out the script name and whether + ;; --annotate has been set. + (let* ((words (with-no-warnings + (split-string-and-unquote command-line))) + (script-name-annotate-p (rdebug-get-script-name + (gud-rdebug-massage-args "1" words))) + (target-name (file-name-nondirectory (car script-name-annotate-p))) + (annotate-p (cadr script-name-annotate-p)) + (cmd-buffer-name (format "rdebug-cmd-%s" target-name)) + (rdebug-cmd-buffer-name (format "*%s*" cmd-buffer-name)) + (rdebug-cmd-buffer (get-buffer rdebug-cmd-buffer-name)) + (program (car words)) + (args (cdr words)) + (gud-chdir-before-run nil)) + + ;; `gud-rdebug-massage-args' needs whole `command-line'. + ;; command-line is refered through dynamic scope. + (rdebug-common-init cmd-buffer-name rdebug-cmd-buffer target-name + program args + 'gud-rdebug-marker-filter + 'gud-rdebug-find-file) + (setq comint-process-echoes t) + + (setq rdebug-inferior-status "running") + + (rdebug-command-initialization) + + ;; Setup exit callback so that the original frame configuration + ;; can be restored. + (let ((process (get-buffer-process gud-comint-buffer))) + (when process + (unless (equal rdebug-line-width 120) + (gud-call (format "set width %d" rdebug-line-width))) + (set-process-sentinel process + 'rdebug-process-sentinel))) + + + ;; Add the buffer-displaying commands to the Gud buffer, + ;; FIXME: combine with code in rdebug-track.el; make common + ;; command buffer mode map. + (let ((prefix-map (make-sparse-keymap))) + (define-key (current-local-map) gud-key-prefix prefix-map) + (define-key prefix-map "t" 'rdebug-goto-traceback-line) + (define-key prefix-map "!" 'rdebug-goto-dollarbang-traceback-line) + (rdebug-populate-secondary-buffer-map-plain prefix-map)) + + (rdebug-populate-common-keys (current-local-map)) + (rdebug-populate-debugger-menu (current-local-map)) + + (setq comint-prompt-regexp (concat "^" rdebug-input-prompt-regexp)) + (setq paragraph-start comint-prompt-regexp) + + (setcdr (assq 'rdebug-debugger-support-minor-mode minor-mode-map-alist) + rdebug-debugger-support-minor-mode-map-when-active) + (when rdebug-many-windows + (rdebug-setup-windows-initially)) + + (run-hooks 'rdebug-mode-hook)))) + + +(defadvice gud-reset (before rdebug-reset) + "Rdebug cleanup - remove debugger's internal buffers (frame, breakpoints, etc.)." + (rdebug-breakpoint-remove-all-icons) + (dolist (buffer (buffer-list)) + (when (string-match "\\*rdebug-[a-z]+\\*" (buffer-name buffer)) + (let ((w (get-buffer-window buffer))) + (when w + (delete-window w))) + (kill-buffer buffer)))) +(ad-activate 'gud-reset) + +(defun rdebug-reset () + "Rdebug cleanup - remove debugger's internal buffers (frame, breakpoints, etc.)." + (interactive) + (rdebug-breakpoint-remove-all-icons) + (dolist (buffer (buffer-list)) + (when (string-match "\\*rdebug-[a-z]+\\*" (buffer-name buffer)) + (let ((w (get-buffer-window buffer))) + (when w + (delete-window w))) + (kill-buffer buffer)))) + +(defun rdebug-reset-keymaps() + "This unbinds the special debugger keys of the source buffers." + (interactive) + (setcdr (assq 'rdebug-debugger-support-minor-mode minor-mode-map-alist) + rdebug-debugger-support-minor-mode-map-when-deactive)) + + +(defun rdebug-customize () + "Use `customize' to edit the settings of the `rdebug' debugger." + (interactive) + (customize-group 'rdebug)) + + +;; ------------------------------------------------------------------- +;; The end. +;; + +(provide 'rdebug-core) + +;;; Local variables: +;;; eval:(put 'rdebug-debug-enter 'lisp-indent-hook 1) +;;; End: + +;;; rdebug-core.el ends here diff --git a/emacs/rdebug-dbg.el b/emacs/rdebug-dbg.el new file mode 100644 index 0000000..0952595 --- /dev/null +++ b/emacs/rdebug-dbg.el @@ -0,0 +1,62 @@ +;;; rdebug-dbg.el --- Ruby debugger frames buffer + +;; Copyright (C) 2008 Rocky Bernstein (rocky@gnu.org) +;; Copyright (C) 2008 Anders Lindgren + +;; $Id: rdebug-dbg.el 702 2008-02-17 22:00:36Z rockyb $ + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; See the manual and the file `rdebug.el' for more information. + +;; This file contains internal debug trace support. + +;;; Code: + +(require 'rdebug-vars) + +(defun rdebug-debug-message (&rest args) + (if rdebug-debug-active + (let ((buf (get-buffer-create "*Xrdebug*"))) + (with-current-buffer buf + (save-excursion + (goto-char (point-max)) + ;; 32 = space. + (insert (make-string (* 4 rdebug-debug-depth) 32)) + (insert (apply #'format args)) + (insert "\n")))))) + + +(defmacro rdebug-debug-enter (str &rest body) + (declare (indent 1) (debug t)) + `(progn + (rdebug-debug-message "--> %s" ,str) + (setq rdebug-debug-depth (+ rdebug-debug-depth 1)) + (unwind-protect + (progn + ,@body) + (setq rdebug-debug-depth (max 0 (- rdebug-debug-depth 1))) + (rdebug-debug-message "<-- %s" ,str)))) + +(provide 'rdebug-dbg) + +;;; Local variables: +;;; eval:(put 'rdebug-debug-enter 'lisp-indent-hook 1) +;;; End: + +;;; rdebug-dbg.el ends here diff --git a/emacs/rdebug-error.el b/emacs/rdebug-error.el new file mode 100644 index 0000000..a16818c --- /dev/null +++ b/emacs/rdebug-error.el @@ -0,0 +1,79 @@ +;;; rdebug-error.el --- Ruby debugger error buffer + +;; Copyright (C) 2008 Rocky Bernstein (rocky@gnu.org) +;; Copyright (C) 2008 Anders Lindgren + +;; $Id: rdebug-error.el 713 2008-02-21 02:56:48Z rockyb $ + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; See the manual and the file `rdebug.el' for more information. + +;; This file contains code dealing with the error secondary buffer. + +;;; Code: + +(require 'rdebug-dbg) +(require 'rdebug-fns) +(require 'rdebug-secondary) +(require 'rdebug-source) + +(defun rdebug-display-error-buffer () + "Display the rdebug error buffer." + (interactive) + (rdebug-display-secondary-buffer "error")) + +(defvar rdebug-error-mode-map + (let ((map (make-sparse-keymap))) + (rdebug-populate-secondary-buffer-map map) + map) + "Keymap used in the error buffer in the `rdebug' Ruby debugger.") + +(defun rdebug-error-mode () + "Major mode for displaying the script error in the `rdebug' Ruby debugger. + +\\{rdebug-error-mode}" + (interactive) + (kill-all-local-variables) + (setq major-mode 'rdebug-error-mode) + (setq mode-name "RDEBUG Error") + (setq buffer-read-only t) + (set (make-local-variable 'rdebug-secondary-buffer) t) + (setq mode-line-process 'rdebug-mode-line-process) + (use-local-map rdebug-error-mode-map) + (run-mode-hooks 'rdebug-error-mode-hook)) + +(defun rebug-setup-error-buffer (buf comint-buffer) + (rdebug-debug-enter "rebug-setup-error-buffer" + (with-current-buffer buf + (rdebug-error-mode) + (set (make-local-variable 'gud-comint-buffer) comint-buffer)))) + +(defun rdebug-errmsg (msg) +;;; (with-current-buffer (rdebug-get-buffer "error" gud-target-name) +;;; (goto-char (point-max)) +;;; (insert msg)) + (message (chomp msg))) + +(provide 'rdebug-error) + +;;; Local variables: +;;; eval:(put 'rdebug-debug-enter 'lisp-indent-hook 1) +;;; End: + +;;; rdebug-error.el ends here diff --git a/emacs/rdebug-fns.el b/emacs/rdebug-fns.el new file mode 100644 index 0000000..ef0c0f1 --- /dev/null +++ b/emacs/rdebug-fns.el @@ -0,0 +1,111 @@ +;;; rdebug-fns.el --- Ruby debugger miscellaneous functions + +;; Copyright (C) 2008 Rocky Bernstein (rocky@gnu.org) +;; Copyright (C) 2008 Anders Lindgren + +;; $Id: rdebug-frames.el 711 2008-02-20 07:09:17Z andersl $ + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; See the manual and the file `rdebug.el' for more information. + +;; This file contains code dealing with the frames secondary buffer. + +;;; Code: + +(require 'gud) +(require 'rdebug-vars) + +(defun chomp(string &optional multiple) + "Remove trailing \n if it's there" + (if multiple + (progn + (while (and (> (length string) 0) + (eq (elt string (- (length string) 1)) ?\n)) + (setq string (substring string 0 -1))) + string) + (if (> (length string) 0) + (let ((s string)) + (if (string= "\n" (substring s -1)) + (substring s 0 -1) + s)) + ""))) + +(defun rdebug-dead-process-p () + "Return true if the rdebug comint-process is dead or exited." + ;; FIXME? Use a variable in gud-comint-buffer's status? + (or (not gud-comint-buffer) + (null (get-buffer-process gud-comint-buffer)) + (not (member (process-status gud-comint-buffer) '(run open))))) + +(defun rdebug-get-secondary-buffer-name (name) + "Get the rdebug NAME secondary buffer. If none found return nil." + (let ((target-name + (or (and gud-comint-buffer + (buffer-local-value 'gud-target-name + gud-comint-buffer)) + gud-target-name))) + (cond ((and (string= "cmd" name) gud-comint-buffer) + (buffer-name gud-comint-buffer)) + (t (format "*rdebug-%s-%s*" name target-name))))) + +(defun rdebug-set-frame-top-arrow (buf) + "Set the fringe arrow in BUF to indicate the top frame." + (with-current-buffer buf + (setq fringe-indicator-alist + '((overlay-arrow . right-triangle))))) + +(defun rdebug-set-frame-not-top-arrow (buf) + "Set the fringe arrow in BUF to indicate a frame other than the top frame." + (with-current-buffer buf + (setq fringe-indicator-alist + '((overlay-arrow . hollow-right-triangle))))) + +(defun rdebug-set-frame-arrow (buf) + "Set the fringe arrow in buffer BUF." + (if (equal 0 rdebug-frames-current-frame-number) + (rdebug-set-frame-top-arrow buf) + (rdebug-set-frame-not-top-arrow buf))) + +;; From Emacs 23 +(unless (fboundp 'split-string-and-unquote) + (defun split-string-and-unquote (string &optional separator) + "Split the STRING into a list of strings. +It understands Emacs Lisp quoting within STRING, such that + (split-string-and-unquote (combine-and-quote-strings strs)) == strs +The SEPARATOR regexp defaults to \"\\s-+\"." + (let ((sep (or separator "\\s-+")) + (i (string-match "[\"]" string))) + (if (null i) + (split-string string sep t) ; no quoting: easy + (append (unless (eq i 0) (split-string (substring string 0 i) sep t)) + (let ((rfs (read-from-string string i))) + (cons (car rfs) + (with-no-warnings + (split-string-and-unquote (substring string (cdr rfs)) + sep)))))))) + ) + + +(provide 'rdebug-fns) + +;;; Local variables: +;;; eval:(put 'rdebug-debug-enter 'lisp-indent-hook 1) +;;; End: + +;;; rdebug-fns.el ends here diff --git a/emacs/rdebug-frames.el b/emacs/rdebug-frames.el new file mode 100644 index 0000000..6cbabb0 --- /dev/null +++ b/emacs/rdebug-frames.el @@ -0,0 +1,230 @@ +;;; rdebug-frames.el --- Ruby debugger frames buffer + +;; Copyright (C) 2008 Rocky Bernstein (rocky@gnu.org) +;; Copyright (C) 2008 Anders Lindgren + +;; $Id: rdebug-frames.el 735 2008-02-29 15:24:51Z rockyb $ + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; See the manual and the file `rdebug.el' for more information. + +;; This file contains code dealing with the frames secondary buffer. + +;;; Code: + +(require 'rdebug-dbg) +(require 'rdebug-fns) +(require 'rdebug-regexp) +(require 'rdebug-secondary) +(require 'rdebug-source) + +(defun rdebug-display-frame-buffer () + "Display the rdebug stack-frame buffer." + (interactive) + (rdebug-display-secondary-buffer "frame")) + +(defvar rdebug-frames-mode-map + (let ((map (make-sparse-keymap))) + (define-key map [double-mouse-1] 'rdebug-goto-frame-mouse) + (define-key map [mouse-2] 'rdebug-goto-frame-mouse) + (define-key map [mouse-3] 'rdebug-goto-frame-mouse) + (define-key map [(control m)] 'rdebug-goto-frame) + (define-key map "0" 'rdebug-goto-frame-n) + (define-key map "1" 'rdebug-goto-frame-n) + (define-key map "2" 'rdebug-goto-frame-n) + (define-key map "3" 'rdebug-goto-frame-n) + (define-key map "4" 'rdebug-goto-frame-n) + (define-key map "5" 'rdebug-goto-frame-n) + (define-key map "6" 'rdebug-goto-frame-n) + (define-key map "7" 'rdebug-goto-frame-n) + (define-key map "8" 'rdebug-goto-frame-n) + (define-key map "9" 'rdebug-goto-frame-n) + (rdebug-populate-secondary-buffer-map map) + + ;; -------------------- + ;; The "Stack window" submenu. + (let ((submenu (make-sparse-keymap))) + (define-key-after map [menu-bar debugger stack] + (cons "Stack window" submenu) + 'placeholder)) + + (define-key map [menu-bar debugger stack goto] + '(menu-item "Goto frame" rdebug-goto-frame)) + map) + "Keymap to navigate rdebug stack frames.") + +(defun rdebug-goto-frame (pt) + "Show the rdebug stack frame corresponding at PT in the rdebug stack buffer." + (interactive "d") + (save-excursion + (goto-char pt) + (let ((s (concat "-->" (buffer-substring (line-beginning-position) + (line-end-position)))) + (s2 (if (= (line-number-at-pos (line-end-position 2)) + (line-number-at-pos (point-max))) + nil + ;;else + (buffer-substring (line-beginning-position 2) + (line-end-position 2))))) + (when (or (string-match rdebug-stack-frame-regexp s) + ;; need to match 1st line last to get the match position right + (and s2 (string-match rdebug-stack-frame-2nd-regexp s2) + (string-match rdebug-stack-frame-1st-regexp s))) + (let ((frame (substring s (match-beginning 2) (match-end 2)))) + (gud-call (concat "frame " frame))))))) + +(defun rdebug-goto-frame-mouse (event) + "Show the rdebug stack frame under the mouse in the rdebug stack buffer." + (interactive "e") + (with-current-buffer (window-buffer (posn-window (event-end event))) + (rdebug-goto-frame (posn-point (event-end event))))) + +;; The following is split in two to facilitate debugging. +(defun rdebug-goto-frame-n-internal (keys) + (if (and (stringp keys) + (= (length keys) 1)) + (progn + (setq rdebug-goto-entry-acc (concat rdebug-goto-entry-acc keys)) + ;; Try to find the longest suffix. + (let ((acc rdebug-goto-entry-acc)) + (while (not (string= acc "")) + (if (not (rdebug-goto-entry-try acc)) + (setq acc (substring acc 1)) + (gud-call (format "frame %s" acc)) + ;; Break loop. + (setq acc ""))))) + (message "`rdebug-goto-frame-n' must be bound to a number key"))) + +(defun rdebug-goto-frame-n () + "Go to the frame number indicated by the accumulated numeric keys just entered. + +This function is usually bound to a numeric key in a 'frame' +secondary buffer. To go to an entry above 9, just keep entering +the number. For example, if you press 1 and then 9, frame 1 is selected +\(if it exists) and then frame 19 (if that exists). Entering any +non-digit will start entry number from the beginning again." + (interactive) + (if (not (eq last-command 'rdebug-goto-frame-n)) + (setq rdebug-goto-entry-acc "")) + (rdebug-goto-frame-n-internal (this-command-keys))) + +(defun rdebug-frames-match-current-line (limit) + (and rdebug-frames-current-frame-number + (re-search-forward + (concat "^ *#" + (number-to-string rdebug-frames-current-frame-number) + ;; At least one space (so that we don't match #1 when looking for #10). + " +" + ;; The entire line. + ".*" + "\n" + ;; And the next, if this entry was split into two. + "\\( *[^# ].*$\\)?") limit t))) + +(defvar rdebug-frames-current-frame-face 'highlight) + +;; Example of frame buffer content: +;; +;; #0 Integer.under_cover at line test.rb:13 +;; #1 ClassA::Nested::DeepDown.under_cover(p#ClassA::Nested::DeepD...) +;; at line test.rb:12 +;; #2 Object.sune(s#String, i#Fixnum) at line test.rb:24 +;; #3 at line test.rb:27 + +(defvar rdebug-frames-font-lock-keywords + '( + ;; Parameters and first type entry. + ("\\<\\([a-zA-Z_][a-zA-Z0-9_]*\\)#\\([a-zA-Z_][a-zA-Z0-9_]*\\)\\>" + (1 font-lock-variable-name-face) + (2 font-lock-type-face)) + ;; "::Type", which occurs in class name of function and in parameter list. + ("::\\([a-zA-Z_][a-zA-Z0-9_]*\\)" + (1 font-lock-type-face)) + ;; The frame number and first type name, if present. + ("^ *#\\([0-9]+\\) *\\(\\([a-zA-Z_][a-zA-Z0-9_]*\\)[.:]\\)?" + (1 font-lock-constant-face) + (3 font-lock-type-face nil t)) ; t means optional. + ;; File name and line number. + ("at line \\(.*\\):\\([0-9]+\\)$" + (1 font-lock-warning-face) + (2 font-lock-constant-face)) + ;; Function name. + ("\\<\\([a-zA-Z_][a-zA-Z0-9_]*\\)\\.\\([a-zA-Z_][a-zA-Z0-9_]*\\)" + (1 font-lock-type-face) + (2 font-lock-function-name-face)) + (rdebug-frames-match-current-line + (0 rdebug-frames-current-frame-face append))) + "Font-lock rules for the stack frame window in `rdebug'.") + +(defun rdebug-frames-mode () + "Major mode for displaying the stack trace in the `rdebug' Ruby debugger. +\\{rdebug-frames-mode-map}" + (interactive) + (kill-all-local-variables) + (setq major-mode 'rdebug-frames-mode) + (setq mode-name "RDEBUG Stack Frames") + (set (make-local-variable 'rdebug-secondary-buffer) t) + (setq mode-line-process 'rdebug-mode-line-process) + (use-local-map rdebug-frames-mode-map) + (set (make-local-variable 'font-lock-defaults) + '(rdebug-frames-font-lock-keywords)) + (run-mode-hooks 'rdebug-frames-mode-hook)) + +;; Note: This function can't restore the original point alone, since +;; the point is already at the end of the buffer when this is called. +(defun rdebug-setup-frame-buffer (buf comint-buffer) + "Find the current frame and display the corresponding source line. + +Also, cleans the buffer somewhat and sets up help for the font-lock rules." + (rdebug-debug-enter "rdebug-setup-stack-buffer" + (with-current-buffer buf + (let ((inhibit-read-only t) + (current-frame-number 0)) + (rdebug-frames-mode) + (set (make-local-variable 'gud-comint-buffer) comint-buffer) + (goto-char (point-min)) + (when (re-search-forward "-->" nil t) + (beginning-of-line) + (setq overlay-arrow-position (make-marker)) + (set-marker overlay-arrow-position (point)) + (when (looking-at rdebug-stack-frame-1st-regexp) + (setq current-frame-number + (string-to-number + (match-string rdebug-stack-frame-number-group))) + (set (make-local-variable 'rdebug-frames-current-frame-number) + current-frame-number) + (with-current-buffer comint-buffer + (setq rdebug-frames-current-frame-number current-frame-number)) + (when gud-last-frame + (rdebug-set-frame-arrow (gud-find-file (car gud-last-frame)))) + (rdebug-set-frame-arrow buf))) + ;; Remove initial ' ' or '-->'. + (save-excursion + (goto-char (point-max)) + (beginning-of-line) + (if (> (point) 4) + (delete-rectangle 4 (point)))))))) + +(provide 'rdebug-frames) + +;;; Local variables: +;;; eval:(put 'rdebug-debug-enter 'lisp-indent-hook 1) +;;; End: + +;;; rdebug-frames.el ends here diff --git a/emacs/rdebug-gud.el b/emacs/rdebug-gud.el new file mode 100644 index 0000000..d4f6086 --- /dev/null +++ b/emacs/rdebug-gud.el @@ -0,0 +1,242 @@ +;;; rdebug-gud.el --- rdebug interface to gud. + +;; Copyright (C) 2007, 2008 Rocky Bernstein (rocky@gnu.org) +;; Copyright (C) 2007, 2008 Anders Lindgren + +;; $Id: rdebug-gud.el 821 2008-04-25 02:54:44Z rockyb $ + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; See the manual and the file `rdebug.el' for more information. + +;; This file contains rdebug Emacs routines which interface with gud. + +;;; Code: + +;; ------------------------------------------------------------------- +;; Dependencies. +;; + +(require 'gud) +(require 'rdebug-error) +(require 'rdebug-fns) +(require 'rdebug-regexp) +(require 'rdebug-vars) + + +(defun gud-rdebug-massage-args (file args) + "Change FILE and list ARGS before running the debugger. + +gud requires this routine to be defined." + args) + + +(defun gud-rdebug-find-file (file) + "`rdebug' and `gud' call this with FILE when they encounter a Ruby program file." + + (find-file-noselect file 'nowarn)) + +(defun rdebug-display-line (file line &optional move-arrow) + "Arrange for marker to appear in at FILE and LINE. +The line marker might appear in the Emacs fringe or as an overlay arroe. +Optional argument MOVE-ARROW indicates whether to move any previous indicator." + (if file + (let ((oldpos (and gud-overlay-arrow-position + (marker-position gud-overlay-arrow-position))) + (oldbuf (and gud-overlay-arrow-position + (marker-buffer gud-overlay-arrow-position)))) + (gud-display-line file line) + (unless move-arrow + (when gud-overlay-arrow-position + (set-marker gud-overlay-arrow-position oldpos oldbuf)))))) + +(defun rdebug-stepping (step-or-next &optional arg) + (or arg (setq arg 1)) + ;;(if (not (member '('rdebug-next 'rdebug-step 'digit-argument) last-command)) + ;; (setq rdebug-stepping-prefix "")) + (unless (member rdebug-stepping-prefix '("" "+" "-")) + (setq rdebug-stepping-prefix "")) + (rdebug-call (format "%s%s %d" step-or-next rdebug-stepping-prefix arg))) + + + +;; ------------------------------------------------------------------- +;; Rdebug commands. +;; + +(defun rdebug-call (cmd) + "Run a debugger command with some error checking." + (if (rdebug-dead-process-p) + (rdebug-errmsg + "Can't find a live debugger process buffer to feed the command to.") + (gud-call cmd))) + +(defun rdebug-call-return (cmd &rest options) + "Register a debugger command whose output should be handled specially. + +OPTIONS is zero or more indicators what should happen with the +output. The following are supported: + * :tooltip -- Show the result in a tool-tip. + * :info -- Show the result in the info secondary buffer." + (if (rdebug-dead-process-p) + (rdebug-errmsg + "Can't find a live debugger process buffer to feed the command to.") + (with-current-buffer gud-comint-buffer + (setq rdebug-call-queue + (append rdebug-call-queue (list (cons cmd options)))) + (gud-call cmd)))) + +(defun rdebug-continue (&optional arg) + "Run a debugger \"continue\" command. + +With a numeric ARG, continue to that line number of the current file." + (interactive "p") + (if arg + (rdebug-call (format "continue %d" arg)) + (rdebug-call (format "continue")))) + + +(defun rdebug-next (&optional arg) + "Run a debugger \"next\" command, respecting `rdebug-stepping-prefix'. + +With a numeric ARG, continue to that line number of the current file." + (interactive "p") + (rdebug-stepping "next" arg)) + +(defvar rdebug-stepping-prefix "" + "The kind of stepping modifier that is desired. + +This variable will have a string value which is either \"\", +\"+\", or \"-\"; this string is be appended to the debugger +stepping commands (\"next\", or \"step\").") + +(defun rdebug-print-cmd (expr &optional cmd) + "Run a debugger print (pl, ps, pp, p) command on `EXPR'; `CMD' is the command to run." + (interactive "s") + (unless cmd (setq cmd "pp")) + (rdebug-call-return (format "%s %s " cmd expr) :tooltip)) + +(defun rdebug-print-list-region (from to) + "Run a debugger \"pl\" command on the marked region." + (interactive "r") + (if (> from to) + (let ((tem to)) + (setq to from from tem))) + (rdebug-print-cmd (buffer-substring from to) "pl")) + +(defun rdebug-print-region (from to) + "Run a debugger \"p\" command on the marked region." + (interactive "r") + (if (> from to) + (let ((tem to)) + (setq to from from tem))) + (rdebug-print-cmd (buffer-substring from to) "p")) + +(defun rdebug-print-sorted-region (from to) + "Run a debugger \"ps\" command on the marked region." + (interactive "r") + (if (> from to) + (let ((tem to)) + (setq to from from tem))) + (rdebug-print-cmd (buffer-substring from to) "ps")) + +(defun rdebug-pretty-print-region (from to) + "Run a debugger \"pp\" command on the marked region." + (interactive "r") + (if (> from to) + (let ((tem to)) + (setq to from from tem))) + (rdebug-print-cmd (buffer-substring from to) "pp")) + + +;; +;; The following two commands should be seen as proof-of-concept +;; functions for the info buffer. +;; + +(defun rdebug-pretty-print-to-buffer (s) + "Pretty print expression to the info buffer." + (interactive "sPretty print: ") + (rdebug-call-return (format "pp %s" s) :info)) + +(defun rdebug-pretty-print-region-to-buffer (from to) + "Pretty print expression in region to the info buffer." + (interactive "r") + (rdebug-call-return (format "pp %s" (buffer-substring from to)) :info)) + + + +(defun rdebug-quit () + "Kill the debugger process associated with the current buffer. + +When `rdebug-many-windows' is active, the original window layout +is restored." + (interactive) + (if (yes-or-no-p "Really quit? ") + (rdebug-call "quit unconditionally"))) + +(defun rdebug-restart () + "Restart the debugged Ruby script. + +An exec restart is used." + (interactive) + (if (yes-or-no-p "Restart? ") + (rdebug-call "restart"))) + +(defun rdebug-set-stepping-prefix () + "Set the granularity of stepping on the subsequent 'next' or 'step' command. +As long as repeated next or step commands are given, they inherit this setting." + (interactive) + (setq rdebug-stepping-prefix (this-command-keys))) + +(defun rdebug-step (&optional arg) + "Run a debugger \"next\" command, respecting `rdebug-stepping-prefix'. + +With a numeric ARG, continue to that line number of the current file." + (interactive "p") + (rdebug-stepping "step" arg)) + +(defun rdebug-newer-frame () + "Run a debugger \"down\" command to an newer frame. + +If we try to go down from frame 0, wrap to the end of the file" + (interactive) + (let* ((buf-name (rdebug-get-secondary-buffer-name "frame")) + (buf (or (get-buffer buf-name) (current-buffer)))) + (with-current-buffer buf + ;; Should we add a mode to disable wrapping? + (if (equal rdebug-frames-current-frame-number 0) + (rdebug-call "frame -1") + (rdebug-call "down 1"))))) + +(defun rdebug-older-frame () + "Run a debugger \"up\" command to an older frame." + (interactive) + (let* ((buf-name (rdebug-get-secondary-buffer-name "frame")) + (buf (or (get-buffer buf-name) (current-buffer)))) + (with-current-buffer buf + ;; Should we add a mode to disable wrapping? + (rdebug-call "up 1")))) + +(provide 'rdebug-gud) + +;;; Local variables: +;;; eval:(put 'rdebug-debug-enter 'lisp-indent-hook 1) +;;; End: + +;;; rdebug-gud.el ends here diff --git a/emacs/rdebug-help.el b/emacs/rdebug-help.el new file mode 100644 index 0000000..7782866 --- /dev/null +++ b/emacs/rdebug-help.el @@ -0,0 +1,104 @@ +;;; rdebug-help.el --- Ruby debugger help + +;; Copyright (C) 2008 Rocky Bernstein (rocky@gnu.org) +;; Copyright (C) 2008 Anders Lindgren + +;; $Id: rdebug-help.el 711 2008-02-20 07:09:17Z andersl $ + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; See the manual and the file `rdebug.el' for more information. + +;; This file contains code dealing with the help buffer. + +;;; Code: + +(defvar rdebug-secondary-window-help-mode-map + (let ((map (make-sparse-keymap))) + (suppress-keymap map) + (rdebug-populate-secondary-buffer-map map) + map) + "Keymap used in the help buffer in the `rdebug' Ruby debugger.") + +(defun rdebug-secondary-window-help-mode () + "Major mode for the secondary buffer help text in the `rdebug' Ruby debugger. + +\\{rdebug-secondary-window-help-mode-map}" + (interactive) + (kill-all-local-variables) + (setq major-mode 'rdebug-secondary-window-help-mode) + (setq mode-name "RDEBUG Help") + (setq buffer-read-only t) + (set (make-local-variable 'rdebug-secondary-buffer) t) + (setq mode-line-process 'rdebug-mode-line-process) + (use-local-map rdebug-secondary-window-help-mode-map) + (run-mode-hooks 'rdebug-secondary-window-help-mode-hook)) + +(defun rdebug-display-secondary-window-help-buffer () + "Display the rdebug help buffer." + (interactive) + (rdebug-display-secondary-buffer "help")) + +(defun rdebug-setup-secondary-window-help-buffer (buf comint-buffer) + (rdebug-debug-enter "rdebug-setup-secondary-window-help-buffer" + (with-current-buffer buf + (rdebug-secondary-window-help-mode) + (set (make-local-variable 'gud-comint-buffer) comint-buffer) + (insert "\ + +This is a rdebug secondary window, you can use it to watch a +number of help buffers. Use capital letters to switch between the +available buffers. Lower case letters (and other key +combinations) are used to issue buffer-specific commands. + +Press `C-h m' for more help, when the individual buffers are visible. + + B - Breakpoints buffer. + C - Command buffer (the debugger shell) + O - Output window + S - go to source frame + T - Stack trace buffer + V - Variables buffer + W - Watch buffer + + SPC - step (into) + + - set for step+ and next+ + - - set for step- and next- + _ - set to remove +/- + c - continue + f - finish (step out) + n - next (step over) + p - print + q - quit + r - run (restart) + R - run (restart) + s - step (into) + + > - go down frame (with numeric argument goes down that many frames) + < - go up one frame (with numeric argument goes down that many frames) + + ? - This help text. +")))) + +(provide 'rdebug-help) + +;;; Local variables: +;;; eval:(put 'rdebug-debug-enter 'lisp-indent-hook 1) +;;; End: + +;;; rdebug-help.el ends here diff --git a/emacs/rdebug-info.el b/emacs/rdebug-info.el new file mode 100644 index 0000000..af09933 --- /dev/null +++ b/emacs/rdebug-info.el @@ -0,0 +1,83 @@ +;;; rdebug-info.el --- This file contains code dealing with the Ruby +;;; debugger's info secondary buffer. + +;; Copyright (C) 2008 Rocky Bernstein (rocky@gnu.org) +;; Copyright (C) 2008 Anders Lindgren + +;; $Id: rdebug-breaks.el 670 2008-02-06 18:15:28Z rockyb $ + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; See the manual and the file `rdebug.el' for more information. + + +;;; Code: + +(require 'rdebug-dbg) +(require 'rdebug-gud) +(require 'rdebug-regexp) +(require 'rdebug-secondary) +(require 'rdebug-source) +(require 'rdebug-vars) + +(defun rdebug-display-info-buffer () + "Display the rdebug breakpoints buffer." + (interactive) + (rdebug-display-secondary-buffer "info")) + +(defvar rdebug-info-mode-map + (let ((map (make-sparse-keymap))) + (rdebug-populate-secondary-buffer-map map) + map) + "Keymap for the Rdebug info secondary buffer.") + +(defun rdebug-info-mode () + "Major mode for Ruby debugger info buffer. + +\\{rdebug-info-mode-map}" + (kill-all-local-variables) + (setq major-mode 'rdebug-info-mode) + (setq mode-name "RDEBUG Info") + (use-local-map rdebug-info-mode-map) + (setq buffer-read-only t) + (set (make-local-variable 'rdebug-secondary-buffer) t) + (setq mode-line-process 'rdebug-mode-line-process) + (run-mode-hooks 'rdebug-info-mode-hook)) + +(defun rdebug-setup-info-buffer (buf comint-buffer) + "Setup the Rdebug debugger info buffer." + (rdebug-debug-enter "rdebug-setup-info-buffer" + (with-current-buffer buf + (let ((inhibit-read-only t) + (old-line-number (buffer-local-value 'rdebug-current-line-number + buf))) + (rdebug-info-mode) + (goto-line old-line-number))))) + + +;; ------------------------------------------------------------------- +;; The end. +;; + +(provide 'rdebug-info) + +;;; Local variables: +;;; eval:(put 'rdebug-debug-enter 'lisp-indent-hook 1) +;;; End: + +;;; rdebug-info.el ends here diff --git a/emacs/rdebug-layouts.el b/emacs/rdebug-layouts.el new file mode 100644 index 0000000..74329f8 --- /dev/null +++ b/emacs/rdebug-layouts.el @@ -0,0 +1,180 @@ +;;; rdebug-layouts.el --- Ruby debugger window layouts. + +;; Copyright (C) 2008 Rocky Bernstein (rocky@gnu.org) +;; Copyright (C) 2008 Anders Lindgren + +;; $Id: rdebug-layouts.el 723 2008-02-24 04:51:39Z rockyb $ + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; This is file contains the window layouts that come with rdebug; the +;; code where can be consulted as a guide for creating other window +;; layouts. + +;; See the manual and the file `rdebug.el' for overall information on +;; the ruby debugger rdebug. + +;;; Code: + +(defun rdebug-get-buffer (name script-name) + "Return a rdebug buffer for displaying NAME when debugging SCRIPT-NAME. +If the buffer doesn't exists it is created." + (get-buffer-create (format "*rdebug-%s-%s*" name script-name))) + + +(defun rdebug-get-existing-buffer (name script-name) + "Return a rdebug buffer for displaying NAME when debugging SCRIPT-NAME. +Return nil if the buffer doesn't exists." + (get-buffer (format "*rdebug-%s-%s*" name script-name))) + + +(defun rdebug-window-layout-conservative (src-buf name) + "A conservative rdebug window layout with three windows. + +This window layout mimics the traditional debugger shell and +source window layout, it only add one secondary window. +Initially, the secondary window displays output of the debugged +process, but any secondary buffer can be displayed, press `?' in +the window for more details. +Argument SRC-BUF the buffer containing the Ruby source program that was initially run. NAME is the name of that buffer." + (delete-other-windows) + (split-window-horizontally) + (other-window 1) + (switch-to-buffer src-buf) + (other-window 1) + (when rdebug-use-separate-io-buffer + (split-window nil 20) + (set-window-buffer + (selected-window) (rdebug-get-buffer "output" name))) + (other-window 1)) + +(defun rdebug-window-layout-rocky (src-buf name) + "Rocky's window layout. + +3 windows. The source window is on top 4/5 of height. The +bottom is split between the command windows and a stack window. + +See `rdebug' for more information. +Argument SRC-BUF the buffer containing the Ruby source program that was initially run. NAME is the name of that buffer." + (delete-other-windows) + (split-window nil ( / ( * (window-height) 4) 5)) + (set-window-buffer + (selected-window) src-buf) + (other-window 1) + (set-window-buffer + (selected-window) (rdebug-get-buffer "frame" name)) + (split-window-horizontally) + (set-window-buffer + (selected-window) (rdebug-get-buffer "cmd" name)) + (goto-char (point-max))) + +(defun rdebug-window-layout-rocky2 (src-buf name) + "This layout is standard window without the output window, see `rdebug'. +for more information. +Argument SRC-BUF is the NAME of the buffer containing the Ruby source program that was initially run." + (delete-other-windows) + (split-window nil ( / ( * (window-height) 3) 4)) + (set-window-buffer + (selected-window) src-buf) + (split-window nil ( / (window-height) 3)) + (split-window-horizontally) + (set-window-buffer + (selected-window) (rdebug-get-buffer "frame" name)) + (other-window 1) + (set-window-buffer + (selected-window) (rdebug-get-buffer "variables" name)) + (other-window 1) + (switch-to-buffer src-buf) + (other-window 1) + (set-window-buffer + (selected-window) (rdebug-get-buffer "cmd" name)) + (goto-char (point-max))) + +(defun rdebug-window-layout-stack-of-windows (src-buf name) + "A rdebug window layout with several secondary windows to the right. +The debugger shell and the source code window is to the left. +Argument SRC-BUF the buffer containing the Ruby source program that was initially run. NAME is the name of that buffer." + (delete-other-windows) + (split-window-horizontally) + (split-window nil 20) + (set-window-buffer + (selected-window) (rdebug-get-buffer "cmd" name)) + (other-window 1) + (switch-to-buffer src-buf) + (other-window 1) + (split-window) + (split-window) + (set-window-buffer + (selected-window) (rdebug-get-buffer "variables" name)) + (other-window 1) + (set-window-buffer + (selected-window) (rdebug-get-buffer "frame" name)) + (when rdebug-use-separate-io-buffer + (other-window 1) + (split-window) + (set-window-buffer + (selected-window) (rdebug-get-buffer "output" name))) + (other-window 1) + (set-window-buffer + (selected-window) (rdebug-get-buffer "breakpoints" name)) + (other-window 1)) + +;; The default layout +(defun rdebug-window-layout-standard (src-buf name) + "The default rdebug window layout, see `rdebug' for more information. +Argument SRC-BUF the buffer containing the Ruby source program that was initially run. NAME is the name of that buffer." + (delete-other-windows) + (split-window nil ( / ( * (window-height) 3) 4)) + (split-window nil ( / (window-height) 3)) + (split-window-horizontally) + (other-window 1) + (set-window-buffer + (selected-window) (rdebug-get-buffer "variables" name)) + (other-window 1) + (switch-to-buffer src-buf) + (when rdebug-use-separate-io-buffer + (split-window-horizontally) + (other-window 1) + (set-window-buffer + (selected-window) (rdebug-get-buffer "output" name))) + (other-window 1) + (set-window-buffer + (selected-window) (rdebug-get-buffer "frame" name)) + (split-window-horizontally) + (other-window 1) + (set-window-buffer + (selected-window) (rdebug-get-buffer "breakpoints" name)) + (other-window 1) + (goto-char (point-max))) + + +(defun rdebug-window-layout-no-shell (src-buf name) + "A rdebug window layout without a shell window. +Argument SRC-BUF the buffer containing the Ruby source program that was initially run. NAME is the name of that buffer." + (delete-other-windows) + (set-window-buffer + (selected-window) (rdebug-get-buffer "watch" name)) + (rdebug-window-layout-standard src-buf name)) + +(provide 'rdebug-layouts) + +;;; Local variables: +;;; eval:(put 'rdebug-debug-enter 'lisp-indent-hook 1) +;;; End: + +;;; rdebug-layouts.el ends here diff --git a/emacs/rdebug-locring.el b/emacs/rdebug-locring.el new file mode 100644 index 0000000..b90b3fd --- /dev/null +++ b/emacs/rdebug-locring.el @@ -0,0 +1,118 @@ +;;; rdebug-locring.el --- Ruby debugger location ring + +;; Copyright (C) 2008, 2009 Rocky Bernstein (rocky@gnu.org) +;; Copyright (C) 2008 Anders Lindgren + +;; $Id: rdebug-locring.el 917 2009-03-31 09:49:37Z rockyb $ + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; This file manages a ring of (recently stopped) positions to allow +;; the programmer to move back and forth between them. + +;;; Code: + +(defvar rdebug-source-location-ring nil + "Ring of the last `rdebug-source-location-ring-size' positions we've stopped aft.") + +(defvar rdebug-source-location-ring-index -1 + "Position in `rdebug-source-location-ring' of where we are.") + +(defun rdebug-locring-add (frame location-history-ring) + "Add FRAME to LOCATION-HISTORY-RING if we are on the top frame and have a frame to add." + ;; Switching frames shouldn't save a new ring + ;; position. Also make sure no position is different. + ;; Perhaps duplicates should be controlled by an option. + (unless (and (not (ring-empty-p location-history-ring)) + (equal (ring-ref location-history-ring + (ring-length location-history-ring)) frame)) + (ring-insert-at-beginning location-history-ring frame))) + +(defun rdebug-locring-clear () + "Clear out all source locations in `Go to the source location of the first stopping point." + (interactive) + (setq rdebug-source-location-ring-index -1) + (while (not (ring-empty-p rdebug-source-location-ring)) + (ring-remove rdebug-source-location-ring))) + +(defun rdebug-locring-goto (ring-position) + "Go the source position RING-POSITION in the stopping history." + (interactive "NSource location ring position (0 is oldest): ") + (with-current-buffer gud-comint-buffer + (setq rdebug-source-location-ring-index ring-position) + (let* ((frame (ring-ref rdebug-source-location-ring ring-position)) + (file (car frame)) + (line (cdr frame))) + (when file + (rdebug-display-line file line) + (message (format "%d %s:%d" rdebug-source-location-ring-index + file line)))))) + +(defun rdebug-locring-newer () + "Cycle through source location stopping history to get the next newer (more recently visited) location." + (interactive) + (with-current-buffer gud-comint-buffer + (if (equal (+ 1 rdebug-source-location-ring-index) + (ring-length rdebug-source-location-ring)) + (progn + (message "At newest - Will set to wrap to oldest.") + (setq rdebug-source-location-ring-index -1)) + ;; else + (rdebug-locring-goto + (if (> rdebug-source-location-ring-index + (ring-length rdebug-source-location-ring)) + 0 + ;; else + (ring-plus1 rdebug-source-location-ring-index + (ring-length rdebug-source-location-ring))))))) + +(defun rdebug-locring-newest () + "Go to the source location of the first stopping point." + (interactive) + (rdebug-locring-goto (- (ring-length rdebug-source-location-ring) 1))) + +(defun rdebug-locring-older () + "Cycle through source location stopping history to get the next older (least recently visited) location." + (interactive) + (with-current-buffer gud-comint-buffer + (if (equal rdebug-source-location-ring-index 0) + (progn + (message "At oldest - Will set to wrap to newest.") + (setq rdebug-source-location-ring-index + (+ 1 (ring-length rdebug-source-location-ring)))) + ;; else + (rdebug-locring-goto + (if (or (not rdebug-source-location-ring-index) + (< rdebug-source-location-ring-index 0)) + 0 + ;; else + (ring-minus1 rdebug-source-location-ring-index + (ring-length rdebug-source-location-ring))))))) + +(defun rdebug-locring-oldest () + "Go to the oldest source position location." + (interactive) + (ring-ref rdebug-source-location-ring 0)) + +(provide 'rdebug-locring) + +;;; Local variables: +;;; eval:(put 'rdebug-debug-enter 'lisp-indent-hook 1) +;;; End: + +;;; rdebug-locring.el ends here diff --git a/emacs/rdebug-output.el b/emacs/rdebug-output.el new file mode 100644 index 0000000..8c475dc --- /dev/null +++ b/emacs/rdebug-output.el @@ -0,0 +1,106 @@ +;;; rdebug-output.el --- Ruby debugger output buffer + +;; Copyright (C) 2008 Rocky Bernstein (rocky@gnu.org) +;; Copyright (C) 2008 Anders Lindgren + +;; $Id: rdebug-output.el 711 2008-02-20 07:09:17Z andersl $ + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; See the manual and the file `rdebug.el' for more information. + +;; This file contains code dealing with the output secondary buffer. + +;;; Code: + +(require 'rdebug-dbg) +(require 'rdebug-secondary) + +(defun rdebug-display-output-buffer () + "Display the rdebug output buffer." + (interactive) + (rdebug-display-secondary-buffer "output")) + +;; FIXME add a macro to toggle read-only and run command. +(defun rdebug-output-add-divider () + (interactive "") + (save-excursion + (goto-char (point-max)) + (setq buffer-read-only nil) + ;; FIXME Cooler would be to pick up stack position in stack line + ;; and prepend a buffer-local marker number + (insert (format "%d: ============================\n" + rdebug-output-marker-number)) + (setq rdebug-output-marker-number (+ rdebug-output-marker-number 1)) + (setq buffer-read-only t))) + +(defun rdebug-output-delete-output () + (interactive) + (setq buffer-read-only nil) + (delete-region (point-min) (point-max)) + (setq buffer-read-only t)) + +(defun rdebug-output-undo () ;FIXME make more global? + (interactive "") + (setq buffer-read-only nil) + (undo) + (setq buffer-read-only t)) + +(defvar rdebug-output-mode-map + (let ((map (make-sparse-keymap))) + (define-key map "d" 'rdebug-output-delete-output) + (define-key map "t" 'rdebug-goto-traceback-line) + (define-key map "!" 'rdebug-goto-dollarbang-traceback-line) + (define-key map "=" 'rdebug-output-add-divider) + (define-key map "\C-_" 'rdebug-output-undo) ; FIXME get from keymap + (define-key map "u" 'rdebug-output-undo) + (suppress-keymap map) + (rdebug-populate-secondary-buffer-map map) + map) + "Keymap used in the output buffer in the `rdebug' Ruby debugger.") + +(defun rdebug-output-mode () + "Major mode for displaying the script output in the `rdebug' Ruby debugger. + +\\{rdebug-output-mode}" + (interactive) + (let ((old-marker-number rdebug-output-marker-number)) + (kill-all-local-variables) + (setq major-mode 'rdebug-output-mode) + (setq mode-name "RDEBUG Output") + (setq buffer-read-only t) + (set (make-local-variable 'rdebug-secondary-buffer) t) + (setq mode-line-process 'rdebug-mode-line-process) + (set (make-local-variable 'rdebug-accumulative-buffer) t) + (use-local-map rdebug-output-mode-map) + (set (make-local-variable 'rdebug-output-marker-number) old-marker-number) + (run-mode-hooks 'rdebug-output-mode-hook))) + +(defun rdebug-setup-output-buffer (buf comint-buffer) + (rdebug-debug-enter "rdebug-setup-output-buffer" + (with-current-buffer buf + (rdebug-output-mode) + (set (make-local-variable 'gud-comint-buffer) comint-buffer)))) + +(provide 'rdebug-output) + +;;; Local variables: +;;; eval:(put 'rdebug-debug-enter 'lisp-indent-hook 1) +;;; End: + +;;; rdebug-output.el ends here diff --git a/emacs/rdebug-regexp.el b/emacs/rdebug-regexp.el new file mode 100644 index 0000000..fe7b043 --- /dev/null +++ b/emacs/rdebug-regexp.el @@ -0,0 +1,118 @@ +;;; rdebug-regexp.el --- Ruby debugger regular expressions + +;; Copyright (C) 2007, 2008 Rocky Bernstein (rocky@gnu.org) +;; Copyright (C) 2007, 2008 Anders Lindgren + +;; $Id: rdebug-regexp.el 724 2008-02-24 16:14:52Z rockyb $ + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; See the manual and the file `rdebug.el' for more information. + +;; Here we have regular expressions and names for matched patterns +;; of those regular expressions. + +;;; Code: + +;; ------------------------------------------------------------------- +;; Variables defining regular expressions (regexp:s). +;; + +(defconst gud-rdebug-marker-regexp + "\\(?:source \\)?\\(\\(?:[a-zA-Z]:\\)?[^:\n]*\\):\\([0-9]*\\).*\n" + "Regular expression used to find a file location given by rdebug. + +Program-location lines look like this: + source /tmp/gcd.rb:29: gcd + /tmp/gcd.rb:29: gcd + source /tmp/gcd.rb:29 + source C:/tmp/gcd.rb:29 + source \\sources\\capfilterscanner\\capanalyzer.rb:3: ") + +(defconst rdebug-annotation-end-regexp + "\n" + "Regular expression to match the end of an annotation.") + +;; Examples of annotations: +;; ^Z^Z\n +;; ^Z^Zfoo\n +;; ^Z^Zpre-prompt\n +;; ^Z^Zsource foo.rb:10\n + +(defconst rdebug-annotation-start-regexp + "\\(\\([a-z][-a-z]*\\)?\n\\|source \\)" + "Regular expression to match the start of an annotation.") + +(defconst rdebug-breakpoint-regexp + "^\\ +\\([0-9]+\\) \\([yn]\\) +at +\\(.+\\):\\([0-9]+\\)\\( if .*\\)?$" + "Regexp to recognize breakpoint lines in rdebug breakpoint buffers.") + +(defconst rdebug-marker-regexp-file-group 2 + "Group position in `rdebug-position-regexp' that matches the file name.") + +(defconst rdebug-marker-regexp-line-group 3 + "Group position in `rdebug-position-regexp' that matches the line number.") + +(defconst rdebug-position-regexp + "\\(\\)\\([-a-zA-Z0-9_/.]*\\):\\([0-9]+\\)" + "Regular expression for a rdebug position.") + +(defconst rdebug-traceback-line-re + "^[ \t]+from \\([^:]+\\):\\([0-9]+\\)\\( in `.*'\\)?" + "Regular expression that describes a Ruby traceback line.") + +(defconst rdebug-dollarbang-traceback-line-re + "^[ \t]+[[]?\\([^:]+\\):\\([0-9]+\\):in `.*'" + "Regular expression that describes a Ruby traceback line from $! list.") + +(defconst rdebug-stack-frame-1st-regexp + "^\\(-->\\| \\) +#\\([0-9]+\\)\\(.*\\)" + "Regexp to match the first line of a stack frame in rdebug stack buffers.") + +(defconst rdebug-stack-frame-number-group 2 + "The group position in `rdebug-stack-frame-1st-regexp' that matches the frame number.") + +(defconst rdebug-stack-frame-2nd-regexp + "\s+at line +\\([^:]+\\):\\([0-9]+\\)$" + "Regexp to match the second line of a stack frame in rdebug stack buffers.") + +(defconst rdebug-stack-frame-2nd-file-group 1 + "Group position in `rdebug-stack-frame-2nd-regexp' that matches the file name.") + +(defconst rdebug-stack-frame-2nd-line-group 2 + "Group position in `rdebug-stack-frame-2nd-regexp' that matches the line number.") +(defconst rdebug-stack-frame-regexp + (concat rdebug-stack-frame-1st-regexp rdebug-stack-frame-2nd-regexp) + "Regexp to recognize a stack frame line in rdebug stack buffers.") + +(defconst rdebug-stack-frame-file-group 4 + "Group position in `rdebug-stack-frame-regexp' that matches the file name.") + +(defconst rdebug-stack-frame-line-group 5 + "Group position in `rdebug-stack-frame-regexp' that matches the line number.") + +(defconst rdebug-input-prompt-regexp "(+rdb:\\([0-9]+\\|post-mortem\\)) " + "Regular expression to recognize a rdebug prompt. Some uses may prepend an anchor to the front.") + +(provide 'rdebug-regexp) + +;;; Local variables: +;;; eval:(put 'rdebug-debug-enter 'lisp-indent-hook 1) +;;; End: + +;;; rdebug-regexp.el ends here diff --git a/emacs/rdebug-secondary.el b/emacs/rdebug-secondary.el new file mode 100644 index 0000000..f3a7961 --- /dev/null +++ b/emacs/rdebug-secondary.el @@ -0,0 +1,260 @@ +;;; rdebug-secondary.el --- Rdebug support windows. + +;; Copyright (C) 2008 Rocky Bernstein (rocky@gnu.org) +;; Copyright (C) 2008 Anders Lindgren + +;; $Id: rdebug-secondary.el 733 2008-02-29 04:34:44Z rockyb $ + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; See the manual and the file `rdebug.el' for more information. + +;; Key bindings and menu for secondary buffers. + +;;; Code: + +(require 'rdebug) + +(defun rdebug-populate-secondary-buffer-map (map) + "Bind all common keys and menu used in the rdebug secondary buffers. +This includes the keys bound to `gud-key-prefix' (typically C-x +C-a)." + (rdebug-populate-secondary-buffer-map-plain map) + (rdebug-populate-common-keys map) + (rdebug-populate-debugger-menu map) + (let ((prefix-map (make-sparse-keymap))) + (rdebug-populate-secondary-buffer-map-plain prefix-map) + (define-key map gud-key-prefix prefix-map))) + + +(defun rdebug-display-cmd-buffer () + "Display the rdebug debugger command buffer." + (interactive) + (rdebug-display-secondary-buffer "cmd")) + +(defun rdebug-pick-secondary-window-categorize (win name orig-win) + "Return how suiteable this window is to display the a secondary buffer. +The higher score the better." + (let ((buffer (window-buffer win))) + (save-current-buffer + (set-buffer buffer) + (cond (rdebug-secondary-buffer + (cond ((eq win orig-win) + ;; If the user issued the command inside a + ;; secondary window, use that window. + 5) + ((and (member name '("variables" "watch")) + (memq major-mode '(rdebug-variables-mode + rdebug-watch-mode))) + ;; Let "Watch" and "Variables" switch content. + 4) + (t + ;; Any other secondary window. + 3))) + ((eq major-mode 'ruby-mode) + ;; Avoid source windows. + 0) + ((eq major-mode 'gud-mode) + ;; Avoid the debugger shell window. + 1) + (t + ;; Just any other window. + 2))))) + + +(defun rdebug-display-secondary-buffer (name) + "Display one of the rdebug secondary buffers. +If the buffer doesn't exist, do nothing. If the buffer is already +displayed, switch to it. Otherwise if the current buffer is a +secondary buffer, bury it replacing with the requested +buffer. Failing that, if there is secondary buffer visible, that +is replaced instead. And finally failing all of the preceding, +we'll just pick a visible buffer to bury and replace." + (let* ((buf-name (rdebug-get-secondary-buffer-name name)) + (buf (get-buffer buf-name)) + (orig-win (selected-window))) + (if (null buf) + (message "Buffer %s not found" buf-name) + ;; Find a suitable window to display the buffer in. + (let ((win (get-buffer-window buf (selected-frame)))) + (if win + ;; Buffer already displayed, switch to it. + (select-window win) + ;; + (let ((candidate nil) + (candidate-score -1)) + (dolist (win (window-list (selected-frame))) + (let ((score (rdebug-pick-secondary-window-categorize + win name orig-win))) + (if (> score candidate-score) + (progn + (setq candidate win) + (setq candidate-score score))))) + (select-window candidate))))) + (switch-to-buffer buf))) + + +;; Note: The generic `gud' framework contains special code to handle +;; this for GDB (see `gud-display-line') which we, unfortuately can't +;; use. Instead, we call `rdebug-pick-source-window' from +;; `gud-rdebug-marker-filter'. When gud becomes more generic we could +;; hopefully solve this in another way. +;; +;; The machanism is that `rdebug-pick-source-window' displays the +;; source file in the window of our choice, and gud kindly re-uses +;; that window. + + +(defun rdebug-display-source-window-categorize (win) + "Return how suitable this window WIN is to display the source buffer. +The higher score the better." + (let ((buffer (window-buffer win))) + (cond ((eq buffer gud-comint-buffer) + 0) + ((buffer-local-value 'rdebug-secondary-buffer buffer) + 1) + ((eq (buffer-local-value 'major-mode buffer) 'ruby-mode) + 3) ; Pick me! Pick me! + (t + 2)))) + +(defun rdebug-display-pick-source-window () + "Return the window that should get replaced by the source window." + (rdebug-debug-enter "rdebug-display-pick-source-window" + (let ((candidate nil) + (candidate-score -1)) + (dolist (win (window-list (selected-frame))) + (let ((score + (rdebug-display-source-window-categorize win))) + (if (> score candidate-score) + (progn + (setq candidate win) + (setq candidate-score score))))) + candidate))) + +(defun rdebug-frame-source-buffer (frame) + "Return the buffer corresponding to the source file given in FRAME, or nil if none." + (and frame + gud-comint-buffer + (save-current-buffer + (set-buffer gud-comint-buffer) + (gud-find-file (car frame))))) + + +(defun rdebug-current-source-buffer () + "Return the latest source buffer, or nil." + (or (rdebug-frame-source-buffer gud-last-frame) + (rdebug-frame-source-buffer gud-last-last-frame))) + + +(defun rdebug-display-source-buffer () + "Display the current source buffer." + (interactive) + (rdebug-debug-enter "rdebug-display-source-buffer" + (let ((buffer (rdebug-current-source-buffer)) + (last-buffer (rdebug-frame-source-buffer gud-last-last-frame))) + (if buffer + (let ((window + (or + ;; Buffer is already visible, re-use the window. + (get-buffer-window buffer) + ;; Re-use the last window + (and last-buffer + (get-buffer-window last-buffer)) + ;; Find a non-rdebug window. + (rdebug-display-pick-source-window)))) + (select-window window) + (switch-to-buffer buffer)))))) + + +(defun rdebug-pick-source-window () + "Display the source file, but do not switch window." + (save-selected-window + (rdebug-display-source-buffer))) + + +(defun rdebug-display-source-buffer-resync () + "Resync output and display the source buffer." + (interactive) + (call-interactively 'gud-source-resync) + (rdebug-display-source-buffer)) + + +(defun rdebug-delete-frame-or-window () + "Delete frame if there is only one window. Otherwise delete the window." + (interactive) + (if (one-window-p) (delete-frame) + (delete-window))) + +(defun rdebug-goto-entry-try (str) + "See if thre is an entry with number STR. If not return nil." + (goto-char (point-min)) + (if (re-search-forward (concat "^[^0-9]*\\(" str "\\)[^0-9]") nil t) + (progn + (goto-char (match-end 1)) + t) + nil)) + + +;; The following is split in two to facilitate debugging. +(defun rdebug-goto-entry-n-internal (keys) + (if (and (stringp keys) + (= (length keys) 1)) + (progn + (setq rdebug-goto-entry-acc (concat rdebug-goto-entry-acc keys)) + ;; Try to find the longest suffix. + (let ((acc rdebug-goto-entry-acc) + (p (point))) + (while (not (string= acc "")) + (if (not (rdebug-goto-entry-try acc)) + (setq acc (substring acc 1)) + (setq p (point)) + ;; Break loop. + (setq acc ""))) + (goto-char p))) + (message "`rdebug-goto-entry-n' must be bound to a number key"))) + + +(defun rdebug-goto-entry-n () + "Go to an entry number. + +Breakpoints, Display expressions and Stack Frames all have +numbers associated with them which are distinct from line +numbers. In a secondary buffer, this function is usually bound to +a numeric key which will position you at that entry number. To +go to an entry above 9, just keep entering the number. For +example, if you press 1 and then 9, you should jump to entry +1 (if it exists) and then 19 (if that exists). Entering any +non-digit will start entry number from the beginning again." + (interactive) + (if (not (eq last-command 'rdebug-goto-entry-n)) + (setq rdebug-goto-entry-acc "")) + (rdebug-goto-entry-n-internal (this-command-keys))) + + +;; ------------------------------------------------------------------- +;; The end. +;; + +(provide 'rdebug-secondary) + +;;; Local variables: +;;; eval:(put 'rdebug-debug-enter 'lisp-indent-hook 1) +;;; End: + +;;; rdebug-secondary.el ends here diff --git a/emacs/rdebug-shortkey.el b/emacs/rdebug-shortkey.el new file mode 100644 index 0000000..10e1710 --- /dev/null +++ b/emacs/rdebug-shortkey.el @@ -0,0 +1,175 @@ +;;; rdebug-watch.el --- Ruby debugger (short and simple) key bindings +;;; and minor mode. + +;; Copyright (C) 2008 Rocky Bernstein (rocky@gnu.org) +;; Copyright (C) 2008 Anders Lindgren + +;; $Id: rdebug-shortkey.el 807 2008-04-08 19:55:37Z andersl $ + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; This file contains code which add short simple key bindings to buffers +;; which are part of an part of an rdebug session. It also handles +;; minor mode setting of these buffers. + +;;; Code: +;; ------------------------------------------------------------------- +;; Source short key mode. +;; +;; When this minor mode is active and the debugger is running, the +;; source window displaying the current debugger frame is marked as +;; read-only and the short keys of the secondary windows can be used, +;; for example, you can use the space-bar to single-step the program. + +;; Implementation note: +;; +;; This is presented to the user as one global minor mode. However, +;; under the surface the real work is done by another, non-global, +;; minor mode named "local short key mode". This is activated and +;; deactivated appropriately by the Rdebug filter functions. + +;; Implementation note: This is the user-level command. It only +;; controls if `rdebug-internal-short-key-mode' should be activated or +;; not. + +(require 'rdebug-source) + +(define-minor-mode rdebug-short-key-mode + "When enabled, short keys can be used in source buffers in `rdebug'." + :group 'rdebug + :global t + :init-value nil + ;; Unless the debugger is running, activating this doesn't do + ;; anything. + (if (featurep 'rdebug-core) + (with-no-warnings + (rdebug-short-key-mode-maybe-activate)))) + +(defvar rdebug-internal-short-key-mode-map + (let ((map (make-sparse-keymap))) + (define-key map "b" 'gud-break) + (define-key map "t" 'rdebug-toggle-source-breakpoint-enabled) + (define-key map [insert] 'rdebug-short-key-mode) + ;;(define-key map "p" 'gud-print) + (rdebug-populate-secondary-buffer-map-plain map) + map) + "Keymap used in `rdebug-internal-short-key-mode'.") + +(defvar rdebug-original-read-only nil + "The value `buffer-read-only' should be restored to after short key mode.") + +;; `define-minor-mode' does not set if the mode was on or off prior to being called. +(defvar rdebug-internal-short-key-mode-previous-state nil + "Used to determine when 'rdebug-internal-short-key-mode' changed state.") + +;; Implementation note: This is the mode that does all the work, it's +;; local to the buffer that is affected. +(define-minor-mode rdebug-internal-short-key-mode + "Minor mode with short keys for source buffers for the `rdebug' debugger. +The buffer is read-only when the minor mode is active. + +Note that this is for internal use only, please use the global +mode `rdebug-short-key-mode'. + +\\{rdebug-internal-short-key-mode-map}" + :group 'rdebug + :global nil + :init-value nil + :lighter " ShortKeys" + :keymap rdebug-internal-short-key-mode-map + (make-local-variable 'rdebug-original-read-only) + (make-local-variable 'rdebug-internal-short-key-mode-previous-state) + ;; Ensure action only is performed when the state actually is toggled. + (unless (eq rdebug-internal-short-key-mode-previous-state + rdebug-internal-short-key-mode) + (if rdebug-internal-short-key-mode + ;; Mode is being turned on. + (progn + (setq rdebug-original-read-only buffer-read-only) + (setq buffer-read-only t)) + ;; Mode is being turned off. + (setq buffer-read-only rdebug-original-read-only)) + ;; Save the current state, so we can determine when the state is + ;; toggled in the future. + (setq rdebug-internal-short-key-mode-previous-state + rdebug-internal-short-key-mode))) + +(defun rdebug-buffer-killed-p (buffer) + "Return t if BUFFER is killed." + (not (buffer-name buffer))) + +(defun rdebug-internal-short-key-mode-on () + "Turn on `rdebug-internal-short-key-mode' in the current debugger frame." + (rdebug-debug-enter "rdebug-internal-short-key-mode-on" + (save-current-buffer + (if (and gud-comint-buffer + (not (rdebug-buffer-killed-p gud-comint-buffer))) + (set-buffer gud-comint-buffer)) + (let ((frame (or gud-last-frame + gud-last-last-frame))) + (if (and frame + rdebug-short-key-mode) + (ignore-errors + ;; `gud-find-file' calls `error' if it doesn't find the file. + (let ((buffer (gud-find-file (car frame)))) + (save-current-buffer + (set-buffer buffer) + ;; Make gud-comint-buffer local + (if gud-comint-buffer + (make-local-variable 'gud-comint-buffer)) + (rdebug-internal-short-key-mode 1))))))))) + + +(defun rdebug-turn-on-short-key-mode () + "Turn on `rdebug-short-key-mode'. + +This function is designed to be used in a user hook, for example: + + (add-hook 'rdebug-mode-hook 'rdebug-turn-on-short-key-mode)" + (interactive) + (rdebug-short-key-mode 1)) + + +(defun rdebug-turn-off-short-key-mode () + "Turn off `rdebug-short-key-mode'." + (interactive) + (rdebug-short-key-mode -1)) + + +(defun rdebug-short-key-mode-maybe-activate () + (if rdebug-short-key-mode + (rdebug-internal-short-key-mode-on) + (rdebug-internal-short-key-mode-off))) + + +(defun rdebug-internal-short-key-mode-off () + "Turn off `rdebug-internal-short-key-mode' in all buffers." + (rdebug-debug-enter "rdebug-internal-short-key-mode-off" + (save-current-buffer + (dolist (buf (buffer-list)) + (set-buffer buf) + (when rdebug-internal-short-key-mode + (rdebug-internal-short-key-mode -1)))))) + +(provide 'rdebug-shortkey) + +;;; Local variables: +;;; eval:(put 'rdebug-debug-enter 'lisp-indent-hook 1) +;;; End: + +;;; rdebug-shortkey.el ends here diff --git a/emacs/rdebug-source.el b/emacs/rdebug-source.el new file mode 100644 index 0000000..a2bc2cd --- /dev/null +++ b/emacs/rdebug-source.el @@ -0,0 +1,568 @@ +;;; rdebug-source.el --- Ruby debugger user interface. + +;; Copyright (C) 2006, 2007, 2008 Rocky Bernstein (rocky@gnu.org) +;; Copyright (C) 2007, 2008 Anders Lindgren + +;; $Id: rdebug-source.el 821 2008-04-25 02:54:44Z rockyb $ + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; See the manual and the file `rdebug.el' for more information. + +;; This file is loaded when a Ruby source buffer is loaded. It +;; contains, among else, the Debugger menu. + +;;; Code: + +;; ------------------------------------------------------------------- +;; Consistency checks. +;; + +(if (< emacs-major-version 22) + (error + "Rdebug needs at least Emacs 22 or greater - you have version %d." + emacs-major-version)) + + +;; ------------------------------------------------------------------- +;; Dependencies. +;; + +(require 'cl) + +(require 'gud) ; For gud-key-prefix, sigh... +(require 'rdebug) +(require 'rdebug-vars) + + +;; ------------------------------------------------------------------- +;; Key bindings +;; + +(defun rdebug-populate-common-keys-standard (map) + "Bind the basic debugger key layout used by many debuggers. + +\\{rdebug-example-map-standard}" + (define-key map [f5] 'gud-cont) + (define-key map [S-f5] 'rdebug-quit) + (define-key map [f9] 'rdebug-toggle-source-breakpoint) + (define-key map [C-f9] 'rdebug-toggle-source-breakpoint-enabled) + (define-key map [f10] 'rdebug-next) + (define-key map [f11] 'rdebug-step) + (define-key map [S-f11] 'gud-finish)) + + +;; TODO: Verify and complement. +(defun rdebug-populate-common-keys-eclipse (map) + "Bind the basic debugger key layout used by Eclipse. + +\\{rdebug-example-map-eclipse}" + ;;(define-key map [] 'gud-cont) + ;;(define-key map [] 'rdebug-quit) + (define-key map [S-C-b] 'rdebug-toggle-source-breakpoint) + (define-key map [f6] 'rdebug-next) + (define-key map [f5] 'rdebug-step) + (define-key map [f7] 'gud-finish)) + + +;; TODO: Verify and complement. +(defun rdebug-populate-common-keys-netbeans (map) + "Bind the basic debugger key layout used by NetBeans. + +\\{rdebug-example-map-netbeans}" + ;;(define-key map [] 'gud-cont) + ;;(define-key map [] 'rdebug-quit) + ;; F4 - Run to cursor. + (define-key map [S-f8] 'rdebug-toggle-source-breakpoint) + (define-key map [f8] 'rdebug-next) + (define-key map [f7] 'rdebug-step) + (define-key map [M-S-f7] 'gud-finish)) + + +;; Note: This is only used in doc-strings. +(defvar rdebug-example-map-standard + (let ((map (make-sparse-keymap))) + (rdebug-populate-common-keys-standard map) + map) + "Rdebug Standard common keymap used only in doc-string.") + + +(defvar rdebug-example-map-eclipse + (let ((map (make-sparse-keymap))) + (rdebug-populate-common-keys-eclipse map) + map) + "Rdebug Eclipse compatibility common keymap used only in doc-string.") + + +(defvar rdebug-example-map-netbeans + (let ((map (make-sparse-keymap))) + (rdebug-populate-common-keys-netbeans map) + map) + "Rdebug NetBeans compatibility common keymap used only in doc-string.") + + +(defun rdebug-populate-common-keys (map) + "Define the keys that are used by all debugger windows, even by the source. + +The variable `rdebug-populate-common-keys-function' controls the layout." + (define-key map "\C-x\C-a\C-q" 'rdebug-short-key-mode) + (if rdebug-populate-common-keys-function + (funcall rdebug-populate-common-keys-function map))) + + +(defun rdebug-populate-digit-keys (map) + (define-key map "0" 'rdebug-goto-entry-n) + (define-key map "1" 'rdebug-goto-entry-n) + (define-key map "2" 'rdebug-goto-entry-n) + (define-key map "3" 'rdebug-goto-entry-n) + (define-key map "4" 'rdebug-goto-entry-n) + (define-key map "5" 'rdebug-goto-entry-n) + (define-key map "6" 'rdebug-goto-entry-n) + (define-key map "7" 'rdebug-goto-entry-n) + (define-key map "8" 'rdebug-goto-entry-n) + (define-key map "9" 'rdebug-goto-entry-n)) + + +;; ------------------------------------------------------------------- +;; Menu support. +;; + + +;; Note: We want the key binding to show in the menu. However, our +;; situation is a little bit complex: +;; +;; 1) We want the binding of the `common' man (i.e. the function key +;; the user has selected.) +;; +;; 2) We want this even when the menu is disabled and the key isn't +;; bound, typically when the debugger isn't running. +;; +;; This has been solved by setting up an explicit ":keys" properly. +(defun rdebug-menu-item (common-map name cmd &rest args) + "Return a menu item entry with the correct key bindings. + +A command can be bound to a number of different key sequences. If +the rdebug common map contains a binding it is displayed in the +menu. (The common map typically contains function key bindings.)" + (let ((key-binding (where-is-internal cmd (list common-map) t)) + (hint '())) + (if key-binding + (setq hint (list :keys (key-description key-binding)))) + (append (list 'menu-item name cmd) + hint + args))) + + +;; Note, we re-populate the menus of the different minor and major +;; modes. The reason is that Emacs caches the key bindings, which +;; means that wrong ones are shown when buffers are changed. + +;; Remember, all menu items are added in the reverse order! + +(defun rdebug-populate-debugger-menu (map) + "Populate the Rdebug 'Debugger' menu." + (let ((menu (make-sparse-keymap)) + (common-map (make-sparse-keymap))) + ;; Use a simple common map to find the best key sequence to + ;; display in menu. + (rdebug-populate-common-keys common-map) + + (define-key map [menu-bar debugger] (cons "Debugger" menu)) + + (define-key menu [break-delete] + (rdebug-menu-item common-map "Enable/disable breakpoint" + 'rdebug-toggle-source-breakpoint-enabled + :enable '(get-buffer-process gud-comint-buffer))) + + (define-key menu [break] + (rdebug-menu-item common-map "Toggle breakpoint" + 'rdebug-toggle-source-breakpoint + :enable '(get-buffer-process gud-comint-buffer))) + + (define-key menu [finish] + (rdebug-menu-item common-map "Step out" 'gud-finish + :enable '(get-buffer-process gud-comint-buffer))) + + (define-key menu [step] + (rdebug-menu-item common-map "Step into" 'rdebug-step + :enable '(get-buffer-process gud-comint-buffer))) + + (define-key menu [next] + (rdebug-menu-item common-map "Step over" 'rdebug-next + :enable '(get-buffer-process gud-comint-buffer))) + + (define-key menu [cont] + (rdebug-menu-item common-map "Continue" 'rdebug-continue + :enable '(get-buffer-process gud-comint-buffer))) + + (define-key map [menu-bar debugger line1] '(menu-item "--")) + + (define-key menu [stop] + (rdebug-menu-item + common-map "Stop the debugger" 'rdebug-quit + :enable '(get-buffer-process gud-comint-buffer))) + + (define-key menu [start] + (rdebug-menu-item common-map "Start the debugger" 'rdebug)) + + (define-key map [menu-bar debugger line2] '(menu-item "--")) + + ;; -------------------- + ;; The "Options" submenu. + + (let ((submenu (make-sparse-keymap))) + (define-key menu [options] (cons "Options" submenu))) + + (define-key map [menu-bar debugger options customize] + (rdebug-menu-item common-map + "Customize Rdebug" 'rdebug-customize)) + + (define-key map [menu-bar debugger options line1] '(menu-item "--")) + + + + ;; ---------------- + ;; The "short key" toggle. + + (define-key map [menu-bar debugger options short-key-mode] + (rdebug-menu-item common-map + "Short keys in source" 'rdebug-short-key-mode + :button + '(:toggle + . rdebug-short-key-mode))) + + (define-key map [menu-bar debugger options line2] '(menu-item "--")) + + ;; ---------------- + ;; Separate I/O buffer. + + (define-key map [menu-bar debugger options io-buffer] + (rdebug-menu-item common-map + "Separate I/O buffer" + 'rdebug-toggle-use-separate-io-buffer + :button + '(:toggle + . rdebug-use-separate-io-buffer))) + + ;; -------------------- + ;; The optional secondary windows submenu. + + + ;; Placeholder used when populating the menu of the secondary buffers. + (define-key menu [placeholder] nil) + + ;; -------------------- + ;; The "Window Layout" submenu. + (let ((submenu (make-sparse-keymap))) + (define-key menu [layout] (cons "Window Layout" submenu))) + + ;; ---------------- + ;; The "Window Layout" submenu. + + + ;; TODO: The following is a somewhat clumsy implementation. Maybe we can + ;; automatically generate the entries, or use the `dynamic' menu kind? + ;; + ;; Also, there might be other situations where the list might be + ;; handy, e.g. completion. + (let ((predefined '(rdebug-window-layout-standard + rdebug-window-layout-no-shell + rdebug-window-layout-conservative + rdebug-window-layout-stack-of-windows + rdebug-window-layout-rocky + rdebug-window-layout-rocky2))) + + (define-key map [menu-bar debugger layout other] + (rdebug-menu-item + common-map + "Other" + 'rdebug-set-window-layout + :button + `(:radio + . (not (memq rdebug-window-layout-function (quote ,predefined)))))) + + (define-key map [menu-bar debugger layout rocky] + (rdebug-menu-item + common-map + "Rocky's Own" + (lambda () + (interactive) + (rdebug-set-window-layout 'rdebug-window-layout-rocky)) + :button + '(:radio + . (eq rdebug-window-layout-function + 'rdebug-window-layout-rocky)))) + + (define-key map [menu-bar debugger layout rocky2] + (rdebug-menu-item + common-map + "Rocky II" + (lambda () + (interactive) + (rdebug-set-window-layout 'rdebug-window-layout-rocky2)) + :button + '(:radio + . (eq rdebug-window-layout-function + 'rdebug-window-layout-rocky2)))) + + (define-key map [menu-bar debugger layout stack] + (rdebug-menu-item + common-map + "Stack of Windows" + (lambda () + (interactive) + (rdebug-set-window-layout 'rdebug-window-layout-stack-of-windows)) + :button + '(:radio + . (eq rdebug-window-layout-function + 'rdebug-window-layout-stack-of-windows)))) + + (define-key map [menu-bar debugger layout conservative] + (rdebug-menu-item + common-map + "Conservative" + (lambda () + (interactive) + (rdebug-set-window-layout 'rdebug-window-layout-conservative)) + :button + '(:radio + . (eq rdebug-window-layout-function + 'rdebug-window-layout-conservative)))) + + (define-key map [menu-bar debugger layout no-shell] + (rdebug-menu-item + common-map + "No Shell" + (lambda () + (interactive) + (rdebug-set-window-layout 'rdebug-window-layout-no-shell)) + :button + '(:radio + . (eq rdebug-window-layout-function + 'rdebug-window-layout-no-shell)))) + + (define-key map [menu-bar debugger layout standard] + (rdebug-menu-item + common-map + "Standard" + (lambda () + (interactive) + (rdebug-set-window-layout 'rdebug-window-layout-standard)) + :button + '(:radio + . (eq rdebug-window-layout-function + 'rdebug-window-layout-standard))))) + + (define-key map [menu-bar debugger layout line3] '(menu-item "--")) + + (define-key map [menu-bar debugger layout initial] + (rdebug-menu-item common-map + "Restore Debugger Layout" + 'rdebug-restore-debugger-window-layout + :enable '(fboundp 'rdebug-restore-debugger-window-layout))) + + (define-key map [menu-bar debugger layout line1] '(menu-item "--")) + + ;; Note: It seems as though :enable doesn't work when :button is used. + (define-key map [menu-bar debugger layout debugger] + (rdebug-menu-item common-map "Current Debugger Layout" + 'rdebug-display-debugger-window-configuration + :button + '(:radio + . (eq rdebug-window-configuration-state 'debugger)))) + + (define-key map [menu-bar debugger layout original] + (rdebug-menu-item common-map "Original Layout" + 'rdebug-display-original-window-configuration + :button + '(:radio + . (eq rdebug-window-configuration-state 'original)))) + + ;; -------------------- + ;; The "View" submenu. + (let ((submenu (make-sparse-keymap))) + (define-key menu [view] (cons "View" submenu))) + + (define-key map [menu-bar debugger view output] + (rdebug-menu-item common-map "Output" 'rdebug-display-output-buffer + :enable '(get-buffer-process gud-comint-buffer))) + + (define-key map [menu-bar debugger view watch] + (rdebug-menu-item common-map "Watch" 'rdebug-display-watch-buffer + :enable '(get-buffer-process gud-comint-buffer))) + + (define-key map [menu-bar debugger view stack] + (rdebug-menu-item common-map "Stack-Frame trace" + 'rdebug-display-frame-buffer + :enable '(get-buffer-process gud-comint-buffer))) + + (define-key map [menu-bar debugger view shell] + (rdebug-menu-item common-map "Debugger Shell" 'rdebug-display-cmd-buffer + :enable '(get-buffer-process gud-comint-buffer))) + + (define-key map [menu-bar debugger view variables] + (rdebug-menu-item common-map "Variables" 'rdebug-display-variables-buffer + :enable '(get-buffer-process gud-comint-buffer))) + + (define-key map [menu-bar debugger view breakpoints] + (rdebug-menu-item common-map + "Breakpoints" 'rdebug-display-breakpoints-buffer + :enable '(get-buffer-process gud-comint-buffer))) + + (define-key map [menu-bar debugger view source] + (rdebug-menu-item common-map + "Source" 'rdebug-display-source-buffer + :enable '(get-buffer-process gud-comint-buffer))) + menu)) + + +;; ----------------------------------------------- +;; Key bindings and menu for secondary buffers. +;; + +(defun rdebug-populate-secondary-buffer-map-plain (map) + "Bind the plain keys used in rdebug secondary buffers. + +This does not menus or prefix keys." + ;; Keys to view other buffers. + (let ((prefix-map (make-sparse-keymap))) + (define-key map "?" 'rdebug-display-secondary-window-help-buffer) + (define-key map "B" 'rdebug-display-breakpoints-buffer) + (define-key map "C" 'rdebug-display-cmd-buffer) + (define-key map "E" 'rdebug-display-error-buffer) + (define-key map "F" 'rdebug-display-frame-buffer) + (define-key map "I" 'rdebug-display-info-buffer) + (define-key map "O" 'rdebug-display-output-buffer) + (define-key map "S" 'rdebug-display-source-buffer) + (define-key map "V" 'rdebug-display-variables-buffer) + (define-key map "W" 'rdebug-display-watch-buffer) + ;; Common debugger commands. + (define-key map " " 'rdebug-step) + (define-key map "_" 'rdebug-set-stepping-prefix) + (define-key map "+" 'rdebug-set-stepping-prefix) + (define-key map "-" 'rdebug-set-stepping-prefix) + (define-key map "<" 'rdebug-newer-frame) + (define-key map ">" 'rdebug-older-frame) + ;; (define-key map "a" 'gud-args) + ;; (define-key map "b" 'gud-break) + (define-key map "c" 'rdebug-continue) + ;; (define-key map "d" 'gud-remove) + (define-key map "f" 'gud-finish) + (define-key map "n" 'rdebug-next) + (define-key map "p" prefix-map) + (define-key map "q" 'rdebug-quit) + (define-key map "r" 'rdebug-restart) + (define-key map "R" 'rdebug-restart) + (define-key map "s" 'rdebug-step) + (define-key map [M-down] 'rdebug-locring-newer) + (define-key map [M-up] 'rdebug-locring-older) + (define-key map [M-S-down] 'rdebug-locring-newest) + (define-key map [M-S-up] 'rdebug-locring-oldest) + (define-key map [mouse-3] 'rdebug-variables-pretty-print-mouse) + (define-key prefix-map "l" 'rdebug-print-list-region) + (define-key prefix-map "p" 'rdebug-pretty-print-region) + (define-key prefix-map "s" 'rdebug-print-sorted-region) + )) + + +;; ------------------------------------------------------------------- +;; Window layout. +;; + +;; This function is intended for the Options submenu. +(defun rdebug-set-window-layout (func) + "Set and, if the debugger is running, display the window layout." + (interactive "aWindow layout function: ") + (setq rdebug-window-layout-function func) + (if gud-comint-buffer + (with-no-warnings + (rdebug-setup-windows)))) + + +;; ------------------------------------------------------------------- +;; The source buffer rdebug support mode. +;; +;; This is a minor mode that is active in Ruby source buffers. It +;; provides the menu and, when the debugger is active, the debugger +;; key bindings. + +(defvar rdebug-debugger-support-minor-mode-map-when-deactive + (let ((map (make-sparse-keymap)) + (prefix-map (make-sparse-keymap))) + (rdebug-populate-debugger-menu map) + (rdebug-populate-secondary-buffer-map-plain prefix-map) + (define-key map gud-key-prefix prefix-map) + map) + "Keymap used by rdebugs support minor mode when the debugger is active.") + +(defvar rdebug-debugger-support-minor-mode-map-when-active + (let ((map (make-sparse-keymap)) + (prefix-map (make-sparse-keymap))) + (rdebug-populate-debugger-menu map) + (rdebug-populate-secondary-buffer-map-plain prefix-map) + (define-key prefix-map [insert] 'rdebug-short-key-mode) + (define-key map gud-key-prefix prefix-map) + (rdebug-populate-common-keys map) + map) + "Keymap used by rdebugs support minor mode when the debugger not active.") + + +(define-minor-mode rdebug-debugger-support-minor-mode + "Minor mode active in source buffers that use the `rdebug' Ruby debugger." + :group rdebug + :global nil + :init-value nil + :keymap rdebug-debugger-support-minor-mode-map-when-deactive + (setq mode-line-process (and rdebug-debugger-support-minor-mode + 'rdebug-mode-line-process))) + + +;;;###autoload +(defun rdebug-turn-on-debugger-support () + "Enable extra source buffer support for the `rdebug' Ruby debugger. + +This includes a 'Debugger' menu and special key bindings when the +debugger is active." + (rdebug-debugger-support-minor-mode 1)) + + +;; ------------------------------------------------------------------- +;; Use separate I/O buffer +;; + +(defun rdebug-toggle-use-separate-io-buffer () + "Toggle `rdebug-use-separate-io-buffer'. +This is used by the menu." + (interactive) + (setq rdebug-use-separate-io-buffer (not rdebug-use-separate-io-buffer)) + (if (interactive-p) + (message "Issue M-x rdebug-restore-debugger-window-layout \ +RET to update display."))) + + +;; ------------------------------------------------------------------- +;; The end. +;; + +(provide 'rdebug-source) + +;;; Local variables: +;;; eval:(put 'rdebug-debug-enter 'lisp-indent-hook 1) +;;; End: + +;;; rdebug-source.el ends here diff --git a/emacs/rdebug-track.el b/emacs/rdebug-track.el new file mode 100644 index 0000000..1d9b4e0 --- /dev/null +++ b/emacs/rdebug-track.el @@ -0,0 +1,392 @@ +;;; rdebug-track.el --- Tracking the Ruby debugger from a shell +;; $Id: rdebug-track.el 909 2009-03-11 18:57:08Z rockyb $ + +;; Copyright (C) 2006, 2007, 2008 Rocky Bernstein (rocky@gnu.org) +;; Copyright (C) 2007, 2008 Anders Lindgren +;; Modified from python-mode in particular the part: +;; pdbtrack support contributed by Ken Manheimer, April 2001. + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; See the manual and the file `rdebug.el' for more information. + +;; `rdebug-track-mode' allows access to full debugger user interface +;; for Ruby debugger sessions started in a standard shell window. +;; `turn-on-rdebug-track-mode' turns the mode on and +;; `turn-off-rdebug-track-mode' turns it off. +;; +;;; Customization: +;; `rdebug-track' sets whether file tracking is done by the shell prompt. +;; `rdebug-track-minor-mode-string' sets the mode indicator to show that +;; tracking is in effect. +;; + +;;; Code: + +;; ------------------------------------------------------------------- +;; Customizable variables. +;; + +(defgroup rdebug-track nil + "Ruby debug and rdebug file tracking by watching the shell prompt." + :prefix "rdebug-track" + :group 'shell) + +(defcustom rdebug-track-do-tracking-p nil + "*Controls whether the rdebug-track feature is enabled or not. +When non-nil, rdebug-track is enabled in all comint-based buffers, +e.g. shell buffers and the *Ruby* buffer. When using rdebug to debug a +Ruby program, rdebug-track notices the rdebug prompt and displays the +source file and line that the program is stopped at, much the same way +as gud-mode does for debugging C programs with gdb." + :type 'boolean + :group 'rdebug) +(make-variable-buffer-local 'rdebug-track-do-tracking-p) + +(defcustom rdebug-track-minor-mode-string " rdebug" + "*String to use in the minor mode list when rdebug-track is enabled." + :type 'string + :group 'rdebug) + + +;; ------------------------------------------------------------------- +;; Variables. +;; + +(defvar gud-rdebug-history nil + "History of argument lists passed to rdebug.") + +;; rdebug-track constants +(defconst rdebug-track-stack-entry-regexp + "^(\\([-a-zA-Z0-9_/.]*\\):\\([0-9]+\\)):[ \t]?\\(.*\n\\)" + "Regular expression rdebug-track uses to find a stack trace entry.") + +(defconst rdebug-track-track-range 10000 + "Max number of characters from end of buffer to search for stack entry.") + + +;; ------------------------------------------------------------------- +;; Dependencies. +;; + +(require 'comint) +(require 'custom) +(require 'cl) +(require 'compile) +(require 'gud) +(require 'shell) +(require 'rdebug-breaks) +(require 'rdebug-cmd) +(require 'rdebug-core) + + +;; ------------------------------------------------------------------- +;; Rdebug track -- support for attaching the `rdebug' ruby debugger to +;; a process running in a shell buffer. +;; + +(defvar rdebug-track-is-tracking-p t) + +(defun rdebug-track-overlay-arrow (activation) + "Activate or de arrow at beginning-of-line in current buffer." + ;; This was derived/simplified from edebug-overlay-arrow + (cond (activation + (setq overlay-arrow-position (make-marker)) + (setq overlay-arrow-string "=>") + (set-marker overlay-arrow-position (point) (current-buffer)) + (setq rdebug-track-is-tracking-p t)) + (rdebug-track-is-tracking-p + (setq overlay-arrow-position nil) + (setq rdebug-track-is-tracking-p nil)) + )) + +(defun rdebug-track-track-stack-file (text) + "Show the file indicated by the rdebug stack entry line, in a separate window. +Activity is disabled if the buffer-local variable +`rdebug-track-do-tracking-p' is nil. + +We depend on the rdebug input prompt matching `rdebug-input-prompt-regexp' +at the beginning of the line." + ;; Instead of trying to piece things together from partial text + ;; (which can be almost useless depending on Emacs version), we + ;; monitor to the point where we have the next rdebug prompt, and then + ;; check all text from comint-last-input-end to process-mark. + ;; + ;; Also, we're very conservative about clearing the overlay arrow, + ;; to minimize residue. This means, for instance, that executing + ;; other rdebug commands wipe out the highlight. You can always do a + ;; 'where' (aka 'w') command to reveal the overlay arrow. + (rdebug-debug-enter "rdebug-track-track-stack-file" + (let* ((origbuf (current-buffer)) + (currproc (get-buffer-process origbuf))) + + (if (not (and currproc rdebug-track-do-tracking-p)) + (rdebug-track-overlay-arrow nil) + ;;else + (let* ((procmark (process-mark currproc)) + (block-start (max comint-last-input-end + (- procmark rdebug-track-track-range))) + (block-str (buffer-substring block-start procmark)) + target target_fname target_lineno target_buffer) + + (if (not (string-match rdebug-input-prompt-regexp block-str)) + (rdebug-track-overlay-arrow nil) + ;;else + (setq target (rdebug-track-get-source-buffer block-str)) + + (if (stringp target) + (rdebug-debug-message "rdebug-track: %s" target) + ;;else + (gud-rdebug-marker-filter block-str) + (setq target_lineno (car target)) + (setq target_buffer (cadr target)) + (setq target_fname (buffer-file-name target_buffer)) + (setq gud-last-frame (cons target_fname target_lineno)) + (switch-to-buffer-other-window target_buffer) + (goto-line target_lineno) + (rdebug-debug-message "rdebug-track: line %s, file %s" + target_lineno target_fname) + (rdebug-track-overlay-arrow t) + (rdebug-set-frame-top-arrow (current-buffer)) + (set (make-local-variable 'gud-comint-buffer) origbuf) + (set (make-local-variable 'gud-delete-prompt-marker) + (make-marker)) + (pop-to-buffer origbuf t) + (rdebug-locring-add gud-last-frame + rdebug-source-location-ring)) + + ;; Delete processed annotations from buffer. + (save-excursion + (let ((annotate-start) + (annotate-end (point-max))) + (goto-char block-start) + (while (re-search-forward + rdebug-annotation-start-regexp annotate-end t) + (let* ((start (match-beginning 0)) + (end (match-end 0)) + (name (or (match-string 1) "source"))) + (cond ((string= name "prompt\n") + (delete-region (- start 1) end)) + ((string= name "pre-prompt\n") + (delete-region start end)) + ((string= name "error-begin\n") + (delete-region start end)) + ((re-search-forward rdebug-annotation-end-regexp + annotate-end t) + (delete-region start (point))) + (t (forward-line))))))) + )))))) + +(defun rdebug-track-get-source-buffer (block-str) + "Return line and buffer of code indicated by block-str's traceback text. + +We look first to visit the file indicated in the trace. + +Failing that, we look for the most recently visited ruby-mode buffer +with the same name or having having the named function. + +If we're unable find the source code we return a string describing the +problem as best as we can determine." + + (if (not (string-match rdebug-position-regexp block-str)) + "line number cue not found" + ;;else + (let* ((filename (match-string rdebug-marker-regexp-file-group block-str)) + (lineno (string-to-number + (match-string rdebug-marker-regexp-line-group block-str))) + funcbuffer) + + (cond ((file-exists-p filename) + (list lineno (find-file-noselect filename))) + + ((= (elt filename 0) ?\<) + (format "(Non-file source: '%s')" filename)) + + (t (format "Not found: %s" filename)))))) + + + +;; ----------------------------------------------- +;; Rdebug track mode +;; + + +(defcustom rdebug-track-mode-text " rdebug" + "*String to display in the mode line when rdebug-track mode is active. + +\(When the string is not empty, make sure that it has a leading space.)" + :tag "rdebug mode text" ; To separate it from `global-...' + :group 'rdebug + :type 'string) + +(define-minor-mode rdebug-track-mode + "Minor mode for tracking ruby debugging inside a process shell." + :init-value nil + ;; The indicator for the mode line. + :lighter rdebug-track-mode-text + ;; The minor mode bindings. + :global nil + :group 'rdebug + (rdebug-track-toggle-stack-tracking 1) + (setq rdebug-track-is-tracking-p t) + (local-set-key "\C-cg" 'rdebug-goto-traceback-line) + (local-set-key "\C-cG" 'rdebug-goto-dollarbang-traceback-line) + + (add-hook 'comint-output-filter-functions 'rdebug-track-track-stack-file) + (run-mode-hooks 'rdebug-track-mode-hook)) + + +(defun rdebug-track-toggle-stack-tracking (arg) + (interactive "P") + (if (not (get-buffer-process (current-buffer))) + (message "No process associated with buffer '%s'" (current-buffer)) + ;;else + ;; missing or 0 is toggle, >0 turn on, <0 turn off + (if (or (not arg) + (zerop (setq arg (prefix-numeric-value arg)))) + (setq rdebug-track-do-tracking-p (not rdebug-track-do-tracking-p)) + (setq rdebug-track-do-tracking-p (> arg 0))) + (message "%sabled rdebug's rdebug-track" + (if rdebug-track-do-tracking-p "En" "Dis")))) + + +;;;###autoload +(defun turn-on-rdebug-track-mode () + "Turn on rdebug-track mode. + +This function is designed to be added to hooks, for example: + (add-hook 'comint-mode-hook 'turn-on-rdebug-track-mode)" + (interactive) + (set (make-local-variable 'gud-last-last-frame) nil) + (set (make-local-variable 'gud-last-frame) nil) + (set (make-local-variable 'gud-comint-buffer) (current-buffer)) + + (set (make-local-variable 'gud-marker-filter) 'gud-rdebug-marker-filter) + (set (make-local-variable 'gud-minor-mode) 'rdebug) + (set (make-local-variable 'comint-prompt-regexp) (concat "^" rdebug-input-prompt-regexp)) + + (set (make-local-variable 'gud-find-file) 'gud-rdebug-find-file) + + (rdebug-command-initialization) + + (rdebug-track-mode 1)) + + +(defun turn-off-rdebug-track-mode () + "Turn off rdebug-track mode." + (interactive) + (setq rdebug-track-is-tracking-p nil) + + (rdebug-track-toggle-stack-tracking 0) + (if (local-variable-p 'gud-last-frame) + (setq gud-last-frame nil)) + (while (not (ring-empty-p rdebug-source-location-ring)) + (ring-remove rdebug-source-location-ring)) + (remove-hook 'comint-output-filter-functions + 'rdebug-track-track-stack-file)) + + +;; ----------------------------------------------- +;; The `attach' function. +;; + +(defun rdebug-track-attach (&optional name rename-shell) + "Do things to make the current process buffer work like a +rdebug command buffer. In particular, the buffer is renamed, +gud-mode is set, and rdebug-track-mode is turned on, among other +things. When `rdebug-many-windows' is non-nil, the initial debugger +window layout is used." + (interactive "sProgram name: ") + (rdebug-debug-enter "rdebug-set-windows" + (rdebug-set-window-configuration-state 'debugger t) + + ;; from rdebug-common-init + (gud-mode) + (set (make-local-variable 'gud-marker-filter) 'gud-rdebug-marker-filter) + (set (make-local-variable 'gud-minor-mode) 'rdebug) + (set (make-local-variable 'gud-last-frame) nil) + (set (make-local-variable 'gud-last-last-frame) nil) + + (set (make-local-variable 'gud-find-file) 'gud-rdebug-find-file) + (set-process-filter (get-buffer-process (current-buffer)) 'gud-filter) + (gud-set-buffer) + ;; + + (rdebug-track-mode 1) + (rdebug-command-initialization) + + (when name + (if rename-shell + (rename-buffer (format "*rdebug-cmd-%s*" gud-target-name))) + (setq gud-target-name name) + (setq gud-comint-buffer (current-buffer))) + + ;; Setup exit callback so that the original frame configuration + ;; can be restored. + (let ((process (get-buffer-process gud-comint-buffer))) + (when process + (unless (equal rdebug-line-width 120) + (gud-call (format "set width %d" rdebug-line-width))) + (set-process-sentinel process + 'rdebug-process-sentinel))) + + (when gud-last-frame + (setq gud-last-last-frame gud-last-frame)) + + ;; Add the buffer-displaying commands to the Gud buffer, + ;; FIXME: combine with code in rdebug-track.el; make common + ;; command buffer mode map. + (let ((prefix-map (make-sparse-keymap)) + (map (current-local-map))) + (define-key map [M-down] 'rdebug-locring-newer) + (define-key map [M-up] 'rdebug-locring-older) + (define-key map [M-S-down] 'rdebug-locring-newest) + (define-key map [M-S-up] 'rdebug-locring-oldest) + (define-key map gud-key-prefix prefix-map) + (define-key prefix-map "t" 'rdebug-goto-traceback-line) + (define-key prefix-map "!" 'rdebug-goto-dollarbang-traceback-line) + + (rdebug-populate-secondary-buffer-map-plain prefix-map)) + + (rdebug-populate-common-keys (current-local-map)) + (rdebug-populate-debugger-menu (current-local-map)) + + (set (make-local-variable 'comint-prompt-regexp) (concat "^" rdebug-input-prompt-regexp)) + (setq paragraph-start comint-prompt-regexp) + + (setcdr (assq 'rdebug-debugger-support-minor-mode minor-mode-map-alist) + rdebug-debugger-support-minor-mode-map-when-active) + + (gud-call "set annotate 3") + (gud-call "frame 0") + (when rdebug-many-windows + (rdebug-setup-windows)) + (run-hooks 'rdebug-mode-hook))) + + +;; ------------------------------------------------------------------- +;; The end. +;; + +(provide 'rdebug-track) + +;;; Local variables: +;;; eval:(put 'rdebug-debug-enter 'lisp-indent-hook 1) +;;; End: + +;;; rdebug-track.el ends here diff --git a/emacs/rdebug-varbuf.el b/emacs/rdebug-varbuf.el new file mode 100644 index 0000000..4ece36b --- /dev/null +++ b/emacs/rdebug-varbuf.el @@ -0,0 +1,150 @@ +;;; rdebug-varbuf.el --- This file contains code dealing with the Ruby +;;; debugger's "variables" secondary buffer. + +;; Copyright (C) 2008 Rocky Bernstein (rocky@gnu.org) +;; Copyright (C) 2008 Anders Lindgren + +;; $Id: rdebug-varbuf.el 711 2008-02-20 07:09:17Z andersl $ + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; See the manual and the file `rdebug.el' for more information. + +;;; Code: + +(defvar rdebug-variables-mode-map + (let ((map (make-sparse-keymap))) + (suppress-keymap map) + (define-key map "\r" 'rdebug-variables-edit) + ;; (define-key map "e" 'rdebug-edit-variables-value) + (define-key map [mouse-2] 'rdebug-variables-edit-mouse) + (define-key map "e" 'rdebug-variables-print) + (define-key map "x" 'rdebug-variables-pretty-print) + (rdebug-populate-secondary-buffer-map map) + + ;; -------------------- + ;; The "Variables window" submenu. + + (let ((submenu (make-sparse-keymap))) + (define-key-after map [menu-bar debugger variables] + (cons "Variables window" submenu) + 'placeholder)) + + (define-key map [menu-bar debugger variables edit] + '(menu-item "Edit" rdebug-variables-edit + :enable (eq major-mode 'rdebug-variables-mode))) + + map) + "Keymap used in the variables buffer in the `rdebug' Ruby debugger.") + +(defvar rdebug-variables-font-lock-keywords + '(("@[a-zA-Z0-9_]+" 0 font-lock-variable-name-face) + ("\\<\\(nil\\|true\\|false\\)\\>" 0 font-lock-constant-face) + ("#<\\([a-zA-Z0-9_]+\\):\\([0-9a-fx]*\\)" + (1 font-lock-type-face) + (2 font-lock-constant-face))) + "Font-lock rules for the variables and watch windows in `rdebug'.") + +(defun rdebug-display-variables-buffer () + "Display the rdebug variables buffer." + (interactive) + (rdebug-display-secondary-buffer "variables")) + +(defun rdebug-variables-mode () + "Major mode for the variables buffer in the `rdebug' Ruby debugger. + +\\{rdebug-variables-mode-map}" + (interactive) + (kill-all-local-variables) + (setq major-mode 'rdebug-variables-mode) + (setq mode-name "RDEBUG Variables") + (setq buffer-read-only t) + (setq truncate-lines t) + (set (make-local-variable 'rdebug-secondary-buffer) t) + (setq mode-line-process 'rdebug-mode-line-process) + (set (make-local-variable 'font-lock-defaults) + '(rdebug-variables-font-lock-keywords)) + (use-local-map rdebug-variables-mode-map) + (run-mode-hooks 'rdebug-variables-mode-hook)) + +(defun rdebug-setup-variables-buffer (buf comint-buffer) + (rdebug-debug-enter "rdebug-setup-variables-buffer" + (with-current-buffer buf + (rdebug-variables-mode) + (set (make-local-variable 'gud-comint-buffer) comint-buffer)))) + +(defun rdebug-variables-edit-mouse (&optional event) + "Assign a value to a variable displayed in the variables buffer. +This function is intended to be bound to a mouse key" + (interactive (list last-input-event)) + (save-excursion + (if event (posn-set-point (event-end event))) + (call-interactively 'rdebug-variables-edit))) + +(defun rdebug-variables-edit (var value) + "Assign a value to a variable displayed in the variables buffer." + (interactive + (let ((var nil) + (value nil)) + (save-excursion + (beginning-of-line) + (when (looking-at "^\\(@?[a-zA-Z_0-9]+\\) *= *\\(.*\\)$") + (setq var (match-string 1)) + (setq value (match-string 2)) + (setq value (read-from-minibuffer + (format "New value (%s): " var) value))) + (list var value)))) + (gud-call (format "p %s=%s" var value))) + +(defun rdebug-variables-pretty-print (var) + "Pretty print a variable in the variables buffer." + (interactive + (let ((var nil)) + (save-excursion + (beginning-of-line) + (when (looking-at "^\\(@?[a-zA-Z_0-9]+\\) *= *\\(.*\\)$") + (setq var (match-string 1))) + (list var)))) + (rdebug-print-cmd var "pp")) + +(defun rdebug-variables-pretty-print-mouse (&optional event) + "Assign a value to a variable displayed in the variables buffer. +This function is intended to be bound to a mouse key" + (interactive (list last-input-event)) + (save-excursion + (if event (posn-set-point (event-end event))) + (call-interactively 'rdebug-variables-pretty-print))) + +(defun rdebug-variables-print (var) + "Print a variable in the variables buffer." + (interactive + (let ((var nil)) + (save-excursion + (beginning-of-line) + (when (looking-at "^\\(@?[a-zA-Z_0-9]+\\) *= *\\(.*\\)$") + (setq var (match-string 1))) + (list var)))) + (rdebug-print-cmd var "p")) + +(provide 'rdebug-varbuf) + +;;; Local variables: +;;; eval:(put 'rdebug-debug-enter 'lisp-indent-hook 1) +;;; End: + +;;; rdebug-varbuf.el ends here diff --git a/emacs/rdebug-vars.el b/emacs/rdebug-vars.el new file mode 100644 index 0000000..6137095 --- /dev/null +++ b/emacs/rdebug-vars.el @@ -0,0 +1,125 @@ +;;; rdebug-var.el --- Ruby debugger variables (other than regexps) + +;; Copyright (C) 2007 Rocky Bernstein (rocky@gnu.org) +;; Copyright (C) 2007 Anders Lindgren + +;; $Id: rdebug-vars.el 769 2008-03-17 14:29:40Z rockyb $ + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; See the manual and the file `rdebug.el' for more information. + +;; +;; Introduction: +;; +;; This is a full-blown debugger user interface to the Ruby rdebug +;; debugger shell. +;; +;; Internal debug support. When `rdebug-debug-active' is non-nil, +;; internal debug messages are placed in the buffer *Xrdebug*. +;; Functions can be annotated with `rdebug-debug-enter' to display a +;; call trace. +;; + +;;; Code: + +(defvar rdebug-current-line-number 1 + "The line number in a secondary window that you were in. We need to save + this value because secondary windows get recreated a lot") + +(defvar rdebug-debug-active nil + "Non-nil when rdebug should emit internal debug output to *Xrdebug*.") + +;; Indentation depth of `rdebug-debug-enter'. +(defvar rdebug-debug-depth 0) + +(defvar rdebug-debugger-window-configuration nil + "The saved window layout of the debugger.") + +(defvar rdebug-frames-current-frame-number nil + "The frame number of the selected frame.") + +(defvar rdebug-goto-entry-acc "") + +(defvar rdebug-output-marker-number 0 + "Number to be used when `rdebug-output-add-divider' is next + called on the secondary output buffer.") + +(defvar rdebug-original-window-configuration nil + "The window layout rdebug should restore when the debugger exits.") + +;; Terminology: a "secondary buffer" is the physical emacs buffer, +;; which can be visible or invisible. A "secondary window", is a window +;; that rdebug is reusing to display different secondary buffers. +;; +;; For example, the "secondary-window-help" buffer is named the way it +;; is since it gives help on how the secondary window is used. +(defvar rdebug-secondary-buffer nil + "Non-nil for rdebug secondary buffers (e.g. the breakpoints buffer).") + +;; Currently, this is the "output" and "info" buffers. +(defvar rdebug-accumulative-buffer nil + "Non-nil for Rdebug secondary buffers that grow.") + +;; This is used to ensure that the original frame configuration is +;; restored even when the user re-starts the debugger several times. +(defvar rdebug-window-configuration-state 'original + "Represent the window layout that currently is in use. +Can be `original' or `debugger'.") + +;; FIXME instead of just a list of commands it should a list of pairs +;; command and lambda callback routine to call with the shell output. +(defvar rdebug-call-queue '() + "List of commands queued up for results of a `rdebug-call'. + +Each entry is a list of the following form: + + (name ... options ...) + +Name is the actual command string. Options are zero or more tags +describing what should happen with the output. + +This is buffer local variable to the rdebug shell buffer.") + +;; TODO: Make this buffer-local to the shell buffer. +(defvar rdebug-inferior-status nil + "The status of the Ruby program debugged under RDebug.") + +;; Unlike the gdb implementation, we don't have to actively update the +;; mode line. +(defvar rdebug-mode-line-process + '(:eval + (and (fboundp 'rdebug-display-inferior-status) + (rdebug-display-inferior-status))) + "A string representing the current debugger state, or nil. +The mode line is displayed in all source and secondary buffers.") +;; Needed to get :eval to work. +(put 'rdebug-mode-line-process 'risky-local-variable t) + + +;; ------------------------------------------------------------------- +;; The end. +;; + +(provide 'rdebug-vars) + +;;; Local variables: +;;; eval:(put 'rdebug-debug-enter 'lisp-indent-hook 1) +;;; End: + +;;; rdebug-vars.el ends here diff --git a/emacs/rdebug-watch.el b/emacs/rdebug-watch.el new file mode 100644 index 0000000..1a50deb --- /dev/null +++ b/emacs/rdebug-watch.el @@ -0,0 +1,132 @@ +;;; rdebug-watch.el --- This file contains code dealing with the Ruby +;;; debugger's watch (AKA display) secondary buffer. + +;; Copyright (C) 2008 Rocky Bernstein (rocky@gnu.org) +;; Copyright (C) 2008 Anders Lindgren + +;; $Id: rdebug-watch.el 711 2008-02-20 07:09:17Z andersl $ + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: +;; See the manual and the file `rdebug.el' for more information. + +;;; Code: + +(require 'rdebug-dbg) + +(defvar rdebug-watch-mode-map + (let ((map (make-sparse-keymap))) + (suppress-keymap map) + (define-key map "a" 'rdebug-watch-add) + (define-key map "\C-d" 'rdebug-watch-delete) + (define-key map "d" 'rdebug-watch-delete) + (define-key map "e" 'rdebug-watch-edit) + (define-key map "\r" 'rdebug-watch-edit) + (rdebug-populate-digit-keys map) + (rdebug-populate-secondary-buffer-map map) + + ;; -------------------- + ;; The "Watch window" submenu. + (let ((submenu (make-sparse-keymap))) + (define-key-after map [menu-bar debugger watch] + (cons "Watch window" submenu) + 'placeholder)) + + (define-key map [menu-bar debugger watch delete] + '(menu-item "Delete" rdebug-watch-delete + :enable (eq major-mode 'rdebug-watch-mode))) + (define-key map [menu-bar debugger watch goto] + '(menu-item "Edit" rdebug-watch-edit + :enable (eq major-mode 'rdebug-watch-mode))) + (define-key map [menu-bar debugger watch add] + '(menu-item "Add" rdebug-watch-add)) + + map) + "Keymap used in the watch buffer in the `rdebug' Ruby debugger.") + +(defun rdebug-display-watch-buffer () + "Display the rdebug watch buffer." + (interactive) + (rdebug-display-secondary-buffer "watch")) + +(defun rdebug-watch-mode () + "Major mode for displaying watched expressions in the `rdebug' Ruby debugger. + +\\{rdebug-watch-mode}" + (interactive) + (kill-all-local-variables) + (setq major-mode 'rdebug-watch-mode) + (setq mode-name "RDEBUG Watch") + (setq buffer-read-only t) + (setq truncate-lines t) + (set (make-local-variable 'rdebug-secondary-buffer) t) + (setq mode-line-process 'rdebug-mode-line-process) + (set (make-local-variable 'font-lock-defaults) + '(rdebug-variables-font-lock-keywords)) + (use-local-map rdebug-watch-mode-map) + (run-mode-hooks 'rdebug-watch-mode-hook)) + +(defun rdebug-setup-watch-buffer (buf comint-buffer) + "Set up the rdebug debugger watch secondary buffer. + +This buffer contains display expressions. BUF is the buffer to set up and COMINT-BUFFER be the assocated gud process buffer." + (rdebug-debug-enter "rdebug-setup-watch-buffer" + (with-current-buffer buf + (rdebug-watch-mode) + (set (make-local-variable 'gud-comint-buffer) comint-buffer)))) + +(defun rdebug-watch-add (expr) + "Add EXPR to watch in the `rdebug' Ruby debugger." + (interactive "sRuby expression: ") + (if (not (string= expr "")) + (gud-call (format "display %s" expr)))) + + +(defun rdebug-watch-delete () + "Delete a display expression in the `rdebug' Ruby debugger." + (interactive) + (save-excursion + (beginning-of-line) + (if (looking-at "^\\([0-9]+\\):") + (gud-call (format "undisplay %s" (match-string 1)))))) + +(defun rdebug-watch-edit (number expr) + "Edit a display expression in the `rdebug' Ruby debugger. +Argument NUMBER is the display expression number. +Argument EXPR is the expression for display number NUMBER." + (interactive + (let ((number nil) + (expr nil)) + (save-excursion + (beginning-of-line) + (when (looking-at "^\\([0-9]+\\): *\\([^=]*[^= ]\\) *=") + (setq number (match-string 1)) + (setq expr (match-string 2)) + (setq expr (read-from-minibuffer "Ruby expression: " expr))) + (list number expr)))) + (when expr + (gud-call (format "undisplay %s" number)) + (gud-call (format "display %s" expr)))) + + +(provide 'rdebug-watch) + +;;; Local variables: +;;; eval:(put 'rdebug-debug-enter 'lisp-indent-hook 1) +;;; End: + +;;; rdebug-watch.el ends here diff --git a/emacs/rdebug.el b/emacs/rdebug.el new file mode 100644 index 0000000..2a326a1 --- /dev/null +++ b/emacs/rdebug.el @@ -0,0 +1,326 @@ +;;; rdebug.el --- Ruby debugger user interface, startup file. + +;; Copyright (C) 2006, 2007, 2008 Rocky Bernstein (rocky@gnu.org) +;; Copyright (C) 2007, 2008 Anders Lindgren + +;; $Id: rdebug.el 409 2007-12-14 02:36:37Z rockyb $ + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; +;; Introduction: +;; +;; This is a full-blown debugger user interface to the Ruby rdebug +;; debugger shell. +;; +;; The main features are: +;; +;; * Window layout with dedicated windows for: +;; + Local and member variables +;; + Stack trace +;; + Display expressions +;; + Breakpoints +;; + Output +;; + Debugger Shell +;; +;; * Source-level debugging: +;; + The current source file is shown and current line is marked. +;; + Function keys bindings for effective stepping in the source code. +;; + A "Debugger" menu for easy access to all features. +;; +;; * A number of predefined window layouts and key bindings are +;; supplied, including binding that emulate Eclipse and NetBeans. +;; The user can easily provide their own window layout and +;; settings. +;; +;; The default window layout looks like the following: +;; +;; +----------------------------------------------------------------------+ +;; | Toolbar | +;; +-----------------------------------+----------------------------------+ +;; | Debugger shell | Variables buffer | +;; +-----------------------------------+----------------------------------+ +;; | | | +;; | Source buffer | Output buffer | +;; | | | +;; +-----------------------------------+----------------------------------+ +;; | Stack buffer | Breakpoints buffer | +;; +-----------------------------------+----------------------------------+ +;; + +;; +;; Installation: +;; +;; To use this package, place the following line in an appropriate +;; init file (for example ~/.emacs): +;; +;; (require 'rdebug) +;; + +;; +;; History and Future: +;; +;; The design of this debugger user interface was inspired by +;; `gdb-ui', a similar user interface to GDB. +;; +;; Hopefully, rdebug, gdb-ui, and other emacs user interfaces could +;; join forces to create a common user-level look and feel, and a +;; battery of underlying support functions. +;; + +;; +;; This file contains only user-customizable variables and code to +;; load the other files when needed. +;; + +;;; Code: + +;; ------------------------------------------------------------------- +;; Consistency checks. +;; + +(if (< emacs-major-version 22) + (error + "This version of rdebug.el needs at least Emacs 22 or greater - you have version %d." + emacs-major-version)) + + +;; ------------------------------------------------------------------- +;; Support functions. +;; + +(defun rdebug-directory () + "The directory of this file, or nil." + (let ((file-name (or load-file-name + (symbol-file 'rdebug-directory)))) + (if file-name + (file-name-directory file-name) + nil))) + + +(defun rdebug-compare-filenames (f1 f2) + "Canonicalize and compare file names." + ;; Canonicalize by: + ;; 1) file-truename ensures that the file has got the correct case, + ;; and that "..":s in the path are eliminated. + ;; 2) file-name-as-directory ensures "/foo" and "/foo/" becomes equal. + + ;; Note: for some reason, when the `comp-elisp' external program is + ;; used, `nil' is part of `load-path'. + (if f1 + (setq f1 (file-name-as-directory (file-truename f1)))) + (if f2 + (setq f2 (file-name-as-directory (file-truename f2)))) + (equal f1 f2)) + + +;; Add the directory of `rdebug.el' to the load-path. This ensures +;; that all the user have do to use this package is to load this file. +(let ((dir (rdebug-directory))) + (if dir + (add-to-list 'load-path dir nil 'rdebug-compare-filenames))) + + +;; ------------------------------------------------------------------- +;; Autoloads. +;; + +(autoload 'rdebug "rdebug-core" + "Run the rdebug Ruby debugger and start the Emacs user interface. + +By default, the \"standard\" user window layout looks like the following: + ++----------------------------------------------------------------------+ +| Toolbar | ++-----------------------------------+----------------------------------+ +| Debugger shell | Variables buffer | ++-----------------------------------+----------------------------------+ +| | | +| Source buffer | Output buffer | +| | | ++-----------------------------------+----------------------------------+ +| Stack buffer | Breakpoints buffer | ++-----------------------------------+----------------------------------+ + +The variable `rdebug-many-windows-layout-function' can be +customized so that another layout is used. In addition to a +number of predefined layouts it's possible to define a function +to perform a custom layout. + +If `rdebug-many-windows' is nil, only a traditional debugger +shell and source window is opened. + +The directory containing the debugged script becomes the initial +working directory and source-file directory for your debugger. + +The custom variable `gud-rdebug-command-name' sets the command +and options used to invoke rdebug." t) + + +(autoload 'rdebug-turn-on-debugger-support "rdebug-source" + "Enable extra source buffer support for the `rdebug' Ruby debugger. + +This includes a 'Debugger' menu and special key bindings when the +debugger is active." + t) + + +(autoload 'rdebug-track-attach "rdebug-track" + "Do things to make the current process buffer work like a +rdebug command buffer." t) + +(autoload 'turn-on-rdebug-track-mode "rdebug-track" + "Turn on rdebugtrack mode. + +This function is designed to be added to hooks, for example: + (add-hook 'comint-mode-hook 'turn-on-rdebugtrack-mode)" + t) + + +(add-hook 'ruby-mode-hook 'rdebug-turn-on-debugger-support) + +;; This is needed, or at least the docstring part of it is needed to +;; get the customization menu to work in Emacs 23. +(defgroup rdebug nil + "The Ruby debugger" + :group 'processes + :group 'tools) + +;; ------------------------------------------------------------------- +;; User definable variables +;; + +(defcustom gud-rdebug-command-name + "rdebug --emacs 3" + "File name for executing the Ruby debugger and command options. +This should be an executable on your path, or an absolute file name." + :type 'string + :group 'gud) + +(defcustom rdebug-line-width 120 + "Length of line before truncation occurs. +This value limits output in secondary buffers." + :type 'integer + :group 'rdebug) + +(defcustom rdebug-many-windows t + "*If non-nil, use the full debugger user interface, see `rdebug'. + +However only set to the multi-window display if the rdebug +command invocation has an annotate options (\"--annotate 3\")." + :type 'boolean + :group 'rdebug) + +(defcustom rdebug-use-separate-io-buffer t + "*If non-nil, output goes to a dedicated windows. + +This only applies when `rdebug-many-windows' is non-nil." + :type 'boolean + :group 'rdebug) + +(defcustom rdebug-populate-common-keys-function + 'rdebug-populate-common-keys-standard + "The function to call to populate key bindings common to all rdebug windows. +This includes the secondary windows, the debugger shell, and all +Ruby source buffers when the debugger is active. + +This variable can be bound to the following: + +* nil -- Don't bind any keys. + +* `rdebug-populate-common-keys-standard' -- Bind according to a widely used + debugger convention: + +\\{rdebug-example-map-standard} + +* `rdebug-populate-common-keys-eclipse' -- Bind according to Eclipse. + +\\{rdebug-example-map-eclipse} + +* `rdebug-populate-common-keys-netbeans' -- Bind according to NetBeans. + +\\{rdebug-example-map-netbeans} + +* Any other value is expected to be a callable function that takes one + argument, the keymap, and populates it with suitable keys." + :type 'function + :group 'rdebug) + +(defcustom rdebug-restore-original-window-configuration :many + "*Control if the original window layout is restored when the debugger exits. +The value can be t, nil, or :many. + +A value of t means that the original layout is always restored, +nil means that it's never restored. + +:many means that the original layout is restored only when +`rdebug-many-windows' is used." + :type '(choice (const :tag "Always restore" t) + (const :tag "Never restore" nil) + (const :tag "Restore in many windows mode" :many)) + :group 'rdebug) + +(defcustom rdebug-use-separate-io-buffer t + "Non-nil means display output from the debugged program in a separate buffer." + :type 'boolean + :group 'gud) + + +(defcustom rdebug-window-layout-function + 'rdebug-window-layout-standard + "*A function that performs the window layout of `rdebug'. + +This is only used in `rdebug-many-windows' mode. This should be +bound to a function that performs the actual window layout. The +function should takes two arguments, the first is the source +buffer and the second the name of the script to debug. + +Rdebug provides the following predefined layout functions: + +* `rdebug-window-layout-standard' -- See `rdebug' + +* `rdebug-window-layout-no-shell' -- Standard + Display, no Shell + +* `rdebug-window-layout-conservative' -- Source + Shell + Output + +* `rdebug-window-layout-stack-of-windows' -- Extra windows to the right + +* `rdebug-window-layout-rocky' -- Rocky's own layout" + :type + '(choice + (function :tag "Standard" rdebug-window-layout-standard) + (function :tag "Conservative" rdebug-window-layout-conservative) + (function :tag "Stack of windows" rdebug-window-layout-stack-of-windows) + (function :tag "Rocky's own" rdebug-window-layout-rocky) + (function :tag "Rocky's II" rdebug-window-layout-rocky2) + (function :tag "Other" function)) + :group 'rdebug) + +(defcustom rdebug-source-location-ring-size 150 + "Size of rdebug position history ring." + :type 'integer + :group 'rdebug) + + +;; ------------------------------------------------------------------- +;; The end. +;; + +(provide 'rdebug) + +;;; rdebug.el ends here diff --git a/emacs/test/.svn/README.txt b/emacs/test/.svn/README.txt new file mode 100644 index 0000000..271a8ce --- /dev/null +++ b/emacs/test/.svn/README.txt @@ -0,0 +1,2 @@ +This is a Subversion working copy administrative directory. +Visit http://subversion.tigris.org/ for more information. diff --git a/emacs/test/.svn/empty-file b/emacs/test/.svn/empty-file new file mode 100644 index 0000000..e69de29 diff --git a/emacs/test/.svn/entries b/emacs/test/.svn/entries new file mode 100644 index 0000000..21a4c0c --- /dev/null +++ b/emacs/test/.svn/entries @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + diff --git a/emacs/test/.svn/format b/emacs/test/.svn/format new file mode 100644 index 0000000..b8626c4 --- /dev/null +++ b/emacs/test/.svn/format @@ -0,0 +1 @@ +4 diff --git a/emacs/test/.svn/prop-base/elk-test.el.svn-base b/emacs/test/.svn/prop-base/elk-test.el.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/emacs/test/.svn/prop-base/elk-test.el.svn-base @@ -0,0 +1 @@ +END diff --git a/emacs/test/.svn/prop-base/test-annotate.el.svn-base b/emacs/test/.svn/prop-base/test-annotate.el.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/emacs/test/.svn/prop-base/test-annotate.el.svn-base @@ -0,0 +1 @@ +END diff --git a/emacs/test/.svn/prop-base/test-cmd.el.svn-base b/emacs/test/.svn/prop-base/test-cmd.el.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/emacs/test/.svn/prop-base/test-cmd.el.svn-base @@ -0,0 +1 @@ +END diff --git a/emacs/test/.svn/prop-base/test-core.el.svn-base b/emacs/test/.svn/prop-base/test-core.el.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/emacs/test/.svn/prop-base/test-core.el.svn-base @@ -0,0 +1 @@ +END diff --git a/emacs/test/.svn/prop-base/test-fns.el.svn-base b/emacs/test/.svn/prop-base/test-fns.el.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/emacs/test/.svn/prop-base/test-fns.el.svn-base @@ -0,0 +1 @@ +END diff --git a/emacs/test/.svn/prop-base/test-frames.el.svn-base b/emacs/test/.svn/prop-base/test-frames.el.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/emacs/test/.svn/prop-base/test-frames.el.svn-base @@ -0,0 +1 @@ +END diff --git a/emacs/test/.svn/prop-base/test-gud.el.svn-base b/emacs/test/.svn/prop-base/test-gud.el.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/emacs/test/.svn/prop-base/test-gud.el.svn-base @@ -0,0 +1 @@ +END diff --git a/emacs/test/.svn/prop-base/test-indent.el.svn-base b/emacs/test/.svn/prop-base/test-indent.el.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/emacs/test/.svn/prop-base/test-indent.el.svn-base @@ -0,0 +1 @@ +END diff --git a/emacs/test/.svn/prop-base/test-regexp.el.svn-base b/emacs/test/.svn/prop-base/test-regexp.el.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/emacs/test/.svn/prop-base/test-regexp.el.svn-base @@ -0,0 +1 @@ +END diff --git a/emacs/test/.svn/prop-base/test-shortkey.el.svn-base b/emacs/test/.svn/prop-base/test-shortkey.el.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/emacs/test/.svn/prop-base/test-shortkey.el.svn-base @@ -0,0 +1 @@ +END diff --git a/emacs/test/.svn/props/elk-test.el.svn-work b/emacs/test/.svn/props/elk-test.el.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/emacs/test/.svn/props/elk-test.el.svn-work @@ -0,0 +1 @@ +END diff --git a/emacs/test/.svn/props/test-annotate.el.svn-work b/emacs/test/.svn/props/test-annotate.el.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/emacs/test/.svn/props/test-annotate.el.svn-work @@ -0,0 +1 @@ +END diff --git a/emacs/test/.svn/props/test-cmd.el.svn-work b/emacs/test/.svn/props/test-cmd.el.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/emacs/test/.svn/props/test-cmd.el.svn-work @@ -0,0 +1 @@ +END diff --git a/emacs/test/.svn/props/test-core.el.svn-work b/emacs/test/.svn/props/test-core.el.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/emacs/test/.svn/props/test-core.el.svn-work @@ -0,0 +1 @@ +END diff --git a/emacs/test/.svn/props/test-fns.el.svn-work b/emacs/test/.svn/props/test-fns.el.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/emacs/test/.svn/props/test-fns.el.svn-work @@ -0,0 +1 @@ +END diff --git a/emacs/test/.svn/props/test-frames.el.svn-work b/emacs/test/.svn/props/test-frames.el.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/emacs/test/.svn/props/test-frames.el.svn-work @@ -0,0 +1 @@ +END diff --git a/emacs/test/.svn/props/test-gud.el.svn-work b/emacs/test/.svn/props/test-gud.el.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/emacs/test/.svn/props/test-gud.el.svn-work @@ -0,0 +1 @@ +END diff --git a/emacs/test/.svn/props/test-indent.el.svn-work b/emacs/test/.svn/props/test-indent.el.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/emacs/test/.svn/props/test-indent.el.svn-work @@ -0,0 +1 @@ +END diff --git a/emacs/test/.svn/props/test-regexp.el.svn-work b/emacs/test/.svn/props/test-regexp.el.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/emacs/test/.svn/props/test-regexp.el.svn-work @@ -0,0 +1 @@ +END diff --git a/emacs/test/.svn/props/test-shortkey.el.svn-work b/emacs/test/.svn/props/test-shortkey.el.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/emacs/test/.svn/props/test-shortkey.el.svn-work @@ -0,0 +1 @@ +END diff --git a/emacs/test/.svn/text-base/elk-test.el.svn-base b/emacs/test/.svn/text-base/elk-test.el.svn-base new file mode 100644 index 0000000..ddfc03c --- /dev/null +++ b/emacs/test/.svn/text-base/elk-test.el.svn-base @@ -0,0 +1,242 @@ +;;; elk-test.el --- Emacs Lisp testing suite + +;; Copyright (C) 2006 Nikolaj Schumacher + +;;; License + +;; This program is free software; you can redistribute it and/or +;; modify it under the terms of the GNU General Public License +;; as published by the Free Software Foundation; either version 2 +;; of the License, or (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program; if not, write to the Free Software +;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +;;; Usage + +;; Use `deftest' to define a test and `run-elk-test' to run it. +;; Create test bundles with `defsuite' or `build-suite'. +;; Verify your code with `assert-equal', `assert-eq', `assert-eql', +;; `assert-nonnil', `assert-t', `assert-nil' and `assert-error' +;; to verify your code. + +;;; Examples + +;; (deftest "test1" +;; (assert-equal t t) +;; (assert-eq t 'foo)) + +;; (defsuite "suite1" +;; (deftest "test1" (assert-equal t t))) + +;; (deftest "test2" +;; (assert-equal t t)) +;; (build-suite "combined-suite" "test1" "test2") + +;; (run-elk-test "combined-suite") +;; (run-elk-test) + +(require 'cl) + +(defvar elk-test-run-on-define nil + "If non-nil, run elk-test tests/suites immediately when defining them.") + +(defvar elk-test-map (make-hash-table :test 'equal) + "A map of elk-test test/suite names to their implementation.") + +(defvar elk-test-list nil + "A list of all defined elk-test tests/suites.") + +(defun elk-test-clear () + "Remove all tests from memory." + (setq elk-test-map (make-hash-table :test 'equal) + elk-test-list nil)) + +(defun run-elk-test (name &optional string-result) + "Run the test case defined as NAME. +The result is a list of errors strings, unless STRING-RESULT is set, in which +case a message describing the errors or success is displayed and returned." + (interactive + (list (completing-read "Test name: " elk-test-list nil t))) + (let ((name name)) + (let ((elk-test-errors nil) + (test-or-suite (gethash name elk-test-map))) + (if (not test-or-suite) + (error "Undefined test <%s>" name) + (if (equal (car test-or-suite) 'suite) + ;; is test suite + (let ((map (cadr test-or-suite))) + (dolist (test (caddr test-or-suite)) + (setq elk-test-errors + (append elk-test-errors + (run-elk-test-internal (gethash test map)))))) + ;; is simple test + (setq elk-test-errors (run-elk-test-internal test-or-suite))) + (if (or string-result (interactive-p)) + (message (if elk-test-errors + (mapconcat 'identity elk-test-errors "\n") + "Test run was successful.")) + elk-test-errors))))) + +(defun run-elk-tests-buffer (&optional buffer) + "Execute BUFFER as lisp code and run all tests therein." + (interactive) + (let* ((elk-test-list) + (elk-test-map (make-hash-table :test 'equal)) + (elk-test-run-on-define nil) + (inhibit-read-only t) + (buffer-name (buffer-name buffer)) + (success t) + (parse-res (condition-case err (eval-buffer buffer) (error err)))) + (if parse-res + (message "Parsing buffer <%s> failed:\n%s" + buffer-name parse-res) + (let ((out-buffer (get-buffer-create + (concat "*elk-test run " buffer-name "*"))) + failure) + (with-current-buffer out-buffer + (erase-buffer) + (dolist (test elk-test-list) + (message "running <%s>" test) + (let ((results (run-elk-test test))) + (when results + (setq failure t) + (insert "test <" test "> failed:\n") + (dolist (result results) + (insert "* " result "\n")))))) + (if failure + (display-buffer out-buffer) + (kill-buffer out-buffer) + (message "Test run was successful.")))))) + +(defun run-elk-test-internal (test) + (let ((elk-test-errors nil)) + (dolist (sexpr test) + (let ((problem (condition-case err (progn (eval sexpr) nil) (error err)))) + (when problem + (push (message "%s" problem) elk-test-errors)))) + elk-test-errors)) + +(defmacro elk-test-error (format-string &rest args) + "Create an error string as the result of a failed elk-test assertion. +The first argument is a format control string, and the rest are data to be +formatted under control of the string. See `format' for details. + +The result will be displayed, returned and if called inside of `run-elk-test' +added to the internal error list." + `(let ((string (message ,format-string ,@args))) + (when (boundp 'elk-test-errors) + (push string elk-test-errors)) + string)) + +(defmacro assert-equal (expected actual) + "Assert that ACTUAL equals EXPECTED, or signal a warning." + `(unless (equal ,expected ,actual) + (elk-test-error "assert-equal for <%s> failed: expected <%s>, was <%s>" + ',actual ,expected ,actual))) + +(defmacro assert-eq (expected actual) + "Assert that ACTUAL equals EXPECTED, or signal a warning." + `(unless (eq ,expected ,actual) + (elk-test-error "assert-eq for <%s> failed: expected <%s>, was <%s>" + ',actual ,expected ,actual))) + +(defmacro assert-eql (expected actual) + "Assert that ACTUAL equals EXPECTED, or signal a warning." + `(unless (eql ,expected ,actual) + (elk-test-error "assert-eql for <%s> failed: expected <%s>, was <%s>" + ',actual ,expected ,actual))) + +(defmacro assert-nonnil (value) + "Assert that VALUE is not nil, or signal a warning." + `(unless ,value + (elk-test-error "assert-nonnil for <%s> failed: was <%s>" + ',value ,value))) + +(defmacro assert-t (value) + "Assert that VALUE is t, or signal a warning." + `(unless (eq ,value t) + (elk-test-error "assert-t for <%s> failed: was <%s>" + ',value ,value))) + +(defmacro assert-nil (value) + "Assert that VALUE is nil, or signal a warning." + `(when ,value + (elk-test-error "assert-nil for <%s> failed: was <%s>" + ',value ,value))) + +(defmacro assert-error (error-message &rest body) + "Assert that BODY raises an `error', or signal a warning. +ERROR-MESSAGE is the expected error string, use nil to accept any error. Use +nil with caution, as errors like 'wrong-number-of-arguments' (likely caused by +typos) will also be caught!" + `(let ((elk-test-error + (condition-case elk-test-error + (progn ,@body) + (error (cons 'elk-test-error (cadr elk-test-error)))))) + (if (not (eq (car elk-test-error) 'elk-test-error)) + ;; no error + (elk-test-error "assert-error for <%s> failed: did not raise an error" + (append '(progn) ',body)) + (when (and ,error-message + (not (equal ,error-message (cdr elk-test-error)))) + (elk-test-error (concat "assert-error for <%s> failed: expected <%s>, " + "raised <%s>") + (append '(progn) ',body) + ,error-message (cdr elk-test-error)))))) + +(defmacro deftest (name &rest body) + "Define a test case. +Use `assert-equal', `assert-eq', `assert-eql', `assert-nonnil', `assert-t', +`assert-nil' and `assert-error' to verify the code." + `(progn (unless (gethash ,name elk-test-map) + (push ,name elk-test-list)) + (puthash ,name ',body elk-test-map) + ,(if elk-test-run-on-define + `(run-elk-test ',name ,t) + name))) + +(defmacro defsuite (name &rest body) + "Define a test suite using a collection of `deftest' forms. +The resulting suite can be called with `run-elk-test' and parameter NAME." + `(let ((suite + (let ((elk-test-map (make-hash-table :test 'equal)) + (elk-test-list nil)) + ,@body + (list 'suite elk-test-map (reverse elk-test-list))))) + (unless (gethash ,name elk-test-map) + (push ,name elk-test-list)) + (puthash ,name suite elk-test-map) + ,(if elk-test-run-on-define + `(run-elk-test ,name t) + name))) + +(defun build-suite (name &rest tests) + "Define a test suite using a collection of test names. +The resulting suite can be run by calling `run-elk-test' with parameter NAME." + (unless (gethash name elk-test-map) + (push name elk-test-list)) + (puthash name + (let ((map (make-hash-table :test 'equal)) + (list nil)) + (dolist (test-name tests) + (push test-name list) + (when (gethash test-name map) + (error "Test used twice")) + (let ((test (gethash test-name elk-test-map))) + (unless test + (error "Undefined test <%s>" test-name)) + (puthash test-name test map))) + (list 'suite map (reverse list))) + elk-test-map) + (if elk-test-run-on-define + (run-elk-test "sample suite" t) + name)) + +(provide 'elk-test) diff --git a/emacs/test/.svn/text-base/test-annotate.el.svn-base b/emacs/test/.svn/text-base/test-annotate.el.svn-base new file mode 100644 index 0000000..2042985 --- /dev/null +++ b/emacs/test/.svn/text-base/test-annotate.el.svn-base @@ -0,0 +1,103 @@ +;; -*- emacs-lisp -*- +;; This program has to be run from the directory it is currently in and +;; the rdebug code has to be in the parent directory +(load-file "./elk-test.el") + +;; FIXME? Should we use "require 'rdebug" here. +;; Would have to prepend . to load-path. +(load-file "../rdebug.el") +(load-file "../rdebug-annotate.el") + +(defvar last-annotation nil + "Value of the last annotation processed") + +;; Redefine functions to make them harmless for testing +(defun rdebug-process-annotation (name contents) + (setq last-annotation name)) + +(make-variable-buffer-local 'gud-rdebug-marker-acc) + +;; ------------------------------------------------------------------- +;; Test harness for testing the filter. +;; + +(require 'advice) + +(defvar rdebug-test-cmd-list '()) + +;; Override, partially because tooltip-show doesn't work in batch +;; mode, and partially because we collect the output here. +(defun tooltip-show (text) + (setq rdebug-test-cmd-list (cons text rdebug-test-cmd-list))) + +(defun assert-filter (output str &optional cmd-list) + (setq rdebug-test-cmd-list '()) + (setq gud-marker-acc "") + (let ((orig-queue rdebug-call-queue)) + (let ((real-output (gud-rdebug-marker-filter str))) + (assert-equal output real-output) + (assert-equal cmd-list (reverse rdebug-test-cmd-list))) + + ;; + ;; Feed the filter one character at a time -- the end result should + ;; be the same. + ;; + (setq rdebug-test-cmd-list '()) + (setq gud-marker-acc "") + (let ((real-output "") + (len (length str)) + (i 0) + (rdebug-call-queue orig-queue)) + (while (< i len) + (setq real-output + (concat real-output + (gud-rdebug-marker-filter + (substring str i (if (equal (+ 1 i) len) + nil + (+ 1 i)))))) + (setq i (+ 1 i))) + (assert-equal output real-output) + (assert-equal cmd-list (reverse rdebug-test-cmd-list))))) + + +(deftest "rdebug-filter" +;;; (assert-filter "X" "X") +;;; (assert-filter "XYZ" "XYZ") +;;; (assert-filter "" "\n") +;;; (assert-filter "Testing 1 2 3" "Testing 1 2 3") +;;; (assert-filter "Testing 1 2 3" "Testing 1 2 3") +;;; (assert-filter "ABC" "\ +;;; breakpoints +;;; No breakpoints +;;;  +;;; ABC") + + ;; Some systems (read: Mac) echoes the command. + (setq rdebug-call-queue '(("pp 100" :tooltip))) + (assert-filter "pp 100\n100\n(rdb:1) " "\ +prompt +pp 100\n100 +pre-prompt +\(rdb:1) \nprompt\n" + '("100\n")) + + ;; Some systems don't echo the command. + (setq rdebug-call-queue '(("pp 100" :tooltip))) + (assert-filter "100\n(rdb:1) " "\ +prompt +100 +pre-prompt +\(rdb:1) \nprompt\n" + '("100\n")) + ) + + +;; ------------------------------------------------------------------- +;; Build and run the test suite. +;; + +(build-suite "rdebug-suite" + "rdebug-filter") + +(run-elk-test "rdebug-suite" + "test regular expressions used in tracking lines") diff --git a/emacs/test/.svn/text-base/test-cmd.el.svn-base b/emacs/test/.svn/text-base/test-cmd.el.svn-base new file mode 100644 index 0000000..972ec1b --- /dev/null +++ b/emacs/test/.svn/text-base/test-cmd.el.svn-base @@ -0,0 +1,116 @@ +;; -*- emacs-lisp -*- +;; This program has to be run from the directory it is currently in and +;; the rdebug code has to be in the parent directory +(load-file "./elk-test.el") + +(setq load-path (cons ".." load-path)) +(require 'rdebug-core) +(require 'rdebug-gud) +(setq load-path (cdr load-path)) + +(defvar last-gud-call nil + "Value of the last gud-call") + +;; Redefine functions to make them harmless for testing +(defun gud-call (command) + (setq last-gud-call command)) + +(defun rdebug-call (command) + (setq last-gud-call command)) + +(deftest "rdebug-goto-frame-test" + (let ((buf (generate-new-buffer "testing"))) + (save-excursion + (switch-to-buffer buf) + (insert "#0 ERB.result(b#Binding) at line /usr/lib/ruby/1.8/erb.rb:736\n") + (insert "#1 Listings.build at line erbtest.rb:24\n") + (insert "#2 at line erbtest.rb:33\n") + (insert "#10 Listings.build at line erbtest.rb:23") + (goto-char (point-min)) + (setq last-gud-call nil) + (setq rdebug-goto-entry-acc "") + + ;; -------------------- + ;; The tests + + (rdebug-goto-frame-n-internal "5") + (assert-equal nil last-gud-call) + (rdebug-goto-frame-n-internal "1") + (assert-equal "frame 1" last-gud-call) + (rdebug-goto-frame-n-internal "0") + (assert-equal "frame 10" last-gud-call)) + (kill-buffer buf))) + + +;; ------------------------------------------------------------------- +;; Check breakpoint toggle commands +;; + +(deftest "rdebug-toggle-breakpoints" + (let ((buf (generate-new-buffer "*rdebug-breakpoint-test.rb*")) + ;; Needed by `rdebug-breakpoint-parse-and-update-cache'. + (gud-comint-buffer (current-buffer))) + (save-excursion + (switch-to-buffer buf) + (insert "Num Enb What\n") + (insert " 1 y at /test.rb:10\n") + (insert " 2 n at /test.rb:11\n") + (insert " 3 y at /test.rb:12\n") + (insert " 4 y at /test.rb:13\n") + (rdebug-breakpoint-parse-and-update-cache)) + (setq gud-target-name "test.rb") + + ;; ---------- + ;; Toggle break point + (assert-equal 4 (length (rdebug-all-breakpoints))) + + ;; ---------- + ;; Toggle break point + + ;; Add new. + (rdebug-toggle-source-breakpoint "/test.rb" 20) + (assert-equal "break /test.rb:20" last-gud-call) + ;; Delete enabled. + (rdebug-toggle-source-breakpoint "/test.rb" 10) + (assert-equal "delete 1" last-gud-call) + ;; Delete disabled. + (rdebug-toggle-source-breakpoint "/test.rb" 11) + (assert-equal "delete 2" last-gud-call) + + ;; ---------- + ;; Toggle enable/disable. + + ;; Add new. + (rdebug-toggle-source-breakpoint-enabled "/test.rb" 30) + (assert-equal "break /test.rb:30" last-gud-call) + + ;; Toggle enabled. + (rdebug-toggle-source-breakpoint-enabled "/test.rb" 10) + (assert-equal "disable 1" last-gud-call) + ;; Toggle disabled. + (rdebug-toggle-source-breakpoint-enabled "/test.rb" 11) + (assert-equal "enable 2" last-gud-call))) + + +;; ------------------------------------------------------------------- +;; Check rdebug-next with prefix toggling commands +;; +(deftest "rdebug-stepping-test" + (setq rdebug-stepping-prefix "") + (assert-equal "next 1" (rdebug-next)) + (setq rdebug-stepping-prefix "-") + (assert-equal "next- 2" (rdebug-next 2)) + (setq rdebug-stepping-prefix "+") + (assert-equal "step+ 1" (rdebug-step)) + ) + +;; ------------------------------------------------------------------- +;; Build and run the test suite. +;; + +(build-suite "rdebug-cmd-suite" + "rdebug-goto-frame-test" + "rdebug-stepping-test" + "rdebug-toggle-breakpoints") +(run-elk-test "rdebug-cmd-suite" + "test some rdebug-core code") diff --git a/emacs/test/.svn/text-base/test-core.el.svn-base b/emacs/test/.svn/text-base/test-core.el.svn-base new file mode 100644 index 0000000..206b60a --- /dev/null +++ b/emacs/test/.svn/text-base/test-core.el.svn-base @@ -0,0 +1,104 @@ +;; -*- emacs-lisp -*- +;; This program has to be run from the directory it is currently in and +;; the rdebug code has to be in the parent directory +(load-file "./elk-test.el") + +;; FIXME? Should we use "require 'rdebug" here. +;; Would have to prepend . to load-path. +(load-file "../rdebug.el") +(load-file "../rdebug-core.el") + +;; Redefine functions to make them harmless for testing +(defun rdebug-process-annotation (name contents) + (message name) + ) + +(make-variable-buffer-local 'gud-rdebug-marker-acc) + +(deftest "rdebug-get-script-name-test" + (assert-equal '("foo" nil) (rdebug-get-script-name '("rdebug" "foo"))) + (assert-equal '("foo" nil) (rdebug-get-script-name '("rdebug" "-m" "foo"))) + (assert-equal '("foo" t) (rdebug-get-script-name + '("rdebug" "--emacs" "3" "foo"))) + (assert-equal '("foo" t) (rdebug-get-script-name + '("myrdebug" "--annotate=1" "foo"))) + (assert-equal '("foo" t) (rdebug-get-script-name + '("ruby" "rdebug" "--annotate" "1" "foo"))) + (assert-equal '("foo" nil) (rdebug-get-script-name + '("/usr/bin/ruby19" "rdebug" "--emacs-basic" "foo"))) + (assert-equal '("foo" nil) (rdebug-get-script-name + '("rdbg.rb" "foo"))) + (assert-equal '("rdbg.rb" nil) (rdebug-get-script-name + '("rdebug" "rdbg.rb" "foo"))) + (assert-equal '("foo" t) (rdebug-get-script-name '("rdebug" "-A" "1" "foo"))) + (assert-equal '("foo" nil) + (rdebug-get-script-name + '("rdebug" "--include" "me" "-n" "foo"))) + (assert-equal '("foo" nil) (rdebug-get-script-name + '("rdebug" "--server" "-d" "--host" + "localhost" "foo" "-1"))) + ) + +(deftest "rdebug-goto-entry-test" + (let ((buf (generate-new-buffer "testing"))) + (save-excursion + (switch-to-buffer buf) + (insert "#0 at line /tmp/gcd.rb:4\n") + (goto-char (point-min)) + (assert-equal t (rdebug-goto-entry-try "0")) + (assert-equal nil (rdebug-goto-entry-try "1")) + (insert " 1 y at gcd.rb:10\n") + (goto-char (point-min)) + ;; Don't know why this doesn't work. + ;;(assert-equal t (rdebug-goto-entry-try "1")) + (insert "5: 1 + 2 = 3\n") + (goto-char (point-min)) + (assert-equal t (rdebug-goto-entry-try "5")) + (goto-char (point-min)) + (assert-equal nil (rdebug-goto-entry-try "3"))) + (kill-buffer buf))) + +(defun rdebug-test-call-entry-n (str) + "Call `rdebug-goto-entry-n', return the line we landed on." + (rdebug-goto-entry-n-internal str) + (beginning-of-line) + (count-lines (point-min) (point))) + +;; The original implementation could not go to "10" if there was no "1" entry. +(deftest "rdebug-goto-entry-test-2" + (let ((buf (generate-new-buffer "testing"))) + (save-excursion + (switch-to-buffer buf) + (insert "#0 at line /tmp/gcd.rb:4\n") + (insert "#2 at line /tmp/gcd.rb:44\n") + (insert "#13 at line /tmp/gcd.rb:444\n") + (goto-char (point-min)) + (setq rdebug-goto-entry-acc "") + ;; Goto "0" + (assert-equal 0 (rdebug-test-call-entry-n "0")) + ;; Goto "2" + (assert-equal 1 (rdebug-test-call-entry-n "2")) + ;; There is no "1" or "21" or "021", so stay. + (assert-equal 1 (rdebug-test-call-entry-n "1")) + ;; Goto "13" + (assert-equal 2 (rdebug-test-call-entry-n "3")) + ;; There is no "5", "35", or "135", so stay. + (assert-equal 2 (rdebug-test-call-entry-n "5")) + ;; Goto "0" + (assert-equal 0 (rdebug-test-call-entry-n "0")) + ;; Goto "2" + (assert-equal 1 (rdebug-test-call-entry-n "2"))) + (kill-buffer buf))) + + +;; ------------------------------------------------------------------- +;; Build and run the test suite. +;; + +(build-suite "rdebug-suite" + "rdebug-get-script-name-test" + "rdebug-goto-entry-test" + "rdebug-goto-entry-test-2") +(run-elk-test "rdebug-suite" + "test things in rdebug-core.el") + diff --git a/emacs/test/.svn/text-base/test-fns.el.svn-base b/emacs/test/.svn/text-base/test-fns.el.svn-base new file mode 100644 index 0000000..89341cf --- /dev/null +++ b/emacs/test/.svn/text-base/test-fns.el.svn-base @@ -0,0 +1,65 @@ +;; -*- emacs-lisp -*- +;; This program has to be run from the directory it is currently in and +;; the rdebug code has to be in the parent directory +(load-file "./elk-test.el") + +(setq load-path (cons ".." load-path)) +(require 'rdebug-fns) +(require 'rdebug-locring) +(setq load-path (cdr load-path)) + +;; ------------------------------------------------------------------- + +(deftest "test-add-to-ring" + (let ((location-ring (make-ring 5))) + (assert-equal t (ring-empty-p location-ring)) + (rdebug-locring-add 'first location-ring) + (assert-equal 'first (ring-ref location-ring 0)) + (assert-equal 1 (ring-length location-ring)) + ;; Trying to add the same entry should not again. + (rdebug-locring-add 'first location-ring) + (assert-equal 1 (ring-length location-ring)) + + ;; Second should go in as last item. + (rdebug-locring-add 'second location-ring) + (assert-equal 'second (ring-ref location-ring 1)) + ;; First item is still 0. + (assert-equal 'first (ring-ref location-ring 0)))) + +(deftest "test-chomp" + (assert-equal "" (chomp "")) + (assert-equal "hi" (chomp "hi")) + (assert-equal "hi" (chomp "hi\n")) + (assert-equal "hi\n" (chomp "hi\n\n")) + (assert-equal "hi" (chomp "hi\n\n" t))) + +(deftest "test-set-frame-arrow" + (let ((rdebug-frames-current-frame-number 0)) + (rdebug-set-frame-arrow (current-buffer)) + (assert-equal '((overlay-arrow . right-triangle)) + fringe-indicator-alist) + (setq rdebug-frames-current-frame-number 1) + (rdebug-set-frame-arrow (current-buffer)) + (assert-equal '((overlay-arrow . hollow-right-triangle)) + fringe-indicator-alist))) + +(require 'shell) +(deftest "test-dead-process-p" + (assert-equal t (rdebug-dead-process-p)) + (let ((gud-comint-buffer nil)) + (assert-equal t (rdebug-dead-process-p)) + (setq gud-comint-buffer (shell)) + (assert-equal nil (rdebug-dead-process-p)))) + +;; ------------------------------------------------------------------- +;; Build and run the test suite. +;; + +(build-suite "rdebug-gud-suite" + "test-add-to-ring" + "test-chomp" + "test-dead-process-p" + "test-set-frame-arrow") + +(run-elk-test "rdebug-gud-suite" + "test some rdebug-error code") diff --git a/emacs/test/.svn/text-base/test-frames.el.svn-base b/emacs/test/.svn/text-base/test-frames.el.svn-base new file mode 100644 index 0000000..c491f75 --- /dev/null +++ b/emacs/test/.svn/text-base/test-frames.el.svn-base @@ -0,0 +1,62 @@ +;; -*- emacs-lisp -*- +;; This program has to be run from the directory it is currently in and +;; the rdebug code has to be in the parent directory +(load-file "./elk-test.el") + +;; FIXME? Should we use "require 'rdebug" here. +;; Would have to prepend . to load-path. +(load-file "../rdebug.el") +(load-file "../rdebug-regexp.el") +(load-file "../rdebug-frames.el") + +(make-variable-buffer-local 'gud-rdebug-marker-acc) + +(deftest "rdebug-stack-buffer-field-test" + (let ((buf (generate-new-buffer "testing"))) + (save-excursion + (switch-to-buffer buf) + (insert + "--> #0 Object.gcd(a#Fixnum, b#Fixnum) at line /tmp/gcd.rb:4\n") + (insert + " at line /foo/bar/custom_require.rb:27\n") + + (goto-char (point-min)) + (let* ((b (line-beginning-position)) (e (line-end-position)) + (s (buffer-substring b e)) + (file nil) (line nil)) + (assert-nonnil (string-match rdebug-stack-frame-regexp s)) + (assert-equal "/tmp/gcd.rb" (rdebug-stack-buffer-field + s b + rdebug-stack-frame-file-group + font-lock-comment-face)) + (assert-equal "4" (rdebug-stack-buffer-field + s b + rdebug-stack-frame-line-group + font-lock-constant-face)) + (forward-line) + (setq b (line-beginning-position)) + (setq e (line-end-position)) + (setq s (buffer-substring b e)) + (assert-nonnil (string-match rdebug-stack-frame-2nd-regexp s)) + (assert-equal "/foo/bar/custom_require.rb" + (rdebug-stack-buffer-field + s b + rdebug-stack-frame-2nd-file-group + font-lock-comment-face)) + (assert-equal "27" (rdebug-stack-buffer-field + s b + rdebug-stack-frame-2nd-line-group + font-lock-constant-face)) + )) + (kill-buffer buf))) + + +;; ------------------------------------------------------------------- +;; Build and run the test suite. +;; + +(build-suite "rdebug-suite" + "rdebug-stack-buffer-field-test") +(run-elk-test "rdebug-suite" + "test things in rdebug-frames.el") + diff --git a/emacs/test/.svn/text-base/test-gud.el.svn-base b/emacs/test/.svn/text-base/test-gud.el.svn-base new file mode 100644 index 0000000..ddf3c39 --- /dev/null +++ b/emacs/test/.svn/text-base/test-gud.el.svn-base @@ -0,0 +1,35 @@ +;; -*- emacs-lisp -*- +;; This program has to be run from the directory it is currently in and +;; the rdebug code has to be in the parent directory +(load-file "./elk-test.el") + +(setq load-path (cons ".." load-path)) +(require 'rdebug-gud) +(setq load-path (cdr load-path)) + +(defun y-or-n-p (prompt) + "Replacement of y-or-n-p() for rdebug testing" + (assert-nil "y-or-n-p should not have been called")) + +(defun error (msg) + "Replacement error() for rdebug testing" + (assert-nil "error should not have been called")) + +;; ------------------------------------------------------------------- + +(deftest "test-rdebug-find-file" + ;; Set to cause a warning in find-file-no-select and + ;; check that it is ignored. + (let ((large-file-warning-threshold 1)) + (gud-rdebug-find-file "elk-test.el"))) + + +;; ------------------------------------------------------------------- +;; Build and run the test suite. +;; + +(build-suite "rdebug-gud-suite" + "test-rdebug-find-file") + +(run-elk-test "rdebug-gud-suite" + "test some rdebug-gud code") diff --git a/emacs/test/.svn/text-base/test-indent.el.svn-base b/emacs/test/.svn/text-base/test-indent.el.svn-base new file mode 100644 index 0000000..ad4ec91 --- /dev/null +++ b/emacs/test/.svn/text-base/test-indent.el.svn-base @@ -0,0 +1,58 @@ +;; -*- emacs-lisp -*- +;; This program has to be run from the directory it is currently in and +;; the rdebug code has to be in the parent directory +(load-file "./elk-test.el") + +;; ------------------------------------------------------------------- +;; Check source code indentation +;; + +(put 'rdebug-debug-enter 'lisp-indent-hook 1) + +(defun rdebug-test-reindent-one-file (file) + (let ((buf (generate-new-buffer "testing")) + (res nil)) + (save-excursion + (switch-to-buffer buf) + (insert-file file) + (emacs-lisp-mode) + (set-buffer-modified-p nil) + (undo-boundary) + (indent-region (point-min) (point-max)) + (if (buffer-modified-p) + (setq res "Reindentation failed"))) + (kill-buffer buf) + res)) + +(deftest "rdebug-indent-files" + (mapcar (lambda (lisp-file) + (message lisp-file) + (assert-nil (rdebug-test-reindent-one-file lisp-file))) + '("../rdebug.el" + "../rdebug-breaks.el" + "../rdebug-cmd.el" + "../rdebug-core.el" + "../rdebug-dbg.el" + "../rdebug-error.el" + "../rdebug-frames.el" + "../rdebug-fns.el" + "../rdebug-gud.el" + "../rdebug-help.el" + "../rdebug-info.el" + "../rdebug-layouts.el" + "../rdebug-output.el" + "../rdebug-regexp.el" + "../rdebug-secondary.el" + "../rdebug-source.el" + "../rdebug-track.el" + "../rdebug-varbuf.el" + "../rdebug-vars.el" + "../rdebug-watch.el" + "./test-cmd.el" + "./test-core.el" + "./test-indent.el" + "./test-regexp.el" + ))) + +(run-elk-test "rdebug-indent-files" + "test indentation of Lisp files") diff --git a/emacs/test/.svn/text-base/test-regexp.el.svn-base b/emacs/test/.svn/text-base/test-regexp.el.svn-base new file mode 100644 index 0000000..790971e --- /dev/null +++ b/emacs/test/.svn/text-base/test-regexp.el.svn-base @@ -0,0 +1,144 @@ +;; -*- emacs-lisp -*- +;; This program has to be run from the directory it is currently in and +;; the rdebug code has to be in the parent directory +(load-file "./elk-test.el") + +;; FIXME? Should we use "require 'rdebug" here. +;; Would have to prepend . to load-path. +(load-file "../rdebug.el") +(load-file "../rdebug-core.el") + +(make-variable-buffer-local 'gud-rdebug-marker-acc) + +(defun regexp-breakpoint-test (location-str pos-str enabled-str file-str line-str) + "Test to see that location-str parses rdebug-breakpoint-regexp properly" + (assert-equal 0 (string-match rdebug-breakpoint-regexp location-str)) + (assert-equal pos-str + (substring location-str (match-beginning 1) (match-end 1))) + (assert-equal enabled-str + (substring location-str (match-beginning 2) (match-end 2))) + (assert-equal file-str + (substring location-str (match-beginning 3) (match-end 3))) + (assert-equal line-str + (substring location-str (match-beginning 4) (match-end 4))) + ) +(deftest "rdebug-regexp-breakpoint-test" + + (regexp-breakpoint-test + " 1 y at gcd.rb:6" + "1" "y" "gcd.rb" "6" + ) + (regexp-breakpoint-test + " 1 y at gcd.rb:6 if 1 == a" + "1" "y" "gcd.rb" "6" + ) + ) + +(defun regexp-file-test (location-str file-str) + "Test to see that location-str matches gud-rdebug-marker-regexp" + (assert-equal 0 (string-match gud-rdebug-marker-regexp location-str)) + (assert-equal file-str + (substring location-str (match-beginning 1) (match-end 1))) + ) +(deftest "rdebug-regexp-file-test" + + (regexp-file-test + "\032\032./hanoi.rb:3\n" + "./hanoi.rb" + ) + (regexp-file-test + "\032\032source ./hanoi.rb:3\n" + "./hanoi.rb" + ) + (regexp-file-test + "\032\032C:/tmp/gcd.rb:29\n" + "C:/tmp/gcd.rb" + ) + (regexp-file-test + "\032\032source \\sources\\capfilterscanner\\capanalyzer.rb:3: \n" + "\\sources\\capfilterscanner\\capanalyzer.rb" + ) + ) + +(deftest "rdebug-regexp-marker-filter-test" + (assert-equal "Testing 1 2 3" (gud-rdebug-marker-filter "Testing 1 2 3")) + (assert-equal "ABC" (gud-rdebug-marker-filter + "\ +breakpoints +No breakpoints + +ABC"))) + +(defun regexp-stack-test (location-str pos-str file-str line-str) + "Test to see that location-str parses rdebug-stack-frame-regexp properly" + (assert-equal 0 (string-match rdebug-stack-frame-regexp location-str)) + (assert-equal pos-str + (substring location-str (match-beginning 2) (match-end 2))) + (assert-equal file-str + (substring location-str (match-beginning 4) (match-end 4))) + (assert-equal line-str + (substring location-str (match-beginning 5) (match-end 5))) + ) +(deftest "rdebug-regexp-stack-test" + + (regexp-stack-test + "--> #0 at line /home/rocky/ruby/gcd.rb:18" + "0" "/home/rocky/ruby/gcd.rb" "18" + ) + ) + +(defun regexp-traceback-test (location-str file-str line-str) + "Test to see that location-str matches position-regexp-file-test with the correct +file and line submatches." + (assert-equal 0 (string-match rdebug-traceback-line-re location-str)) + (assert-equal file-str (match-string 1 location-str)) + (assert-equal line-str (match-string 2 location-str)) + ) + +(deftest "rdebug-regexp-traceback-test" + + (regexp-traceback-test + " from /home/rocky/ruby/gcd.rb:15:in `gcd'" + "/home/rocky/ruby/gcd.rb" "15" + ) + (regexp-traceback-test + " from /home/rocky/ruby/gcd.rb:19" + "/home/rocky/ruby/gcd.rb" "19" + ) + ) + +(defun regexp-unittest-traceback-test (location-str file-str line-str) + "Test to see that location-str matches position-regexp-file-test with the correct +file and line submatches." + (assert-equal 0 (string-match rdebug-dollarbang-traceback-line-re + location-str)) + (assert-equal file-str (match-string 1 location-str)) + (assert-equal line-str (match-string 2 location-str)) + ) + +(deftest "rdebug-regexp-unittest-traceback-test" + + (regexp-unittest-traceback-test + " [test-frame.rb:26:in `test_basic'" + "test-frame.rb" "26" + ) + (regexp-unittest-traceback-test + " test-frame.rb:22:in `test_basic']:" + "test-frame.rb" "22" + ) + ) + +;; ------------------------------------------------------------------- +;; Build and run the test suite. +;; + +(build-suite "rdebug-suite" + "rdebug-regexp-breakpoint-test" + "rdebug-regexp-file-test" + "rdebug-regexp-marker-filter-test" + "rdebug-regexp-stack-test" + "rdebug-regexp-traceback-test" + "rdebug-regexp-unittest-traceback-test") + +(run-elk-test "rdebug-suite" + "test regular expressions used in tracking lines") diff --git a/emacs/test/.svn/text-base/test-shortkey.el.svn-base b/emacs/test/.svn/text-base/test-shortkey.el.svn-base new file mode 100644 index 0000000..3318c40 --- /dev/null +++ b/emacs/test/.svn/text-base/test-shortkey.el.svn-base @@ -0,0 +1,61 @@ +;; -*- emacs-lisp -*- +;; This program has to be run from the directory it is currently in and +;; the rdebug code has to be in the parent directory +(load-file "./elk-test.el") + +;; FIXME? Should we use "require 'rdebug" here. +;; Would have to prepend . to load-path. +(setq load-path (cons ".." load-path)) +(load-file "../rdebug-shortkey.el") + +(deftest "rdebug-shortkey-mode-test" + (let ((buf (generate-new-buffer "shortkey readwrite"))) + (with-current-buffer buf + (setq buffer-read-only nil) + ;; turning on short-key-mode make buffer read-only + (rdebug-internal-short-key-mode 1) + (assert-equal t buffer-read-only) + + ;; turning off short-key-mode should make buffer read-write again + (rdebug-internal-short-key-mode -1) + (assert-equal nil buffer-read-only) + + ;; -------------------- + ;; Check multiple "on": and "off:s". + + (rdebug-internal-short-key-mode 1) + (assert-equal t buffer-read-only) + + (rdebug-internal-short-key-mode 1) + (assert-equal t buffer-read-only) + + (rdebug-internal-short-key-mode 1) + (assert-equal t buffer-read-only) + + (rdebug-internal-short-key-mode -1) + (assert-equal nil buffer-read-only)) + + (kill-buffer buf)) + + (let ((buf (generate-new-buffer "shortkey readonly"))) + (with-current-buffer buf + (setq buffer-read-only t) + + ;; turning on short-key-mode keep buffer read-only + (rdebug-internal-short-key-mode 1) + (assert-equal t buffer-read-only) + + ;; The buffer was originally in read-only mode, it should remain + ;; there. + (rdebug-internal-short-key-mode -1) + (assert-equal t buffer-read-only)) + (kill-buffer buf))) + +;; ------------------------------------------------------------------- +;; Build and run the test suite. +;; + +(build-suite "rdebug-suite" + "rdebug-shortkey-mode-test") +(run-elk-test "rdebug-suite" + "test things in rdebug-shortkey.el") diff --git a/emacs/test/elk-test.el b/emacs/test/elk-test.el new file mode 100644 index 0000000..ddfc03c --- /dev/null +++ b/emacs/test/elk-test.el @@ -0,0 +1,242 @@ +;;; elk-test.el --- Emacs Lisp testing suite + +;; Copyright (C) 2006 Nikolaj Schumacher + +;;; License + +;; This program is free software; you can redistribute it and/or +;; modify it under the terms of the GNU General Public License +;; as published by the Free Software Foundation; either version 2 +;; of the License, or (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program; if not, write to the Free Software +;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +;;; Usage + +;; Use `deftest' to define a test and `run-elk-test' to run it. +;; Create test bundles with `defsuite' or `build-suite'. +;; Verify your code with `assert-equal', `assert-eq', `assert-eql', +;; `assert-nonnil', `assert-t', `assert-nil' and `assert-error' +;; to verify your code. + +;;; Examples + +;; (deftest "test1" +;; (assert-equal t t) +;; (assert-eq t 'foo)) + +;; (defsuite "suite1" +;; (deftest "test1" (assert-equal t t))) + +;; (deftest "test2" +;; (assert-equal t t)) +;; (build-suite "combined-suite" "test1" "test2") + +;; (run-elk-test "combined-suite") +;; (run-elk-test) + +(require 'cl) + +(defvar elk-test-run-on-define nil + "If non-nil, run elk-test tests/suites immediately when defining them.") + +(defvar elk-test-map (make-hash-table :test 'equal) + "A map of elk-test test/suite names to their implementation.") + +(defvar elk-test-list nil + "A list of all defined elk-test tests/suites.") + +(defun elk-test-clear () + "Remove all tests from memory." + (setq elk-test-map (make-hash-table :test 'equal) + elk-test-list nil)) + +(defun run-elk-test (name &optional string-result) + "Run the test case defined as NAME. +The result is a list of errors strings, unless STRING-RESULT is set, in which +case a message describing the errors or success is displayed and returned." + (interactive + (list (completing-read "Test name: " elk-test-list nil t))) + (let ((name name)) + (let ((elk-test-errors nil) + (test-or-suite (gethash name elk-test-map))) + (if (not test-or-suite) + (error "Undefined test <%s>" name) + (if (equal (car test-or-suite) 'suite) + ;; is test suite + (let ((map (cadr test-or-suite))) + (dolist (test (caddr test-or-suite)) + (setq elk-test-errors + (append elk-test-errors + (run-elk-test-internal (gethash test map)))))) + ;; is simple test + (setq elk-test-errors (run-elk-test-internal test-or-suite))) + (if (or string-result (interactive-p)) + (message (if elk-test-errors + (mapconcat 'identity elk-test-errors "\n") + "Test run was successful.")) + elk-test-errors))))) + +(defun run-elk-tests-buffer (&optional buffer) + "Execute BUFFER as lisp code and run all tests therein." + (interactive) + (let* ((elk-test-list) + (elk-test-map (make-hash-table :test 'equal)) + (elk-test-run-on-define nil) + (inhibit-read-only t) + (buffer-name (buffer-name buffer)) + (success t) + (parse-res (condition-case err (eval-buffer buffer) (error err)))) + (if parse-res + (message "Parsing buffer <%s> failed:\n%s" + buffer-name parse-res) + (let ((out-buffer (get-buffer-create + (concat "*elk-test run " buffer-name "*"))) + failure) + (with-current-buffer out-buffer + (erase-buffer) + (dolist (test elk-test-list) + (message "running <%s>" test) + (let ((results (run-elk-test test))) + (when results + (setq failure t) + (insert "test <" test "> failed:\n") + (dolist (result results) + (insert "* " result "\n")))))) + (if failure + (display-buffer out-buffer) + (kill-buffer out-buffer) + (message "Test run was successful.")))))) + +(defun run-elk-test-internal (test) + (let ((elk-test-errors nil)) + (dolist (sexpr test) + (let ((problem (condition-case err (progn (eval sexpr) nil) (error err)))) + (when problem + (push (message "%s" problem) elk-test-errors)))) + elk-test-errors)) + +(defmacro elk-test-error (format-string &rest args) + "Create an error string as the result of a failed elk-test assertion. +The first argument is a format control string, and the rest are data to be +formatted under control of the string. See `format' for details. + +The result will be displayed, returned and if called inside of `run-elk-test' +added to the internal error list." + `(let ((string (message ,format-string ,@args))) + (when (boundp 'elk-test-errors) + (push string elk-test-errors)) + string)) + +(defmacro assert-equal (expected actual) + "Assert that ACTUAL equals EXPECTED, or signal a warning." + `(unless (equal ,expected ,actual) + (elk-test-error "assert-equal for <%s> failed: expected <%s>, was <%s>" + ',actual ,expected ,actual))) + +(defmacro assert-eq (expected actual) + "Assert that ACTUAL equals EXPECTED, or signal a warning." + `(unless (eq ,expected ,actual) + (elk-test-error "assert-eq for <%s> failed: expected <%s>, was <%s>" + ',actual ,expected ,actual))) + +(defmacro assert-eql (expected actual) + "Assert that ACTUAL equals EXPECTED, or signal a warning." + `(unless (eql ,expected ,actual) + (elk-test-error "assert-eql for <%s> failed: expected <%s>, was <%s>" + ',actual ,expected ,actual))) + +(defmacro assert-nonnil (value) + "Assert that VALUE is not nil, or signal a warning." + `(unless ,value + (elk-test-error "assert-nonnil for <%s> failed: was <%s>" + ',value ,value))) + +(defmacro assert-t (value) + "Assert that VALUE is t, or signal a warning." + `(unless (eq ,value t) + (elk-test-error "assert-t for <%s> failed: was <%s>" + ',value ,value))) + +(defmacro assert-nil (value) + "Assert that VALUE is nil, or signal a warning." + `(when ,value + (elk-test-error "assert-nil for <%s> failed: was <%s>" + ',value ,value))) + +(defmacro assert-error (error-message &rest body) + "Assert that BODY raises an `error', or signal a warning. +ERROR-MESSAGE is the expected error string, use nil to accept any error. Use +nil with caution, as errors like 'wrong-number-of-arguments' (likely caused by +typos) will also be caught!" + `(let ((elk-test-error + (condition-case elk-test-error + (progn ,@body) + (error (cons 'elk-test-error (cadr elk-test-error)))))) + (if (not (eq (car elk-test-error) 'elk-test-error)) + ;; no error + (elk-test-error "assert-error for <%s> failed: did not raise an error" + (append '(progn) ',body)) + (when (and ,error-message + (not (equal ,error-message (cdr elk-test-error)))) + (elk-test-error (concat "assert-error for <%s> failed: expected <%s>, " + "raised <%s>") + (append '(progn) ',body) + ,error-message (cdr elk-test-error)))))) + +(defmacro deftest (name &rest body) + "Define a test case. +Use `assert-equal', `assert-eq', `assert-eql', `assert-nonnil', `assert-t', +`assert-nil' and `assert-error' to verify the code." + `(progn (unless (gethash ,name elk-test-map) + (push ,name elk-test-list)) + (puthash ,name ',body elk-test-map) + ,(if elk-test-run-on-define + `(run-elk-test ',name ,t) + name))) + +(defmacro defsuite (name &rest body) + "Define a test suite using a collection of `deftest' forms. +The resulting suite can be called with `run-elk-test' and parameter NAME." + `(let ((suite + (let ((elk-test-map (make-hash-table :test 'equal)) + (elk-test-list nil)) + ,@body + (list 'suite elk-test-map (reverse elk-test-list))))) + (unless (gethash ,name elk-test-map) + (push ,name elk-test-list)) + (puthash ,name suite elk-test-map) + ,(if elk-test-run-on-define + `(run-elk-test ,name t) + name))) + +(defun build-suite (name &rest tests) + "Define a test suite using a collection of test names. +The resulting suite can be run by calling `run-elk-test' with parameter NAME." + (unless (gethash name elk-test-map) + (push name elk-test-list)) + (puthash name + (let ((map (make-hash-table :test 'equal)) + (list nil)) + (dolist (test-name tests) + (push test-name list) + (when (gethash test-name map) + (error "Test used twice")) + (let ((test (gethash test-name elk-test-map))) + (unless test + (error "Undefined test <%s>" test-name)) + (puthash test-name test map))) + (list 'suite map (reverse list))) + elk-test-map) + (if elk-test-run-on-define + (run-elk-test "sample suite" t) + name)) + +(provide 'elk-test) diff --git a/emacs/test/test-annotate.el b/emacs/test/test-annotate.el new file mode 100644 index 0000000..2042985 --- /dev/null +++ b/emacs/test/test-annotate.el @@ -0,0 +1,103 @@ +;; -*- emacs-lisp -*- +;; This program has to be run from the directory it is currently in and +;; the rdebug code has to be in the parent directory +(load-file "./elk-test.el") + +;; FIXME? Should we use "require 'rdebug" here. +;; Would have to prepend . to load-path. +(load-file "../rdebug.el") +(load-file "../rdebug-annotate.el") + +(defvar last-annotation nil + "Value of the last annotation processed") + +;; Redefine functions to make them harmless for testing +(defun rdebug-process-annotation (name contents) + (setq last-annotation name)) + +(make-variable-buffer-local 'gud-rdebug-marker-acc) + +;; ------------------------------------------------------------------- +;; Test harness for testing the filter. +;; + +(require 'advice) + +(defvar rdebug-test-cmd-list '()) + +;; Override, partially because tooltip-show doesn't work in batch +;; mode, and partially because we collect the output here. +(defun tooltip-show (text) + (setq rdebug-test-cmd-list (cons text rdebug-test-cmd-list))) + +(defun assert-filter (output str &optional cmd-list) + (setq rdebug-test-cmd-list '()) + (setq gud-marker-acc "") + (let ((orig-queue rdebug-call-queue)) + (let ((real-output (gud-rdebug-marker-filter str))) + (assert-equal output real-output) + (assert-equal cmd-list (reverse rdebug-test-cmd-list))) + + ;; + ;; Feed the filter one character at a time -- the end result should + ;; be the same. + ;; + (setq rdebug-test-cmd-list '()) + (setq gud-marker-acc "") + (let ((real-output "") + (len (length str)) + (i 0) + (rdebug-call-queue orig-queue)) + (while (< i len) + (setq real-output + (concat real-output + (gud-rdebug-marker-filter + (substring str i (if (equal (+ 1 i) len) + nil + (+ 1 i)))))) + (setq i (+ 1 i))) + (assert-equal output real-output) + (assert-equal cmd-list (reverse rdebug-test-cmd-list))))) + + +(deftest "rdebug-filter" +;;; (assert-filter "X" "X") +;;; (assert-filter "XYZ" "XYZ") +;;; (assert-filter "" "\n") +;;; (assert-filter "Testing 1 2 3" "Testing 1 2 3") +;;; (assert-filter "Testing 1 2 3" "Testing 1 2 3") +;;; (assert-filter "ABC" "\ +;;; breakpoints +;;; No breakpoints +;;;  +;;; ABC") + + ;; Some systems (read: Mac) echoes the command. + (setq rdebug-call-queue '(("pp 100" :tooltip))) + (assert-filter "pp 100\n100\n(rdb:1) " "\ +prompt +pp 100\n100 +pre-prompt +\(rdb:1) \nprompt\n" + '("100\n")) + + ;; Some systems don't echo the command. + (setq rdebug-call-queue '(("pp 100" :tooltip))) + (assert-filter "100\n(rdb:1) " "\ +prompt +100 +pre-prompt +\(rdb:1) \nprompt\n" + '("100\n")) + ) + + +;; ------------------------------------------------------------------- +;; Build and run the test suite. +;; + +(build-suite "rdebug-suite" + "rdebug-filter") + +(run-elk-test "rdebug-suite" + "test regular expressions used in tracking lines") diff --git a/emacs/test/test-cmd.el b/emacs/test/test-cmd.el new file mode 100644 index 0000000..972ec1b --- /dev/null +++ b/emacs/test/test-cmd.el @@ -0,0 +1,116 @@ +;; -*- emacs-lisp -*- +;; This program has to be run from the directory it is currently in and +;; the rdebug code has to be in the parent directory +(load-file "./elk-test.el") + +(setq load-path (cons ".." load-path)) +(require 'rdebug-core) +(require 'rdebug-gud) +(setq load-path (cdr load-path)) + +(defvar last-gud-call nil + "Value of the last gud-call") + +;; Redefine functions to make them harmless for testing +(defun gud-call (command) + (setq last-gud-call command)) + +(defun rdebug-call (command) + (setq last-gud-call command)) + +(deftest "rdebug-goto-frame-test" + (let ((buf (generate-new-buffer "testing"))) + (save-excursion + (switch-to-buffer buf) + (insert "#0 ERB.result(b#Binding) at line /usr/lib/ruby/1.8/erb.rb:736\n") + (insert "#1 Listings.build at line erbtest.rb:24\n") + (insert "#2 at line erbtest.rb:33\n") + (insert "#10 Listings.build at line erbtest.rb:23") + (goto-char (point-min)) + (setq last-gud-call nil) + (setq rdebug-goto-entry-acc "") + + ;; -------------------- + ;; The tests + + (rdebug-goto-frame-n-internal "5") + (assert-equal nil last-gud-call) + (rdebug-goto-frame-n-internal "1") + (assert-equal "frame 1" last-gud-call) + (rdebug-goto-frame-n-internal "0") + (assert-equal "frame 10" last-gud-call)) + (kill-buffer buf))) + + +;; ------------------------------------------------------------------- +;; Check breakpoint toggle commands +;; + +(deftest "rdebug-toggle-breakpoints" + (let ((buf (generate-new-buffer "*rdebug-breakpoint-test.rb*")) + ;; Needed by `rdebug-breakpoint-parse-and-update-cache'. + (gud-comint-buffer (current-buffer))) + (save-excursion + (switch-to-buffer buf) + (insert "Num Enb What\n") + (insert " 1 y at /test.rb:10\n") + (insert " 2 n at /test.rb:11\n") + (insert " 3 y at /test.rb:12\n") + (insert " 4 y at /test.rb:13\n") + (rdebug-breakpoint-parse-and-update-cache)) + (setq gud-target-name "test.rb") + + ;; ---------- + ;; Toggle break point + (assert-equal 4 (length (rdebug-all-breakpoints))) + + ;; ---------- + ;; Toggle break point + + ;; Add new. + (rdebug-toggle-source-breakpoint "/test.rb" 20) + (assert-equal "break /test.rb:20" last-gud-call) + ;; Delete enabled. + (rdebug-toggle-source-breakpoint "/test.rb" 10) + (assert-equal "delete 1" last-gud-call) + ;; Delete disabled. + (rdebug-toggle-source-breakpoint "/test.rb" 11) + (assert-equal "delete 2" last-gud-call) + + ;; ---------- + ;; Toggle enable/disable. + + ;; Add new. + (rdebug-toggle-source-breakpoint-enabled "/test.rb" 30) + (assert-equal "break /test.rb:30" last-gud-call) + + ;; Toggle enabled. + (rdebug-toggle-source-breakpoint-enabled "/test.rb" 10) + (assert-equal "disable 1" last-gud-call) + ;; Toggle disabled. + (rdebug-toggle-source-breakpoint-enabled "/test.rb" 11) + (assert-equal "enable 2" last-gud-call))) + + +;; ------------------------------------------------------------------- +;; Check rdebug-next with prefix toggling commands +;; +(deftest "rdebug-stepping-test" + (setq rdebug-stepping-prefix "") + (assert-equal "next 1" (rdebug-next)) + (setq rdebug-stepping-prefix "-") + (assert-equal "next- 2" (rdebug-next 2)) + (setq rdebug-stepping-prefix "+") + (assert-equal "step+ 1" (rdebug-step)) + ) + +;; ------------------------------------------------------------------- +;; Build and run the test suite. +;; + +(build-suite "rdebug-cmd-suite" + "rdebug-goto-frame-test" + "rdebug-stepping-test" + "rdebug-toggle-breakpoints") +(run-elk-test "rdebug-cmd-suite" + "test some rdebug-core code") diff --git a/emacs/test/test-core.el b/emacs/test/test-core.el new file mode 100644 index 0000000..206b60a --- /dev/null +++ b/emacs/test/test-core.el @@ -0,0 +1,104 @@ +;; -*- emacs-lisp -*- +;; This program has to be run from the directory it is currently in and +;; the rdebug code has to be in the parent directory +(load-file "./elk-test.el") + +;; FIXME? Should we use "require 'rdebug" here. +;; Would have to prepend . to load-path. +(load-file "../rdebug.el") +(load-file "../rdebug-core.el") + +;; Redefine functions to make them harmless for testing +(defun rdebug-process-annotation (name contents) + (message name) + ) + +(make-variable-buffer-local 'gud-rdebug-marker-acc) + +(deftest "rdebug-get-script-name-test" + (assert-equal '("foo" nil) (rdebug-get-script-name '("rdebug" "foo"))) + (assert-equal '("foo" nil) (rdebug-get-script-name '("rdebug" "-m" "foo"))) + (assert-equal '("foo" t) (rdebug-get-script-name + '("rdebug" "--emacs" "3" "foo"))) + (assert-equal '("foo" t) (rdebug-get-script-name + '("myrdebug" "--annotate=1" "foo"))) + (assert-equal '("foo" t) (rdebug-get-script-name + '("ruby" "rdebug" "--annotate" "1" "foo"))) + (assert-equal '("foo" nil) (rdebug-get-script-name + '("/usr/bin/ruby19" "rdebug" "--emacs-basic" "foo"))) + (assert-equal '("foo" nil) (rdebug-get-script-name + '("rdbg.rb" "foo"))) + (assert-equal '("rdbg.rb" nil) (rdebug-get-script-name + '("rdebug" "rdbg.rb" "foo"))) + (assert-equal '("foo" t) (rdebug-get-script-name '("rdebug" "-A" "1" "foo"))) + (assert-equal '("foo" nil) + (rdebug-get-script-name + '("rdebug" "--include" "me" "-n" "foo"))) + (assert-equal '("foo" nil) (rdebug-get-script-name + '("rdebug" "--server" "-d" "--host" + "localhost" "foo" "-1"))) + ) + +(deftest "rdebug-goto-entry-test" + (let ((buf (generate-new-buffer "testing"))) + (save-excursion + (switch-to-buffer buf) + (insert "#0 at line /tmp/gcd.rb:4\n") + (goto-char (point-min)) + (assert-equal t (rdebug-goto-entry-try "0")) + (assert-equal nil (rdebug-goto-entry-try "1")) + (insert " 1 y at gcd.rb:10\n") + (goto-char (point-min)) + ;; Don't know why this doesn't work. + ;;(assert-equal t (rdebug-goto-entry-try "1")) + (insert "5: 1 + 2 = 3\n") + (goto-char (point-min)) + (assert-equal t (rdebug-goto-entry-try "5")) + (goto-char (point-min)) + (assert-equal nil (rdebug-goto-entry-try "3"))) + (kill-buffer buf))) + +(defun rdebug-test-call-entry-n (str) + "Call `rdebug-goto-entry-n', return the line we landed on." + (rdebug-goto-entry-n-internal str) + (beginning-of-line) + (count-lines (point-min) (point))) + +;; The original implementation could not go to "10" if there was no "1" entry. +(deftest "rdebug-goto-entry-test-2" + (let ((buf (generate-new-buffer "testing"))) + (save-excursion + (switch-to-buffer buf) + (insert "#0 at line /tmp/gcd.rb:4\n") + (insert "#2 at line /tmp/gcd.rb:44\n") + (insert "#13 at line /tmp/gcd.rb:444\n") + (goto-char (point-min)) + (setq rdebug-goto-entry-acc "") + ;; Goto "0" + (assert-equal 0 (rdebug-test-call-entry-n "0")) + ;; Goto "2" + (assert-equal 1 (rdebug-test-call-entry-n "2")) + ;; There is no "1" or "21" or "021", so stay. + (assert-equal 1 (rdebug-test-call-entry-n "1")) + ;; Goto "13" + (assert-equal 2 (rdebug-test-call-entry-n "3")) + ;; There is no "5", "35", or "135", so stay. + (assert-equal 2 (rdebug-test-call-entry-n "5")) + ;; Goto "0" + (assert-equal 0 (rdebug-test-call-entry-n "0")) + ;; Goto "2" + (assert-equal 1 (rdebug-test-call-entry-n "2"))) + (kill-buffer buf))) + + +;; ------------------------------------------------------------------- +;; Build and run the test suite. +;; + +(build-suite "rdebug-suite" + "rdebug-get-script-name-test" + "rdebug-goto-entry-test" + "rdebug-goto-entry-test-2") +(run-elk-test "rdebug-suite" + "test things in rdebug-core.el") + diff --git a/emacs/test/test-fns.el b/emacs/test/test-fns.el new file mode 100644 index 0000000..89341cf --- /dev/null +++ b/emacs/test/test-fns.el @@ -0,0 +1,65 @@ +;; -*- emacs-lisp -*- +;; This program has to be run from the directory it is currently in and +;; the rdebug code has to be in the parent directory +(load-file "./elk-test.el") + +(setq load-path (cons ".." load-path)) +(require 'rdebug-fns) +(require 'rdebug-locring) +(setq load-path (cdr load-path)) + +;; ------------------------------------------------------------------- + +(deftest "test-add-to-ring" + (let ((location-ring (make-ring 5))) + (assert-equal t (ring-empty-p location-ring)) + (rdebug-locring-add 'first location-ring) + (assert-equal 'first (ring-ref location-ring 0)) + (assert-equal 1 (ring-length location-ring)) + ;; Trying to add the same entry should not again. + (rdebug-locring-add 'first location-ring) + (assert-equal 1 (ring-length location-ring)) + + ;; Second should go in as last item. + (rdebug-locring-add 'second location-ring) + (assert-equal 'second (ring-ref location-ring 1)) + ;; First item is still 0. + (assert-equal 'first (ring-ref location-ring 0)))) + +(deftest "test-chomp" + (assert-equal "" (chomp "")) + (assert-equal "hi" (chomp "hi")) + (assert-equal "hi" (chomp "hi\n")) + (assert-equal "hi\n" (chomp "hi\n\n")) + (assert-equal "hi" (chomp "hi\n\n" t))) + +(deftest "test-set-frame-arrow" + (let ((rdebug-frames-current-frame-number 0)) + (rdebug-set-frame-arrow (current-buffer)) + (assert-equal '((overlay-arrow . right-triangle)) + fringe-indicator-alist) + (setq rdebug-frames-current-frame-number 1) + (rdebug-set-frame-arrow (current-buffer)) + (assert-equal '((overlay-arrow . hollow-right-triangle)) + fringe-indicator-alist))) + +(require 'shell) +(deftest "test-dead-process-p" + (assert-equal t (rdebug-dead-process-p)) + (let ((gud-comint-buffer nil)) + (assert-equal t (rdebug-dead-process-p)) + (setq gud-comint-buffer (shell)) + (assert-equal nil (rdebug-dead-process-p)))) + +;; ------------------------------------------------------------------- +;; Build and run the test suite. +;; + +(build-suite "rdebug-gud-suite" + "test-add-to-ring" + "test-chomp" + "test-dead-process-p" + "test-set-frame-arrow") + +(run-elk-test "rdebug-gud-suite" + "test some rdebug-error code") diff --git a/emacs/test/test-frames.el b/emacs/test/test-frames.el new file mode 100644 index 0000000..c491f75 --- /dev/null +++ b/emacs/test/test-frames.el @@ -0,0 +1,62 @@ +;; -*- emacs-lisp -*- +;; This program has to be run from the directory it is currently in and +;; the rdebug code has to be in the parent directory +(load-file "./elk-test.el") + +;; FIXME? Should we use "require 'rdebug" here. +;; Would have to prepend . to load-path. +(load-file "../rdebug.el") +(load-file "../rdebug-regexp.el") +(load-file "../rdebug-frames.el") + +(make-variable-buffer-local 'gud-rdebug-marker-acc) + +(deftest "rdebug-stack-buffer-field-test" + (let ((buf (generate-new-buffer "testing"))) + (save-excursion + (switch-to-buffer buf) + (insert + "--> #0 Object.gcd(a#Fixnum, b#Fixnum) at line /tmp/gcd.rb:4\n") + (insert + " at line /foo/bar/custom_require.rb:27\n") + + (goto-char (point-min)) + (let* ((b (line-beginning-position)) (e (line-end-position)) + (s (buffer-substring b e)) + (file nil) (line nil)) + (assert-nonnil (string-match rdebug-stack-frame-regexp s)) + (assert-equal "/tmp/gcd.rb" (rdebug-stack-buffer-field + s b + rdebug-stack-frame-file-group + font-lock-comment-face)) + (assert-equal "4" (rdebug-stack-buffer-field + s b + rdebug-stack-frame-line-group + font-lock-constant-face)) + (forward-line) + (setq b (line-beginning-position)) + (setq e (line-end-position)) + (setq s (buffer-substring b e)) + (assert-nonnil (string-match rdebug-stack-frame-2nd-regexp s)) + (assert-equal "/foo/bar/custom_require.rb" + (rdebug-stack-buffer-field + s b + rdebug-stack-frame-2nd-file-group + font-lock-comment-face)) + (assert-equal "27" (rdebug-stack-buffer-field + s b + rdebug-stack-frame-2nd-line-group + font-lock-constant-face)) + )) + (kill-buffer buf))) + + +;; ------------------------------------------------------------------- +;; Build and run the test suite. +;; + +(build-suite "rdebug-suite" + "rdebug-stack-buffer-field-test") +(run-elk-test "rdebug-suite" + "test things in rdebug-frames.el") + diff --git a/emacs/test/test-gud.el b/emacs/test/test-gud.el new file mode 100644 index 0000000..ddf3c39 --- /dev/null +++ b/emacs/test/test-gud.el @@ -0,0 +1,35 @@ +;; -*- emacs-lisp -*- +;; This program has to be run from the directory it is currently in and +;; the rdebug code has to be in the parent directory +(load-file "./elk-test.el") + +(setq load-path (cons ".." load-path)) +(require 'rdebug-gud) +(setq load-path (cdr load-path)) + +(defun y-or-n-p (prompt) + "Replacement of y-or-n-p() for rdebug testing" + (assert-nil "y-or-n-p should not have been called")) + +(defun error (msg) + "Replacement error() for rdebug testing" + (assert-nil "error should not have been called")) + +;; ------------------------------------------------------------------- + +(deftest "test-rdebug-find-file" + ;; Set to cause a warning in find-file-no-select and + ;; check that it is ignored. + (let ((large-file-warning-threshold 1)) + (gud-rdebug-find-file "elk-test.el"))) + + +;; ------------------------------------------------------------------- +;; Build and run the test suite. +;; + +(build-suite "rdebug-gud-suite" + "test-rdebug-find-file") + +(run-elk-test "rdebug-gud-suite" + "test some rdebug-gud code") diff --git a/emacs/test/test-indent.el b/emacs/test/test-indent.el new file mode 100644 index 0000000..ad4ec91 --- /dev/null +++ b/emacs/test/test-indent.el @@ -0,0 +1,58 @@ +;; -*- emacs-lisp -*- +;; This program has to be run from the directory it is currently in and +;; the rdebug code has to be in the parent directory +(load-file "./elk-test.el") + +;; ------------------------------------------------------------------- +;; Check source code indentation +;; + +(put 'rdebug-debug-enter 'lisp-indent-hook 1) + +(defun rdebug-test-reindent-one-file (file) + (let ((buf (generate-new-buffer "testing")) + (res nil)) + (save-excursion + (switch-to-buffer buf) + (insert-file file) + (emacs-lisp-mode) + (set-buffer-modified-p nil) + (undo-boundary) + (indent-region (point-min) (point-max)) + (if (buffer-modified-p) + (setq res "Reindentation failed"))) + (kill-buffer buf) + res)) + +(deftest "rdebug-indent-files" + (mapcar (lambda (lisp-file) + (message lisp-file) + (assert-nil (rdebug-test-reindent-one-file lisp-file))) + '("../rdebug.el" + "../rdebug-breaks.el" + "../rdebug-cmd.el" + "../rdebug-core.el" + "../rdebug-dbg.el" + "../rdebug-error.el" + "../rdebug-frames.el" + "../rdebug-fns.el" + "../rdebug-gud.el" + "../rdebug-help.el" + "../rdebug-info.el" + "../rdebug-layouts.el" + "../rdebug-output.el" + "../rdebug-regexp.el" + "../rdebug-secondary.el" + "../rdebug-source.el" + "../rdebug-track.el" + "../rdebug-varbuf.el" + "../rdebug-vars.el" + "../rdebug-watch.el" + "./test-cmd.el" + "./test-core.el" + "./test-indent.el" + "./test-regexp.el" + ))) + +(run-elk-test "rdebug-indent-files" + "test indentation of Lisp files") diff --git a/emacs/test/test-regexp.el b/emacs/test/test-regexp.el new file mode 100644 index 0000000..790971e --- /dev/null +++ b/emacs/test/test-regexp.el @@ -0,0 +1,144 @@ +;; -*- emacs-lisp -*- +;; This program has to be run from the directory it is currently in and +;; the rdebug code has to be in the parent directory +(load-file "./elk-test.el") + +;; FIXME? Should we use "require 'rdebug" here. +;; Would have to prepend . to load-path. +(load-file "../rdebug.el") +(load-file "../rdebug-core.el") + +(make-variable-buffer-local 'gud-rdebug-marker-acc) + +(defun regexp-breakpoint-test (location-str pos-str enabled-str file-str line-str) + "Test to see that location-str parses rdebug-breakpoint-regexp properly" + (assert-equal 0 (string-match rdebug-breakpoint-regexp location-str)) + (assert-equal pos-str + (substring location-str (match-beginning 1) (match-end 1))) + (assert-equal enabled-str + (substring location-str (match-beginning 2) (match-end 2))) + (assert-equal file-str + (substring location-str (match-beginning 3) (match-end 3))) + (assert-equal line-str + (substring location-str (match-beginning 4) (match-end 4))) + ) +(deftest "rdebug-regexp-breakpoint-test" + + (regexp-breakpoint-test + " 1 y at gcd.rb:6" + "1" "y" "gcd.rb" "6" + ) + (regexp-breakpoint-test + " 1 y at gcd.rb:6 if 1 == a" + "1" "y" "gcd.rb" "6" + ) + ) + +(defun regexp-file-test (location-str file-str) + "Test to see that location-str matches gud-rdebug-marker-regexp" + (assert-equal 0 (string-match gud-rdebug-marker-regexp location-str)) + (assert-equal file-str + (substring location-str (match-beginning 1) (match-end 1))) + ) +(deftest "rdebug-regexp-file-test" + + (regexp-file-test + "\032\032./hanoi.rb:3\n" + "./hanoi.rb" + ) + (regexp-file-test + "\032\032source ./hanoi.rb:3\n" + "./hanoi.rb" + ) + (regexp-file-test + "\032\032C:/tmp/gcd.rb:29\n" + "C:/tmp/gcd.rb" + ) + (regexp-file-test + "\032\032source \\sources\\capfilterscanner\\capanalyzer.rb:3: \n" + "\\sources\\capfilterscanner\\capanalyzer.rb" + ) + ) + +(deftest "rdebug-regexp-marker-filter-test" + (assert-equal "Testing 1 2 3" (gud-rdebug-marker-filter "Testing 1 2 3")) + (assert-equal "ABC" (gud-rdebug-marker-filter + "\ +breakpoints +No breakpoints + +ABC"))) + +(defun regexp-stack-test (location-str pos-str file-str line-str) + "Test to see that location-str parses rdebug-stack-frame-regexp properly" + (assert-equal 0 (string-match rdebug-stack-frame-regexp location-str)) + (assert-equal pos-str + (substring location-str (match-beginning 2) (match-end 2))) + (assert-equal file-str + (substring location-str (match-beginning 4) (match-end 4))) + (assert-equal line-str + (substring location-str (match-beginning 5) (match-end 5))) + ) +(deftest "rdebug-regexp-stack-test" + + (regexp-stack-test + "--> #0 at line /home/rocky/ruby/gcd.rb:18" + "0" "/home/rocky/ruby/gcd.rb" "18" + ) + ) + +(defun regexp-traceback-test (location-str file-str line-str) + "Test to see that location-str matches position-regexp-file-test with the correct +file and line submatches." + (assert-equal 0 (string-match rdebug-traceback-line-re location-str)) + (assert-equal file-str (match-string 1 location-str)) + (assert-equal line-str (match-string 2 location-str)) + ) + +(deftest "rdebug-regexp-traceback-test" + + (regexp-traceback-test + " from /home/rocky/ruby/gcd.rb:15:in `gcd'" + "/home/rocky/ruby/gcd.rb" "15" + ) + (regexp-traceback-test + " from /home/rocky/ruby/gcd.rb:19" + "/home/rocky/ruby/gcd.rb" "19" + ) + ) + +(defun regexp-unittest-traceback-test (location-str file-str line-str) + "Test to see that location-str matches position-regexp-file-test with the correct +file and line submatches." + (assert-equal 0 (string-match rdebug-dollarbang-traceback-line-re + location-str)) + (assert-equal file-str (match-string 1 location-str)) + (assert-equal line-str (match-string 2 location-str)) + ) + +(deftest "rdebug-regexp-unittest-traceback-test" + + (regexp-unittest-traceback-test + " [test-frame.rb:26:in `test_basic'" + "test-frame.rb" "26" + ) + (regexp-unittest-traceback-test + " test-frame.rb:22:in `test_basic']:" + "test-frame.rb" "22" + ) + ) + +;; ------------------------------------------------------------------- +;; Build and run the test suite. +;; + +(build-suite "rdebug-suite" + "rdebug-regexp-breakpoint-test" + "rdebug-regexp-file-test" + "rdebug-regexp-marker-filter-test" + "rdebug-regexp-stack-test" + "rdebug-regexp-traceback-test" + "rdebug-regexp-unittest-traceback-test") + +(run-elk-test "rdebug-suite" + "test regular expressions used in tracking lines") diff --git a/emacs/test/test-shortkey.el b/emacs/test/test-shortkey.el new file mode 100644 index 0000000..3318c40 --- /dev/null +++ b/emacs/test/test-shortkey.el @@ -0,0 +1,61 @@ +;; -*- emacs-lisp -*- +;; This program has to be run from the directory it is currently in and +;; the rdebug code has to be in the parent directory +(load-file "./elk-test.el") + +;; FIXME? Should we use "require 'rdebug" here. +;; Would have to prepend . to load-path. +(setq load-path (cons ".." load-path)) +(load-file "../rdebug-shortkey.el") + +(deftest "rdebug-shortkey-mode-test" + (let ((buf (generate-new-buffer "shortkey readwrite"))) + (with-current-buffer buf + (setq buffer-read-only nil) + ;; turning on short-key-mode make buffer read-only + (rdebug-internal-short-key-mode 1) + (assert-equal t buffer-read-only) + + ;; turning off short-key-mode should make buffer read-write again + (rdebug-internal-short-key-mode -1) + (assert-equal nil buffer-read-only) + + ;; -------------------- + ;; Check multiple "on": and "off:s". + + (rdebug-internal-short-key-mode 1) + (assert-equal t buffer-read-only) + + (rdebug-internal-short-key-mode 1) + (assert-equal t buffer-read-only) + + (rdebug-internal-short-key-mode 1) + (assert-equal t buffer-read-only) + + (rdebug-internal-short-key-mode -1) + (assert-equal nil buffer-read-only)) + + (kill-buffer buf)) + + (let ((buf (generate-new-buffer "shortkey readonly"))) + (with-current-buffer buf + (setq buffer-read-only t) + + ;; turning on short-key-mode keep buffer read-only + (rdebug-internal-short-key-mode 1) + (assert-equal t buffer-read-only) + + ;; The buffer was originally in read-only mode, it should remain + ;; there. + (rdebug-internal-short-key-mode -1) + (assert-equal t buffer-read-only)) + (kill-buffer buf))) + +;; ------------------------------------------------------------------- +;; Build and run the test suite. +;; + +(build-suite "rdebug-suite" + "rdebug-shortkey-mode-test") +(run-elk-test "rdebug-suite" + "test things in rdebug-shortkey.el") diff --git a/ext/.svn/README.txt b/ext/.svn/README.txt new file mode 100644 index 0000000..271a8ce --- /dev/null +++ b/ext/.svn/README.txt @@ -0,0 +1,2 @@ +This is a Subversion working copy administrative directory. +Visit http://subversion.tigris.org/ for more information. diff --git a/ext/.svn/dir-prop-base b/ext/.svn/dir-prop-base new file mode 100644 index 0000000..58d2b2e --- /dev/null +++ b/ext/.svn/dir-prop-base @@ -0,0 +1,8 @@ +K 10 +svn:ignore +V 34 +.cvsignore +ruby_debug.so +Makefile + +END diff --git a/ext/.svn/dir-props b/ext/.svn/dir-props new file mode 100644 index 0000000..58d2b2e --- /dev/null +++ b/ext/.svn/dir-props @@ -0,0 +1,8 @@ +K 10 +svn:ignore +V 34 +.cvsignore +ruby_debug.so +Makefile + +END diff --git a/ext/.svn/empty-file b/ext/.svn/empty-file new file mode 100644 index 0000000..e69de29 diff --git a/ext/.svn/entries b/ext/.svn/entries new file mode 100644 index 0000000..f163ea7 --- /dev/null +++ b/ext/.svn/entries @@ -0,0 +1,53 @@ + + + + + + + + + diff --git a/ext/.svn/format b/ext/.svn/format new file mode 100644 index 0000000..b8626c4 --- /dev/null +++ b/ext/.svn/format @@ -0,0 +1 @@ +4 diff --git a/ext/.svn/prop-base/breakpoint.c.svn-base b/ext/.svn/prop-base/breakpoint.c.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/ext/.svn/prop-base/breakpoint.c.svn-base @@ -0,0 +1 @@ +END diff --git a/ext/.svn/prop-base/extconf.rb.svn-base b/ext/.svn/prop-base/extconf.rb.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/ext/.svn/prop-base/extconf.rb.svn-base @@ -0,0 +1 @@ +END diff --git a/ext/.svn/prop-base/ruby_debug.c.svn-base b/ext/.svn/prop-base/ruby_debug.c.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/ext/.svn/prop-base/ruby_debug.c.svn-base @@ -0,0 +1 @@ +END diff --git a/ext/.svn/prop-base/ruby_debug.h.svn-base b/ext/.svn/prop-base/ruby_debug.h.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/ext/.svn/prop-base/ruby_debug.h.svn-base @@ -0,0 +1 @@ +END diff --git a/ext/.svn/props/breakpoint.c.svn-work b/ext/.svn/props/breakpoint.c.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/ext/.svn/props/breakpoint.c.svn-work @@ -0,0 +1 @@ +END diff --git a/ext/.svn/props/extconf.rb.svn-work b/ext/.svn/props/extconf.rb.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/ext/.svn/props/extconf.rb.svn-work @@ -0,0 +1 @@ +END diff --git a/ext/.svn/props/ruby_debug.c.svn-work b/ext/.svn/props/ruby_debug.c.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/ext/.svn/props/ruby_debug.c.svn-work @@ -0,0 +1 @@ +END diff --git a/ext/.svn/props/ruby_debug.h.svn-work b/ext/.svn/props/ruby_debug.h.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/ext/.svn/props/ruby_debug.h.svn-work @@ -0,0 +1 @@ +END diff --git a/ext/.svn/text-base/breakpoint.c.svn-base b/ext/.svn/text-base/breakpoint.c.svn-base new file mode 100644 index 0000000..d3b7b78 --- /dev/null +++ b/ext/.svn/text-base/breakpoint.c.svn-base @@ -0,0 +1,579 @@ +#include "ruby_debug.h" + +VALUE rdebug_breakpoints = Qnil; +VALUE rdebug_catchpoints; + +static VALUE cBreakpoint; +static ID idEval; + +static VALUE +eval_expression(VALUE args) +{ + return rb_funcall2(rb_mKernel, idEval, 2, RARRAY(args)->ptr); +} + +int +check_breakpoint_hit_condition(VALUE breakpoint) +{ + debug_breakpoint_t *debug_breakpoint; + + if(breakpoint == Qnil) + return 0; + Data_Get_Struct(breakpoint, debug_breakpoint_t, debug_breakpoint); + + debug_breakpoint->hit_count++; + if (!Qtrue == debug_breakpoint->enabled) return 0; + switch(debug_breakpoint->hit_condition) + { + case HIT_COND_NONE: + return 1; + case HIT_COND_GE: + { + if(debug_breakpoint->hit_count >= debug_breakpoint->hit_value) + return 1; + break; + } + case HIT_COND_EQ: + { + if(debug_breakpoint->hit_count == debug_breakpoint->hit_value) + return 1; + break; + } + case HIT_COND_MOD: + { + if(debug_breakpoint->hit_count % debug_breakpoint->hit_value == 0) + return 1; + break; + } + } + return 0; +} + +static int +check_breakpoint_by_pos(VALUE breakpoint, char *file, int line) +{ + debug_breakpoint_t *debug_breakpoint; + + if(breakpoint == Qnil) + return 0; + Data_Get_Struct(breakpoint, debug_breakpoint_t, debug_breakpoint); + if (!Qtrue == debug_breakpoint->enabled) return 0; + if(debug_breakpoint->type != BP_POS_TYPE) + return 0; + if(debug_breakpoint->pos.line != line) + return 0; + if(filename_cmp(debug_breakpoint->source, file)) + return 1; + return 0; +} + +int +check_breakpoint_by_method(VALUE breakpoint, VALUE klass, ID mid) +{ + debug_breakpoint_t *debug_breakpoint; + + if(breakpoint == Qnil) + return 0; + Data_Get_Struct(breakpoint, debug_breakpoint_t, debug_breakpoint); + if (!Qtrue == debug_breakpoint->enabled) return 0; + if(debug_breakpoint->type != BP_METHOD_TYPE) + return 0; + if(debug_breakpoint->pos.mid != mid) + return 0; + if(classname_cmp(debug_breakpoint->source, klass)) + return 1; + return 0; +} + +VALUE +check_breakpoints_by_pos(debug_context_t *debug_context, char *file, int line) +{ + VALUE breakpoint; + int i; + + if(!CTX_FL_TEST(debug_context, CTX_FL_ENABLE_BKPT)) + return Qnil; + + if(check_breakpoint_by_pos(debug_context->breakpoint, file, line)) + return debug_context->breakpoint; + + if(RARRAY(rdebug_breakpoints)->len == 0) + return Qnil; + for(i = 0; i < RARRAY(rdebug_breakpoints)->len; i++) + { + breakpoint = rb_ary_entry(rdebug_breakpoints, i); + if(check_breakpoint_by_pos(breakpoint, file, line)) + return breakpoint; + } + return Qnil; +} + +VALUE +check_breakpoints_by_method(debug_context_t *debug_context, VALUE klass, ID mid) +{ + VALUE breakpoint; + int i; + + if(!CTX_FL_TEST(debug_context, CTX_FL_ENABLE_BKPT)) + return Qnil; + + if(check_breakpoint_by_method(debug_context->breakpoint, klass, mid)) + return debug_context->breakpoint; + + if(RARRAY(rdebug_breakpoints)->len == 0) + return Qnil; + for(i = 0; i < RARRAY(rdebug_breakpoints)->len; i++) + { + breakpoint = rb_ary_entry(rdebug_breakpoints, i); + if(check_breakpoint_by_method(breakpoint, klass, mid)) + return breakpoint; + } + return Qnil; +} + +int +check_breakpoint_expression(VALUE breakpoint, VALUE binding) +{ + debug_breakpoint_t *debug_breakpoint; + VALUE args, expr_result; + + Data_Get_Struct(breakpoint, debug_breakpoint_t, debug_breakpoint); + if(NIL_P(debug_breakpoint->expr)) + return 1; + + args = rb_ary_new3(2, debug_breakpoint->expr, binding); + expr_result = rb_protect(eval_expression, args, 0); + return RTEST(expr_result); +} + +static void +breakpoint_mark(void *data) +{ + debug_breakpoint_t *breakpoint; + breakpoint = (debug_breakpoint_t *)data; + rb_gc_mark(breakpoint->source); + rb_gc_mark(breakpoint->expr); +} + +VALUE +create_breakpoint_from_args(int argc, VALUE *argv, int id) +{ + VALUE source, pos, expr; + debug_breakpoint_t *breakpoint; + int type; + + if(rb_scan_args(argc, argv, "21", &source, &pos, &expr) == 2) + { + expr = Qnil; + } + type = FIXNUM_P(pos) ? BP_POS_TYPE : BP_METHOD_TYPE; + if(type == BP_POS_TYPE) + source = StringValue(source); + else + pos = StringValue(pos); + breakpoint = ALLOC(debug_breakpoint_t); + breakpoint->id = id; + breakpoint->source = source; + breakpoint->type = type; + if(type == BP_POS_TYPE) + breakpoint->pos.line = FIX2INT(pos); + else + breakpoint->pos.mid = rb_intern(RSTRING(pos)->ptr); + breakpoint->enabled = Qtrue; + breakpoint->expr = NIL_P(expr) ? expr: StringValue(expr); + breakpoint->hit_count = 0; + breakpoint->hit_value = 0; + breakpoint->hit_condition = HIT_COND_NONE; + return Data_Wrap_Struct(cBreakpoint, breakpoint_mark, xfree, breakpoint); +} + +/* + * call-seq: + * Debugger.remove_breakpoint(id) -> breakpoint + * + * Removes breakpoint by its id. + * id is an identificator of a breakpoint. + */ +VALUE +rdebug_remove_breakpoint(VALUE self, VALUE id_value) +{ + int i; + int id; + VALUE breakpoint; + debug_breakpoint_t *debug_breakpoint; + + id = FIX2INT(id_value); + + for( i = 0; i < RARRAY(rdebug_breakpoints)->len; i += 1 ) + { + breakpoint = rb_ary_entry(rdebug_breakpoints, i); + Data_Get_Struct(breakpoint, debug_breakpoint_t, debug_breakpoint); + if(debug_breakpoint->id == id) + { + rb_ary_delete_at(rdebug_breakpoints, i); + return breakpoint; + } + } + return Qnil; +} + +/* + * call-seq: + * Debugger.catchpoints -> hash + * + * Returns a current catchpoints, which is a hash exception names that will + * trigger a debugger when raised. The values are the number of times taht + * catchpoint was hit, initially 0. + */ +VALUE +debug_catchpoints(VALUE self) +{ + debug_check_started(); + + return rdebug_catchpoints; +} + +/* + * call-seq: + * Debugger.catchpoint(string) -> string + * + * Sets catchpoint. Returns the string passed. + */ +VALUE +rdebug_add_catchpoint(VALUE self, VALUE value) +{ + debug_check_started(); + + if (TYPE(value) != T_STRING) { + rb_raise(rb_eTypeError, "value of a catchpoint must be String"); + } + rb_hash_aset(rdebug_catchpoints, rb_str_dup(value), INT2FIX(0)); + return value; +} + +/* + * call-seq: + * context.breakpoint -> breakpoint + * + * Returns a context-specific temporary Breakpoint object. + */ +VALUE +context_breakpoint(VALUE self) +{ + debug_context_t *debug_context; + + debug_check_started(); + + Data_Get_Struct(self, debug_context_t, debug_context); + return debug_context->breakpoint; +} + +/* + * call-seq: + * context.set_breakpoint(source, pos, condition = nil) -> breakpoint + * + * Sets a context-specific temporary breakpoint, which can be used to implement + * 'Run to Cursor' debugger function. When this breakpoint is reached, it will be + * cleared out. + * + * source is a name of a file or a class. + * pos is a line number or a method name if source is a class name. + * condition is a string which is evaluated to +true+ when this breakpoint + * is activated. + */ +VALUE +context_set_breakpoint(int argc, VALUE *argv, VALUE self) +{ + VALUE result; + debug_context_t *debug_context; + + debug_check_started(); + + Data_Get_Struct(self, debug_context_t, debug_context); + result = create_breakpoint_from_args(argc, argv, 0); + debug_context->breakpoint = result; + return result; +} + +/* + * call-seq: + * breakpoint.enabled? + * + * Returns whether breakpoint is enabled or not. + */ +static VALUE +breakpoint_enabled(VALUE self) +{ + debug_breakpoint_t *breakpoint; + + Data_Get_Struct(self, debug_breakpoint_t, breakpoint); + return breakpoint->enabled; +} + +/* + * call-seq: + * breakpoint.enabled = bool + * + * Enables or disables breakpoint. + */ +static VALUE +breakpoint_set_enabled(VALUE self, VALUE bool) +{ + debug_breakpoint_t *breakpoint; + + Data_Get_Struct(self, debug_breakpoint_t, breakpoint); + return breakpoint->enabled = bool; +} + +/* + * call-seq: + * breakpoint.source -> string + * + * Returns a source of the breakpoint. + */ +static VALUE +breakpoint_source(VALUE self) +{ + debug_breakpoint_t *breakpoint; + + Data_Get_Struct(self, debug_breakpoint_t, breakpoint); + return breakpoint->source; +} + +/* + * call-seq: + * breakpoint.source = string + * + * Sets the source of the breakpoint. + */ +static VALUE +breakpoint_set_source(VALUE self, VALUE value) +{ + debug_breakpoint_t *breakpoint; + + Data_Get_Struct(self, debug_breakpoint_t, breakpoint); + breakpoint->source = StringValue(value); + return value; +} + +/* + * call-seq: + * breakpoint.pos -> string or int + * + * Returns the position of this breakpoint. + */ +static VALUE +breakpoint_pos(VALUE self) +{ + debug_breakpoint_t *breakpoint; + + Data_Get_Struct(self, debug_breakpoint_t, breakpoint); + if(breakpoint->type == BP_METHOD_TYPE) + return rb_str_new2(rb_id2name(breakpoint->pos.mid)); + else + return INT2FIX(breakpoint->pos.line); +} + +/* + * call-seq: + * breakpoint.pos = string or int + * + * Sets the position of this breakpoint. + */ +static VALUE +breakpoint_set_pos(VALUE self, VALUE value) +{ + debug_breakpoint_t *breakpoint; + + Data_Get_Struct(self, debug_breakpoint_t, breakpoint); + if(breakpoint->type == BP_METHOD_TYPE) + { + breakpoint->pos.mid = rb_to_id(StringValue(value)); + } + else + breakpoint->pos.line = FIX2INT(value); + return value; +} + +/* + * call-seq: + * breakpoint.expr -> string + * + * Returns a codition expression when this breakpoint should be activated. + */ +static VALUE +breakpoint_expr(VALUE self) +{ + debug_breakpoint_t *breakpoint; + + Data_Get_Struct(self, debug_breakpoint_t, breakpoint); + return breakpoint->expr; +} + +/* + * call-seq: + * breakpoint.expr = string | nil + * + * Sets the codition expression when this breakpoint should be activated. + */ +static VALUE +breakpoint_set_expr(VALUE self, VALUE expr) +{ + debug_breakpoint_t *breakpoint; + + Data_Get_Struct(self, debug_breakpoint_t, breakpoint); + breakpoint->expr = NIL_P(expr) ? expr: StringValue(expr); + return expr; +} + +/* + * call-seq: + * breakpoint.id -> int + * + * Returns id of the breakpoint. + */ +static VALUE +breakpoint_id(VALUE self) +{ + debug_breakpoint_t *breakpoint; + + Data_Get_Struct(self, debug_breakpoint_t, breakpoint); + return INT2FIX(breakpoint->id); +} + +/* + * call-seq: + * breakpoint.hit_count -> int + * + * Returns the hit count of the breakpoint. + */ +static VALUE +breakpoint_hit_count(VALUE self) +{ + debug_breakpoint_t *breakpoint; + + Data_Get_Struct(self, debug_breakpoint_t, breakpoint); + return INT2FIX(breakpoint->hit_count); +} + +/* + * call-seq: + * breakpoint.hit_value -> int + * + * Returns the hit value of the breakpoint. + */ +static VALUE +breakpoint_hit_value(VALUE self) +{ + debug_breakpoint_t *breakpoint; + + Data_Get_Struct(self, debug_breakpoint_t, breakpoint); + return INT2FIX(breakpoint->hit_value); +} + +/* + * call-seq: + * breakpoint.hit_value = int + * + * Sets the hit value of the breakpoint. + */ +static VALUE +breakpoint_set_hit_value(VALUE self, VALUE value) +{ + debug_breakpoint_t *breakpoint; + + Data_Get_Struct(self, debug_breakpoint_t, breakpoint); + breakpoint->hit_value = FIX2INT(value); + return value; +} + +/* + * call-seq: + * breakpoint.hit_condition -> symbol + * + * Returns the hit condition of the breakpoint: + * + * +nil+ if it is an unconditional breakpoint, or + * :greater_or_equal, :equal, :modulo + */ +static VALUE +breakpoint_hit_condition(VALUE self) +{ + debug_breakpoint_t *breakpoint; + + Data_Get_Struct(self, debug_breakpoint_t, breakpoint); + switch(breakpoint->hit_condition) + { + case HIT_COND_GE: + return ID2SYM(rb_intern("greater_or_equal")); + case HIT_COND_EQ: + return ID2SYM(rb_intern("equal")); + case HIT_COND_MOD: + return ID2SYM(rb_intern("modulo")); + case HIT_COND_NONE: + default: + return Qnil; + } +} + +/* + * call-seq: + * breakpoint.hit_condition = symbol + * + * Sets the hit condition of the breakpoint which must be one of the following values: + * + * +nil+ if it is an unconditional breakpoint, or + * :greater_or_equal(:ge), :equal(:eq), :modulo(:mod) + */ +static VALUE +breakpoint_set_hit_condition(VALUE self, VALUE value) +{ + debug_breakpoint_t *breakpoint; + ID id_value; + + Data_Get_Struct(self, debug_breakpoint_t, breakpoint); + id_value = rb_to_id(value); + + if(rb_intern("greater_or_equal") == id_value || rb_intern("ge") == id_value) + breakpoint->hit_condition = HIT_COND_GE; + else if(rb_intern("equal") == id_value || rb_intern("eq") == id_value) + breakpoint->hit_condition = HIT_COND_EQ; + else if(rb_intern("modulo") == id_value || rb_intern("mod") == id_value) + breakpoint->hit_condition = HIT_COND_MOD; + else + rb_raise(rb_eArgError, "Invalid condition parameter"); + return value; +} + +/* + * Document-class: Breakpoint + * + * == Summary + * + * This class represents a breakpoint. It defines position of the breakpoint and + * condition when this breakpoint should be triggered. + */ +void +Init_breakpoint() +{ + cBreakpoint = rb_define_class_under(mDebugger, "Breakpoint", rb_cObject); + rb_define_method(cBreakpoint, "enabled=", breakpoint_set_enabled, 1); + rb_define_method(cBreakpoint, "enabled?", breakpoint_enabled, 0); + rb_define_method(cBreakpoint, "expr", breakpoint_expr, 0); + rb_define_method(cBreakpoint, "expr=", breakpoint_set_expr, 1); + rb_define_method(cBreakpoint, "hit_condition", breakpoint_hit_condition, 0); + rb_define_method(cBreakpoint, "hit_condition=", breakpoint_set_hit_condition, 1); + rb_define_method(cBreakpoint, "hit_count", breakpoint_hit_count, 0); + rb_define_method(cBreakpoint, "hit_value", breakpoint_hit_value, 0); + rb_define_method(cBreakpoint, "hit_value=", breakpoint_set_hit_value, 1); + rb_define_method(cBreakpoint, "id", breakpoint_id, 0); + rb_define_method(cBreakpoint, "pos", breakpoint_pos, 0); + rb_define_method(cBreakpoint, "pos=", breakpoint_set_pos, 1); + rb_define_method(cBreakpoint, "source", breakpoint_source, 0); + rb_define_method(cBreakpoint, "source=", breakpoint_set_source, 1); + idEval = rb_intern("eval"); + rdebug_catchpoints = rb_hash_new(); + +} + + diff --git a/ext/.svn/text-base/extconf.rb.svn-base b/ext/.svn/text-base/extconf.rb.svn-base new file mode 100644 index 0000000..1bb8e40 --- /dev/null +++ b/ext/.svn/text-base/extconf.rb.svn-base @@ -0,0 +1,20 @@ +require "mkmf" + +if RUBY_VERSION >= "1.9" + if RUBY_RELEASE_DATE < "2005-03-17" + STDERR.print("Ruby version is too old\n") + exit(1) + end +elsif RUBY_VERSION >= "1.8" + if RUBY_RELEASE_DATE < "2005-03-22" + STDERR.print("Ruby version is too old\n") + exit(1) + end +else + STDERR.print("Ruby version is too old\n") + exit(1) +end + +# Temporary: to turn off optimization +# $CFLAGS='-fno-strict-aliasing -g -fPIC' +create_makefile("ruby_debug") diff --git a/ext/.svn/text-base/ruby_debug.c.svn-base b/ext/.svn/text-base/ruby_debug.c.svn-base new file mode 100644 index 0000000..503329a --- /dev/null +++ b/ext/.svn/text-base/ruby_debug.c.svn-base @@ -0,0 +1,2322 @@ +#include "ruby_debug.h" + +#include +#include +#include +#include +#include + +#define DEBUG_VERSION "0.10.4" + + +#ifdef _WIN32 +struct FRAME { + VALUE self; + int argc; + ID last_func; + ID orig_func; + VALUE last_class; + struct FRAME *prev; + struct FRAME *tmp; + struct RNode *node; + int iter; + int flags; + unsigned long uniq; +}; + +struct SCOPE { + struct RBasic super; + ID *local_tbl; + VALUE *local_vars; + int flags; +}; + +struct RVarmap { + struct RBasic super; + ID id; + VALUE val; + struct RVarmap *next; +}; + +RUBY_EXTERN struct SCOPE *ruby_scope; +RUBY_EXTERN struct FRAME *ruby_frame; +RUBY_EXTERN struct RVarmap *ruby_dyna_vars; +#else +#include +#endif + +#define FRAME_N(n) (&debug_context->frames[debug_context->stack_size-(n)-1]) +#define GET_FRAME (FRAME_N(check_frame_number(debug_context, frame))) + +#ifndef min +#define min(x,y) ((x) < (y) ? (x) : (y)) +#endif + +#define STACK_SIZE_INCREMENT 128 + +typedef struct { + st_table *tbl; +} threads_table_t; + +static VALUE tracing = Qfalse; +static VALUE locker = Qnil; +static VALUE post_mortem = Qfalse; +static VALUE keep_frame_binding = Qfalse; +static VALUE debug = Qfalse; +static VALUE track_frame_args = Qfalse; + +static VALUE last_context = Qnil; +static VALUE last_thread = Qnil; +static debug_context_t *last_debug_context = NULL; + +VALUE rdebug_threads_tbl = Qnil; /* Context for each of the threads */ +VALUE mDebugger; /* Ruby Debugger Module object */ + +static VALUE cThreadsTable; +static VALUE cContext; +static VALUE cDebugThread; + +static VALUE rb_mObjectSpace; + +static ID idAtBreakpoint; +static ID idAtCatchpoint; +static ID idAtLine; +static ID idAtReturn; +static ID idAtTracing; +static ID idList; + +static int start_count = 0; +static int thnum_max = 0; +static int bkp_count = 0; +static int last_debugged_thnum = -1; +static unsigned long last_check = 0; +static unsigned long hook_count = 0; + +static VALUE create_binding(VALUE); +static VALUE debug_stop(VALUE); +static void save_current_position(debug_context_t *); +static VALUE context_copy_args(debug_frame_t *); +static VALUE context_copy_locals(debug_frame_t *); +static void context_suspend_0(debug_context_t *); +static void context_resume_0(debug_context_t *); +static void copy_scalar_args(debug_frame_t *); + +typedef struct locked_thread_t { + VALUE thread_id; + struct locked_thread_t *next; +} locked_thread_t; + +static locked_thread_t *locked_head = NULL; +static locked_thread_t *locked_tail = NULL; + +/* "Step", "Next" and "Finish" do their work by saving information + about where to stop next. reset_stopping_points removes/resets this + information. */ +inline static void +reset_stepping_stop_points(debug_context_t *debug_context) +{ + debug_context->dest_frame = -1; + debug_context->stop_line = -1; + debug_context->stop_next = -1; +} + +inline static VALUE +real_class(VALUE klass) +{ + if (klass) { + if (TYPE(klass) == T_ICLASS) { + return RBASIC(klass)->klass; + } + else if (FL_TEST(klass, FL_SINGLETON)) { + return rb_iv_get(klass, "__attached__"); + } + } + return klass; +} + +inline static void * +ruby_method_ptr(VALUE class, ID meth_id) +{ + NODE *body, *method; + st_lookup(RCLASS(class)->m_tbl, meth_id, (st_data_t *)&body); + method = (NODE *)body->u2.value; + return (void *)method->u1.value; +} + +inline static VALUE +ref2id(VALUE obj) +{ + return rb_obj_id(obj); +} + +static VALUE +id2ref_unprotected(VALUE id) +{ + typedef VALUE (*id2ref_func_t)(VALUE, VALUE); + static id2ref_func_t f_id2ref = NULL; + if(f_id2ref == NULL) + { + f_id2ref = (id2ref_func_t)ruby_method_ptr(rb_mObjectSpace, rb_intern("_id2ref")); + } + return f_id2ref(rb_mObjectSpace, id); +} + +static VALUE +id2ref_error() +{ + if(debug == Qtrue) + rb_p(ruby_errinfo); + return Qnil; +} + +static VALUE +id2ref(VALUE id) +{ + return rb_rescue(id2ref_unprotected, id, id2ref_error, 0); +} + +inline static VALUE +context_thread_0(debug_context_t *debug_context) +{ + return id2ref(debug_context->thread_id); +} + +static int +is_in_locked(VALUE thread_id) +{ + locked_thread_t *node; + + if(!locked_head) + return 0; + + for(node = locked_head; node != locked_tail; node = node->next) + { + if(node->thread_id == thread_id) return 1; + } + return 0; +} + +static void +add_to_locked(VALUE thread) +{ + locked_thread_t *node; + VALUE thread_id = ref2id(thread); + + if(is_in_locked(thread_id)) + return; + + node = ALLOC(locked_thread_t); + node->thread_id = thread_id; + node->next = NULL; + if(locked_tail) + locked_tail->next = node; + locked_tail = node; + if(!locked_head) + locked_head = node; +} + +static VALUE +remove_from_locked() +{ + VALUE thread; + locked_thread_t *node; + + if(locked_head == NULL) + return Qnil; + node = locked_head; + locked_head = locked_head->next; + if(locked_tail == node) + locked_tail = NULL; + thread = id2ref(node->thread_id); + xfree(node); + return thread; +} + +static int +threads_table_mark_keyvalue(VALUE key, VALUE value, int dummy) +{ + rb_gc_mark(value); + return ST_CONTINUE; +} + +static void +threads_table_mark(void* data) +{ + threads_table_t *threads_table = (threads_table_t*)data; + st_foreach(threads_table->tbl, threads_table_mark_keyvalue, 0); +} + +static void +threads_table_free(void* data) +{ + threads_table_t *threads_table = (threads_table_t*)data; + st_free_table(threads_table->tbl); + xfree(threads_table); +} + +static VALUE +threads_table_create() +{ + threads_table_t *threads_table; + + threads_table = ALLOC(threads_table_t); + threads_table->tbl = st_init_numtable(); + return Data_Wrap_Struct(cThreadsTable, threads_table_mark, threads_table_free, threads_table); +} + +static int +threads_table_clear_i(VALUE key, VALUE value, VALUE dummy) +{ + return ST_DELETE; +} + +static void +threads_table_clear(VALUE table) +{ + threads_table_t *threads_table; + + Data_Get_Struct(table, threads_table_t, threads_table); + st_foreach(threads_table->tbl, threads_table_clear_i, 0); +} + +static VALUE +is_thread_alive(VALUE thread) +{ + typedef VALUE (*thread_alive_func_t)(VALUE); + static thread_alive_func_t f_thread_alive = NULL; + if(!f_thread_alive) + { + f_thread_alive = (thread_alive_func_t)ruby_method_ptr(rb_cThread, rb_intern("alive?")); + } + return f_thread_alive(thread); +} + +static int +threads_table_check_i(VALUE key, VALUE value, VALUE dummy) +{ + VALUE thread; + + thread = id2ref(key); + if(!rb_obj_is_kind_of(thread, rb_cThread)) + { + return ST_DELETE; + } + if(rb_protect(is_thread_alive, thread, 0) != Qtrue) + { + return ST_DELETE; + } + return ST_CONTINUE; +} + +static void +check_thread_contexts() +{ + threads_table_t *threads_table; + + Data_Get_Struct(rdebug_threads_tbl, threads_table_t, threads_table); + st_foreach(threads_table->tbl, threads_table_check_i, 0); +} + +/* + * call-seq: + * Debugger.started? -> bool + * + * Returns +true+ the debugger is started. + */ +static VALUE +debug_is_started(VALUE self) +{ + return IS_STARTED ? Qtrue : Qfalse; +} + +static void +debug_context_mark(void *data) +{ + debug_frame_t *frame; + int i; + + debug_context_t *debug_context = (debug_context_t *)data; + for(i = 0; i < debug_context->stack_size; i++) + { + frame = &(debug_context->frames[i]); + rb_gc_mark(frame->binding); + rb_gc_mark(frame->self); + rb_gc_mark(frame->arg_ary); + if(frame->dead) + { + rb_gc_mark(frame->info.copy.locals); + rb_gc_mark(frame->info.copy.args); + } + } + rb_gc_mark(debug_context->breakpoint); +} + +static void +debug_context_free(void *data) +{ + debug_context_t *debug_context = (debug_context_t *)data; + xfree(debug_context->frames); +} + +static VALUE +debug_context_create(VALUE thread) +{ + debug_context_t *debug_context; + + debug_context = ALLOC(debug_context_t); + debug_context-> thnum = ++thnum_max; + + debug_context->last_file = NULL; + debug_context->last_line = 0; + debug_context->flags = 0; + + debug_context->stop_next = -1; + debug_context->dest_frame = -1; + debug_context->stop_line = -1; + debug_context->stop_frame = -1; + debug_context->stop_reason = CTX_STOP_NONE; + debug_context->stack_len = STACK_SIZE_INCREMENT; + debug_context->frames = ALLOC_N(debug_frame_t, STACK_SIZE_INCREMENT); + debug_context->stack_size = 0; + debug_context->thread_id = ref2id(thread); + debug_context->breakpoint = Qnil; + if(rb_obj_class(thread) == cDebugThread) + CTX_FL_SET(debug_context, CTX_FL_IGNORE); + return Data_Wrap_Struct(cContext, debug_context_mark, debug_context_free, debug_context); +} + +static VALUE +debug_context_dup(debug_context_t *debug_context) +{ + debug_context_t *new_debug_context; + debug_frame_t *new_frame, *old_frame; + int i; + + new_debug_context = ALLOC(debug_context_t); + memcpy(new_debug_context, debug_context, sizeof(debug_context_t)); + new_debug_context->stop_next = -1; + new_debug_context->dest_frame = -1; + new_debug_context->stop_line = -1; + new_debug_context->stop_frame = -1; + new_debug_context->breakpoint = Qnil; + CTX_FL_SET(new_debug_context, CTX_FL_DEAD); + new_debug_context->frames = ALLOC_N(debug_frame_t, debug_context->stack_size); + new_debug_context->stack_len = debug_context->stack_size; + memcpy(new_debug_context->frames, debug_context->frames, sizeof(debug_frame_t) * debug_context->stack_size); + for(i = 0; i < debug_context->stack_size; i++) + { + new_frame = &(new_debug_context->frames[i]); + old_frame = &(debug_context->frames[i]); + new_frame->dead = 1; + new_frame->info.copy.args = context_copy_args(old_frame); + new_frame->info.copy.locals = context_copy_locals(old_frame); + } + return Data_Wrap_Struct(cContext, debug_context_mark, debug_context_free, new_debug_context); +} + +static void +thread_context_lookup(VALUE thread, VALUE *context, debug_context_t **debug_context) +{ + threads_table_t *threads_table; + VALUE thread_id; + debug_context_t *l_debug_context; + + debug_check_started(); + + if(last_thread == thread && last_context != Qnil) + { + *context = last_context; + if(debug_context) + *debug_context = last_debug_context; + return; + } + thread_id = ref2id(thread); + Data_Get_Struct(rdebug_threads_tbl, threads_table_t, threads_table); + if(!st_lookup(threads_table->tbl, thread_id, context)) + { + *context = debug_context_create(thread); + st_insert(threads_table->tbl, thread_id, *context); + } + + Data_Get_Struct(*context, debug_context_t, l_debug_context); + if(debug_context) + *debug_context = l_debug_context; + + last_thread = thread; + last_context = *context; + last_debug_context = l_debug_context; +} + +static VALUE +call_at_line_unprotected(VALUE args) +{ + VALUE context; + context = *RARRAY(args)->ptr; + return rb_funcall2(context, idAtLine, RARRAY(args)->len - 1, RARRAY(args)->ptr + 1); +} + +static VALUE +call_at_line(VALUE context, debug_context_t *debug_context, VALUE file, VALUE line) +{ + VALUE args; + + last_debugged_thnum = debug_context->thnum; + save_current_position(debug_context); + + args = rb_ary_new3(3, context, file, line); + return rb_protect(call_at_line_unprotected, args, 0); +} + +static void +save_call_frame(rb_event_t event, VALUE self, char *file, int line, ID mid, debug_context_t *debug_context) +{ + VALUE binding; + debug_frame_t *debug_frame; + int frame_n; + + binding = self && RTEST(keep_frame_binding)? create_binding(self) : Qnil; + + frame_n = debug_context->stack_size++; + if(frame_n >= debug_context->stack_len) + { + debug_context->stack_len += STACK_SIZE_INCREMENT; + debug_context->frames = REALLOC_N(debug_context->frames, debug_frame_t, debug_context->stack_len); + } + debug_frame = &debug_context->frames[frame_n]; + debug_frame->argc = ruby_frame->argc; + debug_frame->file = file; + debug_frame->line = line; + debug_frame->binding = binding; + debug_frame->id = mid; + debug_frame->orig_id = mid; + debug_frame->dead = 0; + debug_frame->self = self; + debug_frame->arg_ary = Qnil; + debug_frame->info.runtime.frame = ruby_frame; + debug_frame->info.runtime.scope = ruby_scope; + debug_frame->info.runtime.dyna_vars = event == RUBY_EVENT_LINE ? ruby_dyna_vars : NULL; + if (RTEST(track_frame_args)) + copy_scalar_args(debug_frame); +} + + +#if defined DOSISH +#define isdirsep(x) ((x) == '/' || (x) == '\\') +#else +#define isdirsep(x) ((x) == '/') +#endif + +int +filename_cmp(VALUE source, char *file) +{ + char *source_ptr, *file_ptr; + int s_len, f_len, min_len; + int s,f; + int dirsep_flag = 0; + + s_len = RSTRING(source)->len; + f_len = strlen(file); + min_len = min(s_len, f_len); + + source_ptr = RSTRING(source)->ptr; + file_ptr = file; + + for( s = s_len - 1, f = f_len - 1; s >= s_len - min_len && f >= f_len - min_len; s--, f-- ) + { + if((source_ptr[s] == '.' || file_ptr[f] == '.') && dirsep_flag) + return 1; + if(isdirsep(source_ptr[s]) && isdirsep(file_ptr[f])) + dirsep_flag = 1; + else if(source_ptr[s] != file_ptr[f]) + return 0; + } + return 1; +} + +/* + * This is a NASTY HACK. For some reasons rb_f_binding is declared + * static in eval.c. So we create a cons up call to binding in C. + */ +static VALUE +create_binding(VALUE self) +{ + typedef VALUE (*bind_func_t)(VALUE); + static bind_func_t f_binding = NULL; + + if(f_binding == NULL) + { + f_binding = (bind_func_t)ruby_method_ptr(rb_mKernel, rb_intern("binding")); + } + return f_binding(self); +} + +inline static debug_frame_t * +get_top_frame(debug_context_t *debug_context) +{ + if(debug_context->stack_size == 0) + return NULL; + else + return &(debug_context->frames[debug_context->stack_size-1]); +} + +inline static void +save_top_binding(debug_context_t *debug_context, VALUE binding) +{ + debug_frame_t *debug_frame; + debug_frame = get_top_frame(debug_context); + if(debug_frame) + debug_frame->binding = binding; +} + +inline static void +set_frame_source(rb_event_t event, debug_context_t *debug_context, VALUE self, char *file, int line, ID mid) +{ + debug_frame_t *top_frame; + top_frame = get_top_frame(debug_context); + if(top_frame) + { + top_frame->self = self; + top_frame->file = file; + top_frame->line = line; + top_frame->id = mid; + top_frame->info.runtime.dyna_vars = event == RUBY_EVENT_C_CALL ? NULL : ruby_dyna_vars; + } +} + +inline static void +reset_frame_mid(debug_context_t *debug_context) +{ + debug_frame_t *top_frame; + top_frame = get_top_frame(debug_context); + if(top_frame) + { + top_frame->id = 0; + } +} + +static void +save_current_position(debug_context_t *debug_context) +{ + debug_frame_t *debug_frame; + + debug_frame = get_top_frame(debug_context); + if(!debug_frame) return; + debug_context->last_file = debug_frame->file; + debug_context->last_line = debug_frame->line; + CTX_FL_UNSET(debug_context, CTX_FL_ENABLE_BKPT); + CTX_FL_UNSET(debug_context, CTX_FL_STEPPED); + CTX_FL_UNSET(debug_context, CTX_FL_FORCE_MOVE); +} + +inline static char * +get_event_name(rb_event_t event) +{ + switch (event) { + case RUBY_EVENT_LINE: + return "line"; + case RUBY_EVENT_CLASS: + return "class"; + case RUBY_EVENT_END: + return "end"; + case RUBY_EVENT_CALL: + return "call"; + case RUBY_EVENT_RETURN: + return "return"; + case RUBY_EVENT_C_CALL: + return "c-call"; + case RUBY_EVENT_C_RETURN: + return "c-return"; + case RUBY_EVENT_RAISE: + return "raise"; + default: + return "unknown"; + } +} + +inline static int +c_call_new_frame_p(VALUE klass, ID mid) +{ + klass = real_class(klass); + if(rb_block_given_p()) return 1; + if(klass == rb_cProc || klass == rb_mKernel || klass == rb_cModule) return 1; + return 0; +} + +static void +debug_event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass) +{ + VALUE thread, context; + VALUE breakpoint = Qnil, binding = Qnil; + debug_context_t *debug_context; + char *file = NULL; + int line = 0, moved = 0; + + hook_count++; + + if (mid == ID_ALLOCATOR) return; + + thread = rb_thread_current(); + thread_context_lookup(thread, &context, &debug_context); + + /* return if thread is marked as 'ignored'. + debugger's threads are marked this way + */ + if(CTX_FL_TEST(debug_context, CTX_FL_IGNORE)) return; + + while(1) + { + /* halt execution of the current thread if the debugger + is activated in another + */ + while(locker != Qnil && locker != thread) + { + add_to_locked(thread); + rb_thread_stop(); + } + + /* stop the current thread if it's marked as suspended */ + if(CTX_FL_TEST(debug_context, CTX_FL_SUSPEND) && locker != thread) + { + CTX_FL_SET(debug_context, CTX_FL_WAS_RUNNING); + rb_thread_stop(); + } + else break; + } + + /* return if the current thread is the locker */ + if(locker != Qnil) return; + + /* only the current thread can proceed */ + locker = thread; + + /* ignore a skipped section of code */ + if(CTX_FL_TEST(debug_context, CTX_FL_SKIPPED)) goto cleanup; + + if(node) + { + file = node->nd_file; + line = nd_line(node); + + if(debug == Qtrue) + fprintf(stderr, "%s:%d [%s] %s\n", file, line, get_event_name(event), rb_id2name(mid)); + + /* There can be many event calls per line, but we only want + *one* breakpoint per line. */ + if(debug_context->last_line != line || debug_context->last_file == NULL || + strcmp(debug_context->last_file, file) != 0) + { + CTX_FL_SET(debug_context, CTX_FL_ENABLE_BKPT); + moved = 1; + } + else if(event == RUBY_EVENT_LINE) + { + /* There are two line-event trace hook calls per IF node - one + before the expression eval an done afterwards. + */ + /* FIXME: the static variable can't be safely used here, since this method + is re-entrant by multiple threads. If we want to provide this kind of functionality + if_eval_event variable must be moved to debug_context structure. + */ + /* + static int if_eval_event = 0; + if_eval_event = (NODE_IF == nd_type(node)) ? !if_eval_event : 0; + if (!if_eval_event) + { + CTX_FL_SET(debug_context, CTX_FL_ENABLE_BKPT); + } + */ + } + } + else if(event != RUBY_EVENT_RETURN && event != RUBY_EVENT_C_RETURN) + { + if(debug == Qtrue) + fprintf(stderr, "nodeless [%s] %s\n", get_event_name(event), rb_id2name(mid)); + goto cleanup; + } + else + { + if(debug == Qtrue) + fprintf(stderr, "nodeless [%s] %s\n", get_event_name(event), rb_id2name(mid)); + } + + if(event != RUBY_EVENT_LINE) + CTX_FL_SET(debug_context, CTX_FL_STEPPED); + + switch(event) + { + case RUBY_EVENT_LINE: + { + + if(debug_context->stack_size == 0) + save_call_frame(event, self, file, line, mid, debug_context); + else + set_frame_source(event, debug_context, self, file, line, mid); + + if(RTEST(tracing) || CTX_FL_TEST(debug_context, CTX_FL_TRACING)) + rb_funcall(context, idAtTracing, 2, rb_str_new2(file), INT2FIX(line)); + + if(debug_context->dest_frame == -1 || + debug_context->stack_size == debug_context->dest_frame) + { + if(moved || !CTX_FL_TEST(debug_context, CTX_FL_FORCE_MOVE)) + debug_context->stop_next--; + if(debug_context->stop_next < 0) + debug_context->stop_next = -1; + if(moved || (CTX_FL_TEST(debug_context, CTX_FL_STEPPED) && + !CTX_FL_TEST(debug_context, CTX_FL_FORCE_MOVE))) + { + debug_context->stop_line--; + CTX_FL_UNSET(debug_context, CTX_FL_STEPPED); + } + } + else if(debug_context->stack_size < debug_context->dest_frame) + { + debug_context->stop_next = 0; + } + + if(debug_context->stop_next == 0 || debug_context->stop_line == 0 || + (breakpoint = check_breakpoints_by_pos(debug_context, file, line)) != Qnil) + { + binding = self? create_binding(self) : Qnil; + save_top_binding(debug_context, binding); + + debug_context->stop_reason = CTX_STOP_STEP; + + /* check breakpoint expression */ + if(breakpoint != Qnil) + { + if(!check_breakpoint_expression(breakpoint, binding)) + break; + if(!check_breakpoint_hit_condition(breakpoint)) + break; + if(breakpoint != debug_context->breakpoint) + { + debug_context->stop_reason = CTX_STOP_BREAKPOINT; + rb_funcall(context, idAtBreakpoint, 1, breakpoint); + } + else + debug_context->breakpoint = Qnil; + } + + reset_stepping_stop_points(debug_context); + call_at_line(context, debug_context, rb_str_new2(file), INT2FIX(line)); + } + break; + } + case RUBY_EVENT_CALL: + { + save_call_frame(event, self, file, line, mid, debug_context); + breakpoint = check_breakpoints_by_method(debug_context, klass, mid); + if(breakpoint != Qnil) + { + debug_frame_t *debug_frame; + debug_frame = get_top_frame(debug_context); + if(debug_frame) + binding = debug_frame->binding; + if(NIL_P(binding) && self) + binding = create_binding(self); + save_top_binding(debug_context, binding); + + if(!check_breakpoint_expression(breakpoint, binding)) + break; + if(!check_breakpoint_hit_condition(breakpoint)) + break; + if(breakpoint != debug_context->breakpoint) + { + debug_context->stop_reason = CTX_STOP_BREAKPOINT; + rb_funcall(context, idAtBreakpoint, 1, breakpoint); + } + else + debug_context->breakpoint = Qnil; + call_at_line(context, debug_context, rb_str_new2(file), INT2FIX(line)); + } + break; + } + case RUBY_EVENT_C_CALL: + { + if(c_call_new_frame_p(klass, mid)) + save_call_frame(event, self, file, line, mid, debug_context); + else + set_frame_source(event, debug_context, self, file, line, mid); + break; + } + case RUBY_EVENT_C_RETURN: + { + /* note if a block is given we fall through! */ + if(!node || !c_call_new_frame_p(klass, mid)) + break; + } + case RUBY_EVENT_RETURN: + case RUBY_EVENT_END: + { + if(debug_context->stack_size == debug_context->stop_frame) + { + debug_context->stop_next = 1; + debug_context->stop_frame = 0; + /* NOTE: can't use call_at_line function here to trigger a debugger event. + this can lead to segfault. We should only unroll the stack on this event. + */ + } + while(debug_context->stack_size > 0) + { + debug_context->stack_size--; + if(debug_context->frames[debug_context->stack_size].orig_id == mid) + break; + } + CTX_FL_SET(debug_context, CTX_FL_ENABLE_BKPT); + break; + } + case RUBY_EVENT_CLASS: + { + reset_frame_mid(debug_context); + save_call_frame(event, self, file, line, mid, debug_context); + break; + } + case RUBY_EVENT_RAISE: + { + VALUE ancestors; + VALUE expn_class, aclass; + int i; + + set_frame_source(event, debug_context, self, file, line, mid); + + if(post_mortem == Qtrue && self) + { + binding = create_binding(self); + rb_ivar_set(ruby_errinfo, rb_intern("@__debug_file"), rb_str_new2(file)); + rb_ivar_set(ruby_errinfo, rb_intern("@__debug_line"), INT2FIX(line)); + rb_ivar_set(ruby_errinfo, rb_intern("@__debug_binding"), binding); + rb_ivar_set(ruby_errinfo, rb_intern("@__debug_context"), debug_context_dup(debug_context)); + } + + expn_class = rb_obj_class(ruby_errinfo); + + /* This code goes back to the earliest days of ruby-debug. It + tends to disallow catching an exception via the + "catchpoint" command. To address this one possiblilty is to + move this after testing for catchponts. Kent however thinks + there may be a misfeature in Ruby's eval.c: the problem was + in the fact that Ruby doesn't reset exception flag on the + current thread before it calls a notification handler. + + See also the #ifdef'd code below as well. + */ +#ifdef NORMAL_CODE + if( !NIL_P(rb_class_inherited_p(expn_class, rb_eSystemExit)) ) + { + debug_stop(mDebugger); + break; + } +#endif + + if (rdebug_catchpoints == Qnil || + RHASH(rdebug_catchpoints)->tbl->num_entries == 0) + break; + + ancestors = rb_mod_ancestors(expn_class); + for(i = 0; i < RARRAY(ancestors)->len; i++) + { + VALUE mod_name; + VALUE hit_count; + + aclass = rb_ary_entry(ancestors, i); + mod_name = rb_mod_name(aclass); + hit_count = rb_hash_aref(rdebug_catchpoints, mod_name); + if(hit_count != Qnil) + { + hit_count = INT2FIX(FIX2INT(rb_hash_aref(rdebug_catchpoints, + mod_name)+1)); + rb_hash_aset(rdebug_catchpoints, mod_name, hit_count); + debug_context->stop_reason = CTX_STOP_CATCHPOINT; + rb_funcall(context, idAtCatchpoint, 1, ruby_errinfo); + if(self && binding == Qnil) + binding = create_binding(self); + save_top_binding(debug_context, binding); + call_at_line(context, debug_context, rb_str_new2(file), INT2FIX(line)); + break; + } + } + + /* If we stop the debugger, we may not be able to trace into + code that has an exception handler wrapped around it. So + the alternative is to force the user to do his own + Debugger.stop. */ +#ifdef NORMAL_CODE_MOVING_AFTER_ + if( !NIL_P(rb_class_inherited_p(expn_class, rb_eSystemExit)) ) + { + debug_stop(mDebugger); + break; + } +#endif + + break; + } + } + + cleanup: + + debug_context->stop_reason = CTX_STOP_NONE; + + /* check that all contexts point to alive threads */ + if(hook_count - last_check > 3000) + { + check_thread_contexts(); + last_check = hook_count; + } + + /* release a lock */ + locker = Qnil; + /* let the next thread to run */ + thread = remove_from_locked(); + if(thread != Qnil) + rb_thread_run(thread); +} + +static VALUE +debug_stop_i(VALUE self) +{ + if(IS_STARTED) + debug_stop(self); + return Qnil; +} + +/* + * call-seq: + * Debugger.start_ -> bool + * Debugger.start_ { ... } -> bool + * + * This method is internal and activates the debugger. Use + * Debugger.start (from lib/ruby-debug-base.rb) instead. + * + * The return value is the value of !Debugger.started? before + * issuing the +start+; That is, +true+ is returned, unless debugger + * was previously started. + + * If a block is given, it starts debugger and yields to block. When + * the block is finished executing it stops the debugger with + * Debugger.stop method. Inside the block you will probably want to + * have a call to Debugger.debugger. For example: + * Debugger.start{debugger; foo} # Stop inside of foo + * + * Also, ruby-debug only allows + * one invocation of debugger at a time; nested Debugger.start's + * have no effect and you can't use this inside the debugger itself. + * + * Note that if you want to completely remove the debugger hook, + * you must call Debugger.stop as many times as you called + * Debugger.start method. + */ +static VALUE +debug_start(VALUE self) +{ + VALUE result; + start_count++; + + if(IS_STARTED) + result = Qfalse; + else + { + locker = Qnil; + rdebug_breakpoints = rb_ary_new(); + rdebug_catchpoints = rb_hash_new(); + rdebug_threads_tbl = threads_table_create(); + + rb_add_event_hook(debug_event_hook, RUBY_EVENT_ALL); + result = Qtrue; + } + + if(rb_block_given_p()) + rb_ensure(rb_yield, self, debug_stop_i, self); + + return result; +} + +/* + * call-seq: + * Debugger.stop -> bool + * + * This method disables the debugger. It returns +true+ if the debugger is disabled, + * otherwise it returns +false+. + * + * Note that if you want to complete remove the debugger hook, + * you must call Debugger.stop as many times as you called + * Debugger.start method. + */ +static VALUE +debug_stop(VALUE self) +{ + debug_check_started(); + + start_count--; + if(start_count) + return Qfalse; + + rb_remove_event_hook(debug_event_hook); + + locker = Qnil; + rdebug_breakpoints = Qnil; + rdebug_threads_tbl = Qnil; + + return Qtrue; +} + +static int +find_last_context_func(VALUE key, VALUE value, VALUE *result) +{ + debug_context_t *debug_context; + Data_Get_Struct(value, debug_context_t, debug_context); + if(debug_context->thnum == last_debugged_thnum) + { + *result = value; + return ST_STOP; + } + return ST_CONTINUE; +} + +/* + * call-seq: + * Debugger.last_interrupted -> context + * + * Returns last debugged context. + */ +static VALUE +debug_last_interrupted(VALUE self) +{ + VALUE result = Qnil; + threads_table_t *threads_table; + + debug_check_started(); + + Data_Get_Struct(rdebug_threads_tbl, threads_table_t, threads_table); + + st_foreach(threads_table->tbl, find_last_context_func, (st_data_t)&result); + return result; +} + +/* + * call-seq: + * Debugger.current_context -> context + * + * Returns current context. + * Note: Debugger.current_context.thread == Thread.current + */ +static VALUE +debug_current_context(VALUE self) +{ + VALUE thread, context; + + debug_check_started(); + + thread = rb_thread_current(); + thread_context_lookup(thread, &context, NULL); + + return context; +} + +/* + * call-seq: + * Debugger.thread_context(thread) -> context + * + * Returns context of the thread passed as an argument. + */ +static VALUE +debug_thread_context(VALUE self, VALUE thread) +{ + VALUE context; + + debug_check_started(); + thread_context_lookup(thread, &context, NULL); + return context; +} + +/* + * call-seq: + * Debugger.contexts -> array + * + * Returns an array of all contexts. + */ +static VALUE +debug_contexts(VALUE self) +{ + volatile VALUE list; + volatile VALUE new_list; + VALUE thread, context; + threads_table_t *threads_table; + debug_context_t *debug_context; + int i; + + debug_check_started(); + + new_list = rb_ary_new(); + list = rb_funcall(rb_cThread, idList, 0); + for(i = 0; i < RARRAY(list)->len; i++) + { + thread = rb_ary_entry(list, i); + thread_context_lookup(thread, &context, NULL); + rb_ary_push(new_list, context); + } + threads_table_clear(rdebug_threads_tbl); + Data_Get_Struct(rdebug_threads_tbl, threads_table_t, threads_table); + for(i = 0; i < RARRAY(new_list)->len; i++) + { + context = rb_ary_entry(new_list, i); + Data_Get_Struct(context, debug_context_t, debug_context); + st_insert(threads_table->tbl, debug_context->thread_id, context); + } + + return new_list; +} + +/* + * call-seq: + * Debugger.suspend -> Debugger + * + * Suspends all contexts. + */ +static VALUE +debug_suspend(VALUE self) +{ + VALUE current, context; + VALUE saved_crit; + VALUE context_list; + debug_context_t *debug_context; + int i; + + debug_check_started(); + + saved_crit = rb_thread_critical; + rb_thread_critical = Qtrue; + context_list = debug_contexts(self); + thread_context_lookup(rb_thread_current(), ¤t, NULL); + + for(i = 0; i < RARRAY(context_list)->len; i++) + { + context = rb_ary_entry(context_list, i); + if(current == context) + continue; + Data_Get_Struct(context, debug_context_t, debug_context); + context_suspend_0(debug_context); + } + rb_thread_critical = saved_crit; + + if(rb_thread_critical == Qfalse) + rb_thread_schedule(); + + return self; +} + +/* + * call-seq: + * Debugger.resume -> Debugger + * + * Resumes all contexts. + */ +static VALUE +debug_resume(VALUE self) +{ + VALUE current, context; + VALUE saved_crit; + VALUE context_list; + debug_context_t *debug_context; + int i; + + debug_check_started(); + + saved_crit = rb_thread_critical; + rb_thread_critical = Qtrue; + context_list = debug_contexts(self); + + thread_context_lookup(rb_thread_current(), ¤t, NULL); + for(i = 0; i < RARRAY(context_list)->len; i++) + { + context = rb_ary_entry(context_list, i); + if(current == context) + continue; + Data_Get_Struct(context, debug_context_t, debug_context); + context_resume_0(debug_context); + } + rb_thread_critical = saved_crit; + + rb_thread_schedule(); + + return self; +} + +/* + * call-seq: + * Debugger.tracing -> bool + * + * Returns +true+ if the global tracing is activated. + */ +static VALUE +debug_tracing(VALUE self) +{ + return tracing; +} + +/* + * call-seq: + * Debugger.tracing = bool + * + * Sets the global tracing flag. + */ +static VALUE +debug_set_tracing(VALUE self, VALUE value) +{ + tracing = RTEST(value) ? Qtrue : Qfalse; + return value; +} + +/* + * call-seq: + * Debugger.post_mortem? -> bool + * + * Returns +true+ if post-moterm debugging is enabled. + */ +static VALUE +debug_post_mortem(VALUE self) +{ + return post_mortem; +} + +/* + * call-seq: + * Debugger.post_mortem = bool + * + * Sets post-moterm flag. + * FOR INTERNAL USE ONLY. + */ +static VALUE +debug_set_post_mortem(VALUE self, VALUE value) +{ + debug_check_started(); + + post_mortem = RTEST(value) ? Qtrue : Qfalse; + return value; +} + +/* + * call-seq: + * Debugger.track_fame_args? -> bool + * + * Returns +true+ if the debugger track frame argument values on calls. + */ +static VALUE +debug_track_frame_args(VALUE self) +{ + return track_frame_args; +} + +/* + * call-seq: + * Debugger.track_frame_args = bool + * + * Setting to +true+ will make the debugger save argument info on calls. + */ +static VALUE +debug_set_track_frame_args(VALUE self, VALUE value) +{ + track_frame_args = RTEST(value) ? Qtrue : Qfalse; + return value; +} + +/* + * call-seq: + * Debugger.keep_frame_binding? -> bool + * + * Returns +true+ if the debugger will collect frame bindings. + */ +static VALUE +debug_keep_frame_binding(VALUE self) +{ + return keep_frame_binding; +} + +/* + * call-seq: + * Debugger.keep_frame_binding = bool + * + * Setting to +true+ will make the debugger create frame bindings. + */ +static VALUE +debug_set_keep_frame_binding(VALUE self, VALUE value) +{ + keep_frame_binding = RTEST(value) ? Qtrue : Qfalse; + return value; +} + +/* :nodoc: */ +static VALUE +debug_debug(VALUE self) +{ + return debug; +} + +/* :nodoc: */ +static VALUE +debug_set_debug(VALUE self, VALUE value) +{ + debug = RTEST(value) ? Qtrue : Qfalse; + return value; +} + +/* :nodoc: */ +static VALUE +debug_thread_inherited(VALUE klass) +{ + rb_raise(rb_eRuntimeError, "Can't inherite Debugger::DebugThread class"); +} + +/* + * call-seq: + * Debugger.debug_load(file, stop = false, increment_start = false) -> nil + * + * Same as Kernel#load but resets current context's frames. + * +stop+ parameter forces the debugger to stop at the first line of code in the +file+ + * +increment_start+ determines if start_count should be incremented. When + * control threads are used, they have to be set up before loading the + * debugger; so here +increment_start+ will be false. + * FOR INTERNAL USE ONLY. + */ +static VALUE +debug_debug_load(int argc, VALUE *argv, VALUE self) +{ + VALUE file, stop, context, increment_start; + debug_context_t *debug_context; + int state = 0; + + if(rb_scan_args(argc, argv, "12", &file, &stop, &increment_start) == 1) + { + stop = Qfalse; + increment_start = Qtrue; + } + + debug_start(self); + if (Qfalse == increment_start) start_count--; + + context = debug_current_context(self); + Data_Get_Struct(context, debug_context_t, debug_context); + debug_context->stack_size = 0; + if(RTEST(stop)) + debug_context->stop_next = 1; + /* Initializing $0 to the script's path */ + ruby_script(RSTRING(file)->ptr); + rb_load_protect(file, 0, &state); + if (0 != state) { + VALUE errinfo = ruby_errinfo; + debug_suspend(self); + reset_stepping_stop_points(debug_context); + ruby_errinfo = Qnil; + return errinfo; + } + + /* We should run all at_exit handler's in order to provide, + * for instance, a chance to run all defined test cases */ + rb_exec_end_proc(); + + /* We could have issued a Debugger.stop inside the debug + session. */ + if (start_count > 0) { + debug_stop(self); + } + + return Qnil; +} + +static VALUE +set_current_skipped_status(VALUE status) +{ + VALUE context; + debug_context_t *debug_context; + + context = debug_current_context(Qnil); + Data_Get_Struct(context, debug_context_t, debug_context); + if(status) + CTX_FL_SET(debug_context, CTX_FL_SKIPPED); + else + CTX_FL_UNSET(debug_context, CTX_FL_SKIPPED); + return Qnil; +} + +/* + * call-seq: + * Debugger.skip { block } -> obj or nil + * + * The code inside of the block is escaped from the debugger. + */ +static VALUE +debug_skip(VALUE self) +{ + if (!rb_block_given_p()) { + rb_raise(rb_eArgError, "called without a block"); + } + if(!IS_STARTED) + return rb_yield(Qnil); + set_current_skipped_status(Qtrue); + return rb_ensure(rb_yield, Qnil, set_current_skipped_status, Qfalse); +} + +static VALUE +debug_at_exit_c(VALUE proc) +{ + return rb_funcall(proc, rb_intern("call"), 0); +} + +static void +debug_at_exit_i(VALUE proc) +{ + if(!IS_STARTED) + { + debug_at_exit_c(proc); + } + else + { + set_current_skipped_status(Qtrue); + rb_ensure(debug_at_exit_c, proc, set_current_skipped_status, Qfalse); + } +} + +/* + * call-seq: + * Debugger.debug_at_exit { block } -> proc + * + * Register at_exit hook which is escaped from the debugger. + * FOR INTERNAL USE ONLY. + */ +static VALUE +debug_at_exit(VALUE self) +{ + VALUE proc; + if (!rb_block_given_p()) + rb_raise(rb_eArgError, "called without a block"); + proc = rb_block_proc(); + rb_set_end_proc(debug_at_exit_i, proc); + return proc; +} + +/* + * call-seq: + * context.step(steps, force = false) + * + * Stops the current context after a number of +steps+ are made. + * +force+ parameter (if true) ensures that the cursor moves from the current line. + */ +static VALUE +context_stop_next(int argc, VALUE *argv, VALUE self) +{ + VALUE steps, force; + debug_context_t *debug_context; + + debug_check_started(); + + rb_scan_args(argc, argv, "11", &steps, &force); + if(FIX2INT(steps) < 0) + rb_raise(rb_eRuntimeError, "Steps argument can't be negative."); + + Data_Get_Struct(self, debug_context_t, debug_context); + debug_context->stop_next = FIX2INT(steps); + if(RTEST(force)) + CTX_FL_SET(debug_context, CTX_FL_FORCE_MOVE); + else + CTX_FL_UNSET(debug_context, CTX_FL_FORCE_MOVE); + + return steps; +} + +/* + * call-seq: + * context.step_over(steps, frame = nil, force = false) + * + * Steps over a +steps+ number of times. + * Make step over operation on +frame+, by default the current frame. + * +force+ parameter (if true) ensures that the cursor moves from the current line. + */ +static VALUE +context_step_over(int argc, VALUE *argv, VALUE self) +{ + VALUE lines, frame, force; + debug_context_t *debug_context; + + debug_check_started(); + Data_Get_Struct(self, debug_context_t, debug_context); + if(debug_context->stack_size == 0) + rb_raise(rb_eRuntimeError, "No frames collected."); + + rb_scan_args(argc, argv, "12", &lines, &frame, &force); + debug_context->stop_line = FIX2INT(lines); + CTX_FL_UNSET(debug_context, CTX_FL_STEPPED); + if(frame == Qnil) + { + debug_context->dest_frame = debug_context->stack_size; + } + else + { + if(FIX2INT(frame) < 0 && FIX2INT(frame) >= debug_context->stack_size) + rb_raise(rb_eRuntimeError, "Destination frame is out of range."); + debug_context->dest_frame = debug_context->stack_size - FIX2INT(frame); + } + if(RTEST(force)) + CTX_FL_SET(debug_context, CTX_FL_FORCE_MOVE); + else + CTX_FL_UNSET(debug_context, CTX_FL_FORCE_MOVE); + + return Qnil; +} + +/* + * call-seq: + * context.stop_frame(frame) + * + * Stops when a frame with number +frame+ is activated. Implements +finish+ and +next+ commands. + */ +static VALUE +context_stop_frame(VALUE self, VALUE frame) +{ + debug_context_t *debug_context; + + debug_check_started(); + Data_Get_Struct(self, debug_context_t, debug_context); + if(FIX2INT(frame) < 0 && FIX2INT(frame) >= debug_context->stack_size) + rb_raise(rb_eRuntimeError, "Stop frame is out of range."); + debug_context->stop_frame = debug_context->stack_size - FIX2INT(frame); + + return frame; +} + +inline static int +check_frame_number(debug_context_t *debug_context, VALUE frame) +{ + int frame_n; + + frame_n = FIX2INT(frame); + if(frame_n < 0 || frame_n >= debug_context->stack_size) + rb_raise(rb_eArgError, "Invalid frame number %d, stack (0...%d)", + frame_n, debug_context->stack_size); + return frame_n; +} + +static int +optional_frame_position(int argc, VALUE *argv) { + unsigned int i_scanned; + VALUE level; + + if ((argc > 1) || (argc < 0)) + rb_raise(rb_eArgError, "wrong number of arguments (%d for 0 or 1)", argc); + i_scanned = rb_scan_args(argc, argv, "01", &level); + if (0 == i_scanned) { + level = INT2FIX(0); + } + return level; +} + +/* + * call-seq: + * context.frame_args_info(frame_position=0) -> list + if track_frame_args or nil otherwise + * + * Returns info saved about call arguments (if any saved). + */ +static VALUE +context_frame_args_info(int argc, VALUE *argv, VALUE self) +{ + VALUE frame; + debug_context_t *debug_context; + + debug_check_started(); + frame = optional_frame_position(argc, argv); + Data_Get_Struct(self, debug_context_t, debug_context); + + return RTEST(track_frame_args) ? GET_FRAME->arg_ary : Qnil; +} + +/* + * call-seq: + * context.frame_binding(frame_position=0) -> binding + * + * Returns frame's binding. + */ +static VALUE +context_frame_binding(int argc, VALUE *argv, VALUE self) +{ + VALUE frame; + debug_context_t *debug_context; + + debug_check_started(); + frame = optional_frame_position(argc, argv); + Data_Get_Struct(self, debug_context_t, debug_context); + return GET_FRAME->binding; +} + +/* + * call-seq: + * context.frame_method(frame_position=0) -> sym + * + * Returns the sym of the called method. + */ +static VALUE +context_frame_id(int argc, VALUE *argv, VALUE self) +{ + VALUE frame; + debug_context_t *debug_context; + ID id; + + debug_check_started(); + frame = optional_frame_position(argc, argv); + Data_Get_Struct(self, debug_context_t, debug_context); + + id = GET_FRAME->id; + return id ? ID2SYM(id): Qnil; +} + +/* + * call-seq: + * context.frame_line(frame_position) -> int + * + * Returns the line number in the file. + */ +static VALUE +context_frame_line(int argc, VALUE *argv, VALUE self) +{ + VALUE frame; + debug_context_t *debug_context; + + debug_check_started(); + frame = optional_frame_position(argc, argv); + Data_Get_Struct(self, debug_context_t, debug_context); + + return INT2FIX(GET_FRAME->line); +} + +/* + * call-seq: + * context.frame_file(frame_position) -> string + * + * Returns the name of the file. + */ +static VALUE +context_frame_file(int argc, VALUE *argv, VALUE self) +{ + VALUE frame; + debug_context_t *debug_context; + + debug_check_started(); + frame = optional_frame_position(argc, argv); + Data_Get_Struct(self, debug_context_t, debug_context); + + return rb_str_new2(GET_FRAME->file); +} + +static int +arg_value_is_small(VALUE val) +{ + switch (TYPE(val)) { + case T_FIXNUM: case T_FLOAT: case T_CLASS: + case T_NIL: case T_MODULE: case T_FILE: + case T_TRUE: case T_FALSE: case T_UNDEF: + return 1; + default: + return SYMBOL_P(val); + } +} + +/* + * Save scalar arguments or a class name. + */ +static void +copy_scalar_args(debug_frame_t *debug_frame) +{ + unsigned int i; + ID *tbl = ruby_scope->local_tbl;; + if (tbl && ruby_scope->local_vars) + { + int n = *tbl++; + if (debug_frame->argc+2 < n) n = debug_frame->argc+2; + debug_frame->arg_ary = rb_ary_new2(n); + for (i=2; iarg_ary, val); + else + rb_ary_push(debug_frame->arg_ary, + rb_str_new2(rb_obj_classname(val))); + } + } + } +} + + +/* + * call-seq: + * context.copy_args(frame) -> list of args + * + * Returns a array of argument names. + */ +static VALUE +context_copy_args(debug_frame_t *debug_frame) +{ + ID *tbl; + int n, i; + struct SCOPE *scope; + VALUE list = rb_ary_new2(0); /* [] */ + + scope = debug_frame->info.runtime.scope; + tbl = scope->local_tbl; + + if (tbl && scope->local_vars) + { + n = *tbl++; + if (debug_frame->argc+2 < n) n = debug_frame->argc+2; + list = rb_ary_new2(n); + /* skip first 2 ($_ and $~) */ + for (i=2; iinfo.runtime.scope; + tbl = scope->local_tbl; + + if (tbl && scope->local_vars) + { + n = *tbl++; + for (i=2; ilocal_vars[i]); + } + } + + vars = debug_frame->info.runtime.dyna_vars; + while (vars) + { + if (vars->id && rb_is_local_id(vars->id)) + { /* skip $_, $~ and flip states */ + rb_hash_aset(hash, rb_str_new2(rb_id2name(vars->id)), vars->val); + } + vars = vars->next; + } + return hash; +} + +/* + * call-seq: + * context.frame_locals(frame) -> hash + * + * Returns frame's local variables. + */ +static VALUE +context_frame_locals(int argc, VALUE *argv, VALUE self) +{ + VALUE frame; + debug_context_t *debug_context; + debug_frame_t *debug_frame; + + debug_check_started(); + frame = optional_frame_position(argc, argv); + Data_Get_Struct(self, debug_context_t, debug_context); + + debug_frame = GET_FRAME; + if(debug_frame->dead) + return debug_frame->info.copy.locals; + else + return context_copy_locals(debug_frame); +} + +/* + * call-seq: + * context.frame_args(frame_position=0) -> list + * + * Returns frame's argument parameters + */ +static VALUE +context_frame_args(int argc, VALUE *argv, VALUE self) +{ + VALUE frame; + debug_context_t *debug_context; + debug_frame_t *debug_frame; + + debug_check_started(); + frame = optional_frame_position(argc, argv); + Data_Get_Struct(self, debug_context_t, debug_context); + + debug_frame = GET_FRAME; + if(debug_frame->dead) + return debug_frame->info.copy.args; + else + return context_copy_args(debug_frame); +} + +/* + * call-seq: + * context.frame_self(frame_postion=0) -> obj + * + * Returns self object of the frame. + */ +static VALUE +context_frame_self(int argc, VALUE *argv, VALUE self) +{ + VALUE frame; + debug_context_t *debug_context; + debug_frame_t *debug_frame; + + debug_check_started(); + frame = optional_frame_position(argc, argv); + Data_Get_Struct(self, debug_context_t, debug_context); + + debug_frame = GET_FRAME; + return debug_frame->self; +} + +/* + * call-seq: + * context.frame_class(frame_position) -> obj + * + * Returns the real class of the frame. + * It could be different than context.frame_self(frame).class + */ +static VALUE +context_frame_class(int argc, VALUE *argv, VALUE self) +{ + VALUE frame; + debug_context_t *debug_context; + debug_frame_t *debug_frame; + VALUE klass; + + debug_check_started(); + frame = optional_frame_position(argc, argv); + Data_Get_Struct(self, debug_context_t, debug_context); + + debug_frame = GET_FRAME; + + if(CTX_FL_TEST(debug_context, CTX_FL_DEAD)) + return Qnil; + +#if RUBY_VERSION_CODE >= 190 + klass = debug_frame->info.runtime.frame->this_class; +#else + klass = debug_frame->info.runtime.frame->last_class; +#endif + + klass = real_class(klass); + if(TYPE(klass) == T_CLASS || TYPE(klass) == T_MODULE) + return klass; + return Qnil; +} + + +/* + * call-seq: + * context.stack_size-> int + * + * Returns the size of the context stack. + */ +static VALUE +context_stack_size(VALUE self) +{ + debug_context_t *debug_context; + + debug_check_started(); + Data_Get_Struct(self, debug_context_t, debug_context); + + return INT2FIX(debug_context->stack_size); +} + +/* + * call-seq: + * context.thread -> thread + * + * Returns a thread this context is associated with. + */ +static VALUE +context_thread(VALUE self) +{ + debug_context_t *debug_context; + + debug_check_started(); + Data_Get_Struct(self, debug_context_t, debug_context); + return context_thread_0(debug_context); +} + +/* + * call-seq: + * context.thnum -> int + * + * Returns the context's number. + */ +static VALUE +context_thnum(VALUE self) +{ + debug_context_t *debug_context; + + Data_Get_Struct(self, debug_context_t, debug_context); + return INT2FIX(debug_context->thnum); +} + +static void +context_suspend_0(debug_context_t *debug_context) +{ + VALUE status; + + status = rb_funcall(context_thread_0(debug_context), rb_intern("status"), 0); + if(rb_str_cmp(status, rb_str_new2("run")) == 0) + CTX_FL_SET(debug_context, CTX_FL_WAS_RUNNING); + else if(rb_str_cmp(status, rb_str_new2("sleep")) == 0) + CTX_FL_UNSET(debug_context, CTX_FL_WAS_RUNNING); + else + return; + CTX_FL_SET(debug_context, CTX_FL_SUSPEND); +} + +static void +context_resume_0(debug_context_t *debug_context) +{ + if(!CTX_FL_TEST(debug_context, CTX_FL_SUSPEND)) + return; + CTX_FL_UNSET(debug_context, CTX_FL_SUSPEND); + if(CTX_FL_TEST(debug_context, CTX_FL_WAS_RUNNING)) + rb_thread_wakeup(context_thread_0(debug_context)); +} + +/* + * call-seq: + * context.suspend -> nil + * + * Suspends the thread when it is running. + */ +static VALUE +context_suspend(VALUE self) +{ + debug_context_t *debug_context; + + debug_check_started(); + + Data_Get_Struct(self, debug_context_t, debug_context); + if(CTX_FL_TEST(debug_context, CTX_FL_SUSPEND)) + rb_raise(rb_eRuntimeError, "Already suspended."); + context_suspend_0(debug_context); + return Qnil; +} + +/* + * call-seq: + * context.suspended? -> bool + * + * Returns +true+ if the thread is suspended by debugger. + */ +static VALUE +context_is_suspended(VALUE self) +{ + debug_context_t *debug_context; + + debug_check_started(); + + Data_Get_Struct(self, debug_context_t, debug_context); + return CTX_FL_TEST(debug_context, CTX_FL_SUSPEND) ? Qtrue : Qfalse; +} + +/* + * call-seq: + * context.resume -> nil + * + * Resumes the thread from the suspended mode. + */ +static VALUE +context_resume(VALUE self) +{ + debug_context_t *debug_context; + + debug_check_started(); + + Data_Get_Struct(self, debug_context_t, debug_context); + if(!CTX_FL_TEST(debug_context, CTX_FL_SUSPEND)) + rb_raise(rb_eRuntimeError, "Thread is not suspended."); + context_resume_0(debug_context); + return Qnil; +} + +/* + * call-seq: + * context.tracing -> bool + * + * Returns the tracing flag for the current context. + */ +static VALUE +context_tracing(VALUE self) +{ + debug_context_t *debug_context; + + debug_check_started(); + + Data_Get_Struct(self, debug_context_t, debug_context); + return CTX_FL_TEST(debug_context, CTX_FL_TRACING) ? Qtrue : Qfalse; +} + +/* + * call-seq: + * context.tracing = bool + * + * Controls the tracing for this context. + */ +static VALUE +context_set_tracing(VALUE self, VALUE value) +{ + debug_context_t *debug_context; + + debug_check_started(); + + Data_Get_Struct(self, debug_context_t, debug_context); + if(RTEST(value)) + CTX_FL_SET(debug_context, CTX_FL_TRACING); + else + CTX_FL_UNSET(debug_context, CTX_FL_TRACING); + return value; +} + +/* + * call-seq: + * context.ignored? -> bool + * + * Returns the ignore flag for the current context. + */ +static VALUE +context_ignored(VALUE self) +{ + debug_context_t *debug_context; + + debug_check_started(); + + Data_Get_Struct(self, debug_context_t, debug_context); + return CTX_FL_TEST(debug_context, CTX_FL_IGNORE) ? Qtrue : Qfalse; +} + +/* + * call-seq: + * context.dead? -> bool + * + * Returns +true+ if context doesn't represent a live context and is created + * during post-mortem exception handling. + */ +static VALUE +context_dead(VALUE self) +{ + debug_context_t *debug_context; + + debug_check_started(); + + Data_Get_Struct(self, debug_context_t, debug_context); + return CTX_FL_TEST(debug_context, CTX_FL_DEAD) ? Qtrue : Qfalse; +} + +/* + * call-seq: + * context.stop_reason -> sym + * + * Returns the reason for the stop. It maybe of the following values: + * :initial, :step, :breakpoint, :catchpoint, :post-mortem + */ +static VALUE +context_stop_reason(VALUE self) +{ + debug_context_t *debug_context; + char * sym_name; + + debug_check_started(); + + Data_Get_Struct(self, debug_context_t, debug_context); + + switch(debug_context->stop_reason) + { + case CTX_STOP_STEP: + sym_name = "step"; + break; + case CTX_STOP_BREAKPOINT: + sym_name = "breakpoint"; + break; + case CTX_STOP_CATCHPOINT: + sym_name = "catchpoint"; + break; + case CTX_STOP_NONE: + default: + sym_name = "none"; + } + if(CTX_FL_TEST(debug_context, CTX_FL_DEAD)) + sym_name = "post-mortem"; + + return ID2SYM(rb_intern(sym_name)); +} + + +/* + * Document-class: Context + * + * == Summary + * + * Debugger keeps a single instance of this class for each Ruby thread. + */ +static void +Init_context() +{ + cContext = rb_define_class_under(mDebugger, "Context", rb_cObject); + rb_define_method(cContext, "stop_next=", context_stop_next, -1); + rb_define_method(cContext, "step", context_stop_next, -1); + rb_define_method(cContext, "step_over", context_step_over, -1); + rb_define_method(cContext, "stop_frame=", context_stop_frame, 1); + rb_define_method(cContext, "thread", context_thread, 0); + rb_define_method(cContext, "thnum", context_thnum, 0); + rb_define_method(cContext, "stop_reason", context_stop_reason, 0); + rb_define_method(cContext, "suspend", context_suspend, 0); + rb_define_method(cContext, "suspended?", context_is_suspended, 0); + rb_define_method(cContext, "resume", context_resume, 0); + rb_define_method(cContext, "tracing", context_tracing, 0); + rb_define_method(cContext, "tracing=", context_set_tracing, 1); + rb_define_method(cContext, "ignored?", context_ignored, 0); + rb_define_method(cContext, "frame_args", context_frame_args, -1); + rb_define_method(cContext, "frame_args_info", context_frame_args_info, -1); + rb_define_method(cContext, "frame_binding", context_frame_binding, -1); + rb_define_method(cContext, "frame_class", context_frame_class, -1); + rb_define_method(cContext, "frame_file", context_frame_file, -1); + rb_define_method(cContext, "frame_id", context_frame_id, -1); + rb_define_method(cContext, "frame_line", context_frame_line, -1); + rb_define_method(cContext, "frame_locals", context_frame_locals, -1); + rb_define_method(cContext, "frame_method", context_frame_id, -1); + rb_define_method(cContext, "frame_self", context_frame_self, -1); + rb_define_method(cContext, "stack_size", context_stack_size, 0); + rb_define_method(cContext, "dead?", context_dead, 0); + rb_define_method(cContext, "breakpoint", + context_breakpoint, 0); /* in breakpoint.c */ + rb_define_method(cContext, "set_breakpoint", + context_set_breakpoint, -1); /* in breakpoint.c */ +} + +/* + * call-seq: + * Debugger.breakpoints -> array + * + * Returns an array of breakpoints. + */ +static VALUE +debug_breakpoints(VALUE self) +{ + debug_check_started(); + + return rdebug_breakpoints; +} + +/* + * call-seq: + * Debugger.add_breakpoint(source, pos, condition = nil) -> breakpoint + * + * Adds a new breakpoint. + * source is a name of a file or a class. + * pos is a line number or a method name if source is a class name. + * condition is a string which is evaluated to +true+ when this breakpoint + * is activated. + */ +static VALUE +debug_add_breakpoint(int argc, VALUE *argv, VALUE self) +{ + VALUE result; + + debug_check_started(); + + result = create_breakpoint_from_args(argc, argv, ++bkp_count); + rb_ary_push(rdebug_breakpoints, result); + return result; +} + +/* + * Document-class: Debugger + * + * == Summary + * + * This is a singleton class allows controlling the debugger. Use it to start/stop debugger, + * set/remove breakpoints, etc. + */ +#if defined(_WIN32) +__declspec(dllexport) +#endif +void +Init_ruby_debug() +{ + mDebugger = rb_define_module("Debugger"); + rb_define_const(mDebugger, "VERSION", rb_str_new2(DEBUG_VERSION)); + rb_define_module_function(mDebugger, "start_", debug_start, 0); + rb_define_module_function(mDebugger, "stop", debug_stop, 0); + rb_define_module_function(mDebugger, "started?", debug_is_started, 0); + rb_define_module_function(mDebugger, "breakpoints", debug_breakpoints, 0); + rb_define_module_function(mDebugger, "add_breakpoint", debug_add_breakpoint, -1); + rb_define_module_function(mDebugger, "remove_breakpoint", + rdebug_remove_breakpoint, + 1); /* in breakpoint.c */ + rb_define_module_function(mDebugger, "add_catchpoint", + rdebug_add_catchpoint, 1); /* in breakpoint.c */ + rb_define_module_function(mDebugger, "catchpoints", + debug_catchpoints, 0); /* in breakpoint.c */ + rb_define_module_function(mDebugger, "last_context", debug_last_interrupted, 0); + rb_define_module_function(mDebugger, "contexts", debug_contexts, 0); + rb_define_module_function(mDebugger, "current_context", debug_current_context, 0); + rb_define_module_function(mDebugger, "thread_context", debug_thread_context, 1); + rb_define_module_function(mDebugger, "suspend", debug_suspend, 0); + rb_define_module_function(mDebugger, "resume", debug_resume, 0); + rb_define_module_function(mDebugger, "tracing", debug_tracing, 0); + rb_define_module_function(mDebugger, "tracing=", debug_set_tracing, 1); + rb_define_module_function(mDebugger, "debug_load", debug_debug_load, -1); + rb_define_module_function(mDebugger, "skip", debug_skip, 0); + rb_define_module_function(mDebugger, "debug_at_exit", debug_at_exit, 0); + rb_define_module_function(mDebugger, "post_mortem?", debug_post_mortem, 0); + rb_define_module_function(mDebugger, "post_mortem=", debug_set_post_mortem, 1); + rb_define_module_function(mDebugger, "keep_frame_binding?", + debug_keep_frame_binding, 0); + rb_define_module_function(mDebugger, "keep_frame_binding=", + debug_set_keep_frame_binding, 1); + rb_define_module_function(mDebugger, "track_frame_args?", + debug_track_frame_args, 0); + rb_define_module_function(mDebugger, "track_frame_args=", + debug_set_track_frame_args, 1); + rb_define_module_function(mDebugger, "debug", debug_debug, 0); + rb_define_module_function(mDebugger, "debug=", debug_set_debug, 1); + + cThreadsTable = rb_define_class_under(mDebugger, "ThreadsTable", rb_cObject); + + cDebugThread = rb_define_class_under(mDebugger, "DebugThread", rb_cThread); + rb_define_singleton_method(cDebugThread, "inherited", + debug_thread_inherited, 1); + + Init_context(); + Init_breakpoint(); + + idAtBreakpoint = rb_intern("at_breakpoint"); + idAtCatchpoint = rb_intern("at_catchpoint"); + idAtLine = rb_intern("at_line"); + idAtReturn = rb_intern("at_return"); + idAtTracing = rb_intern("at_tracing"); + idList = rb_intern("list"); + + rb_mObjectSpace = rb_const_get(rb_mKernel, rb_intern("ObjectSpace")); + + rb_global_variable(&last_context); + rb_global_variable(&last_thread); + rb_global_variable(&locker); + rb_global_variable(&rdebug_breakpoints); + rb_global_variable(&rdebug_catchpoints); + rb_global_variable(&rdebug_threads_tbl); +} diff --git a/ext/.svn/text-base/ruby_debug.h.svn-base b/ext/.svn/text-base/ruby_debug.h.svn-base new file mode 100644 index 0000000..04a8ae2 --- /dev/null +++ b/ext/.svn/text-base/ruby_debug.h.svn-base @@ -0,0 +1,123 @@ +#include +/* Context info */ +enum ctx_stop_reason {CTX_STOP_NONE, CTX_STOP_STEP, CTX_STOP_BREAKPOINT, + CTX_STOP_CATCHPOINT}; + +/* Context flags */ +#define CTX_FL_SUSPEND (1<<1) +#define CTX_FL_TRACING (1<<2) +#define CTX_FL_SKIPPED (1<<3) +#define CTX_FL_IGNORE (1<<4) +#define CTX_FL_DEAD (1<<5) +#define CTX_FL_WAS_RUNNING (1<<6) +#define CTX_FL_ENABLE_BKPT (1<<7) +#define CTX_FL_STEPPED (1<<8) +#define CTX_FL_FORCE_MOVE (1<<9) + +#define CTX_FL_TEST(c,f) ((c)->flags & (f)) +#define CTX_FL_SET(c,f) do { (c)->flags |= (f); } while (0) +#define CTX_FL_UNSET(c,f) do { (c)->flags &= ~(f); } while (0) + +typedef struct { + int argc; /* Number of arguments a frame should have. */ + VALUE binding; + ID id; + ID orig_id; + int line; + const char * file; + short dead; + VALUE self; + VALUE arg_ary; + union { + struct { + struct FRAME *frame; + struct SCOPE *scope; + struct RVarmap *dyna_vars; + } runtime; + struct { + VALUE args; + VALUE locals; + VALUE arg_ary; + } copy; + } info; +} debug_frame_t; + +typedef struct { + VALUE thread_id; + int thnum; + int flags; + enum ctx_stop_reason stop_reason; + int stop_next; + int dest_frame; + int stop_line; + int stop_frame; + int stack_size; + int stack_len; + debug_frame_t *frames; + const char * last_file; + int last_line; + VALUE breakpoint; +} debug_context_t; + +/* variables in ruby_debug.c */ +extern VALUE mDebugger; +extern VALUE rdebug_breakpoints; +extern VALUE rdebug_catchpoints; +extern VALUE rdebug_threads_tbl; + +/* routines in ruby_debug.c */ +extern int filename_cmp(VALUE source, char *file); + +#define IS_STARTED (rdebug_threads_tbl != Qnil) +static inline void +debug_check_started() +{ + if(!IS_STARTED) + { + rb_raise(rb_eRuntimeError, "Debugger.start is not called yet."); + } +} + +static inline int +classname_cmp(VALUE name, VALUE klass) +{ + VALUE class_name = (Qnil == name) ? rb_str_new2("main") : name; + return (klass != Qnil + && rb_str_cmp(class_name, rb_mod_name(klass)) == 0); +} + +/* Breakpoint information */ +enum bp_type {BP_POS_TYPE, BP_METHOD_TYPE}; +enum hit_condition {HIT_COND_NONE, HIT_COND_GE, HIT_COND_EQ, HIT_COND_MOD}; + +typedef struct { + int id; + enum bp_type type; + VALUE source; + union + { + int line; + ID mid; + } pos; + VALUE expr; + VALUE enabled; + int hit_count; + int hit_value; + enum hit_condition hit_condition; +} debug_breakpoint_t; + +/* routines in breakpoint.c */ +extern int check_breakpoint_expression(VALUE breakpoint, VALUE binding); +extern int check_breakpoint_hit_condition(VALUE breakpoint); +extern VALUE check_breakpoints_by_method(debug_context_t *debug_context, + VALUE klass, ID mid); +extern VALUE check_breakpoints_by_pos(debug_context_t *debug_context, + char *file, int line); +extern VALUE create_breakpoint_from_args(int argc, VALUE *argv, int id); +extern VALUE context_breakpoint(VALUE self); +extern VALUE context_set_breakpoint(int argc, VALUE *argv, VALUE self); +extern VALUE rdebug_add_catchpoint(VALUE self, VALUE value); +extern VALUE debug_catchpoints(VALUE self); +extern VALUE rdebug_remove_breakpoint(VALUE self, VALUE id_value); + +extern void Init_breakpoint(); diff --git a/ext/breakpoint.c b/ext/breakpoint.c new file mode 100644 index 0000000..d3b7b78 --- /dev/null +++ b/ext/breakpoint.c @@ -0,0 +1,579 @@ +#include "ruby_debug.h" + +VALUE rdebug_breakpoints = Qnil; +VALUE rdebug_catchpoints; + +static VALUE cBreakpoint; +static ID idEval; + +static VALUE +eval_expression(VALUE args) +{ + return rb_funcall2(rb_mKernel, idEval, 2, RARRAY(args)->ptr); +} + +int +check_breakpoint_hit_condition(VALUE breakpoint) +{ + debug_breakpoint_t *debug_breakpoint; + + if(breakpoint == Qnil) + return 0; + Data_Get_Struct(breakpoint, debug_breakpoint_t, debug_breakpoint); + + debug_breakpoint->hit_count++; + if (!Qtrue == debug_breakpoint->enabled) return 0; + switch(debug_breakpoint->hit_condition) + { + case HIT_COND_NONE: + return 1; + case HIT_COND_GE: + { + if(debug_breakpoint->hit_count >= debug_breakpoint->hit_value) + return 1; + break; + } + case HIT_COND_EQ: + { + if(debug_breakpoint->hit_count == debug_breakpoint->hit_value) + return 1; + break; + } + case HIT_COND_MOD: + { + if(debug_breakpoint->hit_count % debug_breakpoint->hit_value == 0) + return 1; + break; + } + } + return 0; +} + +static int +check_breakpoint_by_pos(VALUE breakpoint, char *file, int line) +{ + debug_breakpoint_t *debug_breakpoint; + + if(breakpoint == Qnil) + return 0; + Data_Get_Struct(breakpoint, debug_breakpoint_t, debug_breakpoint); + if (!Qtrue == debug_breakpoint->enabled) return 0; + if(debug_breakpoint->type != BP_POS_TYPE) + return 0; + if(debug_breakpoint->pos.line != line) + return 0; + if(filename_cmp(debug_breakpoint->source, file)) + return 1; + return 0; +} + +int +check_breakpoint_by_method(VALUE breakpoint, VALUE klass, ID mid) +{ + debug_breakpoint_t *debug_breakpoint; + + if(breakpoint == Qnil) + return 0; + Data_Get_Struct(breakpoint, debug_breakpoint_t, debug_breakpoint); + if (!Qtrue == debug_breakpoint->enabled) return 0; + if(debug_breakpoint->type != BP_METHOD_TYPE) + return 0; + if(debug_breakpoint->pos.mid != mid) + return 0; + if(classname_cmp(debug_breakpoint->source, klass)) + return 1; + return 0; +} + +VALUE +check_breakpoints_by_pos(debug_context_t *debug_context, char *file, int line) +{ + VALUE breakpoint; + int i; + + if(!CTX_FL_TEST(debug_context, CTX_FL_ENABLE_BKPT)) + return Qnil; + + if(check_breakpoint_by_pos(debug_context->breakpoint, file, line)) + return debug_context->breakpoint; + + if(RARRAY(rdebug_breakpoints)->len == 0) + return Qnil; + for(i = 0; i < RARRAY(rdebug_breakpoints)->len; i++) + { + breakpoint = rb_ary_entry(rdebug_breakpoints, i); + if(check_breakpoint_by_pos(breakpoint, file, line)) + return breakpoint; + } + return Qnil; +} + +VALUE +check_breakpoints_by_method(debug_context_t *debug_context, VALUE klass, ID mid) +{ + VALUE breakpoint; + int i; + + if(!CTX_FL_TEST(debug_context, CTX_FL_ENABLE_BKPT)) + return Qnil; + + if(check_breakpoint_by_method(debug_context->breakpoint, klass, mid)) + return debug_context->breakpoint; + + if(RARRAY(rdebug_breakpoints)->len == 0) + return Qnil; + for(i = 0; i < RARRAY(rdebug_breakpoints)->len; i++) + { + breakpoint = rb_ary_entry(rdebug_breakpoints, i); + if(check_breakpoint_by_method(breakpoint, klass, mid)) + return breakpoint; + } + return Qnil; +} + +int +check_breakpoint_expression(VALUE breakpoint, VALUE binding) +{ + debug_breakpoint_t *debug_breakpoint; + VALUE args, expr_result; + + Data_Get_Struct(breakpoint, debug_breakpoint_t, debug_breakpoint); + if(NIL_P(debug_breakpoint->expr)) + return 1; + + args = rb_ary_new3(2, debug_breakpoint->expr, binding); + expr_result = rb_protect(eval_expression, args, 0); + return RTEST(expr_result); +} + +static void +breakpoint_mark(void *data) +{ + debug_breakpoint_t *breakpoint; + breakpoint = (debug_breakpoint_t *)data; + rb_gc_mark(breakpoint->source); + rb_gc_mark(breakpoint->expr); +} + +VALUE +create_breakpoint_from_args(int argc, VALUE *argv, int id) +{ + VALUE source, pos, expr; + debug_breakpoint_t *breakpoint; + int type; + + if(rb_scan_args(argc, argv, "21", &source, &pos, &expr) == 2) + { + expr = Qnil; + } + type = FIXNUM_P(pos) ? BP_POS_TYPE : BP_METHOD_TYPE; + if(type == BP_POS_TYPE) + source = StringValue(source); + else + pos = StringValue(pos); + breakpoint = ALLOC(debug_breakpoint_t); + breakpoint->id = id; + breakpoint->source = source; + breakpoint->type = type; + if(type == BP_POS_TYPE) + breakpoint->pos.line = FIX2INT(pos); + else + breakpoint->pos.mid = rb_intern(RSTRING(pos)->ptr); + breakpoint->enabled = Qtrue; + breakpoint->expr = NIL_P(expr) ? expr: StringValue(expr); + breakpoint->hit_count = 0; + breakpoint->hit_value = 0; + breakpoint->hit_condition = HIT_COND_NONE; + return Data_Wrap_Struct(cBreakpoint, breakpoint_mark, xfree, breakpoint); +} + +/* + * call-seq: + * Debugger.remove_breakpoint(id) -> breakpoint + * + * Removes breakpoint by its id. + * id is an identificator of a breakpoint. + */ +VALUE +rdebug_remove_breakpoint(VALUE self, VALUE id_value) +{ + int i; + int id; + VALUE breakpoint; + debug_breakpoint_t *debug_breakpoint; + + id = FIX2INT(id_value); + + for( i = 0; i < RARRAY(rdebug_breakpoints)->len; i += 1 ) + { + breakpoint = rb_ary_entry(rdebug_breakpoints, i); + Data_Get_Struct(breakpoint, debug_breakpoint_t, debug_breakpoint); + if(debug_breakpoint->id == id) + { + rb_ary_delete_at(rdebug_breakpoints, i); + return breakpoint; + } + } + return Qnil; +} + +/* + * call-seq: + * Debugger.catchpoints -> hash + * + * Returns a current catchpoints, which is a hash exception names that will + * trigger a debugger when raised. The values are the number of times taht + * catchpoint was hit, initially 0. + */ +VALUE +debug_catchpoints(VALUE self) +{ + debug_check_started(); + + return rdebug_catchpoints; +} + +/* + * call-seq: + * Debugger.catchpoint(string) -> string + * + * Sets catchpoint. Returns the string passed. + */ +VALUE +rdebug_add_catchpoint(VALUE self, VALUE value) +{ + debug_check_started(); + + if (TYPE(value) != T_STRING) { + rb_raise(rb_eTypeError, "value of a catchpoint must be String"); + } + rb_hash_aset(rdebug_catchpoints, rb_str_dup(value), INT2FIX(0)); + return value; +} + +/* + * call-seq: + * context.breakpoint -> breakpoint + * + * Returns a context-specific temporary Breakpoint object. + */ +VALUE +context_breakpoint(VALUE self) +{ + debug_context_t *debug_context; + + debug_check_started(); + + Data_Get_Struct(self, debug_context_t, debug_context); + return debug_context->breakpoint; +} + +/* + * call-seq: + * context.set_breakpoint(source, pos, condition = nil) -> breakpoint + * + * Sets a context-specific temporary breakpoint, which can be used to implement + * 'Run to Cursor' debugger function. When this breakpoint is reached, it will be + * cleared out. + * + * source is a name of a file or a class. + * pos is a line number or a method name if source is a class name. + * condition is a string which is evaluated to +true+ when this breakpoint + * is activated. + */ +VALUE +context_set_breakpoint(int argc, VALUE *argv, VALUE self) +{ + VALUE result; + debug_context_t *debug_context; + + debug_check_started(); + + Data_Get_Struct(self, debug_context_t, debug_context); + result = create_breakpoint_from_args(argc, argv, 0); + debug_context->breakpoint = result; + return result; +} + +/* + * call-seq: + * breakpoint.enabled? + * + * Returns whether breakpoint is enabled or not. + */ +static VALUE +breakpoint_enabled(VALUE self) +{ + debug_breakpoint_t *breakpoint; + + Data_Get_Struct(self, debug_breakpoint_t, breakpoint); + return breakpoint->enabled; +} + +/* + * call-seq: + * breakpoint.enabled = bool + * + * Enables or disables breakpoint. + */ +static VALUE +breakpoint_set_enabled(VALUE self, VALUE bool) +{ + debug_breakpoint_t *breakpoint; + + Data_Get_Struct(self, debug_breakpoint_t, breakpoint); + return breakpoint->enabled = bool; +} + +/* + * call-seq: + * breakpoint.source -> string + * + * Returns a source of the breakpoint. + */ +static VALUE +breakpoint_source(VALUE self) +{ + debug_breakpoint_t *breakpoint; + + Data_Get_Struct(self, debug_breakpoint_t, breakpoint); + return breakpoint->source; +} + +/* + * call-seq: + * breakpoint.source = string + * + * Sets the source of the breakpoint. + */ +static VALUE +breakpoint_set_source(VALUE self, VALUE value) +{ + debug_breakpoint_t *breakpoint; + + Data_Get_Struct(self, debug_breakpoint_t, breakpoint); + breakpoint->source = StringValue(value); + return value; +} + +/* + * call-seq: + * breakpoint.pos -> string or int + * + * Returns the position of this breakpoint. + */ +static VALUE +breakpoint_pos(VALUE self) +{ + debug_breakpoint_t *breakpoint; + + Data_Get_Struct(self, debug_breakpoint_t, breakpoint); + if(breakpoint->type == BP_METHOD_TYPE) + return rb_str_new2(rb_id2name(breakpoint->pos.mid)); + else + return INT2FIX(breakpoint->pos.line); +} + +/* + * call-seq: + * breakpoint.pos = string or int + * + * Sets the position of this breakpoint. + */ +static VALUE +breakpoint_set_pos(VALUE self, VALUE value) +{ + debug_breakpoint_t *breakpoint; + + Data_Get_Struct(self, debug_breakpoint_t, breakpoint); + if(breakpoint->type == BP_METHOD_TYPE) + { + breakpoint->pos.mid = rb_to_id(StringValue(value)); + } + else + breakpoint->pos.line = FIX2INT(value); + return value; +} + +/* + * call-seq: + * breakpoint.expr -> string + * + * Returns a codition expression when this breakpoint should be activated. + */ +static VALUE +breakpoint_expr(VALUE self) +{ + debug_breakpoint_t *breakpoint; + + Data_Get_Struct(self, debug_breakpoint_t, breakpoint); + return breakpoint->expr; +} + +/* + * call-seq: + * breakpoint.expr = string | nil + * + * Sets the codition expression when this breakpoint should be activated. + */ +static VALUE +breakpoint_set_expr(VALUE self, VALUE expr) +{ + debug_breakpoint_t *breakpoint; + + Data_Get_Struct(self, debug_breakpoint_t, breakpoint); + breakpoint->expr = NIL_P(expr) ? expr: StringValue(expr); + return expr; +} + +/* + * call-seq: + * breakpoint.id -> int + * + * Returns id of the breakpoint. + */ +static VALUE +breakpoint_id(VALUE self) +{ + debug_breakpoint_t *breakpoint; + + Data_Get_Struct(self, debug_breakpoint_t, breakpoint); + return INT2FIX(breakpoint->id); +} + +/* + * call-seq: + * breakpoint.hit_count -> int + * + * Returns the hit count of the breakpoint. + */ +static VALUE +breakpoint_hit_count(VALUE self) +{ + debug_breakpoint_t *breakpoint; + + Data_Get_Struct(self, debug_breakpoint_t, breakpoint); + return INT2FIX(breakpoint->hit_count); +} + +/* + * call-seq: + * breakpoint.hit_value -> int + * + * Returns the hit value of the breakpoint. + */ +static VALUE +breakpoint_hit_value(VALUE self) +{ + debug_breakpoint_t *breakpoint; + + Data_Get_Struct(self, debug_breakpoint_t, breakpoint); + return INT2FIX(breakpoint->hit_value); +} + +/* + * call-seq: + * breakpoint.hit_value = int + * + * Sets the hit value of the breakpoint. + */ +static VALUE +breakpoint_set_hit_value(VALUE self, VALUE value) +{ + debug_breakpoint_t *breakpoint; + + Data_Get_Struct(self, debug_breakpoint_t, breakpoint); + breakpoint->hit_value = FIX2INT(value); + return value; +} + +/* + * call-seq: + * breakpoint.hit_condition -> symbol + * + * Returns the hit condition of the breakpoint: + * + * +nil+ if it is an unconditional breakpoint, or + * :greater_or_equal, :equal, :modulo + */ +static VALUE +breakpoint_hit_condition(VALUE self) +{ + debug_breakpoint_t *breakpoint; + + Data_Get_Struct(self, debug_breakpoint_t, breakpoint); + switch(breakpoint->hit_condition) + { + case HIT_COND_GE: + return ID2SYM(rb_intern("greater_or_equal")); + case HIT_COND_EQ: + return ID2SYM(rb_intern("equal")); + case HIT_COND_MOD: + return ID2SYM(rb_intern("modulo")); + case HIT_COND_NONE: + default: + return Qnil; + } +} + +/* + * call-seq: + * breakpoint.hit_condition = symbol + * + * Sets the hit condition of the breakpoint which must be one of the following values: + * + * +nil+ if it is an unconditional breakpoint, or + * :greater_or_equal(:ge), :equal(:eq), :modulo(:mod) + */ +static VALUE +breakpoint_set_hit_condition(VALUE self, VALUE value) +{ + debug_breakpoint_t *breakpoint; + ID id_value; + + Data_Get_Struct(self, debug_breakpoint_t, breakpoint); + id_value = rb_to_id(value); + + if(rb_intern("greater_or_equal") == id_value || rb_intern("ge") == id_value) + breakpoint->hit_condition = HIT_COND_GE; + else if(rb_intern("equal") == id_value || rb_intern("eq") == id_value) + breakpoint->hit_condition = HIT_COND_EQ; + else if(rb_intern("modulo") == id_value || rb_intern("mod") == id_value) + breakpoint->hit_condition = HIT_COND_MOD; + else + rb_raise(rb_eArgError, "Invalid condition parameter"); + return value; +} + +/* + * Document-class: Breakpoint + * + * == Summary + * + * This class represents a breakpoint. It defines position of the breakpoint and + * condition when this breakpoint should be triggered. + */ +void +Init_breakpoint() +{ + cBreakpoint = rb_define_class_under(mDebugger, "Breakpoint", rb_cObject); + rb_define_method(cBreakpoint, "enabled=", breakpoint_set_enabled, 1); + rb_define_method(cBreakpoint, "enabled?", breakpoint_enabled, 0); + rb_define_method(cBreakpoint, "expr", breakpoint_expr, 0); + rb_define_method(cBreakpoint, "expr=", breakpoint_set_expr, 1); + rb_define_method(cBreakpoint, "hit_condition", breakpoint_hit_condition, 0); + rb_define_method(cBreakpoint, "hit_condition=", breakpoint_set_hit_condition, 1); + rb_define_method(cBreakpoint, "hit_count", breakpoint_hit_count, 0); + rb_define_method(cBreakpoint, "hit_value", breakpoint_hit_value, 0); + rb_define_method(cBreakpoint, "hit_value=", breakpoint_set_hit_value, 1); + rb_define_method(cBreakpoint, "id", breakpoint_id, 0); + rb_define_method(cBreakpoint, "pos", breakpoint_pos, 0); + rb_define_method(cBreakpoint, "pos=", breakpoint_set_pos, 1); + rb_define_method(cBreakpoint, "source", breakpoint_source, 0); + rb_define_method(cBreakpoint, "source=", breakpoint_set_source, 1); + idEval = rb_intern("eval"); + rdebug_catchpoints = rb_hash_new(); + +} + + diff --git a/ext/extconf.rb b/ext/extconf.rb new file mode 100644 index 0000000..1bb8e40 --- /dev/null +++ b/ext/extconf.rb @@ -0,0 +1,20 @@ +require "mkmf" + +if RUBY_VERSION >= "1.9" + if RUBY_RELEASE_DATE < "2005-03-17" + STDERR.print("Ruby version is too old\n") + exit(1) + end +elsif RUBY_VERSION >= "1.8" + if RUBY_RELEASE_DATE < "2005-03-22" + STDERR.print("Ruby version is too old\n") + exit(1) + end +else + STDERR.print("Ruby version is too old\n") + exit(1) +end + +# Temporary: to turn off optimization +# $CFLAGS='-fno-strict-aliasing -g -fPIC' +create_makefile("ruby_debug") diff --git a/ext/ruby_debug.c b/ext/ruby_debug.c new file mode 100644 index 0000000..503329a --- /dev/null +++ b/ext/ruby_debug.c @@ -0,0 +1,2322 @@ +#include "ruby_debug.h" + +#include +#include +#include +#include +#include + +#define DEBUG_VERSION "0.10.4" + + +#ifdef _WIN32 +struct FRAME { + VALUE self; + int argc; + ID last_func; + ID orig_func; + VALUE last_class; + struct FRAME *prev; + struct FRAME *tmp; + struct RNode *node; + int iter; + int flags; + unsigned long uniq; +}; + +struct SCOPE { + struct RBasic super; + ID *local_tbl; + VALUE *local_vars; + int flags; +}; + +struct RVarmap { + struct RBasic super; + ID id; + VALUE val; + struct RVarmap *next; +}; + +RUBY_EXTERN struct SCOPE *ruby_scope; +RUBY_EXTERN struct FRAME *ruby_frame; +RUBY_EXTERN struct RVarmap *ruby_dyna_vars; +#else +#include +#endif + +#define FRAME_N(n) (&debug_context->frames[debug_context->stack_size-(n)-1]) +#define GET_FRAME (FRAME_N(check_frame_number(debug_context, frame))) + +#ifndef min +#define min(x,y) ((x) < (y) ? (x) : (y)) +#endif + +#define STACK_SIZE_INCREMENT 128 + +typedef struct { + st_table *tbl; +} threads_table_t; + +static VALUE tracing = Qfalse; +static VALUE locker = Qnil; +static VALUE post_mortem = Qfalse; +static VALUE keep_frame_binding = Qfalse; +static VALUE debug = Qfalse; +static VALUE track_frame_args = Qfalse; + +static VALUE last_context = Qnil; +static VALUE last_thread = Qnil; +static debug_context_t *last_debug_context = NULL; + +VALUE rdebug_threads_tbl = Qnil; /* Context for each of the threads */ +VALUE mDebugger; /* Ruby Debugger Module object */ + +static VALUE cThreadsTable; +static VALUE cContext; +static VALUE cDebugThread; + +static VALUE rb_mObjectSpace; + +static ID idAtBreakpoint; +static ID idAtCatchpoint; +static ID idAtLine; +static ID idAtReturn; +static ID idAtTracing; +static ID idList; + +static int start_count = 0; +static int thnum_max = 0; +static int bkp_count = 0; +static int last_debugged_thnum = -1; +static unsigned long last_check = 0; +static unsigned long hook_count = 0; + +static VALUE create_binding(VALUE); +static VALUE debug_stop(VALUE); +static void save_current_position(debug_context_t *); +static VALUE context_copy_args(debug_frame_t *); +static VALUE context_copy_locals(debug_frame_t *); +static void context_suspend_0(debug_context_t *); +static void context_resume_0(debug_context_t *); +static void copy_scalar_args(debug_frame_t *); + +typedef struct locked_thread_t { + VALUE thread_id; + struct locked_thread_t *next; +} locked_thread_t; + +static locked_thread_t *locked_head = NULL; +static locked_thread_t *locked_tail = NULL; + +/* "Step", "Next" and "Finish" do their work by saving information + about where to stop next. reset_stopping_points removes/resets this + information. */ +inline static void +reset_stepping_stop_points(debug_context_t *debug_context) +{ + debug_context->dest_frame = -1; + debug_context->stop_line = -1; + debug_context->stop_next = -1; +} + +inline static VALUE +real_class(VALUE klass) +{ + if (klass) { + if (TYPE(klass) == T_ICLASS) { + return RBASIC(klass)->klass; + } + else if (FL_TEST(klass, FL_SINGLETON)) { + return rb_iv_get(klass, "__attached__"); + } + } + return klass; +} + +inline static void * +ruby_method_ptr(VALUE class, ID meth_id) +{ + NODE *body, *method; + st_lookup(RCLASS(class)->m_tbl, meth_id, (st_data_t *)&body); + method = (NODE *)body->u2.value; + return (void *)method->u1.value; +} + +inline static VALUE +ref2id(VALUE obj) +{ + return rb_obj_id(obj); +} + +static VALUE +id2ref_unprotected(VALUE id) +{ + typedef VALUE (*id2ref_func_t)(VALUE, VALUE); + static id2ref_func_t f_id2ref = NULL; + if(f_id2ref == NULL) + { + f_id2ref = (id2ref_func_t)ruby_method_ptr(rb_mObjectSpace, rb_intern("_id2ref")); + } + return f_id2ref(rb_mObjectSpace, id); +} + +static VALUE +id2ref_error() +{ + if(debug == Qtrue) + rb_p(ruby_errinfo); + return Qnil; +} + +static VALUE +id2ref(VALUE id) +{ + return rb_rescue(id2ref_unprotected, id, id2ref_error, 0); +} + +inline static VALUE +context_thread_0(debug_context_t *debug_context) +{ + return id2ref(debug_context->thread_id); +} + +static int +is_in_locked(VALUE thread_id) +{ + locked_thread_t *node; + + if(!locked_head) + return 0; + + for(node = locked_head; node != locked_tail; node = node->next) + { + if(node->thread_id == thread_id) return 1; + } + return 0; +} + +static void +add_to_locked(VALUE thread) +{ + locked_thread_t *node; + VALUE thread_id = ref2id(thread); + + if(is_in_locked(thread_id)) + return; + + node = ALLOC(locked_thread_t); + node->thread_id = thread_id; + node->next = NULL; + if(locked_tail) + locked_tail->next = node; + locked_tail = node; + if(!locked_head) + locked_head = node; +} + +static VALUE +remove_from_locked() +{ + VALUE thread; + locked_thread_t *node; + + if(locked_head == NULL) + return Qnil; + node = locked_head; + locked_head = locked_head->next; + if(locked_tail == node) + locked_tail = NULL; + thread = id2ref(node->thread_id); + xfree(node); + return thread; +} + +static int +threads_table_mark_keyvalue(VALUE key, VALUE value, int dummy) +{ + rb_gc_mark(value); + return ST_CONTINUE; +} + +static void +threads_table_mark(void* data) +{ + threads_table_t *threads_table = (threads_table_t*)data; + st_foreach(threads_table->tbl, threads_table_mark_keyvalue, 0); +} + +static void +threads_table_free(void* data) +{ + threads_table_t *threads_table = (threads_table_t*)data; + st_free_table(threads_table->tbl); + xfree(threads_table); +} + +static VALUE +threads_table_create() +{ + threads_table_t *threads_table; + + threads_table = ALLOC(threads_table_t); + threads_table->tbl = st_init_numtable(); + return Data_Wrap_Struct(cThreadsTable, threads_table_mark, threads_table_free, threads_table); +} + +static int +threads_table_clear_i(VALUE key, VALUE value, VALUE dummy) +{ + return ST_DELETE; +} + +static void +threads_table_clear(VALUE table) +{ + threads_table_t *threads_table; + + Data_Get_Struct(table, threads_table_t, threads_table); + st_foreach(threads_table->tbl, threads_table_clear_i, 0); +} + +static VALUE +is_thread_alive(VALUE thread) +{ + typedef VALUE (*thread_alive_func_t)(VALUE); + static thread_alive_func_t f_thread_alive = NULL; + if(!f_thread_alive) + { + f_thread_alive = (thread_alive_func_t)ruby_method_ptr(rb_cThread, rb_intern("alive?")); + } + return f_thread_alive(thread); +} + +static int +threads_table_check_i(VALUE key, VALUE value, VALUE dummy) +{ + VALUE thread; + + thread = id2ref(key); + if(!rb_obj_is_kind_of(thread, rb_cThread)) + { + return ST_DELETE; + } + if(rb_protect(is_thread_alive, thread, 0) != Qtrue) + { + return ST_DELETE; + } + return ST_CONTINUE; +} + +static void +check_thread_contexts() +{ + threads_table_t *threads_table; + + Data_Get_Struct(rdebug_threads_tbl, threads_table_t, threads_table); + st_foreach(threads_table->tbl, threads_table_check_i, 0); +} + +/* + * call-seq: + * Debugger.started? -> bool + * + * Returns +true+ the debugger is started. + */ +static VALUE +debug_is_started(VALUE self) +{ + return IS_STARTED ? Qtrue : Qfalse; +} + +static void +debug_context_mark(void *data) +{ + debug_frame_t *frame; + int i; + + debug_context_t *debug_context = (debug_context_t *)data; + for(i = 0; i < debug_context->stack_size; i++) + { + frame = &(debug_context->frames[i]); + rb_gc_mark(frame->binding); + rb_gc_mark(frame->self); + rb_gc_mark(frame->arg_ary); + if(frame->dead) + { + rb_gc_mark(frame->info.copy.locals); + rb_gc_mark(frame->info.copy.args); + } + } + rb_gc_mark(debug_context->breakpoint); +} + +static void +debug_context_free(void *data) +{ + debug_context_t *debug_context = (debug_context_t *)data; + xfree(debug_context->frames); +} + +static VALUE +debug_context_create(VALUE thread) +{ + debug_context_t *debug_context; + + debug_context = ALLOC(debug_context_t); + debug_context-> thnum = ++thnum_max; + + debug_context->last_file = NULL; + debug_context->last_line = 0; + debug_context->flags = 0; + + debug_context->stop_next = -1; + debug_context->dest_frame = -1; + debug_context->stop_line = -1; + debug_context->stop_frame = -1; + debug_context->stop_reason = CTX_STOP_NONE; + debug_context->stack_len = STACK_SIZE_INCREMENT; + debug_context->frames = ALLOC_N(debug_frame_t, STACK_SIZE_INCREMENT); + debug_context->stack_size = 0; + debug_context->thread_id = ref2id(thread); + debug_context->breakpoint = Qnil; + if(rb_obj_class(thread) == cDebugThread) + CTX_FL_SET(debug_context, CTX_FL_IGNORE); + return Data_Wrap_Struct(cContext, debug_context_mark, debug_context_free, debug_context); +} + +static VALUE +debug_context_dup(debug_context_t *debug_context) +{ + debug_context_t *new_debug_context; + debug_frame_t *new_frame, *old_frame; + int i; + + new_debug_context = ALLOC(debug_context_t); + memcpy(new_debug_context, debug_context, sizeof(debug_context_t)); + new_debug_context->stop_next = -1; + new_debug_context->dest_frame = -1; + new_debug_context->stop_line = -1; + new_debug_context->stop_frame = -1; + new_debug_context->breakpoint = Qnil; + CTX_FL_SET(new_debug_context, CTX_FL_DEAD); + new_debug_context->frames = ALLOC_N(debug_frame_t, debug_context->stack_size); + new_debug_context->stack_len = debug_context->stack_size; + memcpy(new_debug_context->frames, debug_context->frames, sizeof(debug_frame_t) * debug_context->stack_size); + for(i = 0; i < debug_context->stack_size; i++) + { + new_frame = &(new_debug_context->frames[i]); + old_frame = &(debug_context->frames[i]); + new_frame->dead = 1; + new_frame->info.copy.args = context_copy_args(old_frame); + new_frame->info.copy.locals = context_copy_locals(old_frame); + } + return Data_Wrap_Struct(cContext, debug_context_mark, debug_context_free, new_debug_context); +} + +static void +thread_context_lookup(VALUE thread, VALUE *context, debug_context_t **debug_context) +{ + threads_table_t *threads_table; + VALUE thread_id; + debug_context_t *l_debug_context; + + debug_check_started(); + + if(last_thread == thread && last_context != Qnil) + { + *context = last_context; + if(debug_context) + *debug_context = last_debug_context; + return; + } + thread_id = ref2id(thread); + Data_Get_Struct(rdebug_threads_tbl, threads_table_t, threads_table); + if(!st_lookup(threads_table->tbl, thread_id, context)) + { + *context = debug_context_create(thread); + st_insert(threads_table->tbl, thread_id, *context); + } + + Data_Get_Struct(*context, debug_context_t, l_debug_context); + if(debug_context) + *debug_context = l_debug_context; + + last_thread = thread; + last_context = *context; + last_debug_context = l_debug_context; +} + +static VALUE +call_at_line_unprotected(VALUE args) +{ + VALUE context; + context = *RARRAY(args)->ptr; + return rb_funcall2(context, idAtLine, RARRAY(args)->len - 1, RARRAY(args)->ptr + 1); +} + +static VALUE +call_at_line(VALUE context, debug_context_t *debug_context, VALUE file, VALUE line) +{ + VALUE args; + + last_debugged_thnum = debug_context->thnum; + save_current_position(debug_context); + + args = rb_ary_new3(3, context, file, line); + return rb_protect(call_at_line_unprotected, args, 0); +} + +static void +save_call_frame(rb_event_t event, VALUE self, char *file, int line, ID mid, debug_context_t *debug_context) +{ + VALUE binding; + debug_frame_t *debug_frame; + int frame_n; + + binding = self && RTEST(keep_frame_binding)? create_binding(self) : Qnil; + + frame_n = debug_context->stack_size++; + if(frame_n >= debug_context->stack_len) + { + debug_context->stack_len += STACK_SIZE_INCREMENT; + debug_context->frames = REALLOC_N(debug_context->frames, debug_frame_t, debug_context->stack_len); + } + debug_frame = &debug_context->frames[frame_n]; + debug_frame->argc = ruby_frame->argc; + debug_frame->file = file; + debug_frame->line = line; + debug_frame->binding = binding; + debug_frame->id = mid; + debug_frame->orig_id = mid; + debug_frame->dead = 0; + debug_frame->self = self; + debug_frame->arg_ary = Qnil; + debug_frame->info.runtime.frame = ruby_frame; + debug_frame->info.runtime.scope = ruby_scope; + debug_frame->info.runtime.dyna_vars = event == RUBY_EVENT_LINE ? ruby_dyna_vars : NULL; + if (RTEST(track_frame_args)) + copy_scalar_args(debug_frame); +} + + +#if defined DOSISH +#define isdirsep(x) ((x) == '/' || (x) == '\\') +#else +#define isdirsep(x) ((x) == '/') +#endif + +int +filename_cmp(VALUE source, char *file) +{ + char *source_ptr, *file_ptr; + int s_len, f_len, min_len; + int s,f; + int dirsep_flag = 0; + + s_len = RSTRING(source)->len; + f_len = strlen(file); + min_len = min(s_len, f_len); + + source_ptr = RSTRING(source)->ptr; + file_ptr = file; + + for( s = s_len - 1, f = f_len - 1; s >= s_len - min_len && f >= f_len - min_len; s--, f-- ) + { + if((source_ptr[s] == '.' || file_ptr[f] == '.') && dirsep_flag) + return 1; + if(isdirsep(source_ptr[s]) && isdirsep(file_ptr[f])) + dirsep_flag = 1; + else if(source_ptr[s] != file_ptr[f]) + return 0; + } + return 1; +} + +/* + * This is a NASTY HACK. For some reasons rb_f_binding is declared + * static in eval.c. So we create a cons up call to binding in C. + */ +static VALUE +create_binding(VALUE self) +{ + typedef VALUE (*bind_func_t)(VALUE); + static bind_func_t f_binding = NULL; + + if(f_binding == NULL) + { + f_binding = (bind_func_t)ruby_method_ptr(rb_mKernel, rb_intern("binding")); + } + return f_binding(self); +} + +inline static debug_frame_t * +get_top_frame(debug_context_t *debug_context) +{ + if(debug_context->stack_size == 0) + return NULL; + else + return &(debug_context->frames[debug_context->stack_size-1]); +} + +inline static void +save_top_binding(debug_context_t *debug_context, VALUE binding) +{ + debug_frame_t *debug_frame; + debug_frame = get_top_frame(debug_context); + if(debug_frame) + debug_frame->binding = binding; +} + +inline static void +set_frame_source(rb_event_t event, debug_context_t *debug_context, VALUE self, char *file, int line, ID mid) +{ + debug_frame_t *top_frame; + top_frame = get_top_frame(debug_context); + if(top_frame) + { + top_frame->self = self; + top_frame->file = file; + top_frame->line = line; + top_frame->id = mid; + top_frame->info.runtime.dyna_vars = event == RUBY_EVENT_C_CALL ? NULL : ruby_dyna_vars; + } +} + +inline static void +reset_frame_mid(debug_context_t *debug_context) +{ + debug_frame_t *top_frame; + top_frame = get_top_frame(debug_context); + if(top_frame) + { + top_frame->id = 0; + } +} + +static void +save_current_position(debug_context_t *debug_context) +{ + debug_frame_t *debug_frame; + + debug_frame = get_top_frame(debug_context); + if(!debug_frame) return; + debug_context->last_file = debug_frame->file; + debug_context->last_line = debug_frame->line; + CTX_FL_UNSET(debug_context, CTX_FL_ENABLE_BKPT); + CTX_FL_UNSET(debug_context, CTX_FL_STEPPED); + CTX_FL_UNSET(debug_context, CTX_FL_FORCE_MOVE); +} + +inline static char * +get_event_name(rb_event_t event) +{ + switch (event) { + case RUBY_EVENT_LINE: + return "line"; + case RUBY_EVENT_CLASS: + return "class"; + case RUBY_EVENT_END: + return "end"; + case RUBY_EVENT_CALL: + return "call"; + case RUBY_EVENT_RETURN: + return "return"; + case RUBY_EVENT_C_CALL: + return "c-call"; + case RUBY_EVENT_C_RETURN: + return "c-return"; + case RUBY_EVENT_RAISE: + return "raise"; + default: + return "unknown"; + } +} + +inline static int +c_call_new_frame_p(VALUE klass, ID mid) +{ + klass = real_class(klass); + if(rb_block_given_p()) return 1; + if(klass == rb_cProc || klass == rb_mKernel || klass == rb_cModule) return 1; + return 0; +} + +static void +debug_event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass) +{ + VALUE thread, context; + VALUE breakpoint = Qnil, binding = Qnil; + debug_context_t *debug_context; + char *file = NULL; + int line = 0, moved = 0; + + hook_count++; + + if (mid == ID_ALLOCATOR) return; + + thread = rb_thread_current(); + thread_context_lookup(thread, &context, &debug_context); + + /* return if thread is marked as 'ignored'. + debugger's threads are marked this way + */ + if(CTX_FL_TEST(debug_context, CTX_FL_IGNORE)) return; + + while(1) + { + /* halt execution of the current thread if the debugger + is activated in another + */ + while(locker != Qnil && locker != thread) + { + add_to_locked(thread); + rb_thread_stop(); + } + + /* stop the current thread if it's marked as suspended */ + if(CTX_FL_TEST(debug_context, CTX_FL_SUSPEND) && locker != thread) + { + CTX_FL_SET(debug_context, CTX_FL_WAS_RUNNING); + rb_thread_stop(); + } + else break; + } + + /* return if the current thread is the locker */ + if(locker != Qnil) return; + + /* only the current thread can proceed */ + locker = thread; + + /* ignore a skipped section of code */ + if(CTX_FL_TEST(debug_context, CTX_FL_SKIPPED)) goto cleanup; + + if(node) + { + file = node->nd_file; + line = nd_line(node); + + if(debug == Qtrue) + fprintf(stderr, "%s:%d [%s] %s\n", file, line, get_event_name(event), rb_id2name(mid)); + + /* There can be many event calls per line, but we only want + *one* breakpoint per line. */ + if(debug_context->last_line != line || debug_context->last_file == NULL || + strcmp(debug_context->last_file, file) != 0) + { + CTX_FL_SET(debug_context, CTX_FL_ENABLE_BKPT); + moved = 1; + } + else if(event == RUBY_EVENT_LINE) + { + /* There are two line-event trace hook calls per IF node - one + before the expression eval an done afterwards. + */ + /* FIXME: the static variable can't be safely used here, since this method + is re-entrant by multiple threads. If we want to provide this kind of functionality + if_eval_event variable must be moved to debug_context structure. + */ + /* + static int if_eval_event = 0; + if_eval_event = (NODE_IF == nd_type(node)) ? !if_eval_event : 0; + if (!if_eval_event) + { + CTX_FL_SET(debug_context, CTX_FL_ENABLE_BKPT); + } + */ + } + } + else if(event != RUBY_EVENT_RETURN && event != RUBY_EVENT_C_RETURN) + { + if(debug == Qtrue) + fprintf(stderr, "nodeless [%s] %s\n", get_event_name(event), rb_id2name(mid)); + goto cleanup; + } + else + { + if(debug == Qtrue) + fprintf(stderr, "nodeless [%s] %s\n", get_event_name(event), rb_id2name(mid)); + } + + if(event != RUBY_EVENT_LINE) + CTX_FL_SET(debug_context, CTX_FL_STEPPED); + + switch(event) + { + case RUBY_EVENT_LINE: + { + + if(debug_context->stack_size == 0) + save_call_frame(event, self, file, line, mid, debug_context); + else + set_frame_source(event, debug_context, self, file, line, mid); + + if(RTEST(tracing) || CTX_FL_TEST(debug_context, CTX_FL_TRACING)) + rb_funcall(context, idAtTracing, 2, rb_str_new2(file), INT2FIX(line)); + + if(debug_context->dest_frame == -1 || + debug_context->stack_size == debug_context->dest_frame) + { + if(moved || !CTX_FL_TEST(debug_context, CTX_FL_FORCE_MOVE)) + debug_context->stop_next--; + if(debug_context->stop_next < 0) + debug_context->stop_next = -1; + if(moved || (CTX_FL_TEST(debug_context, CTX_FL_STEPPED) && + !CTX_FL_TEST(debug_context, CTX_FL_FORCE_MOVE))) + { + debug_context->stop_line--; + CTX_FL_UNSET(debug_context, CTX_FL_STEPPED); + } + } + else if(debug_context->stack_size < debug_context->dest_frame) + { + debug_context->stop_next = 0; + } + + if(debug_context->stop_next == 0 || debug_context->stop_line == 0 || + (breakpoint = check_breakpoints_by_pos(debug_context, file, line)) != Qnil) + { + binding = self? create_binding(self) : Qnil; + save_top_binding(debug_context, binding); + + debug_context->stop_reason = CTX_STOP_STEP; + + /* check breakpoint expression */ + if(breakpoint != Qnil) + { + if(!check_breakpoint_expression(breakpoint, binding)) + break; + if(!check_breakpoint_hit_condition(breakpoint)) + break; + if(breakpoint != debug_context->breakpoint) + { + debug_context->stop_reason = CTX_STOP_BREAKPOINT; + rb_funcall(context, idAtBreakpoint, 1, breakpoint); + } + else + debug_context->breakpoint = Qnil; + } + + reset_stepping_stop_points(debug_context); + call_at_line(context, debug_context, rb_str_new2(file), INT2FIX(line)); + } + break; + } + case RUBY_EVENT_CALL: + { + save_call_frame(event, self, file, line, mid, debug_context); + breakpoint = check_breakpoints_by_method(debug_context, klass, mid); + if(breakpoint != Qnil) + { + debug_frame_t *debug_frame; + debug_frame = get_top_frame(debug_context); + if(debug_frame) + binding = debug_frame->binding; + if(NIL_P(binding) && self) + binding = create_binding(self); + save_top_binding(debug_context, binding); + + if(!check_breakpoint_expression(breakpoint, binding)) + break; + if(!check_breakpoint_hit_condition(breakpoint)) + break; + if(breakpoint != debug_context->breakpoint) + { + debug_context->stop_reason = CTX_STOP_BREAKPOINT; + rb_funcall(context, idAtBreakpoint, 1, breakpoint); + } + else + debug_context->breakpoint = Qnil; + call_at_line(context, debug_context, rb_str_new2(file), INT2FIX(line)); + } + break; + } + case RUBY_EVENT_C_CALL: + { + if(c_call_new_frame_p(klass, mid)) + save_call_frame(event, self, file, line, mid, debug_context); + else + set_frame_source(event, debug_context, self, file, line, mid); + break; + } + case RUBY_EVENT_C_RETURN: + { + /* note if a block is given we fall through! */ + if(!node || !c_call_new_frame_p(klass, mid)) + break; + } + case RUBY_EVENT_RETURN: + case RUBY_EVENT_END: + { + if(debug_context->stack_size == debug_context->stop_frame) + { + debug_context->stop_next = 1; + debug_context->stop_frame = 0; + /* NOTE: can't use call_at_line function here to trigger a debugger event. + this can lead to segfault. We should only unroll the stack on this event. + */ + } + while(debug_context->stack_size > 0) + { + debug_context->stack_size--; + if(debug_context->frames[debug_context->stack_size].orig_id == mid) + break; + } + CTX_FL_SET(debug_context, CTX_FL_ENABLE_BKPT); + break; + } + case RUBY_EVENT_CLASS: + { + reset_frame_mid(debug_context); + save_call_frame(event, self, file, line, mid, debug_context); + break; + } + case RUBY_EVENT_RAISE: + { + VALUE ancestors; + VALUE expn_class, aclass; + int i; + + set_frame_source(event, debug_context, self, file, line, mid); + + if(post_mortem == Qtrue && self) + { + binding = create_binding(self); + rb_ivar_set(ruby_errinfo, rb_intern("@__debug_file"), rb_str_new2(file)); + rb_ivar_set(ruby_errinfo, rb_intern("@__debug_line"), INT2FIX(line)); + rb_ivar_set(ruby_errinfo, rb_intern("@__debug_binding"), binding); + rb_ivar_set(ruby_errinfo, rb_intern("@__debug_context"), debug_context_dup(debug_context)); + } + + expn_class = rb_obj_class(ruby_errinfo); + + /* This code goes back to the earliest days of ruby-debug. It + tends to disallow catching an exception via the + "catchpoint" command. To address this one possiblilty is to + move this after testing for catchponts. Kent however thinks + there may be a misfeature in Ruby's eval.c: the problem was + in the fact that Ruby doesn't reset exception flag on the + current thread before it calls a notification handler. + + See also the #ifdef'd code below as well. + */ +#ifdef NORMAL_CODE + if( !NIL_P(rb_class_inherited_p(expn_class, rb_eSystemExit)) ) + { + debug_stop(mDebugger); + break; + } +#endif + + if (rdebug_catchpoints == Qnil || + RHASH(rdebug_catchpoints)->tbl->num_entries == 0) + break; + + ancestors = rb_mod_ancestors(expn_class); + for(i = 0; i < RARRAY(ancestors)->len; i++) + { + VALUE mod_name; + VALUE hit_count; + + aclass = rb_ary_entry(ancestors, i); + mod_name = rb_mod_name(aclass); + hit_count = rb_hash_aref(rdebug_catchpoints, mod_name); + if(hit_count != Qnil) + { + hit_count = INT2FIX(FIX2INT(rb_hash_aref(rdebug_catchpoints, + mod_name)+1)); + rb_hash_aset(rdebug_catchpoints, mod_name, hit_count); + debug_context->stop_reason = CTX_STOP_CATCHPOINT; + rb_funcall(context, idAtCatchpoint, 1, ruby_errinfo); + if(self && binding == Qnil) + binding = create_binding(self); + save_top_binding(debug_context, binding); + call_at_line(context, debug_context, rb_str_new2(file), INT2FIX(line)); + break; + } + } + + /* If we stop the debugger, we may not be able to trace into + code that has an exception handler wrapped around it. So + the alternative is to force the user to do his own + Debugger.stop. */ +#ifdef NORMAL_CODE_MOVING_AFTER_ + if( !NIL_P(rb_class_inherited_p(expn_class, rb_eSystemExit)) ) + { + debug_stop(mDebugger); + break; + } +#endif + + break; + } + } + + cleanup: + + debug_context->stop_reason = CTX_STOP_NONE; + + /* check that all contexts point to alive threads */ + if(hook_count - last_check > 3000) + { + check_thread_contexts(); + last_check = hook_count; + } + + /* release a lock */ + locker = Qnil; + /* let the next thread to run */ + thread = remove_from_locked(); + if(thread != Qnil) + rb_thread_run(thread); +} + +static VALUE +debug_stop_i(VALUE self) +{ + if(IS_STARTED) + debug_stop(self); + return Qnil; +} + +/* + * call-seq: + * Debugger.start_ -> bool + * Debugger.start_ { ... } -> bool + * + * This method is internal and activates the debugger. Use + * Debugger.start (from lib/ruby-debug-base.rb) instead. + * + * The return value is the value of !Debugger.started? before + * issuing the +start+; That is, +true+ is returned, unless debugger + * was previously started. + + * If a block is given, it starts debugger and yields to block. When + * the block is finished executing it stops the debugger with + * Debugger.stop method. Inside the block you will probably want to + * have a call to Debugger.debugger. For example: + * Debugger.start{debugger; foo} # Stop inside of foo + * + * Also, ruby-debug only allows + * one invocation of debugger at a time; nested Debugger.start's + * have no effect and you can't use this inside the debugger itself. + * + * Note that if you want to completely remove the debugger hook, + * you must call Debugger.stop as many times as you called + * Debugger.start method. + */ +static VALUE +debug_start(VALUE self) +{ + VALUE result; + start_count++; + + if(IS_STARTED) + result = Qfalse; + else + { + locker = Qnil; + rdebug_breakpoints = rb_ary_new(); + rdebug_catchpoints = rb_hash_new(); + rdebug_threads_tbl = threads_table_create(); + + rb_add_event_hook(debug_event_hook, RUBY_EVENT_ALL); + result = Qtrue; + } + + if(rb_block_given_p()) + rb_ensure(rb_yield, self, debug_stop_i, self); + + return result; +} + +/* + * call-seq: + * Debugger.stop -> bool + * + * This method disables the debugger. It returns +true+ if the debugger is disabled, + * otherwise it returns +false+. + * + * Note that if you want to complete remove the debugger hook, + * you must call Debugger.stop as many times as you called + * Debugger.start method. + */ +static VALUE +debug_stop(VALUE self) +{ + debug_check_started(); + + start_count--; + if(start_count) + return Qfalse; + + rb_remove_event_hook(debug_event_hook); + + locker = Qnil; + rdebug_breakpoints = Qnil; + rdebug_threads_tbl = Qnil; + + return Qtrue; +} + +static int +find_last_context_func(VALUE key, VALUE value, VALUE *result) +{ + debug_context_t *debug_context; + Data_Get_Struct(value, debug_context_t, debug_context); + if(debug_context->thnum == last_debugged_thnum) + { + *result = value; + return ST_STOP; + } + return ST_CONTINUE; +} + +/* + * call-seq: + * Debugger.last_interrupted -> context + * + * Returns last debugged context. + */ +static VALUE +debug_last_interrupted(VALUE self) +{ + VALUE result = Qnil; + threads_table_t *threads_table; + + debug_check_started(); + + Data_Get_Struct(rdebug_threads_tbl, threads_table_t, threads_table); + + st_foreach(threads_table->tbl, find_last_context_func, (st_data_t)&result); + return result; +} + +/* + * call-seq: + * Debugger.current_context -> context + * + * Returns current context. + * Note: Debugger.current_context.thread == Thread.current + */ +static VALUE +debug_current_context(VALUE self) +{ + VALUE thread, context; + + debug_check_started(); + + thread = rb_thread_current(); + thread_context_lookup(thread, &context, NULL); + + return context; +} + +/* + * call-seq: + * Debugger.thread_context(thread) -> context + * + * Returns context of the thread passed as an argument. + */ +static VALUE +debug_thread_context(VALUE self, VALUE thread) +{ + VALUE context; + + debug_check_started(); + thread_context_lookup(thread, &context, NULL); + return context; +} + +/* + * call-seq: + * Debugger.contexts -> array + * + * Returns an array of all contexts. + */ +static VALUE +debug_contexts(VALUE self) +{ + volatile VALUE list; + volatile VALUE new_list; + VALUE thread, context; + threads_table_t *threads_table; + debug_context_t *debug_context; + int i; + + debug_check_started(); + + new_list = rb_ary_new(); + list = rb_funcall(rb_cThread, idList, 0); + for(i = 0; i < RARRAY(list)->len; i++) + { + thread = rb_ary_entry(list, i); + thread_context_lookup(thread, &context, NULL); + rb_ary_push(new_list, context); + } + threads_table_clear(rdebug_threads_tbl); + Data_Get_Struct(rdebug_threads_tbl, threads_table_t, threads_table); + for(i = 0; i < RARRAY(new_list)->len; i++) + { + context = rb_ary_entry(new_list, i); + Data_Get_Struct(context, debug_context_t, debug_context); + st_insert(threads_table->tbl, debug_context->thread_id, context); + } + + return new_list; +} + +/* + * call-seq: + * Debugger.suspend -> Debugger + * + * Suspends all contexts. + */ +static VALUE +debug_suspend(VALUE self) +{ + VALUE current, context; + VALUE saved_crit; + VALUE context_list; + debug_context_t *debug_context; + int i; + + debug_check_started(); + + saved_crit = rb_thread_critical; + rb_thread_critical = Qtrue; + context_list = debug_contexts(self); + thread_context_lookup(rb_thread_current(), ¤t, NULL); + + for(i = 0; i < RARRAY(context_list)->len; i++) + { + context = rb_ary_entry(context_list, i); + if(current == context) + continue; + Data_Get_Struct(context, debug_context_t, debug_context); + context_suspend_0(debug_context); + } + rb_thread_critical = saved_crit; + + if(rb_thread_critical == Qfalse) + rb_thread_schedule(); + + return self; +} + +/* + * call-seq: + * Debugger.resume -> Debugger + * + * Resumes all contexts. + */ +static VALUE +debug_resume(VALUE self) +{ + VALUE current, context; + VALUE saved_crit; + VALUE context_list; + debug_context_t *debug_context; + int i; + + debug_check_started(); + + saved_crit = rb_thread_critical; + rb_thread_critical = Qtrue; + context_list = debug_contexts(self); + + thread_context_lookup(rb_thread_current(), ¤t, NULL); + for(i = 0; i < RARRAY(context_list)->len; i++) + { + context = rb_ary_entry(context_list, i); + if(current == context) + continue; + Data_Get_Struct(context, debug_context_t, debug_context); + context_resume_0(debug_context); + } + rb_thread_critical = saved_crit; + + rb_thread_schedule(); + + return self; +} + +/* + * call-seq: + * Debugger.tracing -> bool + * + * Returns +true+ if the global tracing is activated. + */ +static VALUE +debug_tracing(VALUE self) +{ + return tracing; +} + +/* + * call-seq: + * Debugger.tracing = bool + * + * Sets the global tracing flag. + */ +static VALUE +debug_set_tracing(VALUE self, VALUE value) +{ + tracing = RTEST(value) ? Qtrue : Qfalse; + return value; +} + +/* + * call-seq: + * Debugger.post_mortem? -> bool + * + * Returns +true+ if post-moterm debugging is enabled. + */ +static VALUE +debug_post_mortem(VALUE self) +{ + return post_mortem; +} + +/* + * call-seq: + * Debugger.post_mortem = bool + * + * Sets post-moterm flag. + * FOR INTERNAL USE ONLY. + */ +static VALUE +debug_set_post_mortem(VALUE self, VALUE value) +{ + debug_check_started(); + + post_mortem = RTEST(value) ? Qtrue : Qfalse; + return value; +} + +/* + * call-seq: + * Debugger.track_fame_args? -> bool + * + * Returns +true+ if the debugger track frame argument values on calls. + */ +static VALUE +debug_track_frame_args(VALUE self) +{ + return track_frame_args; +} + +/* + * call-seq: + * Debugger.track_frame_args = bool + * + * Setting to +true+ will make the debugger save argument info on calls. + */ +static VALUE +debug_set_track_frame_args(VALUE self, VALUE value) +{ + track_frame_args = RTEST(value) ? Qtrue : Qfalse; + return value; +} + +/* + * call-seq: + * Debugger.keep_frame_binding? -> bool + * + * Returns +true+ if the debugger will collect frame bindings. + */ +static VALUE +debug_keep_frame_binding(VALUE self) +{ + return keep_frame_binding; +} + +/* + * call-seq: + * Debugger.keep_frame_binding = bool + * + * Setting to +true+ will make the debugger create frame bindings. + */ +static VALUE +debug_set_keep_frame_binding(VALUE self, VALUE value) +{ + keep_frame_binding = RTEST(value) ? Qtrue : Qfalse; + return value; +} + +/* :nodoc: */ +static VALUE +debug_debug(VALUE self) +{ + return debug; +} + +/* :nodoc: */ +static VALUE +debug_set_debug(VALUE self, VALUE value) +{ + debug = RTEST(value) ? Qtrue : Qfalse; + return value; +} + +/* :nodoc: */ +static VALUE +debug_thread_inherited(VALUE klass) +{ + rb_raise(rb_eRuntimeError, "Can't inherite Debugger::DebugThread class"); +} + +/* + * call-seq: + * Debugger.debug_load(file, stop = false, increment_start = false) -> nil + * + * Same as Kernel#load but resets current context's frames. + * +stop+ parameter forces the debugger to stop at the first line of code in the +file+ + * +increment_start+ determines if start_count should be incremented. When + * control threads are used, they have to be set up before loading the + * debugger; so here +increment_start+ will be false. + * FOR INTERNAL USE ONLY. + */ +static VALUE +debug_debug_load(int argc, VALUE *argv, VALUE self) +{ + VALUE file, stop, context, increment_start; + debug_context_t *debug_context; + int state = 0; + + if(rb_scan_args(argc, argv, "12", &file, &stop, &increment_start) == 1) + { + stop = Qfalse; + increment_start = Qtrue; + } + + debug_start(self); + if (Qfalse == increment_start) start_count--; + + context = debug_current_context(self); + Data_Get_Struct(context, debug_context_t, debug_context); + debug_context->stack_size = 0; + if(RTEST(stop)) + debug_context->stop_next = 1; + /* Initializing $0 to the script's path */ + ruby_script(RSTRING(file)->ptr); + rb_load_protect(file, 0, &state); + if (0 != state) { + VALUE errinfo = ruby_errinfo; + debug_suspend(self); + reset_stepping_stop_points(debug_context); + ruby_errinfo = Qnil; + return errinfo; + } + + /* We should run all at_exit handler's in order to provide, + * for instance, a chance to run all defined test cases */ + rb_exec_end_proc(); + + /* We could have issued a Debugger.stop inside the debug + session. */ + if (start_count > 0) { + debug_stop(self); + } + + return Qnil; +} + +static VALUE +set_current_skipped_status(VALUE status) +{ + VALUE context; + debug_context_t *debug_context; + + context = debug_current_context(Qnil); + Data_Get_Struct(context, debug_context_t, debug_context); + if(status) + CTX_FL_SET(debug_context, CTX_FL_SKIPPED); + else + CTX_FL_UNSET(debug_context, CTX_FL_SKIPPED); + return Qnil; +} + +/* + * call-seq: + * Debugger.skip { block } -> obj or nil + * + * The code inside of the block is escaped from the debugger. + */ +static VALUE +debug_skip(VALUE self) +{ + if (!rb_block_given_p()) { + rb_raise(rb_eArgError, "called without a block"); + } + if(!IS_STARTED) + return rb_yield(Qnil); + set_current_skipped_status(Qtrue); + return rb_ensure(rb_yield, Qnil, set_current_skipped_status, Qfalse); +} + +static VALUE +debug_at_exit_c(VALUE proc) +{ + return rb_funcall(proc, rb_intern("call"), 0); +} + +static void +debug_at_exit_i(VALUE proc) +{ + if(!IS_STARTED) + { + debug_at_exit_c(proc); + } + else + { + set_current_skipped_status(Qtrue); + rb_ensure(debug_at_exit_c, proc, set_current_skipped_status, Qfalse); + } +} + +/* + * call-seq: + * Debugger.debug_at_exit { block } -> proc + * + * Register at_exit hook which is escaped from the debugger. + * FOR INTERNAL USE ONLY. + */ +static VALUE +debug_at_exit(VALUE self) +{ + VALUE proc; + if (!rb_block_given_p()) + rb_raise(rb_eArgError, "called without a block"); + proc = rb_block_proc(); + rb_set_end_proc(debug_at_exit_i, proc); + return proc; +} + +/* + * call-seq: + * context.step(steps, force = false) + * + * Stops the current context after a number of +steps+ are made. + * +force+ parameter (if true) ensures that the cursor moves from the current line. + */ +static VALUE +context_stop_next(int argc, VALUE *argv, VALUE self) +{ + VALUE steps, force; + debug_context_t *debug_context; + + debug_check_started(); + + rb_scan_args(argc, argv, "11", &steps, &force); + if(FIX2INT(steps) < 0) + rb_raise(rb_eRuntimeError, "Steps argument can't be negative."); + + Data_Get_Struct(self, debug_context_t, debug_context); + debug_context->stop_next = FIX2INT(steps); + if(RTEST(force)) + CTX_FL_SET(debug_context, CTX_FL_FORCE_MOVE); + else + CTX_FL_UNSET(debug_context, CTX_FL_FORCE_MOVE); + + return steps; +} + +/* + * call-seq: + * context.step_over(steps, frame = nil, force = false) + * + * Steps over a +steps+ number of times. + * Make step over operation on +frame+, by default the current frame. + * +force+ parameter (if true) ensures that the cursor moves from the current line. + */ +static VALUE +context_step_over(int argc, VALUE *argv, VALUE self) +{ + VALUE lines, frame, force; + debug_context_t *debug_context; + + debug_check_started(); + Data_Get_Struct(self, debug_context_t, debug_context); + if(debug_context->stack_size == 0) + rb_raise(rb_eRuntimeError, "No frames collected."); + + rb_scan_args(argc, argv, "12", &lines, &frame, &force); + debug_context->stop_line = FIX2INT(lines); + CTX_FL_UNSET(debug_context, CTX_FL_STEPPED); + if(frame == Qnil) + { + debug_context->dest_frame = debug_context->stack_size; + } + else + { + if(FIX2INT(frame) < 0 && FIX2INT(frame) >= debug_context->stack_size) + rb_raise(rb_eRuntimeError, "Destination frame is out of range."); + debug_context->dest_frame = debug_context->stack_size - FIX2INT(frame); + } + if(RTEST(force)) + CTX_FL_SET(debug_context, CTX_FL_FORCE_MOVE); + else + CTX_FL_UNSET(debug_context, CTX_FL_FORCE_MOVE); + + return Qnil; +} + +/* + * call-seq: + * context.stop_frame(frame) + * + * Stops when a frame with number +frame+ is activated. Implements +finish+ and +next+ commands. + */ +static VALUE +context_stop_frame(VALUE self, VALUE frame) +{ + debug_context_t *debug_context; + + debug_check_started(); + Data_Get_Struct(self, debug_context_t, debug_context); + if(FIX2INT(frame) < 0 && FIX2INT(frame) >= debug_context->stack_size) + rb_raise(rb_eRuntimeError, "Stop frame is out of range."); + debug_context->stop_frame = debug_context->stack_size - FIX2INT(frame); + + return frame; +} + +inline static int +check_frame_number(debug_context_t *debug_context, VALUE frame) +{ + int frame_n; + + frame_n = FIX2INT(frame); + if(frame_n < 0 || frame_n >= debug_context->stack_size) + rb_raise(rb_eArgError, "Invalid frame number %d, stack (0...%d)", + frame_n, debug_context->stack_size); + return frame_n; +} + +static int +optional_frame_position(int argc, VALUE *argv) { + unsigned int i_scanned; + VALUE level; + + if ((argc > 1) || (argc < 0)) + rb_raise(rb_eArgError, "wrong number of arguments (%d for 0 or 1)", argc); + i_scanned = rb_scan_args(argc, argv, "01", &level); + if (0 == i_scanned) { + level = INT2FIX(0); + } + return level; +} + +/* + * call-seq: + * context.frame_args_info(frame_position=0) -> list + if track_frame_args or nil otherwise + * + * Returns info saved about call arguments (if any saved). + */ +static VALUE +context_frame_args_info(int argc, VALUE *argv, VALUE self) +{ + VALUE frame; + debug_context_t *debug_context; + + debug_check_started(); + frame = optional_frame_position(argc, argv); + Data_Get_Struct(self, debug_context_t, debug_context); + + return RTEST(track_frame_args) ? GET_FRAME->arg_ary : Qnil; +} + +/* + * call-seq: + * context.frame_binding(frame_position=0) -> binding + * + * Returns frame's binding. + */ +static VALUE +context_frame_binding(int argc, VALUE *argv, VALUE self) +{ + VALUE frame; + debug_context_t *debug_context; + + debug_check_started(); + frame = optional_frame_position(argc, argv); + Data_Get_Struct(self, debug_context_t, debug_context); + return GET_FRAME->binding; +} + +/* + * call-seq: + * context.frame_method(frame_position=0) -> sym + * + * Returns the sym of the called method. + */ +static VALUE +context_frame_id(int argc, VALUE *argv, VALUE self) +{ + VALUE frame; + debug_context_t *debug_context; + ID id; + + debug_check_started(); + frame = optional_frame_position(argc, argv); + Data_Get_Struct(self, debug_context_t, debug_context); + + id = GET_FRAME->id; + return id ? ID2SYM(id): Qnil; +} + +/* + * call-seq: + * context.frame_line(frame_position) -> int + * + * Returns the line number in the file. + */ +static VALUE +context_frame_line(int argc, VALUE *argv, VALUE self) +{ + VALUE frame; + debug_context_t *debug_context; + + debug_check_started(); + frame = optional_frame_position(argc, argv); + Data_Get_Struct(self, debug_context_t, debug_context); + + return INT2FIX(GET_FRAME->line); +} + +/* + * call-seq: + * context.frame_file(frame_position) -> string + * + * Returns the name of the file. + */ +static VALUE +context_frame_file(int argc, VALUE *argv, VALUE self) +{ + VALUE frame; + debug_context_t *debug_context; + + debug_check_started(); + frame = optional_frame_position(argc, argv); + Data_Get_Struct(self, debug_context_t, debug_context); + + return rb_str_new2(GET_FRAME->file); +} + +static int +arg_value_is_small(VALUE val) +{ + switch (TYPE(val)) { + case T_FIXNUM: case T_FLOAT: case T_CLASS: + case T_NIL: case T_MODULE: case T_FILE: + case T_TRUE: case T_FALSE: case T_UNDEF: + return 1; + default: + return SYMBOL_P(val); + } +} + +/* + * Save scalar arguments or a class name. + */ +static void +copy_scalar_args(debug_frame_t *debug_frame) +{ + unsigned int i; + ID *tbl = ruby_scope->local_tbl;; + if (tbl && ruby_scope->local_vars) + { + int n = *tbl++; + if (debug_frame->argc+2 < n) n = debug_frame->argc+2; + debug_frame->arg_ary = rb_ary_new2(n); + for (i=2; iarg_ary, val); + else + rb_ary_push(debug_frame->arg_ary, + rb_str_new2(rb_obj_classname(val))); + } + } + } +} + + +/* + * call-seq: + * context.copy_args(frame) -> list of args + * + * Returns a array of argument names. + */ +static VALUE +context_copy_args(debug_frame_t *debug_frame) +{ + ID *tbl; + int n, i; + struct SCOPE *scope; + VALUE list = rb_ary_new2(0); /* [] */ + + scope = debug_frame->info.runtime.scope; + tbl = scope->local_tbl; + + if (tbl && scope->local_vars) + { + n = *tbl++; + if (debug_frame->argc+2 < n) n = debug_frame->argc+2; + list = rb_ary_new2(n); + /* skip first 2 ($_ and $~) */ + for (i=2; iinfo.runtime.scope; + tbl = scope->local_tbl; + + if (tbl && scope->local_vars) + { + n = *tbl++; + for (i=2; ilocal_vars[i]); + } + } + + vars = debug_frame->info.runtime.dyna_vars; + while (vars) + { + if (vars->id && rb_is_local_id(vars->id)) + { /* skip $_, $~ and flip states */ + rb_hash_aset(hash, rb_str_new2(rb_id2name(vars->id)), vars->val); + } + vars = vars->next; + } + return hash; +} + +/* + * call-seq: + * context.frame_locals(frame) -> hash + * + * Returns frame's local variables. + */ +static VALUE +context_frame_locals(int argc, VALUE *argv, VALUE self) +{ + VALUE frame; + debug_context_t *debug_context; + debug_frame_t *debug_frame; + + debug_check_started(); + frame = optional_frame_position(argc, argv); + Data_Get_Struct(self, debug_context_t, debug_context); + + debug_frame = GET_FRAME; + if(debug_frame->dead) + return debug_frame->info.copy.locals; + else + return context_copy_locals(debug_frame); +} + +/* + * call-seq: + * context.frame_args(frame_position=0) -> list + * + * Returns frame's argument parameters + */ +static VALUE +context_frame_args(int argc, VALUE *argv, VALUE self) +{ + VALUE frame; + debug_context_t *debug_context; + debug_frame_t *debug_frame; + + debug_check_started(); + frame = optional_frame_position(argc, argv); + Data_Get_Struct(self, debug_context_t, debug_context); + + debug_frame = GET_FRAME; + if(debug_frame->dead) + return debug_frame->info.copy.args; + else + return context_copy_args(debug_frame); +} + +/* + * call-seq: + * context.frame_self(frame_postion=0) -> obj + * + * Returns self object of the frame. + */ +static VALUE +context_frame_self(int argc, VALUE *argv, VALUE self) +{ + VALUE frame; + debug_context_t *debug_context; + debug_frame_t *debug_frame; + + debug_check_started(); + frame = optional_frame_position(argc, argv); + Data_Get_Struct(self, debug_context_t, debug_context); + + debug_frame = GET_FRAME; + return debug_frame->self; +} + +/* + * call-seq: + * context.frame_class(frame_position) -> obj + * + * Returns the real class of the frame. + * It could be different than context.frame_self(frame).class + */ +static VALUE +context_frame_class(int argc, VALUE *argv, VALUE self) +{ + VALUE frame; + debug_context_t *debug_context; + debug_frame_t *debug_frame; + VALUE klass; + + debug_check_started(); + frame = optional_frame_position(argc, argv); + Data_Get_Struct(self, debug_context_t, debug_context); + + debug_frame = GET_FRAME; + + if(CTX_FL_TEST(debug_context, CTX_FL_DEAD)) + return Qnil; + +#if RUBY_VERSION_CODE >= 190 + klass = debug_frame->info.runtime.frame->this_class; +#else + klass = debug_frame->info.runtime.frame->last_class; +#endif + + klass = real_class(klass); + if(TYPE(klass) == T_CLASS || TYPE(klass) == T_MODULE) + return klass; + return Qnil; +} + + +/* + * call-seq: + * context.stack_size-> int + * + * Returns the size of the context stack. + */ +static VALUE +context_stack_size(VALUE self) +{ + debug_context_t *debug_context; + + debug_check_started(); + Data_Get_Struct(self, debug_context_t, debug_context); + + return INT2FIX(debug_context->stack_size); +} + +/* + * call-seq: + * context.thread -> thread + * + * Returns a thread this context is associated with. + */ +static VALUE +context_thread(VALUE self) +{ + debug_context_t *debug_context; + + debug_check_started(); + Data_Get_Struct(self, debug_context_t, debug_context); + return context_thread_0(debug_context); +} + +/* + * call-seq: + * context.thnum -> int + * + * Returns the context's number. + */ +static VALUE +context_thnum(VALUE self) +{ + debug_context_t *debug_context; + + Data_Get_Struct(self, debug_context_t, debug_context); + return INT2FIX(debug_context->thnum); +} + +static void +context_suspend_0(debug_context_t *debug_context) +{ + VALUE status; + + status = rb_funcall(context_thread_0(debug_context), rb_intern("status"), 0); + if(rb_str_cmp(status, rb_str_new2("run")) == 0) + CTX_FL_SET(debug_context, CTX_FL_WAS_RUNNING); + else if(rb_str_cmp(status, rb_str_new2("sleep")) == 0) + CTX_FL_UNSET(debug_context, CTX_FL_WAS_RUNNING); + else + return; + CTX_FL_SET(debug_context, CTX_FL_SUSPEND); +} + +static void +context_resume_0(debug_context_t *debug_context) +{ + if(!CTX_FL_TEST(debug_context, CTX_FL_SUSPEND)) + return; + CTX_FL_UNSET(debug_context, CTX_FL_SUSPEND); + if(CTX_FL_TEST(debug_context, CTX_FL_WAS_RUNNING)) + rb_thread_wakeup(context_thread_0(debug_context)); +} + +/* + * call-seq: + * context.suspend -> nil + * + * Suspends the thread when it is running. + */ +static VALUE +context_suspend(VALUE self) +{ + debug_context_t *debug_context; + + debug_check_started(); + + Data_Get_Struct(self, debug_context_t, debug_context); + if(CTX_FL_TEST(debug_context, CTX_FL_SUSPEND)) + rb_raise(rb_eRuntimeError, "Already suspended."); + context_suspend_0(debug_context); + return Qnil; +} + +/* + * call-seq: + * context.suspended? -> bool + * + * Returns +true+ if the thread is suspended by debugger. + */ +static VALUE +context_is_suspended(VALUE self) +{ + debug_context_t *debug_context; + + debug_check_started(); + + Data_Get_Struct(self, debug_context_t, debug_context); + return CTX_FL_TEST(debug_context, CTX_FL_SUSPEND) ? Qtrue : Qfalse; +} + +/* + * call-seq: + * context.resume -> nil + * + * Resumes the thread from the suspended mode. + */ +static VALUE +context_resume(VALUE self) +{ + debug_context_t *debug_context; + + debug_check_started(); + + Data_Get_Struct(self, debug_context_t, debug_context); + if(!CTX_FL_TEST(debug_context, CTX_FL_SUSPEND)) + rb_raise(rb_eRuntimeError, "Thread is not suspended."); + context_resume_0(debug_context); + return Qnil; +} + +/* + * call-seq: + * context.tracing -> bool + * + * Returns the tracing flag for the current context. + */ +static VALUE +context_tracing(VALUE self) +{ + debug_context_t *debug_context; + + debug_check_started(); + + Data_Get_Struct(self, debug_context_t, debug_context); + return CTX_FL_TEST(debug_context, CTX_FL_TRACING) ? Qtrue : Qfalse; +} + +/* + * call-seq: + * context.tracing = bool + * + * Controls the tracing for this context. + */ +static VALUE +context_set_tracing(VALUE self, VALUE value) +{ + debug_context_t *debug_context; + + debug_check_started(); + + Data_Get_Struct(self, debug_context_t, debug_context); + if(RTEST(value)) + CTX_FL_SET(debug_context, CTX_FL_TRACING); + else + CTX_FL_UNSET(debug_context, CTX_FL_TRACING); + return value; +} + +/* + * call-seq: + * context.ignored? -> bool + * + * Returns the ignore flag for the current context. + */ +static VALUE +context_ignored(VALUE self) +{ + debug_context_t *debug_context; + + debug_check_started(); + + Data_Get_Struct(self, debug_context_t, debug_context); + return CTX_FL_TEST(debug_context, CTX_FL_IGNORE) ? Qtrue : Qfalse; +} + +/* + * call-seq: + * context.dead? -> bool + * + * Returns +true+ if context doesn't represent a live context and is created + * during post-mortem exception handling. + */ +static VALUE +context_dead(VALUE self) +{ + debug_context_t *debug_context; + + debug_check_started(); + + Data_Get_Struct(self, debug_context_t, debug_context); + return CTX_FL_TEST(debug_context, CTX_FL_DEAD) ? Qtrue : Qfalse; +} + +/* + * call-seq: + * context.stop_reason -> sym + * + * Returns the reason for the stop. It maybe of the following values: + * :initial, :step, :breakpoint, :catchpoint, :post-mortem + */ +static VALUE +context_stop_reason(VALUE self) +{ + debug_context_t *debug_context; + char * sym_name; + + debug_check_started(); + + Data_Get_Struct(self, debug_context_t, debug_context); + + switch(debug_context->stop_reason) + { + case CTX_STOP_STEP: + sym_name = "step"; + break; + case CTX_STOP_BREAKPOINT: + sym_name = "breakpoint"; + break; + case CTX_STOP_CATCHPOINT: + sym_name = "catchpoint"; + break; + case CTX_STOP_NONE: + default: + sym_name = "none"; + } + if(CTX_FL_TEST(debug_context, CTX_FL_DEAD)) + sym_name = "post-mortem"; + + return ID2SYM(rb_intern(sym_name)); +} + + +/* + * Document-class: Context + * + * == Summary + * + * Debugger keeps a single instance of this class for each Ruby thread. + */ +static void +Init_context() +{ + cContext = rb_define_class_under(mDebugger, "Context", rb_cObject); + rb_define_method(cContext, "stop_next=", context_stop_next, -1); + rb_define_method(cContext, "step", context_stop_next, -1); + rb_define_method(cContext, "step_over", context_step_over, -1); + rb_define_method(cContext, "stop_frame=", context_stop_frame, 1); + rb_define_method(cContext, "thread", context_thread, 0); + rb_define_method(cContext, "thnum", context_thnum, 0); + rb_define_method(cContext, "stop_reason", context_stop_reason, 0); + rb_define_method(cContext, "suspend", context_suspend, 0); + rb_define_method(cContext, "suspended?", context_is_suspended, 0); + rb_define_method(cContext, "resume", context_resume, 0); + rb_define_method(cContext, "tracing", context_tracing, 0); + rb_define_method(cContext, "tracing=", context_set_tracing, 1); + rb_define_method(cContext, "ignored?", context_ignored, 0); + rb_define_method(cContext, "frame_args", context_frame_args, -1); + rb_define_method(cContext, "frame_args_info", context_frame_args_info, -1); + rb_define_method(cContext, "frame_binding", context_frame_binding, -1); + rb_define_method(cContext, "frame_class", context_frame_class, -1); + rb_define_method(cContext, "frame_file", context_frame_file, -1); + rb_define_method(cContext, "frame_id", context_frame_id, -1); + rb_define_method(cContext, "frame_line", context_frame_line, -1); + rb_define_method(cContext, "frame_locals", context_frame_locals, -1); + rb_define_method(cContext, "frame_method", context_frame_id, -1); + rb_define_method(cContext, "frame_self", context_frame_self, -1); + rb_define_method(cContext, "stack_size", context_stack_size, 0); + rb_define_method(cContext, "dead?", context_dead, 0); + rb_define_method(cContext, "breakpoint", + context_breakpoint, 0); /* in breakpoint.c */ + rb_define_method(cContext, "set_breakpoint", + context_set_breakpoint, -1); /* in breakpoint.c */ +} + +/* + * call-seq: + * Debugger.breakpoints -> array + * + * Returns an array of breakpoints. + */ +static VALUE +debug_breakpoints(VALUE self) +{ + debug_check_started(); + + return rdebug_breakpoints; +} + +/* + * call-seq: + * Debugger.add_breakpoint(source, pos, condition = nil) -> breakpoint + * + * Adds a new breakpoint. + * source is a name of a file or a class. + * pos is a line number or a method name if source is a class name. + * condition is a string which is evaluated to +true+ when this breakpoint + * is activated. + */ +static VALUE +debug_add_breakpoint(int argc, VALUE *argv, VALUE self) +{ + VALUE result; + + debug_check_started(); + + result = create_breakpoint_from_args(argc, argv, ++bkp_count); + rb_ary_push(rdebug_breakpoints, result); + return result; +} + +/* + * Document-class: Debugger + * + * == Summary + * + * This is a singleton class allows controlling the debugger. Use it to start/stop debugger, + * set/remove breakpoints, etc. + */ +#if defined(_WIN32) +__declspec(dllexport) +#endif +void +Init_ruby_debug() +{ + mDebugger = rb_define_module("Debugger"); + rb_define_const(mDebugger, "VERSION", rb_str_new2(DEBUG_VERSION)); + rb_define_module_function(mDebugger, "start_", debug_start, 0); + rb_define_module_function(mDebugger, "stop", debug_stop, 0); + rb_define_module_function(mDebugger, "started?", debug_is_started, 0); + rb_define_module_function(mDebugger, "breakpoints", debug_breakpoints, 0); + rb_define_module_function(mDebugger, "add_breakpoint", debug_add_breakpoint, -1); + rb_define_module_function(mDebugger, "remove_breakpoint", + rdebug_remove_breakpoint, + 1); /* in breakpoint.c */ + rb_define_module_function(mDebugger, "add_catchpoint", + rdebug_add_catchpoint, 1); /* in breakpoint.c */ + rb_define_module_function(mDebugger, "catchpoints", + debug_catchpoints, 0); /* in breakpoint.c */ + rb_define_module_function(mDebugger, "last_context", debug_last_interrupted, 0); + rb_define_module_function(mDebugger, "contexts", debug_contexts, 0); + rb_define_module_function(mDebugger, "current_context", debug_current_context, 0); + rb_define_module_function(mDebugger, "thread_context", debug_thread_context, 1); + rb_define_module_function(mDebugger, "suspend", debug_suspend, 0); + rb_define_module_function(mDebugger, "resume", debug_resume, 0); + rb_define_module_function(mDebugger, "tracing", debug_tracing, 0); + rb_define_module_function(mDebugger, "tracing=", debug_set_tracing, 1); + rb_define_module_function(mDebugger, "debug_load", debug_debug_load, -1); + rb_define_module_function(mDebugger, "skip", debug_skip, 0); + rb_define_module_function(mDebugger, "debug_at_exit", debug_at_exit, 0); + rb_define_module_function(mDebugger, "post_mortem?", debug_post_mortem, 0); + rb_define_module_function(mDebugger, "post_mortem=", debug_set_post_mortem, 1); + rb_define_module_function(mDebugger, "keep_frame_binding?", + debug_keep_frame_binding, 0); + rb_define_module_function(mDebugger, "keep_frame_binding=", + debug_set_keep_frame_binding, 1); + rb_define_module_function(mDebugger, "track_frame_args?", + debug_track_frame_args, 0); + rb_define_module_function(mDebugger, "track_frame_args=", + debug_set_track_frame_args, 1); + rb_define_module_function(mDebugger, "debug", debug_debug, 0); + rb_define_module_function(mDebugger, "debug=", debug_set_debug, 1); + + cThreadsTable = rb_define_class_under(mDebugger, "ThreadsTable", rb_cObject); + + cDebugThread = rb_define_class_under(mDebugger, "DebugThread", rb_cThread); + rb_define_singleton_method(cDebugThread, "inherited", + debug_thread_inherited, 1); + + Init_context(); + Init_breakpoint(); + + idAtBreakpoint = rb_intern("at_breakpoint"); + idAtCatchpoint = rb_intern("at_catchpoint"); + idAtLine = rb_intern("at_line"); + idAtReturn = rb_intern("at_return"); + idAtTracing = rb_intern("at_tracing"); + idList = rb_intern("list"); + + rb_mObjectSpace = rb_const_get(rb_mKernel, rb_intern("ObjectSpace")); + + rb_global_variable(&last_context); + rb_global_variable(&last_thread); + rb_global_variable(&locker); + rb_global_variable(&rdebug_breakpoints); + rb_global_variable(&rdebug_catchpoints); + rb_global_variable(&rdebug_threads_tbl); +} diff --git a/ext/ruby_debug.h b/ext/ruby_debug.h new file mode 100644 index 0000000..04a8ae2 --- /dev/null +++ b/ext/ruby_debug.h @@ -0,0 +1,123 @@ +#include +/* Context info */ +enum ctx_stop_reason {CTX_STOP_NONE, CTX_STOP_STEP, CTX_STOP_BREAKPOINT, + CTX_STOP_CATCHPOINT}; + +/* Context flags */ +#define CTX_FL_SUSPEND (1<<1) +#define CTX_FL_TRACING (1<<2) +#define CTX_FL_SKIPPED (1<<3) +#define CTX_FL_IGNORE (1<<4) +#define CTX_FL_DEAD (1<<5) +#define CTX_FL_WAS_RUNNING (1<<6) +#define CTX_FL_ENABLE_BKPT (1<<7) +#define CTX_FL_STEPPED (1<<8) +#define CTX_FL_FORCE_MOVE (1<<9) + +#define CTX_FL_TEST(c,f) ((c)->flags & (f)) +#define CTX_FL_SET(c,f) do { (c)->flags |= (f); } while (0) +#define CTX_FL_UNSET(c,f) do { (c)->flags &= ~(f); } while (0) + +typedef struct { + int argc; /* Number of arguments a frame should have. */ + VALUE binding; + ID id; + ID orig_id; + int line; + const char * file; + short dead; + VALUE self; + VALUE arg_ary; + union { + struct { + struct FRAME *frame; + struct SCOPE *scope; + struct RVarmap *dyna_vars; + } runtime; + struct { + VALUE args; + VALUE locals; + VALUE arg_ary; + } copy; + } info; +} debug_frame_t; + +typedef struct { + VALUE thread_id; + int thnum; + int flags; + enum ctx_stop_reason stop_reason; + int stop_next; + int dest_frame; + int stop_line; + int stop_frame; + int stack_size; + int stack_len; + debug_frame_t *frames; + const char * last_file; + int last_line; + VALUE breakpoint; +} debug_context_t; + +/* variables in ruby_debug.c */ +extern VALUE mDebugger; +extern VALUE rdebug_breakpoints; +extern VALUE rdebug_catchpoints; +extern VALUE rdebug_threads_tbl; + +/* routines in ruby_debug.c */ +extern int filename_cmp(VALUE source, char *file); + +#define IS_STARTED (rdebug_threads_tbl != Qnil) +static inline void +debug_check_started() +{ + if(!IS_STARTED) + { + rb_raise(rb_eRuntimeError, "Debugger.start is not called yet."); + } +} + +static inline int +classname_cmp(VALUE name, VALUE klass) +{ + VALUE class_name = (Qnil == name) ? rb_str_new2("main") : name; + return (klass != Qnil + && rb_str_cmp(class_name, rb_mod_name(klass)) == 0); +} + +/* Breakpoint information */ +enum bp_type {BP_POS_TYPE, BP_METHOD_TYPE}; +enum hit_condition {HIT_COND_NONE, HIT_COND_GE, HIT_COND_EQ, HIT_COND_MOD}; + +typedef struct { + int id; + enum bp_type type; + VALUE source; + union + { + int line; + ID mid; + } pos; + VALUE expr; + VALUE enabled; + int hit_count; + int hit_value; + enum hit_condition hit_condition; +} debug_breakpoint_t; + +/* routines in breakpoint.c */ +extern int check_breakpoint_expression(VALUE breakpoint, VALUE binding); +extern int check_breakpoint_hit_condition(VALUE breakpoint); +extern VALUE check_breakpoints_by_method(debug_context_t *debug_context, + VALUE klass, ID mid); +extern VALUE check_breakpoints_by_pos(debug_context_t *debug_context, + char *file, int line); +extern VALUE create_breakpoint_from_args(int argc, VALUE *argv, int id); +extern VALUE context_breakpoint(VALUE self); +extern VALUE context_set_breakpoint(int argc, VALUE *argv, VALUE self); +extern VALUE rdebug_add_catchpoint(VALUE self, VALUE value); +extern VALUE debug_catchpoints(VALUE self); +extern VALUE rdebug_remove_breakpoint(VALUE self, VALUE id_value); + +extern void Init_breakpoint(); diff --git a/ext/win32/.cvsignore b/ext/win32/.cvsignore new file mode 100644 index 0000000..3bc7dfb --- /dev/null +++ b/ext/win32/.cvsignore @@ -0,0 +1,3 @@ +*.o +*.so +Makefile diff --git a/ext/win32/.svn/README.txt b/ext/win32/.svn/README.txt new file mode 100644 index 0000000..271a8ce --- /dev/null +++ b/ext/win32/.svn/README.txt @@ -0,0 +1,2 @@ +This is a Subversion working copy administrative directory. +Visit http://subversion.tigris.org/ for more information. diff --git a/ext/win32/.svn/dir-prop-base b/ext/win32/.svn/dir-prop-base new file mode 100644 index 0000000..abe19cc --- /dev/null +++ b/ext/win32/.svn/dir-prop-base @@ -0,0 +1,8 @@ +K 10 +svn:ignore +V 18 +*.o +*.so +Makefile + +END diff --git a/ext/win32/.svn/dir-props b/ext/win32/.svn/dir-props new file mode 100644 index 0000000..abe19cc --- /dev/null +++ b/ext/win32/.svn/dir-props @@ -0,0 +1,8 @@ +K 10 +svn:ignore +V 18 +*.o +*.so +Makefile + +END diff --git a/ext/win32/.svn/empty-file b/ext/win32/.svn/empty-file new file mode 100644 index 0000000..e69de29 diff --git a/ext/win32/.svn/entries b/ext/win32/.svn/entries new file mode 100644 index 0000000..97a4026 --- /dev/null +++ b/ext/win32/.svn/entries @@ -0,0 +1,23 @@ + + + + + diff --git a/ext/win32/.svn/format b/ext/win32/.svn/format new file mode 100644 index 0000000..b8626c4 --- /dev/null +++ b/ext/win32/.svn/format @@ -0,0 +1 @@ +4 diff --git a/ext/win32/.svn/prop-base/.cvsignore.svn-base b/ext/win32/.svn/prop-base/.cvsignore.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/ext/win32/.svn/prop-base/.cvsignore.svn-base @@ -0,0 +1 @@ +END diff --git a/ext/win32/.svn/props/.cvsignore.svn-work b/ext/win32/.svn/props/.cvsignore.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/ext/win32/.svn/props/.cvsignore.svn-work @@ -0,0 +1 @@ +END diff --git a/ext/win32/.svn/text-base/.cvsignore.svn-base b/ext/win32/.svn/text-base/.cvsignore.svn-base new file mode 100644 index 0000000..3bc7dfb --- /dev/null +++ b/ext/win32/.svn/text-base/.cvsignore.svn-base @@ -0,0 +1,3 @@ +*.o +*.so +Makefile diff --git a/lib/.svn/README.txt b/lib/.svn/README.txt new file mode 100644 index 0000000..271a8ce --- /dev/null +++ b/lib/.svn/README.txt @@ -0,0 +1,2 @@ +This is a Subversion working copy administrative directory. +Visit http://subversion.tigris.org/ for more information. diff --git a/lib/.svn/empty-file b/lib/.svn/empty-file new file mode 100644 index 0000000..e69de29 diff --git a/lib/.svn/entries b/lib/.svn/entries new file mode 100644 index 0000000..e5122b0 --- /dev/null +++ b/lib/.svn/entries @@ -0,0 +1,31 @@ + + + + + + diff --git a/lib/.svn/format b/lib/.svn/format new file mode 100644 index 0000000..b8626c4 --- /dev/null +++ b/lib/.svn/format @@ -0,0 +1 @@ +4 diff --git a/lib/.svn/prop-base/ChangeLog.svn-base b/lib/.svn/prop-base/ChangeLog.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/lib/.svn/prop-base/ChangeLog.svn-base @@ -0,0 +1 @@ +END diff --git a/lib/.svn/prop-base/ruby-debug-base.rb.svn-base b/lib/.svn/prop-base/ruby-debug-base.rb.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/lib/.svn/prop-base/ruby-debug-base.rb.svn-base @@ -0,0 +1 @@ +END diff --git a/lib/.svn/props/ChangeLog.svn-work b/lib/.svn/props/ChangeLog.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/lib/.svn/props/ChangeLog.svn-work @@ -0,0 +1 @@ +END diff --git a/lib/.svn/props/ruby-debug-base.rb.svn-work b/lib/.svn/props/ruby-debug-base.rb.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/lib/.svn/props/ruby-debug-base.rb.svn-work @@ -0,0 +1 @@ +END diff --git a/lib/.svn/text-base/ChangeLog.svn-base b/lib/.svn/text-base/ChangeLog.svn-base new file mode 100644 index 0000000..12c8f69 --- /dev/null +++ b/lib/.svn/text-base/ChangeLog.svn-base @@ -0,0 +1,1065 @@ +2009-03-29 03:00 Rocky Bernstein + + * ChangeLog: Canonicalize breakpoint locations a little better. + More work should be done and more work should be done on the + testing side too. + +2009-03-11 23:42 Rocky Bernstein + + * ChangeLog: update texinfo for catch + +2008-11-25 02:43 Rocky Bernstein + + * ChangeLog: Frame without a frame number means frame 0, same as + gdb. We are now in 0.10.4 territory now. + +2008-11-16 00:14 Rocky Bernstein + + * ChangeLog: Add rdoc for rdebug script. + +2008-11-14 19:28 Rocky Bernstein + + * ruby-debug-base.rb: Go over documentation and revise. + +2008-11-14 15:32 Rocky Bernstein + + * ChangeLog, ruby-debug-base.rb: Move Debugger#debugger from base + to cli. Revert code in ruby_debug.c and block parameter in + debugger. cf. -> Compare with. Document Debugger.start better. + +2008-11-13 10:29 Rocky Bernstein + + * ChangeLog: Make Debugger.start{block} work if Debugger.started? + is false. Second try. + +2008-11-11 02:07 Rocky Bernstein + + * ChangeLog: Tweak truncated stack test since Ruby's caller doesn't + seem to include (tail?) recursive calls and we do. Get regression + tests working in light of recent changes. + +2008-11-10 01:48 Kent Sibilev + + * ruby-debug-base.rb: a little bit more readable + +2008-11-10 01:35 Kent Sibilev + + * ruby-debug-base.rb: Debugger.start must always call the passed + block + +2008-11-07 19:35 Rocky Bernstein + + * ChangeLog: Change truncated frame message. + +2008-11-07 10:39 Rocky Bernstein + + * ChangeLog: Add check to "where" to see if the call stack is + truncated; task #2354 + +2008-11-06 16:17 Rocky Bernstein + + * ChangeLog: #22698 Allow ruby-debug-base 0.x.y.z be compatible + with ruby-debug 0.x.y. + +2008-11-02 21:59 Rocky Bernstein + + * ChangeLog, ruby-debug-base.rb: Debugger.start with a block now + stops inside the block. Debugger.debugger with a block works like + Debugger.start with a block. + + The whole interface is hopelessly kludgy and needs to be redone. + +2008-10-26 14:54 Rocky Bernstein + + * ChangeLog: Doc typo. Add comment to remind me how to turn off + optimizationin extconf.rb + +2008-10-25 16:01 Rocky Bernstein + + * ChangeLog: Warn and add a "confirmation" when setting a + breakpoint on a file that is not loaded. Regression tests no + longer fail. + +2008-09-22 00:07 Rocky Bernstein + + * ruby-debug-base.rb: #22118 bug in showing variables post mortem. + Patch thanks to rubikitch. + Update pm.rb integration test. + +2008-09-03 17:29 Rocky Bernstein + + * ChangeLog: Show line numbers when $DEBUG is set. Patch #21772 + from Martin Krauskopf + +2008-07-07 07:11 Rocky Bernstein + + * ruby-debug-base.rb: Tracker [#20041] start erroneously moved to + Kernel - should be in + Debugger.start + +2008-06-20 06:46 Rocky Bernstein + + * ruby-debug-base.rb: trace.rb: add "trace var" + ruby-debug-base.rb: remove another undefined warning. + +2008-05-24 01:27 Rocky Bernstein + + * ChangeLog: Remove dup lines. + +2008-05-15 16:05 Rocky Bernstein + + * ChangeLog: Handle "catch nnn off" Forgotten there during r656. + From mkrauskopf [#20156]. + +2008-05-05 18:05 Rocky Bernstein + + * ChangeLog: make test-frame installation independent. Bug #19931 + +2008-04-29 13:37 Rocky Bernstein + + * ChangeLog: Test line number in "continue" command for validity. + +2008-04-28 16:16 Rocky Bernstein + + * ChangeLog: From Martin Krauskopf via patch #19779 + + Allow folks to configure Ruby used for CLI tests in the + test/config.yaml. The defaults are for native Ruby, so nothing + needs + to be done for ruby-debug. + + Developers of interfaces other than cli might override + config.yaml by + customized config.private.yaml which is ignored. So there will be + no + trash in e.g. 'svn st' output when developer customize the Ruby + to be + used. + + Handy for alternative interface implementations using + svn:externals. + +2008-04-22 02:49 Rocky Bernstein + + * ruby-debug-base.rb: Experiment with debugger(steps=0). Puts us in + the debugger call, but this may be the best we can do for now. + See tracker + #19639. + +2008-04-16 01:11 Rocky Bernstein + + * ChangeLog: In 0.10.2 now. Some work to cope systems without + readline. More work is needed. + Add test of "set autoeval." Undefined command message more + closely like gdb's. + +2008-04-10 08:49 Rocky Bernstein + + * ChangeLog: linecache is required by ruby-debug-base not + ruby-debug. Thanks Martin! + +2008-04-10 08:00 Rocky Bernstein + + * ChangeLog: Last change before 0.10.1 release. + +2008-04-10 02:03 Rocky Bernstein + + * ChangeLog: Cosmetic stuff: spelling corrections. Update node + structure so texinfo + doesn't complain. + +2008-04-08 14:52 Rocky Bernstein + + * ChangeLog: autorequire is deprecated and presumably no longer + needed + http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/182827 + +2008-04-07 00:36 Rocky Bernstein + + * ChangeLog, ruby-debug-base.rb: ruby-debug-base.rb: document + Debugger.start parameters. + CHANGES: Revise what's happened + test-shortkey.el: A failing regression test because I think + rdebug-shortkey-mode + is not correct. + +2008-04-03 19:01 Rocky Bernstein + + * ChangeLog, ruby-debug-base.rb: Allow setting :post_mortem => true + from Debugger.start. + +2008-03-28 13:53 Rocky Bernstein + + * ChangeLog: Don't unconditionally turn on short-key mode when + annotations are on. Use rdebug-short-key-mode setting to decide. + +2008-03-23 17:47 Rocky Bernstein + + * ChangeLog: set.rb -> settings.rb since it's already one command + per file, and + remove another :nodoc. + Rakefile: split long line + +2008-03-18 16:05 Rocky Bernstein + + * ChangeLog: Fix bug in 'list' command when wrapping off the end. + test-finish.rb: tolerate buggy in Ruby versions <= 1.8.7. + +2008-03-13 02:15 Rocky Bernstein + + * ruby-debug-base.rb: INCOMPATIBLE CHANGE: "finish" works like gdb + - stop just before the + most recent method finishes. Will now accept a number which stops + that + many frames completed. (Note that return line numbers will be + funny, + the first line of the method until Ruby 1.8.7.) + +2008-03-10 13:28 Rocky Bernstein + + * ChangeLog: Dunno why we are now one line number less. So be it + (for now). + +2008-03-09 23:30 Rocky Bernstein + + * ChangeLog: For now we require the duplicate numbers on + conditionals. + +2008-03-02 04:20 Rocky Bernstein + + * ruby-debug-base.rb: Better error message for an invalid break + command. + +2008-02-28 05:06 Rocky Bernstein + + * ChangeLog: breakpoints.{cmd,right}: test for an invalid stopping + line number + rdebug-fns.el: move generic split-string-and-unquote from + rdebug-core. + rdebug-core.el: Add rdebug-common-init to replace + gud-common-init. Is + simpler, and finds files better via debugger output/annotations. + Fix bug in rdebug-setup-windows: gud-find-file can return nil, + and + we still need to set buf. + +2008-02-27 04:04 Rocky Bernstein + + * ruby-debug-base.rb: Slightly more robust handle_post_mortem. + +2008-02-26 17:31 Rocky Bernstein + + * ChangeLog: Go over source location positioning. 0 is now the + oldest (first) position. Add M-S-down and M-S-up for first and + last. More tests needed in test-fns.el and need to prompt on wrap + around. + +2008-02-26 00:57 Rocky Bernstein + + * ChangeLog: Fix bug in "info file xxx breakpoints". + +2008-02-24 16:36 Rocky Bernstein + + * ChangeLog: rdebug; make more Ruby 1.9 compatible. + +2008-02-24 16:14 Rocky Bernstein + + * ChangeLog: Minor changes. + rdbg.rb: don't need $DEBUG test any more + rdebug-regexp.el: go over with checkdoc + bin/rdebug: use PATH_SEPARATOR (for 'doze again) + +2008-02-24 04:51 Rocky Bernstein + + * ChangeLog: CLI: Add long help for "info file". + + test/test-help.rb: Make test failures easier to fix and more like + the + other tests. + + emacs/test: finish testing all of the funcitons in rdebug-fns.el + + rdebug-layouts.el: Make checkdoc clean. + rdebug-track.el: don't need to rename shell buffer. Do it as an + option only. + rdebug-secondary.el: get rid of hoaky buffer finding for at least + gud-comint-buf. (Should probably do others as well) + + DOC: Note weird line stopping locations. Describe what "ctrl" in + prompt means. + +2008-02-21 02:56 Rocky Bernstein + + * ChangeLog: Fringe for frame buffer the same as in source code. + Move + miscellaneous small functions to a new file. Reduce duplication + of + "chomp" code. + +2008-02-19 23:44 Rocky Bernstein + + * ChangeLog: rdebug-cmd.el: M-insert toggles shortkey mode in the + command buffer + rdebug: search for Ruby program if file is not found and no + SEPARATOR + chars in the filename + +2008-02-18 19:56 Rocky Bernstein + + * ChangeLog: Frame switching shouldn't be recorded in position + history ring. + +2008-02-17 13:57 Rocky Bernstein + + * ruby-debug-base.rb: Add Debugger.last_exception. Show exception + in post-mortem when "info program" + is issued. Reorganize list of major changes better. + +2008-02-13 21:47 Rocky Bernstein + + * ChangeLog: processor.rb: spelled "post-mortem" incorrectly in + prompt. + +2008-02-13 17:32 Rocky Bernstein + + * ChangeLog: Set up keys for comint-next-prompt and + comint-previous-prompt. + +2008-02-12 02:06 Rocky Bernstein + + * ChangeLog: Fix bug in "info thread verbose" which wasn't showing + full traceback. + +2008-02-09 15:48 Rocky Bernstein + + * ChangeLog: helper.rb Failed attempt to DRY tests more. But save + what we have + which may someday in the future be used to go further. Minus to + undercore in Data file names in preparation such time. (We'll use + the + filename as the test name). + + testing + +2008-02-06 16:15 Rocky Bernstein + + * ChangeLog: Add 'nowarn to find-file-noselect and test that we + don't get a warning. + +2008-02-05 01:41 Rocky Bernstein + + * ChangeLog: rdebug.el: Add a defgroup for rdebug so customization + in Emacs 23 is possible. + Some other minor doc fixes. + setshow.* make sure we don't have an $Id line that we have to + check against. + +2008-02-03 15:23 Rocky Bernstein + + * ChangeLog: Try to get testing a little more organized, although + more work should + be done: Create a data directory for comparison ("right") and + script + command ("cmd") files. Code is now more uniform (and should DRY'd + a + bit more). + +2008-02-02 23:10 Rocky Bernstein + + * ChangeLog: Remove commands in post-mortem which are not + applicable, e.g."step", + "next", "continue"... + + "No breakpoints have been set" is now an error message when + trying to + set a breakpoint. + + Add post-mortem test. + + Debug.init no longer exists. + +2008-02-02 09:27 Rocky Bernstein + + * ruby-debug-base.rb: Remove Debugger.init and fold options + parameter into Debugger.start. + Old Debugger.start has been renamed Deebugger.start_ + +2008-01-31 16:30 Rocky Bernstein + + * ChangeLog: Leave ruby_debug.c this way for now. + +2008-01-31 16:24 Rocky Bernstein + + * ChangeLog: ruby_debug.c: more adventures in exception handling + processor.rb: Removal of crash when annotate is on. Need to fix + the source of the + problem though. + +2008-01-31 15:16 Rocky Bernstein + + * ruby-debug-base.rb: Handle post-mortem and exception traceback + reporting in ruby-debug + +2008-01-30 17:01 Rocky Bernstein + + * ChangeLog: Add Command.find() to find a subcommand name. + condition.right: correct for breakpoint hit counts. + +2008-01-30 01:43 Rocky Bernstein + + * ChangeLog: Add number of times a breakpoint is hit like gdb does. + +2008-01-29 22:37 Rocky Bernstein + + * ChangeLog: Columnize breakpoint output. + +2008-01-29 11:20 Rocky Bernstein + + * ChangeLog: More annotate=2 fixes. + +2008-01-28 15:59 Rocky Bernstein + + * ChangeLog: Add info file breakpoints to show lines which we can + set a breakpoint on. + Revise so we chdir into SRC_DIR. + test-hist.rb is broken - will fix later. + +2008-01-25 12:11 Rocky Bernstein + + * ChangeLog, ruby-debug-base.rb: Add Debugger.init which intializes + things that rdebug does. This + allows a restart even though rdebug wasn't called initially. + +2008-01-22 23:15 Rocky Bernstein + + * ChangeLog: Allow "help info xxx". Add ability for long help on + "info" command. + Add "info break xx". + + test: remove test/unit class name conflicts. All the tests we + wrote + now get run. + +2008-01-19 19:28 Rocky Bernstein + + * ChangeLog: Move ruby-debug-base tests to base directory. Add a + binding_n regression test. + +2008-01-16 18:42 Rocky Bernstein + + * ChangeLog: Need to present source filename (__FILE__) as Ruby and + therefore breakpoint + sees it. + + +2008-01-16 02:19 Rocky Bernstein + + * ChangeLog, ruby-debug-base.rb: Line caching moved to an external + gem, linecache. We now require + version 0.2 of that or greater. + +2008-01-14 01:31 Rocky Bernstein + + * ChangeLog: Make rdebug-track work better in the face of prompt + and error annotations. + control.rb: need another test when rdebug not called initially. + +2008-01-13 21:51 Rocky Bernstein + + * ChangeLog: Some stack -> frame renaming + ext/breakpoint.c: put methods in alpha order (to help with + reference man) + breakpoints.rb: one print -> errmsg + +2008-01-13 18:13 Rocky Bernstein + + * ChangeLog: Create errmsg routine for error output, start tagging + error messages + as errors. Under annotate 3, output errors similar to gdb + --annotate + does (although still simplified). Have Emacs pick up debugger + error + annotations. + +2008-01-13 04:05 Rocky Bernstein + + * ChangeLog: Check validity of expressions in breakpoint conditions + and don't allow + enabling a syntactically invalid expression. + + Start noting messages which are errors via an errmsg routine. + +2008-01-11 10:26 Rocky Bernstein + + * ChangeLog: Document that ruby-debug resets $0. Align program + options in ref manual and --help. Alphabetize better. + +2008-01-10 22:56 Rocky Bernstein + + * ChangeLog: More correct $0 fix. Deal with the case ./ is + automatically added. + However this might not be right in all cases. + +2008-01-10 22:25 Rocky Bernstein + + * ChangeLog: Was gobbling arg in processing --emacs. Add test. + +2008-01-10 10:34 Rocky Bernstein + + * ChangeLog: Add condition command. + +2008-01-09 19:10 Rocky Bernstein + + * ChangeLog: Rakefile: rdebug.rb -> rdbg.el + rdebug-dbg.el: Add $Id$ + +2008-01-09 19:03 Rocky Bernstein + + * ChangeLog: Break out secondary buffer into their own file, and + also internal + debug code and general secondary commands. Secondary buffer code + removed from rdebug-cmd and moved into the appropriate file. + + rdebug-edit-variables-value is not defined so comment out for + now. + +2008-01-08 16:04 Rocky Bernstein + + * ChangeLog: Restore $: to the value it was before rdebug call. + +2008-01-07 20:38 Rocky Bernstein + + * ChangeLog: Add "var class". This means "var const .." can no + longer be abbreviated "var c"; use "var co" instead. + (Or "var const" or "var constant" + +2008-01-07 19:57 Rocky Bernstein + + * ChangeLog: Add class level variables to "info variables" + +2008-01-07 17:37 Rocky Bernstein + + * ChangeLog: Add "self" to list "info variables" spits out. + +2008-01-07 09:59 Rocky Bernstein + + * ChangeLog: --emacs sets width to 120. rdebug-core.el will reset + to 120 unless it's already that. + +2008-01-07 04:29 Rocky Bernstein + + * ChangeLog: Split out ChangeLogs better (I hope). + +2008-01-06 20:56 Rocky Bernstein + + * ChangeLog: test/*-emacs-basic*, tdebug: Add test of running in + Emacs without annotations. + + emacs/*.el: make regexp tests work again, move regexp to from + core to regexp. + Add an annotate regexp test. + + processor.rb: Remove some anotation print from bleeding into + output + when annotations are not wanted. Reinstate "Program finished" in + annotations and outside (rdebug). + +2008-01-06 18:55 Rocky Bernstein + + * ChangeLog: Create Processor class and subclass that. Perhaps a + mixin would be good. + Remove annotation output bleanding when annotate is off. + Try to reduce the mess annotations is adding to processor.rb + rdebug-core.el: fix indentation to pass the regression test + Anders added + Makefile.am: Add rdebug-source.el to distribution. + Make sure "rake test" + +2008-01-06 02:15 Rocky Bernstein + + * ChangeLog: Some work on saving state across a restart. More work + is needed on the + script command to get this working. The save-file name is now + optional. save.rb split off from script.rb Display expressions + and + some settings are now captured in the save/restore file. + Add interface.finalize - things that need to be done before quit + or + restart. + +2008-01-05 21:16 Rocky Bernstein + + * ChangeLog: More work to make annotate more like gdb's. + starting/stopping/exiting + should be more similar. Some code has been commented out until we + get + the Emacs interface to match. See "FIXME: ANNOTATE" in + processor.rb. + Also regression tests for output and annotate currently fail for + this + reason. + +2008-01-02 20:35 Rocky Bernstein + + * ChangeLog: helper.rb: add regexp for a position. TODO: add + parsing routine and use in + various commands + +2008-01-02 14:41 Rocky Bernstein + + * ChangeLog: processor.rb: Redo where starting/exiting annotations + are done. + rdebug.el: back off on setting output command for now. + +2008-01-01 15:23 Rocky Bernstein + + * ChangeLog: Fix --emacs to do --no-quit properly. + +2008-01-01 09:00 Rocky Bernstein + + * ChangeLog: Remove RDoc warnings caused because C files have been + split up. + +2008-01-01 05:51 Rocky Bernstein + + * ChangeLog: reindent -> indent. Makefile.am: wasn't including all + test files. + +2007-12-31 06:26 Rocky Bernstein + + * ChangeLog: Rakefile: add spit-off C files to ruby-debug-base gem. + +2007-12-31 06:23 Rocky Bernstein + + * ChangeLog: rdebug-test-cmd.el: Indentation + +2007-12-31 06:08 Rocky Bernstein + + * ChangeLog: Changes and more changes. + +2007-12-29 13:31 Rocky Bernstein + + * ChangeLog: Remove looping on quit. "-n" is broken so remove it + for now. + +2007-12-28 15:33 Rocky Bernstein + + * ChangeLog: info.rb: Incorrect test for no display expressions. + display.rb: Grammar thing. + processor.rb: Slightly cleaner code + test/* more/better tests. + +2007-12-27 21:03 Rocky Bernstein + + * ChangeLog: Be more agressive about resetting gud-last-frame and + gud-last-last-frame. These foul up tracking when debugging is + interrupted. + We probably need a special "reset" command. + +2007-12-26 18:35 Rocky Bernstein + + * ChangeLog: Version number games - maybe 0.10.1 is better. + +2007-12-25 23:40 Rocky Bernstein + + * ChangeLog: Add step- and step+. Document as well as the new + toggle command. + +2007-12-25 09:55 Rocky Bernstein + + * ChangeLog: Small doc fixes. + +2007-12-25 07:51 Rocky Bernstein + + * ChangeLog: Last commit before 0.10.0 release. + +2007-12-25 02:51 Rocky Bernstein + + * ChangeLog: breakpoints.*: main -> Object. Add bad Class name test + AUTHOR: Add Anders + README: note ruby-debug-extra. More precise (I think) + +2007-12-24 00:25 Rocky Bernstein + + * ChangeLog: Rakefile: set up gem unit test for ruby-debug-base. + Add file in test/ + so we could do the same for ruby-debug were it not for other + mysterious + problems. + +2007-12-23 17:33 Rocky Bernstein + + * ChangeLog: Go over packaging: + ChangeLogs for ruby-debug-base (in ext and lib) separate from CLI + ChangeLog + ChangeLogs now map userid to names + ruby-debug-base regression test included in ruby-debug-base + Columnize test separated. (It will disappear when ruby-debug + requires it + as an external) + +2007-12-16 21:31 Rocky Bernstein + + * ruby-debug-base.rb: Add "info variables test". + + ruby-debug-base.rb: Not sure how test(?M, file) ever worked + before but change + to use File.stat(file).mtime + info.rb: ignore debugger variables which are sometimes set. + +2007-12-10 03:23 Rocky Bernstein + + * ruby-debug-base.rb: doc changes. + +2007-06-26 07:05 Rocky Bernstein + + * ruby-debug-base.rb: Run .rdebugrc on Debugger.start. Look for + this in the current directory and run that instead the one in + $HOME if that exists. Again, inspired and compatible with gdb. + + rdebug: Check script for syntax errors before loading. We get + more informative errors and it doesn't look like rdebug is at + fault. + +2007-06-05 16:36 Kent Sibilev + + * ruby-debug-base.rb: code reorganization. + reverted 'run' command. + +2007-06-05 07:59 Kent Sibilev + + * ruby-debug-base.rb: restore post_mortem + +2007-06-02 15:01 Rocky Bernstein + + * ruby-debug-base.rb: lib/ruby-debug-base.rb: add Quit and Restart + exceptions which can reliably be used after the delayed exception + handling bug is fixed + emacs/rdebug-track.el and cli/ruby-debug/processor.rb: more + accurate line tracking in EMACS. When not in emacs should be more + like what was there. + +2007-06-01 21:57 Rocky Bernstein + + * ruby-debug-base.rb: parens around a print seems to give a + warning. Remove. + +2007-05-23 16:43 Rocky Bernstein + + * ruby-debug-base.rb: post_mortem: to test $! *before* running + debug_at_ext or else we may get an erroneous message: + ruby-debug-base.rb:162:in `current_context': Debugger.start is + not called yet. (RuntimeError) + + A simple test case to show the problem: + + "require rubygems" + "require ruby-debug" + Debugger.start + Debugger.post_mortem + exit # Causes us to incorrectly give the above error + +2007-05-15 20:22 Kent Sibilev + + * ruby-debug-base.rb: various fixes + +2007-04-27 23:21 Kent Sibilev + + * ruby-debug-base.rb: ditto + +2007-04-27 23:19 Kent Sibilev + + * ruby-debug-base.rb: add breakpoint method as an alias for + debugger in case breakpoint method is not defined already + +2007-03-25 01:03 Kent Sibilev + + * ruby-debug-base.rb: will start the debugger if necessary + +2007-03-24 18:17 Kent Sibilev + + * stable becomes the trunk + +2007-03-13 17:06 Kent Sibilev + + * fixed rdoc + +2007-03-01 23:44 Kent Sibilev + + * fixed post-mortem + +2007-02-27 08:02 Kent Sibilev + + * repackaging ruby-debug + +2007-02-23 20:56 Kent Sibilev + + * added an option for Debugger.debug_load to stop at the first line + of code + +2007-02-12 06:59 Kent Sibilev + + * added --emacs option + +2007-02-09 16:56 Kent Sibilev + + * in remote mode the debugger shouldn't stop inside of rdebug + script + +2007-02-09 06:20 Kent Sibilev + + * -- + +2007-02-09 01:00 Kent Sibilev + + * fixed code reloading + made 'reload on' as a part of the 'set' command + evaluate ~/.rdebugrc as an init script + +2007-02-07 02:42 Kent Sibilev + + * should use ignored? method to check for the debugger's thread + +2007-02-06 22:21 Kent Sibilev + + * + +2007-02-05 22:48 Kent Sibilev + + * -- + +2007-02-05 22:11 Kent Sibilev + + * fixed emacs integration + +2007-02-05 20:16 Kent Sibilev + + * fixed another issue where a bogus frame is being left in the + stack + +2007-02-04 23:36 Kent Sibilev + + * seg fault bugfixes + fixed suspend/resume + +2007-02-04 03:49 Kent Sibilev + + * A better fix for the segmentation fault + +2007-02-03 20:24 Kent Sibilev + + * fix seg fault by avoiding ruby's bug + fixed Context#resume + when handling post-mortem all threads must be suspended + +2007-02-02 18:47 Kent Sibilev + + * removed ambiguity with down command + +2007-02-01 23:48 Kent Sibilev + + * typo + +2007-02-01 22:15 Kent Sibilev + + * made eval command available from the control thread + +2007-02-01 07:22 Kent Sibilev + + * added setting command + added Context#suspended? method + dispay suspended status in the thread list + display frame starting from zero + +2007-01-31 21:13 Kent Sibilev + + * ditto + +2007-01-31 21:12 Kent Sibilev + + * fixed help command + +2007-01-31 19:39 Kent Sibilev + + * fixed frame count + added frame_self method to context + +2007-01-31 16:48 Kent Sibilev + + * removed all references to frames array + fixed post-mortem debugging + +2007-01-31 00:51 Kent Sibilev + + * removed obsolete frames usage + +2007-01-31 00:41 Kent Sibilev + + * refactored out frame class and preallocate stack + made local variable available even when bindings are not + collected. + +2007-01-28 20:25 Kent Sibilev + + * -- + +2007-01-28 06:22 Kent Sibilev + + * - Control thread is always started by rdebug script. + - Ability to specify negative frame number to frame commands. + Patch from R. Bernstein. + +2007-01-28 04:52 Kent Sibilev + + * added top frame caching + control thread is always started by rdebug script + +2007-01-27 01:43 Kent Sibilev + + * another performance optimization + +2007-01-26 20:28 Kent Sibilev + + * fixed #7484 + +2007-01-26 17:59 Kent Sibilev + + * revisited file name comparing procedure + +2007-01-26 09:03 Kent Sibilev + + * performance improvements + +2007-01-26 03:12 Kent Sibilev + + * added option to exclude collecting of frame bindings + +2007-01-24 18:33 Kent Sibilev + + * disable tracing when in post-mortem + added -x/--trace option to rdebug script + +2007-01-21 08:13 Kent Sibilev + + * + +2007-01-21 03:34 Kent Sibilev + + * assign an id to the breakpoint + +2007-01-21 01:20 Kent Sibilev + + * added post_mortem_method wrap method + +2006-12-21 20:16 Kent Sibilev + + * added 'restart' command + +2006-12-21 14:12 Kent Sibilev + + * made 'exit' an alias to 'quit' + fixed the interoperability problem with rspec + +2006-12-21 13:43 Kent Sibilev + + * fixed trace command in post-mortem mode + +2006-12-21 01:59 Kent Sibilev + + * initialize only once + +2006-12-21 01:08 Kent Sibilev + + * fixes irb help command + +2006-12-20 21:19 Kent Sibilev + + * check that debugger has been started + +2006-12-20 20:08 Kent Sibilev + + * added post-mortem option to rdebug + +2006-12-20 19:38 Kent Sibilev + + * initial support for post-mortem debugging + +2006-12-19 06:13 Kent Sibilev + + * removed 'run' alias + +2006-12-18 08:34 Kent Sibilev + + * added irb command + fixed source_for method + +2006-12-02 19:15 Kent Sibilev + + * added reload command + +2006-12-02 18:32 Kent Sibilev + + * fixed #6518 and #6545 + +2006-12-01 06:47 Kent Sibilev + + * + +2006-11-21 23:29 Kent Sibilev + + * ensure that on/off is the last on the line + +2006-11-16 00:04 Kent Sibilev + + * fixed debug_method for assignment methods + +2006-11-16 00:01 Kent Sibilev + + * added the new branch for the stable version + +2006-10-15 22:43 Kent Sibilev + + * branching a stable version + +2006-10-15 22:26 Kent Sibilev + + * ruby-debug.rb: remove unused require + uploaded new windows binary + +2006-10-15 19:02 Kent Sibilev + + * ruby-debug/commands/display.rb: remove unused constructor + +2006-10-15 16:54 Kent Sibilev + + * ruby-debug.rb, ruby-debug/commands/threads.rb: new logic of + context suspend/resume + +2006-10-15 07:36 Kent Sibilev + + * ruby-debug.rb, ruby-debug/lock.rb: fixed locking of debugger + threads + +2006-10-09 22:01 Kent Sibilev + + * ruby-debug/interface.rb: fixes for windows version + +2006-10-09 19:06 Kent Sibilev + + * ruby-debug.rb, ruby-debug/interface.rb: added Debugger.skip and + Debugger.debug_at_exit methods + +2006-10-09 16:44 Kent Sibilev + + * ., ruby-debug, ruby-debug.rb, ruby-debug/command.rb, + ruby-debug/commands, ruby-debug/commands/breakpoints.rb, + ruby-debug/commands/catchpoint.rb, + ruby-debug/commands/control.rb, ruby-debug/commands/display.rb, + ruby-debug/commands/eval.rb, ruby-debug/commands/frame.rb, + ruby-debug/commands/help.rb, ruby-debug/commands/list.rb, + ruby-debug/commands/method.rb, ruby-debug/commands/script.rb, + ruby-debug/commands/stepping.rb, ruby-debug/commands/threads.rb, + ruby-debug/commands/tmate.rb, ruby-debug/commands/trace.rb, + ruby-debug/commands/variables.rb, ruby-debug/interface.rb, + ruby-debug/lock.rb, ruby-debug/processor.rb: initial import + diff --git a/lib/.svn/text-base/ruby-debug-base.rb.svn-base b/lib/.svn/text-base/ruby-debug-base.rb.svn-base new file mode 100644 index 0000000..5995a66 --- /dev/null +++ b/lib/.svn/text-base/ruby-debug-base.rb.svn-base @@ -0,0 +1,298 @@ +require 'ruby_debug.so' +require 'rubygems' +require 'linecache' + +module Debugger + + # Default options to Debugger.start + DEFAULT_START_SETTINGS = { + :init => true, # Set $0 and save ARGV? + :post_mortem => false, # post-mortem debugging on uncaught exception? + :tracing => nil # Debugger.tracing value. true/false resets, + # nil keeps the prior value + } unless defined?(DEFAULT_START_SETTINGS) + + class Context + def interrupt + self.stop_next = 1 + end + + alias __c_frame_binding frame_binding + def frame_binding(frame) + __c_frame_binding(frame) || hbinding(frame) + end + + private + + def hbinding(frame) + hash = frame_locals(frame) + code = hash.keys.map{|k| "#{k} = hash['#{k}']" unless k=='self' }.compact.join(';') + ';binding' + if obj = frame_self(frame) + obj.instance_eval code + else + eval code, TOPLEVEL_BINDING + end + end + + def handler + Debugger.handler or raise 'No interface loaded' + end + + def at_breakpoint(breakpoint) + handler.at_breakpoint(self, breakpoint) + end + + def at_catchpoint(excpt) + handler.at_catchpoint(self, excpt) + end + + def at_tracing(file, line) + handler.at_tracing(self, file, line) + end + + def at_line(file, line) + handler.at_line(self, file, line) + end + + def at_return(file, line) + handler.at_return(self, file, line) + end + end + + @reload_source_on_change = false + + class << self + # interface modules provide +handler+ object + attr_accessor :handler + + # if true, checks the modification time of source files and reloads if it was modified + attr_accessor :reload_source_on_change + + attr_accessor :last_exception + Debugger.last_exception = nil + + # + # Interrupts the current thread + # + def interrupt + current_context.interrupt + end + + # + # Interrupts the last debugged thread + # + def interrupt_last + if context = last_context + return nil unless context.thread.alive? + context.interrupt + end + context + end + + def source_reload + LineCache::clear_file_cache(true) + end + + # Get line +line_number+ from file named +filename+. Return "\n" + # there was a problem. Leaking blanks are stripped off. + def line_at(filename, line_number) # :nodoc: + @reload_on_change=nil unless defined?(@reload_on_change) + line = LineCache::getline(filename, line_number, @reload_on_change) + return "\n" unless line + return "#{line.gsub(/^\s+/, '').chomp}\n" + end + + # + # Activates the post-mortem mode. There are two ways of using it: + # + # == Global post-mortem mode + # By calling Debugger.post_mortem method without a block, you install + # at_exit hook that intercepts any unhandled by your script exceptions + # and enables post-mortem mode. + # + # == Local post-mortem mode + # + # If you know that a particular block of code raises an exception you can + # enable post-mortem mode by wrapping this block with Debugger.post_mortem, e.g. + # + # def offender + # raise 'error' + # end + # Debugger.post_mortem do + # ... + # offender + # ... + # end + def post_mortem + if block_given? + old_post_mortem = self.post_mortem? + begin + self.post_mortem = true + yield + rescue Exception => exp + handle_post_mortem(exp) + raise + ensure + self.post_mortem = old_post_mortem + end + else + return if post_mortem? + self.post_mortem = true + debug_at_exit do + handle_post_mortem($!) if $! && post_mortem? + end + end + end + + def handle_post_mortem(exp) + return if !exp || !exp.__debug_context || + exp.__debug_context.stack_size == 0 + Debugger.suspend + orig_tracing = Debugger.tracing, Debugger.current_context.tracing + Debugger.tracing = Debugger.current_context.tracing = false + Debugger.last_exception = exp + handler.at_line(exp.__debug_context, exp.__debug_file, exp.__debug_line) + ensure + Debugger.tracing, Debugger.current_context.tracing = orig_tracing + Debugger.resume + end + # private :handle_post_mortem + end + + class DebugThread # :nodoc: + end + + class ThreadsTable # :nodoc: + end + + # Debugger.start(options) -> bool + # Debugger.start(options) { ... } -> obj + # + # If it's called without a block it returns +true+, unless debugger + # was already started. If a block is given, it starts debugger and + # yields to block. When the block is finished executing it stops + # the debugger with Debugger.stop method. + # + # If a block is given, it starts debugger and yields to block. When + # the block is finished executing it stops the debugger with + # Debugger.stop method. Inside the block you will probably want to + # have a call to Debugger.debugger. For example: + # + # Debugger.start{debugger; foo} # Stop inside of foo + # + # Also, ruby-debug only allows + # one invocation of debugger at a time; nested Debugger.start's + # have no effect and you can't use this inside the debugger itself. + # + # Note that if you want to stop debugger, you must call + # Debugger.stop as many time as you called Debugger.start + # method. + # + # +options+ is a hash used to set various debugging options. + # Set :init true if you want to save ARGV and some variables which + # make a debugger restart possible. Only the first time :init is set true + # will values get set. Since ARGV is saved, you should make sure + # it hasn't been changed before the (first) call. + # Set :post_mortem true if you want to enter post-mortem debugging + # on an uncaught exception. Once post-mortem debugging is set, it can't + # be unset. + def start(options={}, &block) + options = Debugger::DEFAULT_START_SETTINGS.merge(options) + if options[:init] + Debugger.const_set('ARGV', ARGV.clone) unless + defined? Debugger::ARGV + Debugger.const_set('PROG_SCRIPT', $0) unless + defined? Debugger::PROG_SCRIPT + Debugger.const_set('INITIAL_DIR', Dir.pwd) unless + defined? Debugger::INITIAL_DIR + end + Debugger.tracing = options[:tracing] unless options[:tracing].nil? + retval = Debugger.started? ? block && block.call(self) : Debugger.start_(&block) + if options[:post_mortem] + post_mortem + end + return retval + end + module_function :start +end + +module Kernel + + # Enters the debugger in the current thread after _steps_ line events occur. + # Before entering the debugger startup script is read. + # + # Setting _steps_ to 0 will cause a break in the debugger subroutine + # and not wait for a line event to occur. You will have to go "up 1" + # in order to be back in your debugged program rather than the + # debugger. Settings _steps_ to 0 could be useful you want to stop + # right after the last statement in some scope, because the next + # step will take you out of some scope. + + # If a block is given (and the debugger hasn't been started, we run the + # block under the debugger. Alas, when a block is given, we can't support + # running the startup script or support the steps option. FIXME. + def debugger(steps = 1, &block) + if block + Debugger.start({}, &block) + else + Debugger.start unless Debugger.started? + Debugger.run_init_script(StringIO.new) + if 0 == steps + Debugger.current_context.stop_frame = 0 + else + Debugger.current_context.stop_next = steps + end + end + end + alias breakpoint debugger unless respond_to?(:breakpoint) + + # + # Returns a binding of n-th call frame + # + def binding_n(n = 0) + Debugger.skip do + Debugger.current_context.frame_binding(n+2) + end + end +end + +class Exception # :nodoc: + attr_reader :__debug_file, :__debug_line, :__debug_binding, :__debug_context +end + +class Module + # + # Wraps the +meth+ method with Debugger.start {...} block. + # + def debug_method(meth) + old_meth = "__debugee_#{meth}" + old_meth = "#{$1}_set" if old_meth =~ /^(.+)=$/ + alias_method old_meth.to_sym, meth + class_eval <<-EOD + def #{meth}(*args, &block) + Debugger.start do + debugger 2 + #{old_meth}(*args, &block) + end + end + EOD + end + + # + # Wraps the +meth+ method with Debugger.post_mortem {...} block. + # + def post_mortem_method(meth) + old_meth = "__postmortem_#{meth}" + old_meth = "#{$1}_set" if old_meth =~ /^(.+)=$/ + alias_method old_meth.to_sym, meth + class_eval <<-EOD + def #{meth}(*args, &block) + Debugger.start do |dbg| + dbg.post_mortem do + #{old_meth}(*args, &block) + end + end + end + EOD + end +end diff --git a/lib/ChangeLog b/lib/ChangeLog new file mode 100644 index 0000000..12c8f69 --- /dev/null +++ b/lib/ChangeLog @@ -0,0 +1,1065 @@ +2009-03-29 03:00 Rocky Bernstein + + * ChangeLog: Canonicalize breakpoint locations a little better. + More work should be done and more work should be done on the + testing side too. + +2009-03-11 23:42 Rocky Bernstein + + * ChangeLog: update texinfo for catch + +2008-11-25 02:43 Rocky Bernstein + + * ChangeLog: Frame without a frame number means frame 0, same as + gdb. We are now in 0.10.4 territory now. + +2008-11-16 00:14 Rocky Bernstein + + * ChangeLog: Add rdoc for rdebug script. + +2008-11-14 19:28 Rocky Bernstein + + * ruby-debug-base.rb: Go over documentation and revise. + +2008-11-14 15:32 Rocky Bernstein + + * ChangeLog, ruby-debug-base.rb: Move Debugger#debugger from base + to cli. Revert code in ruby_debug.c and block parameter in + debugger. cf. -> Compare with. Document Debugger.start better. + +2008-11-13 10:29 Rocky Bernstein + + * ChangeLog: Make Debugger.start{block} work if Debugger.started? + is false. Second try. + +2008-11-11 02:07 Rocky Bernstein + + * ChangeLog: Tweak truncated stack test since Ruby's caller doesn't + seem to include (tail?) recursive calls and we do. Get regression + tests working in light of recent changes. + +2008-11-10 01:48 Kent Sibilev + + * ruby-debug-base.rb: a little bit more readable + +2008-11-10 01:35 Kent Sibilev + + * ruby-debug-base.rb: Debugger.start must always call the passed + block + +2008-11-07 19:35 Rocky Bernstein + + * ChangeLog: Change truncated frame message. + +2008-11-07 10:39 Rocky Bernstein + + * ChangeLog: Add check to "where" to see if the call stack is + truncated; task #2354 + +2008-11-06 16:17 Rocky Bernstein + + * ChangeLog: #22698 Allow ruby-debug-base 0.x.y.z be compatible + with ruby-debug 0.x.y. + +2008-11-02 21:59 Rocky Bernstein + + * ChangeLog, ruby-debug-base.rb: Debugger.start with a block now + stops inside the block. Debugger.debugger with a block works like + Debugger.start with a block. + + The whole interface is hopelessly kludgy and needs to be redone. + +2008-10-26 14:54 Rocky Bernstein + + * ChangeLog: Doc typo. Add comment to remind me how to turn off + optimizationin extconf.rb + +2008-10-25 16:01 Rocky Bernstein + + * ChangeLog: Warn and add a "confirmation" when setting a + breakpoint on a file that is not loaded. Regression tests no + longer fail. + +2008-09-22 00:07 Rocky Bernstein + + * ruby-debug-base.rb: #22118 bug in showing variables post mortem. + Patch thanks to rubikitch. + Update pm.rb integration test. + +2008-09-03 17:29 Rocky Bernstein + + * ChangeLog: Show line numbers when $DEBUG is set. Patch #21772 + from Martin Krauskopf + +2008-07-07 07:11 Rocky Bernstein + + * ruby-debug-base.rb: Tracker [#20041] start erroneously moved to + Kernel - should be in + Debugger.start + +2008-06-20 06:46 Rocky Bernstein + + * ruby-debug-base.rb: trace.rb: add "trace var" + ruby-debug-base.rb: remove another undefined warning. + +2008-05-24 01:27 Rocky Bernstein + + * ChangeLog: Remove dup lines. + +2008-05-15 16:05 Rocky Bernstein + + * ChangeLog: Handle "catch nnn off" Forgotten there during r656. + From mkrauskopf [#20156]. + +2008-05-05 18:05 Rocky Bernstein + + * ChangeLog: make test-frame installation independent. Bug #19931 + +2008-04-29 13:37 Rocky Bernstein + + * ChangeLog: Test line number in "continue" command for validity. + +2008-04-28 16:16 Rocky Bernstein + + * ChangeLog: From Martin Krauskopf via patch #19779 + + Allow folks to configure Ruby used for CLI tests in the + test/config.yaml. The defaults are for native Ruby, so nothing + needs + to be done for ruby-debug. + + Developers of interfaces other than cli might override + config.yaml by + customized config.private.yaml which is ignored. So there will be + no + trash in e.g. 'svn st' output when developer customize the Ruby + to be + used. + + Handy for alternative interface implementations using + svn:externals. + +2008-04-22 02:49 Rocky Bernstein + + * ruby-debug-base.rb: Experiment with debugger(steps=0). Puts us in + the debugger call, but this may be the best we can do for now. + See tracker + #19639. + +2008-04-16 01:11 Rocky Bernstein + + * ChangeLog: In 0.10.2 now. Some work to cope systems without + readline. More work is needed. + Add test of "set autoeval." Undefined command message more + closely like gdb's. + +2008-04-10 08:49 Rocky Bernstein + + * ChangeLog: linecache is required by ruby-debug-base not + ruby-debug. Thanks Martin! + +2008-04-10 08:00 Rocky Bernstein + + * ChangeLog: Last change before 0.10.1 release. + +2008-04-10 02:03 Rocky Bernstein + + * ChangeLog: Cosmetic stuff: spelling corrections. Update node + structure so texinfo + doesn't complain. + +2008-04-08 14:52 Rocky Bernstein + + * ChangeLog: autorequire is deprecated and presumably no longer + needed + http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/182827 + +2008-04-07 00:36 Rocky Bernstein + + * ChangeLog, ruby-debug-base.rb: ruby-debug-base.rb: document + Debugger.start parameters. + CHANGES: Revise what's happened + test-shortkey.el: A failing regression test because I think + rdebug-shortkey-mode + is not correct. + +2008-04-03 19:01 Rocky Bernstein + + * ChangeLog, ruby-debug-base.rb: Allow setting :post_mortem => true + from Debugger.start. + +2008-03-28 13:53 Rocky Bernstein + + * ChangeLog: Don't unconditionally turn on short-key mode when + annotations are on. Use rdebug-short-key-mode setting to decide. + +2008-03-23 17:47 Rocky Bernstein + + * ChangeLog: set.rb -> settings.rb since it's already one command + per file, and + remove another :nodoc. + Rakefile: split long line + +2008-03-18 16:05 Rocky Bernstein + + * ChangeLog: Fix bug in 'list' command when wrapping off the end. + test-finish.rb: tolerate buggy in Ruby versions <= 1.8.7. + +2008-03-13 02:15 Rocky Bernstein + + * ruby-debug-base.rb: INCOMPATIBLE CHANGE: "finish" works like gdb + - stop just before the + most recent method finishes. Will now accept a number which stops + that + many frames completed. (Note that return line numbers will be + funny, + the first line of the method until Ruby 1.8.7.) + +2008-03-10 13:28 Rocky Bernstein + + * ChangeLog: Dunno why we are now one line number less. So be it + (for now). + +2008-03-09 23:30 Rocky Bernstein + + * ChangeLog: For now we require the duplicate numbers on + conditionals. + +2008-03-02 04:20 Rocky Bernstein + + * ruby-debug-base.rb: Better error message for an invalid break + command. + +2008-02-28 05:06 Rocky Bernstein + + * ChangeLog: breakpoints.{cmd,right}: test for an invalid stopping + line number + rdebug-fns.el: move generic split-string-and-unquote from + rdebug-core. + rdebug-core.el: Add rdebug-common-init to replace + gud-common-init. Is + simpler, and finds files better via debugger output/annotations. + Fix bug in rdebug-setup-windows: gud-find-file can return nil, + and + we still need to set buf. + +2008-02-27 04:04 Rocky Bernstein + + * ruby-debug-base.rb: Slightly more robust handle_post_mortem. + +2008-02-26 17:31 Rocky Bernstein + + * ChangeLog: Go over source location positioning. 0 is now the + oldest (first) position. Add M-S-down and M-S-up for first and + last. More tests needed in test-fns.el and need to prompt on wrap + around. + +2008-02-26 00:57 Rocky Bernstein + + * ChangeLog: Fix bug in "info file xxx breakpoints". + +2008-02-24 16:36 Rocky Bernstein + + * ChangeLog: rdebug; make more Ruby 1.9 compatible. + +2008-02-24 16:14 Rocky Bernstein + + * ChangeLog: Minor changes. + rdbg.rb: don't need $DEBUG test any more + rdebug-regexp.el: go over with checkdoc + bin/rdebug: use PATH_SEPARATOR (for 'doze again) + +2008-02-24 04:51 Rocky Bernstein + + * ChangeLog: CLI: Add long help for "info file". + + test/test-help.rb: Make test failures easier to fix and more like + the + other tests. + + emacs/test: finish testing all of the funcitons in rdebug-fns.el + + rdebug-layouts.el: Make checkdoc clean. + rdebug-track.el: don't need to rename shell buffer. Do it as an + option only. + rdebug-secondary.el: get rid of hoaky buffer finding for at least + gud-comint-buf. (Should probably do others as well) + + DOC: Note weird line stopping locations. Describe what "ctrl" in + prompt means. + +2008-02-21 02:56 Rocky Bernstein + + * ChangeLog: Fringe for frame buffer the same as in source code. + Move + miscellaneous small functions to a new file. Reduce duplication + of + "chomp" code. + +2008-02-19 23:44 Rocky Bernstein + + * ChangeLog: rdebug-cmd.el: M-insert toggles shortkey mode in the + command buffer + rdebug: search for Ruby program if file is not found and no + SEPARATOR + chars in the filename + +2008-02-18 19:56 Rocky Bernstein + + * ChangeLog: Frame switching shouldn't be recorded in position + history ring. + +2008-02-17 13:57 Rocky Bernstein + + * ruby-debug-base.rb: Add Debugger.last_exception. Show exception + in post-mortem when "info program" + is issued. Reorganize list of major changes better. + +2008-02-13 21:47 Rocky Bernstein + + * ChangeLog: processor.rb: spelled "post-mortem" incorrectly in + prompt. + +2008-02-13 17:32 Rocky Bernstein + + * ChangeLog: Set up keys for comint-next-prompt and + comint-previous-prompt. + +2008-02-12 02:06 Rocky Bernstein + + * ChangeLog: Fix bug in "info thread verbose" which wasn't showing + full traceback. + +2008-02-09 15:48 Rocky Bernstein + + * ChangeLog: helper.rb Failed attempt to DRY tests more. But save + what we have + which may someday in the future be used to go further. Minus to + undercore in Data file names in preparation such time. (We'll use + the + filename as the test name). + + testing + +2008-02-06 16:15 Rocky Bernstein + + * ChangeLog: Add 'nowarn to find-file-noselect and test that we + don't get a warning. + +2008-02-05 01:41 Rocky Bernstein + + * ChangeLog: rdebug.el: Add a defgroup for rdebug so customization + in Emacs 23 is possible. + Some other minor doc fixes. + setshow.* make sure we don't have an $Id line that we have to + check against. + +2008-02-03 15:23 Rocky Bernstein + + * ChangeLog: Try to get testing a little more organized, although + more work should + be done: Create a data directory for comparison ("right") and + script + command ("cmd") files. Code is now more uniform (and should DRY'd + a + bit more). + +2008-02-02 23:10 Rocky Bernstein + + * ChangeLog: Remove commands in post-mortem which are not + applicable, e.g."step", + "next", "continue"... + + "No breakpoints have been set" is now an error message when + trying to + set a breakpoint. + + Add post-mortem test. + + Debug.init no longer exists. + +2008-02-02 09:27 Rocky Bernstein + + * ruby-debug-base.rb: Remove Debugger.init and fold options + parameter into Debugger.start. + Old Debugger.start has been renamed Deebugger.start_ + +2008-01-31 16:30 Rocky Bernstein + + * ChangeLog: Leave ruby_debug.c this way for now. + +2008-01-31 16:24 Rocky Bernstein + + * ChangeLog: ruby_debug.c: more adventures in exception handling + processor.rb: Removal of crash when annotate is on. Need to fix + the source of the + problem though. + +2008-01-31 15:16 Rocky Bernstein + + * ruby-debug-base.rb: Handle post-mortem and exception traceback + reporting in ruby-debug + +2008-01-30 17:01 Rocky Bernstein + + * ChangeLog: Add Command.find() to find a subcommand name. + condition.right: correct for breakpoint hit counts. + +2008-01-30 01:43 Rocky Bernstein + + * ChangeLog: Add number of times a breakpoint is hit like gdb does. + +2008-01-29 22:37 Rocky Bernstein + + * ChangeLog: Columnize breakpoint output. + +2008-01-29 11:20 Rocky Bernstein + + * ChangeLog: More annotate=2 fixes. + +2008-01-28 15:59 Rocky Bernstein + + * ChangeLog: Add info file breakpoints to show lines which we can + set a breakpoint on. + Revise so we chdir into SRC_DIR. + test-hist.rb is broken - will fix later. + +2008-01-25 12:11 Rocky Bernstein + + * ChangeLog, ruby-debug-base.rb: Add Debugger.init which intializes + things that rdebug does. This + allows a restart even though rdebug wasn't called initially. + +2008-01-22 23:15 Rocky Bernstein + + * ChangeLog: Allow "help info xxx". Add ability for long help on + "info" command. + Add "info break xx". + + test: remove test/unit class name conflicts. All the tests we + wrote + now get run. + +2008-01-19 19:28 Rocky Bernstein + + * ChangeLog: Move ruby-debug-base tests to base directory. Add a + binding_n regression test. + +2008-01-16 18:42 Rocky Bernstein + + * ChangeLog: Need to present source filename (__FILE__) as Ruby and + therefore breakpoint + sees it. + + +2008-01-16 02:19 Rocky Bernstein + + * ChangeLog, ruby-debug-base.rb: Line caching moved to an external + gem, linecache. We now require + version 0.2 of that or greater. + +2008-01-14 01:31 Rocky Bernstein + + * ChangeLog: Make rdebug-track work better in the face of prompt + and error annotations. + control.rb: need another test when rdebug not called initially. + +2008-01-13 21:51 Rocky Bernstein + + * ChangeLog: Some stack -> frame renaming + ext/breakpoint.c: put methods in alpha order (to help with + reference man) + breakpoints.rb: one print -> errmsg + +2008-01-13 18:13 Rocky Bernstein + + * ChangeLog: Create errmsg routine for error output, start tagging + error messages + as errors. Under annotate 3, output errors similar to gdb + --annotate + does (although still simplified). Have Emacs pick up debugger + error + annotations. + +2008-01-13 04:05 Rocky Bernstein + + * ChangeLog: Check validity of expressions in breakpoint conditions + and don't allow + enabling a syntactically invalid expression. + + Start noting messages which are errors via an errmsg routine. + +2008-01-11 10:26 Rocky Bernstein + + * ChangeLog: Document that ruby-debug resets $0. Align program + options in ref manual and --help. Alphabetize better. + +2008-01-10 22:56 Rocky Bernstein + + * ChangeLog: More correct $0 fix. Deal with the case ./ is + automatically added. + However this might not be right in all cases. + +2008-01-10 22:25 Rocky Bernstein + + * ChangeLog: Was gobbling arg in processing --emacs. Add test. + +2008-01-10 10:34 Rocky Bernstein + + * ChangeLog: Add condition command. + +2008-01-09 19:10 Rocky Bernstein + + * ChangeLog: Rakefile: rdebug.rb -> rdbg.el + rdebug-dbg.el: Add $Id$ + +2008-01-09 19:03 Rocky Bernstein + + * ChangeLog: Break out secondary buffer into their own file, and + also internal + debug code and general secondary commands. Secondary buffer code + removed from rdebug-cmd and moved into the appropriate file. + + rdebug-edit-variables-value is not defined so comment out for + now. + +2008-01-08 16:04 Rocky Bernstein + + * ChangeLog: Restore $: to the value it was before rdebug call. + +2008-01-07 20:38 Rocky Bernstein + + * ChangeLog: Add "var class". This means "var const .." can no + longer be abbreviated "var c"; use "var co" instead. + (Or "var const" or "var constant" + +2008-01-07 19:57 Rocky Bernstein + + * ChangeLog: Add class level variables to "info variables" + +2008-01-07 17:37 Rocky Bernstein + + * ChangeLog: Add "self" to list "info variables" spits out. + +2008-01-07 09:59 Rocky Bernstein + + * ChangeLog: --emacs sets width to 120. rdebug-core.el will reset + to 120 unless it's already that. + +2008-01-07 04:29 Rocky Bernstein + + * ChangeLog: Split out ChangeLogs better (I hope). + +2008-01-06 20:56 Rocky Bernstein + + * ChangeLog: test/*-emacs-basic*, tdebug: Add test of running in + Emacs without annotations. + + emacs/*.el: make regexp tests work again, move regexp to from + core to regexp. + Add an annotate regexp test. + + processor.rb: Remove some anotation print from bleeding into + output + when annotations are not wanted. Reinstate "Program finished" in + annotations and outside (rdebug). + +2008-01-06 18:55 Rocky Bernstein + + * ChangeLog: Create Processor class and subclass that. Perhaps a + mixin would be good. + Remove annotation output bleanding when annotate is off. + Try to reduce the mess annotations is adding to processor.rb + rdebug-core.el: fix indentation to pass the regression test + Anders added + Makefile.am: Add rdebug-source.el to distribution. + Make sure "rake test" + +2008-01-06 02:15 Rocky Bernstein + + * ChangeLog: Some work on saving state across a restart. More work + is needed on the + script command to get this working. The save-file name is now + optional. save.rb split off from script.rb Display expressions + and + some settings are now captured in the save/restore file. + Add interface.finalize - things that need to be done before quit + or + restart. + +2008-01-05 21:16 Rocky Bernstein + + * ChangeLog: More work to make annotate more like gdb's. + starting/stopping/exiting + should be more similar. Some code has been commented out until we + get + the Emacs interface to match. See "FIXME: ANNOTATE" in + processor.rb. + Also regression tests for output and annotate currently fail for + this + reason. + +2008-01-02 20:35 Rocky Bernstein + + * ChangeLog: helper.rb: add regexp for a position. TODO: add + parsing routine and use in + various commands + +2008-01-02 14:41 Rocky Bernstein + + * ChangeLog: processor.rb: Redo where starting/exiting annotations + are done. + rdebug.el: back off on setting output command for now. + +2008-01-01 15:23 Rocky Bernstein + + * ChangeLog: Fix --emacs to do --no-quit properly. + +2008-01-01 09:00 Rocky Bernstein + + * ChangeLog: Remove RDoc warnings caused because C files have been + split up. + +2008-01-01 05:51 Rocky Bernstein + + * ChangeLog: reindent -> indent. Makefile.am: wasn't including all + test files. + +2007-12-31 06:26 Rocky Bernstein + + * ChangeLog: Rakefile: add spit-off C files to ruby-debug-base gem. + +2007-12-31 06:23 Rocky Bernstein + + * ChangeLog: rdebug-test-cmd.el: Indentation + +2007-12-31 06:08 Rocky Bernstein + + * ChangeLog: Changes and more changes. + +2007-12-29 13:31 Rocky Bernstein + + * ChangeLog: Remove looping on quit. "-n" is broken so remove it + for now. + +2007-12-28 15:33 Rocky Bernstein + + * ChangeLog: info.rb: Incorrect test for no display expressions. + display.rb: Grammar thing. + processor.rb: Slightly cleaner code + test/* more/better tests. + +2007-12-27 21:03 Rocky Bernstein + + * ChangeLog: Be more agressive about resetting gud-last-frame and + gud-last-last-frame. These foul up tracking when debugging is + interrupted. + We probably need a special "reset" command. + +2007-12-26 18:35 Rocky Bernstein + + * ChangeLog: Version number games - maybe 0.10.1 is better. + +2007-12-25 23:40 Rocky Bernstein + + * ChangeLog: Add step- and step+. Document as well as the new + toggle command. + +2007-12-25 09:55 Rocky Bernstein + + * ChangeLog: Small doc fixes. + +2007-12-25 07:51 Rocky Bernstein + + * ChangeLog: Last commit before 0.10.0 release. + +2007-12-25 02:51 Rocky Bernstein + + * ChangeLog: breakpoints.*: main -> Object. Add bad Class name test + AUTHOR: Add Anders + README: note ruby-debug-extra. More precise (I think) + +2007-12-24 00:25 Rocky Bernstein + + * ChangeLog: Rakefile: set up gem unit test for ruby-debug-base. + Add file in test/ + so we could do the same for ruby-debug were it not for other + mysterious + problems. + +2007-12-23 17:33 Rocky Bernstein + + * ChangeLog: Go over packaging: + ChangeLogs for ruby-debug-base (in ext and lib) separate from CLI + ChangeLog + ChangeLogs now map userid to names + ruby-debug-base regression test included in ruby-debug-base + Columnize test separated. (It will disappear when ruby-debug + requires it + as an external) + +2007-12-16 21:31 Rocky Bernstein + + * ruby-debug-base.rb: Add "info variables test". + + ruby-debug-base.rb: Not sure how test(?M, file) ever worked + before but change + to use File.stat(file).mtime + info.rb: ignore debugger variables which are sometimes set. + +2007-12-10 03:23 Rocky Bernstein + + * ruby-debug-base.rb: doc changes. + +2007-06-26 07:05 Rocky Bernstein + + * ruby-debug-base.rb: Run .rdebugrc on Debugger.start. Look for + this in the current directory and run that instead the one in + $HOME if that exists. Again, inspired and compatible with gdb. + + rdebug: Check script for syntax errors before loading. We get + more informative errors and it doesn't look like rdebug is at + fault. + +2007-06-05 16:36 Kent Sibilev + + * ruby-debug-base.rb: code reorganization. + reverted 'run' command. + +2007-06-05 07:59 Kent Sibilev + + * ruby-debug-base.rb: restore post_mortem + +2007-06-02 15:01 Rocky Bernstein + + * ruby-debug-base.rb: lib/ruby-debug-base.rb: add Quit and Restart + exceptions which can reliably be used after the delayed exception + handling bug is fixed + emacs/rdebug-track.el and cli/ruby-debug/processor.rb: more + accurate line tracking in EMACS. When not in emacs should be more + like what was there. + +2007-06-01 21:57 Rocky Bernstein + + * ruby-debug-base.rb: parens around a print seems to give a + warning. Remove. + +2007-05-23 16:43 Rocky Bernstein + + * ruby-debug-base.rb: post_mortem: to test $! *before* running + debug_at_ext or else we may get an erroneous message: + ruby-debug-base.rb:162:in `current_context': Debugger.start is + not called yet. (RuntimeError) + + A simple test case to show the problem: + + "require rubygems" + "require ruby-debug" + Debugger.start + Debugger.post_mortem + exit # Causes us to incorrectly give the above error + +2007-05-15 20:22 Kent Sibilev + + * ruby-debug-base.rb: various fixes + +2007-04-27 23:21 Kent Sibilev + + * ruby-debug-base.rb: ditto + +2007-04-27 23:19 Kent Sibilev + + * ruby-debug-base.rb: add breakpoint method as an alias for + debugger in case breakpoint method is not defined already + +2007-03-25 01:03 Kent Sibilev + + * ruby-debug-base.rb: will start the debugger if necessary + +2007-03-24 18:17 Kent Sibilev + + * stable becomes the trunk + +2007-03-13 17:06 Kent Sibilev + + * fixed rdoc + +2007-03-01 23:44 Kent Sibilev + + * fixed post-mortem + +2007-02-27 08:02 Kent Sibilev + + * repackaging ruby-debug + +2007-02-23 20:56 Kent Sibilev + + * added an option for Debugger.debug_load to stop at the first line + of code + +2007-02-12 06:59 Kent Sibilev + + * added --emacs option + +2007-02-09 16:56 Kent Sibilev + + * in remote mode the debugger shouldn't stop inside of rdebug + script + +2007-02-09 06:20 Kent Sibilev + + * -- + +2007-02-09 01:00 Kent Sibilev + + * fixed code reloading + made 'reload on' as a part of the 'set' command + evaluate ~/.rdebugrc as an init script + +2007-02-07 02:42 Kent Sibilev + + * should use ignored? method to check for the debugger's thread + +2007-02-06 22:21 Kent Sibilev + + * + +2007-02-05 22:48 Kent Sibilev + + * -- + +2007-02-05 22:11 Kent Sibilev + + * fixed emacs integration + +2007-02-05 20:16 Kent Sibilev + + * fixed another issue where a bogus frame is being left in the + stack + +2007-02-04 23:36 Kent Sibilev + + * seg fault bugfixes + fixed suspend/resume + +2007-02-04 03:49 Kent Sibilev + + * A better fix for the segmentation fault + +2007-02-03 20:24 Kent Sibilev + + * fix seg fault by avoiding ruby's bug + fixed Context#resume + when handling post-mortem all threads must be suspended + +2007-02-02 18:47 Kent Sibilev + + * removed ambiguity with down command + +2007-02-01 23:48 Kent Sibilev + + * typo + +2007-02-01 22:15 Kent Sibilev + + * made eval command available from the control thread + +2007-02-01 07:22 Kent Sibilev + + * added setting command + added Context#suspended? method + dispay suspended status in the thread list + display frame starting from zero + +2007-01-31 21:13 Kent Sibilev + + * ditto + +2007-01-31 21:12 Kent Sibilev + + * fixed help command + +2007-01-31 19:39 Kent Sibilev + + * fixed frame count + added frame_self method to context + +2007-01-31 16:48 Kent Sibilev + + * removed all references to frames array + fixed post-mortem debugging + +2007-01-31 00:51 Kent Sibilev + + * removed obsolete frames usage + +2007-01-31 00:41 Kent Sibilev + + * refactored out frame class and preallocate stack + made local variable available even when bindings are not + collected. + +2007-01-28 20:25 Kent Sibilev + + * -- + +2007-01-28 06:22 Kent Sibilev + + * - Control thread is always started by rdebug script. + - Ability to specify negative frame number to frame commands. + Patch from R. Bernstein. + +2007-01-28 04:52 Kent Sibilev + + * added top frame caching + control thread is always started by rdebug script + +2007-01-27 01:43 Kent Sibilev + + * another performance optimization + +2007-01-26 20:28 Kent Sibilev + + * fixed #7484 + +2007-01-26 17:59 Kent Sibilev + + * revisited file name comparing procedure + +2007-01-26 09:03 Kent Sibilev + + * performance improvements + +2007-01-26 03:12 Kent Sibilev + + * added option to exclude collecting of frame bindings + +2007-01-24 18:33 Kent Sibilev + + * disable tracing when in post-mortem + added -x/--trace option to rdebug script + +2007-01-21 08:13 Kent Sibilev + + * + +2007-01-21 03:34 Kent Sibilev + + * assign an id to the breakpoint + +2007-01-21 01:20 Kent Sibilev + + * added post_mortem_method wrap method + +2006-12-21 20:16 Kent Sibilev + + * added 'restart' command + +2006-12-21 14:12 Kent Sibilev + + * made 'exit' an alias to 'quit' + fixed the interoperability problem with rspec + +2006-12-21 13:43 Kent Sibilev + + * fixed trace command in post-mortem mode + +2006-12-21 01:59 Kent Sibilev + + * initialize only once + +2006-12-21 01:08 Kent Sibilev + + * fixes irb help command + +2006-12-20 21:19 Kent Sibilev + + * check that debugger has been started + +2006-12-20 20:08 Kent Sibilev + + * added post-mortem option to rdebug + +2006-12-20 19:38 Kent Sibilev + + * initial support for post-mortem debugging + +2006-12-19 06:13 Kent Sibilev + + * removed 'run' alias + +2006-12-18 08:34 Kent Sibilev + + * added irb command + fixed source_for method + +2006-12-02 19:15 Kent Sibilev + + * added reload command + +2006-12-02 18:32 Kent Sibilev + + * fixed #6518 and #6545 + +2006-12-01 06:47 Kent Sibilev + + * + +2006-11-21 23:29 Kent Sibilev + + * ensure that on/off is the last on the line + +2006-11-16 00:04 Kent Sibilev + + * fixed debug_method for assignment methods + +2006-11-16 00:01 Kent Sibilev + + * added the new branch for the stable version + +2006-10-15 22:43 Kent Sibilev + + * branching a stable version + +2006-10-15 22:26 Kent Sibilev + + * ruby-debug.rb: remove unused require + uploaded new windows binary + +2006-10-15 19:02 Kent Sibilev + + * ruby-debug/commands/display.rb: remove unused constructor + +2006-10-15 16:54 Kent Sibilev + + * ruby-debug.rb, ruby-debug/commands/threads.rb: new logic of + context suspend/resume + +2006-10-15 07:36 Kent Sibilev + + * ruby-debug.rb, ruby-debug/lock.rb: fixed locking of debugger + threads + +2006-10-09 22:01 Kent Sibilev + + * ruby-debug/interface.rb: fixes for windows version + +2006-10-09 19:06 Kent Sibilev + + * ruby-debug.rb, ruby-debug/interface.rb: added Debugger.skip and + Debugger.debug_at_exit methods + +2006-10-09 16:44 Kent Sibilev + + * ., ruby-debug, ruby-debug.rb, ruby-debug/command.rb, + ruby-debug/commands, ruby-debug/commands/breakpoints.rb, + ruby-debug/commands/catchpoint.rb, + ruby-debug/commands/control.rb, ruby-debug/commands/display.rb, + ruby-debug/commands/eval.rb, ruby-debug/commands/frame.rb, + ruby-debug/commands/help.rb, ruby-debug/commands/list.rb, + ruby-debug/commands/method.rb, ruby-debug/commands/script.rb, + ruby-debug/commands/stepping.rb, ruby-debug/commands/threads.rb, + ruby-debug/commands/tmate.rb, ruby-debug/commands/trace.rb, + ruby-debug/commands/variables.rb, ruby-debug/interface.rb, + ruby-debug/lock.rb, ruby-debug/processor.rb: initial import + diff --git a/lib/ruby-debug-base.rb b/lib/ruby-debug-base.rb new file mode 100644 index 0000000..5995a66 --- /dev/null +++ b/lib/ruby-debug-base.rb @@ -0,0 +1,298 @@ +require 'ruby_debug.so' +require 'rubygems' +require 'linecache' + +module Debugger + + # Default options to Debugger.start + DEFAULT_START_SETTINGS = { + :init => true, # Set $0 and save ARGV? + :post_mortem => false, # post-mortem debugging on uncaught exception? + :tracing => nil # Debugger.tracing value. true/false resets, + # nil keeps the prior value + } unless defined?(DEFAULT_START_SETTINGS) + + class Context + def interrupt + self.stop_next = 1 + end + + alias __c_frame_binding frame_binding + def frame_binding(frame) + __c_frame_binding(frame) || hbinding(frame) + end + + private + + def hbinding(frame) + hash = frame_locals(frame) + code = hash.keys.map{|k| "#{k} = hash['#{k}']" unless k=='self' }.compact.join(';') + ';binding' + if obj = frame_self(frame) + obj.instance_eval code + else + eval code, TOPLEVEL_BINDING + end + end + + def handler + Debugger.handler or raise 'No interface loaded' + end + + def at_breakpoint(breakpoint) + handler.at_breakpoint(self, breakpoint) + end + + def at_catchpoint(excpt) + handler.at_catchpoint(self, excpt) + end + + def at_tracing(file, line) + handler.at_tracing(self, file, line) + end + + def at_line(file, line) + handler.at_line(self, file, line) + end + + def at_return(file, line) + handler.at_return(self, file, line) + end + end + + @reload_source_on_change = false + + class << self + # interface modules provide +handler+ object + attr_accessor :handler + + # if true, checks the modification time of source files and reloads if it was modified + attr_accessor :reload_source_on_change + + attr_accessor :last_exception + Debugger.last_exception = nil + + # + # Interrupts the current thread + # + def interrupt + current_context.interrupt + end + + # + # Interrupts the last debugged thread + # + def interrupt_last + if context = last_context + return nil unless context.thread.alive? + context.interrupt + end + context + end + + def source_reload + LineCache::clear_file_cache(true) + end + + # Get line +line_number+ from file named +filename+. Return "\n" + # there was a problem. Leaking blanks are stripped off. + def line_at(filename, line_number) # :nodoc: + @reload_on_change=nil unless defined?(@reload_on_change) + line = LineCache::getline(filename, line_number, @reload_on_change) + return "\n" unless line + return "#{line.gsub(/^\s+/, '').chomp}\n" + end + + # + # Activates the post-mortem mode. There are two ways of using it: + # + # == Global post-mortem mode + # By calling Debugger.post_mortem method without a block, you install + # at_exit hook that intercepts any unhandled by your script exceptions + # and enables post-mortem mode. + # + # == Local post-mortem mode + # + # If you know that a particular block of code raises an exception you can + # enable post-mortem mode by wrapping this block with Debugger.post_mortem, e.g. + # + # def offender + # raise 'error' + # end + # Debugger.post_mortem do + # ... + # offender + # ... + # end + def post_mortem + if block_given? + old_post_mortem = self.post_mortem? + begin + self.post_mortem = true + yield + rescue Exception => exp + handle_post_mortem(exp) + raise + ensure + self.post_mortem = old_post_mortem + end + else + return if post_mortem? + self.post_mortem = true + debug_at_exit do + handle_post_mortem($!) if $! && post_mortem? + end + end + end + + def handle_post_mortem(exp) + return if !exp || !exp.__debug_context || + exp.__debug_context.stack_size == 0 + Debugger.suspend + orig_tracing = Debugger.tracing, Debugger.current_context.tracing + Debugger.tracing = Debugger.current_context.tracing = false + Debugger.last_exception = exp + handler.at_line(exp.__debug_context, exp.__debug_file, exp.__debug_line) + ensure + Debugger.tracing, Debugger.current_context.tracing = orig_tracing + Debugger.resume + end + # private :handle_post_mortem + end + + class DebugThread # :nodoc: + end + + class ThreadsTable # :nodoc: + end + + # Debugger.start(options) -> bool + # Debugger.start(options) { ... } -> obj + # + # If it's called without a block it returns +true+, unless debugger + # was already started. If a block is given, it starts debugger and + # yields to block. When the block is finished executing it stops + # the debugger with Debugger.stop method. + # + # If a block is given, it starts debugger and yields to block. When + # the block is finished executing it stops the debugger with + # Debugger.stop method. Inside the block you will probably want to + # have a call to Debugger.debugger. For example: + # + # Debugger.start{debugger; foo} # Stop inside of foo + # + # Also, ruby-debug only allows + # one invocation of debugger at a time; nested Debugger.start's + # have no effect and you can't use this inside the debugger itself. + # + # Note that if you want to stop debugger, you must call + # Debugger.stop as many time as you called Debugger.start + # method. + # + # +options+ is a hash used to set various debugging options. + # Set :init true if you want to save ARGV and some variables which + # make a debugger restart possible. Only the first time :init is set true + # will values get set. Since ARGV is saved, you should make sure + # it hasn't been changed before the (first) call. + # Set :post_mortem true if you want to enter post-mortem debugging + # on an uncaught exception. Once post-mortem debugging is set, it can't + # be unset. + def start(options={}, &block) + options = Debugger::DEFAULT_START_SETTINGS.merge(options) + if options[:init] + Debugger.const_set('ARGV', ARGV.clone) unless + defined? Debugger::ARGV + Debugger.const_set('PROG_SCRIPT', $0) unless + defined? Debugger::PROG_SCRIPT + Debugger.const_set('INITIAL_DIR', Dir.pwd) unless + defined? Debugger::INITIAL_DIR + end + Debugger.tracing = options[:tracing] unless options[:tracing].nil? + retval = Debugger.started? ? block && block.call(self) : Debugger.start_(&block) + if options[:post_mortem] + post_mortem + end + return retval + end + module_function :start +end + +module Kernel + + # Enters the debugger in the current thread after _steps_ line events occur. + # Before entering the debugger startup script is read. + # + # Setting _steps_ to 0 will cause a break in the debugger subroutine + # and not wait for a line event to occur. You will have to go "up 1" + # in order to be back in your debugged program rather than the + # debugger. Settings _steps_ to 0 could be useful you want to stop + # right after the last statement in some scope, because the next + # step will take you out of some scope. + + # If a block is given (and the debugger hasn't been started, we run the + # block under the debugger. Alas, when a block is given, we can't support + # running the startup script or support the steps option. FIXME. + def debugger(steps = 1, &block) + if block + Debugger.start({}, &block) + else + Debugger.start unless Debugger.started? + Debugger.run_init_script(StringIO.new) + if 0 == steps + Debugger.current_context.stop_frame = 0 + else + Debugger.current_context.stop_next = steps + end + end + end + alias breakpoint debugger unless respond_to?(:breakpoint) + + # + # Returns a binding of n-th call frame + # + def binding_n(n = 0) + Debugger.skip do + Debugger.current_context.frame_binding(n+2) + end + end +end + +class Exception # :nodoc: + attr_reader :__debug_file, :__debug_line, :__debug_binding, :__debug_context +end + +class Module + # + # Wraps the +meth+ method with Debugger.start {...} block. + # + def debug_method(meth) + old_meth = "__debugee_#{meth}" + old_meth = "#{$1}_set" if old_meth =~ /^(.+)=$/ + alias_method old_meth.to_sym, meth + class_eval <<-EOD + def #{meth}(*args, &block) + Debugger.start do + debugger 2 + #{old_meth}(*args, &block) + end + end + EOD + end + + # + # Wraps the +meth+ method with Debugger.post_mortem {...} block. + # + def post_mortem_method(meth) + old_meth = "__postmortem_#{meth}" + old_meth = "#{$1}_set" if old_meth =~ /^(.+)=$/ + alias_method old_meth.to_sym, meth + class_eval <<-EOD + def #{meth}(*args, &block) + Debugger.start do |dbg| + dbg.post_mortem do + #{old_meth}(*args, &block) + end + end + end + EOD + end +end diff --git a/rdbg.rb b/rdbg.rb new file mode 100755 index 0000000..558e96b --- /dev/null +++ b/rdbg.rb @@ -0,0 +1,33 @@ +#!/usr/bin/env ruby +#!/usr/bin/env ruby +# $Id: rdbg.rb 756 2008-03-13 02:15:04Z rockyb $ + +# Use this to run rdebug without installing it. We assume that the +# library directories are stored at the same level the directory +# this program. +module RDebugRunner + def runner(stdout=nil) + + # Add libraries to load path. + dirname=File.dirname(__FILE__) + libs = %w(ext lib cli) + libs.each { |lib| $:.unshift File.join(dirname, lib) } + + rdebug=ENV['RDEBUG'] || File.join(dirname, 'bin', 'rdebug') + if stdout + old_stdout = $stdout + $stdout.reopen(stdout) + else + old_stdout = nil + end + load(rdebug, true) + $stdout.reopen(old_stdout) if old_stdout + + # Remove those libraries we just added. + 1.upto(libs.size) {$:.shift} + end + module_function :runner +end +if __FILE__ == $0 + RDebugRunner.runner +end diff --git a/runner.sh b/runner.sh new file mode 100755 index 0000000..5a8f720 --- /dev/null +++ b/runner.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +ruby=${RUBY:-ruby} +dir=`dirname $0` +rdebug=${RDEBUG:-${dir}/bin/rdebug} +$ruby -I${dir}/ext:${dir}/lib:${dir}/cli -- $rdebug $* +exit $? diff --git a/svn2cl_usermap b/svn2cl_usermap new file mode 100644 index 0000000..5181cbd --- /dev/null +++ b/svn2cl_usermap @@ -0,0 +1,3 @@ +andersl:Anders Lindgren +kent:Kent Sibilev +rockyb:Rocky Bernstein diff --git a/test/.cvsignore b/test/.cvsignore new file mode 100644 index 0000000..b997925 --- /dev/null +++ b/test/.cvsignore @@ -0,0 +1 @@ +config.private.yaml diff --git a/test/.svn/README.txt b/test/.svn/README.txt new file mode 100644 index 0000000..271a8ce --- /dev/null +++ b/test/.svn/README.txt @@ -0,0 +1,2 @@ +This is a Subversion working copy administrative directory. +Visit http://subversion.tigris.org/ for more information. diff --git a/test/.svn/dir-prop-base b/test/.svn/dir-prop-base new file mode 100644 index 0000000..b06d36d --- /dev/null +++ b/test/.svn/dir-prop-base @@ -0,0 +1,6 @@ +K 10 +svn:ignore +V 20 +config.private.yaml + +END diff --git a/test/.svn/dir-props b/test/.svn/dir-props new file mode 100644 index 0000000..b06d36d --- /dev/null +++ b/test/.svn/dir-props @@ -0,0 +1,6 @@ +K 10 +svn:ignore +V 20 +config.private.yaml + +END diff --git a/test/.svn/empty-file b/test/.svn/empty-file new file mode 100644 index 0000000..e69de29 diff --git a/test/.svn/entries b/test/.svn/entries new file mode 100644 index 0000000..287fd4f --- /dev/null +++ b/test/.svn/entries @@ -0,0 +1,491 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/.svn/format b/test/.svn/format new file mode 100644 index 0000000..b8626c4 --- /dev/null +++ b/test/.svn/format @@ -0,0 +1 @@ +4 diff --git a/test/.svn/prop-base/.cvsignore.svn-base b/test/.svn/prop-base/.cvsignore.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/.svn/prop-base/.cvsignore.svn-base @@ -0,0 +1 @@ +END diff --git a/test/.svn/prop-base/bp_loop_issue.rb.svn-base b/test/.svn/prop-base/bp_loop_issue.rb.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/.svn/prop-base/bp_loop_issue.rb.svn-base @@ -0,0 +1 @@ +END diff --git a/test/.svn/prop-base/classes.rb.svn-base b/test/.svn/prop-base/classes.rb.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/.svn/prop-base/classes.rb.svn-base @@ -0,0 +1 @@ +END diff --git a/test/.svn/prop-base/config.yaml.svn-base b/test/.svn/prop-base/config.yaml.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/.svn/prop-base/config.yaml.svn-base @@ -0,0 +1 @@ +END diff --git a/test/.svn/prop-base/dollar-0.rb.svn-base b/test/.svn/prop-base/dollar-0.rb.svn-base new file mode 100644 index 0000000..462a03c --- /dev/null +++ b/test/.svn/prop-base/dollar-0.rb.svn-base @@ -0,0 +1,9 @@ +K 3 +add +V 14 +svn:executable +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/prop-base/gcd-dbg-nox.rb.svn-base b/test/.svn/prop-base/gcd-dbg-nox.rb.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/.svn/prop-base/gcd-dbg-nox.rb.svn-base @@ -0,0 +1 @@ +END diff --git a/test/.svn/prop-base/gcd-dbg.rb.svn-base b/test/.svn/prop-base/gcd-dbg.rb.svn-base new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/prop-base/gcd-dbg.rb.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/prop-base/gcd.rb.svn-base b/test/.svn/prop-base/gcd.rb.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/.svn/prop-base/gcd.rb.svn-base @@ -0,0 +1 @@ +END diff --git a/test/.svn/prop-base/helper.rb.svn-base b/test/.svn/prop-base/helper.rb.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/.svn/prop-base/helper.rb.svn-base @@ -0,0 +1 @@ +END diff --git a/test/.svn/prop-base/info-var-bug.rb.svn-base b/test/.svn/prop-base/info-var-bug.rb.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/.svn/prop-base/info-var-bug.rb.svn-base @@ -0,0 +1 @@ +END diff --git a/test/.svn/prop-base/info-var-bug2.rb.svn-base b/test/.svn/prop-base/info-var-bug2.rb.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/.svn/prop-base/info-var-bug2.rb.svn-base @@ -0,0 +1 @@ +END diff --git a/test/.svn/prop-base/null.rb.svn-base b/test/.svn/prop-base/null.rb.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/.svn/prop-base/null.rb.svn-base @@ -0,0 +1 @@ +END diff --git a/test/.svn/prop-base/output.rb.svn-base b/test/.svn/prop-base/output.rb.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/.svn/prop-base/output.rb.svn-base @@ -0,0 +1 @@ +END diff --git a/test/.svn/prop-base/pm-base.rb.svn-base b/test/.svn/prop-base/pm-base.rb.svn-base new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/prop-base/pm-base.rb.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/prop-base/pm-bug.rb.svn-base b/test/.svn/prop-base/pm-bug.rb.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/.svn/prop-base/pm-bug.rb.svn-base @@ -0,0 +1 @@ +END diff --git a/test/.svn/prop-base/pm.rb.svn-base b/test/.svn/prop-base/pm.rb.svn-base new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/prop-base/pm.rb.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/prop-base/raise.rb.svn-base b/test/.svn/prop-base/raise.rb.svn-base new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/prop-base/raise.rb.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/prop-base/rdebug-save.1.svn-base b/test/.svn/prop-base/rdebug-save.1.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/.svn/prop-base/rdebug-save.1.svn-base @@ -0,0 +1 @@ +END diff --git a/test/.svn/prop-base/runall.svn-base b/test/.svn/prop-base/runall.svn-base new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/prop-base/runall.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/prop-base/tdebug.rb.svn-base b/test/.svn/prop-base/tdebug.rb.svn-base new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/prop-base/tdebug.rb.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/prop-base/test-annotate.rb.svn-base b/test/.svn/prop-base/test-annotate.rb.svn-base new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/prop-base/test-annotate.rb.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/prop-base/test-break-bad.rb.svn-base b/test/.svn/prop-base/test-break-bad.rb.svn-base new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/prop-base/test-break-bad.rb.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/prop-base/test-breakpoints.rb.svn-base b/test/.svn/prop-base/test-breakpoints.rb.svn-base new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/prop-base/test-breakpoints.rb.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/prop-base/test-catch.rb.svn-base b/test/.svn/prop-base/test-catch.rb.svn-base new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/prop-base/test-catch.rb.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/prop-base/test-condition.rb.svn-base b/test/.svn/prop-base/test-condition.rb.svn-base new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/prop-base/test-condition.rb.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/prop-base/test-ctrl.rb.svn-base b/test/.svn/prop-base/test-ctrl.rb.svn-base new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/prop-base/test-ctrl.rb.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/prop-base/test-display.rb.svn-base b/test/.svn/prop-base/test-display.rb.svn-base new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/prop-base/test-display.rb.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/prop-base/test-dollar-0.rb.svn-base b/test/.svn/prop-base/test-dollar-0.rb.svn-base new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/prop-base/test-dollar-0.rb.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/prop-base/test-edit.rb.svn-base b/test/.svn/prop-base/test-edit.rb.svn-base new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/prop-base/test-edit.rb.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/prop-base/test-emacs-basic.rb.svn-base b/test/.svn/prop-base/test-emacs-basic.rb.svn-base new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/prop-base/test-emacs-basic.rb.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/prop-base/test-enable.rb.svn-base b/test/.svn/prop-base/test-enable.rb.svn-base new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/prop-base/test-enable.rb.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/prop-base/test-finish.rb.svn-base b/test/.svn/prop-base/test-finish.rb.svn-base new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/prop-base/test-finish.rb.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/prop-base/test-frame.rb.svn-base b/test/.svn/prop-base/test-frame.rb.svn-base new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/prop-base/test-frame.rb.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/prop-base/test-help.rb.svn-base b/test/.svn/prop-base/test-help.rb.svn-base new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/prop-base/test-help.rb.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/prop-base/test-hist.rb.svn-base b/test/.svn/prop-base/test-hist.rb.svn-base new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/prop-base/test-hist.rb.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/prop-base/test-info-thread.rb.svn-base b/test/.svn/prop-base/test-info-thread.rb.svn-base new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/prop-base/test-info-thread.rb.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/prop-base/test-info-var.rb.svn-base b/test/.svn/prop-base/test-info-var.rb.svn-base new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/prop-base/test-info-var.rb.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/prop-base/test-info.rb.svn-base b/test/.svn/prop-base/test-info.rb.svn-base new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/prop-base/test-info.rb.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/prop-base/test-init.rb.svn-base b/test/.svn/prop-base/test-init.rb.svn-base new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/prop-base/test-init.rb.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/prop-base/test-list.rb.svn-base b/test/.svn/prop-base/test-list.rb.svn-base new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/prop-base/test-list.rb.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/prop-base/test-method.rb.svn-base b/test/.svn/prop-base/test-method.rb.svn-base new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/prop-base/test-method.rb.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/prop-base/test-output.rb.svn-base b/test/.svn/prop-base/test-output.rb.svn-base new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/prop-base/test-output.rb.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/prop-base/test-pm.rb.svn-base b/test/.svn/prop-base/test-pm.rb.svn-base new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/prop-base/test-pm.rb.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/prop-base/test-quit.rb.svn-base b/test/.svn/prop-base/test-quit.rb.svn-base new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/prop-base/test-quit.rb.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/prop-base/test-raise.rb.svn-base b/test/.svn/prop-base/test-raise.rb.svn-base new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/prop-base/test-raise.rb.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/prop-base/test-save.rb.svn-base b/test/.svn/prop-base/test-save.rb.svn-base new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/prop-base/test-save.rb.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/prop-base/test-setshow.rb.svn-base b/test/.svn/prop-base/test-setshow.rb.svn-base new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/prop-base/test-setshow.rb.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/prop-base/test-source.rb.svn-base b/test/.svn/prop-base/test-source.rb.svn-base new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/prop-base/test-source.rb.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/prop-base/test-stepping.rb.svn-base b/test/.svn/prop-base/test-stepping.rb.svn-base new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/prop-base/test-stepping.rb.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/prop-base/test-trace.rb.svn-base b/test/.svn/prop-base/test-trace.rb.svn-base new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/prop-base/test-trace.rb.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/prop-base/thread1.rb.svn-base b/test/.svn/prop-base/thread1.rb.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/.svn/prop-base/thread1.rb.svn-base @@ -0,0 +1 @@ +END diff --git a/test/.svn/prop-base/trunc-call.rb.svn-base b/test/.svn/prop-base/trunc-call.rb.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/.svn/prop-base/trunc-call.rb.svn-base @@ -0,0 +1 @@ +END diff --git a/test/.svn/props/.cvsignore.svn-work b/test/.svn/props/.cvsignore.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/.svn/props/.cvsignore.svn-work @@ -0,0 +1 @@ +END diff --git a/test/.svn/props/bp_loop_issue.rb.svn-work b/test/.svn/props/bp_loop_issue.rb.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/.svn/props/bp_loop_issue.rb.svn-work @@ -0,0 +1 @@ +END diff --git a/test/.svn/props/classes.rb.svn-work b/test/.svn/props/classes.rb.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/.svn/props/classes.rb.svn-work @@ -0,0 +1 @@ +END diff --git a/test/.svn/props/config.yaml.svn-work b/test/.svn/props/config.yaml.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/.svn/props/config.yaml.svn-work @@ -0,0 +1 @@ +END diff --git a/test/.svn/props/dollar-0.rb.svn-work b/test/.svn/props/dollar-0.rb.svn-work new file mode 100644 index 0000000..462a03c --- /dev/null +++ b/test/.svn/props/dollar-0.rb.svn-work @@ -0,0 +1,9 @@ +K 3 +add +V 14 +svn:executable +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/props/gcd-dbg-nox.rb.svn-work b/test/.svn/props/gcd-dbg-nox.rb.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/.svn/props/gcd-dbg-nox.rb.svn-work @@ -0,0 +1 @@ +END diff --git a/test/.svn/props/gcd-dbg.rb.svn-work b/test/.svn/props/gcd-dbg.rb.svn-work new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/props/gcd-dbg.rb.svn-work @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/props/gcd.rb.svn-work b/test/.svn/props/gcd.rb.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/.svn/props/gcd.rb.svn-work @@ -0,0 +1 @@ +END diff --git a/test/.svn/props/helper.rb.svn-work b/test/.svn/props/helper.rb.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/.svn/props/helper.rb.svn-work @@ -0,0 +1 @@ +END diff --git a/test/.svn/props/info-var-bug.rb.svn-work b/test/.svn/props/info-var-bug.rb.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/.svn/props/info-var-bug.rb.svn-work @@ -0,0 +1 @@ +END diff --git a/test/.svn/props/info-var-bug2.rb.svn-work b/test/.svn/props/info-var-bug2.rb.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/.svn/props/info-var-bug2.rb.svn-work @@ -0,0 +1 @@ +END diff --git a/test/.svn/props/null.rb.svn-work b/test/.svn/props/null.rb.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/.svn/props/null.rb.svn-work @@ -0,0 +1 @@ +END diff --git a/test/.svn/props/output.rb.svn-work b/test/.svn/props/output.rb.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/.svn/props/output.rb.svn-work @@ -0,0 +1 @@ +END diff --git a/test/.svn/props/pm-base.rb.svn-work b/test/.svn/props/pm-base.rb.svn-work new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/props/pm-base.rb.svn-work @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/props/pm-bug.rb.svn-work b/test/.svn/props/pm-bug.rb.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/.svn/props/pm-bug.rb.svn-work @@ -0,0 +1 @@ +END diff --git a/test/.svn/props/pm.rb.svn-work b/test/.svn/props/pm.rb.svn-work new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/props/pm.rb.svn-work @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/props/raise.rb.svn-work b/test/.svn/props/raise.rb.svn-work new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/props/raise.rb.svn-work @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/props/rdebug-save.1.svn-work b/test/.svn/props/rdebug-save.1.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/.svn/props/rdebug-save.1.svn-work @@ -0,0 +1 @@ +END diff --git a/test/.svn/props/runall.svn-work b/test/.svn/props/runall.svn-work new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/props/runall.svn-work @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/props/tdebug.rb.svn-work b/test/.svn/props/tdebug.rb.svn-work new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/props/tdebug.rb.svn-work @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/props/test-annotate.rb.svn-work b/test/.svn/props/test-annotate.rb.svn-work new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/props/test-annotate.rb.svn-work @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/props/test-break-bad.rb.svn-work b/test/.svn/props/test-break-bad.rb.svn-work new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/props/test-break-bad.rb.svn-work @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/props/test-breakpoints.rb.svn-work b/test/.svn/props/test-breakpoints.rb.svn-work new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/props/test-breakpoints.rb.svn-work @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/props/test-catch.rb.svn-work b/test/.svn/props/test-catch.rb.svn-work new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/props/test-catch.rb.svn-work @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/props/test-condition.rb.svn-work b/test/.svn/props/test-condition.rb.svn-work new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/props/test-condition.rb.svn-work @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/props/test-ctrl.rb.svn-work b/test/.svn/props/test-ctrl.rb.svn-work new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/props/test-ctrl.rb.svn-work @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/props/test-display.rb.svn-work b/test/.svn/props/test-display.rb.svn-work new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/props/test-display.rb.svn-work @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/props/test-dollar-0.rb.svn-work b/test/.svn/props/test-dollar-0.rb.svn-work new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/props/test-dollar-0.rb.svn-work @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/props/test-edit.rb.svn-work b/test/.svn/props/test-edit.rb.svn-work new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/props/test-edit.rb.svn-work @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/props/test-emacs-basic.rb.svn-work b/test/.svn/props/test-emacs-basic.rb.svn-work new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/props/test-emacs-basic.rb.svn-work @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/props/test-enable.rb.svn-work b/test/.svn/props/test-enable.rb.svn-work new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/props/test-enable.rb.svn-work @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/props/test-finish.rb.svn-work b/test/.svn/props/test-finish.rb.svn-work new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/props/test-finish.rb.svn-work @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/props/test-frame.rb.svn-work b/test/.svn/props/test-frame.rb.svn-work new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/props/test-frame.rb.svn-work @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/props/test-help.rb.svn-work b/test/.svn/props/test-help.rb.svn-work new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/props/test-help.rb.svn-work @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/props/test-hist.rb.svn-work b/test/.svn/props/test-hist.rb.svn-work new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/props/test-hist.rb.svn-work @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/props/test-info-thread.rb.svn-work b/test/.svn/props/test-info-thread.rb.svn-work new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/props/test-info-thread.rb.svn-work @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/props/test-info-var.rb.svn-work b/test/.svn/props/test-info-var.rb.svn-work new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/props/test-info-var.rb.svn-work @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/props/test-info.rb.svn-work b/test/.svn/props/test-info.rb.svn-work new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/props/test-info.rb.svn-work @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/props/test-init.rb.svn-work b/test/.svn/props/test-init.rb.svn-work new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/props/test-init.rb.svn-work @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/props/test-list.rb.svn-work b/test/.svn/props/test-list.rb.svn-work new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/props/test-list.rb.svn-work @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/props/test-method.rb.svn-work b/test/.svn/props/test-method.rb.svn-work new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/props/test-method.rb.svn-work @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/props/test-output.rb.svn-work b/test/.svn/props/test-output.rb.svn-work new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/props/test-output.rb.svn-work @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/props/test-pm.rb.svn-work b/test/.svn/props/test-pm.rb.svn-work new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/props/test-pm.rb.svn-work @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/props/test-quit.rb.svn-work b/test/.svn/props/test-quit.rb.svn-work new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/props/test-quit.rb.svn-work @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/props/test-raise.rb.svn-work b/test/.svn/props/test-raise.rb.svn-work new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/props/test-raise.rb.svn-work @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/props/test-save.rb.svn-work b/test/.svn/props/test-save.rb.svn-work new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/props/test-save.rb.svn-work @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/props/test-setshow.rb.svn-work b/test/.svn/props/test-setshow.rb.svn-work new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/props/test-setshow.rb.svn-work @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/props/test-source.rb.svn-work b/test/.svn/props/test-source.rb.svn-work new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/props/test-source.rb.svn-work @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/props/test-stepping.rb.svn-work b/test/.svn/props/test-stepping.rb.svn-work new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/props/test-stepping.rb.svn-work @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/props/test-trace.rb.svn-work b/test/.svn/props/test-trace.rb.svn-work new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/.svn/props/test-trace.rb.svn-work @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/.svn/props/thread1.rb.svn-work b/test/.svn/props/thread1.rb.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/.svn/props/thread1.rb.svn-work @@ -0,0 +1 @@ +END diff --git a/test/.svn/props/trunc-call.rb.svn-work b/test/.svn/props/trunc-call.rb.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/.svn/props/trunc-call.rb.svn-work @@ -0,0 +1 @@ +END diff --git a/test/.svn/text-base/.cvsignore.svn-base b/test/.svn/text-base/.cvsignore.svn-base new file mode 100644 index 0000000..b997925 --- /dev/null +++ b/test/.svn/text-base/.cvsignore.svn-base @@ -0,0 +1 @@ +config.private.yaml diff --git a/test/.svn/text-base/bp_loop_issue.rb.svn-base b/test/.svn/text-base/bp_loop_issue.rb.svn-base new file mode 100644 index 0000000..abe072e --- /dev/null +++ b/test/.svn/text-base/bp_loop_issue.rb.svn-base @@ -0,0 +1,3 @@ +1.upto(2) { + sleep 0.01 +} diff --git a/test/.svn/text-base/classes.rb.svn-base b/test/.svn/text-base/classes.rb.svn-base new file mode 100644 index 0000000..7a874bd --- /dev/null +++ b/test/.svn/text-base/classes.rb.svn-base @@ -0,0 +1,11 @@ +class Mine + def initialize + @myvar = 'init' + end + def mymethod(a, b=5, &block) + end + def self.classmeth + end +end +me = Mine.new +metoo = Mine(new) diff --git a/test/.svn/text-base/config.yaml.svn-base b/test/.svn/text-base/config.yaml.svn-base new file mode 100644 index 0000000..2a3ab2b --- /dev/null +++ b/test/.svn/text-base/config.yaml.svn-base @@ -0,0 +1,8 @@ +# Do not commit personal changes here back to the repository. Create +# config.private.yaml which, if exists, is preferred to this one. + +# either should be on the $PATH or use full path +ruby: ruby + +# possibility to specify interpreter parameters +#ruby_params: -w diff --git a/test/.svn/text-base/dollar-0.rb.svn-base b/test/.svn/text-base/dollar-0.rb.svn-base new file mode 100644 index 0000000..9955e43 --- /dev/null +++ b/test/.svn/text-base/dollar-0.rb.svn-base @@ -0,0 +1,5 @@ +#!/usr/bin/env ruby +# A test to see that rdebug set's $0 properly. +puts $0 +puts __FILE__ + diff --git a/test/.svn/text-base/gcd-dbg-nox.rb.svn-base b/test/.svn/text-base/gcd-dbg-nox.rb.svn-base new file mode 100644 index 0000000..5b84c6e --- /dev/null +++ b/test/.svn/text-base/gcd-dbg-nox.rb.svn-base @@ -0,0 +1,31 @@ +# This program is *NOT* supposed to be executable, but called +# via ruby (in order to test that restart provides a funky $:). +# This program is used to test that 'restart' works when we didn't call +# the debugger initially. + +TOP_SRC_DIR = File.join(File.expand_path(File.dirname(__FILE__), '..')) unless + defined?(TOP_SRC_DIR) + +$:.unshift File.join(TOP_SRC_DIR, 'ext') +$:.unshift File.join(TOP_SRC_DIR, 'lib') +$:.unshift File.join(TOP_SRC_DIR, 'cli') +require 'ruby-debug' +Debugger.init + +# GCD. We assume positive numbers +def gcd(a, b) + # Make: a <= b + debugger + if a > b + a, b = [b, a] + end + + return nil if a <= 0 + + if a == 1 or b-a == 0 + return a + end + return gcd(b-a, a) +end + +gcd(3,5) diff --git a/test/.svn/text-base/gcd-dbg.rb.svn-base b/test/.svn/text-base/gcd-dbg.rb.svn-base new file mode 100644 index 0000000..717518b --- /dev/null +++ b/test/.svn/text-base/gcd-dbg.rb.svn-base @@ -0,0 +1,30 @@ +#!/usr/bin/env ruby +# This program is used to test that 'restart' works when we didn't call +# the debugger initially. + +TOP_SRC_DIR = File.join(File.expand_path(File.dirname(__FILE__), "..")) unless + defined?(TOP_SRC_DIR) + +$:.unshift File.join(TOP_SRC_DIR, "ext") +$:.unshift File.join(TOP_SRC_DIR, "lib") +$:.unshift File.join(TOP_SRC_DIR, "cli") +require 'ruby-debug' +Debugger.start + +# GCD. We assume positive numbers +def gcd(a, b) + # Make: a <= b + debugger + if a > b + a, b = [b, a] + end + + return nil if a <= 0 + + if a == 1 or b-a == 0 + return a + end + return gcd(b-a, a) +end + +gcd(3,5) diff --git a/test/.svn/text-base/gcd.rb.svn-base b/test/.svn/text-base/gcd.rb.svn-base new file mode 100644 index 0000000..184b8df --- /dev/null +++ b/test/.svn/text-base/gcd.rb.svn-base @@ -0,0 +1,18 @@ +#!/usr/bin/env ruby + +# GCD. We assume positive numbers +def gcd(a, b) + # Make: a <= b + if a > b + a, b = [b, a] + end + + return nil if a <= 0 + + if a == 1 or b-a == 0 + return a + end + return gcd(b-a, a) +end + +gcd(3,5) diff --git a/test/.svn/text-base/helper.rb.svn-base b/test/.svn/text-base/helper.rb.svn-base new file mode 100644 index 0000000..a675869 --- /dev/null +++ b/test/.svn/text-base/helper.rb.svn-base @@ -0,0 +1,143 @@ +# Some common routines used in testing. + +require 'fileutils' +require 'yaml' +# require 'diff/lcs' +# require 'diff/lcs/hunk' + +# begin require 'rubygems' rescue LoadError end +# require 'ruby-debug'; Debugger.start + +module TestHelper + + # FIXME: turn args into a hash. + def run_debugger(testname, args='', outfile=nil, filter=nil, old_code=false, + debug_pgm='tdebug.rb') + rightfile = File.join('data', "#{testname}.right") + + outfile = "#{testname}.out" unless outfile + + if File.exists?(outfile) + FileUtils.rm(outfile) + end + + ENV['RDEBUG'] = debug_pgm + + if old_code + cmd = "/bin/sh #{File.join('..', 'runner.sh')} #{args} >#{outfile}" + else + cmd = "#{"#{load_ruby} #{load_params} "}../rdbg.rb #{args} > #{outfile}" + end + puts "'#{cmd}'" if $DEBUG + output = `#{cmd}` + + got_lines = File.read(outfile).split(/\n/) + correct_lines = File.read(rightfile).split(/\n/) + filter.call(got_lines, correct_lines) if filter + if cheap_diff(got_lines, correct_lines) + FileUtils.rm(outfile) + return true + end + return false + end + + def cheap_diff(got_lines, correct_lines) + if $DEBUG + got_lines.each_with_index do |line, i| + printf "%3d %s\n", i+1, line + end + end + correct_lines.each_with_index do |line, i| + correct_lines[i].chomp! + if got_lines[i] != correct_lines[i] + puts "difference found at line #{i+1}" + puts "got : #{got_lines[i]}" + puts "need: #{correct_lines[i]}" + return false + end + end + if correct_lines.size != got_lines.size + puts("difference in number of lines: " + + "#{correct_lines.size} vs. #{got_lines.size}") + return false + end + return true + end + + # FIXME: using this causes the same test to get run several times + # and some tests fail probably because of a lack of environment isolation. + # Many tests follow a basic pattern: run the debugger with a given + # debugger script and compare output produced. The following creates + # this kind of test. + def add_test(base_name, src_dir, script_name=nil, cmd=nil, test_name=nil) + puts "+++ Adding #{base_name} ++++" if $DEBUG + test_name = base_name unless test_name + script_name = File.join('data', test_name + '.cmd') unless script_name + cmd = 'gcd.rb 3 5' unless cmd + eval <<-EOF + def test_#{test_name} + Dir.chdir(\"#{src_dir}\") do + assert_equal(true, + run_debugger(\"#{base_name}\", + \"--script #{script_name} -- #{cmd}\")) + end + end + EOF + end + module_function :add_test + + # Adapted from the Ruby Cookbook, Section 6.10: Comparing two files. + # def diff_as_string(rightfile, checkfile, format=:unified, context_lines=3) + # right_data = File.read(rightfile) + # check_data = File.read(checkfile) + # output = '' + # diffs = Diff::LCS.diff(right_data, check_data) + # return output if diffs.empty? + # oldhunk = hunk = nil + # file_length_difference = 0 + # diffs.each do |piece| + # begin + # hunk = Diff::LCS::Hunk.new(right_data, check_data, piece, + # context_lines, file_length_difference) + # next unless oldhunk + # + # # Hunks may overlap, which is why we need to be careful when our + # # diff includes lines of context. Otherwise, we might print + # # redundant lines. + # if (context_lines > 0) and hunk.overlaps?(oldhunk) + # hunk.unshift(oldhunk) + # else + # output << oldhunk.diff(format) + # end + # ensure + # oldhunk = hunk + # output << '\n' + # end + # end + + # # Handle the last remaining hunk + # output << oldhunk.diff(format) << '\n' + # end + + # Loads key from the _config_._yaml_ file. + def config_load(key, may_be_nil=false, default_value='') + conf = File.join('config.private.yaml') # try private first + conf = File.join('config.yaml') unless File.exists?(conf) + value = YAML.load_file(conf)[key] + assert_not_nil(value, "#{key} is set in config.yaml") unless may_be_nil + value || default_value + end + module_function :config_load + + def load_ruby + config_load('ruby', true) + end + module_function :load_ruby + + def load_params + config_load('ruby_params', true) + end + module_function :load_params + +end + diff --git a/test/.svn/text-base/info-var-bug.rb.svn-base b/test/.svn/text-base/info-var-bug.rb.svn-base new file mode 100644 index 0000000..9250e6e --- /dev/null +++ b/test/.svn/text-base/info-var-bug.rb.svn-base @@ -0,0 +1,47 @@ +class Lousy_inspect + attr_accessor :var + def inspect # An unhelpful inspect + throw "Foo" # Raises an exception + end + def initialize + @var = 'initialized' + end +end +class Lousy_inspect_and_to_s + attr_accessor :var + def inspect # An unhelpful inspect + throw "Foo" # Raises an exception + end + def to_s # An unhelpful to_s + throw "bar" # Raises an exception + end + def initialize + @var = 'initialized' # Something to inspect + end +end + +# Something that will be passed objects with +# bad inspect or to_s methods +class UnsuspectingClass + @@Const = 'A constant' + @@var = 'a class variable' + def initialize(a) + @a = a # "info locals" will try to use + # inspect or to_s here + @b = 5 + end +end +def test_Lousy_inspect + x = Lousy_inspect.new + return x +end +def test_lousy_inspect_and_to_s + x = Lousy_inspect_and_to_s.new + return x +end +x = test_Lousy_inspect +y = test_lousy_inspect_and_to_s +UnsuspectingClass.new(10) +UnsuspectingClass.new(x) +UnsuspectingClass.new(y) +y = 2 diff --git a/test/.svn/text-base/info-var-bug2.rb.svn-base b/test/.svn/text-base/info-var-bug2.rb.svn-base new file mode 100644 index 0000000..83d474e --- /dev/null +++ b/test/.svn/text-base/info-var-bug2.rb.svn-base @@ -0,0 +1,2 @@ +s = '<%= PRODUCT[:name] %>' +y = 0 diff --git a/test/.svn/text-base/null.rb.svn-base b/test/.svn/text-base/null.rb.svn-base new file mode 100644 index 0000000..47f0a27 --- /dev/null +++ b/test/.svn/text-base/null.rb.svn-base @@ -0,0 +1 @@ +# Nothing here. Move along. diff --git a/test/.svn/text-base/output.rb.svn-base b/test/.svn/text-base/output.rb.svn-base new file mode 100644 index 0000000..69fde1b --- /dev/null +++ b/test/.svn/text-base/output.rb.svn-base @@ -0,0 +1,2 @@ +puts "one" +puts "two" diff --git a/test/.svn/text-base/pm-base.rb.svn-base b/test/.svn/text-base/pm-base.rb.svn-base new file mode 100644 index 0000000..8d29f2f --- /dev/null +++ b/test/.svn/text-base/pm-base.rb.svn-base @@ -0,0 +1,22 @@ +#!/usr/bin/env ruby +# Test post-mortem handling using only ruby-debug-base. +src_dir = File.dirname(__FILE__) +%w(ext lib cli).each do |dir| + $:.unshift File.join(src_dir, '..', dir) +end +require 'ruby-debug-base' + +class CommandProcessor + def at_line(context, file, line) + puts 'file: %s, line: %s' % [ File.basename(file), line ] + exit! + end +end + +Debugger.start(:post_mortem => true) +Debugger.handler = CommandProcessor.new +def zero_div + 1/0 +end +zero_div + diff --git a/test/.svn/text-base/pm-bug.rb.svn-base b/test/.svn/text-base/pm-bug.rb.svn-base new file mode 100644 index 0000000..3ced249 --- /dev/null +++ b/test/.svn/text-base/pm-bug.rb.svn-base @@ -0,0 +1,3 @@ +a = 1 +@x = 2 +raise diff --git a/test/.svn/text-base/pm.rb.svn-base b/test/.svn/text-base/pm.rb.svn-base new file mode 100644 index 0000000..f8f0014 --- /dev/null +++ b/test/.svn/text-base/pm.rb.svn-base @@ -0,0 +1,11 @@ +#!/ursr/bin/env ruby +# Test Debugger.catchpoint and post-mortem handling +def zero_div + x = 5 + 1/0 +end +x = 2 +zero_div +raise RuntimeError +x = 3 + diff --git a/test/.svn/text-base/raise.rb.svn-base b/test/.svn/text-base/raise.rb.svn-base new file mode 100644 index 0000000..c6f3b51 --- /dev/null +++ b/test/.svn/text-base/raise.rb.svn-base @@ -0,0 +1,3 @@ +#!/usr/bin/env ruby + +raise "abc" diff --git a/test/.svn/text-base/rdebug-save.1.svn-base b/test/.svn/text-base/rdebug-save.1.svn-base new file mode 100644 index 0000000..f759154 --- /dev/null +++ b/test/.svn/text-base/rdebug-save.1.svn-base @@ -0,0 +1,7 @@ +break gcd.rb:10 +break gcd.rb:12 if a > b +set autoeval on +set basename off +set debuggertesting off +set autolist off +set autoirb off diff --git a/test/.svn/text-base/runall.svn-base b/test/.svn/text-base/runall.svn-base new file mode 100644 index 0000000..634981b --- /dev/null +++ b/test/.svn/text-base/runall.svn-base @@ -0,0 +1,12 @@ +#!/usr/bin/env ruby +#-*- Ruby -*- +debug_opt = '-d ' if $DEBUG or 'd' == ARGV[0] +for file in Dir.glob("test-*.rb") do + puts "=" * 50 + puts "== running #{file}..." + system("ruby #{file}"); +end +if ARGV[0] == "really" + system("(cd test && ruby #{debug_opt}runall)") + system("(cd examples && ruby #{debug_opt}runall)") +end diff --git a/test/.svn/text-base/tdebug.rb.svn-base b/test/.svn/text-base/tdebug.rb.svn-base new file mode 100644 index 0000000..ae13f3e --- /dev/null +++ b/test/.svn/text-base/tdebug.rb.svn-base @@ -0,0 +1,252 @@ +#!/usr/bin/env ruby +# -*- Ruby -*- +# This is a hacked down copy of rdebug which can be used for testing +# FIXME: use the real rdebug script - DRY. + +require 'stringio' +require 'rubygems' +require 'optparse' +require "ostruct" + +TOP_SRC_DIR = File.join(File.dirname(__FILE__), "..") unless + defined?(TOP_SRC_DIR) + +$:.unshift File.join(TOP_SRC_DIR, "ext") +$:.unshift File.join(TOP_SRC_DIR, "lib") +$:.unshift File.join(TOP_SRC_DIR, "cli") + +def debug_program(options) + # Make sure Ruby script syntax checks okay. + # Otherwise we get a load message that looks like rdebug has + # a problem. + output = `ruby -c "#{Debugger::PROG_SCRIPT}" 2>&1` + if $?.exitstatus != 0 and RUBY_PLATFORM !~ /mswin/ + puts output + exit $?.exitstatus + end + print "\032\032starting\n" if Debugger.annotate and Debugger.annotate > 2 + unless options.no_rewrite_program + # Set $0 so things like __FILE == $0 work. + # A more reliable way to do this is to put $0 = __FILE__ *after* + # loading the script to be debugged. For this, adding a debug hook + # for the first time and then switching to the debug hook that's + # normally used would be helpful. Doing this would also help other + # first-time initializations such as reloading debugger state + # after a restart. + + # However This is just a little more than I want to take on right + # now, so I think I'll stick with the slightly hacky approach. + $RDEBUG_0 = $0 + + # cygwin does some sort of funky truncation on $0 ./abcdef => ./ab + # probably something to do with 3-letter extension truncation. + # The hacky workaround is to do slice assignment. Ugh. + d0 = if '.' == File.dirname(Debugger::PROG_SCRIPT) and + Debugger::PROG_SCRIPT[0..0] != '.' + File.join('.', Debugger::PROG_SCRIPT) + else + Debugger::PROG_SCRIPT + end + if $0.frozen? + $0 = d0 + else + $0[0..-1] = d0 + end + end + + # Record where we are we can know if the call stack has been + # truncated or not. + Debugger.start_sentinal=caller(0)[1] + + bt = Debugger.debug_load(Debugger::PROG_SCRIPT, !options.nostop, false) + if bt + if options.post_mortem + Debugger.handle_post_mortem(bt) + else + print bt.backtrace.map{|l| "\t#{l}"}.join("\n"), "\n" + print "Uncaught exception: #{bt}\n" + end + end +end + +options = OpenStruct.new( + 'annotate' => false, + 'emacs' => false, + 'frame_bind' => false, + 'no-quit' => false, + 'no-stop' => false, + 'nx' => false, + 'post_mortem' => false, + 'script' => nil, + 'tracing' => false, + 'verbose_long'=> false, + 'wait' => false +) + +require "ruby-debug" + +program = File.basename($0) +opts = OptionParser.new do |opts| + opts.banner = < -- +EOB + opts.separator "" + opts.separator "Options:" + opts.on("-A", "--annotate LEVEL", Integer, "Set annotation level") do + |Debugger.annotate| + end + opts.on("-d", "--debug", "Set $DEBUG=true") {$DEBUG = true} + opts.on("--emacs-basic", "Activates basic Emacs mode") do + ENV['EMACS'] = '1' + options.emacs = true + end + opts.on("--keep-frame-binding", "Keep frame bindings") do + options.frame_bind = true + end + opts.on("-m", "--post-mortem", "Activate post-mortem mode") do + options.post_mortem = true + end + opts.on("--no-control", "Do not automatically start control thread") do + options.control = false + end + opts.on("--no-quit", "Do not quit when script finishes") do + options.noquit = true + end + opts.on("--no-stop", "Do not stop when script is loaded") do + options.nostop = true + end + opts.on("-nx", "Not run debugger initialization files (e.g. .rdebugrc") do + options.nx = true + end + opts.on("-I", "--include PATH", String, "Add PATH to $LOAD_PATH") do |path| + $LOAD_PATH.unshift(path) + end + opts.on("-r", "--require SCRIPT", String, + "Require the library, before executing your script") do |name| + if name == 'debug' + puts "ruby-debug is not compatible with Ruby's 'debug' library. This option is ignored." + else + require name + end + end + opts.on("--script FILE", String, "Name of the script file to run") do |options.script| + unless File.exists?(options.script) + puts "Script file '#{options.script}' is not found" + exit + end + end + opts.on("-x", "--trace", "Turn on line tracing") {options.tracing = true} + ENV['EMACS'] = nil unless options.emacs + opts.separator "" + opts.separator "Common options:" + opts.on_tail("--help", "Show this message") do + puts opts + exit + end + opts.on_tail("--version", + "Print the version") do + puts "ruby-debug #{Debugger::VERSION}" + exit + end + opts.on("--verbose", "Turn on verbose mode") do + $VERBOSE = true + options.verbose_long = true + end + opts.on_tail("-v", + "Print version number, then turn on verbose mode") do + puts "ruby-debug #{Debugger::VERSION}" + $VERBOSE = true + end +end + +begin + if not defined? Debugger::ARGV + Debugger::ARGV = ARGV.clone + end + rdebug_path = File.expand_path($0) + if RUBY_PLATFORM =~ /mswin/ + rdebug_path += '.cmd' unless rdebug_path =~ /\.cmd$/i + end + Debugger::RDEBUG_SCRIPT = rdebug_path + Debugger::RDEBUG_FILE = __FILE__ + Debugger::INITIAL_DIR = Dir.pwd + opts.parse! ARGV +rescue StandardError => e + puts opts + puts + puts e.message + exit(-1) +end + +if ARGV.empty? + exit if $VERBOSE and not options.verbose_long + puts opts + puts + puts 'Must specify a script to run' + exit(-1) +end + +# save script name +Debugger::PROG_SCRIPT = ARGV.shift + +# install interruption handler +trap('INT') { Debugger.interrupt_last } + +# set options +Debugger.wait_connection = false +Debugger.keep_frame_binding = options.frame_bind + +# Add Debugger trace hook. +Debugger.start + +# start control thread +Debugger.start_control(options.host, options.cport) if options.control + +# activate post-mortem +Debugger.post_mortem if options.post_mortem + +# Set up an interface to read commands from a debugger script file. +if options.script + Debugger.interface = Debugger::ScriptInterface.new(options.script, + STDOUT, true) +end +options.nostop = true if options.tracing +Debugger.tracing = options.tracing + +# Make sure Ruby script syntax checks okay. +# Otherwise we get a load message that looks like rdebug has +# a problem. +output = `ruby -c #{Debugger::PROG_SCRIPT} 2>&1` +if $?.exitstatus != 0 and RUBY_PLATFORM !~ /mswin/ + puts output + exit $?.exitstatus +end + +# load initrc script (e.g. .rdebugrc) +Debugger.run_init_script(StringIO.new) unless options.nx + +# run startup script if specified +if options.script + Debugger.run_script(options.script) +end +# activate post-mortem +Debugger.post_mortem if options.post_mortem +options.stop = false if options.tracing +Debugger.tracing = options.tracing + +if options.noquit + if Debugger.started? + until Debugger.stop do end + end + debug_program(options) + print "The program finished.\n" unless + Debugger.annotate.to_i > 1 # annotate has its own way + interface = Debugger::LocalInterface.new + # Not sure if ControlCommandProcessor is really the right + # thing to use. CommandProcessor requires a state. + processor = Debugger::ControlCommandProcessor.new(interface) + processor.process_commands +else + debug_program(options) +end diff --git a/test/.svn/text-base/test-annotate.rb.svn-base b/test/.svn/text-base/test-annotate.rb.svn-base new file mode 100644 index 0000000..27adff1 --- /dev/null +++ b/test/.svn/text-base/test-annotate.rb.svn-base @@ -0,0 +1,25 @@ +#!/usr/bin/env ruby +require 'test/unit' +require 'fileutils' + +# begin require 'rubygems' rescue LoadError end +# require 'ruby-debug'; Debugger.start + +# Test annotate handling. +class TestAnnotate < Test::Unit::TestCase + @@SRC_DIR = File.dirname(__FILE__) unless + defined?(@@SRC_DIR) + + require File.join(@@SRC_DIR, 'helper') + include TestHelper + + def test_basic + testname='annotate' + Dir.chdir(@@SRC_DIR) do + script = File.join('data', testname + '.cmd') + assert_equal(true, + run_debugger(testname, + "--script #{script} -- gcd.rb 3 5")) + end + end +end diff --git a/test/.svn/text-base/test-break-bad.rb.svn-base b/test/.svn/text-base/test-break-bad.rb.svn-base new file mode 100644 index 0000000..f667ff7 --- /dev/null +++ b/test/.svn/text-base/test-break-bad.rb.svn-base @@ -0,0 +1,36 @@ +#!/usr/bin/env ruby +require 'test/unit' + +# begin require 'rubygems' rescue LoadError end +# require 'ruby-debug'; Debugger.start + +# Test (mostly) invalid breakpoint commands +class TestBadBreak < Test::Unit::TestCase + + @@SRC_DIR = File.dirname(__FILE__) unless + defined?(@@SRC_DIR) + + require File.join(@@SRC_DIR, 'helper') + include TestHelper + + def test_basic + testname='break_bad' + Dir.chdir(@@SRC_DIR) do + script = File.join('data', testname + '.cmd') + assert_equal(true, + run_debugger(testname, + "--script #{script} -- gcd.rb 3 5")) + end + end + + def test_break_loop + testname='break_loop_bug' + Dir.chdir(@@SRC_DIR) do + script = File.join('data', testname + '.cmd') + assert_equal(true, + run_debugger(testname, + "--script #{script} -- bp_loop_issue.rb")) + end + end + +end diff --git a/test/.svn/text-base/test-breakpoints.rb.svn-base b/test/.svn/text-base/test-breakpoints.rb.svn-base new file mode 100644 index 0000000..aa7617e --- /dev/null +++ b/test/.svn/text-base/test-breakpoints.rb.svn-base @@ -0,0 +1,25 @@ +#!/usr/bin/env ruby +require 'test/unit' + +# begin require 'rubygems' rescue LoadError end +# require 'ruby-debug'; Debugger.start + +# Test breakpoint commands +class TestBreakpoints < Test::Unit::TestCase + + @@SRC_DIR = File.dirname(__FILE__) unless + defined?(@@SRC_DIR) + + require File.join(@@SRC_DIR, 'helper') + include TestHelper + + def test_basic + testname='breakpoints' + Dir.chdir(@@SRC_DIR) do + script = File.join('data', testname + '.cmd') + assert_equal(true, + run_debugger(testname, + "--script #{script} -- gcd.rb 3 5")) + end + end +end diff --git a/test/.svn/text-base/test-catch.rb.svn-base b/test/.svn/text-base/test-catch.rb.svn-base new file mode 100644 index 0000000..fc7ef91 --- /dev/null +++ b/test/.svn/text-base/test-catch.rb.svn-base @@ -0,0 +1,25 @@ +#!/usr/bin/env ruby +require 'test/unit' + +# begin require 'rubygems' rescue LoadError end +# require 'ruby-debug'; Debugger.start + +# Test condition command +class TestBreakpoints < Test::Unit::TestCase + + @@SRC_DIR = File.dirname(__FILE__) unless + defined?(@@SRC_DIR) + + require File.join(@@SRC_DIR, 'helper') + include TestHelper + + def test_basic + testname='catch' + Dir.chdir(@@SRC_DIR) do + script = File.join('data', testname + '.cmd') + assert_equal(true, + run_debugger(testname, + "--script #{script} -- pm.rb")) + end + end +end diff --git a/test/.svn/text-base/test-condition.rb.svn-base b/test/.svn/text-base/test-condition.rb.svn-base new file mode 100644 index 0000000..9fea498 --- /dev/null +++ b/test/.svn/text-base/test-condition.rb.svn-base @@ -0,0 +1,25 @@ +#!/usr/bin/env ruby +require 'test/unit' + +# begin require 'rubygems' rescue LoadError end +# require 'ruby-debug'; Debugger.start + +# Test condition command +class TestBreakpoints < Test::Unit::TestCase + + @@SRC_DIR = File.dirname(__FILE__) unless + defined?(@@SRC_DIR) + + require File.join(@@SRC_DIR, 'helper') + include TestHelper + + def test_basic + testname='condition' + Dir.chdir(@@SRC_DIR) do + script = File.join('data', testname + '.cmd') + assert_equal(true, + run_debugger(testname, + "--script #{script} -- gcd.rb 3 5")) + end + end +end diff --git a/test/.svn/text-base/test-ctrl.rb.svn-base b/test/.svn/text-base/test-ctrl.rb.svn-base new file mode 100644 index 0000000..213b592 --- /dev/null +++ b/test/.svn/text-base/test-ctrl.rb.svn-base @@ -0,0 +1,55 @@ +#!/usr/bin/env ruby + +# begin require 'rubygems' rescue LoadError end +# require 'ruby-debug' ; Debugger.start + +require 'test/unit' +SRC_DIR = File.dirname(__FILE__) unless + defined?(SRC_DIR) +%w(ext lib cli).each do |dir| + $: << File.join(SRC_DIR, '..', dir) +end +require 'ruby_debug' +require File.join(SRC_DIR, '..', 'cli', 'ruby-debug') + +# Test Local Control Interface +class TestCtrl < Test::Unit::TestCase + + def cheap_diff(got_lines, correct_lines, outfile) + if correct_lines.size != got_lines.size + puts "Size difference #{correct_lines.size} vs. #{got_lines.size}" + File.open(outfile, 'w') {|f| f.puts got_lines} + return false + end + correct_lines.each_with_index do |line, i| + correct_lines[i].chomp! + if got_lines[i] != correct_lines[i] + puts "difference found at line #{i+1}" + puts "got : #{got_lines[i]}" + puts "need: #{correct_lines[i]}" + File.open(outfile, 'w') {|f| f.puts got_lines} + return false + end + end + end + + require 'stringio' + + # Test initial variables and setting/getting state. + def test_ctrl + ENV['COLUMNS'] = '80' + ENV['EMACS'] = nil + testbase = 'ctrl' + out = StringIO.new('', 'w') + Dir.chdir(SRC_DIR) do + script = File.join('data', "#{testbase}.cmd") + interface = Debugger::ScriptInterface.new(script, out) + processor = Debugger::ControlCommandProcessor.new(interface) + processor.process_commands + got_lines = out.string.split("\n") + right_file = File.join('data', "#{testbase}.right") + correct_lines = File.readlines(right_file) + assert cheap_diff(got_lines, correct_lines, "#{testbase}.out") + end + end +end diff --git a/test/.svn/text-base/test-display.rb.svn-base b/test/.svn/text-base/test-display.rb.svn-base new file mode 100644 index 0000000..4810a44 --- /dev/null +++ b/test/.svn/text-base/test-display.rb.svn-base @@ -0,0 +1,26 @@ +#!/usr/bin/env ruby +require 'test/unit' + +# begin require 'rubygems' rescue LoadError end +# require 'ruby-debug'; Debugger.start + +# Test Display commands +class TestDisplay < Test::Unit::TestCase + + @@SRC_DIR = File.dirname(__FILE__) unless + defined?(@@SRC_DIR) + + require File.join(@@SRC_DIR, 'helper') + include TestHelper + + # Test commands in display.rb + def test_basic + testname='display' + Dir.chdir(@@SRC_DIR) do + script = File.join('data', testname + '.cmd') + assert_equal(true, + run_debugger(testname, + "--script #{script} -- gcd.rb 3 5")) + end + end +end diff --git a/test/.svn/text-base/test-dollar-0.rb.svn-base b/test/.svn/text-base/test-dollar-0.rb.svn-base new file mode 100644 index 0000000..8aa1346 --- /dev/null +++ b/test/.svn/text-base/test-dollar-0.rb.svn-base @@ -0,0 +1,45 @@ +#!/usr/bin/env ruby +require 'test/unit' + +# begin require 'rubygems' rescue LoadError end +# require 'ruby-debug'; Debugger.start + +# Test --no-stop and $0 setting. +class TestDollar0 < Test::Unit::TestCase + + @@SRC_DIR = File.dirname(__FILE__) unless + defined?(@@SRC_DIR) + + require File.join(@@SRC_DIR, 'helper') + include TestHelper + + def test_basic + testname='breakpoints' + Dir.chdir(@@SRC_DIR) do + home_save = ENV['HOME'] + ENV['HOME'] = '.' + filter = Proc.new{|got_lines, correct_lines| + [got_lines, correct_lines].flatten.each do |s| + s.gsub!(/.*dollar-0.rb$/, 'dollar-0.rb') + end + } + + assert_equal(true, + run_debugger('dollar-0', + '-nx --no-stop ./dollar-0.rb', + nil, filter, false, '../bin/rdebug')) + # Ruby's __FILE__ seems to prepend ./ when no directory was added. + assert_equal(true, + run_debugger('dollar-0a', + '-nx --no-stop dollar-0.rb', + nil, filter, false, '../bin/rdebug')) + # Ruby's __FILE__ seems to prepend ./ when no directory was added. + assert_equal(true, + run_debugger('dollar-0b', + '-nx --no-stop ' + + File.join('..', 'test', 'dollar-0.rb'), + nil, filter, false, '../bin/rdebug')) + ENV['HOME'] = home_save + end + end +end diff --git a/test/.svn/text-base/test-edit.rb.svn-base b/test/.svn/text-base/test-edit.rb.svn-base new file mode 100644 index 0000000..27ef6c1 --- /dev/null +++ b/test/.svn/text-base/test-edit.rb.svn-base @@ -0,0 +1,26 @@ +#!/usr/bin/env ruby +require 'test/unit' + +# begin require 'rubygems' rescue LoadError end +# require 'ruby-debug'; Debugger.start + +# Test 'edit' command handling. +class TestEdit < Test::Unit::TestCase + + @@SRC_DIR = File.dirname(__FILE__) unless + defined?(@@SRC_DIR) + + require File.join(@@SRC_DIR, 'helper') + include TestHelper + + def test_basic + testname='edit' + Dir.chdir(@@SRC_DIR) do + script = File.join('data', testname + '.cmd') + ENV['EDITOR']='echo FAKE-EDITOR ' + assert_equal(true, + run_debugger(testname, + "--script #{script} -- gcd.rb 3 5")) + end + end +end diff --git a/test/.svn/text-base/test-emacs-basic.rb.svn-base b/test/.svn/text-base/test-emacs-basic.rb.svn-base new file mode 100644 index 0000000..c4c5518 --- /dev/null +++ b/test/.svn/text-base/test-emacs-basic.rb.svn-base @@ -0,0 +1,26 @@ +#!/usr/bin/env ruby +require 'test/unit' + +# require 'rubygems' +# require 'ruby-debug'; Debugger.start(:post_mortem => true) + +# Test the --emacs-basic option. +class TestEmacsBasic < Test::Unit::TestCase + + @@SRC_DIR = File.dirname(__FILE__) unless + defined?(@@SRC_DIR) + + require File.join(@@SRC_DIR, 'helper.rb') + + include TestHelper + + def test_basic + testname='emacs_basic' + Dir.chdir(@@SRC_DIR) do + script = File.join('data', testname + '.cmd') + assert_equal(true, + run_debugger(testname, + "--emacs-basic --script #{script} -- gcd.rb 3 5")) + end + end +end diff --git a/test/.svn/text-base/test-enable.rb.svn-base b/test/.svn/text-base/test-enable.rb.svn-base new file mode 100644 index 0000000..db73ffe --- /dev/null +++ b/test/.svn/text-base/test-enable.rb.svn-base @@ -0,0 +1,25 @@ +#!/usr/bin/env ruby +require 'test/unit' + +# begin require 'rubygems' rescue LoadError end +# require 'ruby-debug'; Debugger.start + +# Test enable and disable commands +class TestEnable < Test::Unit::TestCase + + @@SRC_DIR = File.dirname(__FILE__) unless + defined?(@@SRC_DIR) + + require File.join(@@SRC_DIR, 'helper') + include TestHelper + + def test_basic + testname='enable' + Dir.chdir(@@SRC_DIR) do + script = File.join('data', testname + '.cmd') + assert_equal(true, + run_debugger(testname, + "--script #{script} -- gcd.rb 3 5")) + end + end +end diff --git a/test/.svn/text-base/test-finish.rb.svn-base b/test/.svn/text-base/test-finish.rb.svn-base new file mode 100644 index 0000000..4f452cf --- /dev/null +++ b/test/.svn/text-base/test-finish.rb.svn-base @@ -0,0 +1,34 @@ +#!/usr/bin/env ruby +require 'test/unit' + +# require 'rubygems' +# require 'ruby-debug'; Debugger.start + +# Test finish command +class TestFinish < Test::Unit::TestCase + + @@src_dir = File.dirname(__FILE__) unless + defined?(@@src_dir) + + require File.join(@@src_dir, 'helper') + include TestHelper + + def test_basic + testname='finish' + # Ruby 1.8.6 and earlier have a trace-line number bug for return + # statements. +# filter = Proc.new{|got_lines, correct_lines| +# [got_lines[31], got_lines[34]].flatten.each do |s| +# s.sub!(/gcd.rb:\d+/, 'gcd.rb:13') +# end +# got_lines[32] = 'return a' +# } + Dir.chdir(@@src_dir) do + script = File.join('data', testname + '.cmd') + assert_equal(true, + run_debugger(testname, + "--script #{script} -- gcd.rb 3 5", + nil, nil)) + end + end +end diff --git a/test/.svn/text-base/test-frame.rb.svn-base b/test/.svn/text-base/test-frame.rb.svn-base new file mode 100644 index 0000000..c5f059f --- /dev/null +++ b/test/.svn/text-base/test-frame.rb.svn-base @@ -0,0 +1,34 @@ +#!/usr/bin/env ruby +require 'test/unit' + +# require 'rubygems' +# require 'ruby-debug'; Debugger.start(:post_mortem => true) + +# Test frame commands +class TestFrame < Test::Unit::TestCase + + @@SRC_DIR = File.dirname(__FILE__) unless + defined?(@@SRC_DIR) + + require File.join(@@SRC_DIR, 'helper') + include TestHelper + + # Test commands in frame.rb + def test_basic + testname='frame' + # Ruby 1.8.6 and earlier have a trace-line number bug for return + # statements. + filter = Proc.new{|got_lines, correct_lines| + [got_lines[11], correct_lines[11]].flatten.each do |s| + s.sub!(/in file ".*gcd.rb/, 'in file "gcd.rb') + end + } + Dir.chdir(@@SRC_DIR) do + script = File.join('data', testname + '.cmd') + assert_equal(true, + run_debugger(testname, + "--script #{script} -- gcd.rb 3 5", + nil, filter)) + end + end +end diff --git a/test/.svn/text-base/test-help.rb.svn-base b/test/.svn/text-base/test-help.rb.svn-base new file mode 100644 index 0000000..460dd6c --- /dev/null +++ b/test/.svn/text-base/test-help.rb.svn-base @@ -0,0 +1,60 @@ +#!/usr/bin/env ruby + +# begin require 'rubygems' rescue LoadError end +# require 'ruby-debug' ; Debugger.start + +require 'test/unit' +SRC_DIR = File.dirname(__FILE__) unless + defined?(SRC_DIR) +%w(ext lib cli).each do |dir| + $:.unshift File.join(SRC_DIR, '..', dir) +end +require 'ruby_debug' + +require File.join(SRC_DIR, '..', 'cli', 'ruby-debug') +$:.shift; $:.shift; $:.shift + +def cheap_diff(got_lines, correct_lines) + puts got_lines if $DEBUG + correct_lines.each_with_index do |line, i| + correct_lines[i].chomp! + if got_lines[i] != correct_lines[i] + puts "difference found at line #{i+1}" + puts "got : #{got_lines[i]}" + puts "need: #{correct_lines[i]}" + return false + end + if correct_lines.size != got_lines.size + puts("difference in number of lines: " + + "#{correct_lines.size} vs. #{got_lines.size}") + return false + end + return true + end +end + +# Test Help commands +class TestHelp < Test::Unit::TestCase + require 'stringio' + + # Test initial variables and setting/getting state. + def test_basic + testbase = 'help' + op = StringIO.new('', 'w') + Dir.chdir(SRC_DIR) do + script = File.join('data', "#{testbase}.cmd") + Debugger.const_set('Version', 'unit testing') + Debugger.run_script(script, op) + got_lines = op.string.split("\n") + right_file = File.join('data', "#{testbase}.right") + correct_lines = File.readlines(right_file) + result = cheap_diff(got_lines, correct_lines) + unless result + puts '-' * 80 + puts got_lines + puts '-' * 80 + end + assert result + end + end +end diff --git a/test/.svn/text-base/test-hist.rb.svn-base b/test/.svn/text-base/test-hist.rb.svn-base new file mode 100644 index 0000000..484394c --- /dev/null +++ b/test/.svn/text-base/test-hist.rb.svn-base @@ -0,0 +1,68 @@ +#!/usr/bin/env ruby +require 'test/unit' + +# begin require 'rubygems' rescue LoadError end +# require 'ruby-debug'; Debugger.start + +# Test history commands + +class TestHistory < Test::Unit::TestCase + + @@SRC_DIR = File.dirname(__FILE__) unless + defined?(@@SRC_DIR) + + require File.join(@@SRC_DIR, 'helper') + include TestHelper + + unless defined?(@@FILE_HISTORY) + @@FILE_HISTORY = '.rdebug_hist' + end + + def test_basic + + # Set up history file to read from. + ENV['HOME']=@@SRC_DIR + ENV['RDEBUG'] = nil + + debugger_commands = ['show commands', + 'set history save on', + 'show history', + 'quit unconditionally'] + debugger_output = 'test-history.out' + + Dir.chdir(@@SRC_DIR) do + correct_lines = File.read(File.join('data', 'history.right')).split(/\n/) + f = File.open(@@FILE_HISTORY, 'w') + correct_lines[0.. -(debugger_commands.length+1)].each do |line| + f.puts line + end + f.close + + # Now that we've set up a history file, run the debugger + # and check that it's reading that correctly. + debug_pgm=File.join('..', 'rdbg.rb') + debugged=File.join('gcd.rb') + IO.popen("#{debug_pgm} #{debugged} 3 5 >#{debugger_output}", 'w') do + |pipe| + debugger_commands.each do |cmd| + pipe.puts cmd + end + end + + # Compare output + got_lines = File.read(@@FILE_HISTORY).split(/\n/) + # FIXME: Disable for now. + assert true, 'FIXME' + return + if cheap_diff(got_lines, correct_lines) + assert true + FileUtils.rm(debugger_output) + FileUtils.rm(@@FILE_HISTORY) + else + assert nil, 'Output differs' + end + end + end +end + + diff --git a/test/.svn/text-base/test-info-thread.rb.svn-base b/test/.svn/text-base/test-info-thread.rb.svn-base new file mode 100644 index 0000000..d90cc8a --- /dev/null +++ b/test/.svn/text-base/test-info-thread.rb.svn-base @@ -0,0 +1,32 @@ +#!/usr/bin/env ruby +require 'test/unit' + +# begin require 'rubygems' rescue LoadError end +# require 'ruby-debug'; Debugger.start + +# Test simple thread commands +class TestInfoThread < Test::Unit::TestCase + + @@SRC_DIR = File.dirname(__FILE__) unless + defined?(@@SRC_DIR) + + require File.join(@@SRC_DIR, 'helper') + include TestHelper + + def test_basic + testname='info-thread' + Dir.chdir(@@SRC_DIR) do + filter = Proc.new{|got_lines, correct_lines| + [got_lines, correct_lines].each do |a| + a.each do |s| + s.sub!(/Thread:0x[0-9a-f]+/, 'Thread:0x12345678') + end + end + } + script = File.join('data', testname + '.cmd') + assert_equal(true, + run_debugger(testname, + "--script #{script} -- gcd.rb 3 5", nil, filter)) + end + end +end diff --git a/test/.svn/text-base/test-info-var.rb.svn-base b/test/.svn/text-base/test-info-var.rb.svn-base new file mode 100644 index 0000000..af06c78 --- /dev/null +++ b/test/.svn/text-base/test-info-var.rb.svn-base @@ -0,0 +1,47 @@ +#!/usr/bin/env ruby +require 'test/unit' + +# begin require 'rubygems' rescue LoadError end +# require 'ruby-debug'; Debugger.start + +# Test info variables command +class TestInfoVar < Test::Unit::TestCase + + @@SRC_DIR = File.dirname(__FILE__) unless + defined?(@@SRC_DIR) + + require File.join(@@SRC_DIR, 'helper') + include TestHelper + + def test_info_variables + + Dir.chdir(@@SRC_DIR) do + + filter = Proc.new{|got_lines, correct_lines| + [got_lines[13-1], correct_lines[13-1]].each do |s| + s.sub!(/Mine:0x[0-9,a-f]+/, 'Mine:') + end + [got_lines, correct_lines].each do |a| + a.each do |s| + s.sub!(/Lousy_inspect:0x[0-9,a-f]+/, 'Lousy_inspect:') + s.sub!(/UnsuspectingClass:0x[0-9,a-f]+/, 'UnsuspectingClass:') + end + end + } + + testname='info-var' + script = File.join('data', testname + '.cmd') + assert_equal(true, + run_debugger(testname, + "--script #{script} -- info-var-bug.rb", + nil, filter)) + testname='info-var-bug2' + script = File.join('data', testname + '.cmd') + assert_equal(true, + run_debugger(testname, + "--script #{script} -- info-var-bug2.rb", + nil)) + + end + end +end diff --git a/test/.svn/text-base/test-info.rb.svn-base b/test/.svn/text-base/test-info.rb.svn-base new file mode 100644 index 0000000..dade3c8 --- /dev/null +++ b/test/.svn/text-base/test-info.rb.svn-base @@ -0,0 +1,26 @@ +#!/usr/bin/env ruby +require 'test/unit' + +# begin require 'rubygems' rescue LoadError end +# require 'ruby-debug'; Debugger.start + +# Test info commands +class TestInfo < Test::Unit::TestCase + + @@SRC_DIR = File.dirname(__FILE__) unless + defined?(@@SRC_DIR) + + require File.join(@@SRC_DIR, 'helper') + include TestHelper + + # Test commands in info.rb + def test_basic + testname='info' + Dir.chdir(@@SRC_DIR) do + script = File.join('data', testname + '.cmd') + assert_equal(true, + run_debugger(testname, + "--script #{script} -- gcd.rb 3 5")) + end + end +end diff --git a/test/.svn/text-base/test-init.rb.svn-base b/test/.svn/text-base/test-init.rb.svn-base new file mode 100644 index 0000000..bbc2394 --- /dev/null +++ b/test/.svn/text-base/test-init.rb.svn-base @@ -0,0 +1,43 @@ +#!/usr/bin/env ruby +require 'test/unit' +require 'rbconfig' +require File.join(File.dirname(__FILE__), 'helper.rb') + +# begin require 'rubygems' rescue LoadError end +# require 'ruby-debug'; Debugger.start + +# Test Debugger.init and setting up ruby-debug variables +class TestDebuggerInit < Test::Unit::TestCase + @@SRC_DIR = File.dirname(__FILE__) unless + defined?(@@SRC_DIR) + def test_basic + debugger_output = 'test-init.out' + Dir.chdir(@@SRC_DIR) do + old_emacs = ENV['EMACS'] + old_columns = ENV['COLUMNS'] + ENV['EMACS'] = nil + ENV['COLUMNS'] = '120' + ruby = "#{TestHelper.load_ruby} #{TestHelper.load_params}" + IO.popen("#{ruby} ./gcd-dbg.rb 5 >#{debugger_output}", 'w') do |pipe| + pipe.puts 'p Debugger::PROG_SCRIPT' + pipe.puts 'show args' + pipe.puts 'quit unconditionally' + end + lines = File.open(debugger_output).readlines + ENV['EMACS'] = old_emacs + ENV['COLUMNS'] = old_columns + + right_file = case Config::CONFIG['host_os'] + when /^darwin/ + 'test-init-osx.right' + when /^cygwin/ + 'test-init-cygwin.right' + else + 'test-init.right' + end + expected = File.open(File.join('data', right_file)).readlines + assert_equal(expected, lines) + File.delete(debugger_output) if expected == lines + end + end +end diff --git a/test/.svn/text-base/test-list.rb.svn-base b/test/.svn/text-base/test-list.rb.svn-base new file mode 100644 index 0000000..12c2680 --- /dev/null +++ b/test/.svn/text-base/test-list.rb.svn-base @@ -0,0 +1,25 @@ +#!/usr/bin/env ruby +require 'test/unit' + +# begin require 'rubygems' rescue LoadError end +# require 'ruby-debug'; Debugger.start + +# Test List commands +class TestList < Test::Unit::TestCase + + @@src_dir = File.dirname(__FILE__) + + require File.join(@@src_dir, 'helper') + include TestHelper + + # Test commands in list.rb + def test_basic + testname='list' + Dir.chdir(@@src_dir) do + script = File.join('data', testname + '.cmd') + assert_equal(true, + run_debugger(testname, + "--script #{script} -- gcd.rb 3 5")) + end + end +end diff --git a/test/.svn/text-base/test-method.rb.svn-base b/test/.svn/text-base/test-method.rb.svn-base new file mode 100644 index 0000000..a8da23b --- /dev/null +++ b/test/.svn/text-base/test-method.rb.svn-base @@ -0,0 +1,34 @@ +#!/usr/bin/env ruby +require 'test/unit' + +# require 'rubygems' +# require 'ruby-debug'; Debugger.start(:post_mortem => true) + +class TestMethod < Test::Unit::TestCase + + @@SRC_DIR = File.dirname(__FILE__) unless + defined?(@@SRC_DIR) + + require File.join(@@SRC_DIR, 'helper') + include TestHelper + + def test_basic + testname='method' + Dir.chdir(@@SRC_DIR) do + script = File.join('data', testname + '.cmd') + assert_equal(true, + run_debugger(testname, + "--script #{script} -- classes.rb")) + begin + require 'methodsig' + testname='methodsig' + script = File.join('data', testname + '.cmd') + assert_equal(true, + run_debugger(testname, + "--script #{script} -- classes.rb")) + rescue LoadError + puts "Skipping method sig test" + end + end + end +end diff --git a/test/.svn/text-base/test-output.rb.svn-base b/test/.svn/text-base/test-output.rb.svn-base new file mode 100644 index 0000000..9435113 --- /dev/null +++ b/test/.svn/text-base/test-output.rb.svn-base @@ -0,0 +1,26 @@ +#!/usr/bin/env ruby +require 'test/unit' + +# begin require 'rubygems' rescue LoadError end +# require 'ruby-debug'; Debugger.start + +# Test 'starting' annotation. +class TestStartingAnnotate < Test::Unit::TestCase + + @@SRC_DIR = File.dirname(__FILE__) unless + defined?(@@SRC_DIR) + + require File.join(@@SRC_DIR, 'helper') + include TestHelper + + def test_basic + testname='output' + Dir.chdir(@@SRC_DIR) do + script = File.join('data', testname + '.cmd') + assert_equal(true, + run_debugger(testname, + "-A 3 --script #{script} -- output.rb", + nil, nil, true)) + end + end +end diff --git a/test/.svn/text-base/test-pm.rb.svn-base b/test/.svn/text-base/test-pm.rb.svn-base new file mode 100644 index 0000000..cc646cc --- /dev/null +++ b/test/.svn/text-base/test-pm.rb.svn-base @@ -0,0 +1,59 @@ +#!/usr/bin/env ruby +require 'test/unit' +require 'rbconfig' + +# begin require 'rubygems' rescue LoadError end +# require 'ruby-debug'; Debugger.start + +# Test Post-mortem command +class TestPM < Test::Unit::TestCase + + @@SRC_DIR = File.dirname(__FILE__) unless + defined?(@@SRC_DIR) + + require File.join(@@SRC_DIR, 'helper') + include TestHelper + + # Test post-mortem handling + def test_basic + Dir.chdir(@@SRC_DIR) do +# filter = Proc.new{|got_lines, correct_lines| +# [got_lines[0], correct_lines[0]].each do |s| +# s.sub!(/tdebug.rb:\d+/, 'rdebug:999') +# end +# } + ENV['COLUMNS'] = '80' + testname='post-mortem' + script = File.join('data', testname + '.cmd') + testname += '-osx' if Config::CONFIG['host_os'] =~ /^darwin/ + assert_equal(true, + run_debugger(testname, + "--script #{script} --post-mortem pm.rb")) + end + end + + # Test post-mortem handling + def test_pm_next + Dir.chdir(@@SRC_DIR) do + ENV['COLUMNS'] = '80' + testname='post-mortem-next' + script = File.join('data', testname + '.cmd') + assert_equal(true, + run_debugger(testname, + "--script #{script} --post-mortem pm.rb")) + end + end + + # Test Tracker #22118 post-mortem giving an error in show internal variables + def test_pm_iv_bug + Dir.chdir(@@SRC_DIR) do + ENV['COLUMNS'] = '80' + testname='pm-bug' + script = File.join('data', testname + '.cmd') + assert_equal(true, + run_debugger(testname, + "--script #{script} --post-mortem pm-bug.rb")) + end + end + +end diff --git a/test/.svn/text-base/test-quit.rb.svn-base b/test/.svn/text-base/test-quit.rb.svn-base new file mode 100644 index 0000000..2a313b8 --- /dev/null +++ b/test/.svn/text-base/test-quit.rb.svn-base @@ -0,0 +1,30 @@ +#!/usr/bin/env ruby +require 'test/unit' + +# begin require 'rubygems' rescue LoadError end +# require 'ruby-debug'; Debugger.start + +# Test Quit command +class TestQuit < Test::Unit::TestCase + + @@SRC_DIR = File.dirname(__FILE__) unless + defined?(@@SRC_DIR) + + require File.join(@@SRC_DIR, 'helper') + include TestHelper + + def test_basic + testname='quit' + Dir.chdir(@@SRC_DIR) do + script = File.join('data', testname + '.cmd') +# filter = Proc.new{|got_lines, correct_lines| +# [got_lines[0], correct_lines[0]].each do |s| +# s.sub!(/tdebug.rb:\d+/, 'rdebug:999') +# end +# } + assert_equal(true, + run_debugger(testname, + "--script #{script} -- null.rb")) + end + end +end diff --git a/test/.svn/text-base/test-raise.rb.svn-base b/test/.svn/text-base/test-raise.rb.svn-base new file mode 100644 index 0000000..c111b9e --- /dev/null +++ b/test/.svn/text-base/test-raise.rb.svn-base @@ -0,0 +1,25 @@ +#!/usr/bin/env ruby +require 'test/unit' + +# begin require 'rubygems' rescue LoadError end +# require 'ruby-debug'; Debugger.start + +# Test Debugger.load handles uncaught exceptions in the debugged program. +class TestBreakpoints < Test::Unit::TestCase + + @@SRC_DIR = File.dirname(__FILE__) unless + defined?(@@SRC_DIR) + + require File.join(@@SRC_DIR, 'helper') + include TestHelper + + def test_basic + testname='raise' + Dir.chdir(@@SRC_DIR) do + script = File.join('data', testname + '.cmd') + assert_equal(true, + run_debugger(testname, + "--script #{script} -- raise.rb")) + end + end +end diff --git a/test/.svn/text-base/test-save.rb.svn-base b/test/.svn/text-base/test-save.rb.svn-base new file mode 100644 index 0000000..6d8c6b0 --- /dev/null +++ b/test/.svn/text-base/test-save.rb.svn-base @@ -0,0 +1,31 @@ +#!/usr/bin/env ruby +require 'test/unit' + +# require 'rubygems' +# require 'ruby-debug'; Debugger.start(:post_mortem =>true) + +class TestSave < Test::Unit::TestCase + + @@SRC_DIR = File.dirname(__FILE__) unless + defined?(@@SRC_DIR) + + require File.join(@@SRC_DIR, 'helper') + include TestHelper + + # Test initial variables and setting/getting state. + def test_basic + testname='save' + filter = Proc.new{|got_lines, correct_lines| + got_lines.each do |s| + s.sub!(/2 file .*gcd.rb/, '2 file gcd.rb') + end + } + Dir.chdir(@@SRC_DIR) do + script = File.join('data', testname + '.cmd') + assert_equal(true, + run_debugger(testname, + "--script #{script} -- gcd.rb 3 5", + nil, filter)) + end + end +end diff --git a/test/.svn/text-base/test-setshow.rb.svn-base b/test/.svn/text-base/test-setshow.rb.svn-base new file mode 100644 index 0000000..1710965 --- /dev/null +++ b/test/.svn/text-base/test-setshow.rb.svn-base @@ -0,0 +1,25 @@ +#!/usr/bin/env ruby +require 'test/unit' + +# begin require 'rubygems' rescue LoadError end +# require 'ruby-debug'; Debugger.start + +class TestSetShow < Test::Unit::TestCase + + @@SRC_DIR = File.dirname(__FILE__) unless + defined?(@@SRC_DIR) + + require File.join(@@SRC_DIR, 'helper') + include TestHelper + + # Test initial variables and setting/getting state. + def test_basic + testname='setshow' + Dir.chdir(@@SRC_DIR) do + script = File.join('data', testname + '.cmd') + assert_equal(true, + run_debugger(testname, + "--script #{script} -- gcd.rb 3 5")) + end + end +end diff --git a/test/.svn/text-base/test-source.rb.svn-base b/test/.svn/text-base/test-source.rb.svn-base new file mode 100644 index 0000000..b6c1629 --- /dev/null +++ b/test/.svn/text-base/test-source.rb.svn-base @@ -0,0 +1,25 @@ +#!/usr/bin/env ruby +require 'test/unit' + +# begin require 'rubygems' rescue LoadError end +# require 'ruby-debug'; Debugger.start + +# Test 'source' command handling. +class TestSource < Test::Unit::TestCase + + @@SRC_DIR = File.dirname(__FILE__) unless + defined?(@@SRC_DIR) + + require File.join(@@SRC_DIR, 'helper') + include TestHelper + + def test_basic + testname='source' + Dir.chdir(@@SRC_DIR) do + script = File.join('data', testname + '.cmd') + assert_equal(true, + run_debugger(testname, + "--script #{script} -- gcd.rb 3 5")) + end + end +end diff --git a/test/.svn/text-base/test-stepping.rb.svn-base b/test/.svn/text-base/test-stepping.rb.svn-base new file mode 100644 index 0000000..8c4f404 --- /dev/null +++ b/test/.svn/text-base/test-stepping.rb.svn-base @@ -0,0 +1,26 @@ +#!/usr/bin/env ruby +require 'test/unit' + +# begin require 'rubygems' rescue LoadError end +# require 'ruby-debug'; Debugger.start + +# Test that linetracing does something. +class TestStepping < Test::Unit::TestCase + + @@SRC_DIR = File.dirname(__FILE__) unless + defined?(@@SRC_DIR) + + require File.join(@@SRC_DIR, 'helper') + include TestHelper + + # Test commands in stepping.rb + def test_basic + testname='stepping' + Dir.chdir(@@SRC_DIR) do + script = File.join('data', testname + '.cmd') + assert_equal(true, + run_debugger(testname, + "--script #{script} -- gcd.rb 3 5")) + end + end +end diff --git a/test/.svn/text-base/test-trace.rb.svn-base b/test/.svn/text-base/test-trace.rb.svn-base new file mode 100644 index 0000000..7e64ed0 --- /dev/null +++ b/test/.svn/text-base/test-trace.rb.svn-base @@ -0,0 +1,63 @@ +#!/usr/bin/env ruby +require 'test/unit' + +# begin require 'rubygems' rescue LoadError end +# require 'ruby-debug'; Debugger.start + +# Test 'edit' command handling. +class TestEdit < Test::Unit::TestCase + + @@SRC_DIR = File.dirname(__FILE__) unless + defined?(@@SRC_DIR) + + require File.join(@@SRC_DIR, 'helper') + include TestHelper + + def test_trace_option + + filter = Proc.new{|got_lines, correct_lines| + got_lines.collect!{|l| l =~ /:gcd\.rb:/? l : nil}.compact! + } + + testname='trace' + Dir.chdir(@@SRC_DIR) do + assert_equal(true, + run_debugger(testname, + "-nx --trace gcd.rb 3 5", nil, filter)) + end + end + + def test_linetrace_command + + filter = Proc.new{|got_lines, correct_lines| + got_lines.collect!{|l| l !~ /:rdbg\.rb:/? l : nil}.compact! + } + + testname='linetrace' + Dir.chdir(@@SRC_DIR) do + script = File.join('data', testname + '.cmd') + assert_equal(true, + run_debugger(testname, + "--script #{script} -- gcd.rb 3 5", nil, + filter)) + + end + end + + def test_linetrace_plus_command + + filter = Proc.new{|got_lines, correct_lines| + got_lines.collect!{|l| l !~ /:rdbg\.rb:/? l : nil}.compact! + } + + testname='linetracep' + Dir.chdir(@@SRC_DIR) do + script = File.join('data', testname + '.cmd') + assert_equal(true, + run_debugger(testname, + "--script #{script} -- gcd.rb 3 5", nil, + filter)) + + end + end +end diff --git a/test/.svn/text-base/thread1.rb.svn-base b/test/.svn/text-base/thread1.rb.svn-base new file mode 100644 index 0000000..26bdf3b --- /dev/null +++ b/test/.svn/text-base/thread1.rb.svn-base @@ -0,0 +1,26 @@ +#!/usr/bin/env ruby +# Adapted from Programming Ruby 2nd Ed. p. 138 +require 'rubygems' + +unless defined?(Debugger) + puts "This program has to be called from the debugger" + exit 1 +end + +def fn(count, i) + sleep(rand(0.1)) + if 4 == i + debugger + end + Thread.current['mycount'] = count +end + +count = 0 +threads = [] +5.times do |i| + threads[i] = Thread.new do + fn(count, i) + count += 1 + end + end +threads.each {|t| t.join } diff --git a/test/.svn/text-base/trunc-call.rb.svn-base b/test/.svn/text-base/trunc-call.rb.svn-base new file mode 100644 index 0000000..d892d4f --- /dev/null +++ b/test/.svn/text-base/trunc-call.rb.svn-base @@ -0,0 +1,31 @@ +#!/usr/bin/env ruby +# This program is used to test that 'restart' works when we didn't call +# the debugger initially. + +TOP_SRC_DIR = File.join(File.expand_path(File.dirname(__FILE__), "..")) unless + defined?(TOP_SRC_DIR) + +$:.unshift File.join(TOP_SRC_DIR, "ext") +$:.unshift File.join(TOP_SRC_DIR, "lib") +$:.unshift File.join(TOP_SRC_DIR, "cli") +require 'ruby-debug' + +# GCD. We assume positive numbers +def gcd(a, b) + # Make: a <= b + if a > b + a, b = [b, a] + end + if a==3 + Debugger.debugger + end + + return nil if a <= 0 + + if a == 1 or b-a == 0 + return a + end + return gcd(b-a, a) +end + +gcd(13,8) diff --git a/test/base/.svn/README.txt b/test/base/.svn/README.txt new file mode 100644 index 0000000..271a8ce --- /dev/null +++ b/test/base/.svn/README.txt @@ -0,0 +1,2 @@ +This is a Subversion working copy administrative directory. +Visit http://subversion.tigris.org/ for more information. diff --git a/test/base/.svn/empty-file b/test/base/.svn/empty-file new file mode 100644 index 0000000..e69de29 diff --git a/test/base/.svn/entries b/test/base/.svn/entries new file mode 100644 index 0000000..f02496e --- /dev/null +++ b/test/base/.svn/entries @@ -0,0 +1,49 @@ + + + + + + + + diff --git a/test/base/.svn/format b/test/base/.svn/format new file mode 100644 index 0000000..b8626c4 --- /dev/null +++ b/test/base/.svn/format @@ -0,0 +1 @@ +4 diff --git a/test/base/.svn/prop-base/base.rb.svn-base b/test/base/.svn/prop-base/base.rb.svn-base new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/base/.svn/prop-base/base.rb.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/base/.svn/prop-base/binding.rb.svn-base b/test/base/.svn/prop-base/binding.rb.svn-base new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/base/.svn/prop-base/binding.rb.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/base/.svn/prop-base/catchpoint.rb.svn-base b/test/base/.svn/prop-base/catchpoint.rb.svn-base new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/base/.svn/prop-base/catchpoint.rb.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/base/.svn/prop-base/load.rb.svn-base b/test/base/.svn/prop-base/load.rb.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/base/.svn/prop-base/load.rb.svn-base @@ -0,0 +1 @@ +END diff --git a/test/base/.svn/props/base.rb.svn-work b/test/base/.svn/props/base.rb.svn-work new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/base/.svn/props/base.rb.svn-work @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/base/.svn/props/binding.rb.svn-work b/test/base/.svn/props/binding.rb.svn-work new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/base/.svn/props/binding.rb.svn-work @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/base/.svn/props/catchpoint.rb.svn-work b/test/base/.svn/props/catchpoint.rb.svn-work new file mode 100644 index 0000000..869ac71 --- /dev/null +++ b/test/base/.svn/props/catchpoint.rb.svn-work @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/test/base/.svn/props/load.rb.svn-work b/test/base/.svn/props/load.rb.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/base/.svn/props/load.rb.svn-work @@ -0,0 +1 @@ +END diff --git a/test/base/.svn/text-base/base.rb.svn-base b/test/base/.svn/text-base/base.rb.svn-base new file mode 100644 index 0000000..aefb56c --- /dev/null +++ b/test/base/.svn/text-base/base.rb.svn-base @@ -0,0 +1,74 @@ +#!/usr/bin/env ruby +require 'test/unit' + +# Some tests of Debugger module in C extension ruby_debug +class TestRubyDebug < Test::Unit::TestCase + $:.unshift File.join(File.dirname(__FILE__), '..', '..', 'ext') + require 'ruby_debug' + $:.shift + + # test current_context + def test_current_context + assert_equal(false, Debugger.started?, + 'debugger should not initially be started.') + Debugger.start_ + assert(Debugger.started?, + 'debugger should now be started.') + assert_equal(__LINE__, Debugger.current_context.frame_line) + assert_equal(nil, Debugger.current_context.frame_args_info, + 'no frame args info.') + assert_equal(Debugger.current_context.frame_file, + Debugger.current_context.frame_file(0)) + assert_equal(File.basename(__FILE__), + File.basename(Debugger.current_context.frame_file)) + assert_raises(ArgumentError) {Debugger.current_context.frame_file(1, 2)} + assert_raises(ArgumentError) {Debugger.current_context.frame_file(10)} + assert_equal(1, Debugger.current_context.stack_size) + assert_equal(TestRubyDebug, Debugger.current_context.frame_class) + assert_equal(false, Debugger.current_context.dead?, 'Not dead yet!') + Debugger.stop + assert_equal(false, Debugger.started?, + 'Debugger should no longer be started.') + end + + # Test initial variables and setting/getting state. + def test_debugger_base + assert_equal(false, Debugger.started?, + 'Debugger should not initially be started.') + Debugger.start_ + assert(Debugger.started?, + 'Debugger should now be started.') + assert_equal(false, Debugger.debug, + 'Debug variable should not be set.') + assert_equal(false, Debugger.post_mortem?, + 'Post mortem debugging should not be set.') + a = Debugger.contexts + assert_equal(1, a.size, + 'There should only be one context.') + assert_equal(Array, a.class, + 'Context should be an array.') + Debugger.stop + assert_equal(false, Debugger.started?, + 'debugger should no longer be started.') + end + + # Test breakpoint handling + def test_breakpoints + Debugger.start_ + assert_equal(0, Debugger.breakpoints.size, + 'There should not be any breakpoints set.') + brk = Debugger.add_breakpoint(__FILE__, 1) + assert_equal(Debugger::Breakpoint, brk.class, + 'Breakpoint should have been set and returned.') + assert_equal(1, Debugger.breakpoints.size, + 'There should now be one breakpoint set.') + Debugger.remove_breakpoint(0) + assert_equal(1, Debugger.breakpoints.size, + 'There should still be one breakpoint set.') + Debugger.remove_breakpoint(1) + assert_equal(0, Debugger.breakpoints.size, + 'There should no longer be any breakpoints set.') + Debugger.stop + end +end + diff --git a/test/base/.svn/text-base/binding.rb.svn-base b/test/base/.svn/text-base/binding.rb.svn-base new file mode 100644 index 0000000..23731fb --- /dev/null +++ b/test/base/.svn/text-base/binding.rb.svn-base @@ -0,0 +1,31 @@ +#!/usr/bin/env ruby + +require 'test/unit' + +# Test binding_n command +class TestBinding < Test::Unit::TestCase + + SRC_DIR = File.expand_path(File.dirname(__FILE__)) unless + defined?(SRC_DIR) + %w(ext lib).each do |dir| + $:.unshift File.join(SRC_DIR, '..', '..', dir) + end + require File.join(SRC_DIR, '..', '..', 'lib', 'ruby-debug-base') + $:.shift; $:.shift + + def test_basic + def inside_fn + s = 'some other string' + b2 = Kernel::binding_n(1) + y2 = eval('s', b2) + assert_equal('this is a test', y2) + end + s = 'this is a test' + Debugger.start + b = Kernel::binding_n(0) + y = eval('s', b) + assert_equal(y, s) + inside_fn + Debugger.stop + end +end diff --git a/test/base/.svn/text-base/catchpoint.rb.svn-base b/test/base/.svn/text-base/catchpoint.rb.svn-base new file mode 100644 index 0000000..f7105db --- /dev/null +++ b/test/base/.svn/text-base/catchpoint.rb.svn-base @@ -0,0 +1,26 @@ +#!/usr/bin/env ruby +require 'test/unit' + +# Test catchpoint in C ruby_debug extension. + +class TestRubyDebugCatchpoint < Test::Unit::TestCase + + $:.unshift File.join(File.dirname(__FILE__), '..', '..', 'ext') + require 'ruby_debug' + $:.shift + + # test current_context + def test_catchpoints + assert_raise(RuntimeError) {Debugger.catchpoints} + Debugger.start_ + assert_equal({}, Debugger.catchpoints) + Debugger.add_catchpoint('ZeroDivisionError') + assert_equal({'ZeroDivisionError' => 0}, Debugger.catchpoints) + Debugger.add_catchpoint('RuntimeError') + assert_equal(['RuntimeError', 'ZeroDivisionError'], + Debugger.catchpoints.keys.sort) + Debugger.stop + end + +end + diff --git a/test/base/.svn/text-base/load.rb.svn-base b/test/base/.svn/text-base/load.rb.svn-base new file mode 100644 index 0000000..5168d8e --- /dev/null +++ b/test/base/.svn/text-base/load.rb.svn-base @@ -0,0 +1,40 @@ +#!/usr/bin/env ruby +require 'test/unit' + +# Test of Debugger.debug_load in C extension ruby_debug.so +class TestDebugLoad < Test::Unit::TestCase + + @@src_dir = File.dirname(__FILE__) + $:.unshift File.join(@@src_dir, '..', '..', 'ext') + require 'ruby_debug' + $:.shift + + class << self + def at_line(file, line) + @@at_line = [File.basename(file), line] + end + end + + Debugger::PROG_SCRIPT = File.join(@@src_dir, '..', 'gcd.rb') + + class Debugger::Context + def at_line(file, line) + TestDebugLoad::at_line(file, line) + end + end + + def test_debug_load + # Without stopping + bt = Debugger.debug_load(Debugger::PROG_SCRIPT, false) + assert_equal(nil, bt) + # With stopping + bt = Debugger.debug_load(Debugger::PROG_SCRIPT, true) + assert_equal(nil, bt) + assert_equal(['gcd.rb', 4], @@at_line) + + # Test that we get a proper backtrace on a script that raises 'abc' + prog_script = File.join(@@src_dir, '..', 'raise.rb') + bt = Debugger.debug_load(prog_script, false) + assert_equal(bt.to_s, 'abc') + end +end diff --git a/test/base/base.rb b/test/base/base.rb new file mode 100755 index 0000000..aefb56c --- /dev/null +++ b/test/base/base.rb @@ -0,0 +1,74 @@ +#!/usr/bin/env ruby +require 'test/unit' + +# Some tests of Debugger module in C extension ruby_debug +class TestRubyDebug < Test::Unit::TestCase + $:.unshift File.join(File.dirname(__FILE__), '..', '..', 'ext') + require 'ruby_debug' + $:.shift + + # test current_context + def test_current_context + assert_equal(false, Debugger.started?, + 'debugger should not initially be started.') + Debugger.start_ + assert(Debugger.started?, + 'debugger should now be started.') + assert_equal(__LINE__, Debugger.current_context.frame_line) + assert_equal(nil, Debugger.current_context.frame_args_info, + 'no frame args info.') + assert_equal(Debugger.current_context.frame_file, + Debugger.current_context.frame_file(0)) + assert_equal(File.basename(__FILE__), + File.basename(Debugger.current_context.frame_file)) + assert_raises(ArgumentError) {Debugger.current_context.frame_file(1, 2)} + assert_raises(ArgumentError) {Debugger.current_context.frame_file(10)} + assert_equal(1, Debugger.current_context.stack_size) + assert_equal(TestRubyDebug, Debugger.current_context.frame_class) + assert_equal(false, Debugger.current_context.dead?, 'Not dead yet!') + Debugger.stop + assert_equal(false, Debugger.started?, + 'Debugger should no longer be started.') + end + + # Test initial variables and setting/getting state. + def test_debugger_base + assert_equal(false, Debugger.started?, + 'Debugger should not initially be started.') + Debugger.start_ + assert(Debugger.started?, + 'Debugger should now be started.') + assert_equal(false, Debugger.debug, + 'Debug variable should not be set.') + assert_equal(false, Debugger.post_mortem?, + 'Post mortem debugging should not be set.') + a = Debugger.contexts + assert_equal(1, a.size, + 'There should only be one context.') + assert_equal(Array, a.class, + 'Context should be an array.') + Debugger.stop + assert_equal(false, Debugger.started?, + 'debugger should no longer be started.') + end + + # Test breakpoint handling + def test_breakpoints + Debugger.start_ + assert_equal(0, Debugger.breakpoints.size, + 'There should not be any breakpoints set.') + brk = Debugger.add_breakpoint(__FILE__, 1) + assert_equal(Debugger::Breakpoint, brk.class, + 'Breakpoint should have been set and returned.') + assert_equal(1, Debugger.breakpoints.size, + 'There should now be one breakpoint set.') + Debugger.remove_breakpoint(0) + assert_equal(1, Debugger.breakpoints.size, + 'There should still be one breakpoint set.') + Debugger.remove_breakpoint(1) + assert_equal(0, Debugger.breakpoints.size, + 'There should no longer be any breakpoints set.') + Debugger.stop + end +end + diff --git a/test/base/binding.rb b/test/base/binding.rb new file mode 100755 index 0000000..23731fb --- /dev/null +++ b/test/base/binding.rb @@ -0,0 +1,31 @@ +#!/usr/bin/env ruby + +require 'test/unit' + +# Test binding_n command +class TestBinding < Test::Unit::TestCase + + SRC_DIR = File.expand_path(File.dirname(__FILE__)) unless + defined?(SRC_DIR) + %w(ext lib).each do |dir| + $:.unshift File.join(SRC_DIR, '..', '..', dir) + end + require File.join(SRC_DIR, '..', '..', 'lib', 'ruby-debug-base') + $:.shift; $:.shift + + def test_basic + def inside_fn + s = 'some other string' + b2 = Kernel::binding_n(1) + y2 = eval('s', b2) + assert_equal('this is a test', y2) + end + s = 'this is a test' + Debugger.start + b = Kernel::binding_n(0) + y = eval('s', b) + assert_equal(y, s) + inside_fn + Debugger.stop + end +end diff --git a/test/base/catchpoint.rb b/test/base/catchpoint.rb new file mode 100755 index 0000000..f7105db --- /dev/null +++ b/test/base/catchpoint.rb @@ -0,0 +1,26 @@ +#!/usr/bin/env ruby +require 'test/unit' + +# Test catchpoint in C ruby_debug extension. + +class TestRubyDebugCatchpoint < Test::Unit::TestCase + + $:.unshift File.join(File.dirname(__FILE__), '..', '..', 'ext') + require 'ruby_debug' + $:.shift + + # test current_context + def test_catchpoints + assert_raise(RuntimeError) {Debugger.catchpoints} + Debugger.start_ + assert_equal({}, Debugger.catchpoints) + Debugger.add_catchpoint('ZeroDivisionError') + assert_equal({'ZeroDivisionError' => 0}, Debugger.catchpoints) + Debugger.add_catchpoint('RuntimeError') + assert_equal(['RuntimeError', 'ZeroDivisionError'], + Debugger.catchpoints.keys.sort) + Debugger.stop + end + +end + diff --git a/test/base/load.rb b/test/base/load.rb new file mode 100644 index 0000000..5168d8e --- /dev/null +++ b/test/base/load.rb @@ -0,0 +1,40 @@ +#!/usr/bin/env ruby +require 'test/unit' + +# Test of Debugger.debug_load in C extension ruby_debug.so +class TestDebugLoad < Test::Unit::TestCase + + @@src_dir = File.dirname(__FILE__) + $:.unshift File.join(@@src_dir, '..', '..', 'ext') + require 'ruby_debug' + $:.shift + + class << self + def at_line(file, line) + @@at_line = [File.basename(file), line] + end + end + + Debugger::PROG_SCRIPT = File.join(@@src_dir, '..', 'gcd.rb') + + class Debugger::Context + def at_line(file, line) + TestDebugLoad::at_line(file, line) + end + end + + def test_debug_load + # Without stopping + bt = Debugger.debug_load(Debugger::PROG_SCRIPT, false) + assert_equal(nil, bt) + # With stopping + bt = Debugger.debug_load(Debugger::PROG_SCRIPT, true) + assert_equal(nil, bt) + assert_equal(['gcd.rb', 4], @@at_line) + + # Test that we get a proper backtrace on a script that raises 'abc' + prog_script = File.join(@@src_dir, '..', 'raise.rb') + bt = Debugger.debug_load(prog_script, false) + assert_equal(bt.to_s, 'abc') + end +end diff --git a/test/bp_loop_issue.rb b/test/bp_loop_issue.rb new file mode 100644 index 0000000..abe072e --- /dev/null +++ b/test/bp_loop_issue.rb @@ -0,0 +1,3 @@ +1.upto(2) { + sleep 0.01 +} diff --git a/test/classes.rb b/test/classes.rb new file mode 100644 index 0000000..7a874bd --- /dev/null +++ b/test/classes.rb @@ -0,0 +1,11 @@ +class Mine + def initialize + @myvar = 'init' + end + def mymethod(a, b=5, &block) + end + def self.classmeth + end +end +me = Mine.new +metoo = Mine(new) diff --git a/test/cli/.svn/README.txt b/test/cli/.svn/README.txt new file mode 100644 index 0000000..271a8ce --- /dev/null +++ b/test/cli/.svn/README.txt @@ -0,0 +1,2 @@ +This is a Subversion working copy administrative directory. +Visit http://subversion.tigris.org/ for more information. diff --git a/test/cli/.svn/empty-file b/test/cli/.svn/empty-file new file mode 100644 index 0000000..e69de29 diff --git a/test/cli/.svn/entries b/test/cli/.svn/entries new file mode 100644 index 0000000..db9fc5c --- /dev/null +++ b/test/cli/.svn/entries @@ -0,0 +1,16 @@ + + + + + diff --git a/test/cli/.svn/format b/test/cli/.svn/format new file mode 100644 index 0000000..b8626c4 --- /dev/null +++ b/test/cli/.svn/format @@ -0,0 +1 @@ +4 diff --git a/test/cli/commands/.svn/README.txt b/test/cli/commands/.svn/README.txt new file mode 100644 index 0000000..271a8ce --- /dev/null +++ b/test/cli/commands/.svn/README.txt @@ -0,0 +1,2 @@ +This is a Subversion working copy administrative directory. +Visit http://subversion.tigris.org/ for more information. diff --git a/test/cli/commands/.svn/empty-file b/test/cli/commands/.svn/empty-file new file mode 100644 index 0000000..e69de29 diff --git a/test/cli/commands/.svn/entries b/test/cli/commands/.svn/entries new file mode 100644 index 0000000..7a5b99c --- /dev/null +++ b/test/cli/commands/.svn/entries @@ -0,0 +1,25 @@ + + + + + + diff --git a/test/cli/commands/.svn/format b/test/cli/commands/.svn/format new file mode 100644 index 0000000..b8626c4 --- /dev/null +++ b/test/cli/commands/.svn/format @@ -0,0 +1 @@ +4 diff --git a/test/cli/commands/.svn/prop-base/catchpoint_test.rb.svn-base b/test/cli/commands/.svn/prop-base/catchpoint_test.rb.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/cli/commands/.svn/prop-base/catchpoint_test.rb.svn-base @@ -0,0 +1 @@ +END diff --git a/test/cli/commands/.svn/props/catchpoint_test.rb.svn-work b/test/cli/commands/.svn/props/catchpoint_test.rb.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/cli/commands/.svn/props/catchpoint_test.rb.svn-work @@ -0,0 +1 @@ +END diff --git a/test/cli/commands/.svn/text-base/catchpoint_test.rb.svn-base b/test/cli/commands/.svn/text-base/catchpoint_test.rb.svn-base new file mode 100644 index 0000000..e9921c5 --- /dev/null +++ b/test/cli/commands/.svn/text-base/catchpoint_test.rb.svn-base @@ -0,0 +1,36 @@ +#!/usr/bin/env ruby + +require 'test/unit' + +class TestCatchCommand < Test::Unit::TestCase + + base_dir = File.expand_path(File.join(File.dirname(__FILE__), + '..', '..', '..')) + + %w(ext lib cli).each do |dir| + $: << File.join(base_dir, dir) + end + + require File.join(base_dir, 'cli', 'ruby-debug') + + class MockState + attr_accessor :message + def context; end + def confirm(msg); true end + def print(*args) + @message = *args + end + end + + # regression test for bug #20156 + def test_catch_does_not_blow_up + state = MockState.new + catch_cmd = Debugger::CatchCommand.new(state) + assert(catch_cmd.match('catch off')) + catch(:debug_error) do + catch_cmd.execute + end + assert_equal(nil, state.message) + end + +end diff --git a/test/cli/commands/catchpoint_test.rb b/test/cli/commands/catchpoint_test.rb new file mode 100644 index 0000000..e9921c5 --- /dev/null +++ b/test/cli/commands/catchpoint_test.rb @@ -0,0 +1,36 @@ +#!/usr/bin/env ruby + +require 'test/unit' + +class TestCatchCommand < Test::Unit::TestCase + + base_dir = File.expand_path(File.join(File.dirname(__FILE__), + '..', '..', '..')) + + %w(ext lib cli).each do |dir| + $: << File.join(base_dir, dir) + end + + require File.join(base_dir, 'cli', 'ruby-debug') + + class MockState + attr_accessor :message + def context; end + def confirm(msg); true end + def print(*args) + @message = *args + end + end + + # regression test for bug #20156 + def test_catch_does_not_blow_up + state = MockState.new + catch_cmd = Debugger::CatchCommand.new(state) + assert(catch_cmd.match('catch off')) + catch(:debug_error) do + catch_cmd.execute + end + assert_equal(nil, state.message) + end + +end diff --git a/test/cli/commands/unit/.svn/README.txt b/test/cli/commands/unit/.svn/README.txt new file mode 100644 index 0000000..271a8ce --- /dev/null +++ b/test/cli/commands/unit/.svn/README.txt @@ -0,0 +1,2 @@ +This is a Subversion working copy administrative directory. +Visit http://subversion.tigris.org/ for more information. diff --git a/test/cli/commands/unit/.svn/empty-file b/test/cli/commands/unit/.svn/empty-file new file mode 100644 index 0000000..e69de29 diff --git a/test/cli/commands/unit/.svn/entries b/test/cli/commands/unit/.svn/entries new file mode 100644 index 0000000..1e3b392 --- /dev/null +++ b/test/cli/commands/unit/.svn/entries @@ -0,0 +1,22 @@ + + + + + diff --git a/test/cli/commands/unit/.svn/format b/test/cli/commands/unit/.svn/format new file mode 100644 index 0000000..b8626c4 --- /dev/null +++ b/test/cli/commands/unit/.svn/format @@ -0,0 +1 @@ +4 diff --git a/test/cli/commands/unit/.svn/prop-base/regexp.rb.svn-base b/test/cli/commands/unit/.svn/prop-base/regexp.rb.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/cli/commands/unit/.svn/prop-base/regexp.rb.svn-base @@ -0,0 +1 @@ +END diff --git a/test/cli/commands/unit/.svn/props/regexp.rb.svn-work b/test/cli/commands/unit/.svn/props/regexp.rb.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/cli/commands/unit/.svn/props/regexp.rb.svn-work @@ -0,0 +1 @@ +END diff --git a/test/cli/commands/unit/.svn/text-base/regexp.rb.svn-base b/test/cli/commands/unit/.svn/text-base/regexp.rb.svn-base new file mode 100644 index 0000000..76ed41d --- /dev/null +++ b/test/cli/commands/unit/.svn/text-base/regexp.rb.svn-base @@ -0,0 +1,42 @@ +require 'test/unit' + + +class TestCommandREs < Test::Unit::TestCase + base_dir=File.expand_path(File.join(File.dirname(__FILE__), + '..', '..', '..', '..', + 'cli', 'ruby-debug')) + require File.join(base_dir, 'command') + require File.join(base_dir, 'commands', 'frame') + include Debugger + + def test_quit + c = QuitCommand.new(nil) + assert c.regexp.match('quit') + assert c.regexp.match('q') + assert c.regexp.match('quit!') + assert c.regexp.match('q!') + assert c.regexp.match('quit unconditionally') + assert c.regexp.match('exit') + assert c.regexp.match('exit!') + end + + def test_up + c = UpCommand.new(nil) + assert c.regexp.match('up') + assert c.regexp.match('up 2') + assert c.regexp.match('up 2+5') + assert c.regexp.match('u') + assert c.regexp.match('u 2') + assert_equal nil, c.regexp.match('ufoo') + end + + def test_down + c = DownCommand.new(nil) + assert c.regexp.match('down') + assert c.regexp.match('down 2') + assert_equal(nil, c.regexp.match('d 2')) + assert_equal(nil, c.regexp.match('d')) + assert_equal(nil, c.regexp.match('dow')) + end +end + diff --git a/test/cli/commands/unit/regexp.rb b/test/cli/commands/unit/regexp.rb new file mode 100644 index 0000000..76ed41d --- /dev/null +++ b/test/cli/commands/unit/regexp.rb @@ -0,0 +1,42 @@ +require 'test/unit' + + +class TestCommandREs < Test::Unit::TestCase + base_dir=File.expand_path(File.join(File.dirname(__FILE__), + '..', '..', '..', '..', + 'cli', 'ruby-debug')) + require File.join(base_dir, 'command') + require File.join(base_dir, 'commands', 'frame') + include Debugger + + def test_quit + c = QuitCommand.new(nil) + assert c.regexp.match('quit') + assert c.regexp.match('q') + assert c.regexp.match('quit!') + assert c.regexp.match('q!') + assert c.regexp.match('quit unconditionally') + assert c.regexp.match('exit') + assert c.regexp.match('exit!') + end + + def test_up + c = UpCommand.new(nil) + assert c.regexp.match('up') + assert c.regexp.match('up 2') + assert c.regexp.match('up 2+5') + assert c.regexp.match('u') + assert c.regexp.match('u 2') + assert_equal nil, c.regexp.match('ufoo') + end + + def test_down + c = DownCommand.new(nil) + assert c.regexp.match('down') + assert c.regexp.match('down 2') + assert_equal(nil, c.regexp.match('d 2')) + assert_equal(nil, c.regexp.match('d')) + assert_equal(nil, c.regexp.match('dow')) + end +end + diff --git a/test/config.yaml b/test/config.yaml new file mode 100644 index 0000000..2a3ab2b --- /dev/null +++ b/test/config.yaml @@ -0,0 +1,8 @@ +# Do not commit personal changes here back to the repository. Create +# config.private.yaml which, if exists, is preferred to this one. + +# either should be on the $PATH or use full path +ruby: ruby + +# possibility to specify interpreter parameters +#ruby_params: -w diff --git a/test/data/.svn/README.txt b/test/data/.svn/README.txt new file mode 100644 index 0000000..271a8ce --- /dev/null +++ b/test/data/.svn/README.txt @@ -0,0 +1,2 @@ +This is a Subversion working copy administrative directory. +Visit http://subversion.tigris.org/ for more information. diff --git a/test/data/.svn/empty-file b/test/data/.svn/empty-file new file mode 100644 index 0000000..e69de29 diff --git a/test/data/.svn/entries b/test/data/.svn/entries new file mode 100644 index 0000000..f67e270 --- /dev/null +++ b/test/data/.svn/entries @@ -0,0 +1,697 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/data/.svn/format b/test/data/.svn/format new file mode 100644 index 0000000..b8626c4 --- /dev/null +++ b/test/data/.svn/format @@ -0,0 +1 @@ +4 diff --git a/test/data/.svn/prop-base/annotate.cmd.svn-base b/test/data/.svn/prop-base/annotate.cmd.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/annotate.cmd.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/annotate.right.svn-base b/test/data/.svn/prop-base/annotate.right.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/annotate.right.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/break_bad.cmd.svn-base b/test/data/.svn/prop-base/break_bad.cmd.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/break_bad.cmd.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/break_bad.right.svn-base b/test/data/.svn/prop-base/break_bad.right.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/break_bad.right.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/break_loop_bug.cmd.svn-base b/test/data/.svn/prop-base/break_loop_bug.cmd.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/break_loop_bug.cmd.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/break_loop_bug.right.svn-base b/test/data/.svn/prop-base/break_loop_bug.right.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/break_loop_bug.right.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/breakpoints.cmd.svn-base b/test/data/.svn/prop-base/breakpoints.cmd.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/breakpoints.cmd.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/breakpoints.right.svn-base b/test/data/.svn/prop-base/breakpoints.right.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/breakpoints.right.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/catch.cmd.svn-base b/test/data/.svn/prop-base/catch.cmd.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/catch.cmd.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/catch.right.svn-base b/test/data/.svn/prop-base/catch.right.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/catch.right.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/condition.cmd.svn-base b/test/data/.svn/prop-base/condition.cmd.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/condition.cmd.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/condition.right.svn-base b/test/data/.svn/prop-base/condition.right.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/condition.right.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/ctrl.cmd.svn-base b/test/data/.svn/prop-base/ctrl.cmd.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/ctrl.cmd.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/ctrl.right.svn-base b/test/data/.svn/prop-base/ctrl.right.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/ctrl.right.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/display.cmd.svn-base b/test/data/.svn/prop-base/display.cmd.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/display.cmd.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/display.right.svn-base b/test/data/.svn/prop-base/display.right.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/display.right.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/dollar-0.right.svn-base b/test/data/.svn/prop-base/dollar-0.right.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/dollar-0.right.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/dollar-0a.right.svn-base b/test/data/.svn/prop-base/dollar-0a.right.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/dollar-0a.right.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/dollar-0b.right.svn-base b/test/data/.svn/prop-base/dollar-0b.right.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/dollar-0b.right.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/edit.cmd.svn-base b/test/data/.svn/prop-base/edit.cmd.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/edit.cmd.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/edit.right.svn-base b/test/data/.svn/prop-base/edit.right.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/edit.right.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/emacs_basic.cmd.svn-base b/test/data/.svn/prop-base/emacs_basic.cmd.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/emacs_basic.cmd.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/emacs_basic.right.svn-base b/test/data/.svn/prop-base/emacs_basic.right.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/emacs_basic.right.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/enable.cmd.svn-base b/test/data/.svn/prop-base/enable.cmd.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/enable.cmd.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/enable.right.svn-base b/test/data/.svn/prop-base/enable.right.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/enable.right.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/finish.cmd.svn-base b/test/data/.svn/prop-base/finish.cmd.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/finish.cmd.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/finish.right.svn-base b/test/data/.svn/prop-base/finish.right.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/finish.right.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/frame.cmd.svn-base b/test/data/.svn/prop-base/frame.cmd.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/frame.cmd.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/frame.right.svn-base b/test/data/.svn/prop-base/frame.right.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/frame.right.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/help.cmd.svn-base b/test/data/.svn/prop-base/help.cmd.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/help.cmd.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/help.right.svn-base b/test/data/.svn/prop-base/help.right.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/help.right.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/history.right.svn-base b/test/data/.svn/prop-base/history.right.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/history.right.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/info-thread.cmd.svn-base b/test/data/.svn/prop-base/info-thread.cmd.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/info-thread.cmd.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/info-thread.right.svn-base b/test/data/.svn/prop-base/info-thread.right.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/info-thread.right.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/info-var-bug2.cmd.svn-base b/test/data/.svn/prop-base/info-var-bug2.cmd.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/info-var-bug2.cmd.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/info-var-bug2.right.svn-base b/test/data/.svn/prop-base/info-var-bug2.right.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/info-var-bug2.right.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/info-var.cmd.svn-base b/test/data/.svn/prop-base/info-var.cmd.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/info-var.cmd.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/info-var.right.svn-base b/test/data/.svn/prop-base/info-var.right.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/info-var.right.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/info.cmd.svn-base b/test/data/.svn/prop-base/info.cmd.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/info.cmd.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/info.right.svn-base b/test/data/.svn/prop-base/info.right.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/info.right.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/linetrace.cmd.svn-base b/test/data/.svn/prop-base/linetrace.cmd.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/linetrace.cmd.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/linetrace.right.svn-base b/test/data/.svn/prop-base/linetrace.right.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/linetrace.right.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/linetracep.cmd.svn-base b/test/data/.svn/prop-base/linetracep.cmd.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/linetracep.cmd.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/linetracep.right.svn-base b/test/data/.svn/prop-base/linetracep.right.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/linetracep.right.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/list.cmd.svn-base b/test/data/.svn/prop-base/list.cmd.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/list.cmd.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/list.right.svn-base b/test/data/.svn/prop-base/list.right.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/list.right.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/method.cmd.svn-base b/test/data/.svn/prop-base/method.cmd.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/method.cmd.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/method.right.svn-base b/test/data/.svn/prop-base/method.right.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/method.right.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/methodsig.cmd.svn-base b/test/data/.svn/prop-base/methodsig.cmd.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/methodsig.cmd.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/methodsig.right.svn-base b/test/data/.svn/prop-base/methodsig.right.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/methodsig.right.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/noquit.right.svn-base b/test/data/.svn/prop-base/noquit.right.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/noquit.right.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/output.cmd.svn-base b/test/data/.svn/prop-base/output.cmd.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/output.cmd.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/output.right.svn-base b/test/data/.svn/prop-base/output.right.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/output.right.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/pm-bug.cmd.svn-base b/test/data/.svn/prop-base/pm-bug.cmd.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/pm-bug.cmd.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/pm-bug.right.svn-base b/test/data/.svn/prop-base/pm-bug.right.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/pm-bug.right.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/post-mortem-next.cmd.svn-base b/test/data/.svn/prop-base/post-mortem-next.cmd.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/post-mortem-next.cmd.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/post-mortem-next.right.svn-base b/test/data/.svn/prop-base/post-mortem-next.right.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/post-mortem-next.right.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/post-mortem-osx.right.svn-base b/test/data/.svn/prop-base/post-mortem-osx.right.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/post-mortem-osx.right.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/post-mortem.cmd.svn-base b/test/data/.svn/prop-base/post-mortem.cmd.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/post-mortem.cmd.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/post-mortem.right.svn-base b/test/data/.svn/prop-base/post-mortem.right.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/post-mortem.right.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/quit.cmd.svn-base b/test/data/.svn/prop-base/quit.cmd.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/quit.cmd.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/quit.right.svn-base b/test/data/.svn/prop-base/quit.right.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/quit.right.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/raise.cmd.svn-base b/test/data/.svn/prop-base/raise.cmd.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/raise.cmd.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/raise.right.svn-base b/test/data/.svn/prop-base/raise.right.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/raise.right.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/save.cmd.svn-base b/test/data/.svn/prop-base/save.cmd.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/save.cmd.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/save.right.svn-base b/test/data/.svn/prop-base/save.right.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/save.right.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/setshow.cmd.svn-base b/test/data/.svn/prop-base/setshow.cmd.svn-base new file mode 100644 index 0000000..92c8ad7 --- /dev/null +++ b/test/data/.svn/prop-base/setshow.cmd.svn-base @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 2 +Id +END diff --git a/test/data/.svn/prop-base/setshow.right.svn-base b/test/data/.svn/prop-base/setshow.right.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/setshow.right.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/source.cmd.svn-base b/test/data/.svn/prop-base/source.cmd.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/source.cmd.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/source.right.svn-base b/test/data/.svn/prop-base/source.right.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/source.right.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/stepping.cmd.svn-base b/test/data/.svn/prop-base/stepping.cmd.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/stepping.cmd.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/stepping.right.svn-base b/test/data/.svn/prop-base/stepping.right.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/stepping.right.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/test-init-cygwin.right.svn-base b/test/data/.svn/prop-base/test-init-cygwin.right.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/test-init-cygwin.right.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/test-init-osx.right.svn-base b/test/data/.svn/prop-base/test-init-osx.right.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/test-init-osx.right.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/test-init.right.svn-base b/test/data/.svn/prop-base/test-init.right.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/test-init.right.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/prop-base/trace.right.svn-base b/test/data/.svn/prop-base/trace.right.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/prop-base/trace.right.svn-base @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/annotate.cmd.svn-work b/test/data/.svn/props/annotate.cmd.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/annotate.cmd.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/annotate.right.svn-work b/test/data/.svn/props/annotate.right.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/annotate.right.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/break_bad.cmd.svn-work b/test/data/.svn/props/break_bad.cmd.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/break_bad.cmd.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/break_bad.right.svn-work b/test/data/.svn/props/break_bad.right.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/break_bad.right.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/break_loop_bug.cmd.svn-work b/test/data/.svn/props/break_loop_bug.cmd.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/break_loop_bug.cmd.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/break_loop_bug.right.svn-work b/test/data/.svn/props/break_loop_bug.right.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/break_loop_bug.right.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/breakpoints.cmd.svn-work b/test/data/.svn/props/breakpoints.cmd.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/breakpoints.cmd.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/breakpoints.right.svn-work b/test/data/.svn/props/breakpoints.right.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/breakpoints.right.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/catch.cmd.svn-work b/test/data/.svn/props/catch.cmd.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/catch.cmd.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/catch.right.svn-work b/test/data/.svn/props/catch.right.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/catch.right.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/condition.cmd.svn-work b/test/data/.svn/props/condition.cmd.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/condition.cmd.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/condition.right.svn-work b/test/data/.svn/props/condition.right.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/condition.right.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/ctrl.cmd.svn-work b/test/data/.svn/props/ctrl.cmd.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/ctrl.cmd.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/ctrl.right.svn-work b/test/data/.svn/props/ctrl.right.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/ctrl.right.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/display.cmd.svn-work b/test/data/.svn/props/display.cmd.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/display.cmd.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/display.right.svn-work b/test/data/.svn/props/display.right.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/display.right.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/dollar-0.right.svn-work b/test/data/.svn/props/dollar-0.right.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/dollar-0.right.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/dollar-0a.right.svn-work b/test/data/.svn/props/dollar-0a.right.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/dollar-0a.right.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/dollar-0b.right.svn-work b/test/data/.svn/props/dollar-0b.right.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/dollar-0b.right.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/edit.cmd.svn-work b/test/data/.svn/props/edit.cmd.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/edit.cmd.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/edit.right.svn-work b/test/data/.svn/props/edit.right.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/edit.right.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/emacs_basic.cmd.svn-work b/test/data/.svn/props/emacs_basic.cmd.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/emacs_basic.cmd.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/emacs_basic.right.svn-work b/test/data/.svn/props/emacs_basic.right.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/emacs_basic.right.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/enable.cmd.svn-work b/test/data/.svn/props/enable.cmd.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/enable.cmd.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/enable.right.svn-work b/test/data/.svn/props/enable.right.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/enable.right.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/finish.cmd.svn-work b/test/data/.svn/props/finish.cmd.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/finish.cmd.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/finish.right.svn-work b/test/data/.svn/props/finish.right.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/finish.right.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/frame.cmd.svn-work b/test/data/.svn/props/frame.cmd.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/frame.cmd.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/frame.right.svn-work b/test/data/.svn/props/frame.right.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/frame.right.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/help.cmd.svn-work b/test/data/.svn/props/help.cmd.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/help.cmd.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/help.right.svn-work b/test/data/.svn/props/help.right.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/help.right.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/history.right.svn-work b/test/data/.svn/props/history.right.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/history.right.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/info-thread.cmd.svn-work b/test/data/.svn/props/info-thread.cmd.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/info-thread.cmd.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/info-thread.right.svn-work b/test/data/.svn/props/info-thread.right.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/info-thread.right.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/info-var-bug2.cmd.svn-work b/test/data/.svn/props/info-var-bug2.cmd.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/info-var-bug2.cmd.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/info-var-bug2.right.svn-work b/test/data/.svn/props/info-var-bug2.right.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/info-var-bug2.right.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/info-var.cmd.svn-work b/test/data/.svn/props/info-var.cmd.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/info-var.cmd.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/info-var.right.svn-work b/test/data/.svn/props/info-var.right.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/info-var.right.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/info.cmd.svn-work b/test/data/.svn/props/info.cmd.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/info.cmd.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/info.right.svn-work b/test/data/.svn/props/info.right.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/info.right.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/linetrace.cmd.svn-work b/test/data/.svn/props/linetrace.cmd.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/linetrace.cmd.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/linetrace.right.svn-work b/test/data/.svn/props/linetrace.right.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/linetrace.right.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/linetracep.cmd.svn-work b/test/data/.svn/props/linetracep.cmd.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/linetracep.cmd.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/linetracep.right.svn-work b/test/data/.svn/props/linetracep.right.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/linetracep.right.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/list.cmd.svn-work b/test/data/.svn/props/list.cmd.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/list.cmd.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/list.right.svn-work b/test/data/.svn/props/list.right.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/list.right.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/method.cmd.svn-work b/test/data/.svn/props/method.cmd.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/method.cmd.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/method.right.svn-work b/test/data/.svn/props/method.right.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/method.right.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/methodsig.cmd.svn-work b/test/data/.svn/props/methodsig.cmd.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/methodsig.cmd.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/methodsig.right.svn-work b/test/data/.svn/props/methodsig.right.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/methodsig.right.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/noquit.right.svn-work b/test/data/.svn/props/noquit.right.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/noquit.right.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/output.cmd.svn-work b/test/data/.svn/props/output.cmd.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/output.cmd.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/output.right.svn-work b/test/data/.svn/props/output.right.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/output.right.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/pm-bug.cmd.svn-work b/test/data/.svn/props/pm-bug.cmd.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/pm-bug.cmd.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/pm-bug.right.svn-work b/test/data/.svn/props/pm-bug.right.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/pm-bug.right.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/post-mortem-next.cmd.svn-work b/test/data/.svn/props/post-mortem-next.cmd.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/post-mortem-next.cmd.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/post-mortem-next.right.svn-work b/test/data/.svn/props/post-mortem-next.right.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/post-mortem-next.right.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/post-mortem-osx.right.svn-work b/test/data/.svn/props/post-mortem-osx.right.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/post-mortem-osx.right.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/post-mortem.cmd.svn-work b/test/data/.svn/props/post-mortem.cmd.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/post-mortem.cmd.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/post-mortem.right.svn-work b/test/data/.svn/props/post-mortem.right.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/post-mortem.right.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/quit.cmd.svn-work b/test/data/.svn/props/quit.cmd.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/quit.cmd.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/quit.right.svn-work b/test/data/.svn/props/quit.right.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/quit.right.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/raise.cmd.svn-work b/test/data/.svn/props/raise.cmd.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/raise.cmd.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/raise.right.svn-work b/test/data/.svn/props/raise.right.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/raise.right.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/save.cmd.svn-work b/test/data/.svn/props/save.cmd.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/save.cmd.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/save.right.svn-work b/test/data/.svn/props/save.right.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/save.right.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/setshow.cmd.svn-work b/test/data/.svn/props/setshow.cmd.svn-work new file mode 100644 index 0000000..92c8ad7 --- /dev/null +++ b/test/data/.svn/props/setshow.cmd.svn-work @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 2 +Id +END diff --git a/test/data/.svn/props/setshow.right.svn-work b/test/data/.svn/props/setshow.right.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/setshow.right.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/source.cmd.svn-work b/test/data/.svn/props/source.cmd.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/source.cmd.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/source.right.svn-work b/test/data/.svn/props/source.right.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/source.right.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/stepping.cmd.svn-work b/test/data/.svn/props/stepping.cmd.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/stepping.cmd.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/stepping.right.svn-work b/test/data/.svn/props/stepping.right.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/stepping.right.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/test-init-cygwin.right.svn-work b/test/data/.svn/props/test-init-cygwin.right.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/test-init-cygwin.right.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/test-init-osx.right.svn-work b/test/data/.svn/props/test-init-osx.right.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/test-init-osx.right.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/test-init.right.svn-work b/test/data/.svn/props/test-init.right.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/test-init.right.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/props/trace.right.svn-work b/test/data/.svn/props/trace.right.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/test/data/.svn/props/trace.right.svn-work @@ -0,0 +1 @@ +END diff --git a/test/data/.svn/text-base/annotate.cmd.svn-base b/test/data/.svn/text-base/annotate.cmd.svn-base new file mode 100644 index 0000000..1fd55f8 --- /dev/null +++ b/test/data/.svn/text-base/annotate.cmd.svn-base @@ -0,0 +1,29 @@ +# ******************************************************** +# This tests annotations +# ******************************************************** +set debuggertesting on +set callstyle last +set force off +set annotate 3 +# Get into gcd +step 2 +# "break" should trigger break annotation +break 10 +# "delete" should trigger break annotation +delete 1 +# p should not trigger a breakpoint annotation +p a +# "up" should trigger annotations +up +# "b" should trigger like "break" +b 12 +# "display" should trigger display annotation +display 1+2 +# undisplay should trigger display annotation +undisplay 1 +step +# Test error annotations +up 10 +frame 100 +break bogus:5 +quit! diff --git a/test/data/.svn/text-base/annotate.right.svn-base b/test/data/.svn/text-base/annotate.right.svn-base new file mode 100644 index 0000000..9048aff --- /dev/null +++ b/test/data/.svn/text-base/annotate.right.svn-base @@ -0,0 +1,139 @@ +gcd.rb:4 +def gcd(a, b) +# # ******************************************************** +# # This tests annotations +# # ******************************************************** +# set debuggertesting on +Currently testing the debugger is on. +# set callstyle last +Frame call-display style is last. +# set force off +force-stepping is off. +# set annotate 3 +Annotation level is 3 +# # Get into gcd +# step 2 +starting +stopped +breakpoints +No breakpoints. + +stack +--> #0 Object.gcd(a#Fixnum, b#Fixnum) at line gcd.rb:6 + #1 at line gcd.rb:18 + +variables +a = 3 +b = 5 +self = main + +source gcd.rb:6 +if a > b +# # "break" should trigger break annotation +# break 10 +Breakpoint 1 file ./gcd.rb, line 10 +breakpoints +Num Enb What + 1 y at ./gcd.rb:10 + +# # "delete" should trigger break annotation +# delete 1 +breakpoints +No breakpoints. + +# # p should not trigger a breakpoint annotation +# p a +3 +# # "up" should trigger annotations +# up +#1 at line gcd.rb:18 +stack + #0 Object.gcd(a#Fixnum, b#Fixnum) at line gcd.rb:6 +--> #1 at line gcd.rb:18 + +variables +self = main + +# # "b" should trigger like "break" +# b 12 +Breakpoint 2 file ./gcd.rb, line 12 +breakpoints +Num Enb What + 2 y at ./gcd.rb:12 + +# # "display" should trigger display annotation +# display 1+2 +1: 1+2 = 3 +display +1: 1+2 = 3 + +# # undisplay should trigger display annotation +# undisplay 1 +display + +# step +display + +starting +stopped +breakpoints +Num Enb What + 2 y at ./gcd.rb:12 + +display + +stack +--> #0 Object.gcd(a#Fixnum, b#Fixnum) at line gcd.rb:6 + #1 at line gcd.rb:18 + +variables +a = 3 +b = 5 +self = main + +source gcd.rb:6 +if a > b +# # Test error annotations +# up 10 +error-begin +Adjusting would put us beyond the oldest (initial) frame. + +display + +stack +--> #0 Object.gcd(a#Fixnum, b#Fixnum) at line gcd.rb:6 + #1 at line gcd.rb:18 + +variables +a = 3 +b = 5 +self = main + +# frame 100 +error-begin +Adjusting would put us beyond the oldest (initial) frame. + +display + +stack +--> #0 Object.gcd(a#Fixnum, b#Fixnum) at line gcd.rb:6 + #1 at line gcd.rb:18 + +variables +a = 3 +b = 5 +self = main + +# break bogus:5 +error-begin +No source file named bogus + +Breakpoint 3 file bogus, line 5 +breakpoints +Num Enb What + 2 y at ./gcd.rb:12 + 3 y at bogus:5 + +display + +# quit! diff --git a/test/data/.svn/text-base/break_bad.cmd.svn-base b/test/data/.svn/text-base/break_bad.cmd.svn-base new file mode 100644 index 0000000..98f17fe --- /dev/null +++ b/test/data/.svn/text-base/break_bad.cmd.svn-base @@ -0,0 +1,18 @@ +# ******************************************************** +# This tests mostly invalid breakpoints. +# We have some valid ones too. +# ******************************************************** +set debuggertesting on +set callstyle last +set autoeval off +# There aren't 100 lines in gcd.rb. +break 100 +break gcd.rb:100 +# Line one isn't a valid stopping point. +# It is a comment. +break gcd.rb:1 +# This line is okay +break gcd.rb:4 +# No class Foo. +break Foo.bar +q diff --git a/test/data/.svn/text-base/break_bad.right.svn-base b/test/data/.svn/text-base/break_bad.right.svn-base new file mode 100644 index 0000000..d27f581 --- /dev/null +++ b/test/data/.svn/text-base/break_bad.right.svn-base @@ -0,0 +1,28 @@ +gcd.rb:4 +def gcd(a, b) +# # ******************************************************** +# # This tests mostly invalid breakpoints. +# # We have some valid ones too. +# # ******************************************************** +# set debuggertesting on +Currently testing the debugger is on. +# set callstyle last +Frame call-display style is last. +# set autoeval off +autoeval is off. +# # There aren't 100 lines in gcd.rb. +# break 100 +*** There are only 18 lines in file "gcd.rb". +# break gcd.rb:100 +*** There are only 18 lines in file "gcd.rb". +# # Line one isn't a valid stopping point. +# # It is a comment. +# break gcd.rb:1 +*** Line 1 is not a stopping point in file "gcd.rb". +# # This line is okay +# break gcd.rb:4 +Breakpoint 1 file gcd.rb, line 4 +# # No class Foo. +# break Foo.bar +*** Unknown class Foo. +# q diff --git a/test/data/.svn/text-base/break_loop_bug.cmd.svn-base b/test/data/.svn/text-base/break_loop_bug.cmd.svn-base new file mode 100644 index 0000000..cbcb79f --- /dev/null +++ b/test/data/.svn/text-base/break_loop_bug.cmd.svn-base @@ -0,0 +1,5 @@ +set debuggertesting on +break 2 +cont +cont +cont diff --git a/test/data/.svn/text-base/break_loop_bug.right.svn-base b/test/data/.svn/text-base/break_loop_bug.right.svn-base new file mode 100644 index 0000000..4de6124 --- /dev/null +++ b/test/data/.svn/text-base/break_loop_bug.right.svn-base @@ -0,0 +1,15 @@ +bp_loop_issue.rb:1 +1.upto(2) { +# set debuggertesting on +Currently testing the debugger is on. +# break 2 +Breakpoint 1 file ./bp_loop_issue.rb, line 2 +# cont +Breakpoint 1 at bp_loop_issue.rb:2 +bp_loop_issue.rb:2 +sleep 0.01 +# cont +Breakpoint 1 at bp_loop_issue.rb:2 +bp_loop_issue.rb:2 +sleep 0.01 +# cont diff --git a/test/data/.svn/text-base/breakpoints.cmd.svn-base b/test/data/.svn/text-base/breakpoints.cmd.svn-base new file mode 100644 index 0000000..f5d0ff0 --- /dev/null +++ b/test/data/.svn/text-base/breakpoints.cmd.svn-base @@ -0,0 +1,38 @@ +# ******************************************************** +# This tests step, next, continue, disable and +# enable. +# FIXME: break out enable/disable +# ******************************************************** +set debuggertesting on +set callstyle last +set autoeval off +break 6 +break 10 +break 11 +continue +where +break Object.gcd +info break +continue +where +info program +c 6 +info break +break foo +info break +disable 1 +info break +delete 1 +# We should see breakpoint 2 but not 1 +info break +# We should still be able to access 2 +disable 2 +disable bar +disable +# We should be able to delete 2 +delete 2 3 +info break +# Should get a message about having no breakpoints. +disable 1 +enable 1 +q! diff --git a/test/data/.svn/text-base/breakpoints.right.svn-base b/test/data/.svn/text-base/breakpoints.right.svn-base new file mode 100644 index 0000000..ef9646b --- /dev/null +++ b/test/data/.svn/text-base/breakpoints.right.svn-base @@ -0,0 +1,98 @@ +gcd.rb:4 +def gcd(a, b) +# # ******************************************************** +# # This tests step, next, continue, disable and +# # enable. +# # FIXME: break out enable/disable +# # ******************************************************** +# set debuggertesting on +Currently testing the debugger is on. +# set callstyle last +Frame call-display style is last. +# set autoeval off +autoeval is off. +# break 6 +Breakpoint 1 file ./gcd.rb, line 6 +# break 10 +Breakpoint 2 file ./gcd.rb, line 10 +# break 11 +*** Line 11 is not a stopping point in file "gcd.rb". +# continue +Breakpoint 1 at gcd.rb:6 +gcd.rb:6 +if a > b +# where +--> #0 Object.gcd(a#Fixnum, b#Fixnum) at line gcd.rb:6 + #1 at line gcd.rb:18 +# break Object.gcd +Breakpoint 3 at Object::gcd +# info break +Num Enb What + 1 y at ./gcd.rb:6 + breakpoint already hit 1 time + 2 y at ./gcd.rb:10 + 3 y at Object:gcd +# continue +Breakpoint 2 at gcd.rb:10 +gcd.rb:10 +return nil if a <= 0 +# where +--> #0 Object.gcd(a#Fixnum, b#Fixnum) at line gcd.rb:10 + #1 at line gcd.rb:18 +# info program +Program stopped. It stopped at a breakpoint. +# c 6 +Breakpoint 3 at Object:gcd +gcd.rb:4 +def gcd(a, b) +# info break +Num Enb What + 1 y at ./gcd.rb:6 + breakpoint already hit 1 time + 2 y at ./gcd.rb:10 + breakpoint already hit 1 time + 3 y at Object:gcd + breakpoint already hit 1 time +# break foo +*** Invalid breakpoint location: foo. +# info break +Num Enb What + 1 y at ./gcd.rb:6 + breakpoint already hit 1 time + 2 y at ./gcd.rb:10 + breakpoint already hit 1 time + 3 y at Object:gcd + breakpoint already hit 1 time +# disable 1 +# info break +Num Enb What + 1 n at ./gcd.rb:6 + breakpoint already hit 1 time + 2 y at ./gcd.rb:10 + breakpoint already hit 1 time + 3 y at Object:gcd + breakpoint already hit 1 time +# delete 1 +# # We should see breakpoint 2 but not 1 +# info break +Num Enb What + 2 y at ./gcd.rb:10 + breakpoint already hit 1 time + 3 y at Object:gcd + breakpoint already hit 1 time +# # We should still be able to access 2 +# disable 2 +# disable bar +Disable breakpoints argument 'bar' needs to be a number. +# disable +*** "disable" must be followed "display", "breakpoints" or breakpoint numbers. +# # We should be able to delete 2 +# delete 2 3 +# info break +No breakpoints. +# # Should get a message about having no breakpoints. +# disable 1 +*** No breakpoints have been set. +# enable 1 +*** No breakpoints have been set. +# q! diff --git a/test/data/.svn/text-base/catch.cmd.svn-base b/test/data/.svn/text-base/catch.cmd.svn-base new file mode 100644 index 0000000..0c5eefe --- /dev/null +++ b/test/data/.svn/text-base/catch.cmd.svn-base @@ -0,0 +1,17 @@ +# *************************************************** +# Test catch +# *************************************************** +set debuggertesting on +set autoeval off +set basename on +info catch +catch ZeroDivisionError off +catch ZeroDivisionError off afdasdf +catch ZeroDivisionError +info catch +catch ZeroDivisionError off +info catch +catch ZeroDivisionError +c +where +quit diff --git a/test/data/.svn/text-base/catch.right.svn-base b/test/data/.svn/text-base/catch.right.svn-base new file mode 100644 index 0000000..ec93c02 --- /dev/null +++ b/test/data/.svn/text-base/catch.right.svn-base @@ -0,0 +1,37 @@ +pm.rb:3 +def zero_div +# # *************************************************** +# # Test catch +# # *************************************************** +# set debuggertesting on +Currently testing the debugger is on. +# set autoeval off +autoeval is off. +# set basename on +basename is on. +# info catch +No exceptions set to be caught. +# catch ZeroDivisionError off +*** Catch for exception ZeroDivisionError not found. +# catch ZeroDivisionError off afdasdf +*** Unknown command: "catch ZeroDivisionError off afdasdf". Try "help". +# catch ZeroDivisionError +Catch exception ZeroDivisionError. +# info catch +ZeroDivisionError +# catch ZeroDivisionError off +Catch for exception ZeroDivisionError removed. +# info catch +No exceptions set to be caught. +# catch ZeroDivisionError +Catch exception ZeroDivisionError. +# c +Catchpoint at pm.rb:5: `divided by 0' (ZeroDivisionError) + from ../rdbg.rb:23:in `runner' + from ../rdbg.rb:32 +pm.rb:5 +1/0 +# where +--> #0 Object./ at line pm.rb:5 + #1 at line pm.rb:8 +# quit diff --git a/test/data/.svn/text-base/condition.cmd.svn-base b/test/data/.svn/text-base/condition.cmd.svn-base new file mode 100644 index 0000000..a2e8967 --- /dev/null +++ b/test/data/.svn/text-base/condition.cmd.svn-base @@ -0,0 +1,28 @@ +# ******************************************************** +# This tests primarily the condition command. +# In order to do this we need to run break, and disable +# ******************************************************** +set debuggertesting on +set callstyle last +set autoeval off +break 6 if a > b +info break +condition 1 +info break +break 12 +condition 2 1 == a +# FIXME: should be able to catch error on: +# condition 2 if 1 == a +disable 1 +continue +info break +p a +# Now test trying to enable an invalid breakpoint +break 6 if a > +info break +enable 3 +info break +condition 3 a > 5 +enable 3 +info break +quit diff --git a/test/data/.svn/text-base/condition.right.svn-base b/test/data/.svn/text-base/condition.right.svn-base new file mode 100644 index 0000000..6b9d7b3 --- /dev/null +++ b/test/data/.svn/text-base/condition.right.svn-base @@ -0,0 +1,65 @@ +gcd.rb:4 +def gcd(a, b) +# # ******************************************************** +# # This tests primarily the condition command. +# # In order to do this we need to run break, and disable +# # ******************************************************** +# set debuggertesting on +Currently testing the debugger is on. +# set callstyle last +Frame call-display style is last. +# set autoeval off +autoeval is off. +# break 6 if a > b +Breakpoint 1 file ./gcd.rb, line 6 +# info break +Num Enb What + 1 y at gcd.rb:6 if a > b +# condition 1 +# info break +Num Enb What + 1 y at gcd.rb:6 +# break 12 +Breakpoint 2 file ./gcd.rb, line 12 +# condition 2 1 == a +# # FIXME: should be able to catch error on: +# # condition 2 if 1 == a +# disable 1 +# continue +Breakpoint 2 at gcd.rb:12 +gcd.rb:12 +if a == 1 or b-a == 0 +# info break +Num Enb What + 1 n at gcd.rb:6 + 2 y at gcd.rb:12 if 1 == a + breakpoint already hit 1 time +# p a +1 +# # Now test trying to enable an invalid breakpoint +# break 6 if a > +Breakpoint 3 file ./gcd.rb, line 6 +*** Expression "a > " syntactically incorrect; breakpoint disabled. +# info break +Num Enb What + 1 n at gcd.rb:6 + 2 y at gcd.rb:12 if 1 == a + breakpoint already hit 1 time + 3 n at gcd.rb:6 if a > +# enable 3 +*** Expression "a > " syntactically incorrect; breakpoint remains disabled. +# info break +Num Enb What + 1 n at gcd.rb:6 + 2 y at gcd.rb:12 if 1 == a + breakpoint already hit 1 time + 3 n at gcd.rb:6 if a > +# condition 3 a > 5 +# enable 3 +# info break +Num Enb What + 1 n at gcd.rb:6 + 2 y at gcd.rb:12 if 1 == a + breakpoint already hit 1 time + 3 y at gcd.rb:6 if a > 5 +# quit diff --git a/test/data/.svn/text-base/ctrl.cmd.svn-base b/test/data/.svn/text-base/ctrl.cmd.svn-base new file mode 100644 index 0000000..29b35fd --- /dev/null +++ b/test/data/.svn/text-base/ctrl.cmd.svn-base @@ -0,0 +1,23 @@ +set debuggertesting on +set width 80 +help +help info +info args +info breakpoints +info display +info program +info global_variables +info line +info locals +info stack +info threads +info variables +eval 1+2 +help show +set trace off +show trace +set trace on +set annotate 0 +show annotate + + diff --git a/test/data/.svn/text-base/ctrl.right.svn-base b/test/data/.svn/text-base/ctrl.right.svn-base new file mode 100644 index 0000000..f0aeeb5 --- /dev/null +++ b/test/data/.svn/text-base/ctrl.right.svn-base @@ -0,0 +1,69 @@ +Currently testing the debugger is on. +width is 80. +Type 'help ' for help on a specific command + +Available commands: +break delete eval help interrupt p ps quit restart set source +catch edit exit info kill pp putl reload save show thread + +Generic command for showing things about the program being debugged. +-- +List of info subcommands: +-- +info args -- Argument variables of current stack frame +info breakpoints -- Status of user-settable breakpoints +info catch -- Exceptions that can be caught in the current stack frame +info display -- Expressions to display when program stops +info file -- Info about a particular file read in +info files -- File names and timestamps of files read in +info global_variables -- Global variables +info instance_variables -- Instance variables of the current stack frame +info line -- Line number and file name of current position in source file +info locals -- Local variables of the current stack frame +info program -- Execution status of the program +info stack -- Backtrace of the stack +info thread -- List info about thread NUM +info threads -- information of currently-known threads +info variables -- Local and instance variables of the current stack frame +No frame selected. +info breakpoints not available here. +info display not available here. +The program being debugged is not being run. +info global_variables not available here. +info line not available here. +info line not available here. +info stack not available here. +info threads not available here. +info variables not available here. +3 +Generic command for showing things about the debugger. + +-- +List of show subcommands: +-- +show annotate -- Show annotation level +show args -- Show argument list to give program being debugged when it is started +show autoeval -- Show if unrecognized command are evaluated +show autolist -- Show if 'list' commands is run on breakpoints +show autoirb -- Show if IRB is invoked on debugger stops +show autoreload -- Show if source code is reloaded when changed +show basename -- Show if basename used in reporting files +show callstyle -- Show paramater style used showing call frames +show commands -- Show the history of commands you typed +show forcestep -- Show if sure 'next/step' forces move to a new line +show fullpath -- Show if full file names are displayed in frames +show history -- Generic command for showing command history parameters +show keep-frame-bindings -- Save frame binding on each call +show linetrace -- Show line execution tracing +show linetrace+ -- Show if consecutive lines should be different are shown in tracing +show listsize -- Show number of source lines to list by default +show port -- Show server port +show post-mortem -- Show whether we go into post-mortem debugging on an uncaught exception +show trace -- Show if a stack trace is displayed when 'eval' raises exception +show version -- Show what version of the debugger this is +show width -- Show the number of characters the debugger thinks are in a line +Displaying stack trace is off. +Displaying stack trace is off. +Displaying stack trace is on. +Annotation level is 0 +Annotation level is 0 diff --git a/test/data/.svn/text-base/display.cmd.svn-base b/test/data/.svn/text-base/display.cmd.svn-base new file mode 100644 index 0000000..429c9f1 --- /dev/null +++ b/test/data/.svn/text-base/display.cmd.svn-base @@ -0,0 +1,24 @@ +# *************************************************** +# This tests display expressions. +# *************************************************** +set debuggertesting on +b 6 +c +# Should be no display expression yet. +info display +display a +display b +disable display b +disable display 1 +c +enable display b +enable display 1 +undisplay a +undisplay 2 +# Should have only one display expression. +info display +undisplay 1 +# Now we have no more display expressions. +info display +q + diff --git a/test/data/.svn/text-base/display.right.svn-base b/test/data/.svn/text-base/display.right.svn-base new file mode 100644 index 0000000..7a3b230 --- /dev/null +++ b/test/data/.svn/text-base/display.right.svn-base @@ -0,0 +1,44 @@ +gcd.rb:4 +def gcd(a, b) +# # *************************************************** +# # This tests display expressions. +# # *************************************************** +# set debuggertesting on +Currently testing the debugger is on. +# b 6 +Breakpoint 1 file ./gcd.rb, line 6 +# c +Breakpoint 1 at gcd.rb:6 +gcd.rb:6 +if a > b +# # Should be no display expression yet. +# info display +There are no auto-display expressions now. +# display a +1: a = 3 +# display b +2: b = 5 +# disable display b +Disable display argument 'b' needs to be a number. +# disable display 1 +# c +Breakpoint 1 at gcd.rb:6 +2: b = 3 +gcd.rb:6 +if a > b +# enable display b +Enable display argument 'b' needs to be a number. +# enable display 1 +# undisplay a +Undisplay argument 'a' needs to be a number. +# undisplay 2 +# # Should have only one display expression. +# info display +Auto-display expressions now in effect: +Num Enb Expression + 1: y a +# undisplay 1 +# # Now we have no more display expressions. +# info display +There are no auto-display expressions now. +# q diff --git a/test/data/.svn/text-base/dollar-0.right.svn-base b/test/data/.svn/text-base/dollar-0.right.svn-base new file mode 100644 index 0000000..b168a38 --- /dev/null +++ b/test/data/.svn/text-base/dollar-0.right.svn-base @@ -0,0 +1,2 @@ +./dollar-0.rb +./dollar-0.rb diff --git a/test/data/.svn/text-base/dollar-0a.right.svn-base b/test/data/.svn/text-base/dollar-0a.right.svn-base new file mode 100644 index 0000000..b168a38 --- /dev/null +++ b/test/data/.svn/text-base/dollar-0a.right.svn-base @@ -0,0 +1,2 @@ +./dollar-0.rb +./dollar-0.rb diff --git a/test/data/.svn/text-base/dollar-0b.right.svn-base b/test/data/.svn/text-base/dollar-0b.right.svn-base new file mode 100644 index 0000000..538a360 --- /dev/null +++ b/test/data/.svn/text-base/dollar-0b.right.svn-base @@ -0,0 +1,2 @@ +../test/dollar-0.rb +../test/dollar-0.rb diff --git a/test/data/.svn/text-base/edit.cmd.svn-base b/test/data/.svn/text-base/edit.cmd.svn-base new file mode 100644 index 0000000..ec4a350 --- /dev/null +++ b/test/data/.svn/text-base/edit.cmd.svn-base @@ -0,0 +1,12 @@ +# ******************************************************** +# This tests the edit command +# ******************************************************** +set debuggertesting on +# Edit using current line position. +edit +edit gcd.rb:5 +# File should not exist +edit foo +# Add space to the end of 'edit' +edit +quit diff --git a/test/data/.svn/text-base/edit.right.svn-base b/test/data/.svn/text-base/edit.right.svn-base new file mode 100644 index 0000000..66523c1 --- /dev/null +++ b/test/data/.svn/text-base/edit.right.svn-base @@ -0,0 +1,19 @@ +gcd.rb:4 +def gcd(a, b) +# # ******************************************************** +# # This tests the edit command +# # ******************************************************** +# set debuggertesting on +Currently testing the debugger is on. +# # Edit using current line position. +# edit +FAKE-EDITOR +4 ./gcd.rb +# edit gcd.rb:5 +FAKE-EDITOR +5 gcd.rb +# # File should not exist +# edit foo +*** Invalid file/line number specification: foo +# # Add space to the end of 'edit' +# edit +FAKE-EDITOR +4 ./gcd.rb +# quit diff --git a/test/data/.svn/text-base/emacs_basic.cmd.svn-base b/test/data/.svn/text-base/emacs_basic.cmd.svn-base new file mode 100644 index 0000000..315eb2a --- /dev/null +++ b/test/data/.svn/text-base/emacs_basic.cmd.svn-base @@ -0,0 +1,43 @@ +# ******************************************************** +# This tests step, next, finish, continue, disable and +# enable. +# FIXME: break out enable/disable +# ******************************************************** +set debuggertesting on +set callstyle last +set autoeval off +break 6 +break 10 +continue +where +break Foo.bar +break Object.gcd +info break +continue +where +info program +c 10 +info break +break foo +info break +disable 1 +info break +enable breakpoint 1 +enable br 10 +delete 1 +# We should see breakpoint 2 but not 1 +info break +# We should still be able to access 2 +disable 2 +enable +enable foo +disable bar +disable +# We should be able to delete 2 +delete 2 3 +info break +# Should get a message about having no breakpoints. +disable 1 +enable 1 +# finish +quit diff --git a/test/data/.svn/text-base/emacs_basic.right.svn-base b/test/data/.svn/text-base/emacs_basic.right.svn-base new file mode 100644 index 0000000..6d80e2a --- /dev/null +++ b/test/data/.svn/text-base/emacs_basic.right.svn-base @@ -0,0 +1,106 @@ +gcd.rb:4 +def gcd(a, b) +# # ******************************************************** +# # This tests step, next, finish, continue, disable and +# # enable. +# # FIXME: break out enable/disable +# # ******************************************************** +# set debuggertesting on +Currently testing the debugger is on. +# set callstyle last +Frame call-display style is last. +# set autoeval off +autoeval is off. +# break 6 +Breakpoint 1 file ./gcd.rb, line 6 +# break 10 +Breakpoint 2 file ./gcd.rb, line 10 +# continue +Breakpoint 1 at gcd.rb:6 +gcd.rb:6 +if a > b +# where +--> #0 Object.gcd(a#Fixnum, b#Fixnum) at line gcd.rb:6 + #1 at line gcd.rb:18 +# break Foo.bar +*** Unknown class Foo. +# break Object.gcd +Breakpoint 3 at Object::gcd +# info break +Num Enb What + 1 y at ./gcd.rb:6 + breakpoint already hit 1 time + 2 y at ./gcd.rb:10 + 3 y at Object:gcd +# continue +Breakpoint 2 at gcd.rb:10 +gcd.rb:10 +return nil if a <= 0 +# where +--> #0 Object.gcd(a#Fixnum, b#Fixnum) at line gcd.rb:10 + #1 at line gcd.rb:18 +# info program +Program stopped. It stopped at a breakpoint. +# c 10 +Breakpoint 3 at Object:gcd +gcd.rb:4 +def gcd(a, b) +# info break +Num Enb What + 1 y at ./gcd.rb:6 + breakpoint already hit 1 time + 2 y at ./gcd.rb:10 + breakpoint already hit 1 time + 3 y at Object:gcd + breakpoint already hit 1 time +# break foo +*** Invalid breakpoint location: foo. +# info break +Num Enb What + 1 y at ./gcd.rb:6 + breakpoint already hit 1 time + 2 y at ./gcd.rb:10 + breakpoint already hit 1 time + 3 y at Object:gcd + breakpoint already hit 1 time +# disable 1 +# info break +Num Enb What + 1 n at ./gcd.rb:6 + breakpoint already hit 1 time + 2 y at ./gcd.rb:10 + breakpoint already hit 1 time + 3 y at Object:gcd + breakpoint already hit 1 time +# enable breakpoint 1 +# enable br 10 +Enable breakpoints argument '10' needs to at most 3. +# delete 1 +# # We should see breakpoint 2 but not 1 +# info break +Num Enb What + 2 y at ./gcd.rb:10 + breakpoint already hit 1 time + 3 y at Object:gcd + breakpoint already hit 1 time +# # We should still be able to access 2 +# disable 2 +# enable +*** "enable" must be followed "display", "breakpoints" or breakpoint numbers. +# enable foo +Enable breakpoints argument 'foo' needs to be a number. +# disable bar +Disable breakpoints argument 'bar' needs to be a number. +# disable +*** "disable" must be followed "display", "breakpoints" or breakpoint numbers. +# # We should be able to delete 2 +# delete 2 3 +# info break +No breakpoints. +# # Should get a message about having no breakpoints. +# disable 1 +*** No breakpoints have been set. +# enable 1 +*** No breakpoints have been set. +# # finish +# quit diff --git a/test/data/.svn/text-base/enable.cmd.svn-base b/test/data/.svn/text-base/enable.cmd.svn-base new file mode 100644 index 0000000..0067f29 --- /dev/null +++ b/test/data/.svn/text-base/enable.cmd.svn-base @@ -0,0 +1,20 @@ +# ******************************************************** +# This tests the enable command. +# ******************************************************** +set debuggertesting on +set callstyle last +set autoeval off +break Object.gcd +# Should have a breakpoint 1 +enable br 1 +# Get help on enable +help enable +# Get help on just enable break +help enable break +# Plain enable should work +enable +# An invalid enable command +enable foo +quit + + diff --git a/test/data/.svn/text-base/enable.right.svn-base b/test/data/.svn/text-base/enable.right.svn-base new file mode 100644 index 0000000..ad97ab0 --- /dev/null +++ b/test/data/.svn/text-base/enable.right.svn-base @@ -0,0 +1,36 @@ +gcd.rb:4 +def gcd(a, b) +# # ******************************************************** +# # This tests the enable command. +# # ******************************************************** +# set debuggertesting on +Currently testing the debugger is on. +# set callstyle last +Frame call-display style is last. +# set autoeval off +autoeval is off. +# break Object.gcd +Breakpoint 1 at Object::gcd +# # Should have a breakpoint 1 +# enable br 1 +# # Get help on enable +# help enable +Enable some things. +This is used to cancel the effect of the "disable" command. +-- +List of enable subcommands: +-- +enable breakpoints -- Enable specified breakpoints +enable display -- Enable some expressions to be displayed when program stops +# # Get help on just enable break +# help enable break +Enable specified breakpoints. +Give breakpoint numbers (separated by spaces) as arguments. +This is used to cancel the effect of the "disable" command. +# # Plain enable should work +# enable +*** "enable" must be followed "display", "breakpoints" or breakpoint numbers. +# # An invalid enable command +# enable foo +Enable breakpoints argument 'foo' needs to be a number. +# quit diff --git a/test/data/.svn/text-base/finish.cmd.svn-base b/test/data/.svn/text-base/finish.cmd.svn-base new file mode 100644 index 0000000..e10d12b --- /dev/null +++ b/test/data/.svn/text-base/finish.cmd.svn-base @@ -0,0 +1,16 @@ +# ******************************************************** +# This tests finish. +# ******************************************************** +set debuggertesting on +set callstyle last +set autoeval off +break 6 +continue +continue +continue +where +finish 0 +where +p a +p b +finish diff --git a/test/data/.svn/text-base/finish.right.svn-base b/test/data/.svn/text-base/finish.right.svn-base new file mode 100644 index 0000000..9979fb0 --- /dev/null +++ b/test/data/.svn/text-base/finish.right.svn-base @@ -0,0 +1,31 @@ +gcd.rb:4 +def gcd(a, b) +# # ******************************************************** +# # This tests finish. +# # ******************************************************** +# set debuggertesting on +Currently testing the debugger is on. +# set callstyle last +Frame call-display style is last. +# set autoeval off +autoeval is off. +# break 6 +Breakpoint 1 file ./gcd.rb, line 6 +# continue +Breakpoint 1 at gcd.rb:6 +gcd.rb:6 +if a > b +# continue +Breakpoint 1 at gcd.rb:6 +gcd.rb:6 +if a > b +# continue +Breakpoint 1 at gcd.rb:6 +gcd.rb:6 +if a > b +# where +--> #0 Object.gcd(a#Fixnum, b#Fixnum) at line gcd.rb:6 + #1 Object.-(a#Fixnum, b#Fixnum) at line gcd.rb:15 + #2 Object.-(a#Fixnum, b#Fixnum) at line gcd.rb:15 + #3 at line gcd.rb:18 +# finish 0 diff --git a/test/data/.svn/text-base/frame.cmd.svn-base b/test/data/.svn/text-base/frame.cmd.svn-base new file mode 100644 index 0000000..579bc3f --- /dev/null +++ b/test/data/.svn/text-base/frame.cmd.svn-base @@ -0,0 +1,26 @@ +# *************************************************** +# This tests step, next, finish and continue +# *************************************************** +set debuggertesting on +set callstyle last +# Invalid line number in continue command +continue 3 +# This time, for sure! +continue 6 +where +up +where +down +where +frame +where +frame -1 +where +up 2 +where +down 2 +where +frame 0 thread 3 +frame 0 thread 1 +# finish +quit diff --git a/test/data/.svn/text-base/frame.right.svn-base b/test/data/.svn/text-base/frame.right.svn-base new file mode 100644 index 0000000..22b24e6 --- /dev/null +++ b/test/data/.svn/text-base/frame.right.svn-base @@ -0,0 +1,55 @@ +gcd.rb:4 +def gcd(a, b) +# # *************************************************** +# # This tests step, next, finish and continue +# # *************************************************** +# set debuggertesting on +Currently testing the debugger is on. +# set callstyle last +Frame call-display style is last. +# # Invalid line number in continue command +# continue 3 +*** Line 3 is not a stopping point in file "gcd.rb". +# # This time, for sure! +# continue 6 +gcd.rb:6 +if a > b +# where +--> #0 Object.gcd(a#Fixnum, b#Fixnum) at line gcd.rb:6 + #1 at line gcd.rb:18 +# up +#1 at line gcd.rb:18 +# where + #0 Object.gcd(a#Fixnum, b#Fixnum) at line gcd.rb:6 +--> #1 at line gcd.rb:18 +# down +#0 Object.gcd(a#Fixnum, b#Fixnum) at line gcd.rb:6 +# where +--> #0 Object.gcd(a#Fixnum, b#Fixnum) at line gcd.rb:6 + #1 at line gcd.rb:18 +# frame +#0 Object.gcd(a#Fixnum, b#Fixnum) at line gcd.rb:6 +# where +--> #0 Object.gcd(a#Fixnum, b#Fixnum) at line gcd.rb:6 + #1 at line gcd.rb:18 +# frame -1 +#1 at line gcd.rb:18 +# where + #0 Object.gcd(a#Fixnum, b#Fixnum) at line gcd.rb:6 +--> #1 at line gcd.rb:18 +# up 2 +*** Adjusting would put us beyond the oldest (initial) frame. +# where + #0 Object.gcd(a#Fixnum, b#Fixnum) at line gcd.rb:6 +--> #1 at line gcd.rb:18 +# down 2 +*** Adjusting would put us beyond the newest (innermost) frame. +# where + #0 Object.gcd(a#Fixnum, b#Fixnum) at line gcd.rb:6 +--> #1 at line gcd.rb:18 +# frame 0 thread 3 +*** Thread 3 doesn't exist. +# frame 0 thread 1 +#0 Object.gcd(a#Fixnum, b#Fixnum) at line gcd.rb:6 +# # finish +# quit diff --git a/test/data/.svn/text-base/help.cmd.svn-base b/test/data/.svn/text-base/help.cmd.svn-base new file mode 100644 index 0000000..4b4dc58 --- /dev/null +++ b/test/data/.svn/text-base/help.cmd.svn-base @@ -0,0 +1,20 @@ +# $Id: setshow.cmd 298 2007-08-28 10:07:35Z rockyb $ +# This tests the functioning of some set/show debugger commands +set debuggertesting on +set autoeval off +set width 80 +### ******************************* +### *** help commands *** +### ******************************* +help foo +help set listsize +help show anno +help show foo +help info file +help info file all +help info file br +help info files + +# FIXME - the below should work +# help +# help step diff --git a/test/data/.svn/text-base/help.right.svn-base b/test/data/.svn/text-base/help.right.svn-base new file mode 100644 index 0000000..52b52ec --- /dev/null +++ b/test/data/.svn/text-base/help.right.svn-base @@ -0,0 +1,21 @@ +Currently testing the debugger is on. +autoeval is off. +width is 80. +Undefined command: "foo". Try "help". +Set number of source lines to list by default. +Show annotation level. +0 == normal; 2 == output annotated suitably for use by programs that control +ruby-debug. +Invalid 'show' subcommand 'foo'. +Info about a particular file read in. + +After the file name is supplied, you can list file attributes that +you wish to see. + +Attributes include: "all", "basic", "breakpoint", "lines", "mtime", "path" +and "sha1". +Info about a particular file read in. +All file information available - breakpoints, lines, mtime, path, and sha1. +Info about a particular file read in. +Show trace line numbers. +File names and timestamps of files read in. diff --git a/test/data/.svn/text-base/history.right.svn-base b/test/data/.svn/text-base/history.right.svn-base new file mode 100644 index 0000000..be1e37f --- /dev/null +++ b/test/data/.svn/text-base/history.right.svn-base @@ -0,0 +1,7 @@ +list +step +show args +show commands +set history save on +show history +quit unconditionally diff --git a/test/data/.svn/text-base/info-thread.cmd.svn-base b/test/data/.svn/text-base/info-thread.cmd.svn-base new file mode 100644 index 0000000..c07064b --- /dev/null +++ b/test/data/.svn/text-base/info-thread.cmd.svn-base @@ -0,0 +1,13 @@ +# ******************************************************** +# This tests basic info thread commands +set debuggertesting on +set callstyle last +set autoeval off +info threads terse +info threads ver +info thread 1 t +info threads +info thread +help info thread +help info threads +q diff --git a/test/data/.svn/text-base/info-thread.right.svn-base b/test/data/.svn/text-base/info-thread.right.svn-base new file mode 100644 index 0000000..fd885bb --- /dev/null +++ b/test/data/.svn/text-base/info-thread.right.svn-base @@ -0,0 +1,37 @@ +gcd.rb:4 +def gcd(a, b) +# # ******************************************************** +# # This tests basic info thread commands +# set debuggertesting on +Currently testing the debugger is on. +# set callstyle last +Frame call-display style is last. +# set autoeval off +autoeval is off. +# info threads terse ++ 1 # ./gcd.rb:4 +# info threads ver ++ 1 # + #0 at line gcd.rb:4 +# info thread 1 t ++ 1 # ./gcd.rb:4 +# info threads ++ 1 # ./gcd.rb:4 +# info thread ++ 1 # ./gcd.rb:4 +# help info thread +List info about thread NUM. + +If no thread number is given, we list info for all threads. 'terse' and 'verbose' +options are possible. If terse, just give summary thread name information. See +"help info threads" for more detail about this summary information. + +If 'verbose' appended to the end of the command, then the entire +stack trace is given for each thread. +# help info threads +information of currently-known threads. + +This information includes whether the thread is current (+), if it is +suspended ($), or ignored (!). The thread number and the top stack +item. If 'verbose' is given then the entire stack frame is shown. +# q diff --git a/test/data/.svn/text-base/info-var-bug2.cmd.svn-base b/test/data/.svn/text-base/info-var-bug2.cmd.svn-base new file mode 100644 index 0000000..a8bf887 --- /dev/null +++ b/test/data/.svn/text-base/info-var-bug2.cmd.svn-base @@ -0,0 +1,5 @@ +step +info variables +quit + + diff --git a/test/data/.svn/text-base/info-var-bug2.right.svn-base b/test/data/.svn/text-base/info-var-bug2.right.svn-base new file mode 100644 index 0000000..1b8cdc6 --- /dev/null +++ b/test/data/.svn/text-base/info-var-bug2.right.svn-base @@ -0,0 +1,10 @@ +info-var-bug2.rb:1 +s = '<%= PRODUCT[:name] %>' +# step +info-var-bug2.rb:2 +y = 0 +# info variables +s = "<%= PRODUCT[:name] %>" +self = main +y = nil +# quit diff --git a/test/data/.svn/text-base/info-var.cmd.svn-base b/test/data/.svn/text-base/info-var.cmd.svn-base new file mode 100644 index 0000000..de35cdb --- /dev/null +++ b/test/data/.svn/text-base/info-var.cmd.svn-base @@ -0,0 +1,23 @@ +# *************************************************** +# Test handling of info variables when we have +# redefined inspect or to_s which give an error. +# *************************************************** +set debuggertesting on +# Go to where we have a bad "inspect" of a local variable +continue 36 +info variables +# Go to where we have a bad "inspect" and "to_s" of a local variable +continue 40 +info variables +break 31 +# The first time through, we can do inspect. +continue +info locals +# Now go to where we have a bad "inspect" of an class variable +continue +info locals +info variables +# Now go to where we have a bad "inspect" and "to_s" of an class variable +continue +info locals +quit diff --git a/test/data/.svn/text-base/info-var.right.svn-base b/test/data/.svn/text-base/info-var.right.svn-base new file mode 100644 index 0000000..72c97b3 --- /dev/null +++ b/test/data/.svn/text-base/info-var.right.svn-base @@ -0,0 +1,52 @@ +info-var-bug.rb:1 +class Lousy_inspect +# # *************************************************** +# # Test handling of info variables when we have +# # redefined inspect or to_s which give an error. +# # *************************************************** +# set debuggertesting on +Currently testing the debugger is on. +# # Go to where we have a bad "inspect" of a local variable +# continue 36 +info-var-bug.rb:36 +return x +# info variables +self = main +x = # +# # Go to where we have a bad "inspect" and "to_s" of a local variable +# continue 40 +info-var-bug.rb:40 +return x +# info variables +self = main +x = *Error in evaluation* +# break 31 +Breakpoint 1 file ./info-var-bug.rb, line 31 +# # The first time through, we can do inspect. +# continue +Breakpoint 1 at info-var-bug.rb:31 +info-var-bug.rb:31 +@b = 5 +# info locals +a = 10 +# # Now go to where we have a bad "inspect" of an class variable +# continue +Breakpoint 1 at info-var-bug.rb:31 +info-var-bug.rb:31 +@b = 5 +# info locals +a = # +# info variables +a = # +self = # +@a = # +@@Const = "A constant" +@@var = "a class variable" +# # Now go to where we have a bad "inspect" and "to_s" of an class variable +# continue +Breakpoint 1 at info-var-bug.rb:31 +info-var-bug.rb:31 +@b = 5 +# info locals +*Error in evaluation* +# quit diff --git a/test/data/.svn/text-base/info.cmd.svn-base b/test/data/.svn/text-base/info.cmd.svn-base new file mode 100644 index 0000000..d0c2c4a --- /dev/null +++ b/test/data/.svn/text-base/info.cmd.svn-base @@ -0,0 +1,21 @@ +# *************************************************** +# This tests info command handling +# *************************************************** +set debuggertesting on +set callstyle last +help info +info args +info line +info locals +info stack +info display +help info break +help info display +break 10 +break 12 +info break 10 +info break 1 +info break 1 2 +info break +info file ./gcd.rb break +quit diff --git a/test/data/.svn/text-base/info.right.svn-base b/test/data/.svn/text-base/info.right.svn-base new file mode 100644 index 0000000..67ff19e --- /dev/null +++ b/test/data/.svn/text-base/info.right.svn-base @@ -0,0 +1,65 @@ +gcd.rb:4 +def gcd(a, b) +# # *************************************************** +# # This tests info command handling +# # *************************************************** +# set debuggertesting on +Currently testing the debugger is on. +# set callstyle last +Frame call-display style is last. +# help info +Generic command for showing things about the program being debugged. +-- +List of info subcommands: +-- +info args -- Argument variables of current stack frame +info breakpoints -- Status of user-settable breakpoints +info catch -- Exceptions that can be caught in the current stack frame +info display -- Expressions to display when program stops +info file -- Info about a particular file read in +info files -- File names and timestamps of files read in +info global_variables -- Global variables +info instance_variables -- Instance variables of the current stack frame +info line -- Line number and file name of current position in source file +info locals -- Local variables of the current stack frame +info program -- Execution status of the program +info stack -- Backtrace of the stack +info thread -- List info about thread NUM +info threads -- information of currently-known threads +info variables -- Local and instance variables of the current stack frame +# info args +# info line +Line 4 of "./gcd.rb" +# info locals +# info stack +--> #0 at line gcd.rb:4 +# info display +There are no auto-display expressions now. +# help info break +Status of user-settable breakpoints. +Without argument, list info about all breakpoints. With an +integer argument, list info on that breakpoint. +# help info display +Expressions to display when program stops. +# break 10 +Breakpoint 1 file ./gcd.rb, line 10 +# break 12 +Breakpoint 2 file ./gcd.rb, line 12 +# info break 10 +*** No breakpoints found among list given. +# info break 1 +Num Enb What + 1 y at ./gcd.rb:10 +# info break 1 2 +Num Enb What + 1 y at ./gcd.rb:10 + 2 y at ./gcd.rb:12 +# info break +Num Enb What + 1 y at ./gcd.rb:10 + 2 y at ./gcd.rb:12 +# info file ./gcd.rb break +File ./gcd.rb + breakpoint line numbers: +4 6 6 7 10 10 12 12 13 15 18 +# quit diff --git a/test/data/.svn/text-base/linetrace.cmd.svn-base b/test/data/.svn/text-base/linetrace.cmd.svn-base new file mode 100644 index 0000000..d2424e9 --- /dev/null +++ b/test/data/.svn/text-base/linetrace.cmd.svn-base @@ -0,0 +1,6 @@ +# ******************************************************** +# This tests the 'linetrace' command. +# ******************************************************** +set basename on +set linetrace on +continue diff --git a/test/data/.svn/text-base/linetrace.right.svn-base b/test/data/.svn/text-base/linetrace.right.svn-base new file mode 100644 index 0000000..7aea2cf --- /dev/null +++ b/test/data/.svn/text-base/linetrace.right.svn-base @@ -0,0 +1,32 @@ +gcd.rb:4 +def gcd(a, b) +# # ******************************************************** +# # This tests the 'linetrace' command. +# # ******************************************************** +# set basename on +basename is on. +# set linetrace on +line tracing is on. +# continue +Tracing(1):gcd.rb:18 gcd(3,5) +Tracing(1):gcd.rb:6 if a > b +Tracing(1):gcd.rb:6 if a > b +Tracing(1):gcd.rb:10 return nil if a <= 0 +Tracing(1):gcd.rb:10 return nil if a <= 0 +Tracing(1):gcd.rb:12 if a == 1 or b-a == 0 +Tracing(1):gcd.rb:12 if a == 1 or b-a == 0 +Tracing(1):gcd.rb:15 return gcd(b-a, a) +Tracing(1):gcd.rb:6 if a > b +Tracing(1):gcd.rb:6 if a > b +Tracing(1):gcd.rb:10 return nil if a <= 0 +Tracing(1):gcd.rb:10 return nil if a <= 0 +Tracing(1):gcd.rb:12 if a == 1 or b-a == 0 +Tracing(1):gcd.rb:12 if a == 1 or b-a == 0 +Tracing(1):gcd.rb:15 return gcd(b-a, a) +Tracing(1):gcd.rb:6 if a > b +Tracing(1):gcd.rb:6 if a > b +Tracing(1):gcd.rb:10 return nil if a <= 0 +Tracing(1):gcd.rb:10 return nil if a <= 0 +Tracing(1):gcd.rb:12 if a == 1 or b-a == 0 +Tracing(1):gcd.rb:12 if a == 1 or b-a == 0 +Tracing(1):gcd.rb:13 return a diff --git a/test/data/.svn/text-base/linetracep.cmd.svn-base b/test/data/.svn/text-base/linetracep.cmd.svn-base new file mode 100644 index 0000000..1d90ec0 --- /dev/null +++ b/test/data/.svn/text-base/linetracep.cmd.svn-base @@ -0,0 +1,7 @@ +# ******************************************************** +# This tests the 'linetrace+' command. +# ******************************************************** +set basename on +set linetrace+ on +set linetrace on +continue diff --git a/test/data/.svn/text-base/linetracep.right.svn-base b/test/data/.svn/text-base/linetracep.right.svn-base new file mode 100644 index 0000000..d3a387e --- /dev/null +++ b/test/data/.svn/text-base/linetracep.right.svn-base @@ -0,0 +1,25 @@ +gcd.rb:4 +def gcd(a, b) +# # ******************************************************** +# # This tests the 'linetrace+' command. +# # ******************************************************** +# set basename on +basename is on. +# set linetrace+ on +line tracing style is different consecutive lines. +# set linetrace on +line tracing is on. +# continue +Tracing(1):gcd.rb:18 gcd(3,5) +Tracing(1):gcd.rb:6 if a > b +Tracing(1):gcd.rb:10 return nil if a <= 0 +Tracing(1):gcd.rb:12 if a == 1 or b-a == 0 +Tracing(1):gcd.rb:15 return gcd(b-a, a) +Tracing(1):gcd.rb:6 if a > b +Tracing(1):gcd.rb:10 return nil if a <= 0 +Tracing(1):gcd.rb:12 if a == 1 or b-a == 0 +Tracing(1):gcd.rb:15 return gcd(b-a, a) +Tracing(1):gcd.rb:6 if a > b +Tracing(1):gcd.rb:10 return nil if a <= 0 +Tracing(1):gcd.rb:12 if a == 1 or b-a == 0 +Tracing(1):gcd.rb:13 return a diff --git a/test/data/.svn/text-base/list.cmd.svn-base b/test/data/.svn/text-base/list.cmd.svn-base new file mode 100644 index 0000000..a4efa3a --- /dev/null +++ b/test/data/.svn/text-base/list.cmd.svn-base @@ -0,0 +1,19 @@ +# ******************************************************** +# This tests the 'list' command. +# ******************************************************** +set basename on +list +list +list +list +list - +list - +list - +list - +list 1 +list 20 +set listsize 5 +list 5 +list = +list 3-4 + diff --git a/test/data/.svn/text-base/list.right.svn-base b/test/data/.svn/text-base/list.right.svn-base new file mode 100644 index 0000000..cc12084 --- /dev/null +++ b/test/data/.svn/text-base/list.right.svn-base @@ -0,0 +1,127 @@ +gcd.rb:4 +def gcd(a, b) +# # ******************************************************** +# # This tests the 'list' command. +# # ******************************************************** +# set basename on +basename is on. +# list +[-1, 8] in ./gcd.rb + 1 #!/usr/bin/env ruby + 2 + 3 # GCD. We assume positive numbers +=> 4 def gcd(a, b) + 5 # Make: a <= b + 6 if a > b + 7 a, b = [b, a] + 8 end +# list +[9, 18] in ./gcd.rb + 9 + 10 return nil if a <= 0 + 11 + 12 if a == 1 or b-a == 0 + 13 return a + 14 end + 15 return gcd(b-a, a) + 16 end + 17 + 18 gcd(3,5) +# list +[9, 18] in ./gcd.rb + 9 + 10 return nil if a <= 0 + 11 + 12 if a == 1 or b-a == 0 + 13 return a + 14 end + 15 return gcd(b-a, a) + 16 end + 17 + 18 gcd(3,5) +# list +[9, 18] in ./gcd.rb + 9 + 10 return nil if a <= 0 + 11 + 12 if a == 1 or b-a == 0 + 13 return a + 14 end + 15 return gcd(b-a, a) + 16 end + 17 + 18 gcd(3,5) +# list - +[-1, 8] in ./gcd.rb + 1 #!/usr/bin/env ruby + 2 + 3 # GCD. We assume positive numbers +=> 4 def gcd(a, b) + 5 # Make: a <= b + 6 if a > b + 7 a, b = [b, a] + 8 end +# list - +[-1, 8] in ./gcd.rb + 1 #!/usr/bin/env ruby + 2 + 3 # GCD. We assume positive numbers +=> 4 def gcd(a, b) + 5 # Make: a <= b + 6 if a > b + 7 a, b = [b, a] + 8 end +# list - +[-1, 8] in ./gcd.rb + 1 #!/usr/bin/env ruby + 2 + 3 # GCD. We assume positive numbers +=> 4 def gcd(a, b) + 5 # Make: a <= b + 6 if a > b + 7 a, b = [b, a] + 8 end +# list - +[-1, 8] in ./gcd.rb + 1 #!/usr/bin/env ruby + 2 + 3 # GCD. We assume positive numbers +=> 4 def gcd(a, b) + 5 # Make: a <= b + 6 if a > b + 7 a, b = [b, a] + 8 end +# list 1 +[-4, 5] in ./gcd.rb + 1 #!/usr/bin/env ruby + 2 + 3 # GCD. We assume positive numbers +=> 4 def gcd(a, b) + 5 # Make: a <= b +# list 20 +[15, 24] in ./gcd.rb + 15 return gcd(b-a, a) + 16 end + 17 + 18 gcd(3,5) +# set listsize 5 +Number of source lines to list by default is 5. +# list 5 +[3, 7] in ./gcd.rb + 3 # GCD. We assume positive numbers +=> 4 def gcd(a, b) + 5 # Make: a <= b + 6 if a > b + 7 a, b = [b, a] +# list = +[2, 6] in ./gcd.rb + 2 + 3 # GCD. We assume positive numbers +=> 4 def gcd(a, b) + 5 # Make: a <= b + 6 if a > b +# list 3-4 +[3, 4] in ./gcd.rb + 3 # GCD. We assume positive numbers +=> 4 def gcd(a, b) +# diff --git a/test/data/.svn/text-base/method.cmd.svn-base b/test/data/.svn/text-base/method.cmd.svn-base new file mode 100644 index 0000000..2e9feb8 --- /dev/null +++ b/test/data/.svn/text-base/method.cmd.svn-base @@ -0,0 +1,10 @@ +# ******************************************************** +# This tests the 'method' command +# ******************************************************** +set debuggertesting on +set autoeval off +b 11 +c +method Mine +m iv me +quit diff --git a/test/data/.svn/text-base/method.right.svn-base b/test/data/.svn/text-base/method.right.svn-base new file mode 100644 index 0000000..343bab8 --- /dev/null +++ b/test/data/.svn/text-base/method.right.svn-base @@ -0,0 +1,21 @@ +classes.rb:1 +class Mine +# # ******************************************************** +# # This tests the 'method' command +# # ******************************************************** +# set debuggertesting on +Currently testing the debugger is on. +# set autoeval off +autoeval is off. +# b 11 +Breakpoint 1 file ./classes.rb, line 11 +# c +Breakpoint 1 at classes.rb:11 +classes.rb:11 +metoo = Mine(new) +# method Mine +mymethod + +# m iv me +@myvar = "init" +# quit diff --git a/test/data/.svn/text-base/methodsig.cmd.svn-base b/test/data/.svn/text-base/methodsig.cmd.svn-base new file mode 100644 index 0000000..e3445a8 --- /dev/null +++ b/test/data/.svn/text-base/methodsig.cmd.svn-base @@ -0,0 +1,10 @@ +# ******************************************************** +# This tests the 'method' command +# ******************************************************** +set debuggertesting on +set autoeval off +b 3 +c +method sig initialize +method sig mymethod +quit diff --git a/test/data/.svn/text-base/methodsig.right.svn-base b/test/data/.svn/text-base/methodsig.right.svn-base new file mode 100644 index 0000000..5553b57 --- /dev/null +++ b/test/data/.svn/text-base/methodsig.right.svn-base @@ -0,0 +1,20 @@ +classes.rb:1 +class Mine +# # ******************************************************** +# # This tests the 'method' command +# # ******************************************************** +# set debuggertesting on +Currently testing the debugger is on. +# set autoeval off +autoeval is off. +# b 3 +Breakpoint 1 file ./classes.rb, line 3 +# c +Breakpoint 1 at classes.rb:3 +classes.rb:3 +@myvar = 'init' +# method sig initialize +Mine#initialize() +# method sig mymethod +Mine#mymethod(a, b=5, &block) +# quit diff --git a/test/data/.svn/text-base/noquit.right.svn-base b/test/data/.svn/text-base/noquit.right.svn-base new file mode 100644 index 0000000..b56a50c --- /dev/null +++ b/test/data/.svn/text-base/noquit.right.svn-base @@ -0,0 +1 @@ +The program has finished and will be restarted. diff --git a/test/data/.svn/text-base/output.cmd.svn-base b/test/data/.svn/text-base/output.cmd.svn-base new file mode 100644 index 0000000..1c17bde --- /dev/null +++ b/test/data/.svn/text-base/output.cmd.svn-base @@ -0,0 +1,6 @@ +# ******************************************************** +# This tests the "starting" annotation +# ******************************************************** +step +step +quit diff --git a/test/data/.svn/text-base/output.right.svn-base b/test/data/.svn/text-base/output.right.svn-base new file mode 100644 index 0000000..b70dbeb --- /dev/null +++ b/test/data/.svn/text-base/output.right.svn-base @@ -0,0 +1,31 @@ +starting +stopped +breakpoints +No breakpoints. + +stack +--> #0 at line output.rb:1 + +variables +self = main + +source output.rb:1 +puts "one" +# # ******************************************************** +# # This tests the "starting" annotation +# # ******************************************************** +# step +starting +one +stopped +stack +--> #0 at line output.rb:2 + +variables +self = main + +source output.rb:2 +puts "two" +# step +starting +two diff --git a/test/data/.svn/text-base/pm-bug.cmd.svn-base b/test/data/.svn/text-base/pm-bug.cmd.svn-base new file mode 100644 index 0000000..45a38a0 --- /dev/null +++ b/test/data/.svn/text-base/pm-bug.cmd.svn-base @@ -0,0 +1,7 @@ +# ******************************************************** +# This tests the edit command +# ******************************************************** +set debuggertesting on +# Tracker #22118 +i v +quit diff --git a/test/data/.svn/text-base/pm-bug.right.svn-base b/test/data/.svn/text-base/pm-bug.right.svn-base new file mode 100644 index 0000000..9ce6385 --- /dev/null +++ b/test/data/.svn/text-base/pm-bug.right.svn-base @@ -0,0 +1,12 @@ +pm-bug.rb:1 +a = 1 +# # ******************************************************** +# # This tests the edit command +# # ******************************************************** +# set debuggertesting on +Currently testing the debugger is on. +# # Tracker #22118 +# i v +a = nil +self = main +# quit diff --git a/test/data/.svn/text-base/post-mortem-next.cmd.svn-base b/test/data/.svn/text-base/post-mortem-next.cmd.svn-base new file mode 100644 index 0000000..09663c9 --- /dev/null +++ b/test/data/.svn/text-base/post-mortem-next.cmd.svn-base @@ -0,0 +1,8 @@ +# ****************************************************** +# This tests running "next" over code that post-mortems +# ****************************************************** +set debuggertesting on +next 2 +next +quit + diff --git a/test/data/.svn/text-base/post-mortem-next.right.svn-base b/test/data/.svn/text-base/post-mortem-next.right.svn-base new file mode 100644 index 0000000..0ecb616 --- /dev/null +++ b/test/data/.svn/text-base/post-mortem-next.right.svn-base @@ -0,0 +1,14 @@ +pm.rb:3 +def zero_div +# # ****************************************************** +# # This tests running "next" over code that post-mortems +# # ****************************************************** +# set debuggertesting on +Currently testing the debugger is on. +# next 2 +pm.rb:8 +zero_div +# next +pm.rb:5 +1/0 +# quit diff --git a/test/data/.svn/text-base/post-mortem-osx.right.svn-base b/test/data/.svn/text-base/post-mortem-osx.right.svn-base new file mode 100644 index 0000000..afa520c --- /dev/null +++ b/test/data/.svn/text-base/post-mortem-osx.right.svn-base @@ -0,0 +1,31 @@ +pm.rb:3 +def zero_div +# # *************************************************** +# # This tests post-mortem handling. +# # *************************************************** +# set debuggertesting on +Currently testing the debugger is on. +# continue +pm.rb:5 +1/0 +# # Should have got a divide by 0 error +# info program +The program crashed. +Exception: # +# where +--> #0 / at line pm.rb:5 + #1 at line pm.rb:8 +# up +#1 at line pm.rb:8 +# p x +2 +# help +Type 'help ' for help on a specific command + +Available commands: +backtrace delete edit frame list ps restart source undisplay +break disable enable help method putl save thread up +catch display eval info p quit set tmate var +condition down exit irb pp reload show trace where + +# quit diff --git a/test/data/.svn/text-base/post-mortem.cmd.svn-base b/test/data/.svn/text-base/post-mortem.cmd.svn-base new file mode 100644 index 0000000..d89f0f1 --- /dev/null +++ b/test/data/.svn/text-base/post-mortem.cmd.svn-base @@ -0,0 +1,13 @@ +# *************************************************** +# This tests post-mortem handling. +# *************************************************** +set debuggertesting on +continue +# Should have got a divide by 0 error +info program +where +up +p x +help +quit + diff --git a/test/data/.svn/text-base/post-mortem.right.svn-base b/test/data/.svn/text-base/post-mortem.right.svn-base new file mode 100644 index 0000000..d136ee1 --- /dev/null +++ b/test/data/.svn/text-base/post-mortem.right.svn-base @@ -0,0 +1,32 @@ +pm.rb:3 +def zero_div +# # *************************************************** +# # This tests post-mortem handling. +# # *************************************************** +# set debuggertesting on +Currently testing the debugger is on. +# continue +pm.rb:5 +1/0 +# # Should have got a divide by 0 error +# info program +The program crashed. +Exception: # +# where +--> #0 / at line pm.rb:5 + #1 at line pm.rb:8 +# up +#1 at line pm.rb:8 +# p x +2 +# help +Type 'help ' for help on a specific command + +Available commands: +backtrace delete enable info p reload source var +break disable eval irb pp restart thread where +catch display exit kill ps save trace +condition down frame list putl set undisplay +continue edit help method quit show up + +# quit diff --git a/test/data/.svn/text-base/quit.cmd.svn-base b/test/data/.svn/text-base/quit.cmd.svn-base new file mode 100644 index 0000000..e2a69b7 --- /dev/null +++ b/test/data/.svn/text-base/quit.cmd.svn-base @@ -0,0 +1,6 @@ +# *************************************************** +# This tests the quit. +# *************************************************** +set debuggertesting on +# FIXME need to test --no-quit. +quit diff --git a/test/data/.svn/text-base/quit.right.svn-base b/test/data/.svn/text-base/quit.right.svn-base new file mode 100644 index 0000000..e69de29 diff --git a/test/data/.svn/text-base/raise.cmd.svn-base b/test/data/.svn/text-base/raise.cmd.svn-base new file mode 100644 index 0000000..ad1eaee --- /dev/null +++ b/test/data/.svn/text-base/raise.cmd.svn-base @@ -0,0 +1,11 @@ +# ******************************************************** +# This tests that the debugger doesn't step into itself +# when the application doesn't terminate the right way. +# ******************************************************** +set debuggertesting on +catch x +catch ZeroDivisionError +info catch +catch 5 +step +quit diff --git a/test/data/.svn/text-base/raise.right.svn-base b/test/data/.svn/text-base/raise.right.svn-base new file mode 100644 index 0000000..6c86c04 --- /dev/null +++ b/test/data/.svn/text-base/raise.right.svn-base @@ -0,0 +1,26 @@ +raise.rb:3 +raise "abc" +# # ******************************************************** +# # This tests that the debugger doesn't step into itself +# # when the application doesn't terminate the right way. +# # ******************************************************** +# set debuggertesting on +Currently testing the debugger is on. +# catch x +NameError Exception: undefined local variable or method `x' for main:Object +# catch ZeroDivisionError +Catch exception ZeroDivisionError. +# info catch +ZeroDivisionError +# catch 5 +Warning 5 is not known to be a Class +Catch exception 5. +# step + ./raise.rb:3 + ./tdebug.rb:61:in `debug_load' + ./tdebug.rb:61:in `debug_program' + ./tdebug.rb:251 + ../rdbg.rb:23:in `load' + ../rdbg.rb:23:in `runner' + ../rdbg.rb:32 +Uncaught exception: abc diff --git a/test/data/.svn/text-base/save.cmd.svn-base b/test/data/.svn/text-base/save.cmd.svn-base new file mode 100644 index 0000000..69dae60 --- /dev/null +++ b/test/data/.svn/text-base/save.cmd.svn-base @@ -0,0 +1,33 @@ +# This tests the functioning of some set/show debugger commands +set debuggertesting on +### ******************************* +### *** save/source commands *** +### ******************************* +######################################## +### test args and baseneme... +######################################## +set basename off +set autoeval off +# Should have nothing set +info break +info catch +# Should save nothing +save temp +eval File.open("temp").readlines +# Should read in nothing +source temp +info break +# Now try saving something interesting +break 10 +catch RuntimeError +save temp +eval File.open("temp").readlines +# FIXME: The below is broken +## Change parameters above +## catch RuntimeError off +## info catch +##set listsize 55 +source temp +##info break +##info catch +##show listsize diff --git a/test/data/.svn/text-base/save.right.svn-base b/test/data/.svn/text-base/save.right.svn-base new file mode 100644 index 0000000..83599d0 --- /dev/null +++ b/test/data/.svn/text-base/save.right.svn-base @@ -0,0 +1,59 @@ +gcd.rb:4 +def gcd(a, b) +# # This tests the functioning of some set/show debugger commands +# set debuggertesting on +Currently testing the debugger is on. +# ### ******************************* +# ### *** save/source commands *** +# ### ******************************* +# ######################################## +# ### test args and baseneme... +# ######################################## +# set basename off +basename is off. +# set autoeval off +autoeval is off. +# # Should have nothing set +# info break +No breakpoints. +# info catch +No exceptions set to be caught. +# # Should save nothing +# save temp +Saved to 'temp' +# eval File.open("temp").readlines +["set autoeval off\n", "set basename off\n", "set debuggertesting on\n", "set autolist off\n", "set autoirb off\n"] +# # Should read in nothing +# source temp +autoeval is off. +basename is off. +Currently testing the debugger is on. +autolist is off. +autoirb is off. +# info break +No breakpoints. +# # Now try saving something interesting +# break 10 +Breakpoint 1 file ./gcd.rb, line 10 +# catch RuntimeError +Catch exception RuntimeError. +# save temp +Saved to 'temp' +# eval File.open("temp").readlines +["break ./gcd.rb:10\n", "catch RuntimeError\n", "set autoeval off\n", "set basename on\n", "set debuggertesting on\n", "set autolist off\n", "set autoirb off\n"] +# # FIXME: The below is broken +# ## Change parameters above +# ## catch RuntimeError off +# ## info catch +# ##set listsize 55 +# source temp +Breakpoint 2 file gcd.rb, line 10 +Catch exception RuntimeError. +autoeval is off. +basename is on. +Currently testing the debugger is on. +autolist is off. +autoirb is off. +# ##info break +# ##info catch +# ##show listsize diff --git a/test/data/.svn/text-base/setshow.cmd.svn-base b/test/data/.svn/text-base/setshow.cmd.svn-base new file mode 100644 index 0000000..b842821 --- /dev/null +++ b/test/data/.svn/text-base/setshow.cmd.svn-base @@ -0,0 +1,56 @@ +# This tests the functioning of some set/show debugger commands +set debuggertesting on +### ******************************* +### *** Set/show commands *** +### ******************************* +######################################## +### test args and baseneme... +######################################## +set args this is a test +show args +show basename +set basename foo +show base +set basename off +show basename +set basename 0 +show basename +set basename 1 +show basename +######################################## +### test listsize tests... +######################################## +show listsize +show listsi +set listsize abc +set listsize -20 +######################################## +### test linetrace... +######################################## +set linetrace on +show linetrace +set linetrace off +show linetrace +######################################## +### show history +######################################## +set history +set history size 10 +show history size +set history save off +show history save +set history save 1 +show history save +#### Test 'autoeval'... +set autoeval on +puts 'printed via autoeval' +set autoeval off +puts 'autoeval should not run this' +#### Test 'callstyle'... +set callstyle +set callstyle short +set callstyle last +set callstyle tracked +set callstyle foo + + diff --git a/test/data/.svn/text-base/setshow.right.svn-base b/test/data/.svn/text-base/setshow.right.svn-base new file mode 100644 index 0000000..63aca57 --- /dev/null +++ b/test/data/.svn/text-base/setshow.right.svn-base @@ -0,0 +1,97 @@ +gcd.rb:4 +def gcd(a, b) +# # This tests the functioning of some set/show debugger commands +# set debuggertesting on +Currently testing the debugger is on. +# ### ******************************* +# ### *** Set/show commands *** +# ### ******************************* +# ######################################## +# ### test args and baseneme... +# ######################################## +# set args this is a test +Argument list to give program being debugged when it is started is "this is a test". +# show args +Argument list to give program being debugged when it is started is "this is a test". +# show basename +basename is on. +# set basename foo +Expecting 'on', 1, 'off', or 0. Got: foo. +# show base +basename is on. +# set basename off +basename is off. +# show basename +basename is off. +# set basename 0 +basename is off. +# show basename +basename is off. +# set basename 1 +basename is on. +# show basename +basename is on. +# ######################################## +# ### test listsize tests... +# ######################################## +# show listsize +Number of source lines to list by default is 10. +# show listsi +Number of source lines to list by default is 10. +# set listsize abc +Set listsize argument 'abc' needs to be a number. +# set listsize -20 +Set listsize argument '-20' needs to at least 1. +# ######################################## +# ### test linetrace... +# ######################################## +# set linetrace on +line tracing is on. +# show linetrace +line tracing is on. +# set linetrace off +line tracing is off. +# show linetrace +line tracing is off. +# ######################################## +# ### show history +# ######################################## +# set history +Need two parameters for 'set history'; got 0. +# set history size 10 +Debugger history size is 10 +# show history size +Debugger history size is 10 +# set history save off +Saving of history save is off. +# show history save +Saving of history save is off. +# set history save 1 +Saving of history save is on. +# show history save +Saving of history save is on. +# #### Test 'autoeval'... +# set autoeval on +autoeval is on. +# puts 'printed via autoeval' +printed via autoeval +nil +# set autoeval off +autoeval is off. +# puts 'autoeval should not run this' +*** Unknown command: "puts 'autoeval should not run this'". Try "help". +# #### Test 'callstyle'... +# set callstyle +Invalid call style . Should be one of: 'short', 'last', or 'tracked'. +Frame call-display style is last. +# set callstyle short +Frame call-display style is short. +# set callstyle last +Frame call-display style is last. +# set callstyle tracked +Frame call-display style is tracked. +# set callstyle foo +Invalid call style foo. Should be one of: 'short', 'last', or 'tracked'. +Frame call-display style is tracked. +# +# diff --git a/test/data/.svn/text-base/source.cmd.svn-base b/test/data/.svn/text-base/source.cmd.svn-base new file mode 100644 index 0000000..71716f3 --- /dev/null +++ b/test/data/.svn/text-base/source.cmd.svn-base @@ -0,0 +1,5 @@ +# Test the source command +# rdebug-save has breakpoint commands +set debuggertesting on +source ./rdebug-save.1 +quit diff --git a/test/data/.svn/text-base/source.right.svn-base b/test/data/.svn/text-base/source.right.svn-base new file mode 100644 index 0000000..40d0cf8 --- /dev/null +++ b/test/data/.svn/text-base/source.right.svn-base @@ -0,0 +1,15 @@ +gcd.rb:4 +def gcd(a, b) +# # Test the source command +# # rdebug-save has breakpoint commands +# set debuggertesting on +Currently testing the debugger is on. +# source ./rdebug-save.1 +Breakpoint 1 file gcd.rb, line 10 +Breakpoint 2 file gcd.rb, line 12 +autoeval is on. +basename is off. +Currently testing the debugger is on. +autolist is off. +autoirb is off. +# quit diff --git a/test/data/.svn/text-base/stepping.cmd.svn-base b/test/data/.svn/text-base/stepping.cmd.svn-base new file mode 100644 index 0000000..f9a7473 --- /dev/null +++ b/test/data/.svn/text-base/stepping.cmd.svn-base @@ -0,0 +1,21 @@ +# *************************************************** +# This tests step, next, finish and continue +# *************************************************** +set debuggertesting on +set callstyle last +next +where +step a +set forcestep on +step- ; step- +set forcestep off +where +n 2 +step+ +where +step 3 +step+ +where +next+ +# finish +quit diff --git a/test/data/.svn/text-base/stepping.right.svn-base b/test/data/.svn/text-base/stepping.right.svn-base new file mode 100644 index 0000000..7791547 --- /dev/null +++ b/test/data/.svn/text-base/stepping.right.svn-base @@ -0,0 +1,50 @@ +gcd.rb:4 +def gcd(a, b) +# # *************************************************** +# # This tests step, next, finish and continue +# # *************************************************** +# set debuggertesting on +Currently testing the debugger is on. +# set callstyle last +Frame call-display style is last. +# next +gcd.rb:18 +gcd(3,5) +# where +--> #0 at line gcd.rb:18 +# step a +Step argument 'a' needs to be a number. +# set forcestep on +force-stepping is on. +# step- ; step- +gcd.rb:6 +if a > b +# set forcestep off +force-stepping is off. +# where +--> #0 Object.gcd(a#Fixnum, b#Fixnum) at line gcd.rb:6 + #1 at line gcd.rb:18 +# n 2 +gcd.rb:10 +return nil if a <= 0 +# step+ +gcd.rb:12 +if a == 1 or b-a == 0 +# where +--> #0 Object.gcd(a#Fixnum, b#Fixnum) at line gcd.rb:12 + #1 at line gcd.rb:18 +# step 3 +gcd.rb:6 +if a > b +# step+ +gcd.rb:10 +return nil if a <= 0 +# where +--> #0 Object.gcd(a#Fixnum, b#Fixnum) at line gcd.rb:10 + #1 Object.-(a#Fixnum, b#Fixnum) at line gcd.rb:15 + #2 at line gcd.rb:18 +# next+ +gcd.rb:12 +if a == 1 or b-a == 0 +# # finish +# quit diff --git a/test/data/.svn/text-base/test-init-cygwin.right.svn-base b/test/data/.svn/text-base/test-init-cygwin.right.svn-base new file mode 100644 index 0000000..8d683f3 --- /dev/null +++ b/test/data/.svn/text-base/test-init-cygwin.right.svn-base @@ -0,0 +1,7 @@ +gcd-dbg.rb:18 +if a > b +(rdb:1) p Debugger::PROG_SCRIPT +"./gcd-dbg.rb" +(rdb:1) show args +Argument list to give program being debugged when it is started is "5". +(rdb:1) quit unconditionally diff --git a/test/data/.svn/text-base/test-init-osx.right.svn-base b/test/data/.svn/text-base/test-init-osx.right.svn-base new file mode 100644 index 0000000..a50319c --- /dev/null +++ b/test/data/.svn/text-base/test-init-osx.right.svn-base @@ -0,0 +1,4 @@ +gcd-dbg.rb:18 +if a > b +"./gcd-dbg.rb" +Argument list to give program being debugged when it is started is "5". diff --git a/test/data/.svn/text-base/test-init.right.svn-base b/test/data/.svn/text-base/test-init.right.svn-base new file mode 100644 index 0000000..981c233 --- /dev/null +++ b/test/data/.svn/text-base/test-init.right.svn-base @@ -0,0 +1,5 @@ +gcd-dbg.rb:18 +if a > b +(rdb:1) "./gcd-dbg.rb" +(rdb:1) Argument list to give program being debugged when it is started is "5". +(rdb:1) \ No newline at end of file diff --git a/test/data/.svn/text-base/trace.right.svn-base b/test/data/.svn/text-base/trace.right.svn-base new file mode 100644 index 0000000..ada9008 --- /dev/null +++ b/test/data/.svn/text-base/trace.right.svn-base @@ -0,0 +1,23 @@ +Tracing(1):gcd.rb:4 def gcd(a, b) +Tracing(1):gcd.rb:18 gcd(3,5) +Tracing(1):gcd.rb:6 if a > b +Tracing(1):gcd.rb:6 if a > b +Tracing(1):gcd.rb:10 return nil if a <= 0 +Tracing(1):gcd.rb:10 return nil if a <= 0 +Tracing(1):gcd.rb:12 if a == 1 or b-a == 0 +Tracing(1):gcd.rb:12 if a == 1 or b-a == 0 +Tracing(1):gcd.rb:15 return gcd(b-a, a) +Tracing(1):gcd.rb:6 if a > b +Tracing(1):gcd.rb:6 if a > b +Tracing(1):gcd.rb:10 return nil if a <= 0 +Tracing(1):gcd.rb:10 return nil if a <= 0 +Tracing(1):gcd.rb:12 if a == 1 or b-a == 0 +Tracing(1):gcd.rb:12 if a == 1 or b-a == 0 +Tracing(1):gcd.rb:15 return gcd(b-a, a) +Tracing(1):gcd.rb:6 if a > b +Tracing(1):gcd.rb:6 if a > b +Tracing(1):gcd.rb:10 return nil if a <= 0 +Tracing(1):gcd.rb:10 return nil if a <= 0 +Tracing(1):gcd.rb:12 if a == 1 or b-a == 0 +Tracing(1):gcd.rb:12 if a == 1 or b-a == 0 +Tracing(1):gcd.rb:13 return a diff --git a/test/data/annotate.cmd b/test/data/annotate.cmd new file mode 100644 index 0000000..1fd55f8 --- /dev/null +++ b/test/data/annotate.cmd @@ -0,0 +1,29 @@ +# ******************************************************** +# This tests annotations +# ******************************************************** +set debuggertesting on +set callstyle last +set force off +set annotate 3 +# Get into gcd +step 2 +# "break" should trigger break annotation +break 10 +# "delete" should trigger break annotation +delete 1 +# p should not trigger a breakpoint annotation +p a +# "up" should trigger annotations +up +# "b" should trigger like "break" +b 12 +# "display" should trigger display annotation +display 1+2 +# undisplay should trigger display annotation +undisplay 1 +step +# Test error annotations +up 10 +frame 100 +break bogus:5 +quit! diff --git a/test/data/annotate.right b/test/data/annotate.right new file mode 100644 index 0000000..9048aff --- /dev/null +++ b/test/data/annotate.right @@ -0,0 +1,139 @@ +gcd.rb:4 +def gcd(a, b) +# # ******************************************************** +# # This tests annotations +# # ******************************************************** +# set debuggertesting on +Currently testing the debugger is on. +# set callstyle last +Frame call-display style is last. +# set force off +force-stepping is off. +# set annotate 3 +Annotation level is 3 +# # Get into gcd +# step 2 +starting +stopped +breakpoints +No breakpoints. + +stack +--> #0 Object.gcd(a#Fixnum, b#Fixnum) at line gcd.rb:6 + #1 at line gcd.rb:18 + +variables +a = 3 +b = 5 +self = main + +source gcd.rb:6 +if a > b +# # "break" should trigger break annotation +# break 10 +Breakpoint 1 file ./gcd.rb, line 10 +breakpoints +Num Enb What + 1 y at ./gcd.rb:10 + +# # "delete" should trigger break annotation +# delete 1 +breakpoints +No breakpoints. + +# # p should not trigger a breakpoint annotation +# p a +3 +# # "up" should trigger annotations +# up +#1 at line gcd.rb:18 +stack + #0 Object.gcd(a#Fixnum, b#Fixnum) at line gcd.rb:6 +--> #1 at line gcd.rb:18 + +variables +self = main + +# # "b" should trigger like "break" +# b 12 +Breakpoint 2 file ./gcd.rb, line 12 +breakpoints +Num Enb What + 2 y at ./gcd.rb:12 + +# # "display" should trigger display annotation +# display 1+2 +1: 1+2 = 3 +display +1: 1+2 = 3 + +# # undisplay should trigger display annotation +# undisplay 1 +display + +# step +display + +starting +stopped +breakpoints +Num Enb What + 2 y at ./gcd.rb:12 + +display + +stack +--> #0 Object.gcd(a#Fixnum, b#Fixnum) at line gcd.rb:6 + #1 at line gcd.rb:18 + +variables +a = 3 +b = 5 +self = main + +source gcd.rb:6 +if a > b +# # Test error annotations +# up 10 +error-begin +Adjusting would put us beyond the oldest (initial) frame. + +display + +stack +--> #0 Object.gcd(a#Fixnum, b#Fixnum) at line gcd.rb:6 + #1 at line gcd.rb:18 + +variables +a = 3 +b = 5 +self = main + +# frame 100 +error-begin +Adjusting would put us beyond the oldest (initial) frame. + +display + +stack +--> #0 Object.gcd(a#Fixnum, b#Fixnum) at line gcd.rb:6 + #1 at line gcd.rb:18 + +variables +a = 3 +b = 5 +self = main + +# break bogus:5 +error-begin +No source file named bogus + +Breakpoint 3 file bogus, line 5 +breakpoints +Num Enb What + 2 y at ./gcd.rb:12 + 3 y at bogus:5 + +display + +# quit! diff --git a/test/data/break_bad.cmd b/test/data/break_bad.cmd new file mode 100644 index 0000000..98f17fe --- /dev/null +++ b/test/data/break_bad.cmd @@ -0,0 +1,18 @@ +# ******************************************************** +# This tests mostly invalid breakpoints. +# We have some valid ones too. +# ******************************************************** +set debuggertesting on +set callstyle last +set autoeval off +# There aren't 100 lines in gcd.rb. +break 100 +break gcd.rb:100 +# Line one isn't a valid stopping point. +# It is a comment. +break gcd.rb:1 +# This line is okay +break gcd.rb:4 +# No class Foo. +break Foo.bar +q diff --git a/test/data/break_bad.right b/test/data/break_bad.right new file mode 100644 index 0000000..d27f581 --- /dev/null +++ b/test/data/break_bad.right @@ -0,0 +1,28 @@ +gcd.rb:4 +def gcd(a, b) +# # ******************************************************** +# # This tests mostly invalid breakpoints. +# # We have some valid ones too. +# # ******************************************************** +# set debuggertesting on +Currently testing the debugger is on. +# set callstyle last +Frame call-display style is last. +# set autoeval off +autoeval is off. +# # There aren't 100 lines in gcd.rb. +# break 100 +*** There are only 18 lines in file "gcd.rb". +# break gcd.rb:100 +*** There are only 18 lines in file "gcd.rb". +# # Line one isn't a valid stopping point. +# # It is a comment. +# break gcd.rb:1 +*** Line 1 is not a stopping point in file "gcd.rb". +# # This line is okay +# break gcd.rb:4 +Breakpoint 1 file gcd.rb, line 4 +# # No class Foo. +# break Foo.bar +*** Unknown class Foo. +# q diff --git a/test/data/break_loop_bug.cmd b/test/data/break_loop_bug.cmd new file mode 100644 index 0000000..cbcb79f --- /dev/null +++ b/test/data/break_loop_bug.cmd @@ -0,0 +1,5 @@ +set debuggertesting on +break 2 +cont +cont +cont diff --git a/test/data/break_loop_bug.right b/test/data/break_loop_bug.right new file mode 100644 index 0000000..4de6124 --- /dev/null +++ b/test/data/break_loop_bug.right @@ -0,0 +1,15 @@ +bp_loop_issue.rb:1 +1.upto(2) { +# set debuggertesting on +Currently testing the debugger is on. +# break 2 +Breakpoint 1 file ./bp_loop_issue.rb, line 2 +# cont +Breakpoint 1 at bp_loop_issue.rb:2 +bp_loop_issue.rb:2 +sleep 0.01 +# cont +Breakpoint 1 at bp_loop_issue.rb:2 +bp_loop_issue.rb:2 +sleep 0.01 +# cont diff --git a/test/data/breakpoints.cmd b/test/data/breakpoints.cmd new file mode 100644 index 0000000..f5d0ff0 --- /dev/null +++ b/test/data/breakpoints.cmd @@ -0,0 +1,38 @@ +# ******************************************************** +# This tests step, next, continue, disable and +# enable. +# FIXME: break out enable/disable +# ******************************************************** +set debuggertesting on +set callstyle last +set autoeval off +break 6 +break 10 +break 11 +continue +where +break Object.gcd +info break +continue +where +info program +c 6 +info break +break foo +info break +disable 1 +info break +delete 1 +# We should see breakpoint 2 but not 1 +info break +# We should still be able to access 2 +disable 2 +disable bar +disable +# We should be able to delete 2 +delete 2 3 +info break +# Should get a message about having no breakpoints. +disable 1 +enable 1 +q! diff --git a/test/data/breakpoints.right b/test/data/breakpoints.right new file mode 100644 index 0000000..ef9646b --- /dev/null +++ b/test/data/breakpoints.right @@ -0,0 +1,98 @@ +gcd.rb:4 +def gcd(a, b) +# # ******************************************************** +# # This tests step, next, continue, disable and +# # enable. +# # FIXME: break out enable/disable +# # ******************************************************** +# set debuggertesting on +Currently testing the debugger is on. +# set callstyle last +Frame call-display style is last. +# set autoeval off +autoeval is off. +# break 6 +Breakpoint 1 file ./gcd.rb, line 6 +# break 10 +Breakpoint 2 file ./gcd.rb, line 10 +# break 11 +*** Line 11 is not a stopping point in file "gcd.rb". +# continue +Breakpoint 1 at gcd.rb:6 +gcd.rb:6 +if a > b +# where +--> #0 Object.gcd(a#Fixnum, b#Fixnum) at line gcd.rb:6 + #1 at line gcd.rb:18 +# break Object.gcd +Breakpoint 3 at Object::gcd +# info break +Num Enb What + 1 y at ./gcd.rb:6 + breakpoint already hit 1 time + 2 y at ./gcd.rb:10 + 3 y at Object:gcd +# continue +Breakpoint 2 at gcd.rb:10 +gcd.rb:10 +return nil if a <= 0 +# where +--> #0 Object.gcd(a#Fixnum, b#Fixnum) at line gcd.rb:10 + #1 at line gcd.rb:18 +# info program +Program stopped. It stopped at a breakpoint. +# c 6 +Breakpoint 3 at Object:gcd +gcd.rb:4 +def gcd(a, b) +# info break +Num Enb What + 1 y at ./gcd.rb:6 + breakpoint already hit 1 time + 2 y at ./gcd.rb:10 + breakpoint already hit 1 time + 3 y at Object:gcd + breakpoint already hit 1 time +# break foo +*** Invalid breakpoint location: foo. +# info break +Num Enb What + 1 y at ./gcd.rb:6 + breakpoint already hit 1 time + 2 y at ./gcd.rb:10 + breakpoint already hit 1 time + 3 y at Object:gcd + breakpoint already hit 1 time +# disable 1 +# info break +Num Enb What + 1 n at ./gcd.rb:6 + breakpoint already hit 1 time + 2 y at ./gcd.rb:10 + breakpoint already hit 1 time + 3 y at Object:gcd + breakpoint already hit 1 time +# delete 1 +# # We should see breakpoint 2 but not 1 +# info break +Num Enb What + 2 y at ./gcd.rb:10 + breakpoint already hit 1 time + 3 y at Object:gcd + breakpoint already hit 1 time +# # We should still be able to access 2 +# disable 2 +# disable bar +Disable breakpoints argument 'bar' needs to be a number. +# disable +*** "disable" must be followed "display", "breakpoints" or breakpoint numbers. +# # We should be able to delete 2 +# delete 2 3 +# info break +No breakpoints. +# # Should get a message about having no breakpoints. +# disable 1 +*** No breakpoints have been set. +# enable 1 +*** No breakpoints have been set. +# q! diff --git a/test/data/catch.cmd b/test/data/catch.cmd new file mode 100644 index 0000000..0c5eefe --- /dev/null +++ b/test/data/catch.cmd @@ -0,0 +1,17 @@ +# *************************************************** +# Test catch +# *************************************************** +set debuggertesting on +set autoeval off +set basename on +info catch +catch ZeroDivisionError off +catch ZeroDivisionError off afdasdf +catch ZeroDivisionError +info catch +catch ZeroDivisionError off +info catch +catch ZeroDivisionError +c +where +quit diff --git a/test/data/catch.right b/test/data/catch.right new file mode 100644 index 0000000..ec93c02 --- /dev/null +++ b/test/data/catch.right @@ -0,0 +1,37 @@ +pm.rb:3 +def zero_div +# # *************************************************** +# # Test catch +# # *************************************************** +# set debuggertesting on +Currently testing the debugger is on. +# set autoeval off +autoeval is off. +# set basename on +basename is on. +# info catch +No exceptions set to be caught. +# catch ZeroDivisionError off +*** Catch for exception ZeroDivisionError not found. +# catch ZeroDivisionError off afdasdf +*** Unknown command: "catch ZeroDivisionError off afdasdf". Try "help". +# catch ZeroDivisionError +Catch exception ZeroDivisionError. +# info catch +ZeroDivisionError +# catch ZeroDivisionError off +Catch for exception ZeroDivisionError removed. +# info catch +No exceptions set to be caught. +# catch ZeroDivisionError +Catch exception ZeroDivisionError. +# c +Catchpoint at pm.rb:5: `divided by 0' (ZeroDivisionError) + from ../rdbg.rb:23:in `runner' + from ../rdbg.rb:32 +pm.rb:5 +1/0 +# where +--> #0 Object./ at line pm.rb:5 + #1 at line pm.rb:8 +# quit diff --git a/test/data/condition.cmd b/test/data/condition.cmd new file mode 100644 index 0000000..a2e8967 --- /dev/null +++ b/test/data/condition.cmd @@ -0,0 +1,28 @@ +# ******************************************************** +# This tests primarily the condition command. +# In order to do this we need to run break, and disable +# ******************************************************** +set debuggertesting on +set callstyle last +set autoeval off +break 6 if a > b +info break +condition 1 +info break +break 12 +condition 2 1 == a +# FIXME: should be able to catch error on: +# condition 2 if 1 == a +disable 1 +continue +info break +p a +# Now test trying to enable an invalid breakpoint +break 6 if a > +info break +enable 3 +info break +condition 3 a > 5 +enable 3 +info break +quit diff --git a/test/data/condition.right b/test/data/condition.right new file mode 100644 index 0000000..6b9d7b3 --- /dev/null +++ b/test/data/condition.right @@ -0,0 +1,65 @@ +gcd.rb:4 +def gcd(a, b) +# # ******************************************************** +# # This tests primarily the condition command. +# # In order to do this we need to run break, and disable +# # ******************************************************** +# set debuggertesting on +Currently testing the debugger is on. +# set callstyle last +Frame call-display style is last. +# set autoeval off +autoeval is off. +# break 6 if a > b +Breakpoint 1 file ./gcd.rb, line 6 +# info break +Num Enb What + 1 y at gcd.rb:6 if a > b +# condition 1 +# info break +Num Enb What + 1 y at gcd.rb:6 +# break 12 +Breakpoint 2 file ./gcd.rb, line 12 +# condition 2 1 == a +# # FIXME: should be able to catch error on: +# # condition 2 if 1 == a +# disable 1 +# continue +Breakpoint 2 at gcd.rb:12 +gcd.rb:12 +if a == 1 or b-a == 0 +# info break +Num Enb What + 1 n at gcd.rb:6 + 2 y at gcd.rb:12 if 1 == a + breakpoint already hit 1 time +# p a +1 +# # Now test trying to enable an invalid breakpoint +# break 6 if a > +Breakpoint 3 file ./gcd.rb, line 6 +*** Expression "a > " syntactically incorrect; breakpoint disabled. +# info break +Num Enb What + 1 n at gcd.rb:6 + 2 y at gcd.rb:12 if 1 == a + breakpoint already hit 1 time + 3 n at gcd.rb:6 if a > +# enable 3 +*** Expression "a > " syntactically incorrect; breakpoint remains disabled. +# info break +Num Enb What + 1 n at gcd.rb:6 + 2 y at gcd.rb:12 if 1 == a + breakpoint already hit 1 time + 3 n at gcd.rb:6 if a > +# condition 3 a > 5 +# enable 3 +# info break +Num Enb What + 1 n at gcd.rb:6 + 2 y at gcd.rb:12 if 1 == a + breakpoint already hit 1 time + 3 y at gcd.rb:6 if a > 5 +# quit diff --git a/test/data/ctrl.cmd b/test/data/ctrl.cmd new file mode 100644 index 0000000..29b35fd --- /dev/null +++ b/test/data/ctrl.cmd @@ -0,0 +1,23 @@ +set debuggertesting on +set width 80 +help +help info +info args +info breakpoints +info display +info program +info global_variables +info line +info locals +info stack +info threads +info variables +eval 1+2 +help show +set trace off +show trace +set trace on +set annotate 0 +show annotate + + diff --git a/test/data/ctrl.right b/test/data/ctrl.right new file mode 100644 index 0000000..f0aeeb5 --- /dev/null +++ b/test/data/ctrl.right @@ -0,0 +1,69 @@ +Currently testing the debugger is on. +width is 80. +Type 'help ' for help on a specific command + +Available commands: +break delete eval help interrupt p ps quit restart set source +catch edit exit info kill pp putl reload save show thread + +Generic command for showing things about the program being debugged. +-- +List of info subcommands: +-- +info args -- Argument variables of current stack frame +info breakpoints -- Status of user-settable breakpoints +info catch -- Exceptions that can be caught in the current stack frame +info display -- Expressions to display when program stops +info file -- Info about a particular file read in +info files -- File names and timestamps of files read in +info global_variables -- Global variables +info instance_variables -- Instance variables of the current stack frame +info line -- Line number and file name of current position in source file +info locals -- Local variables of the current stack frame +info program -- Execution status of the program +info stack -- Backtrace of the stack +info thread -- List info about thread NUM +info threads -- information of currently-known threads +info variables -- Local and instance variables of the current stack frame +No frame selected. +info breakpoints not available here. +info display not available here. +The program being debugged is not being run. +info global_variables not available here. +info line not available here. +info line not available here. +info stack not available here. +info threads not available here. +info variables not available here. +3 +Generic command for showing things about the debugger. + +-- +List of show subcommands: +-- +show annotate -- Show annotation level +show args -- Show argument list to give program being debugged when it is started +show autoeval -- Show if unrecognized command are evaluated +show autolist -- Show if 'list' commands is run on breakpoints +show autoirb -- Show if IRB is invoked on debugger stops +show autoreload -- Show if source code is reloaded when changed +show basename -- Show if basename used in reporting files +show callstyle -- Show paramater style used showing call frames +show commands -- Show the history of commands you typed +show forcestep -- Show if sure 'next/step' forces move to a new line +show fullpath -- Show if full file names are displayed in frames +show history -- Generic command for showing command history parameters +show keep-frame-bindings -- Save frame binding on each call +show linetrace -- Show line execution tracing +show linetrace+ -- Show if consecutive lines should be different are shown in tracing +show listsize -- Show number of source lines to list by default +show port -- Show server port +show post-mortem -- Show whether we go into post-mortem debugging on an uncaught exception +show trace -- Show if a stack trace is displayed when 'eval' raises exception +show version -- Show what version of the debugger this is +show width -- Show the number of characters the debugger thinks are in a line +Displaying stack trace is off. +Displaying stack trace is off. +Displaying stack trace is on. +Annotation level is 0 +Annotation level is 0 diff --git a/test/data/display.cmd b/test/data/display.cmd new file mode 100644 index 0000000..429c9f1 --- /dev/null +++ b/test/data/display.cmd @@ -0,0 +1,24 @@ +# *************************************************** +# This tests display expressions. +# *************************************************** +set debuggertesting on +b 6 +c +# Should be no display expression yet. +info display +display a +display b +disable display b +disable display 1 +c +enable display b +enable display 1 +undisplay a +undisplay 2 +# Should have only one display expression. +info display +undisplay 1 +# Now we have no more display expressions. +info display +q + diff --git a/test/data/display.right b/test/data/display.right new file mode 100644 index 0000000..7a3b230 --- /dev/null +++ b/test/data/display.right @@ -0,0 +1,44 @@ +gcd.rb:4 +def gcd(a, b) +# # *************************************************** +# # This tests display expressions. +# # *************************************************** +# set debuggertesting on +Currently testing the debugger is on. +# b 6 +Breakpoint 1 file ./gcd.rb, line 6 +# c +Breakpoint 1 at gcd.rb:6 +gcd.rb:6 +if a > b +# # Should be no display expression yet. +# info display +There are no auto-display expressions now. +# display a +1: a = 3 +# display b +2: b = 5 +# disable display b +Disable display argument 'b' needs to be a number. +# disable display 1 +# c +Breakpoint 1 at gcd.rb:6 +2: b = 3 +gcd.rb:6 +if a > b +# enable display b +Enable display argument 'b' needs to be a number. +# enable display 1 +# undisplay a +Undisplay argument 'a' needs to be a number. +# undisplay 2 +# # Should have only one display expression. +# info display +Auto-display expressions now in effect: +Num Enb Expression + 1: y a +# undisplay 1 +# # Now we have no more display expressions. +# info display +There are no auto-display expressions now. +# q diff --git a/test/data/dollar-0.right b/test/data/dollar-0.right new file mode 100644 index 0000000..b168a38 --- /dev/null +++ b/test/data/dollar-0.right @@ -0,0 +1,2 @@ +./dollar-0.rb +./dollar-0.rb diff --git a/test/data/dollar-0a.right b/test/data/dollar-0a.right new file mode 100644 index 0000000..b168a38 --- /dev/null +++ b/test/data/dollar-0a.right @@ -0,0 +1,2 @@ +./dollar-0.rb +./dollar-0.rb diff --git a/test/data/dollar-0b.right b/test/data/dollar-0b.right new file mode 100644 index 0000000..538a360 --- /dev/null +++ b/test/data/dollar-0b.right @@ -0,0 +1,2 @@ +../test/dollar-0.rb +../test/dollar-0.rb diff --git a/test/data/edit.cmd b/test/data/edit.cmd new file mode 100644 index 0000000..ec4a350 --- /dev/null +++ b/test/data/edit.cmd @@ -0,0 +1,12 @@ +# ******************************************************** +# This tests the edit command +# ******************************************************** +set debuggertesting on +# Edit using current line position. +edit +edit gcd.rb:5 +# File should not exist +edit foo +# Add space to the end of 'edit' +edit +quit diff --git a/test/data/edit.right b/test/data/edit.right new file mode 100644 index 0000000..66523c1 --- /dev/null +++ b/test/data/edit.right @@ -0,0 +1,19 @@ +gcd.rb:4 +def gcd(a, b) +# # ******************************************************** +# # This tests the edit command +# # ******************************************************** +# set debuggertesting on +Currently testing the debugger is on. +# # Edit using current line position. +# edit +FAKE-EDITOR +4 ./gcd.rb +# edit gcd.rb:5 +FAKE-EDITOR +5 gcd.rb +# # File should not exist +# edit foo +*** Invalid file/line number specification: foo +# # Add space to the end of 'edit' +# edit +FAKE-EDITOR +4 ./gcd.rb +# quit diff --git a/test/data/emacs_basic.cmd b/test/data/emacs_basic.cmd new file mode 100644 index 0000000..315eb2a --- /dev/null +++ b/test/data/emacs_basic.cmd @@ -0,0 +1,43 @@ +# ******************************************************** +# This tests step, next, finish, continue, disable and +# enable. +# FIXME: break out enable/disable +# ******************************************************** +set debuggertesting on +set callstyle last +set autoeval off +break 6 +break 10 +continue +where +break Foo.bar +break Object.gcd +info break +continue +where +info program +c 10 +info break +break foo +info break +disable 1 +info break +enable breakpoint 1 +enable br 10 +delete 1 +# We should see breakpoint 2 but not 1 +info break +# We should still be able to access 2 +disable 2 +enable +enable foo +disable bar +disable +# We should be able to delete 2 +delete 2 3 +info break +# Should get a message about having no breakpoints. +disable 1 +enable 1 +# finish +quit diff --git a/test/data/emacs_basic.right b/test/data/emacs_basic.right new file mode 100644 index 0000000..6d80e2a --- /dev/null +++ b/test/data/emacs_basic.right @@ -0,0 +1,106 @@ +gcd.rb:4 +def gcd(a, b) +# # ******************************************************** +# # This tests step, next, finish, continue, disable and +# # enable. +# # FIXME: break out enable/disable +# # ******************************************************** +# set debuggertesting on +Currently testing the debugger is on. +# set callstyle last +Frame call-display style is last. +# set autoeval off +autoeval is off. +# break 6 +Breakpoint 1 file ./gcd.rb, line 6 +# break 10 +Breakpoint 2 file ./gcd.rb, line 10 +# continue +Breakpoint 1 at gcd.rb:6 +gcd.rb:6 +if a > b +# where +--> #0 Object.gcd(a#Fixnum, b#Fixnum) at line gcd.rb:6 + #1 at line gcd.rb:18 +# break Foo.bar +*** Unknown class Foo. +# break Object.gcd +Breakpoint 3 at Object::gcd +# info break +Num Enb What + 1 y at ./gcd.rb:6 + breakpoint already hit 1 time + 2 y at ./gcd.rb:10 + 3 y at Object:gcd +# continue +Breakpoint 2 at gcd.rb:10 +gcd.rb:10 +return nil if a <= 0 +# where +--> #0 Object.gcd(a#Fixnum, b#Fixnum) at line gcd.rb:10 + #1 at line gcd.rb:18 +# info program +Program stopped. It stopped at a breakpoint. +# c 10 +Breakpoint 3 at Object:gcd +gcd.rb:4 +def gcd(a, b) +# info break +Num Enb What + 1 y at ./gcd.rb:6 + breakpoint already hit 1 time + 2 y at ./gcd.rb:10 + breakpoint already hit 1 time + 3 y at Object:gcd + breakpoint already hit 1 time +# break foo +*** Invalid breakpoint location: foo. +# info break +Num Enb What + 1 y at ./gcd.rb:6 + breakpoint already hit 1 time + 2 y at ./gcd.rb:10 + breakpoint already hit 1 time + 3 y at Object:gcd + breakpoint already hit 1 time +# disable 1 +# info break +Num Enb What + 1 n at ./gcd.rb:6 + breakpoint already hit 1 time + 2 y at ./gcd.rb:10 + breakpoint already hit 1 time + 3 y at Object:gcd + breakpoint already hit 1 time +# enable breakpoint 1 +# enable br 10 +Enable breakpoints argument '10' needs to at most 3. +# delete 1 +# # We should see breakpoint 2 but not 1 +# info break +Num Enb What + 2 y at ./gcd.rb:10 + breakpoint already hit 1 time + 3 y at Object:gcd + breakpoint already hit 1 time +# # We should still be able to access 2 +# disable 2 +# enable +*** "enable" must be followed "display", "breakpoints" or breakpoint numbers. +# enable foo +Enable breakpoints argument 'foo' needs to be a number. +# disable bar +Disable breakpoints argument 'bar' needs to be a number. +# disable +*** "disable" must be followed "display", "breakpoints" or breakpoint numbers. +# # We should be able to delete 2 +# delete 2 3 +# info break +No breakpoints. +# # Should get a message about having no breakpoints. +# disable 1 +*** No breakpoints have been set. +# enable 1 +*** No breakpoints have been set. +# # finish +# quit diff --git a/test/data/enable.cmd b/test/data/enable.cmd new file mode 100644 index 0000000..0067f29 --- /dev/null +++ b/test/data/enable.cmd @@ -0,0 +1,20 @@ +# ******************************************************** +# This tests the enable command. +# ******************************************************** +set debuggertesting on +set callstyle last +set autoeval off +break Object.gcd +# Should have a breakpoint 1 +enable br 1 +# Get help on enable +help enable +# Get help on just enable break +help enable break +# Plain enable should work +enable +# An invalid enable command +enable foo +quit + + diff --git a/test/data/enable.right b/test/data/enable.right new file mode 100644 index 0000000..ad97ab0 --- /dev/null +++ b/test/data/enable.right @@ -0,0 +1,36 @@ +gcd.rb:4 +def gcd(a, b) +# # ******************************************************** +# # This tests the enable command. +# # ******************************************************** +# set debuggertesting on +Currently testing the debugger is on. +# set callstyle last +Frame call-display style is last. +# set autoeval off +autoeval is off. +# break Object.gcd +Breakpoint 1 at Object::gcd +# # Should have a breakpoint 1 +# enable br 1 +# # Get help on enable +# help enable +Enable some things. +This is used to cancel the effect of the "disable" command. +-- +List of enable subcommands: +-- +enable breakpoints -- Enable specified breakpoints +enable display -- Enable some expressions to be displayed when program stops +# # Get help on just enable break +# help enable break +Enable specified breakpoints. +Give breakpoint numbers (separated by spaces) as arguments. +This is used to cancel the effect of the "disable" command. +# # Plain enable should work +# enable +*** "enable" must be followed "display", "breakpoints" or breakpoint numbers. +# # An invalid enable command +# enable foo +Enable breakpoints argument 'foo' needs to be a number. +# quit diff --git a/test/data/finish.cmd b/test/data/finish.cmd new file mode 100644 index 0000000..e10d12b --- /dev/null +++ b/test/data/finish.cmd @@ -0,0 +1,16 @@ +# ******************************************************** +# This tests finish. +# ******************************************************** +set debuggertesting on +set callstyle last +set autoeval off +break 6 +continue +continue +continue +where +finish 0 +where +p a +p b +finish diff --git a/test/data/finish.right b/test/data/finish.right new file mode 100644 index 0000000..9979fb0 --- /dev/null +++ b/test/data/finish.right @@ -0,0 +1,31 @@ +gcd.rb:4 +def gcd(a, b) +# # ******************************************************** +# # This tests finish. +# # ******************************************************** +# set debuggertesting on +Currently testing the debugger is on. +# set callstyle last +Frame call-display style is last. +# set autoeval off +autoeval is off. +# break 6 +Breakpoint 1 file ./gcd.rb, line 6 +# continue +Breakpoint 1 at gcd.rb:6 +gcd.rb:6 +if a > b +# continue +Breakpoint 1 at gcd.rb:6 +gcd.rb:6 +if a > b +# continue +Breakpoint 1 at gcd.rb:6 +gcd.rb:6 +if a > b +# where +--> #0 Object.gcd(a#Fixnum, b#Fixnum) at line gcd.rb:6 + #1 Object.-(a#Fixnum, b#Fixnum) at line gcd.rb:15 + #2 Object.-(a#Fixnum, b#Fixnum) at line gcd.rb:15 + #3 at line gcd.rb:18 +# finish 0 diff --git a/test/data/frame.cmd b/test/data/frame.cmd new file mode 100644 index 0000000..579bc3f --- /dev/null +++ b/test/data/frame.cmd @@ -0,0 +1,26 @@ +# *************************************************** +# This tests step, next, finish and continue +# *************************************************** +set debuggertesting on +set callstyle last +# Invalid line number in continue command +continue 3 +# This time, for sure! +continue 6 +where +up +where +down +where +frame +where +frame -1 +where +up 2 +where +down 2 +where +frame 0 thread 3 +frame 0 thread 1 +# finish +quit diff --git a/test/data/frame.right b/test/data/frame.right new file mode 100644 index 0000000..22b24e6 --- /dev/null +++ b/test/data/frame.right @@ -0,0 +1,55 @@ +gcd.rb:4 +def gcd(a, b) +# # *************************************************** +# # This tests step, next, finish and continue +# # *************************************************** +# set debuggertesting on +Currently testing the debugger is on. +# set callstyle last +Frame call-display style is last. +# # Invalid line number in continue command +# continue 3 +*** Line 3 is not a stopping point in file "gcd.rb". +# # This time, for sure! +# continue 6 +gcd.rb:6 +if a > b +# where +--> #0 Object.gcd(a#Fixnum, b#Fixnum) at line gcd.rb:6 + #1 at line gcd.rb:18 +# up +#1 at line gcd.rb:18 +# where + #0 Object.gcd(a#Fixnum, b#Fixnum) at line gcd.rb:6 +--> #1 at line gcd.rb:18 +# down +#0 Object.gcd(a#Fixnum, b#Fixnum) at line gcd.rb:6 +# where +--> #0 Object.gcd(a#Fixnum, b#Fixnum) at line gcd.rb:6 + #1 at line gcd.rb:18 +# frame +#0 Object.gcd(a#Fixnum, b#Fixnum) at line gcd.rb:6 +# where +--> #0 Object.gcd(a#Fixnum, b#Fixnum) at line gcd.rb:6 + #1 at line gcd.rb:18 +# frame -1 +#1 at line gcd.rb:18 +# where + #0 Object.gcd(a#Fixnum, b#Fixnum) at line gcd.rb:6 +--> #1 at line gcd.rb:18 +# up 2 +*** Adjusting would put us beyond the oldest (initial) frame. +# where + #0 Object.gcd(a#Fixnum, b#Fixnum) at line gcd.rb:6 +--> #1 at line gcd.rb:18 +# down 2 +*** Adjusting would put us beyond the newest (innermost) frame. +# where + #0 Object.gcd(a#Fixnum, b#Fixnum) at line gcd.rb:6 +--> #1 at line gcd.rb:18 +# frame 0 thread 3 +*** Thread 3 doesn't exist. +# frame 0 thread 1 +#0 Object.gcd(a#Fixnum, b#Fixnum) at line gcd.rb:6 +# # finish +# quit diff --git a/test/data/help.cmd b/test/data/help.cmd new file mode 100644 index 0000000..4b4dc58 --- /dev/null +++ b/test/data/help.cmd @@ -0,0 +1,20 @@ +# $Id: setshow.cmd 298 2007-08-28 10:07:35Z rockyb $ +# This tests the functioning of some set/show debugger commands +set debuggertesting on +set autoeval off +set width 80 +### ******************************* +### *** help commands *** +### ******************************* +help foo +help set listsize +help show anno +help show foo +help info file +help info file all +help info file br +help info files + +# FIXME - the below should work +# help +# help step diff --git a/test/data/help.right b/test/data/help.right new file mode 100644 index 0000000..52b52ec --- /dev/null +++ b/test/data/help.right @@ -0,0 +1,21 @@ +Currently testing the debugger is on. +autoeval is off. +width is 80. +Undefined command: "foo". Try "help". +Set number of source lines to list by default. +Show annotation level. +0 == normal; 2 == output annotated suitably for use by programs that control +ruby-debug. +Invalid 'show' subcommand 'foo'. +Info about a particular file read in. + +After the file name is supplied, you can list file attributes that +you wish to see. + +Attributes include: "all", "basic", "breakpoint", "lines", "mtime", "path" +and "sha1". +Info about a particular file read in. +All file information available - breakpoints, lines, mtime, path, and sha1. +Info about a particular file read in. +Show trace line numbers. +File names and timestamps of files read in. diff --git a/test/data/history.right b/test/data/history.right new file mode 100644 index 0000000..be1e37f --- /dev/null +++ b/test/data/history.right @@ -0,0 +1,7 @@ +list +step +show args +show commands +set history save on +show history +quit unconditionally diff --git a/test/data/info-thread.cmd b/test/data/info-thread.cmd new file mode 100644 index 0000000..c07064b --- /dev/null +++ b/test/data/info-thread.cmd @@ -0,0 +1,13 @@ +# ******************************************************** +# This tests basic info thread commands +set debuggertesting on +set callstyle last +set autoeval off +info threads terse +info threads ver +info thread 1 t +info threads +info thread +help info thread +help info threads +q diff --git a/test/data/info-thread.right b/test/data/info-thread.right new file mode 100644 index 0000000..fd885bb --- /dev/null +++ b/test/data/info-thread.right @@ -0,0 +1,37 @@ +gcd.rb:4 +def gcd(a, b) +# # ******************************************************** +# # This tests basic info thread commands +# set debuggertesting on +Currently testing the debugger is on. +# set callstyle last +Frame call-display style is last. +# set autoeval off +autoeval is off. +# info threads terse ++ 1 # ./gcd.rb:4 +# info threads ver ++ 1 # + #0 at line gcd.rb:4 +# info thread 1 t ++ 1 # ./gcd.rb:4 +# info threads ++ 1 # ./gcd.rb:4 +# info thread ++ 1 # ./gcd.rb:4 +# help info thread +List info about thread NUM. + +If no thread number is given, we list info for all threads. 'terse' and 'verbose' +options are possible. If terse, just give summary thread name information. See +"help info threads" for more detail about this summary information. + +If 'verbose' appended to the end of the command, then the entire +stack trace is given for each thread. +# help info threads +information of currently-known threads. + +This information includes whether the thread is current (+), if it is +suspended ($), or ignored (!). The thread number and the top stack +item. If 'verbose' is given then the entire stack frame is shown. +# q diff --git a/test/data/info-var-bug2.cmd b/test/data/info-var-bug2.cmd new file mode 100644 index 0000000..a8bf887 --- /dev/null +++ b/test/data/info-var-bug2.cmd @@ -0,0 +1,5 @@ +step +info variables +quit + + diff --git a/test/data/info-var-bug2.right b/test/data/info-var-bug2.right new file mode 100644 index 0000000..1b8cdc6 --- /dev/null +++ b/test/data/info-var-bug2.right @@ -0,0 +1,10 @@ +info-var-bug2.rb:1 +s = '<%= PRODUCT[:name] %>' +# step +info-var-bug2.rb:2 +y = 0 +# info variables +s = "<%= PRODUCT[:name] %>" +self = main +y = nil +# quit diff --git a/test/data/info-var.cmd b/test/data/info-var.cmd new file mode 100644 index 0000000..de35cdb --- /dev/null +++ b/test/data/info-var.cmd @@ -0,0 +1,23 @@ +# *************************************************** +# Test handling of info variables when we have +# redefined inspect or to_s which give an error. +# *************************************************** +set debuggertesting on +# Go to where we have a bad "inspect" of a local variable +continue 36 +info variables +# Go to where we have a bad "inspect" and "to_s" of a local variable +continue 40 +info variables +break 31 +# The first time through, we can do inspect. +continue +info locals +# Now go to where we have a bad "inspect" of an class variable +continue +info locals +info variables +# Now go to where we have a bad "inspect" and "to_s" of an class variable +continue +info locals +quit diff --git a/test/data/info-var.right b/test/data/info-var.right new file mode 100644 index 0000000..72c97b3 --- /dev/null +++ b/test/data/info-var.right @@ -0,0 +1,52 @@ +info-var-bug.rb:1 +class Lousy_inspect +# # *************************************************** +# # Test handling of info variables when we have +# # redefined inspect or to_s which give an error. +# # *************************************************** +# set debuggertesting on +Currently testing the debugger is on. +# # Go to where we have a bad "inspect" of a local variable +# continue 36 +info-var-bug.rb:36 +return x +# info variables +self = main +x = # +# # Go to where we have a bad "inspect" and "to_s" of a local variable +# continue 40 +info-var-bug.rb:40 +return x +# info variables +self = main +x = *Error in evaluation* +# break 31 +Breakpoint 1 file ./info-var-bug.rb, line 31 +# # The first time through, we can do inspect. +# continue +Breakpoint 1 at info-var-bug.rb:31 +info-var-bug.rb:31 +@b = 5 +# info locals +a = 10 +# # Now go to where we have a bad "inspect" of an class variable +# continue +Breakpoint 1 at info-var-bug.rb:31 +info-var-bug.rb:31 +@b = 5 +# info locals +a = # +# info variables +a = # +self = # +@a = # +@@Const = "A constant" +@@var = "a class variable" +# # Now go to where we have a bad "inspect" and "to_s" of an class variable +# continue +Breakpoint 1 at info-var-bug.rb:31 +info-var-bug.rb:31 +@b = 5 +# info locals +*Error in evaluation* +# quit diff --git a/test/data/info.cmd b/test/data/info.cmd new file mode 100644 index 0000000..d0c2c4a --- /dev/null +++ b/test/data/info.cmd @@ -0,0 +1,21 @@ +# *************************************************** +# This tests info command handling +# *************************************************** +set debuggertesting on +set callstyle last +help info +info args +info line +info locals +info stack +info display +help info break +help info display +break 10 +break 12 +info break 10 +info break 1 +info break 1 2 +info break +info file ./gcd.rb break +quit diff --git a/test/data/info.right b/test/data/info.right new file mode 100644 index 0000000..67ff19e --- /dev/null +++ b/test/data/info.right @@ -0,0 +1,65 @@ +gcd.rb:4 +def gcd(a, b) +# # *************************************************** +# # This tests info command handling +# # *************************************************** +# set debuggertesting on +Currently testing the debugger is on. +# set callstyle last +Frame call-display style is last. +# help info +Generic command for showing things about the program being debugged. +-- +List of info subcommands: +-- +info args -- Argument variables of current stack frame +info breakpoints -- Status of user-settable breakpoints +info catch -- Exceptions that can be caught in the current stack frame +info display -- Expressions to display when program stops +info file -- Info about a particular file read in +info files -- File names and timestamps of files read in +info global_variables -- Global variables +info instance_variables -- Instance variables of the current stack frame +info line -- Line number and file name of current position in source file +info locals -- Local variables of the current stack frame +info program -- Execution status of the program +info stack -- Backtrace of the stack +info thread -- List info about thread NUM +info threads -- information of currently-known threads +info variables -- Local and instance variables of the current stack frame +# info args +# info line +Line 4 of "./gcd.rb" +# info locals +# info stack +--> #0 at line gcd.rb:4 +# info display +There are no auto-display expressions now. +# help info break +Status of user-settable breakpoints. +Without argument, list info about all breakpoints. With an +integer argument, list info on that breakpoint. +# help info display +Expressions to display when program stops. +# break 10 +Breakpoint 1 file ./gcd.rb, line 10 +# break 12 +Breakpoint 2 file ./gcd.rb, line 12 +# info break 10 +*** No breakpoints found among list given. +# info break 1 +Num Enb What + 1 y at ./gcd.rb:10 +# info break 1 2 +Num Enb What + 1 y at ./gcd.rb:10 + 2 y at ./gcd.rb:12 +# info break +Num Enb What + 1 y at ./gcd.rb:10 + 2 y at ./gcd.rb:12 +# info file ./gcd.rb break +File ./gcd.rb + breakpoint line numbers: +4 6 6 7 10 10 12 12 13 15 18 +# quit diff --git a/test/data/linetrace.cmd b/test/data/linetrace.cmd new file mode 100644 index 0000000..d2424e9 --- /dev/null +++ b/test/data/linetrace.cmd @@ -0,0 +1,6 @@ +# ******************************************************** +# This tests the 'linetrace' command. +# ******************************************************** +set basename on +set linetrace on +continue diff --git a/test/data/linetrace.right b/test/data/linetrace.right new file mode 100644 index 0000000..7aea2cf --- /dev/null +++ b/test/data/linetrace.right @@ -0,0 +1,32 @@ +gcd.rb:4 +def gcd(a, b) +# # ******************************************************** +# # This tests the 'linetrace' command. +# # ******************************************************** +# set basename on +basename is on. +# set linetrace on +line tracing is on. +# continue +Tracing(1):gcd.rb:18 gcd(3,5) +Tracing(1):gcd.rb:6 if a > b +Tracing(1):gcd.rb:6 if a > b +Tracing(1):gcd.rb:10 return nil if a <= 0 +Tracing(1):gcd.rb:10 return nil if a <= 0 +Tracing(1):gcd.rb:12 if a == 1 or b-a == 0 +Tracing(1):gcd.rb:12 if a == 1 or b-a == 0 +Tracing(1):gcd.rb:15 return gcd(b-a, a) +Tracing(1):gcd.rb:6 if a > b +Tracing(1):gcd.rb:6 if a > b +Tracing(1):gcd.rb:10 return nil if a <= 0 +Tracing(1):gcd.rb:10 return nil if a <= 0 +Tracing(1):gcd.rb:12 if a == 1 or b-a == 0 +Tracing(1):gcd.rb:12 if a == 1 or b-a == 0 +Tracing(1):gcd.rb:15 return gcd(b-a, a) +Tracing(1):gcd.rb:6 if a > b +Tracing(1):gcd.rb:6 if a > b +Tracing(1):gcd.rb:10 return nil if a <= 0 +Tracing(1):gcd.rb:10 return nil if a <= 0 +Tracing(1):gcd.rb:12 if a == 1 or b-a == 0 +Tracing(1):gcd.rb:12 if a == 1 or b-a == 0 +Tracing(1):gcd.rb:13 return a diff --git a/test/data/linetracep.cmd b/test/data/linetracep.cmd new file mode 100644 index 0000000..1d90ec0 --- /dev/null +++ b/test/data/linetracep.cmd @@ -0,0 +1,7 @@ +# ******************************************************** +# This tests the 'linetrace+' command. +# ******************************************************** +set basename on +set linetrace+ on +set linetrace on +continue diff --git a/test/data/linetracep.right b/test/data/linetracep.right new file mode 100644 index 0000000..d3a387e --- /dev/null +++ b/test/data/linetracep.right @@ -0,0 +1,25 @@ +gcd.rb:4 +def gcd(a, b) +# # ******************************************************** +# # This tests the 'linetrace+' command. +# # ******************************************************** +# set basename on +basename is on. +# set linetrace+ on +line tracing style is different consecutive lines. +# set linetrace on +line tracing is on. +# continue +Tracing(1):gcd.rb:18 gcd(3,5) +Tracing(1):gcd.rb:6 if a > b +Tracing(1):gcd.rb:10 return nil if a <= 0 +Tracing(1):gcd.rb:12 if a == 1 or b-a == 0 +Tracing(1):gcd.rb:15 return gcd(b-a, a) +Tracing(1):gcd.rb:6 if a > b +Tracing(1):gcd.rb:10 return nil if a <= 0 +Tracing(1):gcd.rb:12 if a == 1 or b-a == 0 +Tracing(1):gcd.rb:15 return gcd(b-a, a) +Tracing(1):gcd.rb:6 if a > b +Tracing(1):gcd.rb:10 return nil if a <= 0 +Tracing(1):gcd.rb:12 if a == 1 or b-a == 0 +Tracing(1):gcd.rb:13 return a diff --git a/test/data/list.cmd b/test/data/list.cmd new file mode 100644 index 0000000..a4efa3a --- /dev/null +++ b/test/data/list.cmd @@ -0,0 +1,19 @@ +# ******************************************************** +# This tests the 'list' command. +# ******************************************************** +set basename on +list +list +list +list +list - +list - +list - +list - +list 1 +list 20 +set listsize 5 +list 5 +list = +list 3-4 + diff --git a/test/data/list.right b/test/data/list.right new file mode 100644 index 0000000..cc12084 --- /dev/null +++ b/test/data/list.right @@ -0,0 +1,127 @@ +gcd.rb:4 +def gcd(a, b) +# # ******************************************************** +# # This tests the 'list' command. +# # ******************************************************** +# set basename on +basename is on. +# list +[-1, 8] in ./gcd.rb + 1 #!/usr/bin/env ruby + 2 + 3 # GCD. We assume positive numbers +=> 4 def gcd(a, b) + 5 # Make: a <= b + 6 if a > b + 7 a, b = [b, a] + 8 end +# list +[9, 18] in ./gcd.rb + 9 + 10 return nil if a <= 0 + 11 + 12 if a == 1 or b-a == 0 + 13 return a + 14 end + 15 return gcd(b-a, a) + 16 end + 17 + 18 gcd(3,5) +# list +[9, 18] in ./gcd.rb + 9 + 10 return nil if a <= 0 + 11 + 12 if a == 1 or b-a == 0 + 13 return a + 14 end + 15 return gcd(b-a, a) + 16 end + 17 + 18 gcd(3,5) +# list +[9, 18] in ./gcd.rb + 9 + 10 return nil if a <= 0 + 11 + 12 if a == 1 or b-a == 0 + 13 return a + 14 end + 15 return gcd(b-a, a) + 16 end + 17 + 18 gcd(3,5) +# list - +[-1, 8] in ./gcd.rb + 1 #!/usr/bin/env ruby + 2 + 3 # GCD. We assume positive numbers +=> 4 def gcd(a, b) + 5 # Make: a <= b + 6 if a > b + 7 a, b = [b, a] + 8 end +# list - +[-1, 8] in ./gcd.rb + 1 #!/usr/bin/env ruby + 2 + 3 # GCD. We assume positive numbers +=> 4 def gcd(a, b) + 5 # Make: a <= b + 6 if a > b + 7 a, b = [b, a] + 8 end +# list - +[-1, 8] in ./gcd.rb + 1 #!/usr/bin/env ruby + 2 + 3 # GCD. We assume positive numbers +=> 4 def gcd(a, b) + 5 # Make: a <= b + 6 if a > b + 7 a, b = [b, a] + 8 end +# list - +[-1, 8] in ./gcd.rb + 1 #!/usr/bin/env ruby + 2 + 3 # GCD. We assume positive numbers +=> 4 def gcd(a, b) + 5 # Make: a <= b + 6 if a > b + 7 a, b = [b, a] + 8 end +# list 1 +[-4, 5] in ./gcd.rb + 1 #!/usr/bin/env ruby + 2 + 3 # GCD. We assume positive numbers +=> 4 def gcd(a, b) + 5 # Make: a <= b +# list 20 +[15, 24] in ./gcd.rb + 15 return gcd(b-a, a) + 16 end + 17 + 18 gcd(3,5) +# set listsize 5 +Number of source lines to list by default is 5. +# list 5 +[3, 7] in ./gcd.rb + 3 # GCD. We assume positive numbers +=> 4 def gcd(a, b) + 5 # Make: a <= b + 6 if a > b + 7 a, b = [b, a] +# list = +[2, 6] in ./gcd.rb + 2 + 3 # GCD. We assume positive numbers +=> 4 def gcd(a, b) + 5 # Make: a <= b + 6 if a > b +# list 3-4 +[3, 4] in ./gcd.rb + 3 # GCD. We assume positive numbers +=> 4 def gcd(a, b) +# diff --git a/test/data/method.cmd b/test/data/method.cmd new file mode 100644 index 0000000..2e9feb8 --- /dev/null +++ b/test/data/method.cmd @@ -0,0 +1,10 @@ +# ******************************************************** +# This tests the 'method' command +# ******************************************************** +set debuggertesting on +set autoeval off +b 11 +c +method Mine +m iv me +quit diff --git a/test/data/method.right b/test/data/method.right new file mode 100644 index 0000000..343bab8 --- /dev/null +++ b/test/data/method.right @@ -0,0 +1,21 @@ +classes.rb:1 +class Mine +# # ******************************************************** +# # This tests the 'method' command +# # ******************************************************** +# set debuggertesting on +Currently testing the debugger is on. +# set autoeval off +autoeval is off. +# b 11 +Breakpoint 1 file ./classes.rb, line 11 +# c +Breakpoint 1 at classes.rb:11 +classes.rb:11 +metoo = Mine(new) +# method Mine +mymethod + +# m iv me +@myvar = "init" +# quit diff --git a/test/data/methodsig.cmd b/test/data/methodsig.cmd new file mode 100644 index 0000000..e3445a8 --- /dev/null +++ b/test/data/methodsig.cmd @@ -0,0 +1,10 @@ +# ******************************************************** +# This tests the 'method' command +# ******************************************************** +set debuggertesting on +set autoeval off +b 3 +c +method sig initialize +method sig mymethod +quit diff --git a/test/data/methodsig.right b/test/data/methodsig.right new file mode 100644 index 0000000..5553b57 --- /dev/null +++ b/test/data/methodsig.right @@ -0,0 +1,20 @@ +classes.rb:1 +class Mine +# # ******************************************************** +# # This tests the 'method' command +# # ******************************************************** +# set debuggertesting on +Currently testing the debugger is on. +# set autoeval off +autoeval is off. +# b 3 +Breakpoint 1 file ./classes.rb, line 3 +# c +Breakpoint 1 at classes.rb:3 +classes.rb:3 +@myvar = 'init' +# method sig initialize +Mine#initialize() +# method sig mymethod +Mine#mymethod(a, b=5, &block) +# quit diff --git a/test/data/noquit.right b/test/data/noquit.right new file mode 100644 index 0000000..b56a50c --- /dev/null +++ b/test/data/noquit.right @@ -0,0 +1 @@ +The program has finished and will be restarted. diff --git a/test/data/output.cmd b/test/data/output.cmd new file mode 100644 index 0000000..1c17bde --- /dev/null +++ b/test/data/output.cmd @@ -0,0 +1,6 @@ +# ******************************************************** +# This tests the "starting" annotation +# ******************************************************** +step +step +quit diff --git a/test/data/output.right b/test/data/output.right new file mode 100644 index 0000000..b70dbeb --- /dev/null +++ b/test/data/output.right @@ -0,0 +1,31 @@ +starting +stopped +breakpoints +No breakpoints. + +stack +--> #0 at line output.rb:1 + +variables +self = main + +source output.rb:1 +puts "one" +# # ******************************************************** +# # This tests the "starting" annotation +# # ******************************************************** +# step +starting +one +stopped +stack +--> #0 at line output.rb:2 + +variables +self = main + +source output.rb:2 +puts "two" +# step +starting +two diff --git a/test/data/pm-bug.cmd b/test/data/pm-bug.cmd new file mode 100644 index 0000000..45a38a0 --- /dev/null +++ b/test/data/pm-bug.cmd @@ -0,0 +1,7 @@ +# ******************************************************** +# This tests the edit command +# ******************************************************** +set debuggertesting on +# Tracker #22118 +i v +quit diff --git a/test/data/pm-bug.right b/test/data/pm-bug.right new file mode 100644 index 0000000..9ce6385 --- /dev/null +++ b/test/data/pm-bug.right @@ -0,0 +1,12 @@ +pm-bug.rb:1 +a = 1 +# # ******************************************************** +# # This tests the edit command +# # ******************************************************** +# set debuggertesting on +Currently testing the debugger is on. +# # Tracker #22118 +# i v +a = nil +self = main +# quit diff --git a/test/data/post-mortem-next.cmd b/test/data/post-mortem-next.cmd new file mode 100644 index 0000000..09663c9 --- /dev/null +++ b/test/data/post-mortem-next.cmd @@ -0,0 +1,8 @@ +# ****************************************************** +# This tests running "next" over code that post-mortems +# ****************************************************** +set debuggertesting on +next 2 +next +quit + diff --git a/test/data/post-mortem-next.right b/test/data/post-mortem-next.right new file mode 100644 index 0000000..0ecb616 --- /dev/null +++ b/test/data/post-mortem-next.right @@ -0,0 +1,14 @@ +pm.rb:3 +def zero_div +# # ****************************************************** +# # This tests running "next" over code that post-mortems +# # ****************************************************** +# set debuggertesting on +Currently testing the debugger is on. +# next 2 +pm.rb:8 +zero_div +# next +pm.rb:5 +1/0 +# quit diff --git a/test/data/post-mortem-osx.right b/test/data/post-mortem-osx.right new file mode 100644 index 0000000..afa520c --- /dev/null +++ b/test/data/post-mortem-osx.right @@ -0,0 +1,31 @@ +pm.rb:3 +def zero_div +# # *************************************************** +# # This tests post-mortem handling. +# # *************************************************** +# set debuggertesting on +Currently testing the debugger is on. +# continue +pm.rb:5 +1/0 +# # Should have got a divide by 0 error +# info program +The program crashed. +Exception: # +# where +--> #0 / at line pm.rb:5 + #1 at line pm.rb:8 +# up +#1 at line pm.rb:8 +# p x +2 +# help +Type 'help ' for help on a specific command + +Available commands: +backtrace delete edit frame list ps restart source undisplay +break disable enable help method putl save thread up +catch display eval info p quit set tmate var +condition down exit irb pp reload show trace where + +# quit diff --git a/test/data/post-mortem.cmd b/test/data/post-mortem.cmd new file mode 100644 index 0000000..d89f0f1 --- /dev/null +++ b/test/data/post-mortem.cmd @@ -0,0 +1,13 @@ +# *************************************************** +# This tests post-mortem handling. +# *************************************************** +set debuggertesting on +continue +# Should have got a divide by 0 error +info program +where +up +p x +help +quit + diff --git a/test/data/post-mortem.right b/test/data/post-mortem.right new file mode 100644 index 0000000..d136ee1 --- /dev/null +++ b/test/data/post-mortem.right @@ -0,0 +1,32 @@ +pm.rb:3 +def zero_div +# # *************************************************** +# # This tests post-mortem handling. +# # *************************************************** +# set debuggertesting on +Currently testing the debugger is on. +# continue +pm.rb:5 +1/0 +# # Should have got a divide by 0 error +# info program +The program crashed. +Exception: # +# where +--> #0 / at line pm.rb:5 + #1 at line pm.rb:8 +# up +#1 at line pm.rb:8 +# p x +2 +# help +Type 'help ' for help on a specific command + +Available commands: +backtrace delete enable info p reload source var +break disable eval irb pp restart thread where +catch display exit kill ps save trace +condition down frame list putl set undisplay +continue edit help method quit show up + +# quit diff --git a/test/data/quit.cmd b/test/data/quit.cmd new file mode 100644 index 0000000..e2a69b7 --- /dev/null +++ b/test/data/quit.cmd @@ -0,0 +1,6 @@ +# *************************************************** +# This tests the quit. +# *************************************************** +set debuggertesting on +# FIXME need to test --no-quit. +quit diff --git a/test/data/quit.right b/test/data/quit.right new file mode 100644 index 0000000..e69de29 diff --git a/test/data/raise.cmd b/test/data/raise.cmd new file mode 100644 index 0000000..ad1eaee --- /dev/null +++ b/test/data/raise.cmd @@ -0,0 +1,11 @@ +# ******************************************************** +# This tests that the debugger doesn't step into itself +# when the application doesn't terminate the right way. +# ******************************************************** +set debuggertesting on +catch x +catch ZeroDivisionError +info catch +catch 5 +step +quit diff --git a/test/data/raise.right b/test/data/raise.right new file mode 100644 index 0000000..6c86c04 --- /dev/null +++ b/test/data/raise.right @@ -0,0 +1,26 @@ +raise.rb:3 +raise "abc" +# # ******************************************************** +# # This tests that the debugger doesn't step into itself +# # when the application doesn't terminate the right way. +# # ******************************************************** +# set debuggertesting on +Currently testing the debugger is on. +# catch x +NameError Exception: undefined local variable or method `x' for main:Object +# catch ZeroDivisionError +Catch exception ZeroDivisionError. +# info catch +ZeroDivisionError +# catch 5 +Warning 5 is not known to be a Class +Catch exception 5. +# step + ./raise.rb:3 + ./tdebug.rb:61:in `debug_load' + ./tdebug.rb:61:in `debug_program' + ./tdebug.rb:251 + ../rdbg.rb:23:in `load' + ../rdbg.rb:23:in `runner' + ../rdbg.rb:32 +Uncaught exception: abc diff --git a/test/data/save.cmd b/test/data/save.cmd new file mode 100644 index 0000000..69dae60 --- /dev/null +++ b/test/data/save.cmd @@ -0,0 +1,33 @@ +# This tests the functioning of some set/show debugger commands +set debuggertesting on +### ******************************* +### *** save/source commands *** +### ******************************* +######################################## +### test args and baseneme... +######################################## +set basename off +set autoeval off +# Should have nothing set +info break +info catch +# Should save nothing +save temp +eval File.open("temp").readlines +# Should read in nothing +source temp +info break +# Now try saving something interesting +break 10 +catch RuntimeError +save temp +eval File.open("temp").readlines +# FIXME: The below is broken +## Change parameters above +## catch RuntimeError off +## info catch +##set listsize 55 +source temp +##info break +##info catch +##show listsize diff --git a/test/data/save.right b/test/data/save.right new file mode 100644 index 0000000..83599d0 --- /dev/null +++ b/test/data/save.right @@ -0,0 +1,59 @@ +gcd.rb:4 +def gcd(a, b) +# # This tests the functioning of some set/show debugger commands +# set debuggertesting on +Currently testing the debugger is on. +# ### ******************************* +# ### *** save/source commands *** +# ### ******************************* +# ######################################## +# ### test args and baseneme... +# ######################################## +# set basename off +basename is off. +# set autoeval off +autoeval is off. +# # Should have nothing set +# info break +No breakpoints. +# info catch +No exceptions set to be caught. +# # Should save nothing +# save temp +Saved to 'temp' +# eval File.open("temp").readlines +["set autoeval off\n", "set basename off\n", "set debuggertesting on\n", "set autolist off\n", "set autoirb off\n"] +# # Should read in nothing +# source temp +autoeval is off. +basename is off. +Currently testing the debugger is on. +autolist is off. +autoirb is off. +# info break +No breakpoints. +# # Now try saving something interesting +# break 10 +Breakpoint 1 file ./gcd.rb, line 10 +# catch RuntimeError +Catch exception RuntimeError. +# save temp +Saved to 'temp' +# eval File.open("temp").readlines +["break ./gcd.rb:10\n", "catch RuntimeError\n", "set autoeval off\n", "set basename on\n", "set debuggertesting on\n", "set autolist off\n", "set autoirb off\n"] +# # FIXME: The below is broken +# ## Change parameters above +# ## catch RuntimeError off +# ## info catch +# ##set listsize 55 +# source temp +Breakpoint 2 file gcd.rb, line 10 +Catch exception RuntimeError. +autoeval is off. +basename is on. +Currently testing the debugger is on. +autolist is off. +autoirb is off. +# ##info break +# ##info catch +# ##show listsize diff --git a/test/data/setshow.cmd b/test/data/setshow.cmd new file mode 100644 index 0000000..b842821 --- /dev/null +++ b/test/data/setshow.cmd @@ -0,0 +1,56 @@ +# This tests the functioning of some set/show debugger commands +set debuggertesting on +### ******************************* +### *** Set/show commands *** +### ******************************* +######################################## +### test args and baseneme... +######################################## +set args this is a test +show args +show basename +set basename foo +show base +set basename off +show basename +set basename 0 +show basename +set basename 1 +show basename +######################################## +### test listsize tests... +######################################## +show listsize +show listsi +set listsize abc +set listsize -20 +######################################## +### test linetrace... +######################################## +set linetrace on +show linetrace +set linetrace off +show linetrace +######################################## +### show history +######################################## +set history +set history size 10 +show history size +set history save off +show history save +set history save 1 +show history save +#### Test 'autoeval'... +set autoeval on +puts 'printed via autoeval' +set autoeval off +puts 'autoeval should not run this' +#### Test 'callstyle'... +set callstyle +set callstyle short +set callstyle last +set callstyle tracked +set callstyle foo + + diff --git a/test/data/setshow.right b/test/data/setshow.right new file mode 100644 index 0000000..63aca57 --- /dev/null +++ b/test/data/setshow.right @@ -0,0 +1,97 @@ +gcd.rb:4 +def gcd(a, b) +# # This tests the functioning of some set/show debugger commands +# set debuggertesting on +Currently testing the debugger is on. +# ### ******************************* +# ### *** Set/show commands *** +# ### ******************************* +# ######################################## +# ### test args and baseneme... +# ######################################## +# set args this is a test +Argument list to give program being debugged when it is started is "this is a test". +# show args +Argument list to give program being debugged when it is started is "this is a test". +# show basename +basename is on. +# set basename foo +Expecting 'on', 1, 'off', or 0. Got: foo. +# show base +basename is on. +# set basename off +basename is off. +# show basename +basename is off. +# set basename 0 +basename is off. +# show basename +basename is off. +# set basename 1 +basename is on. +# show basename +basename is on. +# ######################################## +# ### test listsize tests... +# ######################################## +# show listsize +Number of source lines to list by default is 10. +# show listsi +Number of source lines to list by default is 10. +# set listsize abc +Set listsize argument 'abc' needs to be a number. +# set listsize -20 +Set listsize argument '-20' needs to at least 1. +# ######################################## +# ### test linetrace... +# ######################################## +# set linetrace on +line tracing is on. +# show linetrace +line tracing is on. +# set linetrace off +line tracing is off. +# show linetrace +line tracing is off. +# ######################################## +# ### show history +# ######################################## +# set history +Need two parameters for 'set history'; got 0. +# set history size 10 +Debugger history size is 10 +# show history size +Debugger history size is 10 +# set history save off +Saving of history save is off. +# show history save +Saving of history save is off. +# set history save 1 +Saving of history save is on. +# show history save +Saving of history save is on. +# #### Test 'autoeval'... +# set autoeval on +autoeval is on. +# puts 'printed via autoeval' +printed via autoeval +nil +# set autoeval off +autoeval is off. +# puts 'autoeval should not run this' +*** Unknown command: "puts 'autoeval should not run this'". Try "help". +# #### Test 'callstyle'... +# set callstyle +Invalid call style . Should be one of: 'short', 'last', or 'tracked'. +Frame call-display style is last. +# set callstyle short +Frame call-display style is short. +# set callstyle last +Frame call-display style is last. +# set callstyle tracked +Frame call-display style is tracked. +# set callstyle foo +Invalid call style foo. Should be one of: 'short', 'last', or 'tracked'. +Frame call-display style is tracked. +# +# diff --git a/test/data/source.cmd b/test/data/source.cmd new file mode 100644 index 0000000..71716f3 --- /dev/null +++ b/test/data/source.cmd @@ -0,0 +1,5 @@ +# Test the source command +# rdebug-save has breakpoint commands +set debuggertesting on +source ./rdebug-save.1 +quit diff --git a/test/data/source.right b/test/data/source.right new file mode 100644 index 0000000..40d0cf8 --- /dev/null +++ b/test/data/source.right @@ -0,0 +1,15 @@ +gcd.rb:4 +def gcd(a, b) +# # Test the source command +# # rdebug-save has breakpoint commands +# set debuggertesting on +Currently testing the debugger is on. +# source ./rdebug-save.1 +Breakpoint 1 file gcd.rb, line 10 +Breakpoint 2 file gcd.rb, line 12 +autoeval is on. +basename is off. +Currently testing the debugger is on. +autolist is off. +autoirb is off. +# quit diff --git a/test/data/stepping.cmd b/test/data/stepping.cmd new file mode 100644 index 0000000..f9a7473 --- /dev/null +++ b/test/data/stepping.cmd @@ -0,0 +1,21 @@ +# *************************************************** +# This tests step, next, finish and continue +# *************************************************** +set debuggertesting on +set callstyle last +next +where +step a +set forcestep on +step- ; step- +set forcestep off +where +n 2 +step+ +where +step 3 +step+ +where +next+ +# finish +quit diff --git a/test/data/stepping.right b/test/data/stepping.right new file mode 100644 index 0000000..7791547 --- /dev/null +++ b/test/data/stepping.right @@ -0,0 +1,50 @@ +gcd.rb:4 +def gcd(a, b) +# # *************************************************** +# # This tests step, next, finish and continue +# # *************************************************** +# set debuggertesting on +Currently testing the debugger is on. +# set callstyle last +Frame call-display style is last. +# next +gcd.rb:18 +gcd(3,5) +# where +--> #0 at line gcd.rb:18 +# step a +Step argument 'a' needs to be a number. +# set forcestep on +force-stepping is on. +# step- ; step- +gcd.rb:6 +if a > b +# set forcestep off +force-stepping is off. +# where +--> #0 Object.gcd(a#Fixnum, b#Fixnum) at line gcd.rb:6 + #1 at line gcd.rb:18 +# n 2 +gcd.rb:10 +return nil if a <= 0 +# step+ +gcd.rb:12 +if a == 1 or b-a == 0 +# where +--> #0 Object.gcd(a#Fixnum, b#Fixnum) at line gcd.rb:12 + #1 at line gcd.rb:18 +# step 3 +gcd.rb:6 +if a > b +# step+ +gcd.rb:10 +return nil if a <= 0 +# where +--> #0 Object.gcd(a#Fixnum, b#Fixnum) at line gcd.rb:10 + #1 Object.-(a#Fixnum, b#Fixnum) at line gcd.rb:15 + #2 at line gcd.rb:18 +# next+ +gcd.rb:12 +if a == 1 or b-a == 0 +# # finish +# quit diff --git a/test/data/test-init-cygwin.right b/test/data/test-init-cygwin.right new file mode 100644 index 0000000..8d683f3 --- /dev/null +++ b/test/data/test-init-cygwin.right @@ -0,0 +1,7 @@ +gcd-dbg.rb:18 +if a > b +(rdb:1) p Debugger::PROG_SCRIPT +"./gcd-dbg.rb" +(rdb:1) show args +Argument list to give program being debugged when it is started is "5". +(rdb:1) quit unconditionally diff --git a/test/data/test-init-osx.right b/test/data/test-init-osx.right new file mode 100644 index 0000000..a50319c --- /dev/null +++ b/test/data/test-init-osx.right @@ -0,0 +1,4 @@ +gcd-dbg.rb:18 +if a > b +"./gcd-dbg.rb" +Argument list to give program being debugged when it is started is "5". diff --git a/test/data/test-init.right b/test/data/test-init.right new file mode 100644 index 0000000..981c233 --- /dev/null +++ b/test/data/test-init.right @@ -0,0 +1,5 @@ +gcd-dbg.rb:18 +if a > b +(rdb:1) "./gcd-dbg.rb" +(rdb:1) Argument list to give program being debugged when it is started is "5". +(rdb:1) \ No newline at end of file diff --git a/test/data/trace.right b/test/data/trace.right new file mode 100644 index 0000000..ada9008 --- /dev/null +++ b/test/data/trace.right @@ -0,0 +1,23 @@ +Tracing(1):gcd.rb:4 def gcd(a, b) +Tracing(1):gcd.rb:18 gcd(3,5) +Tracing(1):gcd.rb:6 if a > b +Tracing(1):gcd.rb:6 if a > b +Tracing(1):gcd.rb:10 return nil if a <= 0 +Tracing(1):gcd.rb:10 return nil if a <= 0 +Tracing(1):gcd.rb:12 if a == 1 or b-a == 0 +Tracing(1):gcd.rb:12 if a == 1 or b-a == 0 +Tracing(1):gcd.rb:15 return gcd(b-a, a) +Tracing(1):gcd.rb:6 if a > b +Tracing(1):gcd.rb:6 if a > b +Tracing(1):gcd.rb:10 return nil if a <= 0 +Tracing(1):gcd.rb:10 return nil if a <= 0 +Tracing(1):gcd.rb:12 if a == 1 or b-a == 0 +Tracing(1):gcd.rb:12 if a == 1 or b-a == 0 +Tracing(1):gcd.rb:15 return gcd(b-a, a) +Tracing(1):gcd.rb:6 if a > b +Tracing(1):gcd.rb:6 if a > b +Tracing(1):gcd.rb:10 return nil if a <= 0 +Tracing(1):gcd.rb:10 return nil if a <= 0 +Tracing(1):gcd.rb:12 if a == 1 or b-a == 0 +Tracing(1):gcd.rb:12 if a == 1 or b-a == 0 +Tracing(1):gcd.rb:13 return a diff --git a/test/dollar-0.rb b/test/dollar-0.rb new file mode 100755 index 0000000..9955e43 --- /dev/null +++ b/test/dollar-0.rb @@ -0,0 +1,5 @@ +#!/usr/bin/env ruby +# A test to see that rdebug set's $0 properly. +puts $0 +puts __FILE__ + diff --git a/test/gcd-dbg-nox.rb b/test/gcd-dbg-nox.rb new file mode 100644 index 0000000..5b84c6e --- /dev/null +++ b/test/gcd-dbg-nox.rb @@ -0,0 +1,31 @@ +# This program is *NOT* supposed to be executable, but called +# via ruby (in order to test that restart provides a funky $:). +# This program is used to test that 'restart' works when we didn't call +# the debugger initially. + +TOP_SRC_DIR = File.join(File.expand_path(File.dirname(__FILE__), '..')) unless + defined?(TOP_SRC_DIR) + +$:.unshift File.join(TOP_SRC_DIR, 'ext') +$:.unshift File.join(TOP_SRC_DIR, 'lib') +$:.unshift File.join(TOP_SRC_DIR, 'cli') +require 'ruby-debug' +Debugger.init + +# GCD. We assume positive numbers +def gcd(a, b) + # Make: a <= b + debugger + if a > b + a, b = [b, a] + end + + return nil if a <= 0 + + if a == 1 or b-a == 0 + return a + end + return gcd(b-a, a) +end + +gcd(3,5) diff --git a/test/gcd-dbg.rb b/test/gcd-dbg.rb new file mode 100755 index 0000000..717518b --- /dev/null +++ b/test/gcd-dbg.rb @@ -0,0 +1,30 @@ +#!/usr/bin/env ruby +# This program is used to test that 'restart' works when we didn't call +# the debugger initially. + +TOP_SRC_DIR = File.join(File.expand_path(File.dirname(__FILE__), "..")) unless + defined?(TOP_SRC_DIR) + +$:.unshift File.join(TOP_SRC_DIR, "ext") +$:.unshift File.join(TOP_SRC_DIR, "lib") +$:.unshift File.join(TOP_SRC_DIR, "cli") +require 'ruby-debug' +Debugger.start + +# GCD. We assume positive numbers +def gcd(a, b) + # Make: a <= b + debugger + if a > b + a, b = [b, a] + end + + return nil if a <= 0 + + if a == 1 or b-a == 0 + return a + end + return gcd(b-a, a) +end + +gcd(3,5) diff --git a/test/gcd.rb b/test/gcd.rb new file mode 100644 index 0000000..184b8df --- /dev/null +++ b/test/gcd.rb @@ -0,0 +1,18 @@ +#!/usr/bin/env ruby + +# GCD. We assume positive numbers +def gcd(a, b) + # Make: a <= b + if a > b + a, b = [b, a] + end + + return nil if a <= 0 + + if a == 1 or b-a == 0 + return a + end + return gcd(b-a, a) +end + +gcd(3,5) diff --git a/test/helper.rb b/test/helper.rb new file mode 100644 index 0000000..a675869 --- /dev/null +++ b/test/helper.rb @@ -0,0 +1,143 @@ +# Some common routines used in testing. + +require 'fileutils' +require 'yaml' +# require 'diff/lcs' +# require 'diff/lcs/hunk' + +# begin require 'rubygems' rescue LoadError end +# require 'ruby-debug'; Debugger.start + +module TestHelper + + # FIXME: turn args into a hash. + def run_debugger(testname, args='', outfile=nil, filter=nil, old_code=false, + debug_pgm='tdebug.rb') + rightfile = File.join('data', "#{testname}.right") + + outfile = "#{testname}.out" unless outfile + + if File.exists?(outfile) + FileUtils.rm(outfile) + end + + ENV['RDEBUG'] = debug_pgm + + if old_code + cmd = "/bin/sh #{File.join('..', 'runner.sh')} #{args} >#{outfile}" + else + cmd = "#{"#{load_ruby} #{load_params} "}../rdbg.rb #{args} > #{outfile}" + end + puts "'#{cmd}'" if $DEBUG + output = `#{cmd}` + + got_lines = File.read(outfile).split(/\n/) + correct_lines = File.read(rightfile).split(/\n/) + filter.call(got_lines, correct_lines) if filter + if cheap_diff(got_lines, correct_lines) + FileUtils.rm(outfile) + return true + end + return false + end + + def cheap_diff(got_lines, correct_lines) + if $DEBUG + got_lines.each_with_index do |line, i| + printf "%3d %s\n", i+1, line + end + end + correct_lines.each_with_index do |line, i| + correct_lines[i].chomp! + if got_lines[i] != correct_lines[i] + puts "difference found at line #{i+1}" + puts "got : #{got_lines[i]}" + puts "need: #{correct_lines[i]}" + return false + end + end + if correct_lines.size != got_lines.size + puts("difference in number of lines: " + + "#{correct_lines.size} vs. #{got_lines.size}") + return false + end + return true + end + + # FIXME: using this causes the same test to get run several times + # and some tests fail probably because of a lack of environment isolation. + # Many tests follow a basic pattern: run the debugger with a given + # debugger script and compare output produced. The following creates + # this kind of test. + def add_test(base_name, src_dir, script_name=nil, cmd=nil, test_name=nil) + puts "+++ Adding #{base_name} ++++" if $DEBUG + test_name = base_name unless test_name + script_name = File.join('data', test_name + '.cmd') unless script_name + cmd = 'gcd.rb 3 5' unless cmd + eval <<-EOF + def test_#{test_name} + Dir.chdir(\"#{src_dir}\") do + assert_equal(true, + run_debugger(\"#{base_name}\", + \"--script #{script_name} -- #{cmd}\")) + end + end + EOF + end + module_function :add_test + + # Adapted from the Ruby Cookbook, Section 6.10: Comparing two files. + # def diff_as_string(rightfile, checkfile, format=:unified, context_lines=3) + # right_data = File.read(rightfile) + # check_data = File.read(checkfile) + # output = '' + # diffs = Diff::LCS.diff(right_data, check_data) + # return output if diffs.empty? + # oldhunk = hunk = nil + # file_length_difference = 0 + # diffs.each do |piece| + # begin + # hunk = Diff::LCS::Hunk.new(right_data, check_data, piece, + # context_lines, file_length_difference) + # next unless oldhunk + # + # # Hunks may overlap, which is why we need to be careful when our + # # diff includes lines of context. Otherwise, we might print + # # redundant lines. + # if (context_lines > 0) and hunk.overlaps?(oldhunk) + # hunk.unshift(oldhunk) + # else + # output << oldhunk.diff(format) + # end + # ensure + # oldhunk = hunk + # output << '\n' + # end + # end + + # # Handle the last remaining hunk + # output << oldhunk.diff(format) << '\n' + # end + + # Loads key from the _config_._yaml_ file. + def config_load(key, may_be_nil=false, default_value='') + conf = File.join('config.private.yaml') # try private first + conf = File.join('config.yaml') unless File.exists?(conf) + value = YAML.load_file(conf)[key] + assert_not_nil(value, "#{key} is set in config.yaml") unless may_be_nil + value || default_value + end + module_function :config_load + + def load_ruby + config_load('ruby', true) + end + module_function :load_ruby + + def load_params + config_load('ruby_params', true) + end + module_function :load_params + +end + diff --git a/test/info-var-bug.rb b/test/info-var-bug.rb new file mode 100644 index 0000000..9250e6e --- /dev/null +++ b/test/info-var-bug.rb @@ -0,0 +1,47 @@ +class Lousy_inspect + attr_accessor :var + def inspect # An unhelpful inspect + throw "Foo" # Raises an exception + end + def initialize + @var = 'initialized' + end +end +class Lousy_inspect_and_to_s + attr_accessor :var + def inspect # An unhelpful inspect + throw "Foo" # Raises an exception + end + def to_s # An unhelpful to_s + throw "bar" # Raises an exception + end + def initialize + @var = 'initialized' # Something to inspect + end +end + +# Something that will be passed objects with +# bad inspect or to_s methods +class UnsuspectingClass + @@Const = 'A constant' + @@var = 'a class variable' + def initialize(a) + @a = a # "info locals" will try to use + # inspect or to_s here + @b = 5 + end +end +def test_Lousy_inspect + x = Lousy_inspect.new + return x +end +def test_lousy_inspect_and_to_s + x = Lousy_inspect_and_to_s.new + return x +end +x = test_Lousy_inspect +y = test_lousy_inspect_and_to_s +UnsuspectingClass.new(10) +UnsuspectingClass.new(x) +UnsuspectingClass.new(y) +y = 2 diff --git a/test/info-var-bug2.rb b/test/info-var-bug2.rb new file mode 100644 index 0000000..83d474e --- /dev/null +++ b/test/info-var-bug2.rb @@ -0,0 +1,2 @@ +s = '<%= PRODUCT[:name] %>' +y = 0 diff --git a/test/null.rb b/test/null.rb new file mode 100644 index 0000000..47f0a27 --- /dev/null +++ b/test/null.rb @@ -0,0 +1 @@ +# Nothing here. Move along. diff --git a/test/output.rb b/test/output.rb new file mode 100644 index 0000000..69fde1b --- /dev/null +++ b/test/output.rb @@ -0,0 +1,2 @@ +puts "one" +puts "two" diff --git a/test/pm-base.rb b/test/pm-base.rb new file mode 100755 index 0000000..8d29f2f --- /dev/null +++ b/test/pm-base.rb @@ -0,0 +1,22 @@ +#!/usr/bin/env ruby +# Test post-mortem handling using only ruby-debug-base. +src_dir = File.dirname(__FILE__) +%w(ext lib cli).each do |dir| + $:.unshift File.join(src_dir, '..', dir) +end +require 'ruby-debug-base' + +class CommandProcessor + def at_line(context, file, line) + puts 'file: %s, line: %s' % [ File.basename(file), line ] + exit! + end +end + +Debugger.start(:post_mortem => true) +Debugger.handler = CommandProcessor.new +def zero_div + 1/0 +end +zero_div + diff --git a/test/pm-bug.rb b/test/pm-bug.rb new file mode 100644 index 0000000..3ced249 --- /dev/null +++ b/test/pm-bug.rb @@ -0,0 +1,3 @@ +a = 1 +@x = 2 +raise diff --git a/test/pm.rb b/test/pm.rb new file mode 100755 index 0000000..f8f0014 --- /dev/null +++ b/test/pm.rb @@ -0,0 +1,11 @@ +#!/ursr/bin/env ruby +# Test Debugger.catchpoint and post-mortem handling +def zero_div + x = 5 + 1/0 +end +x = 2 +zero_div +raise RuntimeError +x = 3 + diff --git a/test/raise.rb b/test/raise.rb new file mode 100755 index 0000000..c6f3b51 --- /dev/null +++ b/test/raise.rb @@ -0,0 +1,3 @@ +#!/usr/bin/env ruby + +raise "abc" diff --git a/test/rdebug-save.1 b/test/rdebug-save.1 new file mode 100644 index 0000000..f759154 --- /dev/null +++ b/test/rdebug-save.1 @@ -0,0 +1,7 @@ +break gcd.rb:10 +break gcd.rb:12 if a > b +set autoeval on +set basename off +set debuggertesting off +set autolist off +set autoirb off diff --git a/test/runall b/test/runall new file mode 100755 index 0000000..634981b --- /dev/null +++ b/test/runall @@ -0,0 +1,12 @@ +#!/usr/bin/env ruby +#-*- Ruby -*- +debug_opt = '-d ' if $DEBUG or 'd' == ARGV[0] +for file in Dir.glob("test-*.rb") do + puts "=" * 50 + puts "== running #{file}..." + system("ruby #{file}"); +end +if ARGV[0] == "really" + system("(cd test && ruby #{debug_opt}runall)") + system("(cd examples && ruby #{debug_opt}runall)") +end diff --git a/test/tdebug.rb b/test/tdebug.rb new file mode 100755 index 0000000..ae13f3e --- /dev/null +++ b/test/tdebug.rb @@ -0,0 +1,252 @@ +#!/usr/bin/env ruby +# -*- Ruby -*- +# This is a hacked down copy of rdebug which can be used for testing +# FIXME: use the real rdebug script - DRY. + +require 'stringio' +require 'rubygems' +require 'optparse' +require "ostruct" + +TOP_SRC_DIR = File.join(File.dirname(__FILE__), "..") unless + defined?(TOP_SRC_DIR) + +$:.unshift File.join(TOP_SRC_DIR, "ext") +$:.unshift File.join(TOP_SRC_DIR, "lib") +$:.unshift File.join(TOP_SRC_DIR, "cli") + +def debug_program(options) + # Make sure Ruby script syntax checks okay. + # Otherwise we get a load message that looks like rdebug has + # a problem. + output = `ruby -c "#{Debugger::PROG_SCRIPT}" 2>&1` + if $?.exitstatus != 0 and RUBY_PLATFORM !~ /mswin/ + puts output + exit $?.exitstatus + end + print "\032\032starting\n" if Debugger.annotate and Debugger.annotate > 2 + unless options.no_rewrite_program + # Set $0 so things like __FILE == $0 work. + # A more reliable way to do this is to put $0 = __FILE__ *after* + # loading the script to be debugged. For this, adding a debug hook + # for the first time and then switching to the debug hook that's + # normally used would be helpful. Doing this would also help other + # first-time initializations such as reloading debugger state + # after a restart. + + # However This is just a little more than I want to take on right + # now, so I think I'll stick with the slightly hacky approach. + $RDEBUG_0 = $0 + + # cygwin does some sort of funky truncation on $0 ./abcdef => ./ab + # probably something to do with 3-letter extension truncation. + # The hacky workaround is to do slice assignment. Ugh. + d0 = if '.' == File.dirname(Debugger::PROG_SCRIPT) and + Debugger::PROG_SCRIPT[0..0] != '.' + File.join('.', Debugger::PROG_SCRIPT) + else + Debugger::PROG_SCRIPT + end + if $0.frozen? + $0 = d0 + else + $0[0..-1] = d0 + end + end + + # Record where we are we can know if the call stack has been + # truncated or not. + Debugger.start_sentinal=caller(0)[1] + + bt = Debugger.debug_load(Debugger::PROG_SCRIPT, !options.nostop, false) + if bt + if options.post_mortem + Debugger.handle_post_mortem(bt) + else + print bt.backtrace.map{|l| "\t#{l}"}.join("\n"), "\n" + print "Uncaught exception: #{bt}\n" + end + end +end + +options = OpenStruct.new( + 'annotate' => false, + 'emacs' => false, + 'frame_bind' => false, + 'no-quit' => false, + 'no-stop' => false, + 'nx' => false, + 'post_mortem' => false, + 'script' => nil, + 'tracing' => false, + 'verbose_long'=> false, + 'wait' => false +) + +require "ruby-debug" + +program = File.basename($0) +opts = OptionParser.new do |opts| + opts.banner = < -- +EOB + opts.separator "" + opts.separator "Options:" + opts.on("-A", "--annotate LEVEL", Integer, "Set annotation level") do + |Debugger.annotate| + end + opts.on("-d", "--debug", "Set $DEBUG=true") {$DEBUG = true} + opts.on("--emacs-basic", "Activates basic Emacs mode") do + ENV['EMACS'] = '1' + options.emacs = true + end + opts.on("--keep-frame-binding", "Keep frame bindings") do + options.frame_bind = true + end + opts.on("-m", "--post-mortem", "Activate post-mortem mode") do + options.post_mortem = true + end + opts.on("--no-control", "Do not automatically start control thread") do + options.control = false + end + opts.on("--no-quit", "Do not quit when script finishes") do + options.noquit = true + end + opts.on("--no-stop", "Do not stop when script is loaded") do + options.nostop = true + end + opts.on("-nx", "Not run debugger initialization files (e.g. .rdebugrc") do + options.nx = true + end + opts.on("-I", "--include PATH", String, "Add PATH to $LOAD_PATH") do |path| + $LOAD_PATH.unshift(path) + end + opts.on("-r", "--require SCRIPT", String, + "Require the library, before executing your script") do |name| + if name == 'debug' + puts "ruby-debug is not compatible with Ruby's 'debug' library. This option is ignored." + else + require name + end + end + opts.on("--script FILE", String, "Name of the script file to run") do |options.script| + unless File.exists?(options.script) + puts "Script file '#{options.script}' is not found" + exit + end + end + opts.on("-x", "--trace", "Turn on line tracing") {options.tracing = true} + ENV['EMACS'] = nil unless options.emacs + opts.separator "" + opts.separator "Common options:" + opts.on_tail("--help", "Show this message") do + puts opts + exit + end + opts.on_tail("--version", + "Print the version") do + puts "ruby-debug #{Debugger::VERSION}" + exit + end + opts.on("--verbose", "Turn on verbose mode") do + $VERBOSE = true + options.verbose_long = true + end + opts.on_tail("-v", + "Print version number, then turn on verbose mode") do + puts "ruby-debug #{Debugger::VERSION}" + $VERBOSE = true + end +end + +begin + if not defined? Debugger::ARGV + Debugger::ARGV = ARGV.clone + end + rdebug_path = File.expand_path($0) + if RUBY_PLATFORM =~ /mswin/ + rdebug_path += '.cmd' unless rdebug_path =~ /\.cmd$/i + end + Debugger::RDEBUG_SCRIPT = rdebug_path + Debugger::RDEBUG_FILE = __FILE__ + Debugger::INITIAL_DIR = Dir.pwd + opts.parse! ARGV +rescue StandardError => e + puts opts + puts + puts e.message + exit(-1) +end + +if ARGV.empty? + exit if $VERBOSE and not options.verbose_long + puts opts + puts + puts 'Must specify a script to run' + exit(-1) +end + +# save script name +Debugger::PROG_SCRIPT = ARGV.shift + +# install interruption handler +trap('INT') { Debugger.interrupt_last } + +# set options +Debugger.wait_connection = false +Debugger.keep_frame_binding = options.frame_bind + +# Add Debugger trace hook. +Debugger.start + +# start control thread +Debugger.start_control(options.host, options.cport) if options.control + +# activate post-mortem +Debugger.post_mortem if options.post_mortem + +# Set up an interface to read commands from a debugger script file. +if options.script + Debugger.interface = Debugger::ScriptInterface.new(options.script, + STDOUT, true) +end +options.nostop = true if options.tracing +Debugger.tracing = options.tracing + +# Make sure Ruby script syntax checks okay. +# Otherwise we get a load message that looks like rdebug has +# a problem. +output = `ruby -c #{Debugger::PROG_SCRIPT} 2>&1` +if $?.exitstatus != 0 and RUBY_PLATFORM !~ /mswin/ + puts output + exit $?.exitstatus +end + +# load initrc script (e.g. .rdebugrc) +Debugger.run_init_script(StringIO.new) unless options.nx + +# run startup script if specified +if options.script + Debugger.run_script(options.script) +end +# activate post-mortem +Debugger.post_mortem if options.post_mortem +options.stop = false if options.tracing +Debugger.tracing = options.tracing + +if options.noquit + if Debugger.started? + until Debugger.stop do end + end + debug_program(options) + print "The program finished.\n" unless + Debugger.annotate.to_i > 1 # annotate has its own way + interface = Debugger::LocalInterface.new + # Not sure if ControlCommandProcessor is really the right + # thing to use. CommandProcessor requires a state. + processor = Debugger::ControlCommandProcessor.new(interface) + processor.process_commands +else + debug_program(options) +end diff --git a/test/test-annotate.rb b/test/test-annotate.rb new file mode 100755 index 0000000..27adff1 --- /dev/null +++ b/test/test-annotate.rb @@ -0,0 +1,25 @@ +#!/usr/bin/env ruby +require 'test/unit' +require 'fileutils' + +# begin require 'rubygems' rescue LoadError end +# require 'ruby-debug'; Debugger.start + +# Test annotate handling. +class TestAnnotate < Test::Unit::TestCase + @@SRC_DIR = File.dirname(__FILE__) unless + defined?(@@SRC_DIR) + + require File.join(@@SRC_DIR, 'helper') + include TestHelper + + def test_basic + testname='annotate' + Dir.chdir(@@SRC_DIR) do + script = File.join('data', testname + '.cmd') + assert_equal(true, + run_debugger(testname, + "--script #{script} -- gcd.rb 3 5")) + end + end +end diff --git a/test/test-break-bad.rb b/test/test-break-bad.rb new file mode 100755 index 0000000..f667ff7 --- /dev/null +++ b/test/test-break-bad.rb @@ -0,0 +1,36 @@ +#!/usr/bin/env ruby +require 'test/unit' + +# begin require 'rubygems' rescue LoadError end +# require 'ruby-debug'; Debugger.start + +# Test (mostly) invalid breakpoint commands +class TestBadBreak < Test::Unit::TestCase + + @@SRC_DIR = File.dirname(__FILE__) unless + defined?(@@SRC_DIR) + + require File.join(@@SRC_DIR, 'helper') + include TestHelper + + def test_basic + testname='break_bad' + Dir.chdir(@@SRC_DIR) do + script = File.join('data', testname + '.cmd') + assert_equal(true, + run_debugger(testname, + "--script #{script} -- gcd.rb 3 5")) + end + end + + def test_break_loop + testname='break_loop_bug' + Dir.chdir(@@SRC_DIR) do + script = File.join('data', testname + '.cmd') + assert_equal(true, + run_debugger(testname, + "--script #{script} -- bp_loop_issue.rb")) + end + end + +end diff --git a/test/test-breakpoints.rb b/test/test-breakpoints.rb new file mode 100755 index 0000000..aa7617e --- /dev/null +++ b/test/test-breakpoints.rb @@ -0,0 +1,25 @@ +#!/usr/bin/env ruby +require 'test/unit' + +# begin require 'rubygems' rescue LoadError end +# require 'ruby-debug'; Debugger.start + +# Test breakpoint commands +class TestBreakpoints < Test::Unit::TestCase + + @@SRC_DIR = File.dirname(__FILE__) unless + defined?(@@SRC_DIR) + + require File.join(@@SRC_DIR, 'helper') + include TestHelper + + def test_basic + testname='breakpoints' + Dir.chdir(@@SRC_DIR) do + script = File.join('data', testname + '.cmd') + assert_equal(true, + run_debugger(testname, + "--script #{script} -- gcd.rb 3 5")) + end + end +end diff --git a/test/test-catch.rb b/test/test-catch.rb new file mode 100755 index 0000000..fc7ef91 --- /dev/null +++ b/test/test-catch.rb @@ -0,0 +1,25 @@ +#!/usr/bin/env ruby +require 'test/unit' + +# begin require 'rubygems' rescue LoadError end +# require 'ruby-debug'; Debugger.start + +# Test condition command +class TestBreakpoints < Test::Unit::TestCase + + @@SRC_DIR = File.dirname(__FILE__) unless + defined?(@@SRC_DIR) + + require File.join(@@SRC_DIR, 'helper') + include TestHelper + + def test_basic + testname='catch' + Dir.chdir(@@SRC_DIR) do + script = File.join('data', testname + '.cmd') + assert_equal(true, + run_debugger(testname, + "--script #{script} -- pm.rb")) + end + end +end diff --git a/test/test-condition.rb b/test/test-condition.rb new file mode 100755 index 0000000..9fea498 --- /dev/null +++ b/test/test-condition.rb @@ -0,0 +1,25 @@ +#!/usr/bin/env ruby +require 'test/unit' + +# begin require 'rubygems' rescue LoadError end +# require 'ruby-debug'; Debugger.start + +# Test condition command +class TestBreakpoints < Test::Unit::TestCase + + @@SRC_DIR = File.dirname(__FILE__) unless + defined?(@@SRC_DIR) + + require File.join(@@SRC_DIR, 'helper') + include TestHelper + + def test_basic + testname='condition' + Dir.chdir(@@SRC_DIR) do + script = File.join('data', testname + '.cmd') + assert_equal(true, + run_debugger(testname, + "--script #{script} -- gcd.rb 3 5")) + end + end +end diff --git a/test/test-ctrl.rb b/test/test-ctrl.rb new file mode 100755 index 0000000..213b592 --- /dev/null +++ b/test/test-ctrl.rb @@ -0,0 +1,55 @@ +#!/usr/bin/env ruby + +# begin require 'rubygems' rescue LoadError end +# require 'ruby-debug' ; Debugger.start + +require 'test/unit' +SRC_DIR = File.dirname(__FILE__) unless + defined?(SRC_DIR) +%w(ext lib cli).each do |dir| + $: << File.join(SRC_DIR, '..', dir) +end +require 'ruby_debug' +require File.join(SRC_DIR, '..', 'cli', 'ruby-debug') + +# Test Local Control Interface +class TestCtrl < Test::Unit::TestCase + + def cheap_diff(got_lines, correct_lines, outfile) + if correct_lines.size != got_lines.size + puts "Size difference #{correct_lines.size} vs. #{got_lines.size}" + File.open(outfile, 'w') {|f| f.puts got_lines} + return false + end + correct_lines.each_with_index do |line, i| + correct_lines[i].chomp! + if got_lines[i] != correct_lines[i] + puts "difference found at line #{i+1}" + puts "got : #{got_lines[i]}" + puts "need: #{correct_lines[i]}" + File.open(outfile, 'w') {|f| f.puts got_lines} + return false + end + end + end + + require 'stringio' + + # Test initial variables and setting/getting state. + def test_ctrl + ENV['COLUMNS'] = '80' + ENV['EMACS'] = nil + testbase = 'ctrl' + out = StringIO.new('', 'w') + Dir.chdir(SRC_DIR) do + script = File.join('data', "#{testbase}.cmd") + interface = Debugger::ScriptInterface.new(script, out) + processor = Debugger::ControlCommandProcessor.new(interface) + processor.process_commands + got_lines = out.string.split("\n") + right_file = File.join('data', "#{testbase}.right") + correct_lines = File.readlines(right_file) + assert cheap_diff(got_lines, correct_lines, "#{testbase}.out") + end + end +end diff --git a/test/test-display.rb b/test/test-display.rb new file mode 100755 index 0000000..4810a44 --- /dev/null +++ b/test/test-display.rb @@ -0,0 +1,26 @@ +#!/usr/bin/env ruby +require 'test/unit' + +# begin require 'rubygems' rescue LoadError end +# require 'ruby-debug'; Debugger.start + +# Test Display commands +class TestDisplay < Test::Unit::TestCase + + @@SRC_DIR = File.dirname(__FILE__) unless + defined?(@@SRC_DIR) + + require File.join(@@SRC_DIR, 'helper') + include TestHelper + + # Test commands in display.rb + def test_basic + testname='display' + Dir.chdir(@@SRC_DIR) do + script = File.join('data', testname + '.cmd') + assert_equal(true, + run_debugger(testname, + "--script #{script} -- gcd.rb 3 5")) + end + end +end diff --git a/test/test-dollar-0.rb b/test/test-dollar-0.rb new file mode 100755 index 0000000..8aa1346 --- /dev/null +++ b/test/test-dollar-0.rb @@ -0,0 +1,45 @@ +#!/usr/bin/env ruby +require 'test/unit' + +# begin require 'rubygems' rescue LoadError end +# require 'ruby-debug'; Debugger.start + +# Test --no-stop and $0 setting. +class TestDollar0 < Test::Unit::TestCase + + @@SRC_DIR = File.dirname(__FILE__) unless + defined?(@@SRC_DIR) + + require File.join(@@SRC_DIR, 'helper') + include TestHelper + + def test_basic + testname='breakpoints' + Dir.chdir(@@SRC_DIR) do + home_save = ENV['HOME'] + ENV['HOME'] = '.' + filter = Proc.new{|got_lines, correct_lines| + [got_lines, correct_lines].flatten.each do |s| + s.gsub!(/.*dollar-0.rb$/, 'dollar-0.rb') + end + } + + assert_equal(true, + run_debugger('dollar-0', + '-nx --no-stop ./dollar-0.rb', + nil, filter, false, '../bin/rdebug')) + # Ruby's __FILE__ seems to prepend ./ when no directory was added. + assert_equal(true, + run_debugger('dollar-0a', + '-nx --no-stop dollar-0.rb', + nil, filter, false, '../bin/rdebug')) + # Ruby's __FILE__ seems to prepend ./ when no directory was added. + assert_equal(true, + run_debugger('dollar-0b', + '-nx --no-stop ' + + File.join('..', 'test', 'dollar-0.rb'), + nil, filter, false, '../bin/rdebug')) + ENV['HOME'] = home_save + end + end +end diff --git a/test/test-edit.rb b/test/test-edit.rb new file mode 100755 index 0000000..27ef6c1 --- /dev/null +++ b/test/test-edit.rb @@ -0,0 +1,26 @@ +#!/usr/bin/env ruby +require 'test/unit' + +# begin require 'rubygems' rescue LoadError end +# require 'ruby-debug'; Debugger.start + +# Test 'edit' command handling. +class TestEdit < Test::Unit::TestCase + + @@SRC_DIR = File.dirname(__FILE__) unless + defined?(@@SRC_DIR) + + require File.join(@@SRC_DIR, 'helper') + include TestHelper + + def test_basic + testname='edit' + Dir.chdir(@@SRC_DIR) do + script = File.join('data', testname + '.cmd') + ENV['EDITOR']='echo FAKE-EDITOR ' + assert_equal(true, + run_debugger(testname, + "--script #{script} -- gcd.rb 3 5")) + end + end +end diff --git a/test/test-emacs-basic.rb b/test/test-emacs-basic.rb new file mode 100755 index 0000000..c4c5518 --- /dev/null +++ b/test/test-emacs-basic.rb @@ -0,0 +1,26 @@ +#!/usr/bin/env ruby +require 'test/unit' + +# require 'rubygems' +# require 'ruby-debug'; Debugger.start(:post_mortem => true) + +# Test the --emacs-basic option. +class TestEmacsBasic < Test::Unit::TestCase + + @@SRC_DIR = File.dirname(__FILE__) unless + defined?(@@SRC_DIR) + + require File.join(@@SRC_DIR, 'helper.rb') + + include TestHelper + + def test_basic + testname='emacs_basic' + Dir.chdir(@@SRC_DIR) do + script = File.join('data', testname + '.cmd') + assert_equal(true, + run_debugger(testname, + "--emacs-basic --script #{script} -- gcd.rb 3 5")) + end + end +end diff --git a/test/test-enable.rb b/test/test-enable.rb new file mode 100755 index 0000000..db73ffe --- /dev/null +++ b/test/test-enable.rb @@ -0,0 +1,25 @@ +#!/usr/bin/env ruby +require 'test/unit' + +# begin require 'rubygems' rescue LoadError end +# require 'ruby-debug'; Debugger.start + +# Test enable and disable commands +class TestEnable < Test::Unit::TestCase + + @@SRC_DIR = File.dirname(__FILE__) unless + defined?(@@SRC_DIR) + + require File.join(@@SRC_DIR, 'helper') + include TestHelper + + def test_basic + testname='enable' + Dir.chdir(@@SRC_DIR) do + script = File.join('data', testname + '.cmd') + assert_equal(true, + run_debugger(testname, + "--script #{script} -- gcd.rb 3 5")) + end + end +end diff --git a/test/test-finish.rb b/test/test-finish.rb new file mode 100755 index 0000000..4f452cf --- /dev/null +++ b/test/test-finish.rb @@ -0,0 +1,34 @@ +#!/usr/bin/env ruby +require 'test/unit' + +# require 'rubygems' +# require 'ruby-debug'; Debugger.start + +# Test finish command +class TestFinish < Test::Unit::TestCase + + @@src_dir = File.dirname(__FILE__) unless + defined?(@@src_dir) + + require File.join(@@src_dir, 'helper') + include TestHelper + + def test_basic + testname='finish' + # Ruby 1.8.6 and earlier have a trace-line number bug for return + # statements. +# filter = Proc.new{|got_lines, correct_lines| +# [got_lines[31], got_lines[34]].flatten.each do |s| +# s.sub!(/gcd.rb:\d+/, 'gcd.rb:13') +# end +# got_lines[32] = 'return a' +# } + Dir.chdir(@@src_dir) do + script = File.join('data', testname + '.cmd') + assert_equal(true, + run_debugger(testname, + "--script #{script} -- gcd.rb 3 5", + nil, nil)) + end + end +end diff --git a/test/test-frame.rb b/test/test-frame.rb new file mode 100755 index 0000000..c5f059f --- /dev/null +++ b/test/test-frame.rb @@ -0,0 +1,34 @@ +#!/usr/bin/env ruby +require 'test/unit' + +# require 'rubygems' +# require 'ruby-debug'; Debugger.start(:post_mortem => true) + +# Test frame commands +class TestFrame < Test::Unit::TestCase + + @@SRC_DIR = File.dirname(__FILE__) unless + defined?(@@SRC_DIR) + + require File.join(@@SRC_DIR, 'helper') + include TestHelper + + # Test commands in frame.rb + def test_basic + testname='frame' + # Ruby 1.8.6 and earlier have a trace-line number bug for return + # statements. + filter = Proc.new{|got_lines, correct_lines| + [got_lines[11], correct_lines[11]].flatten.each do |s| + s.sub!(/in file ".*gcd.rb/, 'in file "gcd.rb') + end + } + Dir.chdir(@@SRC_DIR) do + script = File.join('data', testname + '.cmd') + assert_equal(true, + run_debugger(testname, + "--script #{script} -- gcd.rb 3 5", + nil, filter)) + end + end +end diff --git a/test/test-help.rb b/test/test-help.rb new file mode 100755 index 0000000..460dd6c --- /dev/null +++ b/test/test-help.rb @@ -0,0 +1,60 @@ +#!/usr/bin/env ruby + +# begin require 'rubygems' rescue LoadError end +# require 'ruby-debug' ; Debugger.start + +require 'test/unit' +SRC_DIR = File.dirname(__FILE__) unless + defined?(SRC_DIR) +%w(ext lib cli).each do |dir| + $:.unshift File.join(SRC_DIR, '..', dir) +end +require 'ruby_debug' + +require File.join(SRC_DIR, '..', 'cli', 'ruby-debug') +$:.shift; $:.shift; $:.shift + +def cheap_diff(got_lines, correct_lines) + puts got_lines if $DEBUG + correct_lines.each_with_index do |line, i| + correct_lines[i].chomp! + if got_lines[i] != correct_lines[i] + puts "difference found at line #{i+1}" + puts "got : #{got_lines[i]}" + puts "need: #{correct_lines[i]}" + return false + end + if correct_lines.size != got_lines.size + puts("difference in number of lines: " + + "#{correct_lines.size} vs. #{got_lines.size}") + return false + end + return true + end +end + +# Test Help commands +class TestHelp < Test::Unit::TestCase + require 'stringio' + + # Test initial variables and setting/getting state. + def test_basic + testbase = 'help' + op = StringIO.new('', 'w') + Dir.chdir(SRC_DIR) do + script = File.join('data', "#{testbase}.cmd") + Debugger.const_set('Version', 'unit testing') + Debugger.run_script(script, op) + got_lines = op.string.split("\n") + right_file = File.join('data', "#{testbase}.right") + correct_lines = File.readlines(right_file) + result = cheap_diff(got_lines, correct_lines) + unless result + puts '-' * 80 + puts got_lines + puts '-' * 80 + end + assert result + end + end +end diff --git a/test/test-hist.rb b/test/test-hist.rb new file mode 100755 index 0000000..484394c --- /dev/null +++ b/test/test-hist.rb @@ -0,0 +1,68 @@ +#!/usr/bin/env ruby +require 'test/unit' + +# begin require 'rubygems' rescue LoadError end +# require 'ruby-debug'; Debugger.start + +# Test history commands + +class TestHistory < Test::Unit::TestCase + + @@SRC_DIR = File.dirname(__FILE__) unless + defined?(@@SRC_DIR) + + require File.join(@@SRC_DIR, 'helper') + include TestHelper + + unless defined?(@@FILE_HISTORY) + @@FILE_HISTORY = '.rdebug_hist' + end + + def test_basic + + # Set up history file to read from. + ENV['HOME']=@@SRC_DIR + ENV['RDEBUG'] = nil + + debugger_commands = ['show commands', + 'set history save on', + 'show history', + 'quit unconditionally'] + debugger_output = 'test-history.out' + + Dir.chdir(@@SRC_DIR) do + correct_lines = File.read(File.join('data', 'history.right')).split(/\n/) + f = File.open(@@FILE_HISTORY, 'w') + correct_lines[0.. -(debugger_commands.length+1)].each do |line| + f.puts line + end + f.close + + # Now that we've set up a history file, run the debugger + # and check that it's reading that correctly. + debug_pgm=File.join('..', 'rdbg.rb') + debugged=File.join('gcd.rb') + IO.popen("#{debug_pgm} #{debugged} 3 5 >#{debugger_output}", 'w') do + |pipe| + debugger_commands.each do |cmd| + pipe.puts cmd + end + end + + # Compare output + got_lines = File.read(@@FILE_HISTORY).split(/\n/) + # FIXME: Disable for now. + assert true, 'FIXME' + return + if cheap_diff(got_lines, correct_lines) + assert true + FileUtils.rm(debugger_output) + FileUtils.rm(@@FILE_HISTORY) + else + assert nil, 'Output differs' + end + end + end +end + + diff --git a/test/test-info-thread.rb b/test/test-info-thread.rb new file mode 100755 index 0000000..d90cc8a --- /dev/null +++ b/test/test-info-thread.rb @@ -0,0 +1,32 @@ +#!/usr/bin/env ruby +require 'test/unit' + +# begin require 'rubygems' rescue LoadError end +# require 'ruby-debug'; Debugger.start + +# Test simple thread commands +class TestInfoThread < Test::Unit::TestCase + + @@SRC_DIR = File.dirname(__FILE__) unless + defined?(@@SRC_DIR) + + require File.join(@@SRC_DIR, 'helper') + include TestHelper + + def test_basic + testname='info-thread' + Dir.chdir(@@SRC_DIR) do + filter = Proc.new{|got_lines, correct_lines| + [got_lines, correct_lines].each do |a| + a.each do |s| + s.sub!(/Thread:0x[0-9a-f]+/, 'Thread:0x12345678') + end + end + } + script = File.join('data', testname + '.cmd') + assert_equal(true, + run_debugger(testname, + "--script #{script} -- gcd.rb 3 5", nil, filter)) + end + end +end diff --git a/test/test-info-var.rb b/test/test-info-var.rb new file mode 100755 index 0000000..af06c78 --- /dev/null +++ b/test/test-info-var.rb @@ -0,0 +1,47 @@ +#!/usr/bin/env ruby +require 'test/unit' + +# begin require 'rubygems' rescue LoadError end +# require 'ruby-debug'; Debugger.start + +# Test info variables command +class TestInfoVar < Test::Unit::TestCase + + @@SRC_DIR = File.dirname(__FILE__) unless + defined?(@@SRC_DIR) + + require File.join(@@SRC_DIR, 'helper') + include TestHelper + + def test_info_variables + + Dir.chdir(@@SRC_DIR) do + + filter = Proc.new{|got_lines, correct_lines| + [got_lines[13-1], correct_lines[13-1]].each do |s| + s.sub!(/Mine:0x[0-9,a-f]+/, 'Mine:') + end + [got_lines, correct_lines].each do |a| + a.each do |s| + s.sub!(/Lousy_inspect:0x[0-9,a-f]+/, 'Lousy_inspect:') + s.sub!(/UnsuspectingClass:0x[0-9,a-f]+/, 'UnsuspectingClass:') + end + end + } + + testname='info-var' + script = File.join('data', testname + '.cmd') + assert_equal(true, + run_debugger(testname, + "--script #{script} -- info-var-bug.rb", + nil, filter)) + testname='info-var-bug2' + script = File.join('data', testname + '.cmd') + assert_equal(true, + run_debugger(testname, + "--script #{script} -- info-var-bug2.rb", + nil)) + + end + end +end diff --git a/test/test-info.rb b/test/test-info.rb new file mode 100755 index 0000000..dade3c8 --- /dev/null +++ b/test/test-info.rb @@ -0,0 +1,26 @@ +#!/usr/bin/env ruby +require 'test/unit' + +# begin require 'rubygems' rescue LoadError end +# require 'ruby-debug'; Debugger.start + +# Test info commands +class TestInfo < Test::Unit::TestCase + + @@SRC_DIR = File.dirname(__FILE__) unless + defined?(@@SRC_DIR) + + require File.join(@@SRC_DIR, 'helper') + include TestHelper + + # Test commands in info.rb + def test_basic + testname='info' + Dir.chdir(@@SRC_DIR) do + script = File.join('data', testname + '.cmd') + assert_equal(true, + run_debugger(testname, + "--script #{script} -- gcd.rb 3 5")) + end + end +end diff --git a/test/test-init.rb b/test/test-init.rb new file mode 100755 index 0000000..bbc2394 --- /dev/null +++ b/test/test-init.rb @@ -0,0 +1,43 @@ +#!/usr/bin/env ruby +require 'test/unit' +require 'rbconfig' +require File.join(File.dirname(__FILE__), 'helper.rb') + +# begin require 'rubygems' rescue LoadError end +# require 'ruby-debug'; Debugger.start + +# Test Debugger.init and setting up ruby-debug variables +class TestDebuggerInit < Test::Unit::TestCase + @@SRC_DIR = File.dirname(__FILE__) unless + defined?(@@SRC_DIR) + def test_basic + debugger_output = 'test-init.out' + Dir.chdir(@@SRC_DIR) do + old_emacs = ENV['EMACS'] + old_columns = ENV['COLUMNS'] + ENV['EMACS'] = nil + ENV['COLUMNS'] = '120' + ruby = "#{TestHelper.load_ruby} #{TestHelper.load_params}" + IO.popen("#{ruby} ./gcd-dbg.rb 5 >#{debugger_output}", 'w') do |pipe| + pipe.puts 'p Debugger::PROG_SCRIPT' + pipe.puts 'show args' + pipe.puts 'quit unconditionally' + end + lines = File.open(debugger_output).readlines + ENV['EMACS'] = old_emacs + ENV['COLUMNS'] = old_columns + + right_file = case Config::CONFIG['host_os'] + when /^darwin/ + 'test-init-osx.right' + when /^cygwin/ + 'test-init-cygwin.right' + else + 'test-init.right' + end + expected = File.open(File.join('data', right_file)).readlines + assert_equal(expected, lines) + File.delete(debugger_output) if expected == lines + end + end +end diff --git a/test/test-list.rb b/test/test-list.rb new file mode 100755 index 0000000..12c2680 --- /dev/null +++ b/test/test-list.rb @@ -0,0 +1,25 @@ +#!/usr/bin/env ruby +require 'test/unit' + +# begin require 'rubygems' rescue LoadError end +# require 'ruby-debug'; Debugger.start + +# Test List commands +class TestList < Test::Unit::TestCase + + @@src_dir = File.dirname(__FILE__) + + require File.join(@@src_dir, 'helper') + include TestHelper + + # Test commands in list.rb + def test_basic + testname='list' + Dir.chdir(@@src_dir) do + script = File.join('data', testname + '.cmd') + assert_equal(true, + run_debugger(testname, + "--script #{script} -- gcd.rb 3 5")) + end + end +end diff --git a/test/test-method.rb b/test/test-method.rb new file mode 100755 index 0000000..a8da23b --- /dev/null +++ b/test/test-method.rb @@ -0,0 +1,34 @@ +#!/usr/bin/env ruby +require 'test/unit' + +# require 'rubygems' +# require 'ruby-debug'; Debugger.start(:post_mortem => true) + +class TestMethod < Test::Unit::TestCase + + @@SRC_DIR = File.dirname(__FILE__) unless + defined?(@@SRC_DIR) + + require File.join(@@SRC_DIR, 'helper') + include TestHelper + + def test_basic + testname='method' + Dir.chdir(@@SRC_DIR) do + script = File.join('data', testname + '.cmd') + assert_equal(true, + run_debugger(testname, + "--script #{script} -- classes.rb")) + begin + require 'methodsig' + testname='methodsig' + script = File.join('data', testname + '.cmd') + assert_equal(true, + run_debugger(testname, + "--script #{script} -- classes.rb")) + rescue LoadError + puts "Skipping method sig test" + end + end + end +end diff --git a/test/test-output.rb b/test/test-output.rb new file mode 100755 index 0000000..9435113 --- /dev/null +++ b/test/test-output.rb @@ -0,0 +1,26 @@ +#!/usr/bin/env ruby +require 'test/unit' + +# begin require 'rubygems' rescue LoadError end +# require 'ruby-debug'; Debugger.start + +# Test 'starting' annotation. +class TestStartingAnnotate < Test::Unit::TestCase + + @@SRC_DIR = File.dirname(__FILE__) unless + defined?(@@SRC_DIR) + + require File.join(@@SRC_DIR, 'helper') + include TestHelper + + def test_basic + testname='output' + Dir.chdir(@@SRC_DIR) do + script = File.join('data', testname + '.cmd') + assert_equal(true, + run_debugger(testname, + "-A 3 --script #{script} -- output.rb", + nil, nil, true)) + end + end +end diff --git a/test/test-pm.rb b/test/test-pm.rb new file mode 100755 index 0000000..cc646cc --- /dev/null +++ b/test/test-pm.rb @@ -0,0 +1,59 @@ +#!/usr/bin/env ruby +require 'test/unit' +require 'rbconfig' + +# begin require 'rubygems' rescue LoadError end +# require 'ruby-debug'; Debugger.start + +# Test Post-mortem command +class TestPM < Test::Unit::TestCase + + @@SRC_DIR = File.dirname(__FILE__) unless + defined?(@@SRC_DIR) + + require File.join(@@SRC_DIR, 'helper') + include TestHelper + + # Test post-mortem handling + def test_basic + Dir.chdir(@@SRC_DIR) do +# filter = Proc.new{|got_lines, correct_lines| +# [got_lines[0], correct_lines[0]].each do |s| +# s.sub!(/tdebug.rb:\d+/, 'rdebug:999') +# end +# } + ENV['COLUMNS'] = '80' + testname='post-mortem' + script = File.join('data', testname + '.cmd') + testname += '-osx' if Config::CONFIG['host_os'] =~ /^darwin/ + assert_equal(true, + run_debugger(testname, + "--script #{script} --post-mortem pm.rb")) + end + end + + # Test post-mortem handling + def test_pm_next + Dir.chdir(@@SRC_DIR) do + ENV['COLUMNS'] = '80' + testname='post-mortem-next' + script = File.join('data', testname + '.cmd') + assert_equal(true, + run_debugger(testname, + "--script #{script} --post-mortem pm.rb")) + end + end + + # Test Tracker #22118 post-mortem giving an error in show internal variables + def test_pm_iv_bug + Dir.chdir(@@SRC_DIR) do + ENV['COLUMNS'] = '80' + testname='pm-bug' + script = File.join('data', testname + '.cmd') + assert_equal(true, + run_debugger(testname, + "--script #{script} --post-mortem pm-bug.rb")) + end + end + +end diff --git a/test/test-quit.rb b/test/test-quit.rb new file mode 100755 index 0000000..2a313b8 --- /dev/null +++ b/test/test-quit.rb @@ -0,0 +1,30 @@ +#!/usr/bin/env ruby +require 'test/unit' + +# begin require 'rubygems' rescue LoadError end +# require 'ruby-debug'; Debugger.start + +# Test Quit command +class TestQuit < Test::Unit::TestCase + + @@SRC_DIR = File.dirname(__FILE__) unless + defined?(@@SRC_DIR) + + require File.join(@@SRC_DIR, 'helper') + include TestHelper + + def test_basic + testname='quit' + Dir.chdir(@@SRC_DIR) do + script = File.join('data', testname + '.cmd') +# filter = Proc.new{|got_lines, correct_lines| +# [got_lines[0], correct_lines[0]].each do |s| +# s.sub!(/tdebug.rb:\d+/, 'rdebug:999') +# end +# } + assert_equal(true, + run_debugger(testname, + "--script #{script} -- null.rb")) + end + end +end diff --git a/test/test-raise.rb b/test/test-raise.rb new file mode 100755 index 0000000..c111b9e --- /dev/null +++ b/test/test-raise.rb @@ -0,0 +1,25 @@ +#!/usr/bin/env ruby +require 'test/unit' + +# begin require 'rubygems' rescue LoadError end +# require 'ruby-debug'; Debugger.start + +# Test Debugger.load handles uncaught exceptions in the debugged program. +class TestBreakpoints < Test::Unit::TestCase + + @@SRC_DIR = File.dirname(__FILE__) unless + defined?(@@SRC_DIR) + + require File.join(@@SRC_DIR, 'helper') + include TestHelper + + def test_basic + testname='raise' + Dir.chdir(@@SRC_DIR) do + script = File.join('data', testname + '.cmd') + assert_equal(true, + run_debugger(testname, + "--script #{script} -- raise.rb")) + end + end +end diff --git a/test/test-save.rb b/test/test-save.rb new file mode 100755 index 0000000..6d8c6b0 --- /dev/null +++ b/test/test-save.rb @@ -0,0 +1,31 @@ +#!/usr/bin/env ruby +require 'test/unit' + +# require 'rubygems' +# require 'ruby-debug'; Debugger.start(:post_mortem =>true) + +class TestSave < Test::Unit::TestCase + + @@SRC_DIR = File.dirname(__FILE__) unless + defined?(@@SRC_DIR) + + require File.join(@@SRC_DIR, 'helper') + include TestHelper + + # Test initial variables and setting/getting state. + def test_basic + testname='save' + filter = Proc.new{|got_lines, correct_lines| + got_lines.each do |s| + s.sub!(/2 file .*gcd.rb/, '2 file gcd.rb') + end + } + Dir.chdir(@@SRC_DIR) do + script = File.join('data', testname + '.cmd') + assert_equal(true, + run_debugger(testname, + "--script #{script} -- gcd.rb 3 5", + nil, filter)) + end + end +end diff --git a/test/test-setshow.rb b/test/test-setshow.rb new file mode 100755 index 0000000..1710965 --- /dev/null +++ b/test/test-setshow.rb @@ -0,0 +1,25 @@ +#!/usr/bin/env ruby +require 'test/unit' + +# begin require 'rubygems' rescue LoadError end +# require 'ruby-debug'; Debugger.start + +class TestSetShow < Test::Unit::TestCase + + @@SRC_DIR = File.dirname(__FILE__) unless + defined?(@@SRC_DIR) + + require File.join(@@SRC_DIR, 'helper') + include TestHelper + + # Test initial variables and setting/getting state. + def test_basic + testname='setshow' + Dir.chdir(@@SRC_DIR) do + script = File.join('data', testname + '.cmd') + assert_equal(true, + run_debugger(testname, + "--script #{script} -- gcd.rb 3 5")) + end + end +end diff --git a/test/test-source.rb b/test/test-source.rb new file mode 100755 index 0000000..b6c1629 --- /dev/null +++ b/test/test-source.rb @@ -0,0 +1,25 @@ +#!/usr/bin/env ruby +require 'test/unit' + +# begin require 'rubygems' rescue LoadError end +# require 'ruby-debug'; Debugger.start + +# Test 'source' command handling. +class TestSource < Test::Unit::TestCase + + @@SRC_DIR = File.dirname(__FILE__) unless + defined?(@@SRC_DIR) + + require File.join(@@SRC_DIR, 'helper') + include TestHelper + + def test_basic + testname='source' + Dir.chdir(@@SRC_DIR) do + script = File.join('data', testname + '.cmd') + assert_equal(true, + run_debugger(testname, + "--script #{script} -- gcd.rb 3 5")) + end + end +end diff --git a/test/test-stepping.rb b/test/test-stepping.rb new file mode 100755 index 0000000..8c4f404 --- /dev/null +++ b/test/test-stepping.rb @@ -0,0 +1,26 @@ +#!/usr/bin/env ruby +require 'test/unit' + +# begin require 'rubygems' rescue LoadError end +# require 'ruby-debug'; Debugger.start + +# Test that linetracing does something. +class TestStepping < Test::Unit::TestCase + + @@SRC_DIR = File.dirname(__FILE__) unless + defined?(@@SRC_DIR) + + require File.join(@@SRC_DIR, 'helper') + include TestHelper + + # Test commands in stepping.rb + def test_basic + testname='stepping' + Dir.chdir(@@SRC_DIR) do + script = File.join('data', testname + '.cmd') + assert_equal(true, + run_debugger(testname, + "--script #{script} -- gcd.rb 3 5")) + end + end +end diff --git a/test/test-trace.rb b/test/test-trace.rb new file mode 100755 index 0000000..7e64ed0 --- /dev/null +++ b/test/test-trace.rb @@ -0,0 +1,63 @@ +#!/usr/bin/env ruby +require 'test/unit' + +# begin require 'rubygems' rescue LoadError end +# require 'ruby-debug'; Debugger.start + +# Test 'edit' command handling. +class TestEdit < Test::Unit::TestCase + + @@SRC_DIR = File.dirname(__FILE__) unless + defined?(@@SRC_DIR) + + require File.join(@@SRC_DIR, 'helper') + include TestHelper + + def test_trace_option + + filter = Proc.new{|got_lines, correct_lines| + got_lines.collect!{|l| l =~ /:gcd\.rb:/? l : nil}.compact! + } + + testname='trace' + Dir.chdir(@@SRC_DIR) do + assert_equal(true, + run_debugger(testname, + "-nx --trace gcd.rb 3 5", nil, filter)) + end + end + + def test_linetrace_command + + filter = Proc.new{|got_lines, correct_lines| + got_lines.collect!{|l| l !~ /:rdbg\.rb:/? l : nil}.compact! + } + + testname='linetrace' + Dir.chdir(@@SRC_DIR) do + script = File.join('data', testname + '.cmd') + assert_equal(true, + run_debugger(testname, + "--script #{script} -- gcd.rb 3 5", nil, + filter)) + + end + end + + def test_linetrace_plus_command + + filter = Proc.new{|got_lines, correct_lines| + got_lines.collect!{|l| l !~ /:rdbg\.rb:/? l : nil}.compact! + } + + testname='linetracep' + Dir.chdir(@@SRC_DIR) do + script = File.join('data', testname + '.cmd') + assert_equal(true, + run_debugger(testname, + "--script #{script} -- gcd.rb 3 5", nil, + filter)) + + end + end +end diff --git a/test/thread1.rb b/test/thread1.rb new file mode 100644 index 0000000..26bdf3b --- /dev/null +++ b/test/thread1.rb @@ -0,0 +1,26 @@ +#!/usr/bin/env ruby +# Adapted from Programming Ruby 2nd Ed. p. 138 +require 'rubygems' + +unless defined?(Debugger) + puts "This program has to be called from the debugger" + exit 1 +end + +def fn(count, i) + sleep(rand(0.1)) + if 4 == i + debugger + end + Thread.current['mycount'] = count +end + +count = 0 +threads = [] +5.times do |i| + threads[i] = Thread.new do + fn(count, i) + count += 1 + end + end +threads.each {|t| t.join } diff --git a/test/trunc-call.rb b/test/trunc-call.rb new file mode 100644 index 0000000..d892d4f --- /dev/null +++ b/test/trunc-call.rb @@ -0,0 +1,31 @@ +#!/usr/bin/env ruby +# This program is used to test that 'restart' works when we didn't call +# the debugger initially. + +TOP_SRC_DIR = File.join(File.expand_path(File.dirname(__FILE__), "..")) unless + defined?(TOP_SRC_DIR) + +$:.unshift File.join(TOP_SRC_DIR, "ext") +$:.unshift File.join(TOP_SRC_DIR, "lib") +$:.unshift File.join(TOP_SRC_DIR, "cli") +require 'ruby-debug' + +# GCD. We assume positive numbers +def gcd(a, b) + # Make: a <= b + if a > b + a, b = [b, a] + end + if a==3 + Debugger.debugger + end + + return nil if a <= 0 + + if a == 1 or b-a == 0 + return a + end + return gcd(b-a, a) +end + +gcd(13,8)