rb8-trepanning 0.1.3

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 (274) hide show
  1. data/.gitignore +3 -0
  2. data/CHANGES +34 -0
  3. data/ChangeLog +875 -0
  4. data/README.textile +59 -0
  5. data/Rakefile +215 -0
  6. data/app/.gitignore +1 -0
  7. data/app/cmd_parse.kpeg +241 -0
  8. data/app/cmd_parse.rb +212 -0
  9. data/app/cmd_parser.rb +1948 -0
  10. data/app/complete.rb +79 -0
  11. data/app/default.rb +90 -0
  12. data/app/display.rb +148 -0
  13. data/app/eventbuffer.rb +147 -0
  14. data/app/frame.rb +166 -0
  15. data/app/irb.rb +114 -0
  16. data/app/options.rb +200 -0
  17. data/app/run.rb +74 -0
  18. data/app/util.rb +65 -0
  19. data/bin/.gitignore +1 -0
  20. data/bin/trepan8 +115 -0
  21. data/data/.gitignore +1 -0
  22. data/data/irbrc +41 -0
  23. data/interface/.gitignore +1 -0
  24. data/interface/base_intf.rb +109 -0
  25. data/interface/client.rb +82 -0
  26. data/interface/comcodes.rb +20 -0
  27. data/interface/script.rb +110 -0
  28. data/interface/server.rb +147 -0
  29. data/interface/user.rb +165 -0
  30. data/io/base_io.rb +148 -0
  31. data/io/input.rb +158 -0
  32. data/io/null_output.rb +46 -0
  33. data/io/string_array.rb +156 -0
  34. data/io/tcpclient.rb +129 -0
  35. data/io/tcpfns.rb +33 -0
  36. data/io/tcpserver.rb +141 -0
  37. data/lib/debugger.rb +8 -0
  38. data/lib/trepanning.rb +283 -0
  39. data/processor/.gitignore +1 -0
  40. data/processor/command-ruby-debug/breakpoints.rb +155 -0
  41. data/processor/command-ruby-debug/catchpoint.rb +55 -0
  42. data/processor/command-ruby-debug/condition.rb +49 -0
  43. data/processor/command-ruby-debug/control.rb +31 -0
  44. data/processor/command-ruby-debug/display.rb +120 -0
  45. data/processor/command-ruby-debug/enable.rb +202 -0
  46. data/processor/command-ruby-debug/frame.rb +199 -0
  47. data/processor/command-ruby-debug/help.rb +63 -0
  48. data/processor/command-ruby-debug/info.rb +359 -0
  49. data/processor/command-ruby-debug/method.rb +84 -0
  50. data/processor/command-ruby-debug/reload.rb +40 -0
  51. data/processor/command-ruby-debug/save.rb +90 -0
  52. data/processor/command-ruby-debug/set.rb +237 -0
  53. data/processor/command-ruby-debug/show.rb +251 -0
  54. data/processor/command-ruby-debug/source.rb +36 -0
  55. data/processor/command-ruby-debug/threads.rb +189 -0
  56. data/processor/command-ruby-debug/trace.rb +57 -0
  57. data/processor/command-ruby-debug/variables.rb +199 -0
  58. data/processor/command.rb +270 -0
  59. data/processor/command/.gitignore +1 -0
  60. data/processor/command/alias.rb +54 -0
  61. data/processor/command/backtrace.rb +123 -0
  62. data/processor/command/base/cmd.rb +177 -0
  63. data/processor/command/base/subcmd.rb +230 -0
  64. data/processor/command/base/submgr.rb +188 -0
  65. data/processor/command/base/subsubcmd.rb +128 -0
  66. data/processor/command/base/subsubmgr.rb +199 -0
  67. data/processor/command/break.rb +114 -0
  68. data/processor/command/catch.rb +71 -0
  69. data/processor/command/complete.rb +39 -0
  70. data/processor/command/continue.rb +57 -0
  71. data/processor/command/directory.rb +50 -0
  72. data/processor/command/disable.rb +85 -0
  73. data/processor/command/display.rb +78 -0
  74. data/processor/command/down.rb +54 -0
  75. data/processor/command/edit.rb +79 -0
  76. data/processor/command/enable.rb +48 -0
  77. data/processor/command/eval.rb +90 -0
  78. data/processor/command/exit.rb +66 -0
  79. data/processor/command/finish.rb +59 -0
  80. data/processor/command/frame.rb +97 -0
  81. data/processor/command/help.rb +230 -0
  82. data/processor/command/help/.gitignore +1 -0
  83. data/processor/command/help/README +10 -0
  84. data/processor/command/help/command.txt +58 -0
  85. data/processor/command/help/examples.txt +16 -0
  86. data/processor/command/help/filename.txt +40 -0
  87. data/processor/command/help/location.txt +37 -0
  88. data/processor/command/help/suffixes.txt +17 -0
  89. data/processor/command/info.rb +28 -0
  90. data/processor/command/info_subcmd/.gitignore +1 -0
  91. data/processor/command/info_subcmd/args.rb +39 -0
  92. data/processor/command/info_subcmd/breakpoints.rb +80 -0
  93. data/processor/command/info_subcmd/catch.rb +36 -0
  94. data/processor/command/info_subcmd/files.rb +39 -0
  95. data/processor/command/info_subcmd/globals.rb +64 -0
  96. data/processor/command/info_subcmd/line.rb +30 -0
  97. data/processor/command/info_subcmd/locals.rb +69 -0
  98. data/processor/command/info_subcmd/macro.rb +62 -0
  99. data/processor/command/info_subcmd/program.rb +51 -0
  100. data/processor/command/info_subcmd/ruby.rb +57 -0
  101. data/processor/command/info_subcmd/source.rb +74 -0
  102. data/processor/command/info_subcmd/stack.rb +25 -0
  103. data/processor/command/info_subcmd/threads.rb +75 -0
  104. data/processor/command/kill.rb +78 -0
  105. data/processor/command/list.rb +117 -0
  106. data/processor/command/macro.rb +68 -0
  107. data/processor/command/next.rb +79 -0
  108. data/processor/command/parsetree.rb +56 -0
  109. data/processor/command/pp.rb +40 -0
  110. data/processor/command/pr.rb +37 -0
  111. data/processor/command/ps.rb +40 -0
  112. data/processor/command/restart.rb +86 -0
  113. data/processor/command/save.rb +58 -0
  114. data/processor/command/set.rb +47 -0
  115. data/processor/command/set_subcmd/.gitignore +1 -0
  116. data/processor/command/set_subcmd/abbrev.rb +25 -0
  117. data/processor/command/set_subcmd/auto.rb +27 -0
  118. data/processor/command/set_subcmd/auto_subcmd/.gitignore +1 -0
  119. data/processor/command/set_subcmd/auto_subcmd/eval.rb +53 -0
  120. data/processor/command/set_subcmd/auto_subcmd/irb.rb +33 -0
  121. data/processor/command/set_subcmd/auto_subcmd/list.rb +33 -0
  122. data/processor/command/set_subcmd/basename.rb +25 -0
  123. data/processor/command/set_subcmd/callstyle.rb +46 -0
  124. data/processor/command/set_subcmd/confirm.rb +24 -0
  125. data/processor/command/set_subcmd/debug.rb +47 -0
  126. data/processor/command/set_subcmd/different.rb +61 -0
  127. data/processor/command/set_subcmd/highlight.rb +43 -0
  128. data/processor/command/set_subcmd/max.rb +26 -0
  129. data/processor/command/set_subcmd/max_subcmd/list.rb +49 -0
  130. data/processor/command/set_subcmd/max_subcmd/stack.rb +50 -0
  131. data/processor/command/set_subcmd/max_subcmd/string.rb +76 -0
  132. data/processor/command/set_subcmd/max_subcmd/width.rb +49 -0
  133. data/processor/command/set_subcmd/reload.rb +42 -0
  134. data/processor/command/set_subcmd/timer.rb +58 -0
  135. data/processor/command/set_subcmd/trace.rb +37 -0
  136. data/processor/command/set_subcmd/trace_subcmd/buffer.rb +42 -0
  137. data/processor/command/set_subcmd/trace_subcmd/print.rb +41 -0
  138. data/processor/command/shell.rb +139 -0
  139. data/processor/command/show.rb +39 -0
  140. data/processor/command/show_subcmd/.gitignore +1 -0
  141. data/processor/command/show_subcmd/abbrev.rb +20 -0
  142. data/processor/command/show_subcmd/alias.rb +46 -0
  143. data/processor/command/show_subcmd/args.rb +34 -0
  144. data/processor/command/show_subcmd/auto.rb +28 -0
  145. data/processor/command/show_subcmd/auto_subcmd/eval.rb +27 -0
  146. data/processor/command/show_subcmd/auto_subcmd/irb.rb +23 -0
  147. data/processor/command/show_subcmd/auto_subcmd/list.rb +22 -0
  148. data/processor/command/show_subcmd/basename.rb +20 -0
  149. data/processor/command/show_subcmd/callstyle.rb +22 -0
  150. data/processor/command/show_subcmd/confirm.rb +18 -0
  151. data/processor/command/show_subcmd/debug.rb +26 -0
  152. data/processor/command/show_subcmd/debug_subcmd/dbgr.rb +21 -0
  153. data/processor/command/show_subcmd/debug_subcmd/skip.rb +22 -0
  154. data/processor/command/show_subcmd/debug_subcmd/step.rb +22 -0
  155. data/processor/command/show_subcmd/different.rb +26 -0
  156. data/processor/command/show_subcmd/directories.rb +22 -0
  157. data/processor/command/show_subcmd/highlight.rb +24 -0
  158. data/processor/command/show_subcmd/max.rb +27 -0
  159. data/processor/command/show_subcmd/max_subcmd/list.rb +38 -0
  160. data/processor/command/show_subcmd/max_subcmd/stack.rb +36 -0
  161. data/processor/command/show_subcmd/max_subcmd/string.rb +42 -0
  162. data/processor/command/show_subcmd/max_subcmd/width.rb +37 -0
  163. data/processor/command/show_subcmd/reload.rb +18 -0
  164. data/processor/command/show_subcmd/timer.rb +18 -0
  165. data/processor/command/show_subcmd/trace.rb +29 -0
  166. data/processor/command/show_subcmd/trace_subcmd/buffer.rb +65 -0
  167. data/processor/command/show_subcmd/trace_subcmd/print.rb +23 -0
  168. data/processor/command/show_subcmd/version.rb +23 -0
  169. data/processor/command/source.rb +134 -0
  170. data/processor/command/step.rb +81 -0
  171. data/processor/command/tbreak.rb +19 -0
  172. data/processor/command/unalias.rb +44 -0
  173. data/processor/command/undisplay.rb +59 -0
  174. data/processor/command/up.rb +72 -0
  175. data/processor/default.rb +56 -0
  176. data/processor/display.rb +17 -0
  177. data/processor/eval.rb +113 -0
  178. data/processor/eventbuf.rb +105 -0
  179. data/processor/frame.rb +172 -0
  180. data/processor/help.rb +92 -0
  181. data/processor/helper.rb +76 -0
  182. data/processor/hook.rb +134 -0
  183. data/processor/load_cmds.rb +258 -0
  184. data/processor/location.rb +174 -0
  185. data/processor/main.rb +455 -0
  186. data/processor/mock.rb +136 -0
  187. data/processor/msg.rb +61 -0
  188. data/processor/processor.rb +674 -0
  189. data/processor/running.rb +168 -0
  190. data/processor/stepping.rb +18 -0
  191. data/processor/subcmd.rb +161 -0
  192. data/processor/validate.rb +355 -0
  193. data/processor/virtual.rb +34 -0
  194. data/test/data/.gitignore +1 -0
  195. data/test/data/break_bad.cmd +19 -0
  196. data/test/data/break_bad.right +29 -0
  197. data/test/data/break_loop_bug.cmd +5 -0
  198. data/test/data/break_loop_bug.right +15 -0
  199. data/test/data/dollar-0.right +2 -0
  200. data/test/data/dollar-0a.right +2 -0
  201. data/test/data/dollar-0b.right +2 -0
  202. data/test/data/edit.cmd +14 -0
  203. data/test/data/edit.right +24 -0
  204. data/test/data/file-with-space.cmd +6 -0
  205. data/test/data/file-with-space.right +4 -0
  206. data/test/data/printvar.cmd +17 -0
  207. data/test/data/printvar.right +31 -0
  208. data/test/data/raise.cmd +11 -0
  209. data/test/data/raise.right +19 -0
  210. data/test/data/source.cmd +5 -0
  211. data/test/data/source.right +18 -0
  212. data/test/data/stepping-1.9.right +50 -0
  213. data/test/data/stepping.cmd +21 -0
  214. data/test/data/stepping.right +48 -0
  215. data/test/data/trepan8-save.1 +6 -0
  216. data/test/example/bp_loop_issue.rb +3 -0
  217. data/test/example/break-bug.rb +7 -0
  218. data/test/example/brkpt-class-bug.rb +8 -0
  219. data/test/example/classes.rb +11 -0
  220. data/test/example/dollar-0.rb +5 -0
  221. data/test/example/except-bug1.rb +4 -0
  222. data/test/example/except-bug2.rb +7 -0
  223. data/test/example/file with space.rb +1 -0
  224. data/test/example/gcd.rb +18 -0
  225. data/test/example/info-var-bug.rb +47 -0
  226. data/test/example/info-var-bug2.rb +2 -0
  227. data/test/example/null.rb +1 -0
  228. data/test/example/pm-bug.rb +3 -0
  229. data/test/example/pm.rb +11 -0
  230. data/test/example/raise.rb +3 -0
  231. data/test/integration/.gitignore +4 -0
  232. data/test/integration/config.yaml +8 -0
  233. data/test/integration/helper.rb +154 -0
  234. data/test/integration/test-break_bad.rb +26 -0
  235. data/test/integration/test-dollar-0.rb +31 -0
  236. data/test/integration/test-edit.rb +17 -0
  237. data/test/integration/test-file-with-space.rb +26 -0
  238. data/test/integration/test-printvar.rb +17 -0
  239. data/test/integration/test-raise.rb +21 -0
  240. data/test/integration/test-source.rb +16 -0
  241. data/test/integration/test-stepping.rb +24 -0
  242. data/test/unit/.gitignore +1 -0
  243. data/test/unit/cmd-helper.rb +52 -0
  244. data/test/unit/mock-helper.rb +12 -0
  245. data/test/unit/test-app-cmd_parse.rb +97 -0
  246. data/test/unit/test-app-cmd_parser.rb +23 -0
  247. data/test/unit/test-app-complete.rb +39 -0
  248. data/test/unit/test-app-frame.rb +32 -0
  249. data/test/unit/test-app-options.rb +92 -0
  250. data/test/unit/test-app-run.rb +14 -0
  251. data/test/unit/test-app-util.rb +44 -0
  252. data/test/unit/test-base-cmd.rb +45 -0
  253. data/test/unit/test-base-subcmd.rb +57 -0
  254. data/test/unit/test-base-submgr.rb +23 -0
  255. data/test/unit/test-base-subsubcmd.rb +17 -0
  256. data/test/unit/test-cmd-alias.rb +48 -0
  257. data/test/unit/test-cmd-exit.rb +27 -0
  258. data/test/unit/test-cmd-help.rb +104 -0
  259. data/test/unit/test-cmd-kill.rb +46 -0
  260. data/test/unit/test-cmd-source.rb +34 -0
  261. data/test/unit/test-completion.rb +42 -0
  262. data/test/unit/test-intf-user.rb +46 -0
  263. data/test/unit/test-io-input.rb +27 -0
  264. data/test/unit/test-io-tcp.rb +33 -0
  265. data/test/unit/test-io-tcpclient.rb +54 -0
  266. data/test/unit/test-io-tcpfns.rb +17 -0
  267. data/test/unit/test-io-tcpserver.rb +50 -0
  268. data/test/unit/test-proc-eval.rb +36 -0
  269. data/test/unit/test-proc-hook.rb +30 -0
  270. data/test/unit/test-proc-load_cmds.rb +50 -0
  271. data/test/unit/test-proc-location.rb +79 -0
  272. data/test/unit/test-subcmd-help.rb +44 -0
  273. data/trepan8.gemspec +52 -0
  274. metadata +391 -0
