ruby-debug-base193 0.0.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/AUTHORS +10 -0
- data/CHANGES +334 -0
- data/LICENSE +23 -0
- data/README +122 -0
- data/Rakefile +266 -0
- data/ext/ruby_debug/breakpoint.c +578 -0
- data/ext/ruby_debug/extconf.rb +39 -0
- data/ext/ruby_debug/ruby_debug.c +2541 -0
- data/ext/ruby_debug/ruby_debug.h +138 -0
- data/lib/ChangeLog +1065 -0
- data/lib/ruby-debug-base.rb +304 -0
- data/test/base/base.rb +56 -0
- data/test/base/binding.rb +31 -0
- data/test/base/catchpoint.rb +23 -0
- metadata +127 -0
data/Rakefile
ADDED
@@ -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
|
+
|