trepanning 0.0.9 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (108) hide show
  1. data/ChangeLog +237 -0
  2. data/NEWS +8 -0
  3. data/Rakefile +3 -2
  4. data/app/breakpoint.rb +8 -8
  5. data/app/brkptmgr.rb +86 -85
  6. data/app/client.rb +60 -0
  7. data/app/core.rb-consider +198 -0
  8. data/app/default.rb +17 -7
  9. data/app/disassemble.rb +12 -2
  10. data/app/options.rb +51 -20
  11. data/app/yarv.rb +183 -0
  12. data/bin/trepan +15 -9
  13. data/data/custom_require.rb +44 -0
  14. data/data/irbrc +41 -0
  15. data/data/prelude.rb +38 -0
  16. data/interface/base_intf.rb +10 -4
  17. data/interface/client.rb +79 -0
  18. data/interface/comcodes.rb +18 -0
  19. data/interface/server.rb +142 -0
  20. data/io/base_io.rb +57 -3
  21. data/io/tcpclient.rb +122 -0
  22. data/io/tcpfns.rb +31 -0
  23. data/io/tcpserver.rb +137 -0
  24. data/lib/trepanning.rb +57 -28
  25. data/processor/command/base/cmd.rb +10 -6
  26. data/processor/command/base/subcmd.rb +13 -1
  27. data/processor/command/directory.rb +15 -8
  28. data/processor/command/disassemble.rb +3 -2
  29. data/processor/command/help.rb +71 -19
  30. data/processor/command/info_subcmd/args.rb +2 -3
  31. data/processor/command/info_subcmd/breakpoints.rb +2 -3
  32. data/processor/command/info_subcmd/file.rb +2 -3
  33. data/processor/command/info_subcmd/frame.rb +2 -3
  34. data/processor/command/info_subcmd/iseq.rb +4 -5
  35. data/processor/command/info_subcmd/locals.rb +2 -3
  36. data/processor/command/info_subcmd/program.rb +2 -3
  37. data/processor/command/info_subcmd/registers.rb +2 -3
  38. data/processor/command/info_subcmd/return.rb +2 -3
  39. data/processor/command/info_subcmd/thread.rb +2 -3
  40. data/processor/command/list.rb +10 -6
  41. data/processor/command/reload.rb +1 -1
  42. data/processor/command/reload_subcmd/command.rb +29 -16
  43. data/processor/command/server.rb +70 -0
  44. data/processor/command/set_subcmd/auto.rb +2 -3
  45. data/processor/command/set_subcmd/basename.rb +2 -3
  46. data/processor/command/set_subcmd/debug.rb +2 -3
  47. data/processor/command/set_subcmd/different.rb +2 -3
  48. data/processor/command/set_subcmd/events.rb +2 -3
  49. data/processor/command/set_subcmd/hidelevel.rb +6 -7
  50. data/processor/command/set_subcmd/highlight.rb +32 -0
  51. data/processor/command/set_subcmd/max.rb +2 -3
  52. data/processor/command/set_subcmd/return.rb +2 -3
  53. data/processor/command/set_subcmd/sp.rb +2 -3
  54. data/processor/command/set_subcmd/substitute.rb +2 -3
  55. data/processor/command/set_subcmd/timer.rb +2 -3
  56. data/processor/command/set_subcmd/trace.rb +3 -4
  57. data/processor/command/show_subcmd/alias.rb +3 -3
  58. data/processor/command/show_subcmd/args.rb +2 -3
  59. data/processor/command/show_subcmd/auto.rb +1 -2
  60. data/processor/command/show_subcmd/basename.rb +2 -3
  61. data/processor/command/show_subcmd/debug.rb +1 -2
  62. data/processor/command/show_subcmd/different.rb +2 -1
  63. data/processor/command/show_subcmd/events.rb +2 -2
  64. data/processor/command/show_subcmd/hidelevel.rb +2 -3
  65. data/processor/command/show_subcmd/highlight.rb +23 -0
  66. data/processor/command/show_subcmd/macro.rb +2 -1
  67. data/processor/command/show_subcmd/max.rb +2 -3
  68. data/processor/command/show_subcmd/trace.rb +2 -3
  69. data/processor/command/source.rb +78 -28
  70. data/processor/default.rb +3 -2
  71. data/processor/load_cmds.rb +39 -19
  72. data/processor/location.rb +11 -7
  73. data/processor/main.rb +31 -15
  74. data/processor/mock.rb +22 -7
  75. data/processor/msg.rb +24 -8
  76. data/test/data/fname-with-blank.right +3 -0
  77. data/test/data/quit.right +2 -0
  78. data/test/functional/test-break-long.rb +87 -0
  79. data/test/functional/tmp/b3.rb +5 -0
  80. data/test/functional/tmp/immediate-bug1.rb +9 -0
  81. data/test/integration/helper.rb +14 -11
  82. data/test/integration/test-fname-with-blank.rb +5 -1
  83. data/test/integration/test-quit.rb +6 -2
  84. data/test/unit/cmd-helper.rb +9 -4
  85. data/test/unit/mock-helper.rb +9 -0
  86. data/test/unit/test-app-brkpt.rb +4 -4
  87. data/test/unit/test-app-brkptmgr.rb +2 -2
  88. data/test/unit/test-app-file.rb +0 -1
  89. data/test/unit/test-app-options.rb +26 -5
  90. data/test/unit/test-base-subcmd.rb +0 -1
  91. data/test/unit/test-cmd-alias.rb +0 -1
  92. data/test/unit/test-cmd-break.rb +0 -4
  93. data/test/unit/test-cmd-endisable.rb +1 -3
  94. data/test/unit/test-cmd-help.rb +0 -1
  95. data/test/unit/test-cmd-kill.rb +4 -5
  96. data/test/unit/test-cmd-quit.rb +4 -7
  97. data/test/unit/test-cmd-source.rb +33 -0
  98. data/test/unit/test-cmd-step.rb +0 -2
  99. data/test/unit/test-io-tcp.rb +32 -0
  100. data/test/unit/test-io-tcpclient.rb +53 -0
  101. data/test/unit/test-io-tcpserver.rb +49 -0
  102. data/test/unit/test-proc-main.rb +2 -2
  103. metadata +195 -175
  104. data/processor/command/stepi.rb +0 -63
  105. data/test/functional/tmp/b1.rb +0 -5
  106. data/test/functional/tmp/s1.rb +0 -9
  107. data/test/functional/tmp/t2.rb +0 -6
  108. data/test/integration/try-test-enable.rb +0 -11
