readapt 0.3.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 +7 -0
- data/.gitignore +14 -0
- data/.rspec +3 -0
- data/.travis.yml +13 -0
- data/CHANGELOG.md +15 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +29 -0
- data/Rakefile +25 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/exe/readapt +5 -0
- data/ext/readapt/extconf.rb +3 -0
- data/ext/readapt/monitor.c +332 -0
- data/ext/readapt/monitor.h +1 -0
- data/ext/readapt/readapt.c +12 -0
- data/ext/readapt/threads.c +101 -0
- data/ext/readapt/threads.h +18 -0
- data/lib/readapt.rb +34 -0
- data/lib/readapt/adapter.rb +138 -0
- data/lib/readapt/breakpoint.rb +16 -0
- data/lib/readapt/breakpoints.rb +58 -0
- data/lib/readapt/debugger.rb +173 -0
- data/lib/readapt/finder.rb +20 -0
- data/lib/readapt/frame.rb +68 -0
- data/lib/readapt/location.rb +25 -0
- data/lib/readapt/message.rb +57 -0
- data/lib/readapt/message/attach.rb +11 -0
- data/lib/readapt/message/base.rb +32 -0
- data/lib/readapt/message/configuration_done.rb +11 -0
- data/lib/readapt/message/continue.rb +15 -0
- data/lib/readapt/message/disconnect.rb +14 -0
- data/lib/readapt/message/initialize.rb +13 -0
- data/lib/readapt/message/launch.rb +11 -0
- data/lib/readapt/message/next.rb +12 -0
- data/lib/readapt/message/pause.rb +11 -0
- data/lib/readapt/message/scopes.rb +25 -0
- data/lib/readapt/message/set_breakpoints.rb +26 -0
- data/lib/readapt/message/set_exception_breakpoints.rb +8 -0
- data/lib/readapt/message/stack_trace.rb +26 -0
- data/lib/readapt/message/step_in.rb +11 -0
- data/lib/readapt/message/step_out.rb +11 -0
- data/lib/readapt/message/threads.rb +18 -0
- data/lib/readapt/message/variables.rb +57 -0
- data/lib/readapt/monitor.rb +31 -0
- data/lib/readapt/shell.rb +48 -0
- data/lib/readapt/snapshot.rb +50 -0
- data/lib/readapt/thread.rb +39 -0
- data/lib/readapt/variable.rb +70 -0
- data/lib/readapt/version.rb +3 -0
- data/readapt.gemspec +39 -0
- metadata +184 -0
| @@ -0,0 +1,20 @@ | |
| 1 | 
            +
            require 'pathname'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Readapt
         | 
| 4 | 
            +
              module Finder
         | 
| 5 | 
            +
                module_function
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                def find program
         | 
| 8 | 
            +
                  return program if File.exist?(program)
         | 
| 9 | 
            +
                  which(program) || raise(LoadError, "#{program} is not a valid Ruby file or program")
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                def which program
         | 
| 13 | 
            +
                  ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
         | 
| 14 | 
            +
                    exe = File.join(path, program)
         | 
| 15 | 
            +
                    return exe if File.file?(exe)
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
                  nil
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
              end
         | 
| 20 | 
            +
            end
         | 
| @@ -0,0 +1,68 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Readapt
         | 
| 4 | 
            +
              class Frame
         | 
| 5 | 
            +
                attr_reader :location
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                def initialize location, binding_id
         | 
| 8 | 
            +
                  @location = location
         | 
| 9 | 
            +
                  @binding = ObjectSpace._id2ref(binding_id)
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                def local_id
         | 
| 13 | 
            +
                  @binding.object_id
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                def locals
         | 
| 17 | 
            +
                  return [] if @binding.nil?
         | 
| 18 | 
            +
                  result = []
         | 
| 19 | 
            +
                  @binding.local_variables.each do |sym|
         | 
| 20 | 
            +
                    var = @binding.local_variable_get(sym)
         | 
| 21 | 
            +
                    result.push Variable.new(sym, var)
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
                  if @binding.receiver != TOPLEVEL_BINDING.receiver
         | 
