debase 0.2.2 → 0.2.4.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.
- 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
|