trepanning 0.0.9 → 0.1.0

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.
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