@@ -0,0 +1,18 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright (C) 2011 Rocky Bernstein <rockyb@rubyforge.net>
3
+
4
+ # Communication status codes
5
+ module Trepanning
6
+ # Most of these go from debugged process to front-end
7
+ # client interface. COMMAND goes the other way.
8
+ module RemoteCommunication
9
+ PRINT = '.'
10
+ COMMAND = 'C'
11
+ CONFIRM_TRUE = 'Y'
12
+ CONFIRM_FALSE = 'N'
13
+ CONFIRM_REPLY = '?'
14
+ QUIT = 'q'
15
+ PROMPT = 'p'
16
+ RESTART = 'r'
17
+ end
18
+ end
@@ -0,0 +1,142 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright (C) 2011 Rocky Bernstein <rockyb@rubyforge.net>
3
+
4
+ # Our local modules
5
+ require_relative 'base_intf'
6
+ require_relative 'comcodes'
7
+ require_relative '../io/input'
8
+ require_relative '../io/tcpserver'
9
+
10
+ # Mfifoserver = import_relative('fifoserver', '..io', 'pydbgr')
11
+
12
+ # Interface for debugging a program but having user control
13
+ # reside outside of the debugged process, possibly on another
14
+ # computer
15
+ class Trepan::ServerInterface < Trepan::Interface
16
+
17
+ include Trepanning::RemoteCommunication
18
+
19
+ DEFAULT_INIT_CONNECTION_OPTS = {
20
+ :io => 'TCP'
21
+ } unless defined?(DEFAULT_INIT_CONNECTION_OPTS)
22
+
23
+ def initialize(inout=nil, out=nil, connection_opts={})
24
+
25
+ @connection_opts = DEFAULT_INIT_CONNECTION_OPTS.merge(connection_opts)
26
+
27
+ at_exit { finalize }
28
+ @inout =
29
+ if inout
30
+ inout
31
+ else
32
+ server_type = @connection_opts[:io]
33
+ # FIXME: complete this.
34
+ # if 'FIFO' == server_type
35
+ # FIFOServer.new
36
+ # else
37
+ Trepan::TCPDbgServer.new(@connection_opts)
38
+ # end
39
+ end
40
+ # For Compatability
41
+ @output = @inout
42
+ @input = @inout
43
+ @interactive = true # Or at least so we think initially
44
+ end
45
+
46
+ # Closes both input and output
47
+ def close
48
+ if @inout && @inout.connected?
49
+ @inout.write(QUIT + 'bye')
50
+ @inout.close
51
+ end
52
+ end
53
+
54
+ # Called when a dangerous action is about to be done to make sure
55
+ # it's okay. `prompt' is printed; user response is returned.
56
+ # FIXME: make common routine for this and user.rb
57
+ def confirm(prompt, default)
58
+ while true
59
+ begin
60
+ write_confirm(prompt, default)
61
+ reply = readline(nil).strip.downcase
62
+ rescue EOFError
63
+ return default
64
+ end
65
+ if YES.member?(reply)
66
+ return true
67
+ elsif NO.member?(reply)
68
+ return false
69
+ else
70
+ msg "Please answer 'yes' or 'no'. Try again."
71
+ end
72
+ end
73
+ return default
74
+ end
75
+
76
+ # Return true if we are connected
77
+ def connected?
78
+ :connected == @inout.state
79
+ end
80
+
81
+ # print exit annotation
82
+ def finalize(last_wishes=QUIT)
83
+ @inout.writeline(last_wishes) if connected?
84
+ close
85
+ end
86
+
87
+ def input_eof?
88
+ false
89
+ end
90
+
91
+ # used to write to a debugger that is connected to this
92
+ # server; `str' written will have a newline added to it
93
+ def msg(msg)
94
+ @inout.writeline(PRINT + msg)
95
+ end
96
+
97
+ # used to write to a debugger that is connected to this
98
+ # server; `str' written will not have a newline added to it
99
+ def msg_nocr(msg)
100
+ @inout.write(PRINT + msg)
101
+ end
102
+
103
+ def read_command(prompt)
104
+ readline(prompt)
105
+ end
106
+
107
+ def read_data
108
+ @inout.read_dat
109
+ end
110
+
111
+ def readline(prompt, add_to_history=true)
112
+ if prompt
113
+ write_prompt(prompt)
114
+ end
115
+ coded_line = @inout.read_msg()
116
+ @read_ctrl = coded_line[0..0]
117
+ coded_line[1..-1]
118
+ end
119
+
120
+ # Return connected
121
+ def state
122
+ @inout.state
123
+ end
124
+
125
+ def write_prompt(prompt)
126
+ @inout.write(PROMPT + prompt)
127
+ end
128
+
129
+ def write_confirm(prompt, default)
130
+ if default
131
+ code = CONFIRM_TRUE
132
+ else
133
+ code = CONFIRM_FALSE
134
+ end
135
+ @inout.write(code + prompt)
136
+ end
137
+ end
138
+
139
+ # Demo
140
+ if __FILE__ == $0
141
+ intf = Trepan::ServerInterface.new(nil, nil, :open => false)
142
+ end
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
1
+ # Copyright (C) 2010, 2011 Rocky Bernstein <rockyb@rubyforge.net>
2
2
  # classes to support communication to and from the debugger. This
