ruby-debug-base193 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,266 @@
1
+ #!/usr/bin/env rake
2
+ # -*- Ruby -*-
3
+ require 'rubygems'
4
+ require 'rake/gempackagetask'
5
+ require 'rake/rdoctask'
6
+ require 'rake/testtask'
7
+ require 'rake/extensiontask'
8
+
9
+ Rake::ExtensionTask.new('ruby_debug')
10
+
11
+ SO_NAME = "ruby_debug.so"
12
+
13
+ # ------- Default Package ----------
14
+ RUBY_DEBUG_VERSION = open("ext/ruby_debug/ruby_debug.c") do |f|
15
+ f.grep(/^#define DEBUG_VERSION/).first[/"(.+)"/,1]
16
+ end
17
+
18
+ RUBY_DEBUG_TEENY = ".0"
19
+ RUBY_DEBUG_BASE_TEENY = ".0"
20
+
21
+ COMMON_FILES = FileList[
22
+ 'AUTHORS',
23
+ 'CHANGES',
24
+ 'LICENSE',
25
+ 'README',
26
+ 'Rakefile',
27
+ ]
28
+
29
+ CLI_TEST_FILE_LIST = FileList['test/cli/commands/unit/*.rb',
30
+ 'test/cli/commands/*_test.rb',
31
+ 'test/cli/**/*_test.rb',
32
+ 'test/test-*.rb']
33
+ CLI_FILES = COMMON_FILES + FileList[
34
+ "cli/**/*",
35
+ 'ChangeLog',
36
+ 'bin/*',
37
+ 'doc/rdebug.1',
38
+ 'test/**/data/*.cmd',
39
+ 'test/**/data/*.right',
40
+ 'test/**/*.rb',
41
+ 'rdbg.rb',
42
+ CLI_TEST_FILE_LIST
43
+ ]
44
+
45
+ BASE_TEST_FILE_LIST = %w(
46
+ test/base/base.rb
47
+ test/base/binding.rb
48
+ test/base/catchpoint.rb)
49
+ BASE_FILES = COMMON_FILES + FileList[
50
+ 'ext/ruby_debug/breakpoint.c',
51
+ 'ext/ruby_debug/extconf.rb',
52
+ 'ext/ruby_debug/ruby_debug.c',
53
+ 'ext/ruby_debug/ruby_debug.h',
54
+ 'ext/win32/*',
55
+ 'lib/**/*',
56
+ BASE_TEST_FILE_LIST,
57
+ ]
58
+
59
+ desc "Test everything."
60
+ task :test => :test_base do
61
+ Rake::TestTask.new(:test) do |t|
62
+ t.libs << './ext'
63
+ t.libs << './lib'
64
+ t.libs << './cli'
65
+ t.test_files = CLI_TEST_FILE_LIST
66
+ t.verbose = true
67
+ end
68
+ end
69
+
70
+ desc "Test ruby-debug-base."
71
+ task :test_base => :lib do
72
+ Rake::TestTask.new(:test_base) do |t|
73
+ t.libs << './ext'
74
+ t.libs << './lib'
75
+ t.test_files = FileList[BASE_TEST_FILE_LIST]
76
+ t.verbose = true
77
+ end
78
+ end
79
+
80
+ desc "Test everything - same as test."
81
+ task :check => :test
82
+
83
+ desc "Create the core ruby-debug shared library extension"
84
+ task :lib do
85
+ Dir.chdir("ext") do
86
+ system("#{Gem.ruby} extconf.rb && make")
87
+ end
88
+ end
89
+
90
+ desc "Compile Emacs code"
91
+ task :emacs => "emacs/rdebug.elc"
92
+ file "emacs/rdebug.elc" => ["emacs/elisp-comp", "emacs/rdebug.el"] do
93
+ Dir.chdir("emacs") do
94
+ system("./elisp-comp ./rdebug.el")
95
+ end
96
+ end
97
+
98
+ desc "Create a GNU-style ChangeLog via svn2cl"
99
+ task :ChangeLog do
100
+ system("svn2cl --authors=svn2cl_usermap svn://rubyforge.org/var/svn/ruby-debug/trunk")
101
+ system("svn2cl --authors=svn2cl_usermap svn://rubyforge.org/var/svn/ruby-debug/trunk/ext -o ext/ChangeLog")
102
+ system("svn2cl --authors=svn2cl_usermap svn://rubyforge.org/var/svn/ruby-debug/trunk/lib -o lib/ChangeLog")
103
+ end
104
+
105
+ # Base GEM Specification
106
+ base_spec = Gem::Specification.new do |spec|
107
+ spec.name = "ruby-debug-base19"
108
+
109
+ spec.homepage = "http://rubyforge.org/projects/ruby-debug19/"
110
+ spec.summary = "Fast Ruby debugger - core component"
111
+ spec.description = <<-EOF
112
+ ruby-debug-base19 is a fast implementation of the standard Ruby debugger debug.rb.
113
+ It is implemented by utilizing a new Ruby C API hook. The core component
114
+ provides support that front-ends can build on. It provides breakpoint
115
+ handling, bindings for stack frames among other things.
116
+ EOF
117
+
118
+ spec.version = RUBY_DEBUG_VERSION + RUBY_DEBUG_BASE_TEENY
119
+
120
+ spec.authors = ["Kent Sibilev", "Mark Moseley"]
121
+ spec.email = "mark@fast-software.com"
122
+ spec.platform = Gem::Platform::RUBY
123
+ spec.require_path = "lib"
124
+ spec.extensions = ["ext/ruby_debug/extconf.rb"]
125
+ spec.files = BASE_FILES.to_a
126
+
127
+ spec.required_ruby_version = '>= 1.8.2'
128
+ spec.date = Time.now
129
+ spec.rubyforge_project = 'ruby-debug19'
130
+ spec.add_dependency('ruby_core_source', '>= 0.1.4')
131
+ spec.add_dependency('linecache19', '>= 0.5.11')
132
+
133
+ spec.test_files = FileList[BASE_TEST_FILE_LIST]
134
+
135
+ # rdoc
136
+ spec.has_rdoc = true
137
+ spec.extra_rdoc_files = ['README', 'ext/ruby_debug/ruby_debug.c']
138
+ end
139
+
140
+ cli_spec = Gem::Specification.new do |spec|
141
+ spec.name = "ruby-debug19"
142
+
143
+ spec.homepage = "http://rubyforge.org/projects/ruby-debug19/"
144
+ spec.summary = "Command line interface (CLI) for ruby-debug-base19"
145
+ spec.description = <<-EOF
146
+ A generic command line interface for ruby-debug.
147
+ EOF
148
+
149
+ spec.version = RUBY_DEBUG_VERSION + RUBY_DEBUG_TEENY
150
+
151
+ spec.authors = ["Kent Sibilev", "Mark Moseley"]
152
+ spec.email = "mark@fast-software.com"
153
+ spec.platform = Gem::Platform::RUBY
154
+ spec.require_path = "cli"
155
+ spec.bindir = "bin"
156
+ spec.executables = ["rdebug"]
157
+ spec.files = CLI_FILES.to_a
158
+
159
+ spec.required_ruby_version = '>= 1.8.2'
160
+ spec.date = Time.now
161
+ spec.rubyforge_project = 'ruby-debug'
162
+ spec.add_dependency('columnize', '>= 0.3.1')
163
+ spec.add_dependency('linecache19', '>= 0.5.11')
164
+ spec.add_dependency('ruby-debug-base19', '>= 0.12.0')
165
+
166
+ # FIXME: work out operational logistics for this
167
+ # spec.test_files = FileList[CLI_TEST_FILE_LIST]
168
+
169
+ # rdoc
170
+ spec.has_rdoc = true
171
+ spec.extra_rdoc_files = ['README']
172
+ end
173
+
174
+ # Rake task to build the default package
175
+ Rake::GemPackageTask.new(base_spec) do |pkg|
176
+ pkg.need_tar = true
177
+ end
178
+ Rake::GemPackageTask.new(cli_spec) do |pkg|
179
+ pkg.need_tar = true
180
+ end
181
+
182
+ task :default => [:package]
183
+
184
+ # Windows specification
185
+ win_spec = base_spec.clone
186
+ win_spec.extensions = []
187
+ ## win_spec.platform = Gem::Platform::WIN32 # deprecated
188
+ win_spec.platform = 'mswin32'
189
+ win_spec.files += ["lib/#{SO_NAME}"]
190
+
191
+ desc "Create Windows Gem"
192
+ task :win32_gem do
193
+ # Copy the win32 extension the top level directory
194
+ current_dir = File.expand_path(File.dirname(__FILE__))
195
+ source = File.join(current_dir, "ext", "win32", SO_NAME)
196
+ target = File.join(current_dir, "lib", SO_NAME)
197
+ cp(source, target)
198
+
199
+ # Create the gem, then move it to pkg.
200
+ Gem::Builder.new(win_spec).build
201
+ gem_file = "#{win_spec.name}-#{win_spec.version}-#{win_spec.platform}.gem"
202
+ mv(gem_file, "pkg/#{gem_file}")
203
+
204
+ # Remove win extension from top level directory.
205
+ rm(target)
206
+ end
207
+
208
+ desc "Publish ruby-debug to RubyForge."
209
+ task :publish do
210
+ require 'rake/contrib/sshpublisher'
211
+
212
+ # Get ruby-debug path.
213
+ ruby_debug_path = File.expand_path(File.dirname(__FILE__))
214
+
215
+ Rake::SshDirPublisher.new("kent@rubyforge.org",
216
+ "/var/www/gforge-projects/ruby-debug", ruby_debug_path)
217
+ end
218
+
219
+ desc "Remove built files"
220
+ task :clean do
221
+ cd "ext" do
222
+ if File.exists?("Makefile")
223
+ sh "make clean"
224
+ rm "Makefile"
225
+ end
226
+ derived_files = Dir.glob(".o") + Dir.glob("*.so")
227
+ rm derived_files unless derived_files.empty?
228
+ end
229
+ end
230
+
231
+ # --------- RDoc Documentation ------
232
+ desc "Generate rdoc documentation"
233
+ Rake::RDocTask.new("rdoc") do |rdoc|
234
+ rdoc.rdoc_dir = 'doc/rdoc'
235
+ rdoc.title = "ruby-debug"
236
+ # Show source inline with line numbers
237
+ rdoc.options << "--inline-source" << "--line-numbers"
238
+ # Make the readme file the start page for the generated html
239
+ rdoc.options << '--main' << 'README'
240
+ rdoc.rdoc_files.include('bin/**/*',
241
+ 'cli/ruby-debug/commands/*.rb',
242
+ 'lib/**/*.rb',
243
+ 'ext/**/ruby_debug.c',
244
+ 'README',
245
+ 'LICENSE')
246
+ end
247
+
248
+ desc "Publish the release files to RubyForge."
249
+ task :rubyforge_upload do
250
+ `rubyforge login`
251
+ release_command = "rubyforge add_release #{PKG_NAME} #{PKG_NAME} '#{PKG_NAME}-#{PKG_VERSION}' pkg/#{PKG_NAME}-#{PKG_VERSION}.gem"
252
+ puts release_command
253
+ system(release_command)
254
+ end
255
+
256
+ PKG_NAME = 'ruby-debug'
257
+ desc "Publish the release files to RubyForge."
258
+ task :rubyforge_upload do
259
+ `rubyforge login`
260
+ for pkg_name in ['ruby-debug', 'ruby-debug-base'] do
261
+ pkg_file_name = "#{pkg_name}-#{pkg_version}"
262
+ release_command = "rubyforge add_release ruby-debug #{pkg_name} '#{pkg_file_name}' pkg/#{pkg_file_name}.gem"
263
+ puts release_command
264
+ system(release_command)
265
+ end
266
+ end
@@ -0,0 +1,578 @@
1
+ #include <ruby.h>
2
+ #include <stdio.h>
3
+ #include <vm_core.h>
4
+ #include <iseq.h>
5
+ #include "ruby_debug.h"
6
+
7
+ VALUE rdebug_breakpoints = Qnil;
8
+ VALUE rdebug_catchpoints;
9
+
10
+ static VALUE cBreakpoint;
11
+ static ID idEval;
12
+
13
+ static VALUE
14
+ eval_expression(VALUE args)
15
+ {
16
+ return rb_funcall2(rb_mKernel, idEval, 2, RARRAY_PTR(args));
17
+ }
18
+
19
+ int
20
+ check_breakpoint_hit_condition(VALUE breakpoint)
21
+ {
22
+ debug_breakpoint_t *debug_breakpoint;
23
+
24
+ if(breakpoint == Qnil)
25
+ return 0;
26
+ Data_Get_Struct(breakpoint, debug_breakpoint_t, debug_breakpoint);
27
+
28
+ debug_breakpoint->hit_count++;
29
+ if (!Qtrue == debug_breakpoint->enabled) return 0;
30
+ switch(debug_breakpoint->hit_condition)
31
+ {
32
+ case HIT_COND_NONE:
33
+ return 1;
34
+ case HIT_COND_GE:
35
+ {
36
+ if(debug_breakpoint->hit_count >= debug_breakpoint->hit_value)
37
+ return 1;
38
+ break;
39
+ }
40
+ case HIT_COND_EQ:
41
+ {
42
+ if(debug_breakpoint->hit_count == debug_breakpoint->hit_value)
43
+ return 1;
44
+ break;
45
+ }
46
+ case HIT_COND_MOD:
47
+ {
48
+ if(debug_breakpoint->hit_count % debug_breakpoint->hit_value == 0)
49
+ return 1;
50
+ break;
51
+ }
52
+ }
53
+ return 0;
54
+ }
55
+
56
+ static int
57
+ check_breakpoint_by_pos(VALUE breakpoint, const char *file, int line)
58
+ {
59
+ debug_breakpoint_t *debug_breakpoint;
60
+
61
+ if(breakpoint == Qnil)
62
+ return 0;
63
+ Data_Get_Struct(breakpoint, debug_breakpoint_t, debug_breakpoint);
64
+ if (!Qtrue == debug_breakpoint->enabled) return 0;
65
+ if(debug_breakpoint->type != BP_POS_TYPE)
66
+ return 0;
67
+ if(debug_breakpoint->pos.line != line)
68
+ return 0;
69
+ if(filename_cmp(debug_breakpoint->source, file))
70
+ return 1;
71
+ return 0;
72
+ }
73
+
74
+ int
75
+ check_breakpoint_by_method(VALUE breakpoint, VALUE klass, ID mid, VALUE self)
76
+ {
77
+ debug_breakpoint_t *debug_breakpoint;
78
+
79
+ if(breakpoint == Qnil)
80
+ return 0;
81
+ Data_Get_Struct(breakpoint, debug_breakpoint_t, debug_breakpoint);
82
+ if (!Qtrue == debug_breakpoint->enabled) return 0;
83
+ if(debug_breakpoint->type != BP_METHOD_TYPE)
84
+ return 0;
85
+ if(debug_breakpoint->pos.mid != mid)
86
+ return 0;
87
+ if(classname_cmp(debug_breakpoint->source, klass))
88
+ return 1;
89
+ if ((rb_type(self) == T_CLASS) &&
90
+ classname_cmp(debug_breakpoint->source, self))
91
+ return 1;
92
+ return 0;
93
+ }
94
+
95
+ VALUE
96
+ check_breakpoints_by_pos(debug_context_t *debug_context, const char *file, int line)
97
+ {
98
+ VALUE breakpoint;
99
+ int i;
100
+
101
+ if(!CTX_FL_TEST(debug_context, CTX_FL_ENABLE_BKPT))
102
+ return Qnil;
103
+
104
+ if(check_breakpoint_by_pos(debug_context->breakpoint, file, line))
105
+ return debug_context->breakpoint;
106
+
107
+ if(RARRAY_LEN(rdebug_breakpoints) == 0)
108
+ return Qnil;
109
+ for(i = 0; i < RARRAY_LEN(rdebug_breakpoints); i++)
110
+ {
111
+ breakpoint = rb_ary_entry(rdebug_breakpoints, i);
112
+ if(check_breakpoint_by_pos(breakpoint, file, line))
113
+ return breakpoint;
114
+ }
115
+ return Qnil;
116
+ }
117
+
118
+ VALUE
119
+ check_breakpoints_by_method(debug_context_t *debug_context, VALUE klass, ID mid, VALUE self)
120
+ {
121
+ VALUE breakpoint;
122
+ int i;
123
+
124
+ if(!CTX_FL_TEST(debug_context, CTX_FL_ENABLE_BKPT))
125
+ return Qnil;
126
+
127
+ if(check_breakpoint_by_method(debug_context->breakpoint, klass, mid, self))
128
+ return debug_context->breakpoint;
129
+
130
+ if(RARRAY_LEN(rdebug_breakpoints) == 0)
131
+ return Qnil;
132
+ for(i = 0; i < RARRAY_LEN(rdebug_breakpoints); i++)
133
+ {
134
+ breakpoint = rb_ary_entry(rdebug_breakpoints, i);
135
+ if(check_breakpoint_by_method(breakpoint, klass, mid, self))
136
+ return breakpoint;
137
+ }
138
+ return Qnil;
139
+ }
140
+
141
+ int
142
+ check_breakpoint_expression(VALUE breakpoint, VALUE binding)
143
+ {
144
+ debug_breakpoint_t *debug_breakpoint;
145
+ VALUE args, expr_result;
146
+
147
+ Data_Get_Struct(breakpoint, debug_breakpoint_t, debug_breakpoint);
148
+ if(NIL_P(debug_breakpoint->expr))
149
+ return 1;
150
+
151
+ args = rb_ary_new3(2, debug_breakpoint->expr, binding);
152
+ expr_result = rb_protect(eval_expression, args, 0);
153
+ return RTEST(expr_result);
154
+ }
155
+
156
+ static void
157
+ breakpoint_mark(void *data)
158
+ {
159
+ debug_breakpoint_t *breakpoint;
160
+ breakpoint = (debug_breakpoint_t *)data;
161
+ rb_gc_mark(breakpoint->source);
162
+ rb_gc_mark(breakpoint->expr);
163
+ }
164
+
165
+ VALUE
166
+ create_breakpoint_from_args(int argc, VALUE *argv, int id)
167
+ {
168
+ VALUE source, pos, expr;
169
+ debug_breakpoint_t *breakpoint;
170
+ int type;
171
+
172
+ if(rb_scan_args(argc, argv, "21", &source, &pos, &expr) == 2)
173
+ {
174
+ expr = Qnil;
175
+ }
176
+ type = FIXNUM_P(pos) ? BP_POS_TYPE : BP_METHOD_TYPE;
177
+ if(type == BP_POS_TYPE)
178
+ source = StringValue(source);
179
+ else
180
+ pos = StringValue(pos);
181
+ breakpoint = ALLOC(debug_breakpoint_t);
182
+ breakpoint->id = id;
183
+ breakpoint->source = source;
184
+ breakpoint->type = type;
185
+ if(type == BP_POS_TYPE)
186
+ breakpoint->pos.line = FIX2INT(pos);
187
+ else
188
+ breakpoint->pos.mid = rb_intern(RSTRING_PTR(pos));
189
+ breakpoint->enabled = Qtrue;
190
+ breakpoint->expr = NIL_P(expr) ? expr: StringValue(expr);
191
+ breakpoint->hit_count = 0;
192
+ breakpoint->hit_value = 0;
193
+ breakpoint->hit_condition = HIT_COND_NONE;
194
+ return Data_Wrap_Struct(cBreakpoint, breakpoint_mark, xfree, breakpoint);
195
+ }
196
+
197
+ /*
198
+ * call-seq:
199
+ * Debugger.remove_breakpoint(id) -> breakpoint
200
+ *
201
+ * Removes breakpoint by its id.
202
+ * <i>id</i> is an identificator of a breakpoint.
203
+ */
204
+ VALUE
205
+ rdebug_remove_breakpoint(VALUE self, VALUE id_value)
206
+ {
207
+ int i;
208
+ int id;
209
+ VALUE breakpoint;
210
+ debug_breakpoint_t *debug_breakpoint;
211
+
212
+ id = FIX2INT(id_value);
213
+
214
+ for( i = 0; i < RARRAY_LEN(rdebug_breakpoints); i += 1 )
215
+ {
216
+ breakpoint = rb_ary_entry(rdebug_breakpoints, i);
217
+ Data_Get_Struct(breakpoint, debug_breakpoint_t, debug_breakpoint);
218
+ if(debug_breakpoint->id == id)
219
+ {
220
+ rb_ary_delete_at(rdebug_breakpoints, i);
221
+ return breakpoint;
222
+ }
223
+ }
224
+ return Qnil;
225
+ }
226
+
227
+ /*
228
+ * call-seq:
229
+ * Debugger.catchpoints -> hash
230
+ *
231
+ * Returns a current catchpoints, which is a hash exception names that will
232
+ * trigger a debugger when raised. The values are the number of times taht
233
+ * catchpoint was hit, initially 0.
234
+ */
235
+ VALUE
236
+ debug_catchpoints(VALUE self)
237
+ {
238
+ return rdebug_catchpoints;
239
+ }
240
+
241
+ /*
242
+ * call-seq:
243
+ * Debugger.catchpoint(string) -> string
244
+ *
245
+ * Sets catchpoint. Returns the string passed.
246
+ */
247
+ VALUE
248
+ rdebug_add_catchpoint(VALUE self, VALUE value)
249
+ {
250
+ if (TYPE(value) != T_STRING) {
251
+ rb_raise(rb_eTypeError, "value of a catchpoint must be String");
252
+ }
253
+ rb_hash_aset(rdebug_catchpoints, rb_str_dup(value), INT2FIX(0));
254
+ return value;
255
+ }
256
+
257
+ /*
258
+ * call-seq:
259
+ * context.breakpoint -> breakpoint
260
+ *
261
+ * Returns a context-specific temporary Breakpoint object.
262
+ */
263
+ VALUE
264
+ context_breakpoint(VALUE self)
265
+ {
266
+ debug_context_t *debug_context;
267
+
268
+ Data_Get_Struct(self, debug_context_t, debug_context);
269
+ return debug_context->breakpoint;
270
+ }
271
+
272
+ /*
273
+ * call-seq:
274
+ * context.set_breakpoint(source, pos, condition = nil) -> breakpoint
275
+ *
276
+ * Sets a context-specific temporary breakpoint, which can be used to implement
277
+ * 'Run to Cursor' debugger function. When this breakpoint is reached, it will be
278
+ * cleared out.
279
+ *
280
+ * <i>source</i> is a name of a file or a class.
281
+ * <i>pos</i> is a line number or a method name if <i>source</i> is a class name.
282
+ * <i>condition</i> is a string which is evaluated to +true+ when this breakpoint
283
+ * is activated.
284
+ */
285
+ VALUE
286
+ context_set_breakpoint(int argc, VALUE *argv, VALUE self)
287
+ {
288
+ VALUE result;
289
+ debug_context_t *debug_context;
290
+
291
+ Data_Get_Struct(self, debug_context_t, debug_context);
292
+ result = create_breakpoint_from_args(argc, argv, 0);
293
+ debug_context->breakpoint = result;
294
+ return result;
295
+ }
296
+
297
+ /*
298
+ * call-seq:
299
+ * breakpoint.enabled?
300
+ *
301
+ * Returns whether breakpoint is enabled or not.
302
+ */
303
+ static VALUE
304
+ breakpoint_enabled(VALUE self)
305
+ {
306
+ debug_breakpoint_t *breakpoint;
307
+
308
+ Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
309
+ return breakpoint->enabled;
310
+ }
311
+
312
+ /*
313
+ * call-seq:
314
+ * breakpoint.enabled = bool
315
+ *
316
+ * Enables or disables breakpoint.
317
+ */
318
+ static VALUE
319
+ breakpoint_set_enabled(VALUE self, VALUE bool)
320
+ {
321
+ debug_breakpoint_t *breakpoint;
322
+
323
+ Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
324
+ return breakpoint->enabled = bool;
325
+ }
326
+
327
+ /*
328
+ * call-seq:
329
+ * breakpoint.source -> string
330
+ *
331
+ * Returns a source of the breakpoint.
332
+ */
333
+ static VALUE
334
+ breakpoint_source(VALUE self)
335
+ {
336
+ debug_breakpoint_t *breakpoint;
337
+
338
+ Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
339
+ return breakpoint->source;
340
+ }
341
+
342
+ /*
343
+ * call-seq:
344
+ * breakpoint.source = string
345
+ *
346
+ * Sets the source of the breakpoint.
347
+ */
348
+ static VALUE
349
+ breakpoint_set_source(VALUE self, VALUE value)
350
+ {
351
+ debug_breakpoint_t *breakpoint;
352
+
353
+ Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
354
+ breakpoint->source = StringValue(value);
355
+ return value;
356
+ }
357
+
358
+ /*
359
+ * call-seq:
360
+ * breakpoint.pos -> string or int
361
+ *
362
+ * Returns the position of this breakpoint.
363
+ */
364
+ static VALUE
365
+ breakpoint_pos(VALUE self)
366
+ {
367
+ debug_breakpoint_t *breakpoint;
368
+
369
+ Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
370
+ if(breakpoint->type == BP_METHOD_TYPE)
371
+ return rb_str_new2(rb_id2name(breakpoint->pos.mid));
372
+ else
373
+ return INT2FIX(breakpoint->pos.line);
374
+ }
375
+
376
+ /*
377
+ * call-seq:
378
+ * breakpoint.pos = string or int
379
+ *
380
+ * Sets the position of this breakpoint.
381
+ */
382
+ static VALUE
383
+ breakpoint_set_pos(VALUE self, VALUE value)
384
+ {
385
+ debug_breakpoint_t *breakpoint;
386
+
387
+ Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
388
+ if(breakpoint->type == BP_METHOD_TYPE)
389
+ {
390
+ breakpoint->pos.mid = rb_to_id(StringValue(value));
391
+ }
392
+ else
393
+ breakpoint->pos.line = FIX2INT(value);
394
+ return value;
395
+ }
396
+
397
+ /*
398
+ * call-seq:
399
+ * breakpoint.expr -> string
400
+ *
401
+ * Returns a codition expression when this breakpoint should be activated.
402
+ */
403
+ static VALUE
404
+ breakpoint_expr(VALUE self)
405
+ {
406
+ debug_breakpoint_t *breakpoint;
407
+
408
+ Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
409
+ return breakpoint->expr;
410
+ }
411
+
412
+ /*
413
+ * call-seq:
414
+ * breakpoint.expr = string | nil
415
+ *
416
+ * Sets the codition expression when this breakpoint should be activated.
417
+ */
418
+ static VALUE
419
+ breakpoint_set_expr(VALUE self, VALUE expr)
420
+ {
421
+ debug_breakpoint_t *breakpoint;
422
+
423
+ Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
424
+ breakpoint->expr = NIL_P(expr) ? expr: StringValue(expr);
425
+ return expr;
426
+ }
427
+
428
+ /*
429
+ * call-seq:
430
+ * breakpoint.id -> int
431
+ *
432
+ * Returns id of the breakpoint.
433
+ */
434
+ static VALUE
435
+ breakpoint_id(VALUE self)
436
+ {
437
+ debug_breakpoint_t *breakpoint;
438
+
439
+ Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
440
+ return INT2FIX(breakpoint->id);
441
+ }
442
+
443
+ /*
444
+ * call-seq:
445
+ * breakpoint.hit_count -> int
446
+ *
447
+ * Returns the hit count of the breakpoint.
448
+ */
449
+ static VALUE
450
+ breakpoint_hit_count(VALUE self)
451
+ {
452
+ debug_breakpoint_t *breakpoint;
453
+
454
+ Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
455
+ return INT2FIX(breakpoint->hit_count);
456
+ }
457
+
458
+ /*
459
+ * call-seq:
460
+ * breakpoint.hit_value -> int
461
+ *
462
+ * Returns the hit value of the breakpoint.
463
+ */
464
+ static VALUE
465
+ breakpoint_hit_value(VALUE self)
466
+ {
467
+ debug_breakpoint_t *breakpoint;
468
+
469
+ Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
470
+ return INT2FIX(breakpoint->hit_value);
471
+ }
472
+
473
+ /*
474
+ * call-seq:
475
+ * breakpoint.hit_value = int
476
+ *
477
+ * Sets the hit value of the breakpoint.
478
+ */
479
+ static VALUE
480
+ breakpoint_set_hit_value(VALUE self, VALUE value)
481
+ {
482
+ debug_breakpoint_t *breakpoint;
483
+
484
+ Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
485
+ breakpoint->hit_value = FIX2INT(value);
486
+ return value;
487
+ }
488
+
489
+ /*
490
+ * call-seq:
491
+ * breakpoint.hit_condition -> symbol
492
+ *
493
+ * Returns the hit condition of the breakpoint:
494
+ *
495
+ * +nil+ if it is an unconditional breakpoint, or
496
+ * :greater_or_equal, :equal, :modulo
497
+ */
498
+ static VALUE
499
+ breakpoint_hit_condition(VALUE self)
500
+ {
501
+ debug_breakpoint_t *breakpoint;
502
+
503
+ Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
504
+ switch(breakpoint->hit_condition)
505
+ {
506
+ case HIT_COND_GE:
507
+ return ID2SYM(rb_intern("greater_or_equal"));
508
+ case HIT_COND_EQ:
509
+ return ID2SYM(rb_intern("equal"));
510
+ case HIT_COND_MOD:
511
+ return ID2SYM(rb_intern("modulo"));
512
+ case HIT_COND_NONE:
513
+ default:
514
+ return Qnil;
515
+ }
516
+ }
517
+
518
+ /*
519
+ * call-seq:
520
+ * breakpoint.hit_condition = symbol
521
+ *
522
+ * Sets the hit condition of the breakpoint which must be one of the following values:
523
+ *
524
+ * +nil+ if it is an unconditional breakpoint, or
525
+ * :greater_or_equal(:ge), :equal(:eq), :modulo(:mod)
526
+ */
527
+ static VALUE
528
+ breakpoint_set_hit_condition(VALUE self, VALUE value)
529
+ {
530
+ debug_breakpoint_t *breakpoint;
531
+ ID id_value;
532
+
533
+ Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
534
+ id_value = rb_to_id(value);
535
+
536
+ if(rb_intern("greater_or_equal") == id_value || rb_intern("ge") == id_value)
537
+ breakpoint->hit_condition = HIT_COND_GE;
538
+ else if(rb_intern("equal") == id_value || rb_intern("eq") == id_value)
539
+ breakpoint->hit_condition = HIT_COND_EQ;
540
+ else if(rb_intern("modulo") == id_value || rb_intern("mod") == id_value)
541
+ breakpoint->hit_condition = HIT_COND_MOD;
542
+ else
543
+ rb_raise(rb_eArgError, "Invalid condition parameter");
544
+ return value;
545
+ }
546
+
547
+ /*
548
+ * Document-class: Breakpoint
549
+ *
550
+ * == Summary
551
+ *
552
+ * This class represents a breakpoint. It defines position of the breakpoint and
553
+ * condition when this breakpoint should be triggered.
554
+ */
555
+ void
556
+ Init_breakpoint()
557
+ {
558
+ cBreakpoint = rb_define_class_under(mDebugger, "Breakpoint", rb_cObject);
559
+ rb_define_method(cBreakpoint, "enabled=", breakpoint_set_enabled, 1);
560
+ rb_define_method(cBreakpoint, "enabled?", breakpoint_enabled, 0);
561
+ rb_define_method(cBreakpoint, "expr", breakpoint_expr, 0);
562
+ rb_define_method(cBreakpoint, "expr=", breakpoint_set_expr, 1);
563
+ rb_define_method(cBreakpoint, "hit_condition", breakpoint_hit_condition, 0);
564
+ rb_define_method(cBreakpoint, "hit_condition=", breakpoint_set_hit_condition, 1);
565
+ rb_define_method(cBreakpoint, "hit_count", breakpoint_hit_count, 0);
566
+ rb_define_method(cBreakpoint, "hit_value", breakpoint_hit_value, 0);
567
+ rb_define_method(cBreakpoint, "hit_value=", breakpoint_set_hit_value, 1);
568
+ rb_define_method(cBreakpoint, "id", breakpoint_id, 0);
569
+ rb_define_method(cBreakpoint, "pos", breakpoint_pos, 0);
570
+ rb_define_method(cBreakpoint, "pos=", breakpoint_set_pos, 1);
571
+ rb_define_method(cBreakpoint, "source", breakpoint_source, 0);
572
+ rb_define_method(cBreakpoint, "source=", breakpoint_set_source, 1);
573
+ idEval = rb_intern("eval");
574
+ rdebug_catchpoints = rb_hash_new();
575
+
576
+ }
577
+
578
+