debase 0.2.2 → 0.2.4.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.travis.yml +2 -1
- data/ext/attach/extconf.rb +7 -1
- data/ext/context.c +4 -16
- data/ext/debase_internals.c +96 -18
- data/ext/debase_internals.h +5 -5
- data/ext/extconf.rb +7 -2
- data/lib/debase.rb +30 -1
- data/lib/debase/version.rb +1 -1
- data/test/example/bootsnap/a.rb +5 -0
- data/test/example/bootsnap/bootsnap.rb +3 -0
- data/test/test_load.rb +34 -0
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 107e62228760d4c312c185830e9b6c152814c02b2f85d94a094c44e6687402b8
|
4
|
+
data.tar.gz: 740ccb46f3bb6e97d60afd38e90c6d9cb3be58f0a29c66efc44f0e06d18acec8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6ade635981299fee6a15e4e353c66db86f6afe14ae5c1a3e6f364a7936cec11f21f32ce4527d249d89738a573106a80be861b63ff334d591ef29adf6bdbcc5f0
|
7
|
+
data.tar.gz: a9c840b6868a842f94f4402a4161115b703522c9a29ff5bb3b09ab2025fcff451b3bb912858d413bfb673eb2a994c989498fe08cef062cd04db44c68f4d5ad54
|
data/.travis.yml
CHANGED
data/ext/attach/extconf.rb
CHANGED
@@ -28,7 +28,13 @@ RbConfig::MAKEFILE_CONFIG['CC'] = ENV['CC'] if ENV['CC']
|
|
28
28
|
require "debase/ruby_core_source"
|
29
29
|
|
30
30
|
hdrs = proc {
|
31
|
-
have_header("vm_core.h")
|
31
|
+
have_header("vm_core.h") and
|
32
|
+
have_header("iseq.h") and
|
33
|
+
have_header("version.h") and
|
34
|
+
have_header("vm_core.h") and
|
35
|
+
have_header("vm_insnhelper.h") and
|
36
|
+
have_header("vm_core.h") and
|
37
|
+
have_header("method.h")
|
32
38
|
}
|
33
39
|
|
34
40
|
# Allow use customization of compile options. For example, the
|
data/ext/context.c
CHANGED
@@ -135,7 +135,6 @@ Context_mark(debug_context_t *context)
|
|
135
135
|
|
136
136
|
static void
|
137
137
|
Context_free(debug_context_t *context) {
|
138
|
-
xfree(context->init_stack_files);
|
139
138
|
xfree(context);
|
140
139
|
}
|
141
140
|
|
@@ -143,25 +142,12 @@ extern VALUE
|
|
143
142
|
context_create(VALUE thread, VALUE cDebugThread) {
|
144
143
|
debug_context_t *context;
|
145
144
|
VALUE locations;
|
146
|
-
VALUE location;
|
147
|
-
VALUE path;
|
148
|
-
VALUE lineno;
|
149
145
|
|
150
146
|
context = ALLOC(debug_context_t);
|
151
147
|
context->stack_size = 0;
|
152
148
|
locations = rb_funcall(thread, rb_intern("backtrace_locations"), 1, INT2FIX(1));
|
153
|
-
context->
|
154
|
-
|
155
|
-
context->init_stack_files = ruby_xmalloc2((context->init_stack_size),sizeof(char*));
|
156
|
-
|
157
|
-
int i;
|
158
|
-
for (i = 0; i < context->init_stack_size; i++) {
|
159
|
-
location = rb_ary_entry(locations, i);
|
160
|
-
path = rb_funcall(location, rb_intern("path"), 0);
|
161
|
-
lineno = rb_funcall(location, rb_intern("lineno"), 0);
|
162
|
-
context->init_stack_files[i] = path != Qnil ? RSTRING_PTR(path) : "";
|
163
|
-
}
|
164
|
-
|
149
|
+
context->calced_stack_size = locations != Qnil ? RARRAY_LENINT(locations) : 0;
|
150
|
+
context->init_stack_size = -1;
|
165
151
|
|
166
152
|
context->stack = NULL;
|
167
153
|
context->thnum = ++thnum_current;
|
@@ -169,6 +155,8 @@ context_create(VALUE thread, VALUE cDebugThread) {
|
|
169
155
|
context->flags = 0;
|
170
156
|
context->last_file = NULL;
|
171
157
|
context->last_line = -1;
|
158
|
+
context->hit_user_code = 0;
|
159
|
+
context->script_finished = 0;
|
172
160
|
context->stop_frame = -1;
|
173
161
|
context->thread_pause = 0;
|
174
162
|
context->stop_reason = CTX_STOP_NONE;
|
data/ext/debase_internals.c
CHANGED
@@ -303,6 +303,8 @@ remove_pause_flag(VALUE thread, VALUE context_object, VALUE ignored)
|
|
303
303
|
static void
|
304
304
|
call_at_line(debug_context_t *context, char *file, int line, VALUE context_object)
|
305
305
|
{
|
306
|
+
context->hit_user_code = 1;
|
307
|
+
|
306
308
|
rb_hash_foreach(contexts, remove_pause_flag, 0);
|
307
309
|
CTX_FL_UNSET(context, CTX_FL_STEPPED);
|
308
310
|
CTX_FL_UNSET(context, CTX_FL_FORCE_MOVE);
|
@@ -311,6 +313,35 @@ call_at_line(debug_context_t *context, char *file, int line, VALUE context_objec
|
|
311
313
|
rb_funcall(context_object, idAtLine, 2, rb_str_new2(file), INT2FIX(line));
|
312
314
|
}
|
313
315
|
|
316
|
+
int count_stack_size() {
|
317
|
+
rb_thread_t *thread = ruby_current_thread;
|
318
|
+
rb_control_frame_t *last_cfp = TH_CFP(thread);
|
319
|
+
rb_control_frame_t *start_cfp = RUBY_VM_END_CONTROL_FRAME(TH_INFO(thread));
|
320
|
+
rb_control_frame_t *cfp;
|
321
|
+
|
322
|
+
ptrdiff_t size, i;
|
323
|
+
|
324
|
+
start_cfp =
|
325
|
+
RUBY_VM_NEXT_CONTROL_FRAME(
|
326
|
+
RUBY_VM_NEXT_CONTROL_FRAME(start_cfp)); /* skip top frames */
|
327
|
+
|
328
|
+
if (start_cfp < last_cfp) {
|
329
|
+
size = 0;
|
330
|
+
}
|
331
|
+
else {
|
332
|
+
size = start_cfp - last_cfp + 1;
|
333
|
+
}
|
334
|
+
|
335
|
+
int stack_size = 0;
|
336
|
+
for (i=0, cfp = start_cfp; i<size; i++, cfp = RUBY_VM_NEXT_CONTROL_FRAME(cfp)) {
|
337
|
+
if (cfp->iseq && cfp->pc) {
|
338
|
+
stack_size++;
|
339
|
+
}
|
340
|
+
}
|
341
|
+
|
342
|
+
return stack_size;
|
343
|
+
}
|
344
|
+
|
314
345
|
static void
|
315
346
|
process_line_event(VALUE trace_point, void *data)
|
316
347
|
{
|
@@ -323,7 +354,6 @@ process_line_event(VALUE trace_point, void *data)
|
|
323
354
|
char *file;
|
324
355
|
int line;
|
325
356
|
int moved;
|
326
|
-
int not_user_code = 0;
|
327
357
|
|
328
358
|
context_object = Debase_current_context(mDebase);
|
329
359
|
Data_Get_Struct(context_object, debug_context_t, context);
|
@@ -338,19 +368,14 @@ process_line_event(VALUE trace_point, void *data)
|
|
338
368
|
file = RSTRING_PTR(path);
|
339
369
|
line = FIX2INT(lineno);
|
340
370
|
|
341
|
-
int i;
|
342
|
-
if(context->calced_stack_size < context->init_stack_size) {
|
343
|
-
for(i = 0; i < context->init_stack_size; i++)
|
344
|
-
{
|
345
|
-
if(strcmp(file, context->init_stack_files[i]) == 0) {
|
346
|
-
not_user_code = 1;
|
347
|
-
}
|
348
|
-
}
|
349
|
-
}
|
350
|
-
|
351
371
|
update_stack_size(context);
|
352
372
|
print_event(tp, context);
|
353
373
|
|
374
|
+
if(context->init_stack_size == -1) {
|
375
|
+
context->stack_size = count_stack_size();
|
376
|
+
context->init_stack_size = context->stack_size;
|
377
|
+
}
|
378
|
+
|
354
379
|
if (context->thread_pause) {
|
355
380
|
context->stop_next = 1;
|
356
381
|
context->dest_frame = -1;
|
@@ -384,15 +409,20 @@ process_line_event(VALUE trace_point, void *data)
|
|
384
409
|
}
|
385
410
|
|
386
411
|
breakpoint = breakpoint_find(breakpoints, path, lineno, trace_point);
|
387
|
-
if (
|
412
|
+
if (context->stop_next == 0 || context->stop_line == 0 || breakpoint != Qnil) {
|
388
413
|
rb_ensure(start_inspector, context_object, stop_inspector, Qnil);
|
389
|
-
context->
|
390
|
-
|
391
|
-
|
392
|
-
|
414
|
+
if(context->stack_size <= context->init_stack_size && context->hit_user_code) {
|
415
|
+
context->script_finished = 1;
|
416
|
+
}
|
417
|
+
if(!context->script_finished) {
|
418
|
+
context->stop_reason = CTX_STOP_STEP;
|
419
|
+
if (breakpoint != Qnil) {
|
420
|
+
context->stop_reason = CTX_STOP_BREAKPOINT;
|
421
|
+
rb_funcall(context_object, idAtBreakpoint, 1, breakpoint);
|
422
|
+
}
|
423
|
+
reset_stepping_stop_points(context);
|
424
|
+
call_at_line(context, file, line, context_object);
|
393
425
|
}
|
394
|
-
reset_stepping_stop_points(context);
|
395
|
-
call_at_line(context, file, line, context_object);
|
396
426
|
}
|
397
427
|
}
|
398
428
|
cleanup(context);
|
@@ -648,6 +678,50 @@ Debase_enable_file_filtering(VALUE self, VALUE value)
|
|
648
678
|
return value;
|
649
679
|
}
|
650
680
|
|
681
|
+
#if RUBY_API_VERSION_CODE >= 20500 && RUBY_API_VERSION_CODE < 20600 && !(RUBY_RELEASE_YEAR == 2017 && RUBY_RELEASE_MONTH == 10 && RUBY_RELEASE_DAY == 10)
|
682
|
+
static const rb_iseq_t *
|
683
|
+
my_iseqw_check(VALUE iseqw)
|
684
|
+
{
|
685
|
+
rb_iseq_t *iseq = DATA_PTR(iseqw);
|
686
|
+
|
687
|
+
if (!iseq->body) {
|
688
|
+
return NULL;
|
689
|
+
}
|
690
|
+
|
691
|
+
return iseq;
|
692
|
+
}
|
693
|
+
|
694
|
+
static void
|
695
|
+
Debase_set_trace_flag_to_iseq(VALUE self, VALUE rb_iseq) {
|
696
|
+
if (!SPECIAL_CONST_P(rb_iseq) && RBASIC_CLASS(rb_iseq) == rb_cISeq) {
|
697
|
+
rb_iseq_t *iseq = my_iseqw_check(rb_iseq);
|
698
|
+
|
699
|
+
if(iseq) {
|
700
|
+
rb_iseq_trace_set(iseq, RUBY_EVENT_TRACEPOINT_ALL);
|
701
|
+
}
|
702
|
+
}
|
703
|
+
}
|
704
|
+
|
705
|
+
static void
|
706
|
+
Debase_unset_trace_flags(VALUE self, VALUE rb_iseq) {
|
707
|
+
if (!SPECIAL_CONST_P(rb_iseq) && RBASIC_CLASS(rb_iseq) == rb_cISeq) {
|
708
|
+
rb_iseq_t *iseq = my_iseqw_check(rb_iseq);
|
709
|
+
|
710
|
+
if(iseq) {
|
711
|
+
rb_iseq_trace_set(iseq, RUBY_EVENT_NONE);
|
712
|
+
}
|
713
|
+
}
|
714
|
+
}
|
715
|
+
#else
|
716
|
+
static void
|
717
|
+
Debase_set_trace_flag_to_iseq(VALUE self, VALUE rb_iseq) {
|
718
|
+
}
|
719
|
+
|
720
|
+
static void
|
721
|
+
Debase_unset_trace_flags(VALUE self, VALUE rb_iseq) {
|
722
|
+
}
|
723
|
+
#endif
|
724
|
+
|
651
725
|
static VALUE
|
652
726
|
Debase_init_variables()
|
653
727
|
{
|
@@ -691,6 +765,10 @@ Init_debase_internals()
|
|
691
765
|
rb_define_module_function(mDebase, "enable_trace_points", Debase_enable_trace_points, 0);
|
692
766
|
rb_define_module_function(mDebase, "prepare_context", Debase_prepare_context, 0);
|
693
767
|
rb_define_module_function(mDebase, "init_variables", Debase_init_variables, 0);
|
768
|
+
rb_define_module_function(mDebase, "set_trace_flag_to_iseq", Debase_set_trace_flag_to_iseq, 1);
|
769
|
+
|
770
|
+
//use only for tests
|
771
|
+
rb_define_module_function(mDebase, "unset_iseq_flags", Debase_unset_trace_flags, 1);
|
694
772
|
|
695
773
|
idAlive = rb_intern("alive?");
|
696
774
|
idAtLine = rb_intern("at_line");
|
data/ext/debase_internals.h
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
#ifndef DEBASE_INTERNALS
|
2
2
|
#define DEBASE_INTERNALS
|
3
3
|
|
4
|
-
#include
|
5
|
-
#include
|
4
|
+
#include "ruby.h"
|
5
|
+
#include "ruby/debug.h"
|
6
6
|
|
7
7
|
typedef struct rb_trace_arg_struct rb_trace_point_t;
|
8
8
|
|
@@ -57,12 +57,12 @@ typedef struct debug_context {
|
|
57
57
|
/* dest_frame uses calced_stack_size for stepping */
|
58
58
|
int dest_frame;
|
59
59
|
int calced_stack_size;
|
60
|
-
int init_stack_size;
|
61
|
-
|
62
|
-
char **init_stack_files;
|
63
60
|
|
64
61
|
char *last_file;
|
65
62
|
int last_line;
|
63
|
+
int init_stack_size;
|
64
|
+
int script_finished;
|
65
|
+
int hit_user_code;
|
66
66
|
} debug_context_t;
|
67
67
|
|
68
68
|
typedef struct
|
data/ext/extconf.rb
CHANGED
@@ -28,8 +28,13 @@ RbConfig::MAKEFILE_CONFIG['CC'] = ENV['CC'] if ENV['CC']
|
|
28
28
|
require "debase/ruby_core_source"
|
29
29
|
|
30
30
|
hdrs = proc {
|
31
|
-
have_header("vm_core.h")
|
32
|
-
have_header("
|
31
|
+
have_header("vm_core.h") and
|
32
|
+
have_header("iseq.h") and
|
33
|
+
have_header("version.h") and
|
34
|
+
have_header("vm_core.h") and
|
35
|
+
have_header("vm_insnhelper.h") and
|
36
|
+
have_header("vm_core.h") and
|
37
|
+
have_header("method.h")
|
33
38
|
}
|
34
39
|
|
35
40
|
# Allow use customization of compile options. For example, the
|
data/lib/debase.rb
CHANGED
@@ -20,7 +20,21 @@ module Debase
|
|
20
20
|
Debugger.const_set('ARGV', ARGV.clone) unless defined? Debugger::ARGV
|
21
21
|
Debugger.const_set('PROG_SCRIPT', $0) unless defined? Debugger::PROG_SCRIPT
|
22
22
|
Debugger.const_set('INITIAL_DIR', Dir.pwd) unless defined? Debugger::INITIAL_DIR
|
23
|
-
|
23
|
+
|
24
|
+
monkey_patch_prepend
|
25
|
+
|
26
|
+
Debugger.started? ? block && block.call(self) : Debugger.start_(&block)
|
27
|
+
end
|
28
|
+
|
29
|
+
def monkey_patch_prepend
|
30
|
+
class << RubyVM::InstructionSequence
|
31
|
+
def self.prepend(mod, *smth)
|
32
|
+
super
|
33
|
+
if mod.to_s.include?('Bootsnap') && RUBY_VERSION >= '2.5' && RUBY_VERSION < '2.6'
|
34
|
+
prepend InstructionSequenceMixin
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
24
38
|
end
|
25
39
|
|
26
40
|
# @param [String] file
|
@@ -81,6 +95,21 @@ module Debase
|
|
81
95
|
def file_filter
|
82
96
|
@file_filter ||= FileFilter.new
|
83
97
|
end
|
98
|
+
|
99
|
+
module InstructionSequenceMixin
|
100
|
+
def load_iseq(path)
|
101
|
+
iseq = super(path)
|
102
|
+
|
103
|
+
do_set_flags(iseq)
|
104
|
+
|
105
|
+
iseq
|
106
|
+
end
|
107
|
+
|
108
|
+
def do_set_flags(iseq)
|
109
|
+
Debugger.set_trace_flag_to_iseq(iseq)
|
110
|
+
iseq.each_child { |child_iseq| do_set_flags(child_iseq) } if iseq.respond_to? :each_child
|
111
|
+
end
|
112
|
+
end
|
84
113
|
end
|
85
114
|
|
86
115
|
class FileFilter
|
data/lib/debase/version.rb
CHANGED
data/test/test_load.rb
CHANGED
@@ -3,6 +3,9 @@ require File.expand_path("helper", File.dirname(__FILE__))
|
|
3
3
|
|
4
4
|
# Test of Debugger.debug_load in C extension ruby_debug.so
|
5
5
|
class TestDebugLoad < Test::Unit::TestCase
|
6
|
+
|
7
|
+
self.test_order = :defined
|
8
|
+
|
6
9
|
class << self
|
7
10
|
def at_line(file, line)
|
8
11
|
@@at_line = [File.basename(file), line]
|
@@ -41,4 +44,35 @@ class TestDebugLoad < Test::Unit::TestCase
|
|
41
44
|
ensure
|
42
45
|
Debugger.stop if Debugger.started?
|
43
46
|
end
|
47
|
+
|
48
|
+
module MyBootsnap
|
49
|
+
def load_iseq(path)
|
50
|
+
iseq = RubyVM::InstructionSequence.compile_file(path)
|
51
|
+
|
52
|
+
Debugger.unset_iseq_flags(iseq)
|
53
|
+
iseq
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_bootsnap
|
58
|
+
@@at_line = nil
|
59
|
+
src_dir = File.dirname(__FILE__)
|
60
|
+
prog_script = File.join(src_dir, 'example', 'bootsnap', 'bootsnap.rb')
|
61
|
+
|
62
|
+
class << RubyVM::InstructionSequence
|
63
|
+
prepend MyBootsnap
|
64
|
+
end
|
65
|
+
bt = Debugger.debug_load(prog_script, true)
|
66
|
+
assert_equal(nil, bt)
|
67
|
+
assert_not_nil(@@at_line)
|
68
|
+
if RUBY_VERSION >= '2.5' && RUBY_VERSION < '2.6'
|
69
|
+
assert_equal(['debase.rb', 101], @@at_line)
|
70
|
+
end
|
71
|
+
|
72
|
+
assert(Debugger.started?)
|
73
|
+
Debugger.stop
|
74
|
+
|
75
|
+
class << RubyVM::InstructionSequence; self end.class_eval { undef_method :load_iseq }
|
76
|
+
|
77
|
+
end
|
44
78
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: debase
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.4.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dennis Ushakov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-09-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: debase-ruby_core_source
|
@@ -94,6 +94,8 @@ files:
|
|
94
94
|
- test/example/a/example.rb
|
95
95
|
- test/example/at-exit.rb
|
96
96
|
- test/example/b/example.rb
|
97
|
+
- test/example/bootsnap/a.rb
|
98
|
+
- test/example/bootsnap/bootsnap.rb
|
97
99
|
- test/example/bp_loop_issue.rb
|
98
100
|
- test/example/breakpoints-basename.rb
|
99
101
|
- test/example/brkpt-class-bug.rb
|
@@ -134,8 +136,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
134
136
|
- !ruby/object:Gem::Version
|
135
137
|
version: '0'
|
136
138
|
requirements: []
|
137
|
-
|
138
|
-
rubygems_version: 2.6.10
|
139
|
+
rubygems_version: 3.0.3
|
139
140
|
signing_key:
|
140
141
|
specification_version: 4
|
141
142
|
summary: debase is a fast implementation of the standard Ruby debugger debug.rb for
|