| 24 | 
            +
                    result.push Variable.new(:self, @binding.receiver)
         | 
| 25 | 
            +
                  end
         | 
| 26 | 
            +
                  result
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                def variables
         | 
| 30 | 
            +
                  return [] if @binding.nil?
         | 
| 31 | 
            +
                  result = []
         | 
| 32 | 
            +
                  @binding.local_variables.each do |sym|
         | 
| 33 | 
            +
                    var = @binding.local_variable_get(sym)
         | 
| 34 | 
            +
                    result.push Variable.new(sym, var)
         | 
| 35 | 
            +
                  end
         | 
| 36 | 
            +
                  if @binding.receiver != TOPLEVEL_BINDING.receiver
         | 
| 37 | 
            +
                    @binding.instance_variables.each do |sym|
         | 
| 38 | 
            +
                      var = @binding.receiver.instance_variable_get(sym)
         | 
| 39 | 
            +
                      result.push Variable.new(sym, var)
         | 
| 40 | 
            +
                    end
         | 
| 41 | 
            +
                    @binding.class.class_variables.each do |sym|
         | 
| 42 | 
            +
                      var = @binding.receiver.class.class_variable_get(sym)
         | 
| 43 | 
            +
                      result.push Variable.new(sym, var)
         | 
| 44 | 
            +
                    end
         | 
| 45 | 
            +
                  end
         | 
| 46 | 
            +
                  result
         | 
| 47 | 
            +
                end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                def local sym
         | 
| 50 | 
            +
                  return @binding.receiver if sym == :self
         | 
| 51 | 
            +
                  @binding.local_variable_get sym
         | 
| 52 | 
            +
                end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                def globals
         | 
| 55 | 
            +
                  global_variables
         | 
| 56 | 
            +
                end
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                def global sym
         | 
| 59 | 
            +
                  global sym
         | 
| 60 | 
            +
                end
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                def evaluate code
         | 
| 63 | 
            +
                  @binding.eval code
         | 
| 64 | 
            +
                end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                NULL_FRAME = Frame.new(nil, nil.object_id)
         | 
| 67 | 
            +
              end
         | 
| 68 | 
            +
            end
         | 
| @@ -0,0 +1,25 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Readapt
         | 
| 4 | 
            +
              # A simple file/line reference.
         | 
| 5 | 
            +
              #
         | 
| 6 | 
            +
              class Location
         | 
| 7 | 
            +
                # @return [String]
         | 
| 8 | 
            +
                attr_reader :file
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                # @return [Integer]
         | 
| 11 | 
            +
                attr_reader :line
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                # @param file [String]
         | 
| 14 | 
            +
                # @param line [Integer]
         | 
| 15 | 
            +
                def initialize file, line
         | 
| 16 | 
            +
                  @file = file
         | 
| 17 | 
            +
                  @line = line
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                def match? other
         | 
| 21 | 
            +
                  return false unless other.is_a?(Location)
         | 
| 22 | 
            +
                  file == other.file && line == other.line
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
              end
         | 
| 25 | 
            +
            end
         | 
| @@ -0,0 +1,57 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'readapt/message/base'
         | 
| 4 | 
            +
            require 'readapt/message/initialize'
         | 
| 5 | 
            +
            require 'readapt/message/launch'
         | 
| 6 | 
            +
            require 'readapt/message/set_breakpoints'
         | 
| 7 | 
            +
            require 'readapt/message/set_exception_breakpoints'
         | 
| 8 | 
            +
            require 'readapt/message/configuration_done'
         | 
| 9 | 
            +
            require 'readapt/message/threads'
         | 
| 10 | 
            +
            require 'readapt/message/stack_trace'
         | 
| 11 | 
            +
            require 'readapt/message/scopes'
         | 
| 12 | 
            +
            require 'readapt/message/continue'
         | 
| 13 | 
            +
            require 'readapt/message/variables'
         | 
| 14 | 
            +
            require 'readapt/message/next'
         | 
