needy_debugger 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (187) hide show
  1. data/.gitignore +14 -0
  2. data/.travis.yml +8 -0
  3. data/AUTHORS +10 -0
  4. data/CHANGELOG.md +68 -0
  5. data/CONTRIBUTING.md +1 -0
  6. data/Gemfile +3 -0
  7. data/LICENSE +23 -0
  8. data/OLDER_CHANGELOG +334 -0
  9. data/OLD_CHANGELOG +5655 -0
  10. data/OLD_README +122 -0
  11. data/README.md +141 -0
  12. data/Rakefile +78 -0
  13. data/bin/rdebug +397 -0
  14. data/doc/.cvsignore +42 -0
  15. data/doc/Makefile.am +63 -0
  16. data/doc/emacs-notes.txt +38 -0
  17. data/doc/hanoi.rb +35 -0
  18. data/doc/primes.rb +28 -0
  19. data/doc/rdebug-emacs.texi +1030 -0
  20. data/doc/ruby-debug.texi +3791 -0
  21. data/doc/test-tri2.rb +18 -0
  22. data/doc/tri3.rb +8 -0
  23. data/doc/triangle.rb +12 -0
  24. data/emacs/Makefile.am +130 -0
  25. data/emacs/rdebug-annotate.el +385 -0
  26. data/emacs/rdebug-breaks.el +407 -0
  27. data/emacs/rdebug-cmd.el +92 -0
  28. data/emacs/rdebug-core.el +502 -0
  29. data/emacs/rdebug-dbg.el +62 -0
  30. data/emacs/rdebug-error.el +79 -0
  31. data/emacs/rdebug-fns.el +111 -0
  32. data/emacs/rdebug-frames.el +230 -0
  33. data/emacs/rdebug-gud.el +242 -0
  34. data/emacs/rdebug-help.el +104 -0
  35. data/emacs/rdebug-info.el +83 -0
  36. data/emacs/rdebug-layouts.el +180 -0
  37. data/emacs/rdebug-locring.el +118 -0
  38. data/emacs/rdebug-output.el +106 -0
  39. data/emacs/rdebug-regexp.el +118 -0
  40. data/emacs/rdebug-secondary.el +260 -0
  41. data/emacs/rdebug-shortkey.el +175 -0
  42. data/emacs/rdebug-source.el +568 -0
  43. data/emacs/rdebug-track.el +392 -0
  44. data/emacs/rdebug-varbuf.el +150 -0
  45. data/emacs/rdebug-vars.el +125 -0
  46. data/emacs/rdebug-watch.el +132 -0
  47. data/emacs/rdebug.el +326 -0
  48. data/emacs/test/elk-test.el +242 -0
  49. data/emacs/test/test-annotate.el +103 -0
  50. data/emacs/test/test-cmd.el +116 -0
  51. data/emacs/test/test-core.el +104 -0
  52. data/emacs/test/test-fns.el +65 -0
  53. data/emacs/test/test-frames.el +62 -0
  54. data/emacs/test/test-gud.el +35 -0
  55. data/emacs/test/test-indent.el +58 -0
  56. data/emacs/test/test-regexp.el +144 -0
  57. data/emacs/test/test-shortkey.el +61 -0
  58. data/ext/ruby_debug/192/breakpoint.c +586 -0
  59. data/ext/ruby_debug/192/ruby_debug.c +2645 -0
  60. data/ext/ruby_debug/192/ruby_debug.h +148 -0
  61. data/ext/ruby_debug/193/breakpoint.c +586 -0
  62. data/ext/ruby_debug/193/ruby_debug.c +2626 -0
  63. data/ext/ruby_debug/193/ruby_debug.h +148 -0
  64. data/ext/ruby_debug/200/breakpoint.c +586 -0
  65. data/ext/ruby_debug/200/ruby_debug.c +2692 -0
  66. data/ext/ruby_debug/200/ruby_debug.h +148 -0
  67. data/ext/ruby_debug/extconf.rb +94 -0
  68. data/lib/debugger.rb +5 -0
  69. data/lib/debugger/version.rb +5 -0
  70. data/lib/ruby-debug-base.rb +305 -0
  71. data/lib/ruby-debug.rb +177 -0
  72. data/lib/ruby-debug/command.rb +227 -0
  73. data/lib/ruby-debug/commands/breakpoints.rb +153 -0
  74. data/lib/ruby-debug/commands/catchpoint.rb +55 -0
  75. data/lib/ruby-debug/commands/condition.rb +49 -0
  76. data/lib/ruby-debug/commands/continue.rb +38 -0
  77. data/lib/ruby-debug/commands/control.rb +107 -0
  78. data/lib/ruby-debug/commands/display.rb +120 -0
  79. data/lib/ruby-debug/commands/edit.rb +48 -0
  80. data/lib/ruby-debug/commands/enable.rb +202 -0
  81. data/lib/ruby-debug/commands/eval.rb +176 -0
  82. data/lib/ruby-debug/commands/finish.rb +42 -0
  83. data/lib/ruby-debug/commands/frame.rb +301 -0
  84. data/lib/ruby-debug/commands/help.rb +56 -0
  85. data/lib/ruby-debug/commands/info.rb +467 -0
  86. data/lib/ruby-debug/commands/irb.rb +123 -0
  87. data/lib/ruby-debug/commands/jump.rb +66 -0
  88. data/lib/ruby-debug/commands/kill.rb +51 -0
  89. data/lib/ruby-debug/commands/list.rb +94 -0
  90. data/lib/ruby-debug/commands/method.rb +84 -0
  91. data/lib/ruby-debug/commands/quit.rb +50 -0
  92. data/lib/ruby-debug/commands/reload.rb +40 -0
  93. data/lib/ruby-debug/commands/save.rb +90 -0
  94. data/lib/ruby-debug/commands/set.rb +223 -0
  95. data/lib/ruby-debug/commands/show.rb +247 -0
  96. data/lib/ruby-debug/commands/skip.rb +35 -0
  97. data/lib/ruby-debug/commands/source.rb +36 -0
  98. data/lib/ruby-debug/commands/stepping.rb +81 -0
  99. data/lib/ruby-debug/commands/threads.rb +189 -0
  100. data/lib/ruby-debug/commands/tmate.rb +36 -0
  101. data/lib/ruby-debug/commands/trace.rb +57 -0
  102. data/lib/ruby-debug/commands/variables.rb +199 -0
  103. data/lib/ruby-debug/debugger.rb +5 -0
  104. data/lib/ruby-debug/helper.rb +69 -0
  105. data/lib/ruby-debug/interface.rb +232 -0
  106. data/lib/ruby-debug/processor.rb +474 -0
  107. data/man/rdebug.1 +241 -0
  108. data/needy_debugger.gemspec +31 -0
  109. data/old_scripts/Makefile.am +14 -0
  110. data/old_scripts/README.md +2 -0
  111. data/old_scripts/autogen.sh +4 -0
  112. data/old_scripts/configure.ac +12 -0
  113. data/old_scripts/rdbg.rb +33 -0
  114. data/old_scripts/runner.sh +7 -0
  115. data/old_scripts/svn2cl_usermap +3 -0
  116. data/test/.cvsignore +1 -0
  117. data/test/breakpoints_test.rb +365 -0
  118. data/test/conditions_test.rb +76 -0
  119. data/test/continue_test.rb +28 -0
  120. data/test/display_test.rb +141 -0
  121. data/test/edit_test.rb +55 -0
  122. data/test/eval_test.rb +92 -0
  123. data/test/examples/breakpoint1.rb +15 -0
  124. data/test/examples/breakpoint2.rb +7 -0
  125. data/test/examples/conditions.rb +4 -0
  126. data/test/examples/continue.rb +4 -0
  127. data/test/examples/display.rb +5 -0
  128. data/test/examples/edit.rb +3 -0
  129. data/test/examples/edit2.rb +3 -0
  130. data/test/examples/eval.rb +4 -0
  131. data/test/examples/finish.rb +20 -0
  132. data/test/examples/frame.rb +31 -0
  133. data/test/examples/help.rb +2 -0
  134. data/test/examples/info.rb +48 -0
  135. data/test/examples/info2.rb +3 -0
  136. data/test/examples/irb.rb +6 -0
  137. data/test/examples/jump.rb +14 -0
  138. data/test/examples/kill.rb +2 -0
  139. data/test/examples/list.rb +12 -0
  140. data/test/examples/method.rb +15 -0
  141. data/test/examples/post_mortem.rb +19 -0
  142. data/test/examples/quit.rb +2 -0
  143. data/test/examples/reload.rb +6 -0
  144. data/test/examples/restart.rb +6 -0
  145. data/test/examples/save.rb +3 -0
  146. data/test/examples/set.rb +3 -0
  147. data/test/examples/set_annotate.rb +12 -0
  148. data/test/examples/settings.rb +1 -0
  149. data/test/examples/show.rb +2 -0
  150. data/test/examples/source.rb +3 -0
  151. data/test/examples/stepping.rb +21 -0
  152. data/test/examples/thread.rb +32 -0
  153. data/test/examples/tmate.rb +10 -0
  154. data/test/examples/trace.rb +7 -0
  155. data/test/examples/trace_threads.rb +20 -0
  156. data/test/examples/variables.rb +26 -0
  157. data/test/finish_test.rb +48 -0
  158. data/test/frame_test.rb +140 -0
  159. data/test/help_test.rb +50 -0
  160. data/test/info_test.rb +325 -0
  161. data/test/irb_test.rb +81 -0
  162. data/test/jump_test.rb +70 -0
  163. data/test/kill_test.rb +47 -0
  164. data/test/list_test.rb +145 -0
  165. data/test/method_test.rb +70 -0
  166. data/test/post_mortem_test.rb +25 -0
  167. data/test/quit_test.rb +55 -0
  168. data/test/reload_test.rb +43 -0
  169. data/test/restart_test.rb +143 -0
  170. data/test/save_test.rb +92 -0
  171. data/test/set_test.rb +177 -0
  172. data/test/show_test.rb +292 -0
  173. data/test/source_test.rb +44 -0
  174. data/test/stepping_test.rb +118 -0
  175. data/test/support/breakpoint.rb +12 -0
  176. data/test/support/context.rb +14 -0
  177. data/test/support/matchers.rb +67 -0
  178. data/test/support/mocha_extensions.rb +71 -0
  179. data/test/support/processor.rb +7 -0
  180. data/test/support/test_dsl.rb +205 -0
  181. data/test/support/test_interface.rb +66 -0
  182. data/test/test_helper.rb +8 -0
  183. data/test/thread_test.rb +122 -0
  184. data/test/tmate_test.rb +43 -0
  185. data/test/trace_test.rb +154 -0
  186. data/test/variables_test.rb +114 -0
  187. metadata +352 -0
