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
|