3
3
  # communcation might be to/from another process or another computer.
4
4
  # And reading may be from a debugger command script.
@@ -60,8 +60,8 @@ class Trepan
60
60
  attr_reader :output
61
61
  def initialize(out, opts={})
62
62
  @output = out
63
- @eof = false
64
63
  @flush_after_write = false
64
+ @eof = false
65
65
  end
66
66
 
67
67
  def close
@@ -86,9 +86,63 @@ class Trepan
86
86
  # used to write to a debugger that is connected to this
87
87
  # `str' written will have a newline added to it
88
88
  #
89
- def writeline( msg)
89
+ def writeline(msg)
90
90
  @output.write("%s\n" % msg)
91
91
  end
92
92
  end
93
+
94
+ # This is an abstract class that specifies debugger input output when
95
+ # handled by the same channel, e.g. a socket or tty.
96
+ #
97
+ class InOutBase
98
+
99
+ def initialize(inout, opts={})
100
+ @opts = DEFAULT_OPTS.merge(opts)
101
+ @inout = inout
102
+ end
103
+
104
+ def close
105
+ @inout.close() if @inout
106
+ end
107
+
108
+ def eof?
109
+ begin
110
+ @input.eof?
111
+ rescue IOError
112
+ true
113
+ end
114
+ end
115
+
116
+ def flush
117
+ @inout.flush
118
+ end
119
+
120
+ # Read a line of input. EOFError will be raised on EOF.
121
+ #
122
+ # Note that we don't support prompting first. Instead, arrange to
123
+ # call DebuggerOutput.write() first with the prompt. If `use_raw'
124
+ # is set raw_input() will be used in that is supported by the
125
+ # specific input input. If this option is left nil as is normally
126
+ # expected the value from the class initialization is used.
127
+ def readline(use_raw=nil)
128
+ @input.readline
129
+ end
130
+
131
+ # Use this to set where to write to. output can be a
132
+ # file object or a string. This code raises IOError on error.
133
+ #
134
+ # Use this to set where to write to. output can be a
135
+ # file object or a string. This code raises IOError on error.
136
+ def write(*args)
137
+ @inout.write(*args)
138
+ end
139
+
140
+ # used to write to a debugger that is connected to this
141
+ # server; `str' written will have a newline added to it
142
+ def writeline( msg)
143
+ @inout.write("%s\n" % msg)
144
+ end
145
+ end
146
+
93
147
  end
