ruby-debug-base 0.10.0 → 0.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/CHANGES CHANGED
@@ -1,4 +1,96 @@
1
+ 0.10.1
2
+ 4/10/08 - in honor of the 30th Birthday of Kate Schwarz
3
+
4
+ - bin/rdebug
5
+
6
+ * "rdebug --post-mortem" now really catches uncaught exceptions and
7
+ brings you to post-mortem handling. "info program" shows the exception.
8
+
9
+ * rdebug now searches using ENV['PATH'] for a Ruby program to debug
10
+ if the program name is not found and doesn't have any path
11
+ characters in it.
12
+
13
+ * Use ~/.rdboptrc (rdbopt.ini on MS Windows) to change default options.
14
+
15
+ * --emacs is now --emacs-basic while --emacs 3 now implies emacs-basic
16
+ ---annotate=3 --post-mortem --no-control --no-start --no-quit
17
+
18
+ - rdebug (CLI)
19
+
20
+ * "info" command additions and changes:
21
+ o fix bug in "info variables" when string had embedded %s'
22
+ o "info program" now shows uncaught exception information
23
+ o "info files" show what Ruby files are loaded
24
+ o "info file <f>" specific file information of <f> (e.g. time, # of lines, SHA1)
25
+ o "info catch" - Exceptions that can be caught in the current stack frame.
26
+ o "info "variables" shows "self" and class variables
27
+ o "info threads verbose" shows stack trace of all threads
28
+ o "info thread <t> verbose" shows stack trace of thread <t>.
29
+
30
+ * "frame" command now accepts an optional thread number argument
31
+
32
+ * Long information added to commands with subcommands: show, set,
33
+ info, enable, and disable. For example "help info <xxx>" will give
34
+ more detailed information about the "info <xxx>" command.
35
+
36
+ * columnize now pulled in from a separate package.
37
+
38
+ * add "var cl[ass]" command. Note "var const" can no longer be
39
+ abbreviated "var c"; use "var co" (or const or constant).
40
+
41
+ * add "condition" command. Allow removal of condition.
42
+
43
+ * $0 == __FILE__ when running rdebug should work -- most of the
44
+ time. See comments in code for a better solution.
45
+
46
+ * rdebug command history can be displayed with "show commands". Fix a bug
47
+ in history saving.
48
+
49
+ * INCOMPATIBLE CHANGE: "finish" works like gdb - stop just before the most
50
+ recent method finishes. Will now accept a number which stops that many
51
+ frames completed. (Note that return line numbers will be funny, the
52
+ first line of the method until Ruby 1.8.7.)
53
+
54
+ * fix bug in 'list' command when wrapping off the end.
55
+
56
+ - Emacs interaction drastically reworked, expanded, and improved.
57
+
58
+ - rdebug base
59
+ * allow catching multiple exceptions.
60
+ INCOMPATIBLE CHANGE: variable "Debugger.catchpoint", a String, was turned
61
+ into "Debugger.catchpoints", a Hash. Method "Debugger.catchpoint=" no
62
+ longer exists. Debugger.set_catchpoint was turned into
63
+ Debugger.add_catchpoint
64
+
65
+ * Add Debugger.last_exception which is set in post-mortem.
66
+
67
+ * remove Debugger.stop() when an exception is raised that would terminate the
68
+ debugged program. This may allow catchpoints to work and allow tracing user
69
+ code which handles "Exit" exceptions
70
+
71
+ * split off breakpoint code in ruby_debug.c.
72
+
73
+ * preface ruby_debug global Ruby variables with rdebug_.
74
+
75
+ * Change Debugger.start() to accept an optional options argument
76
+ :init => true saves things (like $0 and ARGV) necessary to
77
+ allow restart. Default: true
78
+ :post_mortem => true runs post-mortem on an uncaught exception
79
+ Default: false
80
+
81
+ The old Debugger.start() is now renamed to Debugger.start_()
82
+
83
+ * split of line caching to an external gem. We now only allow setting
84
+ breakpoints on lines where it makes sense to do so.
85
+
86
+ * Incompatible enhancement: even return/end will now call event handler
87
+
88
+ See ChangeLog for full details, and the reference guide for more complete
89
+ documentation of these changes.
90
+
1
91
  0.10.0
92
+ 12/25/07
93
+
2
94
  - '-r' option can be used to require additional libraries.
3
95
  - --noquit option added to stay in debugger when the program exits
4
96
  - gdb-like --annotate option added. Can be used by front-ends to get information
@@ -27,7 +119,7 @@
27
119
  - INCOMPATIBLE CHANGE: "script" command removed. Use "source" command instead
28
120
  (same as gdb).
29
121
  - Run .rdebugrc on Debugger.start. Look for a file in the current directory and
30
- run that instead the one in $HOME if that exists. Again, inspired and compatible
122
+ run that instead of the one in $HOME if that exists. Again, inspired by and compatible
31
123
  with gdb.
32
124
  - Changes compatible with Ruby 1.9. NOTE: this debugger will NOT work with
33
125
  Ruby 1.9
@@ -35,7 +127,7 @@
35
127
  is also cleared when leaving irb
36
128
  - help "foo" gives message "Undefined command "foo" rather than a list
37
129
  of help commands. (Message test is gdb's)
38
- - Add set linetrace+ - similar step+ for linetrace
130
+ - Add set linetrace+ - similar to step+ for linetrace
39
131
  - Start unit tests.
40
132
  - Start a reference guide.
41
133
 
data/README CHANGED
@@ -14,6 +14,12 @@ are sometimes available), you'll need a C compiler and Ruby
14
14
  development headers, and a Make program so the extension in
15
15
  ruby-debug-base can be compiled when it is installed.
16
16
 
17
+ To install on Microsoft Windows, unless you run under cygwin or mingw
18
+ you'll need Microsoft Visual C++ 6.0 also known as VC6.
19
+ http://rubyforge.org/tracker/index.php?func=detail&aid=16774&group_id=1900&atid=7436
20
+ suggests why.
21
+
22
+
17
23
  == Install
18
24
 
19
25
  ruby-debug is provided as a RubyGem. To install:
@@ -22,6 +28,10 @@ ruby-debug is provided as a RubyGem. To install:
22
28
 
23
29
  This should also pull in <tt>ruby-debug-base</tt> as a dependency.
24
30
 
31
+ (If you install ruby-debug-base explicitly, you can add in the secret
32
+ --test option after "install" to have the regression test run before
33
+ installing.)
34
+
25
35
  For Emacs support and the Reference Manual, get
26
36
  <tt>ruby-debug-extra</tt>. This is not a RubyGem, you'll need a Make
27
37
  program and a POSIX shell. With this installed, run:
@@ -29,9 +39,28 @@ program and a POSIX shell. With this installed, run:
29
39
  <pre>
30
40
  sh ./configure
31
41
  make
32
- make install
42
+ make test # optional, but a good idea
43
+ sudo make install
33
44
  </pre>
34
45
 
46
+ ==== Install on MS Windows
47
+
48
+ Compiling under cygwin or mingw works like it does on Unix.
49
+
50
+ * Have Microsoft Visual C++ 6.0 (VC6) installed - exactly that version.
51
+
52
+ * Set the appropriate environment variables.
53
+
54
+ * run `nmake'.
55
+
56
+ * Copy ruby_debug.so to `win32'.
57
+
58
+ * Go to the ruby_debug root.
59
+
60
+ * rake win32_gem
61
+
62
+ * The file is in named `rdebug-debug-base-0.10.0-mswin32.gem'.
63
+
35
64
  == Usage
36
65
 
37
66
  There are two ways of running ruby-debug.
data/Rakefile CHANGED
@@ -8,7 +8,9 @@ require 'rake/testtask'
8
8
  SO_NAME = "ruby_debug.so"
9
9
 
10
10
  # ------- Default Package ----------
11
- RUBY_DEBUG_VERSION = open("ext/ruby_debug.c"){|f| f.grep(/^#define DEBUG_VERSION/).first[/"(.+)"/,1]}
11
+ RUBY_DEBUG_VERSION = open("ext/ruby_debug.c") do |f|
12
+ f.grep(/^#define DEBUG_VERSION/).first[/"(.+)"/,1]
13
+ end
12
14
 
13
15
  COMMON_FILES = FileList[
14
16
  'AUTHORS',
@@ -18,35 +20,35 @@ COMMON_FILES = FileList[
18
20
  'Rakefile',
19
21
  ]
20
22
 
21
- CLI_TEST_FILE_LIST = 'test/**/*test-*.rb'
23
+ CLI_TEST_FILE_LIST = 'test/test-*.rb'
22
24
  CLI_FILES = COMMON_FILES + FileList[
23
25
  "cli/**/*",
24
26
  'ChangeLog',
25
27
  'bin/*',
26
28
  'doc/rdebug.1',
27
- 'test/**/*.cmd',
28
- 'test/**/*.right',
29
- 'test/**/gcd.rb',
30
- 'test/**/helper.rb',
31
- 'test/**/info-var-bug.rb',
32
- 'test/**/tdebug.rb',
33
- 'test/**/test-*.cmd',
34
- 'runner.sh',
29
+ 'test/**/data/*.cmd',
30
+ 'test/**/data/*.right',
31
+ 'test/**/*.rb',
32
+ 'rdbg.rb',
35
33
  CLI_TEST_FILE_LIST,
36
34
  ]
37
35
 
38
- BASE_TEST_FILE_LIST = 'test/test-ruby-debug-base.rb'
36
+ BASE_TEST_FILE_LIST = %w(
37
+ test/base/base.rb
38
+ test/base/binding.rb
39
+ test/base/catchpoint.rb)
39
40
  BASE_FILES = COMMON_FILES + FileList[
40
- 'lib/**/*',
41
- 'ext/ChangeLog',
42
- 'ext/ruby_debug.c',
41
+ 'ext/breakpoint.c',
43
42
  'ext/extconf.rb',
43
+ 'ext/ruby_debug.c',
44
+ 'ext/ruby_debug.h',
44
45
  'ext/win32/*',
46
+ 'lib/**/*',
45
47
  BASE_TEST_FILE_LIST,
46
48
  ]
47
49
 
48
50
  desc "Test everything."
49
- test_task = task :test => :lib do
51
+ test_task = task :test => [:lib, :test_base] do
50
52
  Rake::TestTask.new(:test) do |t|
51
53
  t.libs << ['./ext', './lib', './cli']
52
54
  t.pattern = CLI_TEST_FILE_LIST
@@ -54,6 +56,15 @@ test_task = task :test => :lib do
54
56
  end
55
57
  end
56
58
 
59
+ desc "Test ruby-debug-base."
60
+ test_task = task :test_base => :lib do
61
+ Rake::TestTask.new(:test_base) do |t|
62
+ t.libs << ['./ext', './lib']
63
+ t.test_files = FileList[BASE_TEST_FILE_LIST]
64
+ t.verbose = true
65
+ end
66
+ end
67
+
57
68
  desc "Test everything - same as test."
58
69
  task :check => :test
59
70
 
@@ -99,12 +110,12 @@ EOF
99
110
  spec.platform = Gem::Platform::RUBY
100
111
  spec.require_path = "lib"
101
112
  spec.extensions = ["ext/extconf.rb"]
102
- spec.autorequire = "ruby-debug-base"
103
113
  spec.files = BASE_FILES.to_a
104
114
 
105
115
  spec.required_ruby_version = '>= 1.8.2'
106
116
  spec.date = Time.now
107
117
  spec.rubyforge_project = 'ruby-debug'
118
+ spec.add_dependency('linecache', '>= 0.3')
108
119
 
109
120
  spec.test_files = FileList[BASE_TEST_FILE_LIST]
110
121
 
@@ -130,12 +141,12 @@ EOF
130
141
  spec.require_path = "cli"
131
142
  spec.bindir = "bin"
132
143
  spec.executables = ["rdebug"]
133
- spec.autorequire = "ruby-debug"
134
144
  spec.files = CLI_FILES.to_a
135
145
 
136
146
  spec.required_ruby_version = '>= 1.8.2'
137
147
  spec.date = Time.now
138
148
  spec.rubyforge_project = 'ruby-debug'
149
+ spec.add_dependency('columnize', '>= 0.1')
139
150
  spec.add_dependency('ruby-debug-base', RUBY_DEBUG_VERSION)
140
151
 
141
152
  # FIXME: work out operational logistics for this
@@ -159,7 +170,8 @@ task :default => [:package]
159
170
  # Windows specification
160
171
  win_spec = base_spec.clone
161
172
  win_spec.extensions = []
162
- win_spec.platform = Gem::Platform::WIN32
173
+ ## win_spec.platform = Gem::Platform::WIN32 # deprecated
174
+ win_spec.platform = 'mswin32'
163
175
  win_spec.files += ["lib/#{SO_NAME}"]
164
176
 
165
177
  desc "Create Windows Gem"
@@ -170,20 +182,20 @@ task :win32_gem do
170
182
  target = File.join(current_dir, "lib", SO_NAME)
171
183
  cp(source, target)
172
184
 
173
- # Create the gem, then move it to pkg
174
- Gem::Builder.new(win_spec).build
175
- gem_file = "#{win_spec.name}-#{win_spec.version}-#{win_spec.platform}.gem"
185
+ # Create the gem, then move it to pkg.
186
+ Gem::Builder.new(win_spec).build
187
+ gem_file = "#{win_spec.name}-#{win_spec.version}-#{win_spec.platform}.gem"
176
188
  mv(gem_file, "pkg/#{gem_file}")
177
189
 
178
- # Remove win extension fro top level directory
179
- rm(target)
190
+ # Remove win extension from top level directory.
191
+ rm(target)
180
192
  end
181
193
 
182
194
  desc "Publish ruby-debug to RubyForge."
183
195
  task :publish do
184
196
  require 'rake/contrib/sshpublisher'
185
197
 
186
- # Get ruby-debug path
198
+ # Get ruby-debug path.
187
199
  ruby_debug_path = File.expand_path(File.dirname(__FILE__))
188
200
 
189
201
  publisher = Rake::SshDirPublisher.new("kent@rubyforge.org",
@@ -218,3 +230,22 @@ Rake::RDocTask.new("rdoc") do |rdoc|
218
230
  'LICENSE')
219
231
  end
220
232
 
233
+ desc "Publish the release files to RubyForge."
234
+ task :rubyforge_upload do
235
+ `rubyforge login`
236
+ release_command = "rubyforge add_release #{PKG_NAME} #{PKG_NAME} '#{PKG_NAME}-#{PKG_VERSION}' pkg/#{PKG_NAME}-#{PKG_VERSION}.gem"
237
+ puts release_command
238
+ system(release_command)
239
+ end
240
+
241
+ PKG_NAME = 'ruby-debug'
242
+ desc "Publish the release files to RubyForge."
243
+ task :rubyforge_upload do
244
+ `rubyforge login`
245
+ for pkg_name in ['ruby-debug', 'ruby-debug-base'] do
246
+ pkg_file_name = "#{pkg_name}-#{pkg_version}"
247
+ release_command = "rubyforge add_release ruby-debug #{pkg_name} '#{pkg_file_name}' pkg/#{pkg_file_name}.gem"
248
+ puts release_command
249
+ system(release_command)
250
+ end
251
+ end
@@ -0,0 +1,581 @@
1
+ #include "ruby_debug.h"
2
+
3
+ VALUE rdebug_breakpoints = Qnil;
4
+ VALUE rdebug_catchpoints = Qnil;
5
+
6
+ static VALUE cBreakpoint;
7
+ static ID idEval;
8
+
9
+ static VALUE
10
+ eval_expression(VALUE args)
11
+ {
12
+ return rb_funcall2(rb_mKernel, idEval, 2, RARRAY(args)->ptr);
13
+ }
14
+
15
+ int
16
+ check_breakpoint_hit_condition(VALUE breakpoint)
17
+ {
18
+ debug_breakpoint_t *debug_breakpoint;
19
+
20
+ if(breakpoint == Qnil)
21
+ return 0;
22
+ Data_Get_Struct(breakpoint, debug_breakpoint_t, debug_breakpoint);
23
+
24
+ debug_breakpoint->hit_count++;
25
+ if (!Qtrue == debug_breakpoint->enabled) return 0;
26
+ switch(debug_breakpoint->hit_condition)
27
+ {
28
+ case HIT_COND_NONE:
29
+ return 1;
30
+ case HIT_COND_GE:
31
+ {
32
+ if(debug_breakpoint->hit_count >= debug_breakpoint->hit_value)
33
+ return 1;
34
+ break;
35
+ }
36
+ case HIT_COND_EQ:
37
+ {
38
+ if(debug_breakpoint->hit_count == debug_breakpoint->hit_value)
39
+ return 1;
40
+ break;
41
+ }
42
+ case HIT_COND_MOD:
43
+ {
44
+ if(debug_breakpoint->hit_count % debug_breakpoint->hit_value == 0)
45
+ return 1;
46
+ break;
47
+ }
48
+ }
49
+ return 0;
50
+ }
51
+
52
+ static int
53
+ check_breakpoint_by_pos(VALUE breakpoint, char *file, int line)
54
+ {
55
+ debug_breakpoint_t *debug_breakpoint;
56
+
57
+ if(breakpoint == Qnil)
58
+ return 0;
59
+ Data_Get_Struct(breakpoint, debug_breakpoint_t, debug_breakpoint);
60
+ if (!Qtrue == debug_breakpoint->enabled) return 0;
61
+ if(debug_breakpoint->type != BP_POS_TYPE)
62
+ return 0;
63
+ if(debug_breakpoint->pos.line != line)
64
+ return 0;
65
+ if(filename_cmp(debug_breakpoint->source, file))
66
+ return 1;
67
+ return 0;
68
+ }
69
+
70
+ static int
71
+ check_breakpoint_by_method(VALUE breakpoint, VALUE klass, ID mid)
72
+ {
73
+ debug_breakpoint_t *debug_breakpoint;
74
+
75
+ if(breakpoint == Qnil)
76
+ return 0;
77
+ Data_Get_Struct(breakpoint, debug_breakpoint_t, debug_breakpoint);
78
+ if (!Qtrue == debug_breakpoint->enabled) return 0;
79
+ if(debug_breakpoint->type != BP_METHOD_TYPE)
80
+ return 0;
81
+ if(debug_breakpoint->pos.mid != mid)
82
+ return 0;
83
+ if(classname_cmp(debug_breakpoint->source, klass))
84
+ return 1;
85
+ return 0;
86
+ }
87
+
88
+ VALUE
89
+ check_breakpoints_by_pos(debug_context_t *debug_context, char *file, int line)
90
+ {
91
+ VALUE breakpoint;
92
+ int i;
93
+
94
+ if(!CTX_FL_TEST(debug_context, CTX_FL_ENABLE_BKPT))
95
+ return Qnil;
96
+
97
+ if(check_breakpoint_by_pos(debug_context->breakpoint, file, line))
98
+ return debug_context->breakpoint;
99
+
100
+ if(RARRAY(rdebug_breakpoints)->len == 0)
101
+ return Qnil;
102
+ for(i = 0; i < RARRAY(rdebug_breakpoints)->len; i++)
103
+ {
104
+ breakpoint = rb_ary_entry(rdebug_breakpoints, i);
105
+ if(check_breakpoint_by_pos(breakpoint, file, line))
106
+ return breakpoint;
107
+ }
108
+ return Qnil;
109
+ }
110
+
111
+ VALUE
112
+ check_breakpoints_by_method(debug_context_t *debug_context, VALUE klass, ID mid)
113
+ {
114
+ VALUE breakpoint;
115
+ int i;
116
+
117
+ if(!CTX_FL_TEST(debug_context, CTX_FL_ENABLE_BKPT))
118
+ return Qnil;
119
+
120
+ if(check_breakpoint_by_method(debug_context->breakpoint, klass, mid))
121
+ return debug_context->breakpoint;
122
+
123
+ if(RARRAY(rdebug_breakpoints)->len == 0)
124
+ return Qnil;
125
+ for(i = 0; i < RARRAY(rdebug_breakpoints)->len; i++)
126
+ {
127
+ breakpoint = rb_ary_entry(rdebug_breakpoints, i);
128
+ if(check_breakpoint_by_method(breakpoint, klass, mid))
129
+ return breakpoint;
130
+ }
131
+ return Qnil;
132
+ }
133
+
134
+ int
135
+ check_breakpoint_expression(VALUE breakpoint, VALUE binding)
136
+ {
137
+ debug_breakpoint_t *debug_breakpoint;
138
+ VALUE args, expr_result;
139
+
140
+ Data_Get_Struct(breakpoint, debug_breakpoint_t, debug_breakpoint);
141
+ if(NIL_P(debug_breakpoint->expr))
142
+ return 1;
143
+
144
+ args = rb_ary_new3(2, debug_breakpoint->expr, binding);
145
+ expr_result = rb_protect(eval_expression, args, 0);
146
+ return RTEST(expr_result);
147
+ }
148
+
149
+ static void
150
+ breakpoint_mark(void *data)
151
+ {
152
+ debug_breakpoint_t *breakpoint;
153
+ breakpoint = (debug_breakpoint_t *)data;
154
+ rb_gc_mark(breakpoint->source);
155
+ rb_gc_mark(breakpoint->expr);
156
+ }
157
+
158
+ VALUE
159
+ create_breakpoint_from_args(int argc, VALUE *argv, int id)
160
+ {
161
+ VALUE source, pos, expr;
162
+ debug_breakpoint_t *breakpoint;
163
+ int type;
164
+
165
+ if(rb_scan_args(argc, argv, "21", &source, &pos, &expr) == 2)
166
+ {
167
+ expr = Qnil;
168
+ }
169
+ type = FIXNUM_P(pos) ? BP_POS_TYPE : BP_METHOD_TYPE;
170
+ if(type == BP_POS_TYPE)
171
+ source = StringValue(source);
172
+ else
173
+ pos = StringValue(pos);
174
+ breakpoint = ALLOC(debug_breakpoint_t);
175
+ breakpoint->id = id;
176
+ breakpoint->source = source;
177
+ breakpoint->type = type;
178
+ if(type == BP_POS_TYPE)
179
+ breakpoint->pos.line = FIX2INT(pos);
180
+ else
181
+ breakpoint->pos.mid = rb_intern(RSTRING(pos)->ptr);
182
+ breakpoint->enabled = Qtrue;
183
+ breakpoint->expr = NIL_P(expr) ? expr: StringValue(expr);
184
+ breakpoint->hit_count = 0;
185
+ breakpoint->hit_value = 0;
186
+ breakpoint->hit_condition = HIT_COND_NONE;
187
+ return Data_Wrap_Struct(cBreakpoint, breakpoint_mark, xfree, breakpoint);
188
+ }
189
+
190
+ /*
191
+ * call-seq:
192
+ * Debugger.remove_breakpoint(id) -> breakpoint
193
+ *
194
+ * Removes breakpoint by its id.
195
+ * <i>id</i> is an identificator of a breakpoint.
196
+ */
197
+ VALUE
198
+ rdebug_remove_breakpoint(VALUE self, VALUE id_value)
199
+ {
200
+ int i;
201
+ int id;
202
+ VALUE breakpoint;
203
+ debug_breakpoint_t *debug_breakpoint;
204
+
205
+ id = FIX2INT(id_value);
206
+
207
+ for( i = 0; i < RARRAY(rdebug_breakpoints)->len; i += 1 )
208
+ {
209
+ breakpoint = rb_ary_entry(rdebug_breakpoints, i);
210
+ Data_Get_Struct(breakpoint, debug_breakpoint_t, debug_breakpoint);
211
+ if(debug_breakpoint->id == id)
212
+ {
213
+ rb_ary_delete_at(rdebug_breakpoints, i);
214
+ return breakpoint;
215
+ }
216
+ }
217
+ return Qnil;
218
+ }
219
+
220
+ /*
221
+ * call-seq:
222
+ * Debugger.catchpoints -> string
223
+ *
224
+ * Returns a current catchpoints, which is a hash exception names that will
225
+ * trigger a debugger when raised. The values are the number of times taht
226
+ * catchpoint was hit, initially 0.
227
+ */
228
+ VALUE
229
+ debug_catchpoints(VALUE self)
230
+ {
231
+ debug_check_started();
232
+
233
+ return rdebug_catchpoints;
234
+ }
235
+
236
+ /*
237
+ * call-seq:
238
+ * Debugger.checkpoint = string -> string
239
+ *
240
+ * Sets catchpoint.
241
+ */
242
+ VALUE
243
+ rdebug_add_catchpoint(VALUE self, VALUE value)
244
+ {
245
+ debug_check_started();
246
+
247
+ if (!NIL_P(value) && TYPE(value) != T_STRING) {
248
+ rb_raise(rb_eTypeError, "value of chatchpoint must be String");
249
+ }
250
+ if(NIL_P(value))
251
+ rdebug_catchpoints = Qnil;
252
+ else
253
+ rb_hash_aset(rdebug_catchpoints, rb_str_dup(value),
254
+ INT2FIX(0));
255
+ return value;
256
+ }
257
+
258
+ /*
259
+ * call-seq:
260
+ * context.breakpoint -> breakpoint
261
+ *
262
+ * Returns a context-specific temporary Breakpoint object.
263
+ */
264
+ VALUE
265
+ context_breakpoint(VALUE self)
266
+ {
267
+ debug_context_t *debug_context;
268
+
269
+ debug_check_started();
270
+
271
+ Data_Get_Struct(self, debug_context_t, debug_context);
272
+ return debug_context->breakpoint;
273
+ }
274
+
275
+ /*
276
+ * call-seq:
277
+ * context.set_breakpoint(source, pos, condition = nil) -> breakpoint
278
+ *
279
+ * Sets a context-specific temporary breakpoint, which can be used to implement
280
+ * 'Run to Cursor' debugger function. When this breakpoint is reached, it will be
281
+ * cleared out.
282
+ *
283
+ * <i>source</i> is a name of a file or a class.
284
+ * <i>pos</i> is a line number or a method name if <i>source</i> is a class name.
285
+ * <i>condition</i> is a string which is evaluated to +true+ when this breakpoint
286
+ * is activated.
287
+ */
288
+ VALUE
289
+ context_set_breakpoint(int argc, VALUE *argv, VALUE self)
290
+ {
291
+ VALUE result;
292
+ debug_context_t *debug_context;
293
+
294
+ debug_check_started();
295
+
296
+ Data_Get_Struct(self, debug_context_t, debug_context);
297
+ result = create_breakpoint_from_args(argc, argv, 0);
298
+ debug_context->breakpoint = result;
299
+ return result;
300
+ }
301
+
302
+ /*
303
+ * call-seq:
304
+ * breakpoint.enabled?
305
+ *
306
+ * Returns whether breakpoint is enabled or not.
307
+ */
308
+ static VALUE
309
+ breakpoint_enabled(VALUE self)
310
+ {
311
+ debug_breakpoint_t *breakpoint;
312
+
313
+ Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
314
+ return breakpoint->enabled;
315
+ }
316
+
317
+ /*
318
+ * call-seq:
319
+ * breakpoint.enabled = bool
320
+ *
321
+ * Enables or disables breakpoint.
322
+ */
323
+ static VALUE
324
+ breakpoint_set_enabled(VALUE self, VALUE bool)
325
+ {
326
+ debug_breakpoint_t *breakpoint;
327
+
328
+ Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
329
+ return breakpoint->enabled = bool;
330
+ }
331
+
332
+ /*
333
+ * call-seq:
334
+ * breakpoint.source -> string
335
+ *
336
+ * Returns a source of the breakpoint.
337
+ */
338
+ static VALUE
339
+ breakpoint_source(VALUE self)
340
+ {
341
+ debug_breakpoint_t *breakpoint;
342
+
343
+ Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
344
+ return breakpoint->source;
345
+ }
346
+
347
+ /*
348
+ * call-seq:
349
+ * breakpoint.source = string
350
+ *
351
+ * Sets the source of the breakpoint.
352
+ */
353
+ static VALUE
354
+ breakpoint_set_source(VALUE self, VALUE value)
355
+ {
356
+ debug_breakpoint_t *breakpoint;
357
+
358
+ Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
359
+ breakpoint->source = StringValue(value);
360
+ return value;
361
+ }
362
+
363
+ /*
364
+ * call-seq:
365
+ * breakpoint.pos -> string or int
366
+ *
367
+ * Returns the position of this breakpoint.
368
+ */
369
+ static VALUE
370
+ breakpoint_pos(VALUE self)
371
+ {
372
+ debug_breakpoint_t *breakpoint;
373
+
374
+ Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
375
+ if(breakpoint->type == BP_METHOD_TYPE)
376
+ return rb_str_new2(rb_id2name(breakpoint->pos.mid));
377
+ else
378
+ return INT2FIX(breakpoint->pos.line);
379
+ }
380
+
381
+ /*
382
+ * call-seq:
383
+ * breakpoint.pos = string or int
384
+ *
385
+ * Sets the position of this breakpoint.
386
+ */
387
+ static VALUE
388
+ breakpoint_set_pos(VALUE self, VALUE value)
389
+ {
390
+ debug_breakpoint_t *breakpoint;
391
+
392
+ Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
393
+ if(breakpoint->type == BP_METHOD_TYPE)
394
+ {
395
+ breakpoint->pos.mid = rb_to_id(StringValue(value));
396
+ }
397
+ else
398
+ breakpoint->pos.line = FIX2INT(value);
399
+ return value;
400
+ }
401
+
402
+ /*
403
+ * call-seq:
404
+ * breakpoint.expr -> string
405
+ *
406
+ * Returns a codition expression when this breakpoint should be activated.
407
+ */
408
+ static VALUE
409
+ breakpoint_expr(VALUE self)
410
+ {
411
+ debug_breakpoint_t *breakpoint;
412
+
413
+ Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
414
+ return breakpoint->expr;
415
+ }
416
+
417
+ /*
418
+ * call-seq:
419
+ * breakpoint.expr = string | nil
420
+ *
421
+ * Sets the codition expression when this breakpoint should be activated.
422
+ */
423
+ static VALUE
424
+ breakpoint_set_expr(VALUE self, VALUE expr)
425
+ {
426
+ debug_breakpoint_t *breakpoint;
427
+
428
+ Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
429
+ breakpoint->expr = NIL_P(expr) ? expr: StringValue(expr);
430
+ return expr;
431
+ }
432
+
433
+ /*
434
+ * call-seq:
435
+ * breakpoint.id -> int
436
+ *
437
+ * Returns id of the breakpoint.
438
+ */
439
+ static VALUE
440
+ breakpoint_id(VALUE self)
441
+ {
442
+ debug_breakpoint_t *breakpoint;
443
+
444
+ Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
445
+ return INT2FIX(breakpoint->id);
446
+ }
447
+
448
+ /*
449
+ * call-seq:
450
+ * breakpoint.hit_count -> int
451
+ *
452
+ * Returns the hit count of the breakpoint.
453
+ */
454
+ static VALUE
455
+ breakpoint_hit_count(VALUE self)
456
+ {
457
+ debug_breakpoint_t *breakpoint;
458
+
459
+ Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
460
+ return INT2FIX(breakpoint->hit_count);
461
+ }
462
+
463
+ /*
464
+ * call-seq:
465
+ * breakpoint.hit_value -> int
466
+ *
467
+ * Returns the hit value of the breakpoint.
468
+ */
469
+ static VALUE
470
+ breakpoint_hit_value(VALUE self)
471
+ {
472
+ debug_breakpoint_t *breakpoint;
473
+
474
+ Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
475
+ return INT2FIX(breakpoint->hit_value);
476
+ }
477
+
478
+ /*
479
+ * call-seq:
480
+ * breakpoint.hit_value = int
481
+ *
482
+ * Sets the hit value of the breakpoint.
483
+ */
484
+ static VALUE
485
+ breakpoint_set_hit_value(VALUE self, VALUE value)
486
+ {
487
+ debug_breakpoint_t *breakpoint;
488
+
489
+ Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
490
+ breakpoint->hit_value = FIX2INT(value);
491
+ return value;
492
+ }
493
+
494
+ /*
495
+ * call-seq:
496
+ * breakpoint.hit_condition -> symbol
497
+ *
498
+ * Returns the hit condition of the breakpoint:
499
+ *
500
+ * +nil+ if it is an unconditional breakpoint, or
501
+ * :greater_or_equal, :equal, :modulo
502
+ */
503
+ static VALUE
504
+ breakpoint_hit_condition(VALUE self)
505
+ {
506
+ debug_breakpoint_t *breakpoint;
507
+
508
+ Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
509
+ switch(breakpoint->hit_condition)
510
+ {
511
+ case HIT_COND_GE:
512
+ return ID2SYM(rb_intern("greater_or_equal"));
513
+ case HIT_COND_EQ:
514
+ return ID2SYM(rb_intern("equal"));
515
+ case HIT_COND_MOD:
516
+ return ID2SYM(rb_intern("modulo"));
517
+ case HIT_COND_NONE:
518
+ default:
519
+ return Qnil;
520
+ }
521
+ }
522
+
523
+ /*
524
+ * call-seq:
525
+ * breakpoint.hit_condition = symbol
526
+ *
527
+ * Sets the hit condition of the breakpoint which must be one of the following values:
528
+ *
529
+ * +nil+ if it is an unconditional breakpoint, or
530
+ * :greater_or_equal(:ge), :equal(:eq), :modulo(:mod)
531
+ */
532
+ static VALUE
533
+ breakpoint_set_hit_condition(VALUE self, VALUE value)
534
+ {
535
+ debug_breakpoint_t *breakpoint;
536
+ ID id_value;
537
+
538
+ Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
539
+ id_value = rb_to_id(value);
540
+
541
+ if(rb_intern("greater_or_equal") == id_value || rb_intern("ge") == id_value)
542
+ breakpoint->hit_condition = HIT_COND_GE;
543
+ else if(rb_intern("equal") == id_value || rb_intern("eq") == id_value)
544
+ breakpoint->hit_condition = HIT_COND_EQ;
545
+ else if(rb_intern("modulo") == id_value || rb_intern("mod") == id_value)
546
+ breakpoint->hit_condition = HIT_COND_MOD;
547
+ else
548
+ rb_raise(rb_eArgError, "Invalid condition parameter");
549
+ return value;
550
+ }
551
+
552
+ /*
553
+ * Document-class: Breakpoint
554
+ *
555
+ * == Summary
556
+ *
557
+ * This class represents a breakpoint. It defines position of the breakpoint and
558
+ * condition when this breakpoint should be triggered.
559
+ */
560
+ void
561
+ Init_breakpoint()
562
+ {
563
+ cBreakpoint = rb_define_class_under(mDebugger, "Breakpoint", rb_cObject);
564
+ rb_define_method(cBreakpoint, "enabled=", breakpoint_set_enabled, 1);
565
+ rb_define_method(cBreakpoint, "enabled?", breakpoint_enabled, 0);
566
+ rb_define_method(cBreakpoint, "expr", breakpoint_expr, 0);
567
+ rb_define_method(cBreakpoint, "expr=", breakpoint_set_expr, 1);
568
+ rb_define_method(cBreakpoint, "hit_condition", breakpoint_hit_condition, 0);
569
+ rb_define_method(cBreakpoint, "hit_condition=", breakpoint_set_hit_condition, 1);
570
+ rb_define_method(cBreakpoint, "hit_count", breakpoint_hit_count, 0);
571
+ rb_define_method(cBreakpoint, "hit_value", breakpoint_hit_value, 0);
572
+ rb_define_method(cBreakpoint, "hit_value=", breakpoint_set_hit_value, 1);
573
+ rb_define_method(cBreakpoint, "id", breakpoint_id, 0);
574
+ rb_define_method(cBreakpoint, "pos", breakpoint_pos, 0);
575
+ rb_define_method(cBreakpoint, "pos=", breakpoint_set_pos, 1);
576
+ rb_define_method(cBreakpoint, "source", breakpoint_source, 0);
577
+ rb_define_method(cBreakpoint, "source=", breakpoint_set_source, 1);
578
+ idEval = rb_intern("eval");
579
+ }
580
+
581
+