| 15 | 
            +
            require 'readapt/message/step_in'
         | 
| 16 | 
            +
            require 'readapt/message/step_out'
         | 
| 17 | 
            +
            require 'readapt/message/disconnect'
         | 
| 18 | 
            +
            require 'readapt/message/attach'
         | 
| 19 | 
            +
            require 'readapt/message/pause'
         | 
| 20 | 
            +
             | 
| 21 | 
            +
            module Readapt
         | 
| 22 | 
            +
              module Message
         | 
| 23 | 
            +
                @@messages = {}
         | 
| 24 | 
            +
                @@seq = 0
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                def self.register name, klass
         | 
| 27 | 
            +
                  @@messages[name] = klass
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                def self.process arguments, debugger
         | 
| 31 | 
            +
                  message = @@messages[arguments['command']].new(arguments['arguments'], debugger)
         | 
| 32 | 
            +
                  message.run
         | 
| 33 | 
            +
                  message
         | 
| 34 | 
            +
                rescue Exception => e
         | 
| 35 | 
            +
                  STDERR.puts "Skipping error: #{e.message}"
         | 
| 36 | 
            +
                  STDERR.puts "Received: #{arguments}"
         | 
| 37 | 
            +
                  STDERR.puts e.backtrace
         | 
| 38 | 
            +
                end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                register 'initialize', Message::Initialize
         | 
| 41 | 
            +
                register 'attach', Message::Attach
         | 
| 42 | 
            +
                register 'launch', Message::Launch
         | 
| 43 | 
            +
                register 'setBreakpoints', Message::SetBreakpoints
         | 
| 44 | 
            +
                register 'setExceptionBreakpoints', Message::SetExceptionBreakpoints
         | 
| 45 | 
            +
                register 'configurationDone', Message::ConfigurationDone
         | 
| 46 | 
            +
                register 'threads', Message::Threads
         | 
| 47 | 
            +
                register 'stackTrace', Message::StackTrace
         | 
| 48 | 
            +
                register 'scopes', Message::Scopes
         | 
| 49 | 
            +
                register 'continue', Message::Continue
         | 
| 50 | 
            +
                register 'variables', Message::Variables
         | 
| 51 | 
            +
                register 'next', Message::Next
         | 
| 52 | 
            +
                register 'stepIn', Message::StepIn
         | 
| 53 | 
            +
                register 'stepOut', Message::StepOut
         | 
| 54 | 
            +
                register 'disconnect', Message::Disconnect
         | 
| 55 | 
            +
                register 'pause', Message::Pause
         | 
| 56 | 
            +
              end
         | 
| 57 | 
            +
            end
         | 
| @@ -0,0 +1,32 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Readapt
         | 
| 4 | 
            +
              module Message
         | 
| 5 | 
            +
                class Base
         | 
| 6 | 
            +
                  # @return [Hash]
         | 
| 7 | 
            +
                  attr_reader :arguments
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                  # @return [Debugger]
         | 
| 10 | 
            +
                  attr_reader :debugger
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                  def initialize arguments, debugger
         | 
| 13 | 
            +
                    @arguments = arguments
         | 
| 14 | 
            +
                    @debugger = debugger
         | 
| 15 | 
            +
                  end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  def run; end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                  def body
         | 
| 20 | 
            +
                    @body ||= {}
         | 
| 21 | 
            +
                  end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                  def set_body hash
         | 
| 24 | 
            +
                    @body = hash
         | 
| 25 | 
            +
                  end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                  def self.run arguments, debugger
         | 
| 28 | 
            +
                    new(arguments, debugger).run
         | 
| 29 | 
            +
                  end
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
              end
         | 
| 32 | 
            +
            end
         | 
| @@ -0,0 +1,15 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Readapt
         | 
| 4 | 
            +
              module Message
         | 
| 5 | 
            +
                class Continue < Base
         | 
| 6 | 
            +
                  def run
         | 
| 7 | 
            +
                    thread = debugger.thread(arguments['threadId'])
         | 
| 8 | 
            +
                    thread.control = :continue
         | 
