ruby-debug-base 0.10.0 → 0.10.1

Sign up to get free protection for your applications and to get access to all the features.
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
+