data/io/tcpfns.rb ADDED
@@ -0,0 +1,33 @@
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
+ unless defined?(TCP_MAX_PACKET)
9
+ TCP_MAX_PACKET = 8192 # Largest size for a recv
10
+ LOG_MAX_MSG = Math.log10(TCP_MAX_PACKET).ceil
11
+ end
12
+
13
+ def pack_msg(msg)
14
+ fmt = '%%%dd' % LOG_MAX_MSG # A funny way of writing: '%4d'
15
+ (fmt % msg.size) + msg
16
+ end
17
+
18
+ def unpack_msg(buf)
19
+ length = Integer(buf[0...LOG_MAX_MSG])
20
+ data = buf[LOG_MAX_MSG..LOG_MAX_MSG+length]
21
+ buf = buf[LOG_MAX_MSG+length..-1]
22
+ [buf, data]
23
+ end
24
+ end
25
+ end
26
+
27
+ # Demo
28
+ if __FILE__ == $0
29
+ include Trepanning::TCPPacking
30
+ msg = "Hi there!"
31
+ puts unpack_msg(pack_msg(msg))[1] == msg
32
+ end
33
+
data/io/tcpserver.rb ADDED
@@ -0,0 +1,141 @@
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 'rubygems'; require 'require_relative'
7
+ require_relative '../app/default' # For host and port
8
+ require_relative 'base_io'
9
+ require_relative 'tcpfns'
10
+
11
+ module Trepan
12
+ # Debugger Server Input/Output Socket.
13
+ class TCPDbgServer < Trepan::InOutBase
14
+
15
+ include Trepanning::TCPPacking
16
+
17
+ unless defined?(SERVER_SOCKET_OPTS)
18
+ DEFAULT_INIT_OPTS = {:open => true}
19
+
20
+ SERVER_SOCKET_OPTS = {
21
+ :host => Trepan::DEFAULT_SETTINGS[:host],
22
+ :port => Trepan::DEFAULT_SETTINGS[:port], # A non-privileged port
23
+ :timeout => 5, # FIXME: not used
24
+ :reuse => true, # FIXME: not used. Allow port to be resued on close?
25
+ # Python has: 'posix' == os.name
26
+ }
27
+ end
28
+
29
+ attr_reader :state
30
+
31
+ def initialize(opts={})
32
+ @opts = DEFAULT_INIT_OPTS.merge(opts)
33
+ @input = @output = @session = nil
34
+ @buf = '' # Read buffer
35
+ @state = :disconnected
36
+ @port = nil # Current port in use
37
+ @host = nil # current host in use
38
+ @line_edit = false
39
+ open(@opts) if @opts[:open]
40
+ end
41
+
42
+ def connected?
43
+ :connected == @state
44
+ end
45
+
46
+
47
+ # Closes server connection.
48
+ def close
49
+ @state = :closing
50
+ @session.close if @session
51
+ @state = :disconnected
52
+ end
53
+
54
+ def open(opts={})
55
+ @opts = SERVER_SOCKET_OPTS.merge(opts)
56
+ @host = @opts[:host]
57
+ @port = @opts[:port]
58
+ @server = TCPServer.new(@host, @port)
59
+ # @server.setsockopt(Socket::SOL_SOCKET, Socket::SO_RCVTIMEO, 5)
60
+ # # @opts[:timeout])
61
+ @state = :listening
62
+ end
63
+
64
+ # Read one message unit. It's possible however that
65
+ # more than one message will be set in a receive, so we will
66
+ # have to buffer that for the next read.
67
+ # EOFError will be raised on EOF.
68
+ def read_msg
69
+ wait_for_connect unless connected?
70
+ while !@buf || @buf.empty?
71
+ @buf, info = @session.recvfrom(TCP_MAX_PACKET)
72
+ end
73
+ @buf, data = unpack_msg(@buf)
74
+ data
75
+ end
76
+
77
+ def wait_for_connect
78
+ @input = @output = @session = @server.accept
79
+ @state = :connected
80
+ end
81
+
82
+ # This method the debugger uses to write. In contrast to
83
+ # writeline, no newline is added to the end to `str'. Also
84
+ # msg doesn't have to be a string.
85
+ def write(msg)
86
+ wait_for_connect() unless connected?
87
+ # FIXME: do we have to check the size of msg and split output?
88
+ @session.print(pack_msg(msg))
89
+ end
90
+
91
+ def writeline(msg)
92
+ write(msg + "\n")
93
+ end
94
+
95
+ end
96
+ end
97
+
98
+ # Demo
99
+ if __FILE__ == $0
100
+ include Trepanning::TCPPacking
101
+ server = Trepan::TCPDbgServer.new({ :open => false,
102
+ :port => 1027,
103
+ :host => 'localhost'
104
+ })
105
+ if ARGV.size > 0
106
+ puts 'Listening for connection...'
107
+ server.open
108
+ threads = []
109
+ Thread.new do
110
+ while true do
111
+ begin
112
+ line = server.read_msg.chomp
113
+ puts "got #{line}"
114
+ rescue EOFError
115
+ puts 'Got EOF'
116
+ break
117
+ end
118
+ end
119
+ end
120
+ threads << Thread.new do
121
+ t = TCPSocket.new('localhost', 1027)
122
+ while true do
123
+ begin
124
+ print "input? "
125
+ line = STDIN.gets
126
+ break if !line || line.chomp == 'quit'
127
+ t.puts(pack_msg(line))
128
+ rescue EOFError
129
+ puts "Got EOF"
130
+ break
131
+ rescue Exception => e
132
+ puts "Got #{e}"
133
+ break
134
+ end
135
+ end
136
+ t.close
137
+ end
138
+ threads.each {|t| t.join }
139
+ server.close
140
+ end
141
+ end
data/lib/debugger.rb ADDED
@@ -0,0 +1,8 @@
1
+ # Module/Package to do the most-common thing: get into the debugger with
2
+ # minimal fuss. Compare with: require "debug"
3
+ require 'rubygems'
4
+ require 'require_relative'
5
+ require_relative "rubygems"
6
+ require './trepanning'
7
+ Trepan.start
8
+ debugger
data/lib/trepanning.rb ADDED
@@ -0,0 +1,283 @@
1
+ require 'rubygems'
2
+ require 'pp'
3
+ require 'stringio'
4
+ require 'socket'
5
+ require 'thread'
6
+ require 'ruby-debug-base'
7
+ require 'require_relative'
8
+ require_relative '../interface/script'
9
+ require_relative '../interface/user'
10
+ require_relative '../processor/processor'
11
+
12
+ module Trepan
13
+
14
+ class << self
15
+
16
+ ## FIXME: see if we can put this in app/complete.
17
+ # The method is called when we want to do debugger command completion
18
+ # such as called from GNU Readline with <TAB>.
19
+ def self.completion_method(last_token, leading=nil)
20
+ if leading.nil?
21
+ if Readline.respond_to?(:line_buffer)
22
+ completion =
23
+ Trepan.handler.cmdproc.complete(Readline.line_buffer,
24
+ last_token)
25
+ else
26
+ completion = Trepan.handler.cmdproc.complete(last_token, '')
27
+ end
28
+ else
29
+ completion = Trepan.handler.cmdproc.complete(leading, last_token)
30
+ end
31
+ if 1 == completion.size
32
+ completion_token = completion[0]
33
+ if last_token.end_with?(' ')
34
+ if last_token.rstrip == completion_token
35
+ # There is nothing more to complete
36
+ []
37
+ else
38
+ []
39
+ end
40
+ else
41
+ [completion_token]
42
+ end
43
+ else
44
+ # We have multiple completions. Get the last token so that will
45
+ # be presented as a list of completions.
46
+ completion
47
+ end
48
+ end
49
+ completion_proc = method(:completion_method).to_proc
50
+ ## FIXME: figure out how to get at this for testing.
51
+ $trepan_completion_proc = completion_proc
52
+
53
+ opts = {
54
+ :complete => completion_proc,
55
+ :readline => true
56
+ }
57
+
58
+ @@intf = [Trepan::UserInterface.new(nil, nil, opts)]
59
+
60
+ attr_accessor :handler
61
+ Trepan.handler = Debugger.handler = CommandProcessor.new(@@intf)
62
+
63
+ # gdb-style annotation mode. Used in GNU Emacs interface
64
+ attr_accessor :annotate
65
+
66
+ # in remote mode, wait for the remote connection
67
+ attr_accessor :wait_connection
68
+
69
+ # If start_sentinal is set, it is a string to look for in caller()
70
+ # and is used to see if the call stack is truncated. Is also
71
+ # defined in app/default.rb
72
+ attr_accessor :start_sentinal
73
+
74
+ attr_reader :thread, :control_thread, :cmd_port, :ctrl_port
75
+
76
+ def interface=(value) # :nodoc:
77
+ Debugger.handler.interface = value
78
+ end
79
+
80
+ # Trepan.start(options) -> bool
81
+ # Trepan.start(options) { ... } -> obj
82
+ #
83
+ # If it's called without a block it returns +true+, unless debugger
84
+ # was already started. If a block is given, it starts debugger and
85
+ # yields to block. When the block is finished executing it stops
86
+ # the debugger with Trepan.stop method.
87
+ #
88
+ # If a block is given, it starts debugger and yields to block. When
89
+ # the block is finished executing it stops the debugger with
90
+ # Trepan.stop method. Inside the block you will probably want to
91
+ # have a call to Trepan.debugger. For example:
92
+ #
93
+ # Trepan.start{debugger; foo} # Stop inside of foo
94
+ #
95
+ # Also, ruby-debug only allows
96
+ # one invocation of debugger at a time; nested Trepan.start's
97
+ # have no effect and you can't use this inside the debugger itself.
98
+ #
99
+ # <i>Note that if you want to stop debugger, you must call
100
+ # Trepan.stop as many time as you called Trepan.start
101
+ # method.</i>
102
+ #
103
+ # +options+ is a hash used to set various debugging options.
104
+ # Set :init true if you want to save ARGV and some variables which
105
+ # make a debugger restart possible. Only the first time :init is set true
106
+ # will values get set. Since ARGV is saved, you should make sure
107
+ # it hasn't been changed before the (first) call.
108
+ # Set :post_mortem true if you want to enter post-mortem debugging
109
+ # on an uncaught exception. Once post-mortem debugging is set, it can't
110
+ # be unset.
111
+ def start(options={}, &block)
112
+ options = Trepan::DEFAULT_START_SETTINGS.merge(options)
113
+ if options[:init]
114
+ Trepan.const_set('ARGV', ARGV.clone) unless
115
+ defined? Trepan::ARGV
116
+ Trepan.const_set('PROG_SCRIPT', $0) unless
117
+ defined? Trepan::PROG_SCRIPT
118
+ Trepan.const_set('INITIAL_DIR', Dir.pwd) unless
119
+ defined? Trepan::INITIAL_DIR
120
+ end
121
+ Trepan.tracing = options[:tracing] unless options[:tracing].nil?
122
+ retval = Debugger.started? ? block && block.call(self) : Debugger.start_(&block)
123
+ if options[:post_mortem]
124
+ post_mortem
125
+ end
126
+ return retval
127
+ end
128
+
129
+ def started?
130
+ Debugger.started?
131
+ end
132
+
133
+ #
134
+ # Starts a remote debugger.
135
+ #
136
+ def start_remote(host = nil, port = PORT, post_mortem = false)
137
+ return if @thread
138
+ return if started?
139
+
140
+ self.interface = nil
141
+ start
142
+ self.post_mortem if post_mortem
143
+
144
+ if port.kind_of?(Array)
145
+ cmd_port, ctrl_port = port
146
+ else
147
+ cmd_port, ctrl_port = port, port + 1
148
+ end
149
+
150
+ ctrl_port = start_control(host, ctrl_port)
151
+
152
+ yield if block_given?
153
+
154
+ mutex = Mutex.new
155
+ proceed = ConditionVariable.new
156
+
157
+ server = TCPServer.new(host, cmd_port)
158
+ @cmd_port = cmd_port = server.addr[1]
159
+ @thread = Debugger::DebugThread.new do
160
+ while (session = server.accept)
161
+ self.interface = RemoteInterface.new(session)
162
+ if wait_connection
163
+ mutex.synchronize do
164
+ proceed.signal
165
+ end
166
+ end
167
+ end
168
+ end
169
+ if wait_connection
170
+ mutex.synchronize do
171
+ proceed.wait(mutex)
172
+ end
173
+ end
174
+ end
175
+ alias start_server start_remote
176
+
177
+ def start_control(host = nil, ctrl_port = PORT + 1) # :nodoc:
178
+ raise "Debugger is not started" unless started?
179
+ return @ctrl_port if defined?(@control_thread) && @control_thread
180
+ server = TCPServer.new(host, ctrl_port)
181
+ @ctrl_port = server.addr[1]
182
+ @control_thread = Debugger::DebugThread.new do
183
+ while (session = server.accept)
184
+ interface = RemoteInterface.new(session)
185
+ processor = ControlCommandProcessor.new(interface)
186
+ processor.process_commands
187
+ end
188
+ end
189
+ @ctrl_port
190
+ end
191
+
192
+ #
193
+ # Connects to the remote debugger
194
+ #
195
+ def start_client(host = 'localhost', port = PORT)
196
+ require "socket"
197
+ interface = Trepan::LocalInterface.new
198
+ socket = TCPSocket.new(host, port)
199
+ puts "Connected."
200
+
201
+ catch(:exit) do
202
+ while (line = socket.gets)
203
+ case line
204
+ when /^PROMPT (.*)$/
205
+ input = interface.read_command($1)
206
+ throw :exit unless input
207
+ socket.puts input
208
+ when /^CONFIRM (.*)$/
209
+ input = interface.confirm($1)
210
+ throw :exit unless input
211
+ socket.puts input
212
+ else
213
+ print line
214
+ end
215
+ end
216
+ end
217
+ socket.close
218
+ end
219
+
220
+ def add_command_file(cmdfile, opts={}, stderr=$stderr)
221
+ unless File.readable?(cmdfile)
222
+ if File.exists?(cmdfile)
223
+ stderr.puts "Command file '#{cmdfile}' is not readable."
224
+ return
225
+ else
226
+ stderr.puts "Command file '#{cmdfile}' does not exist."
227
+ return
228
+ end
229
+ end
230
+ @@intf << Trepan::ScriptInterface.new(cmdfile, @output, opts)
231
+ end
232
+
233
+ def add_startup_files()
234
+ seen = {}
235
+ cwd_initfile = File.join('.', Trepan::CMD_INITFILE_BASE)
236
+ [cwd_initfile, Trepan::CMD_INITFILE].each do |initfile|
237
+ full_initfile_path = File.expand_path(initfile)
238
+ next if seen[full_initfile_path]
239
+ add_command_file(full_initfile_path) if
240
+ File.readable?(full_initfile_path)
241
+ seen[full_initfile_path] = true
242
+ end
243
+ end
244
+
245
+ def process_cmdfile_setting(settings)
246
+ p settings
247
+ puts caller
248
+ exit
249
+ settings[:cmdfiles].each do |item|
250
+ cmdfile, opts =
251
+ if item.kind_of?(Array)
252
+ item
253
+ else
254
+ [item, {}]
255
+ end
256
+ add_command_file(cmdfile, opts)
257
+ end if settings.member?(:cmdfiles)
258
+ end
259
+ end
260
+ end
261
+
262
+ module Kernel
263
+
264
+ # Enters the debugger in the current thread after _steps_ line events occur.
265
+ # Before entering the debugger startup script is read.
266
+ #
267
+ # Setting _steps_ to 0 will cause a break in the debugger subroutine
268
+ # and not wait for a line event to occur. You will have to go "up 1"
269
+ # in order to be back in your debugged program rather than the
270
+ # debugger. Settings _steps_ to 0 could be useful you want to stop
271
+ # right after the last statement in some scope, because the next
272
+ # step will take you out of some scope.
273
+ def debugger(steps = 1)
274
+ Trepan.start unless Trepan.started?
275
+ Trepan.add_startup_files
276
+ if 0 == steps
277
+ Debugger.current_context.stop_frame = 0
278
+ else
279
+ Debugger.current_context.stop_next = steps
280
+ end
281
+ end
282
+ alias breakpoint debugger unless respond_to?(:breakpoint)
283
+ end