diff --git a/ext/debase_internals.c b/ext/debase_internals.c index 20670d9..896e63b 100644 --- a/ext/debase_internals.c +++ b/ext/debase_internals.c @@ -637,6 +637,50 @@ Debase_enable_file_filtering(VALUE self, VALUE value) return value; } +#if RUBY_API_VERSION_CODE >= 20500 && RUBY_API_VERSION_CODE < 20600 && !(RUBY_RELEASE_YEAR == 2017 && RUBY_RELEASE_MONTH == 10 && RUBY_RELEASE_DAY == 10) + static const rb_iseq_t * + my_iseqw_check(VALUE iseqw) + { + rb_iseq_t *iseq = DATA_PTR(iseqw); + + if (!iseq->body) { + return NULL; + } + + return iseq; + } + + static void + Debase_set_trace_flag_to_iseq(VALUE self, VALUE rb_iseq) { + if (!SPECIAL_CONST_P(rb_iseq) && RBASIC_CLASS(rb_iseq) == rb_cISeq) { + rb_iseq_t *iseq = my_iseqw_check(rb_iseq); + + if(iseq) { + rb_iseq_trace_set(iseq, RUBY_EVENT_TRACEPOINT_ALL); + } + } + } + + static void + Debase_unset_trace_flags(VALUE self, VALUE rb_iseq) { + if (!SPECIAL_CONST_P(rb_iseq) && RBASIC_CLASS(rb_iseq) == rb_cISeq) { + rb_iseq_t *iseq = my_iseqw_check(rb_iseq); + + if(iseq) { + rb_iseq_trace_set(iseq, RUBY_EVENT_NONE); + } + } + } +#else + static void + Debase_set_trace_flag_to_iseq(VALUE self, VALUE rb_iseq) { + } + + static void + Debase_unset_trace_flags(VALUE self, VALUE rb_iseq) { + } +#endif + static VALUE Debase_init_variables() { @@ -680,6 +724,10 @@ Init_debase_internals() rb_define_module_function(mDebase, "enable_trace_points", Debase_enable_trace_points, 0); rb_define_module_function(mDebase, "prepare_context", Debase_prepare_context, 0); rb_define_module_function(mDebase, "init_variables", Debase_init_variables, 0); + rb_define_module_function(mDebase, "set_trace_flag_to_iseq", Debase_set_trace_flag_to_iseq, 1); + + //use only for tests + rb_define_module_function(mDebase, "unset_iseq_flags", Debase_unset_trace_flags, 1); idAlive = rb_intern("alive?"); idAtLine = rb_intern("at_line"); diff --git a/lib/debase.rb b/lib/debase.rb index f15a1a6..4459835 100644 --- a/lib/debase.rb +++ b/lib/debase.rb @@ -21,9 +21,22 @@ def start(options={}, &block) Debugger.const_set('PROG_SCRIPT', $0) unless defined? Debugger::PROG_SCRIPT Debugger.const_set('INITIAL_DIR', Dir.pwd) unless defined? Debugger::INITIAL_DIR + monkey_patch_prepend + Debugger.started? ? block && block.call(self) : Debugger.start_(&block) end + def monkey_patch_prepend + class << RubyVM::InstructionSequence + def self.prepend(mod, *smth) + super + if mod.to_s.include?('Bootsnap') && RUBY_VERSION >= '2.5' && RUBY_VERSION < '2.6' + prepend InstructionSequenceMixin + end + end + end + end + # @param [String] file # @param [Fixnum] line # @param [String] expr @@ -82,6 +95,21 @@ def last_context def file_filter @file_filter ||= FileFilter.new end + + module InstructionSequenceMixin + def load_iseq(path) + iseq = super(path) + + do_set_flags(iseq) + + iseq + end + + def do_set_flags(iseq) + Debugger.set_trace_flag_to_iseq(iseq) + iseq.each_child { |child_iseq| do_set_flags(child_iseq) } if iseq.respond_to? :each_child + end + end end class FileFilter diff --git a/lib/debase/version.rb b/lib/debase/version.rb index 3d99717..757ad80 100644 --- a/lib/debase/version.rb +++ b/lib/debase/version.rb @@ -1,3 +1,3 @@ module Debase - VERSION = "0.2.3.beta4" unless defined? VERSION + VERSION = "0.2.3.beta5" unless defined? VERSION end diff --git a/test/test_load.rb b/test/test_load.rb index 60e3de7..ed04a32 100644 --- a/test/test_load.rb +++ b/test/test_load.rb @@ -44,4 +44,35 @@ def test_debug_load ensure Debugger.stop if Debugger.started? end + + module MyBootsnap + def load_iseq(path) + iseq = RubyVM::InstructionSequence.compile_file(path) + + Debugger.unset_iseq_flags(iseq) + iseq + end + end + + def test_bootsnap + @@at_line = nil + src_dir = File.dirname(__FILE__) + prog_script = File.join(src_dir, 'example', 'bootsnap', 'bootsnap.rb') + + class << RubyVM::InstructionSequence + prepend MyBootsnap + end + bt = Debugger.debug_load(prog_script, true) + assert_equal(nil, bt) + assert_not_nil(@@at_line) + if RUBY_VERSION >= '2.5' && RUBY_VERSION < '2.6' + assert_equal(['debase.rb', 101], @@at_line) + end + + assert(Debugger.started?) + Debugger.stop + + class << RubyVM::InstructionSequence; self end.class_eval { undef_method :load_iseq } + + end end