debase 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +8 -0
- data/.travis.yml +4 -0
- data/Gemfile +4 -0
- data/LICENSE +23 -0
- data/MIT_LICENSE +22 -0
- data/README +22 -0
- data/Rakefile +34 -0
- data/debase.gemspec +30 -0
- data/ext/breakpoint.c +233 -0
- data/ext/context.c +377 -0
- data/ext/debase_internals.c +427 -0
- data/ext/debase_internals.h +94 -0
- data/ext/extconf.rb +14 -0
- data/ext/locker.c +52 -0
- data/lib/debase.rb +57 -0
- data/lib/debase/context.rb +44 -0
- data/lib/debase/version.rb +3 -0
- data/test/example/a/example.rb +1 -0
- data/test/example/at-exit.rb +3 -0
- data/test/example/b/example.rb +1 -0
- data/test/example/bp_loop_issue.rb +3 -0
- data/test/example/breakpoints-basename.rb +2 -0
- data/test/example/brkpt-class-bug.rb +8 -0
- data/test/example/classes.rb +11 -0
- data/test/example/dollar-0.rb +6 -0
- data/test/example/except-bug1.rb +4 -0
- data/test/example/file with space.rb +1 -0
- data/test/example/gcd.rb +18 -0
- data/test/example/info-var-bug.rb +47 -0
- data/test/example/info-var-bug2.rb +2 -0
- data/test/example/null.rb +1 -0
- data/test/example/output.rb +2 -0
- data/test/example/pm-bug.rb +3 -0
- data/test/example/pm.rb +11 -0
- data/test/example/raise.rb +3 -0
- data/test/helper.rb +2 -0
- data/test/test_base.rb +77 -0
- data/test/test_breakpoints.rb +14 -0
- data/test/test_catchpoint.rb +19 -0
- data/test/test_load.rb +44 -0
- data/test/test_reload_bug.rb +8 -0
- metadata +142 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b4c8f78116379934df37e337705708147ce878c3
|
4
|
+
data.tar.gz: 6a037e645748a877e64fd2548025b9d72c2fb698
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: f35b489310522fe41416655463caceb0c63c527c37e446d79629b6aa8850c00f7787b9a805b2d35ddf25cd1d96de57daa5dabc0fbab00ac1869fa1de9e0f3206
|
7
|
+
data.tar.gz: fcaf13c8b8eb973d419a2ead16c8a2c35904685888ea7382be6a9d627538126e5380666955fcd6d09c556fe723a3a991512622be725f5ac7745e6a932b7056d3
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
Copyright (C) 2005 Kent Sibilev <ksibilev@yahoo.com>
|
2
|
+
All rights reserved.
|
3
|
+
*
|
4
|
+
Redistribution and use in source and binary forms, with or without
|
5
|
+
modification, are permitted provided that the following conditions
|
6
|
+
are met:
|
7
|
+
1. Redistributions of source code must retain the above copyright
|
8
|
+
notice, this list of conditions and the following disclaimer.
|
9
|
+
2. Redistributions in binary form must reproduce the above copyright
|
10
|
+
notice, this list of conditions and the following disclaimer in the
|
11
|
+
documentation and/or other materials provided with the distribution.
|
12
|
+
*
|
13
|
+
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
14
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
15
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
16
|
+
ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
17
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
18
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
19
|
+
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
20
|
+
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
21
|
+
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
22
|
+
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
23
|
+
SUCH DAMAGE.
|
data/MIT_LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2007-2008, debug-commons team
|
2
|
+
Copyright (c) 2012, Dennis Ushakov
|
3
|
+
|
4
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
a copy of this software and associated documentation files (the
|
6
|
+
"Software"), to deal in the Software without restriction, including
|
7
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be
|
13
|
+
included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
|
data/README
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
= debase
|
2
|
+
|
3
|
+
== Overview
|
4
|
+
|
5
|
+
debase is a fast implementation of the standard debugger debug.rb for
|
6
|
+
Ruby 2.0.0. The faster execution speed and 2.0.0 compatibility is achieved
|
7
|
+
by utilizing a TracePoint mechanism in the Ruby C API.
|
8
|
+
|
9
|
+
== Requirements
|
10
|
+
|
11
|
+
debase requires Ruby 2.0.0 or higher.
|
12
|
+
|
13
|
+
== Install
|
14
|
+
|
15
|
+
debase is provided as a RubyGem. To install:
|
16
|
+
|
17
|
+
<tt>gem install debase</tt>
|
18
|
+
|
19
|
+
== License
|
20
|
+
|
21
|
+
debase contains parts of the code from ruby-debug-base gem.
|
22
|
+
See MIT_LICENSE and LICENSE for license information.
|
data/Rakefile
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
require 'rake/testtask'
|
3
|
+
|
4
|
+
BASE_TEST_FILE_LIST = Dir['test/**/test_*.rb']
|
5
|
+
|
6
|
+
desc "Remove built files"
|
7
|
+
task :clean do
|
8
|
+
cd "ext" do
|
9
|
+
if File.exists?("Makefile")
|
10
|
+
sh "make clean"
|
11
|
+
rm "Makefile"
|
12
|
+
end
|
13
|
+
derived_files = Dir.glob(".o") + Dir.glob("*.so") + Dir.glob("*.bundle")
|
14
|
+
rm derived_files unless derived_files.empty?
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
desc "Create the core debase shared library extension"
|
19
|
+
task :lib => :clean do
|
20
|
+
Dir.chdir("ext") do
|
21
|
+
system("#{Gem.ruby} extconf.rb && make")
|
22
|
+
exit $?.to_i if $?.to_i != 0
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
desc "Test debase."
|
27
|
+
Rake::TestTask.new(:test) do |t|
|
28
|
+
t.libs += ['./ext', './lib']
|
29
|
+
t.test_files = FileList[BASE_TEST_FILE_LIST]
|
30
|
+
t.verbose = true
|
31
|
+
end
|
32
|
+
task :test => :lib
|
33
|
+
|
34
|
+
task :default => :test
|
data/debase.gemspec
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "debase/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "debase"
|
7
|
+
s.version = Debase::VERSION
|
8
|
+
s.authors = ["Dennis Ushakov"]
|
9
|
+
s.email = ["dennis.ushakov@gmail.com"]
|
10
|
+
s.homepage = ""
|
11
|
+
s.summary = %q{debase is a fast implementation of the standard Ruby debugger debug.rb for Ruby 2.0}
|
12
|
+
s.description = <<-EOF
|
13
|
+
debase is a fast implementation of the standard Ruby debugger debug.rb for Ruby 2.0.
|
14
|
+
It is implemented by utilizing a new Ruby TracePoint class. The core component
|
15
|
+
provides support that front-ends can build on. It provides breakpoint
|
16
|
+
handling, bindings for stack frames among other things.
|
17
|
+
EOF
|
18
|
+
|
19
|
+
s.rubyforge_project = "debase"
|
20
|
+
|
21
|
+
s.files = `git ls-files`.split("\n")
|
22
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
23
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
24
|
+
s.require_paths = ["lib"]
|
25
|
+
|
26
|
+
s.extensions = ["ext/extconf.rb"]
|
27
|
+
|
28
|
+
s.add_development_dependency "test-unit"
|
29
|
+
s.add_development_dependency "rake"
|
30
|
+
end
|
data/ext/breakpoint.c
ADDED
@@ -0,0 +1,233 @@
|
|
1
|
+
#include <debase_internals.h>
|
2
|
+
|
3
|
+
#ifdef _WIN32
|
4
|
+
#include <ctype.h>
|
5
|
+
#endif
|
6
|
+
|
7
|
+
#if defined DOSISH
|
8
|
+
#define isdirsep(x) ((x) == '/' || (x) == '\\')
|
9
|
+
#else
|
10
|
+
#define isdirsep(x) ((x) == '/')
|
11
|
+
#endif
|
12
|
+
|
13
|
+
static VALUE cBreakpoint;
|
14
|
+
static int breakpoint_max;
|
15
|
+
|
16
|
+
extern VALUE
|
17
|
+
catchpoint_hit_count(VALUE catchpoints, VALUE exception, VALUE *exception_name) {
|
18
|
+
VALUE ancestors;
|
19
|
+
VALUE expn_class;
|
20
|
+
VALUE aclass;
|
21
|
+
VALUE mod_name;
|
22
|
+
VALUE hit_count;
|
23
|
+
int i;
|
24
|
+
|
25
|
+
if (catchpoints == Qnil /*|| st_get_num_entries(RHASH_TBL(rdebug_catchpoints)) == 0)*/)
|
26
|
+
return Qnil;
|
27
|
+
expn_class = rb_obj_class(exception);
|
28
|
+
ancestors = rb_mod_ancestors(expn_class);
|
29
|
+
for(i = 0; i < RARRAY_LEN(ancestors); i++)
|
30
|
+
{
|
31
|
+
aclass = rb_ary_entry(ancestors, i);
|
32
|
+
mod_name = rb_mod_name(aclass);
|
33
|
+
hit_count = rb_hash_aref(catchpoints, mod_name);
|
34
|
+
if(hit_count != Qnil)
|
35
|
+
{
|
36
|
+
*exception_name = mod_name;
|
37
|
+
return hit_count;
|
38
|
+
}
|
39
|
+
}
|
40
|
+
return Qnil;
|
41
|
+
}
|
42
|
+
|
43
|
+
static void
|
44
|
+
Breakpoint_mark(breakpoint_t *breakpoint)
|
45
|
+
{
|
46
|
+
rb_gc_mark(breakpoint->source);
|
47
|
+
rb_gc_mark(breakpoint->expr);
|
48
|
+
}
|
49
|
+
|
50
|
+
static VALUE
|
51
|
+
Breakpoint_create(VALUE klass)
|
52
|
+
{
|
53
|
+
breakpoint_t *breakpoint;
|
54
|
+
|
55
|
+
breakpoint = ALLOC(breakpoint_t);
|
56
|
+
return Data_Wrap_Struct(klass, Breakpoint_mark, xfree, breakpoint);
|
57
|
+
}
|
58
|
+
|
59
|
+
static VALUE
|
60
|
+
Breakpoint_initialize(VALUE self, VALUE source, VALUE pos, VALUE expr)
|
61
|
+
{
|
62
|
+
breakpoint_t *breakpoint;
|
63
|
+
|
64
|
+
Data_Get_Struct(self, breakpoint_t, breakpoint);
|
65
|
+
breakpoint->id = ++breakpoint_max;
|
66
|
+
breakpoint->source = StringValue(source);
|
67
|
+
breakpoint->line = FIX2INT(pos);
|
68
|
+
breakpoint->enabled = Qtrue;
|
69
|
+
breakpoint->expr = NIL_P(expr) ? expr : StringValue(expr);
|
70
|
+
|
71
|
+
return Qnil;
|
72
|
+
}
|
73
|
+
|
74
|
+
static VALUE
|
75
|
+
Breakpoint_remove(VALUE self, VALUE breakpoints, VALUE id_value)
|
76
|
+
{
|
77
|
+
int i;
|
78
|
+
int id;
|
79
|
+
VALUE breakpoint_object;
|
80
|
+
breakpoint_t *breakpoint;
|
81
|
+
|
82
|
+
if (breakpoints == Qnil) return Qnil;
|
83
|
+
|
84
|
+
id = FIX2INT(id_value);
|
85
|
+
|
86
|
+
for(i = 0; i < RARRAY_LEN(breakpoints); i++)
|
87
|
+
{
|
88
|
+
breakpoint_object = rb_ary_entry(breakpoints, i);
|
89
|
+
Data_Get_Struct(breakpoint_object, breakpoint_t, breakpoint);
|
90
|
+
if(breakpoint->id == id)
|
91
|
+
{
|
92
|
+
rb_ary_delete_at(breakpoints, i);
|
93
|
+
return breakpoint_object;
|
94
|
+
}
|
95
|
+
}
|
96
|
+
return Qnil;
|
97
|
+
}
|
98
|
+
|
99
|
+
static VALUE
|
100
|
+
Breakpoint_id(VALUE self)
|
101
|
+
{
|
102
|
+
breakpoint_t *breakpoint;
|
103
|
+
|
104
|
+
Data_Get_Struct(self, breakpoint_t, breakpoint);
|
105
|
+
return INT2FIX(breakpoint->id);
|
106
|
+
}
|
107
|
+
|
108
|
+
static VALUE
|
109
|
+
Breakpoint_source(VALUE self)
|
110
|
+
{
|
111
|
+
breakpoint_t *breakpoint;
|
112
|
+
|
113
|
+
Data_Get_Struct(self, breakpoint_t, breakpoint);
|
114
|
+
return breakpoint->source;
|
115
|
+
}
|
116
|
+
|
117
|
+
static VALUE
|
118
|
+
Breakpoint_pos(VALUE self)
|
119
|
+
{
|
120
|
+
breakpoint_t *breakpoint;
|
121
|
+
|
122
|
+
Data_Get_Struct(self, breakpoint_t, breakpoint);
|
123
|
+
return INT2FIX(breakpoint->line);
|
124
|
+
}
|
125
|
+
|
126
|
+
int
|
127
|
+
filename_cmp_impl(VALUE source, char *file)
|
128
|
+
{
|
129
|
+
char *source_ptr, *file_ptr;
|
130
|
+
long s_len, f_len, min_len;
|
131
|
+
long s,f;
|
132
|
+
int dirsep_flag = 0;
|
133
|
+
|
134
|
+
s_len = RSTRING_LEN(source);
|
135
|
+
f_len = strlen(file);
|
136
|
+
min_len = s_len < f_len ? s_len : f_len;
|
137
|
+
|
138
|
+
source_ptr = RSTRING_PTR(source);
|
139
|
+
file_ptr = file;
|
140
|
+
|
141
|
+
for( s = s_len - 1, f = f_len - 1; s >= s_len - min_len && f >= f_len - min_len; s--, f-- )
|
142
|
+
{
|
143
|
+
if((source_ptr[s] == '.' || file_ptr[f] == '.') && dirsep_flag)
|
144
|
+
return 1;
|
145
|
+
if(isdirsep(source_ptr[s]) && isdirsep(file_ptr[f]))
|
146
|
+
dirsep_flag = 1;
|
147
|
+
#ifdef DOSISH_DRIVE_LETTER
|
148
|
+
else if (s == 0)
|
149
|
+
return(toupper(source_ptr[s]) == toupper(file_ptr[f]));
|
150
|
+
#endif
|
151
|
+
else if(source_ptr[s] != file_ptr[f])
|
152
|
+
return 0;
|
153
|
+
}
|
154
|
+
return 1;
|
155
|
+
}
|
156
|
+
|
157
|
+
int
|
158
|
+
filename_cmp(VALUE source, char *file)
|
159
|
+
{
|
160
|
+
#ifdef _WIN32
|
161
|
+
return filename_cmp_impl(source, file);
|
162
|
+
#else
|
163
|
+
#ifdef PATH_MAX
|
164
|
+
char path[PATH_MAX + 1];
|
165
|
+
path[PATH_MAX] = 0;
|
166
|
+
return filename_cmp_impl(source, realpath(file, path) != NULL ? path : file);
|
167
|
+
#else
|
168
|
+
char *path;
|
169
|
+
int result;
|
170
|
+
path = realpath(file, NULL);
|
171
|
+
result = filename_cmp_impl(source, path == NULL ? file : path);
|
172
|
+
free(path);
|
173
|
+
return result;
|
174
|
+
#endif
|
175
|
+
#endif
|
176
|
+
}
|
177
|
+
|
178
|
+
static int
|
179
|
+
check_breakpoint_by_pos(VALUE breakpoint_object, char *file, int line)
|
180
|
+
{
|
181
|
+
breakpoint_t *breakpoint;
|
182
|
+
|
183
|
+
if(breakpoint_object == Qnil)
|
184
|
+
return 0;
|
185
|
+
Data_Get_Struct(breakpoint_object, breakpoint_t, breakpoint);
|
186
|
+
if (Qtrue != breakpoint->enabled) return 0;
|
187
|
+
if(breakpoint->line != line)
|
188
|
+
return 0;
|
189
|
+
if(filename_cmp(breakpoint->source, file))
|
190
|
+
return 1;
|
191
|
+
return 0;
|
192
|
+
}
|
193
|
+
|
194
|
+
static VALUE
|
195
|
+
Breakpoint_find(VALUE self, VALUE breakpoints, VALUE source, VALUE pos, VALUE binding)
|
196
|
+
{
|
197
|
+
return breakpoint_find(breakpoints, source, pos, binding);
|
198
|
+
}
|
199
|
+
|
200
|
+
extern VALUE
|
201
|
+
breakpoint_find(VALUE breakpoints, VALUE source, VALUE pos, VALUE binding)
|
202
|
+
{
|
203
|
+
VALUE breakpoint_object;
|
204
|
+
char *file;
|
205
|
+
int line;
|
206
|
+
int i;
|
207
|
+
|
208
|
+
file = RSTRING_PTR(source);
|
209
|
+
line = FIX2INT(pos);
|
210
|
+
for(i = 0; i < RARRAY_LEN(breakpoints); i++)
|
211
|
+
{
|
212
|
+
breakpoint_object = rb_ary_entry(breakpoints, i);
|
213
|
+
if (check_breakpoint_by_pos(breakpoint_object, file, line))
|
214
|
+
{
|
215
|
+
return breakpoint_object;
|
216
|
+
}
|
217
|
+
}
|
218
|
+
return Qnil;
|
219
|
+
}
|
220
|
+
|
221
|
+
extern void
|
222
|
+
Init_breakpoint(VALUE mDebase)
|
223
|
+
{
|
224
|
+
breakpoint_max = 0;
|
225
|
+
cBreakpoint = rb_define_class_under(mDebase, "Breakpoint", rb_cObject);
|
226
|
+
rb_define_singleton_method(cBreakpoint, "find", Breakpoint_find, 4);
|
227
|
+
rb_define_singleton_method(cBreakpoint, "remove", Breakpoint_remove, 2);
|
228
|
+
rb_define_method(cBreakpoint, "initialize", Breakpoint_initialize, 3);
|
229
|
+
rb_define_method(cBreakpoint, "id", Breakpoint_id, 0);
|
230
|
+
rb_define_method(cBreakpoint, "source", Breakpoint_source, 0);
|
231
|
+
rb_define_method(cBreakpoint, "pos", Breakpoint_pos, 0);
|
232
|
+
rb_define_alloc_func(cBreakpoint, Breakpoint_create);
|
233
|
+
}
|
data/ext/context.c
ADDED
@@ -0,0 +1,377 @@
|
|
1
|
+
#include <debase_internals.h>
|
2
|
+
|
3
|
+
static VALUE cContext;
|
4
|
+
static int thnum_current = 0;
|
5
|
+
|
6
|
+
static VALUE idAlive;
|
7
|
+
|
8
|
+
/* "Step", "Next" and "Finish" do their work by saving information
|
9
|
+
about where to stop next. reset_stopping_points removes/resets this
|
10
|
+
information. */
|
11
|
+
extern void
|
12
|
+
reset_stepping_stop_points(debug_context_t *context)
|
13
|
+
{
|
14
|
+
context->dest_frame = -1;
|
15
|
+
context->stop_line = -1;
|
16
|
+
context->stop_next = -1;
|
17
|
+
}
|
18
|
+
|
19
|
+
static inline VALUE
|
20
|
+
Context_thnum(VALUE self) {
|
21
|
+
debug_context_t *context;
|
22
|
+
Data_Get_Struct(self, debug_context_t, context);
|
23
|
+
return INT2FIX(context->thnum);
|
24
|
+
}
|
25
|
+
|
26
|
+
static inline void
|
27
|
+
delete_frame(debug_context_t *context)
|
28
|
+
{
|
29
|
+
debug_frame_t *frame;
|
30
|
+
|
31
|
+
frame = context->stack;
|
32
|
+
context->stack = frame->prev;
|
33
|
+
context->stack_size--;
|
34
|
+
xfree(frame);
|
35
|
+
}
|
36
|
+
|
37
|
+
static inline void
|
38
|
+
fill_frame(debug_frame_t *frame, char* file, int line, VALUE binding, VALUE self)
|
39
|
+
{
|
40
|
+
frame->file = file;
|
41
|
+
frame->line = line;
|
42
|
+
frame->binding = binding;
|
43
|
+
frame->self = self;
|
44
|
+
}
|
45
|
+
|
46
|
+
static inline VALUE
|
47
|
+
Context_stack_size(VALUE self)
|
48
|
+
{
|
49
|
+
debug_context_t *context;
|
50
|
+
Data_Get_Struct(self, debug_context_t, context);
|
51
|
+
return INT2FIX(context->stack_size);
|
52
|
+
}
|
53
|
+
|
54
|
+
static inline VALUE
|
55
|
+
Context_thread(VALUE self)
|
56
|
+
{
|
57
|
+
debug_context_t *context;
|
58
|
+
Data_Get_Struct(self, debug_context_t, context);
|
59
|
+
return context->thread;
|
60
|
+
}
|
61
|
+
|
62
|
+
static inline VALUE
|
63
|
+
Context_dead(VALUE self)
|
64
|
+
{
|
65
|
+
debug_context_t *context;
|
66
|
+
Data_Get_Struct(self, debug_context_t, context);
|
67
|
+
return IS_THREAD_ALIVE(context->thread) ? Qfalse : Qtrue;
|
68
|
+
}
|
69
|
+
|
70
|
+
extern VALUE
|
71
|
+
Context_ignored(VALUE self)
|
72
|
+
{
|
73
|
+
debug_context_t *context;
|
74
|
+
|
75
|
+
if (self == Qnil) return Qtrue;
|
76
|
+
Data_Get_Struct(self, debug_context_t, context);
|
77
|
+
return CTX_FL_TEST(context, CTX_FL_IGNORE) ? Qtrue : Qfalse;
|
78
|
+
}
|
79
|
+
|
80
|
+
extern void
|
81
|
+
push_frame(VALUE context_object, char* file, int line, VALUE binding, VALUE self)
|
82
|
+
{
|
83
|
+
debug_context_t *context;
|
84
|
+
debug_frame_t *frame;
|
85
|
+
Data_Get_Struct(context_object, debug_context_t, context);
|
86
|
+
|
87
|
+
frame = ALLOC(debug_frame_t);
|
88
|
+
fill_frame(frame, file, line, binding, self);
|
89
|
+
frame->prev = context->stack;
|
90
|
+
context->stack = frame;
|
91
|
+
context->stack_size++;
|
92
|
+
}
|
93
|
+
|
94
|
+
extern void
|
95
|
+
pop_frame(VALUE context_object)
|
96
|
+
{
|
97
|
+
debug_context_t *context;
|
98
|
+
Data_Get_Struct(context_object, debug_context_t, context);
|
99
|
+
|
100
|
+
if (context->stack_size > 0) {
|
101
|
+
delete_frame(context);
|
102
|
+
}
|
103
|
+
}
|
104
|
+
|
105
|
+
extern void
|
106
|
+
update_frame(VALUE context_object, char* file, int line, VALUE binding, VALUE self)
|
107
|
+
{
|
108
|
+
debug_context_t *context;
|
109
|
+
Data_Get_Struct(context_object, debug_context_t, context);
|
110
|
+
|
111
|
+
if (context->stack_size == 0) {
|
112
|
+
push_frame(context_object, file, line, binding, self);
|
113
|
+
return;
|
114
|
+
}
|
115
|
+
fill_frame(context->stack, file, line, binding, self);
|
116
|
+
}
|
117
|
+
|
118
|
+
static void
|
119
|
+
Context_mark(debug_context_t *context)
|
120
|
+
{
|
121
|
+
debug_frame_t *frame;
|
122
|
+
|
123
|
+
rb_gc_mark(context->thread);
|
124
|
+
frame = context->stack;
|
125
|
+
while (frame != NULL) {
|
126
|
+
rb_gc_mark(frame->self);
|
127
|
+
rb_gc_mark(frame->binding);
|
128
|
+
frame = frame->prev;
|
129
|
+
}
|
130
|
+
}
|
131
|
+
|
132
|
+
static void
|
133
|
+
Context_free(debug_context_t *context) {
|
134
|
+
while(context->stack_size > 0) {
|
135
|
+
delete_frame(context);
|
136
|
+
}
|
137
|
+
xfree(context);
|
138
|
+
}
|
139
|
+
|
140
|
+
extern VALUE
|
141
|
+
context_create(VALUE thread, VALUE cDebugThread) {
|
142
|
+
debug_context_t *context;
|
143
|
+
|
144
|
+
context = ALLOC(debug_context_t);
|
145
|
+
context->stack_size = 0;
|
146
|
+
context->stack = NULL;
|
147
|
+
context->thnum = ++thnum_current;
|
148
|
+
context->thread = thread;
|
149
|
+
context->flags = 0;
|
150
|
+
context->last_file = NULL;
|
151
|
+
context->last_line = -1;
|
152
|
+
context->stop_frame = -1;
|
153
|
+
reset_stepping_stop_points(context);
|
154
|
+
if(rb_obj_class(thread) == cDebugThread) CTX_FL_SET(context, CTX_FL_IGNORE);
|
155
|
+
return Data_Wrap_Struct(cContext, Context_mark, Context_free, context);
|
156
|
+
}
|
157
|
+
|
158
|
+
static inline void
|
159
|
+
check_frame_number_valid(debug_context_t *context, int frame_no)
|
160
|
+
{
|
161
|
+
if (frame_no < 0 || frame_no >= context->stack_size) {
|
162
|
+
rb_raise(rb_eArgError, "Invalid frame number %d, stack (0...%d)",
|
163
|
+
frame_no, context->stack_size);
|
164
|
+
}
|
165
|
+
}
|
166
|
+
|
167
|
+
static debug_frame_t*
|
168
|
+
get_frame_no(debug_context_t *context, int frame_n)
|
169
|
+
{
|
170
|
+
debug_frame_t *frame;
|
171
|
+
int i;
|
172
|
+
|
173
|
+
check_frame_number_valid(context, frame_n);
|
174
|
+
frame = context->stack;
|
175
|
+
for (i = 0; i < frame_n; i++) {
|
176
|
+
frame = frame->prev;
|
177
|
+
}
|
178
|
+
return frame;
|
179
|
+
}
|
180
|
+
|
181
|
+
static VALUE
|
182
|
+
Context_frame_file(int argc, VALUE *argv, VALUE self)
|
183
|
+
{
|
184
|
+
debug_context_t *context;
|
185
|
+
debug_frame_t *frame;
|
186
|
+
VALUE frame_no;
|
187
|
+
int frame_n;
|
188
|
+
|
189
|
+
Data_Get_Struct(self, debug_context_t, context);
|
190
|
+
frame_n = rb_scan_args(argc, argv, "01", &frame_no) == 0 ? 0 : FIX2INT(frame_no);
|
191
|
+
frame = get_frame_no(context, frame_n);
|
192
|
+
return rb_str_new2(frame->file);
|
193
|
+
}
|
194
|
+
|
195
|
+
static VALUE
|
196
|
+
Context_frame_line(int argc, VALUE *argv, VALUE self)
|
197
|
+
{
|
198
|
+
debug_context_t *context;
|
199
|
+
debug_frame_t *frame;
|
200
|
+
VALUE frame_no;
|
201
|
+
int frame_n;
|
202
|
+
|
203
|
+
Data_Get_Struct(self, debug_context_t, context);
|
204
|
+
frame_n = rb_scan_args(argc, argv, "01", &frame_no) == 0 ? 0 : FIX2INT(frame_no);
|
205
|
+
frame = get_frame_no(context, frame_n);
|
206
|
+
return INT2FIX(frame->line);
|
207
|
+
}
|
208
|
+
|
209
|
+
static VALUE
|
210
|
+
Context_frame_binding(int argc, VALUE *argv, VALUE self)
|
211
|
+
{
|
212
|
+
debug_context_t *context;
|
213
|
+
debug_frame_t *frame;
|
214
|
+
VALUE frame_no;
|
215
|
+
int frame_n;
|
216
|
+
|
217
|
+
Data_Get_Struct(self, debug_context_t, context);
|
218
|
+
frame_n = rb_scan_args(argc, argv, "01", &frame_no) == 0 ? 0 : FIX2INT(frame_no);
|
219
|
+
frame = get_frame_no(context, frame_n);
|
220
|
+
return frame->binding;
|
221
|
+
}
|
222
|
+
|
223
|
+
static VALUE
|
224
|
+
Context_frame_self(int argc, VALUE *argv, VALUE self)
|
225
|
+
{
|
226
|
+
debug_context_t *context;
|
227
|
+
debug_frame_t *frame;
|
228
|
+
VALUE frame_no;
|
229
|
+
int frame_n;
|
230
|
+
|
231
|
+
Data_Get_Struct(self, debug_context_t, context);
|
232
|
+
frame_n = rb_scan_args(argc, argv, "01", &frame_no) == 0 ? 0 : FIX2INT(frame_no);
|
233
|
+
frame = get_frame_no(context, frame_n);
|
234
|
+
return frame->self;
|
235
|
+
}
|
236
|
+
|
237
|
+
static VALUE
|
238
|
+
Context_stop_reason(VALUE self)
|
239
|
+
{
|
240
|
+
debug_context_t *context;
|
241
|
+
const char *symbol;
|
242
|
+
|
243
|
+
Data_Get_Struct(self, debug_context_t, context);
|
244
|
+
|
245
|
+
switch(context->stop_reason)
|
246
|
+
{
|
247
|
+
case CTX_STOP_STEP:
|
248
|
+
symbol = "step";
|
249
|
+
break;
|
250
|
+
case CTX_STOP_BREAKPOINT:
|
251
|
+
symbol = "breakpoint";
|
252
|
+
break;
|
253
|
+
case CTX_STOP_CATCHPOINT:
|
254
|
+
symbol = "catchpoint";
|
255
|
+
break;
|
256
|
+
case CTX_STOP_NONE:
|
257
|
+
default:
|
258
|
+
symbol = "none";
|
259
|
+
}
|
260
|
+
if(CTX_FL_TEST(context, CTX_FL_DEAD))
|
261
|
+
symbol = "post-mortem";
|
262
|
+
|
263
|
+
return ID2SYM(rb_intern(symbol));
|
264
|
+
}
|
265
|
+
|
266
|
+
static VALUE
|
267
|
+
Context_stop_next(int argc, VALUE *argv, VALUE self)
|
268
|
+
{
|
269
|
+
VALUE steps;
|
270
|
+
VALUE force;
|
271
|
+
debug_context_t *context;
|
272
|
+
|
273
|
+
rb_scan_args(argc, argv, "11", &steps, &force);
|
274
|
+
if(FIX2INT(steps) < 0) rb_raise(rb_eRuntimeError, "Steps argument can't be negative.");
|
275
|
+
|
276
|
+
Data_Get_Struct(self, debug_context_t, context);
|
277
|
+
context->stop_next = FIX2INT(steps);
|
278
|
+
if(RTEST(force))
|
279
|
+
CTX_FL_SET(context, CTX_FL_FORCE_MOVE);
|
280
|
+
else
|
281
|
+
CTX_FL_UNSET(context, CTX_FL_FORCE_MOVE);
|
282
|
+
|
283
|
+
return steps;
|
284
|
+
}
|
285
|
+
|
286
|
+
static VALUE
|
287
|
+
Context_step_over(int argc, VALUE *argv, VALUE self)
|
288
|
+
{
|
289
|
+
VALUE lines, frame, force;
|
290
|
+
debug_context_t *context;
|
291
|
+
|
292
|
+
Data_Get_Struct(self, debug_context_t, context);
|
293
|
+
if(context->stack_size == 0)
|
294
|
+
rb_raise(rb_eRuntimeError, "No frames collected.");
|
295
|
+
|
296
|
+
rb_scan_args(argc, argv, "12", &lines, &frame, &force);
|
297
|
+
context->stop_line = FIX2INT(lines);
|
298
|
+
CTX_FL_UNSET(context, CTX_FL_STEPPED);
|
299
|
+
if(frame == Qnil)
|
300
|
+
{
|
301
|
+
context->dest_frame = context->stack_size;
|
302
|
+
}
|
303
|
+
else
|
304
|
+
{
|
305
|
+
if(FIX2INT(frame) < 0 && FIX2INT(frame) >= context->stack_size)
|
306
|
+
rb_raise(rb_eRuntimeError, "Destination frame is out of range.");
|
307
|
+
context->dest_frame = context->stack_size - FIX2INT(frame);
|
308
|
+
}
|
309
|
+
if(RTEST(force))
|
310
|
+
CTX_FL_SET(context, CTX_FL_FORCE_MOVE);
|
311
|
+
else
|
312
|
+
CTX_FL_UNSET(context, CTX_FL_FORCE_MOVE);
|
313
|
+
|
314
|
+
return Qnil;
|
315
|
+
}
|
316
|
+
|
317
|
+
static VALUE
|
318
|
+
Context_stop_frame(VALUE self, VALUE frame)
|
319
|
+
{
|
320
|
+
debug_context_t *debug_context;
|
321
|
+
|
322
|
+
Data_Get_Struct(self, debug_context_t, debug_context);
|
323
|
+
if(FIX2INT(frame) < 0 && FIX2INT(frame) >= debug_context->stack_size)
|
324
|
+
rb_raise(rb_eRuntimeError, "Stop frame is out of range.");
|
325
|
+
debug_context->stop_frame = debug_context->stack_size - FIX2INT(frame);
|
326
|
+
|
327
|
+
return frame;
|
328
|
+
}
|
329
|
+
|
330
|
+
/*
|
331
|
+
* Document-class: Context
|
332
|
+
*
|
333
|
+
* == Summary
|
334
|
+
*
|
335
|
+
* Debugger keeps a single instance of this class for each Ruby thread.
|
336
|
+
*/
|
337
|
+
VALUE
|
338
|
+
Init_context(VALUE mDebase)
|
339
|
+
{
|
340
|
+
cContext = rb_define_class_under(mDebase, "Context", rb_cObject);
|
341
|
+
rb_define_method(cContext, "stack_size", Context_stack_size, 0);
|
342
|
+
rb_define_method(cContext, "thread", Context_thread, 0);
|
343
|
+
rb_define_method(cContext, "dead?", Context_dead, 0);
|
344
|
+
rb_define_method(cContext, "ignored?", Context_ignored, 0);
|
345
|
+
rb_define_method(cContext, "thnum", Context_thnum, 0);
|
346
|
+
rb_define_method(cContext, "stop_reason", Context_stop_reason, 0);
|
347
|
+
rb_define_method(cContext, "frame_file", Context_frame_file, -1);
|
348
|
+
rb_define_method(cContext, "frame_line", Context_frame_line, -1);
|
349
|
+
rb_define_method(cContext, "frame_binding", Context_frame_binding, -1);
|
350
|
+
rb_define_method(cContext, "frame_self", Context_frame_self, -1);
|
351
|
+
rb_define_method(cContext, "stop_next=", Context_stop_next, -1);
|
352
|
+
rb_define_method(cContext, "step", Context_stop_next, -1);
|
353
|
+
rb_define_method(cContext, "step_over", Context_step_over, -1);
|
354
|
+
rb_define_method(cContext, "stop_frame=", Context_stop_frame, 1);
|
355
|
+
|
356
|
+
idAlive = rb_intern("alive?");
|
357
|
+
|
358
|
+
return cContext;
|
359
|
+
// rb_define_method(cContext, "suspend", context_suspend, 0);
|
360
|
+
// rb_define_method(cContext, "suspended?", context_is_suspended, 0);
|
361
|
+
// rb_define_method(cContext, "resume", context_resume, 0);
|
362
|
+
// rb_define_method(cContext, "tracing", context_tracing, 0);
|
363
|
+
// rb_define_method(cContext, "tracing=", context_set_tracing, 1);
|
364
|
+
// rb_define_method(cContext, "ignored?", context_ignored, 0);
|
365
|
+
// rb_define_method(cContext, "frame_args", context_frame_args, -1);
|
366
|
+
// rb_define_method(cContext, "frame_args_info", context_frame_args_info, -1);
|
367
|
+
// rb_define_method(cContext, "frame_class", context_frame_class, -1);
|
368
|
+
// rb_define_method(cContext, "frame_id", context_frame_id, -1);
|
369
|
+
// rb_define_method(cContext, "frame_locals", context_frame_locals, -1);
|
370
|
+
// rb_define_method(cContext, "frame_method", context_frame_id, -1);
|
371
|
+
// rb_define_method(cContext, "breakpoint",
|
372
|
+
// context_breakpoint, 0); /* in breakpoint.c */
|
373
|
+
// rb_define_method(cContext, "set_breakpoint",
|
374
|
+
// context_set_breakpoint, -1); /* in breakpoint.c */
|
375
|
+
// rb_define_method(cContext, "jump", context_jump, 2);
|
376
|
+
// rb_define_method(cContext, "pause", context_pause, 0);
|
377
|
+
}
|