| 9 | 
            +
                    set_body({
         | 
| 10 | 
            +
                      allThreadsContinued: false
         | 
| 11 | 
            +
                    })
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
            end
         | 
| @@ -0,0 +1,25 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Readapt
         | 
| 4 | 
            +
              module Message
         | 
| 5 | 
            +
                class Scopes < Base
         | 
| 6 | 
            +
                  def run
         | 
| 7 | 
            +
                    frame = debugger.frame(arguments['frameId'])
         | 
| 8 | 
            +
                    set_body({
         | 
| 9 | 
            +
                      scopes: [
         | 
| 10 | 
            +
                        {
         | 
| 11 | 
            +
                          name: 'Local',
         | 
| 12 | 
            +
                          variablesReference: frame.local_id,
         | 
| 13 | 
            +
                          expensive: false
         | 
| 14 | 
            +
                        },
         | 
| 15 | 
            +
                        {
         | 
| 16 | 
            +
                          name: 'Global',
         | 
| 17 | 
            +
                          variablesReference: TOPLEVEL_BINDING.receiver.object_id,
         | 
| 18 | 
            +
                          expensive: true
         | 
| 19 | 
            +
                        }
         | 
| 20 | 
            +
                      ]
         | 
| 21 | 
            +
                    })
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
              end
         | 
| 25 | 
            +
            end
         | 
| @@ -0,0 +1,26 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Readapt
         | 
| 4 | 
            +
              module Message
         | 
| 5 | 
            +
                class SetBreakpoints < Base
         | 
| 6 | 
            +
                  def run
         | 
| 7 | 
            +
                    path = Readapt.normalize_path(arguments['source']['path'])
         | 
| 8 | 
            +
                    Monitor.breakpoints.clear path
         | 
| 9 | 
            +
                    result = arguments['lines'].map do |l|
         | 
| 10 | 
            +
                      # @todo Assuming breakpoints are verified
         | 
| 11 | 
            +
                      Breakpoint.new(path, l, true)
         | 
| 12 | 
            +
                    end
         | 
| 13 | 
            +
                    Monitor.breakpoints.concat result
         | 
| 14 | 
            +
                    set_body({
         | 
| 15 | 
            +
                      breakpoints: result.map { |bp|
         | 
| 16 | 
            +
                        {
         | 
| 17 | 
            +
                          verified: bp.verified,
         | 
| 18 | 
            +
                          source: arguments['source'],
         | 
| 19 | 
            +
                          line: bp.line
         | 
| 20 | 
            +
                        }
         | 
| 21 | 
            +
                      }
         | 
| 22 | 
            +
                    })
         | 
| 23 | 
            +
                  end
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
              end
         | 
| 26 | 
            +
            end
         | 
| @@ -0,0 +1,26 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Readapt
         | 
| 4 | 
            +
              module Message
         | 
| 5 | 
            +
                class StackTrace < Base
         | 
| 6 | 
            +
                  def run
         | 
| 7 | 
            +
                    frames = debugger.thread(arguments['threadId']).frames
         | 
| 8 | 
            +
                    set_body({
         | 
| 9 | 
            +
                      stackFrames: frames.map do |frm|
         | 
| 10 | 
            +
                        {
         | 
| 11 | 
            +
                          name: "#{File.basename(frm.location.file)}:#{frm.location.line}",
         | 
| 12 | 
            +
                          source: {
         | 
| 13 | 
            +
                            name: File.basename(frm.location.file),
         | 
| 14 | 
            +
                            path: frm.location.file
         | 
| 15 | 
            +
                          },
         | 
| 16 | 
            +
                          id: frm.local_id,
         | 
| 17 | 
            +
                          line: frm.location.line,
         | 
| 18 | 
            +
                          column: 0
         | 
| 19 | 
            +
                        }
         | 
| 20 | 
            +
                      end,
         | 
| 21 | 
            +
                      totalFrames: frames.length
         | 
| 22 | 
            +
                    })
         | 
| 23 | 
            +
                  end
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
              end
         | 
| 26 | 
            +
            end
         |