@@ -0,0 +1,148 @@
1
+ /* Context info */
2
+ enum ctx_stop_reason {CTX_STOP_NONE, CTX_STOP_STEP, CTX_STOP_BREAKPOINT,
3
+ CTX_STOP_CATCHPOINT};
4
+
5
+ /* Context flags */
6
+ #define CTX_FL_SUSPEND (1<<1)
7
+ #define CTX_FL_TRACING (1<<2)
8
+ #define CTX_FL_SKIPPED (1<<3)
9
+ #define CTX_FL_IGNORE (1<<4)
10
+ #define CTX_FL_DEAD (1<<5)
11
+ #define CTX_FL_WAS_RUNNING (1<<6)
12
+ #define CTX_FL_ENABLE_BKPT (1<<7)
13
+ #define CTX_FL_STEPPED (1<<8)
14
+ #define CTX_FL_FORCE_MOVE (1<<9)
15
+ #define CTX_FL_CATCHING (1<<10)
16
+
17
+ #define CTX_FL_TEST(c,f) ((c)->flags & (f))
18
+ #define CTX_FL_SET(c,f) do { (c)->flags |= (f); } while (0)
19
+ #define CTX_FL_UNSET(c,f) do { (c)->flags &= ~(f); } while (0)
20
+
21
+ typedef struct {
22
+ struct iseq_catch_table_entry tmp_catch_table;
23
+ struct iseq_catch_table_entry *old_catch_table;
24
+ int old_catch_table_size;
25
+ VALUE mod_name;
26
+ VALUE errinfo;
27
+ } debug_catch_t;
28
+
29
+ typedef struct {
30
+ struct rb_iseq_struct *iseq;
31
+ struct iseq_catch_table_entry *catch_table;
32
+ int catch_table_size;
33
+ } iseq_catch_t;
34
+
35
+ typedef struct {
36
+ int argc; /* Number of arguments a frame should have. */
37
+ VALUE binding;
38
+ ID id;
39
+ ID orig_id;
40
+ int line;
41
+ const char * file;
42
+ short dead;
43
+ VALUE self;
44
+ VALUE arg_ary;
45
+ union {
46
+ struct {
47
+ rb_control_frame_t *cfp;
48
+ VALUE *bp;
49
+ struct rb_iseq_struct *block_iseq;
50
+ VALUE *block_pc;
51
+ VALUE *last_pc;
52
+ } runtime;
53
+ struct {
54
+ VALUE args;
55
+ VALUE locals;
56
+ VALUE arg_ary;
57
+ } copy;
58
+ } info;
59
+ } debug_frame_t;
60
+
61
+ typedef struct {
62
+ VALUE thread_id;
63
+ int thnum;
64
+ int flags;
65
+ enum ctx_stop_reason stop_reason;
66
+ int stop_next;
67
+ int dest_frame;
68
+ int stop_line;
69
+ int stop_frame;
70
+ int stack_size;
71
+ int stack_len;
72
+ debug_frame_t *frames;
73
+ const char * last_file;
74
+ int last_line;
75
+ VALUE breakpoint;
76
+ debug_catch_t catch_table;
77
+ VALUE saved_jump_ins[2];
78
+ rb_control_frame_t *jump_cfp;
79
+ VALUE *jump_pc;
80
+ iseq_catch_t *old_iseq_catch;
81
+ volatile int thread_pause;
82
+ } debug_context_t;
83
+
84
+ /* variables in ruby_debug.c */
85
+ extern VALUE mDebugger;
86
+ extern VALUE rdebug_breakpoints;
87
+ extern VALUE rdebug_catchpoints;
88
+ extern VALUE rdebug_threads_tbl;
89
+
90
+ /* routines in ruby_debug.c */
91
+ extern int filename_cmp(VALUE source, char *file);
92
+
93
+ #define IS_STARTED (rdebug_threads_tbl != Qnil)
94
+ static inline void
95
+ debug_check_started()
96
+ {
97
+ if(!IS_STARTED)
98
+ {
99
+ rb_raise(rb_eRuntimeError, "Debugger.start is not called yet.");
100
+ }
101
+ }
102
+
103
+ static inline int
104
+ classname_cmp(VALUE name, VALUE klass)
105
+ {
106
+ VALUE mod_name;
107
+ VALUE class_name = (Qnil == name) ? rb_str_new2("main") : name;
108
+ if (klass == Qnil) return(0);
109
+ mod_name = rb_mod_name(klass);
110
+ return (mod_name != Qnil
111
+ && rb_str_cmp(class_name, mod_name) == 0);
112
+ }
113
+
114
+ /* Breakpoint information */
115
+ enum bp_type {BP_POS_TYPE, BP_METHOD_TYPE};
116
+ enum hit_condition {HIT_COND_NONE, HIT_COND_GE, HIT_COND_EQ, HIT_COND_MOD};
117
+
118
+ typedef struct {
119
+ int id;
120
+ enum bp_type type;
121
+ VALUE source;
122
+ union
123
+ {
124
+ int line;
125
+ ID mid;
126
+ } pos;
127
+ VALUE expr;
128
+ VALUE enabled;
129
+ int hit_count;
130
+ int hit_value;
131
+ enum hit_condition hit_condition;
132
+ } debug_breakpoint_t;
133
+
134
+ /* routines in breakpoint.c */
135
+ extern int check_breakpoint_expression(VALUE breakpoint, VALUE binding);
136
+ extern int check_breakpoint_hit_condition(VALUE breakpoint);
137
+ extern VALUE check_breakpoints_by_method(debug_context_t *debug_context,
138
+ VALUE klass, ID mid, VALUE self);
139
+ extern VALUE check_breakpoints_by_pos(debug_context_t *debug_context,
140
+ char *file, int line);
141
+ extern VALUE create_breakpoint_from_args(int argc, VALUE *argv, int id);
142
+ extern VALUE context_breakpoint(VALUE self);
143
+ extern VALUE context_set_breakpoint(int argc, VALUE *argv, VALUE self);
144
+ extern VALUE rdebug_add_catchpoint(VALUE self, VALUE value);
145
+ extern VALUE debug_catchpoints(VALUE self);
146
+ extern VALUE rdebug_remove_breakpoint(VALUE self, VALUE id_value);
147
+
148
+ extern void Init_breakpoint();
@@ -0,0 +1,94 @@
1
+ # autodetect ruby headers
2
+ unless ARGV.any? {|arg| arg.include?('--with-ruby-include') }
3
+ require 'rbconfig'
4
+ bindir = RbConfig::CONFIG['bindir']
5
+ if bindir =~ %r{(^.*/\.rbenv/versions)/([^/]+)/bin$}
6
+ ruby_include = "#{$1}/#{$2}/include/ruby-#{RUBY_VERSION.start_with?("1.9") ? "1.9.1" : RUBY_VERSION}/ruby-#{$2}"
7
+ ARGV << "--with-ruby-include=#{ruby_include}"
8
+ elsif bindir =~ %r{(^.*/\.rvm/rubies)/([^/]+)/bin$}
9
+ ruby_include = "#{$1}/#{$2}/include/ruby-#{RUBY_VERSION.start_with?("1.9") ? "1.9.1" : RUBY_VERSION}/#{$2}"
10
+ ruby_include = "#{ENV['rvm_path']}/src/#{$2}" unless File.exist?(ruby_include)
11
+ ARGV << "--with-ruby-include=#{ruby_include}"
12
+ end
13
+ end
14
+
15
+ require "mkmf"
16
+ require "debugger/ruby_core_source"
17
+ require 'fileutils'
18
+
19
+ if RUBY_VERSION < "1.9"
20
+ STDERR.print("Ruby version is too old\n")
21
+ exit(1)
22
+ end
23
+
24
+ hdrs = if RUBY_VERSION == '1.9.2'
25
+ lambda {
26
+ have_struct_member("rb_method_entry_t", "body", "method.h")
27
+ have_header("vm_core.h") and have_header("iseq.h") and have_header("insns.inc") and
28
+ have_header("insns_info.inc") and have_header("eval_intern.h")
29
+ }
30
+ elsif RUBY_VERSION == '1.9.3'
31
+ lambda {
32
+ iseqs = %w[vm_core.h iseq.h]
33
+ begin
34
+ have_struct_member("rb_method_entry_t", "called_id", "method.h") or
35
+ have_struct_member("rb_control_frame_t", "method_id", "method.h")
36
+ end and
37
+ have_header("vm_core.h") and have_header("iseq.h") and have_header("insns.inc") and
38
+ have_header("insns_info.inc") and have_header("eval_intern.h") or return(false)
39
+ have_type("struct iseq_line_info_entry", iseqs) or
40
+ have_type("struct iseq_insn_info_entry", iseqs) or
41
+ return(false)
42
+ if checking_for(checking_message("if rb_iseq_compile_with_option was added an argument filepath")) do
43
+ try_compile(<<SRC)
44
+ #include <ruby.h>
45
+ #include "vm_core.h"
46
+ extern VALUE rb_iseq_new_main(NODE *node, VALUE filename, VALUE filepath);
47
+ SRC
48
+ end
49
+ $defs << '-DRB_ISEQ_COMPILE_5ARGS'
50
+ end
51
+ }
52
+ elsif RUBY_VERSION == '2.0.0'
53
+ lambda {
54
+ iseqs = %w[vm_core.h iseq.h]
55
+ begin
56
+ have_struct_member("rb_method_entry_t", "called_id", "method.h") or
57
+ have_struct_member("rb_control_frame_t", "method_id", "method.h")
58
+ end and
59
+ have_header("vm_core.h") and have_header("iseq.h") and have_header("insns.inc") and
60
+ have_header("insns_info.inc") and have_header("eval_intern.h") or return(false)
61
+ have_type("struct iseq_line_info_entry", iseqs) or
62
+ have_type("struct iseq_insn_info_entry", iseqs) or
63
+ return(false)
64
+ if checking_for(checking_message("if rb_iseq_compile_with_option was added an argument filepath")) do
65
+ try_compile(<<SRC)
66
+ #include <ruby.h>
67
+ #include "vm_core.h"
68
+ extern VALUE rb_iseq_new_main(NODE *node, VALUE filename, VALUE filepath);
69
+ SRC
70
+ end
71
+ $defs << "-DHAVE_RB_ISEQ_COMPILE_ON_BASE -DVM_DEBUG_BP_CHECK -DHAVE_RB_CONTROL_FRAME_T_EP -DHAVE_RB_ISEQ_T_LOCATION -DHAVE_RB_ISEQ_T_LINE_INFO_SIZE "
72
+ end
73
+ }
74
+ else
75
+ STDERR.puts "Ruby version #{RUBY_VERSION} is not supported."
76
+ exit(1)
77
+ end
78
+
79
+
80
+ header_dir = RUBY_VERSION.gsub('.', '')
81
+ current_dir = File.dirname(__FILE__)
82
+ %w{ruby_debug.h ruby_debug.c breakpoint.c}.each do |file|
83
+ FileUtils.cp("#{current_dir}/#{header_dir}/#{file}", current_dir)
84
+ end
85
+
86
+ dir_config("ruby")
87
+ if !Debugger::RubyCoreSource.create_makefile_with_core(hdrs, "ruby_debug")
88
+ STDERR.print("Makefile creation failed\n")
89
+ STDERR.print("*************************************************************\n\n")
90
+ STDERR.print(" NOTE: If your headers were not found, try passing\n")
91
+ STDERR.print(" --with-ruby-include=PATH_TO_HEADERS \n\n")
92
+ STDERR.print("*************************************************************\n\n")
93
+ exit(1)
94
+ end
@@ -0,0 +1,5 @@
1
+ module Debugger
2
+ end
3
+
4
+ require 'ruby-debug'
5
+ require 'debugger/version'
@@ -0,0 +1,5 @@
1
+ module Debugger
2
+ # TODO: remove version from C ext
3
+ send :remove_const, :VERSION if const_defined? :VERSION
4
+ VERSION = '1.4.0'
5
+ end
@@ -0,0 +1,305 @@
1
+ require 'ruby_debug.so'
2
+ require 'linecache19'
3
+
4
+ module Debugger
5
+
6
+ # Default options to Debugger.start
7
+ DEFAULT_START_SETTINGS = {
8
+ :init => true, # Set $0 and save ARGV?
9
+ :post_mortem => false, # post-mortem debugging on uncaught exception?
10
+ :tracing => nil # Debugger.tracing value. true/false resets,
11
+ # nil keeps the prior value
12
+ } unless defined?(DEFAULT_START_SETTINGS)
13
+
14
+ class Context
15
+ def interrupt
16
+ self.stop_next = 1
17
+ end
18
+
19
+ alias __c_frame_binding frame_binding
20
+ def frame_binding(frame)
21
+ __c_frame_binding(frame) || hbinding(frame)
22
+ end
23
+
24
+ private
25
+
26
+ def hbinding(frame)
27
+ hash = frame_locals(frame)
28
+ code = hash.keys.map{|k| "#{k} = hash['#{k}']" unless k=='self' }.compact.join(';') + ';binding'
29
+ if obj = frame_self(frame)
30
+ obj.instance_eval code
31
+ else
32
+ eval code, TOPLEVEL_BINDING
33
+ end
34
+ end
35
+
36
+ def handler
37
+ Debugger.handler or raise 'No interface loaded'
38
+ end
39
+
40
+ def at_breakpoint(breakpoint)
41
+ handler.at_breakpoint(self, breakpoint)
42
+ end
43
+
44
+ def at_catchpoint(excpt)
45
+ handler.at_catchpoint(self, excpt)
46
+ end
47
+
48
+ def at_tracing(file, line)
49
+ @tracing_started = File.identical?(file, Debugger::PROG_SCRIPT)
50
+ handler.at_tracing(self, file, line) if @tracing_started
51
+ end
52
+
53
+ def at_line(file, line)
54
+ handler.at_line(self, file, line)
55
+ end
56
+
57
+ def at_return(file, line)
58
+ handler.at_return(self, file, line)
59
+ end
60
+ end
61
+
62
+ @reload_source_on_change = false
63
+ @tracing_started = false
64
+
65
+ class << self
66
+ # interface modules provide +handler+ object
67
+ attr_accessor :handler
68
+
69
+ # if <tt>true</tt>, checks the modification time of source files and reloads if it was modified
70
+ attr_accessor :reload_source_on_change
71
+
72
+ attr_accessor :last_exception
73
+ Debugger.last_exception = nil
74
+
75
+ #
76
+ # Interrupts the current thread
77
+ #
78
+ def interrupt
79
+ current_context.interrupt
80
+ end
81
+
82
+ #
83
+ # Interrupts the last debugged thread
84
+ #
85
+ def interrupt_last
86
+ if context = last_context
87
+ return nil unless context.thread.alive?
88
+ context.interrupt
89
+ end
90
+ context
91
+ end
92
+
93
+ def source_reload
94
+ Object.send(:remove_const, "SCRIPT_LINES__") if Object.const_defined?("SCRIPT_LINES__")
95
+ Object.const_set("SCRIPT_LINES__", {})
96
+ LineCache::clear_file_cache
97
+ end
98
+
99
+ # Get line +line_number+ from file named +filename+. Return "\n"
100
+ # there was a problem. Leaking blanks are stripped off.
101
+ def line_at(filename, line_number) # :nodoc:
102
+ @reload_on_change=nil unless defined?(@reload_on_change)
103
+ line = LineCache::getline(filename, line_number, @reload_on_change)
104
+ return "\n" unless line
105
+ return "#{line.gsub(/^\s+/, '').chomp}\n"
106
+ end
107
+
108
+ #
109
+ # Activates the post-mortem mode. There are two ways of using it:
110
+ #
111
+ # == Global post-mortem mode
112
+ # By calling Debugger.post_mortem method without a block, you install
113
+ # at_exit hook that intercepts any unhandled by your script exceptions
114
+ # and enables post-mortem mode.
115
+ #
116
+ # == Local post-mortem mode
117
+ #
118
+ # If you know that a particular block of code raises an exception you can
119
+ # enable post-mortem mode by wrapping this block with Debugger.post_mortem, e.g.
120
+ #
121
+ # def offender
122
+ # raise 'error'
123
+ # end
124
+ # Debugger.post_mortem do
125
+ # ...
126
+ # offender
127
+ # ...
128
+ # end
129
+ def post_mortem
130
+ if block_given?
131
+ old_post_mortem = self.post_mortem?
132
+ begin
133
+ self.post_mortem = true
134
+ yield
135
+ rescue Exception => exp
136
+ handle_post_mortem(exp)
137
+ raise
138
+ ensure
139
+ self.post_mortem = old_post_mortem
140
+ end
141
+ else
142
+ return if post_mortem?
143
+ self.post_mortem = true
144
+ debug_at_exit do
145
+ handle_post_mortem($!) if $! && post_mortem?
146
+ end
147
+ end
148
+ end
149
+
150
+ def handle_post_mortem(exp)
151
+ return if !exp || !exp.__debug_context ||
152
+ exp.__debug_context.stack_size == 0
153
+ Debugger.suspend
154
+ orig_tracing = Debugger.tracing, Debugger.current_context.tracing
155
+ Debugger.tracing = Debugger.current_context.tracing = false
156
+ Debugger.last_exception = exp
157
+ handler.at_line(exp.__debug_context, exp.__debug_file, exp.__debug_line)
158
+ ensure
159
+ Debugger.tracing, Debugger.current_context.tracing = orig_tracing
160
+ Debugger.resume
161
+ end
162
+ # private :handle_post_mortem
163
+ end
164
+
165
+ class DebugThread # :nodoc:
166
+ end
167
+
168
+ class ThreadsTable # :nodoc:
169
+ end
170
+
171
+ # Debugger.start(options) -> bool
172
+ # Debugger.start(options) { ... } -> obj
173
+ #
174
+ # If it's called without a block it returns +true+, unless debugger
175
+ # was already started. If a block is given, it starts debugger and
176
+ # yields to block. When the block is finished executing it stops
177
+ # the debugger with Debugger.stop method.
178
+ #
179
+ # If a block is given, it starts debugger and yields to block. When
180
+ # the block is finished executing it stops the debugger with
181
+ # Debugger.stop method. Inside the block you will probably want to
182
+ # have a call to Debugger.debugger. For example:
183
+ #
184
+ # Debugger.start{debugger; foo} # Stop inside of foo
185
+ #
186
+ # Also, ruby-debug only allows
187
+ # one invocation of debugger at a time; nested Debugger.start's
188
+ # have no effect and you can't use this inside the debugger itself.
189
+ #
190
+ # <i>Note that if you want to stop debugger, you must call
191
+ # Debugger.stop as many time as you called Debugger.start
192
+ # method.</i>
193
+ #
194
+ # +options+ is a hash used to set various debugging options.
195
+ # Set :init true if you want to save ARGV and some variables which
196
+ # make a debugger restart possible. Only the first time :init is set true
197
+ # will values get set. Since ARGV is saved, you should make sure
198
+ # it hasn't been changed before the (first) call.
199
+ # Set :post_mortem true if you want to enter post-mortem debugging
200
+ # on an uncaught exception. Once post-mortem debugging is set, it can't
201
+ # be unset.
202
+ def start(options={}, &block)
203
+ options = Debugger::DEFAULT_START_SETTINGS.merge(options)
204
+ if options[:init]
205
+ Debugger.const_set('ARGV', ARGV.clone) unless
206
+ defined? Debugger::ARGV
207
+ Debugger.const_set('PROG_SCRIPT', $0) unless
208
+ defined? Debugger::PROG_SCRIPT
209
+ Debugger.const_set('INITIAL_DIR', Dir.pwd) unless
210
+ defined? Debugger::INITIAL_DIR
211
+ end
212
+ Debugger.tracing = options[:tracing] unless options[:tracing].nil?
213
+ retval = Debugger.started? ? block && block.call(self) : Debugger.start_(&block)
214
+ if options[:post_mortem]
215
+ post_mortem
216
+ end
217
+ return retval
218
+ end
219
+ module_function :start
220
+ end
221
+
222
+ module Kernel
223
+
224
+ # Enters the debugger in the current thread after _steps_ line events occur.
225
+ # Before entering the debugger startup script is read.
226
+ #
227
+ # Setting _steps_ to 0 will cause a break in the debugger subroutine
228
+ # and not wait for a line event to occur. You will have to go "up 1"
229
+ # in order to be back in your debugged program rather than the
230
+ # debugger. Settings _steps_ to 0 could be useful you want to stop
231
+ # right after the last statement in some scope, because the next
232
+ # step will take you out of some scope.
233
+
234
+ # If a block is given (and the debugger hasn't been started, we run the
235
+ # block under the debugger. Alas, when a block is given, we can't support
236
+ # running the startup script or support the steps option. FIXME.
237
+ def debugger(steps = 1, &block)
238
+ if block
239
+ Debugger.start({}, &block)
240
+ else
241
+ Debugger.start unless Debugger.started?
242
+ Debugger.run_init_script(StringIO.new)
243
+ if 0 == steps
244
+ Debugger.current_context.stop_frame = 0
245
+ else
246
+ Debugger.current_context.stop_next = steps
247
+ end
248
+ end
249
+ end
250
+ alias breakpoint debugger unless respond_to?(:breakpoint)
251
+
252
+ #
253
+ # Returns a binding of n-th call frame
254
+ #
255
+ def binding_n(n = 0)
256
+ Debugger.skip do
257
+ if RUBY_VERSION < "1.9"
258
+ Debugger.current_context.frame_binding(n+2)
259
+ else
260
+ Debugger.current_context.frame_binding(n+1)
261
+ end
262
+ end
263
+ end
264
+ end
265
+
266
+ class Exception # :nodoc:
267
+ attr_reader :__debug_file, :__debug_line, :__debug_binding, :__debug_context
268
+ end
269
+
270
+ class Module
271
+ #
272
+ # Wraps the +meth+ method with Debugger.start {...} block.
273
+ #
274
+ def debug_method(meth)
275
+ old_meth = "__debugee_#{meth}"
276
+ old_meth = "#{$1}_set" if old_meth =~ /^(.+)=$/
277
+ alias_method old_meth.to_sym, meth
278
+ class_eval <<-EOD
279
+ def #{meth}(*args, &block)
280
+ Debugger.start do
281
+ debugger 2
282
+ #{old_meth}(*args, &block)
283
+ end
284
+ end
285
+ EOD
286
+ end
287
+
288
+ #
289
+ # Wraps the +meth+ method with Debugger.post_mortem {...} block.
290
+ #
291
+ def post_mortem_method(meth)
292
+ old_meth = "__postmortem_#{meth}"
293
+ old_meth = "#{$1}_set" if old_meth =~ /^(.+)=$/
294
+ alias_method old_meth.to_sym, meth
295
+ class_eval <<-EOD
296
+ def #{meth}(*args, &block)
297
+ Debugger.start do |dbg|
298
+ dbg.post_mortem do
299
+ #{old_meth}(*args, &block)
300
+ end
301
+ end
302
+ end
303
+ EOD
304
+ end
305
+ end