94
148
 
@@ -0,0 +1,122 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright (C) 2011 Rocky Bernstein <rockyb@rubyforge.net>
3
+ # Debugger Socket Input/Output Interface.
4
+
5
+ require 'socket'
6
+ require_relative 'base_io'
7
+ require_relative 'tcpfns'
8
+
9
+ class Trepan
10
+ # Debugger Client Input/Output Socket.
11
+ class TCPDbgClient < Trepan::InOutBase
12
+
13
+ include Trepanning::TCPPacking
14
+
15
+ DEFAULT_INIT_OPTS = {:open => true}
16
+
17
+ CLIENT_SOCKET_OPTS = {
18
+ :host => 'localhost', # Symbolic name
19
+ :port => 1027, # Arbitrary non-privileged port
20
+ }
21
+
22
+ def initialize(opts={})
23
+ @opts = CLIENT_SOCKET_OPTS.merge(opts)
24
+ @addr = nil
25
+ @buf = ''
26
+ @line_edit = false # Our name for GNU readline capability
27
+ @state = :disconnected
28
+ @inout = nil
29
+ open(@opts) if @opts[:open]
30
+ end
31
+
32
+ # Closes both input and output
33
+ def close
34
+ @state = :closing
35
+ @inout.close if @inout
36
+ @state = :disconnnected
37
+ end
38
+
39
+ def open(opts={})
40
+ @opts = CLIENT_SOCKET_OPTS.merge(opts)
41
+ @host = @opts[:host]
42
+ @port = @opts[:port]
43
+ begin
44
+ @inout = TCPSocket.new(@host, @port)
45
+ @state = :connected
46
+ rescue SystemCallError => e
47
+ raise IOError,
48
+ ('Open client for host %s on port %s gives error: %s' %
49
+ [@host, @port, e])
50
+ end
51
+ end
52
+
53
+ # Read one message unit. It's possible however that
54
+ # more than one message will be set in a receive, so we will
55
+ # have to buffer that for the next read.
56
+ # EOFError will be raised on EOF.
57
+ def read_msg
58
+ if @state == :connected
59
+ if !@buf || @buf.empty?
60
+ @buf = @inout.recv(TCP_MAX_PACKET)
61
+ if @buf.empty?
62
+ @state = :disconnected
63
+ raise EOFError
64
+ end
65
+ end
66
+ @buf, data = unpack_msg(@buf)
67
+ return data
68
+ else
69
+ raise IOError, ("read_msg called in state: %s." % @state.to_s)
70
+ end
71
+ end
72
+
73
+ # This method the debugger uses to write a message unit.
74
+ def write(msg)
75
+ # FIXME: do we have to check the size of msg and split output?
76
+ @inout.write(pack_msg(msg))
77
+ end
78
+
79
+ def writeline(msg)
80
+ write(msg + "\n")
81
+ end
82
+ end
83
+ end
84
+
85
+ # Demo
86
+ if __FILE__ == $0
87
+ client = Trepan::TCPDbgClient.new({'open' => false})
88
+ if ARGV.size > 0
89
+ threads = []
90
+ Thread.new do
91
+ server = TCPServer.new('localhost', 1027)
92
+ session = server.accept
93
+ while 'quit' != (line = session.gets)
94
+ session.puts line
95
+ end
96
+ session.close
97
+ end
98
+
99
+ threads << Thread.new do
100
+ print 'Connecting...'
101
+ client.open()
102
+ puts 'connected.'
103
+ while true
104
+ print "input? "
105
+ line = STDIN.gets
106
+ break if line.chomp == 'quit'
107
+ begin
108
+ line = client.writeline(line)
109
+ puts "Got: #{client.read_msg.chomp}"
110
+ rescue EOFError
111
+ puts "Got EOF"
112
+ break
113
+ rescue Exception => e
114
+ puts "Got #{e}"
115
+ break
116
+ end
117
+ end
118
+ end
119
+ threads.each {|t| t.join }
120
+ end
121
+ client.close
122
+ end
@@ -0,0 +1,31 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright (C) 2011 Rocky Bernstein <rockyb@rubyforge.net>
3
+ # Subsidiary routines used to "pack" and "unpack" TCP messages.
4
+
5
+ module Trepanning
6
+ module TCPPacking
7
+
8
+ TCP_MAX_PACKET = 8192 # Largest size for a recv
9
+ LOG_MAX_MSG = Math.log10(TCP_MAX_PACKET).ceil
10
+
11
+ def pack_msg(msg)
12
+ fmt = '%%%dd' % LOG_MAX_MSG # A funny way of writing: '%4d'
13
+ (fmt % msg.size) + msg
14
+ end
15
+
16
+ def unpack_msg(buf)
17
+ length = Integer(buf[0...LOG_MAX_MSG])
18
+ data = buf[LOG_MAX_MSG..LOG_MAX_MSG+length]
19
+ buf = buf[LOG_MAX_MSG+length..-1]
20
+ [buf, data]
21
+ end
22
+ end
23
+ end
24
+
25
+ # Demo
26
+ if __FILE__ == $0
27
+ include Trepanning::TCPPacking
28
+ msg = "Hi there!"
29
+ puts unpack_msg(pack_msg(msg))[1] == msg
30
+ end
31
+
@@ -0,0 +1,137 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright (C) 2011 Rocky Bernstein <rockyb@rubyforge.net>
3
+ # Debugger Server Input/Output interface.
4
+
5
+ require 'socket'
6
+ require_relative '../app/default' # For host and port
7
+ require_relative 'base_io'
8
+ require_relative 'tcpfns'
9
+
10
+ class Trepan
11
+ # Debugger Server Input/Output Socket.
12
+ class TCPDbgServer < Trepan::InOutBase
13
+
14
+ include Trepanning::TCPPacking
15
+
16
+ DEFAULT_INIT_OPTS = {:open => true}
17
+
18
+ SERVER_SOCKET_OPTS = {
19
+ :host => Trepan::DEFAULT_SETTINGS[:host],
20
+ :port => Trepan::DEFAULT_SETTINGS[:port], # A non-privileged port
21
+ :timeout => 5, # FIXME: not used
22
+ :reuse => true, # FIXME: not used. Allow port to be resued on close?
23
+ # Python has: 'posix' == os.name
24
+ }
25
+
26
+ attr_reader :state
27
+
28
+ def initialize(opts={})
29
+ @opts = DEFAULT_INIT_OPTS.merge(opts)
30
+ @input = @output = @session = nil
31
+ @buf = '' # Read buffer
32
+ @state = :disconnected
33
+ @port = nil # Current port in use
34
+ @host = nil # current host in use
35
+ open(@opts) if @opts[:open]
36
+ end
37
+
38
+ def connected?
39
+ :connected == @state
40
+ end
41
+
42
+
43
+ # Closes server connection.
44
+ def close
45
+ @state = :closing
46
+ @session.close if @session
47
+ @state = :disconnected
48
+ end
49
+
50
+ def open(opts={})
51
+ @opts = SERVER_SOCKET_OPTS.merge(opts)
52
+ @host = @opts[:host]
53
+ @port = @opts[:port]
54
+ @server = TCPServer.new(@host, @port)
55
+ # @server.setsockopt(Socket::SOL_SOCKET, Socket::SO_RCVTIMEO, 5)
56
+ # # @opts[:timeout])
57
+ @state = :listening
58
+ end
59
+
60
+ # Read one message unit. It's possible however that
61
+ # more than one message will be set in a receive, so we will
62
+ # have to buffer that for the next read.
63
+ # EOFError will be raised on EOF.
64
+ def read_msg
65
+ wait_for_connect unless connected?
66
+ while !@buf || @buf.empty?
67
+ @buf, info = @session.recvfrom(TCP_MAX_PACKET)
68
+ end
69
+ @buf, data = unpack_msg(@buf)
70
+ data
71
+ end
72
+
73
+ def wait_for_connect
74
+ @input = @output = @session = @server.accept
75
+ @state = :connected
76
+ end
77
+
78
+ # This method the debugger uses to write. In contrast to
79
+ # writeline, no newline is added to the end to `str'. Also
80
+ # msg doesn't have to be a string.
81
+ def write(msg)
82
+ wait_for_connect() unless connected?
83
+ # FIXME: do we have to check the size of msg and split output?
84
+ @session.print(pack_msg(msg))
85
+ end
86
+
87
+ def writeline(msg)
88
+ write(msg + "\n")
89
+ end
90
+
91
+ end
92
+ end
93
+
94
+ # Demo
95
+ if __FILE__ == $0
96
+ include Trepanning::TCPPacking
97
+ server = Trepan::TCPDbgServer.new({ :open => false,
98
+ :port => 1027,
99
+ :host => 'localhost'
100
+ })
101
+ if ARGV.size > 0
102
+ puts 'Listening for connection...'
103
+ server.open
104
+ threads = []
105
+ Thread.new do
106
+ while true do
107
+ begin
108
+ line = server.read_msg.chomp
109
+ puts "got #{line}"
110
+ rescue EOFError
111
+ puts 'Got EOF'
112
+ break
113
+ end
114
+ end
115
+ end
116
+ threads << Thread.new do
117
+ t = TCPSocket.new('localhost', 1027)
118
+ while true do
119
+ begin
120
+ print "input? "
121
+ line = STDIN.gets
122
+ break if !line || line.chomp == 'quit'
123
+ t.puts(pack_msg(line))
124
+ rescue EOFError
125
+ puts "Got EOF"
126
+ break
127
+ rescue Exception => e
128
+ puts "Got #{e}"
129
+ break
130
+ end
131
+ end
132
+ t.close
133
+ end
134
+ threads.each {|t| t.join }
135
+ server.close
136
+ end
137
+ end