rb8-trepanning 0.1.3-universal-ruby-1.9.2

Sign up to get free protection for your applications and to get access to all the features.
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 +58 -0
  274. metadata +388 -0
data/processor/mock.rb ADDED
@@ -0,0 +1,136 @@
1
+ # Copyright (C) 2010, 2011 Rocky Bernstein <rockyb@rubyforge.net>
2
+ # Mock setup for commands.
3
+ require 'rubygems'; require 'require_relative'
4
+ require_relative 'virtual'
5
+
6
+ # require_relative '../app/core'
7
+ require_relative '../app/default'
8
+ require_relative '../interface/user' # user interface (includes I/O)
9
+
10
+ require 'ruby-debug-base'; Debugger.start(:init => true)
11
+ require_relative 'processor'
12
+
13
+ module MockDebugger
14
+ class MockDebugger
15
+ attr_accessor :trace_filter # Procs/Methods we ignore.
16
+
17
+ attr_accessor :frame # Actually a "Rubinius::Location object
18
+ attr_accessor :core # access to Debugger::Core instance
19
+ attr_accessor :intf # The way the outside world interfaces with us.
20
+ attr_reader :initial_dir # String. Current directory when program
21
+ # started. Used in restart program.
22
+ attr_accessor :restart_argv # How to restart us, empty or nil.
23
+ # Note restart[0] is typically $0.
24
+ attr_reader :settings # Hash[:symbol] of things you can configure
25
+ attr_accessor :processor
26
+
27
+ # FIXME: move more stuff of here and into Trepan::CmdProcessor
28
+ # These below should go into Trepan::CmdProcessor.
29
+ attr_reader :cmd_argstr, :cmd_name, :current_frame, :completion_proc
30
+
31
+ def initialize(settings={:start_frame=>1})
32
+ @before_cmdloop_hooks = []
33
+ @settings = Trepan::DEFAULT_SETTINGS.merge(settings)
34
+ @intf = [Trepan::UserInterface.new(nil, nil,
35
+ :history_save=>false)]
36
+ # @current_frame = Trepan::Frame.new(context)
37
+ @frames = []
38
+
39
+ @trace_filter = []
40
+
41
+ @completion_proc = Proc.new{|str| str}
42
+
43
+ # Don't allow user commands in mocks.
44
+ ## @core.processor.settings[:user_cmd_dir] = nil
45
+
46
+ end
47
+
48
+ def frame(num)
49
+ @frames[num] ||= caller
50
+ end
51
+ end
52
+
53
+ # Common Mock debugger setup
54
+ def setup(name=nil, show_constants=true)
55
+ unless name
56
+ file = caller.first.split(/:\d/,2).first
57
+ name = File.basename(File.basename(file), '.rb')
58
+ end
59
+
60
+ if ARGV.size > 0 && ARGV[0] == 'debug'
61
+ require_relative '../lib/trepanning'
62
+ dbgr = Trepan.new
63
+ dbgr.debugger
64
+ else
65
+ dbgr = MockDebugger.new(:start_frame=>2)
66
+ end
67
+
68
+ cmdproc = Trepan::CmdProcessor.new(dbgr.intf)
69
+ state = Trepan::CommandProcessor::State.new(self) do |s|
70
+ s.context = Debugger.current_context
71
+ s.binding = binding
72
+ end
73
+ cmdproc.frame_setup(state.context, state)
74
+ dbgr.processor = cmdproc
75
+
76
+ cmdproc.interfaces = dbgr.intf
77
+ cmdproc.load_cmds_initialize
78
+ cmds = cmdproc.commands
79
+ cmd = cmds[name]
80
+ ## cmd.proc.frame_setup
81
+ ## cmd.proc.event = 'debugger-call'
82
+ show_special_class_constants(cmd) if show_constants
83
+
84
+ def cmd.confirm(prompt, default)
85
+ true
86
+ end
87
+ def cmd.msg_nocr(message, opts={})
88
+ print message
89
+ end
90
+
91
+ return dbgr, cmd
92
+ end
93
+ module_function :setup
94
+
95
+ def sub_setup(sub_class, run=true)
96
+ sub_name = sub_class.const_get('PREFIX')
97
+ dbgr, cmd = setup(sub_name[0], false)
98
+ sub_cmd = sub_class.new(cmd)
99
+ sub_cmd.summary_help(sub_cmd.name)
100
+ puts
101
+ sub_cmd.run([cmd.name]) if run
102
+ return sub_cmd
103
+ end
104
+ module_function :sub_setup
105
+
106
+ def subsub_setup(sub_class, subsub_class, run=true)
107
+ subsub_name = subsub_class.const_get('PREFIX')
108
+ dbgr, cmd = setup(subsub_name[0], false)
109
+ sub_cmd = sub_class.new(dbgr.processor, cmd)
110
+ subsub_cmd = subsub_class.new(cmd.proc, sub_cmd, subsub_name.join(''))
111
+ subsub_cmd.run([subsub_cmd.name]) if run
112
+ return subsub_cmd
113
+ end
114
+ module_function :subsub_setup
115
+
116
+ def show_special_class_constants(cmd)
117
+ puts 'ALIASES: %s' % [cmd.class.const_get('ALIASES').inspect] if
118
+ cmd.class.constants.member?(:ALIASES)
119
+ %w(CATEGORY MIN_ARGS MAX_ARGS
120
+ NAME NEED_STACK SHORT_HELP).each do |name|
121
+ puts '%s: %s' % [name, cmd.class.const_get(name).inspect]
122
+ end
123
+ puts '-' * 30
124
+ puts cmd.class.const_get('HELP')
125
+ puts '=' * 30
126
+ end
127
+ module_function :show_special_class_constants
128
+
129
+ end
130
+
131
+ if __FILE__ == $0
132
+ dbgr = MockDebugger::MockDebugger.new
133
+ p dbgr.settings
134
+ puts '=' * 10
135
+ # p dbgr.core.processor.settings
136
+ end
data/processor/msg.rb ADDED
@@ -0,0 +1,61 @@
1
+ # Copyright (C) 2010, 2011 Rocky Bernstein <rockyb@rubyforge.net>
2
+ # I/O related command processor methods
3
+ require 'rubygems'; require 'require_relative'
4
+ require_relative '../app/util'
5
+ require_relative 'virtual'
6
+ module Trepan
7
+ class CmdProcessor < VirtualCmdProcessor
8
+ attr_accessor :ruby_highlighter
9
+
10
+ def errmsg(message, opts={})
11
+ message = safe_rep(message) unless opts[:unlimited]
12
+ if @settings[:highlight] && defined?(Term::ANSIColor)
13
+ message =
14
+ Term::ANSIColor.italic + message + Term::ANSIColor.reset
15
+ end
16
+ @intf.errmsg(message)
17
+ end
18
+
19
+ def msg(message, opts={})
20
+ message = safe_rep(message) unless opts[:unlimited]
21
+ @intf.msg(message)
22
+ end
23
+
24
+ def msg_nocr(message, opts={})
25
+ message = safe_rep(message) unless opts[:unlimited]
26
+ @intf.msg_nocr(message)
27
+ end
28
+
29
+ def read_command()
30
+ @intf.read_command(@prompt)
31
+ end
32
+
33
+ def ruby_format(text)
34
+ return text unless settings[:highlight]
35
+ unless @ruby_highlighter
36
+ begin
37
+ require 'coderay'
38
+ require 'term/ansicolor'
39
+ @ruby_highlighter = CodeRay::Duo[:ruby, :term]
40
+ rescue LoadError
41
+ return text
42
+ end
43
+ end
44
+ return @ruby_highlighter.encode(text)
45
+ end
46
+
47
+ def safe_rep(str)
48
+ Util::safe_repr(str, @settings[:maxstring])
49
+ end
50
+
51
+ def section(message, opts={})
52
+ message = safe_rep(message) unless opts[:unlimited]
53
+ if @settings[:highlight] && defined?(Term::ANSIColor)
54
+ message =
55
+ Term::ANSIColor.bold + message + Term::ANSIColor.reset
56
+ end
57
+ @intf.msg(message)
58
+ end
59
+
60
+ end
61
+ end
@@ -0,0 +1,674 @@
1
+ require 'rubygems'
2
+ require 'ruby-debug-base'
3
+ require 'require_relative'
4
+ require_relative '../interface/user'
5
+ require_relative './command'
6
+ require_relative './default'
7
+ require_relative './main'
8
+ require_relative '../app/frame'
9
+
10
+ # _Trepan_ is the module name space for this debugger.
11
+ module Trepan
12
+
13
+ # A processor handles the kind of front-end to program interaction.
14
+ # Debugger::Processor is the the base class with subclasses
15
+ # Debugger::CommandProcessor and Debugger::ControlCommandProcessor.
16
+ class Processor
17
+ attr_accessor :interface
18
+ attr_reader :processor
19
+ attr_reader :commands
20
+
21
+ attr_accessor :frame # FIXME: move to frame.rb
22
+
23
+ # optional argument passed passed in callback. For catchpoints it is
24
+ # the catch object. For breakpoints it is the breakpoint object.
25
+ attr_reader :event_arg
26
+
27
+ # Format _msg_ with gdb-style annotation header.
28
+ def afmt(msg, newline="\n")
29
+ "\032\032#{msg}#{newline}"
30
+ end
31
+
32
+ # Print "annotation" message _msg_. Annotation messages are used
33
+ # by the GNU-Emacs front-end to get status about stacks and
34
+ # the state of the debugger without having to poll it for information
35
+ def aprint(msg)
36
+ print afmt(msg) if Trepan.annotate.to_i > 2
37
+ end
38
+
39
+ # Print a debugger error message; _args_ should be compatible
40
+ # with something you would pass to Kernel::print.
41
+ def errmsg(*args)
42
+ @interface.errmsg(*args)
43
+ @interface.print("\n")
44
+ end
45
+
46
+ # Print a normal debugger message; _args_ should be compatible
47
+ # with something you would pass to Kernel::print.
48
+ #
49
+ # Callers of this routine should make sure to use comma to
50
+ # separate format argments rather than %. Otherwise it seems that
51
+ # if the string you want to print has format specifier, which
52
+ # could happen if you are trying to show say a source-code line
53
+ # with "puts" or "print" in it, this print routine will give an
54
+ # error saying it is looking for more arguments.
55
+ def print(*args)
56
+ @interface.msg(*args)
57
+ end
58
+
59
+ end
60
+
61
+ # A Debugger::CommandProcessor is the kind of Debugger::Processor
62
+ # used when you are running inside the same process as the debugged
63
+ # program.
64
+ class CommandProcessor < Processor
65
+ attr_reader :display
66
+ attr_accessor :frame
67
+ attr_reader :cmdproc
68
+
69
+ # FIXME: get from Command regexp method.
70
+ @@Show_breakpoints_postcmd = [
71
+ /^\s*b(?:reak)?/,
72
+ /^\s* cond(?:ition)? (?:\s+(\d+)\s*(.*))?$/ix,
73
+ /^\s*del(?:ete)?(?:\s+(.*))?$/ix,
74
+ /^\s* dis(?:able)? (?:\s+(.*))?$/ix,
75
+ /^\s* en(?:able)? (?:\s+(.*))?$/ix,
76
+ # "tbreak", "clear",
77
+ ]
78
+ @@Show_annotations_run = [
79
+ /^\s*c(?:ont(?:inue)?)?(?:\s+(.*))?$/,
80
+ /^\s*fin(?:ish)?$/,
81
+ /^\s*n(?:ext)?([+-])?(?:\s+(.*))?$/,
82
+ /^\s*s(?:tep)?([+-])?(?:\s+(.*))?$/
83
+ ]
84
+
85
+ @@Show_annotations_postcmd = [
86
+ /^\s* down (?:\s+(.*))? .*$/x,
87
+ /^\s* f(?:rame)? (?:\s+ (.*))? \s*$/x,
88
+ /^\s* u(?:p)? (?:\s+(.*))?$/x
89
+ ]
90
+
91
+ def initialize(interfaces = [Trepan::UserInterface.new], settings={})
92
+ @interface = interfaces.first
93
+ @commands = []
94
+ @display = []
95
+
96
+ @mutex = Mutex.new
97
+ @last_cmd = nil
98
+ @last_file = nil # Filename the last time we stopped
99
+ @last_line = nil # line number the last time we stopped
100
+ @debugger_breakpoints_were_empty = false # Show breakpoints 1st time
101
+ @debugger_displays_were_empty = true # No display 1st time
102
+ @debugger_context_was_dead = true # Assume we haven't started.
103
+ @cmdproc = CmdProcessor.new(interfaces, settings)
104
+ end
105
+
106
+ def interface=(interface)
107
+ @mutex.synchronize do
108
+ @interface.close if @interface
109
+ @interface = interface
110
+ end
111
+ end
112
+
113
+ require 'pathname' # For cleanpath
114
+
115
+ # Regularize or "canonicalize" file name _filename_.
116
+ # This is also used as a common funnel place if basename is
117
+ # desired or if we are working remotely and want to change the
118
+ # basename. Or we are eliding filenames.
119
+ def self.canonic_file(filename)
120
+ # For now we want resolved filenames
121
+ if OldCommand.settings[:basename]
122
+ File.basename(filename)
123
+ else
124
+ # Cache this?
125
+ Pathname.new(filename).cleanpath.to_s
126
+ end
127
+ end
128
+
129
+ def self.print_location_and_text(file, line)
130
+ file_line = "%s:%s\n%s" % [canonic_file(file), line,
131
+ Debugger.line_at(file, line)]
132
+ # FIXME: use annotations routines
133
+ if Trepan.annotate.to_i > 2
134
+ file_line = "\032\032source #{file_line}"
135
+ elsif Trepan.inside_emacs?
136
+ file_line = "\032\032#{file_line}"
137
+ end
138
+ print file_line
139
+ end
140
+
141
+ # Create a "protected" version of method _mname_. A protected
142
+ # method handles all unhandled exceptions that would cause the
143
+ # program to terminate.
144
+ def self.protect(mname)
145
+ alias_method "__#{mname}", mname
146
+ module_eval %{
147
+ def #{mname}(*args)
148
+ @mutex.synchronize do
149
+ return unless @interface
150
+ __#{mname}(*args)
151
+ end
152
+ rescue IOError, Errno::EPIPE
153
+ self.interface = nil
154
+ rescue SignalException
155
+ raise
156
+ rescue Exception
157
+ print "INTERNAL ERROR!!! #\{$!\}\n" rescue nil
158
+ print $!.backtrace.map{|l| "\t#\{l\}"}.join("\n") rescue nil
159
+ end
160
+ }
161
+ end
162
+
163
+ # This is a callback routine when the debugged program hits a
164
+ # breakpoint event. For example ruby-debug-base calls this method.
165
+ def at_breakpoint(context, breakpoint)
166
+ @event_arg = breakpoint
167
+ @cmdproc.event = 'brkpt'
168
+ aprint 'stopped' if Trepan.annotate.to_i > 2
169
+ n = Debugger.breakpoints.index(breakpoint) + 1
170
+ file = @cmdproc.canonic_file(breakpoint.source)
171
+ line = breakpoint.pos
172
+ if Trepan.annotate.to_i > 2
173
+ print afmt("source #{file}:#{line}")
174
+ end
175
+ @cmdproc.msg 'Breakpoint %d at %s:%s' % [n, file, line]
176
+ end
177
+ protect :at_breakpoint
178
+
179
+ # This is a callback routine when the debugged program raises an
180
+ # unhandled exception that we have arranged to catch.
181
+ # In particular, ruby-debug-base calls this method
182
+ def at_catchpoint(context, excpt)
183
+ @event_arg = excpt
184
+ @cmdproc.event = 'raise'
185
+ file = @cmdproc.canonic_file(context.frame_file(0))
186
+ line = context.frame_line(0)
187
+ @cmdproc.msg("Catchpoint at %s:%d: `%s' (%s)" %
188
+ [file, line, excpt, excpt.class])
189
+ process_commands(context, file, line)
190
+ end
191
+ protect :at_catchpoint
192
+
193
+ def at_tracing(context, file, line)
194
+ @cmdproc.event = 'tracing'
195
+ return if defined?(Debugger::RDEBUG_FILE) &&
196
+ Debugger::RDEBUG_FILE == file # Don't trace ourself
197
+ @last_file = CommandProcessor.canonic_file(file)
198
+ canonic_file = CommandProcessor.canonic_file(file)
199
+ unless canonic_file == @last_file and @last_line == line and
200
+ Command.settings[:tracing_plus]
201
+ print "Tracing(%d):%s:%s %s",
202
+ context.thnum, canonic_file, line, Debugger.line_at(file, line)
203
+ @last_file = canonic_file
204
+ @last_line = line
205
+ end
206
+ always_run(context, file, line, 2)
207
+ end
208
+ protect :at_tracing
209
+
210
+ # This is a callback routine when the debugged program hits a
211
+ # "line" (or statement boundary) event. For example
212
+ # ruby-debug-base calls this.
213
+ def at_line(context, file, line)
214
+ @cmdproc.event = 'line'
215
+ process_commands(context, file, line)
216
+ end
217
+ protect :at_line
218
+
219
+ # This is a callback routine when the debugged program hits a
220
+ # "return" event. For example ruby-debug-base calls this.
221
+ # Note: right now ruby-debug-base does not call this. Perhaps
222
+ # other bases routines such as the one in JRuby do.
223
+ def at_return(context, file, line)
224
+ @cmdproc.event = 'return'
225
+ context.stop_frame = -1
226
+ process_commands(context, file, line)
227
+ end
228
+
229
+ # Return the command object to run given input string _input_.
230
+ def lookup(input)
231
+ ###########################################
232
+ ## Test the waters with new-style commands
233
+ args = input.split
234
+ cmd_name = args[0]
235
+ run_cmd_name =
236
+ if @cmdproc.aliases.member?(cmd_name)
237
+ @cmdproc.aliases[cmd_name]
238
+ else
239
+ cmd_name
240
+ end
241
+
242
+ if @cmdproc.commands.member?(run_cmd_name)
243
+ cmd = @cmdproc.commands[run_cmd_name]
244
+ if @cmdproc.ok_for_running(cmd, run_cmd_name, args.size-1)
245
+ return cmd
246
+ end
247
+ end
248
+ ###########################################
249
+
250
+ @commands.find{ |c| c.match(input) }
251
+ end
252
+
253
+ # Run a single command specified by string _input_; _commands_ is and
254
+ # Array of possible debugger command objects and _context_ is
255
+ # a Debugger::Context object.
256
+ def one_cmd(commands, context, input)
257
+ if cmd = lookup(input)
258
+ if cmd.kind_of?(Command)
259
+ if context.dead? && cmd.class.need_context
260
+ p cmd
261
+ print "Command is unavailable\n"
262
+ else
263
+ args = input.split
264
+ cmd_name = args[0]
265
+ @cmdproc.instance_variable_set('@cmd_argstr', input[cmd_name.size..-1].lstrip)
266
+ @cmdproc.instance_variable_set('@cmd_name', cmd_name)
267
+ begin
268
+ cmd.run(args)
269
+ rescue Exception
270
+ print "INTERNAL ERROR running command: #{cmd_name}\n"
271
+ print "#{$!}\n"
272
+ print $!.backtrace.map{|l| "\t#{l}"}.join("\n"), "\n" rescue nil
273
+ end
274
+ end
275
+ elsif context.dead? && cmd.class.need_context
276
+ p cmd
277
+ msg "Command is unavailable"
278
+ else
279
+ puts "Using old-style command" unless
280
+ @cmdproc.settings[:debuggertesting]
281
+ cmd.execute
282
+ end
283
+ else
284
+ unknown_cmd = commands.find{|cmd| cmd.class.unknown }
285
+ if unknown_cmd
286
+ unknown_cmd.execute
287
+ else
288
+ if @cmdproc.settings[:autoeval]
289
+ begin
290
+ @cmdproc.eval_code(input, @cmdproc.settings[:maxstring])
291
+ return
292
+ rescue NameError
293
+ end
294
+ end
295
+ errmsg "Unknown command: \"#{input.chomp}\". Try \"help\"."
296
+ end
297
+ end
298
+ end
299
+
300
+ private
301
+
302
+ # Return a prompt string to show before reading a command.
303
+ def prompt(context)
304
+ p = '(rdb:%s) ' % (context.dead? ? 'post-mortem' : context.thnum)
305
+ p = afmt("pre-prompt")+p+"\n"+afmt("prompt") if
306
+ Trepan.annotate.to_i > 2
307
+ return p
308
+ end
309
+
310
+ # Run commands that we always have to run before a entering a
311
+ # command loop. For example commands registered via debugger "set
312
+ # display", "set autolist", or set "autoirb". We return a list of
313
+ # commands that are acceptable to run bound to the current state.
314
+ def always_run(context, file, line, run_level)
315
+ event_cmds = OldCommand.commands.select{|cmd| cmd.event }
316
+
317
+ # Remove some commands if we are post mortem.
318
+ event_cmds = event_cmds.find_all do |cmd|
319
+ cmd.allow_in_post_mortem
320
+ end if !context || context.dead?
321
+
322
+ state = State.new(self) do |s|
323
+ s.context = context
324
+ s.file = file
325
+ s.line = line
326
+ s.display = display
327
+ s.commands = event_cmds
328
+ end
329
+ @interface.state = state if @interface.respond_to?('state=')
330
+
331
+ # Bind commands to the current state.
332
+ commands = event_cmds.map{|cmd| cmd.new(state)}
333
+
334
+ commands.select do |cmd|
335
+ cmd.class.always_run >= run_level
336
+ end.each {|cmd| cmd.execute}
337
+ return state, commands
338
+ end
339
+
340
+ # This the main debugger command-line loop. Here we read a
341
+ # debugger command, perform it, and ask for another one unless we
342
+ # are told to continue execution or terminate.
343
+ def process_commands(context, file, line)
344
+ @state, @commands = always_run(context, file, line, 1)
345
+ $rdebug_state = @state if @cmdproc.settings[:debuggertesting]
346
+ @cmdproc.process_commands(context, @state)
347
+
348
+ # @cmdproc.frame_setup(context, @state)
349
+ # splitter = lambda do |str|
350
+ # str.split(/;/).inject([]) do |m, v|
351
+ # if m.empty?
352
+ # m << v
353
+ # else
354
+ # if m.last[-1] == ?\\
355
+ # m.last[-1,1] = ''
356
+ # m.last << ';' << v
357
+ # else
358
+ # m << v
359
+ # end
360
+ # end
361
+ # m
362
+ # end
363
+ # end
364
+
365
+ # preloop(@commands, context)
366
+ # CommandProcessor.print_location_and_text(file, line)
367
+ # while !@state.proceed?
368
+ # input = if @interface.command_queue.empty?
369
+ # @interface.read_command(prompt(context))
370
+ # else
371
+ # @interface.command_queue.shift
372
+ # end
373
+ # break unless input
374
+ # next if input =~ /^\s*#/
375
+ # catch(:debug_error) do
376
+ # if input == ""
377
+ # next unless @last_cmd
378
+ # input = @last_cmd
379
+ # else
380
+ # @last_cmd = input
381
+ # end
382
+ # splitter[input].each do |cmd|
383
+ # one_cmd(@commands, context, cmd)
384
+ # postcmd(@commands, context, cmd)
385
+ # end
386
+ # end
387
+ # end
388
+ # postloop(@commands, context)
389
+ end # process_commands
390
+
391
+ # Things we do before entering the debugger command loop.
392
+ # Note: in the trepanning debuggers this and always_run have been
393
+ # merged. To do this and get the order right we add a priority level
394
+ # for each hook.
395
+ def preloop(commands, context)
396
+ aprint('stopped') if Trepan.annotate.to_i > 2
397
+ if context.dead?
398
+ unless @debugger_context_was_dead
399
+ if Trepan.annotate.to_i > 2
400
+ aprint('exited')
401
+ print "The program finished.\n"
402
+ end
403
+ @debugger_context_was_dead = true
404
+ end
405
+ end
406
+
407
+ if Trepan.annotate.to_i > 2
408
+ # if we are here, the stack frames have changed outside the
409
+ # command loop (e.g. after a "continue" command), so we show
410
+ # the annotations again
411
+ breakpoint_annotations(commands, context)
412
+ display_annotations(commands, context)
413
+ annotation('stack', commands, context, "where")
414
+ annotation('variables', commands, context, "info variables") unless
415
+ context.dead?
416
+ end
417
+ end
418
+
419
+ # Things we do after leaving the debugger command loop.
420
+ def postcmd(commands, context, cmd)
421
+ if Trepan.annotate.to_i > 0
422
+ cmd = @last_cmd unless cmd
423
+ breakpoint_annotations(commands, context) if
424
+ @@Show_breakpoints_postcmd.find{|pat| cmd =~ pat}
425
+ display_annotations(commands, context)
426
+ if @@Show_annotations_postcmd.find{|pat| cmd =~ pat}
427
+ annotation('stack', commands, context, "where") if
428
+ context.stack_size > 0
429
+ annotation('variables', commands, context, "info variables") unless
430
+ context.dead?
431
+ end
432
+ if not context.dead? and @@Show_annotations_run.find{|pat| cmd =~ pat}
433
+ aprint 'starting' if Trepan.annotate.to_i > 2
434
+
435
+ @debugger_context_was_dead = false
436
+ end
437
+ end
438
+ end
439
+
440
+ # Things we do after leaving the debugger command loop.
441
+ def postloop(commands, context)
442
+ end
443
+
444
+ # Run a command in String _cmd_, but tag output with annotation
445
+ # specified in String _label+. +commands_ is an Array of all
446
+ # possible debugger command objects, and _context_ is a
447
+ # Debugger::Context object.
448
+ def annotation(label, commands, context, cmd)
449
+ print afmt(label)
450
+ one_cmd(commands, context, cmd)
451
+ ### FIXME ANNOTATE: the following line should be deleted
452
+ print "\032\032\n"
453
+ end
454
+
455
+ def breakpoint_annotations(commands, context)
456
+ unless Debugger.breakpoints.empty? and @debugger_breakpoints_were_empty
457
+ annotation('breakpoints', commands, context, "info breakpoints")
458
+ @debugger_breakpoints_were_empty = Debugger.breakpoints.empty?
459
+ end
460
+ end
461
+
462
+ def display_annotations(commands, context)
463
+ return if display.empty?
464
+ # have_display = display.find{|d| d[0]}
465
+ # return unless have_display and @debugger_displays_were_empty
466
+ # @debugger_displays_were_empty = have_display
467
+ annotation('display', commands, context, "display")
468
+ end
469
+
470
+ class State # :nodoc:
471
+ attr_accessor :context, :file, :line, :binding
472
+ attr_accessor :frame_pos, :previous_line, :display
473
+ attr_accessor :interface, :commands, :processor
474
+
475
+ def initialize(processor=nil)
476
+ super()
477
+ @frame_pos = 0
478
+ @previous_line = nil
479
+ @proceed = false
480
+ @processor = processor
481
+ yield self
482
+ end
483
+
484
+ # Print a debugger error message; _args_ should be compatible
485
+ # with something you would pass to Kernel::print.
486
+ def errmsg(*args)
487
+ @interface.errmsg(*args)
488
+ @interface.msg("\n")
489
+ end
490
+
491
+ # Print a normal debugger message; _args_ should be compatible
492
+ # with something you would pass to Kernel::print.
493
+ #
494
+ # Callers of this routine should make sure to use comma to
495
+ # separate format argments rather than %. Otherwise it seems that
496
+ # if the string you want to print has format specifier, which
497
+ # could happen if you are trying to show say a source-code line
498
+ # with "puts" or "print" in it, this print routine will give an
499
+ # error saying it is looking for more arguments.
500
+ def print(*args)
501
+ @interface.print(*args)
502
+ end
503
+
504
+ # confirm is called before performing a dangerous action.
505
+ def confirm(*args)
506
+ @interface.confirm(*args)
507
+ end
508
+
509
+ def proceed?
510
+ @proceed
511
+ end
512
+
513
+ def proceed
514
+ @proceed = true
515
+ end
516
+ end
517
+ end
518
+
519
+ # A Debugger::ControlCommandProcessor is the kind of Debugger::Processor
520
+ # used the debugged program is running remotely. It is also entered
521
+ # after the debugged program has terminated.
522
+ class ControlCommandProcessor < Processor
523
+ def initialize(interface)
524
+ super()
525
+ @interface = interface
526
+ @cmdproc = CmdProcessor.new([interface])
527
+ @debugger_context_was_dead = true # Assume we haven't started.
528
+ end
529
+
530
+ # Return the command object to run given input string _input_.
531
+ def lookup(input)
532
+ ###########################################
533
+ ## Test the waters with new-style commands
534
+ args = input.split
535
+ cmd_name = args[0]
536
+ run_cmd_name =
537
+ if @cmdproc.aliases.member?(cmd_name)
538
+ @cmdproc.aliases[cmd_name]
539
+ else
540
+ cmd_name
541
+ end
542
+
543
+ if @cmdproc.commands.member?(run_cmd_name)
544
+ cmd = @cmdproc.commands[run_cmd_name]
545
+ if @cmdproc.ok_for_running(cmd, run_cmd_name, args.size-1)
546
+ return cmd
547
+ end
548
+ end
549
+ ###########################################
550
+
551
+ @commands.find{ |c| c.match(input) }
552
+ end
553
+
554
+ # This the main debugger command-line loop. Here we read a
555
+ # debugger command, perform it, and ask for another one unless we
556
+ # are told to continue execution or terminate.
557
+ def process_commands(verbose=false)
558
+ control_cmds = OldCommand.commands.select do |cmd|
559
+ cmd.allow_in_control
560
+ end
561
+ context = Debugger.current_context
562
+ @state = State.new(@interface, control_cmds)
563
+ @cmdproc.frame_setup(context, @state)
564
+ @commands = control_cmds.map{|cmd| cmd.new(@state) }
565
+
566
+ unless @debugger_context_was_dead
567
+ if Trepan.annotate.to_i > 2
568
+ aprint 'exited'
569
+ print "The program finished.\n"
570
+ end
571
+ @debugger_context_was_dead = true
572
+ end
573
+
574
+ while input = @interface.read_command(prompt(nil))
575
+ print "+#{input}\n" if true # verbose
576
+ catch(:debug_error) do
577
+ if cmd = lookup(input)
578
+ if cmd.kind_of?(Command)
579
+ args = input.split
580
+ cmd_name = args[0]
581
+ @cmdproc.instance_variable_set('@cmd_argstr', input[cmd_name.size..-1].lstrip)
582
+ @cmdproc.instance_variable_set('@cmd_name', cmd_name)
583
+ begin
584
+ cmd.run(args)
585
+ rescue Exception
586
+ print "INTERNAL ERROR running command: #{cmd_name}\n"
587
+ print "#{$!}\n"
588
+ print $!.backtrace.map{|l| "\t#{l}"}.join("\n"), "\n" rescue nil
589
+ end
590
+ else
591
+ puts "Using old-style command" unless
592
+ @cmdproc.settings[:debuggertesting]
593
+ cmd.execute
594
+ end
595
+ else
596
+ if @cmdproc.settings[:autoeval]
597
+ begin
598
+ @cmdproc.eval_code(input, @cmdproc.settings[:maxstring])
599
+ return
600
+ rescue NameError
601
+ end
602
+ end
603
+ errmsg "Unknown command: \"#{input.chomp}\". Try \"help\"."
604
+ end
605
+ end
606
+ end
607
+ rescue IOError, Errno::EPIPE
608
+ # rescue Exception
609
+ # print "INTERNAL ERROR!!! #{$!}\n" rescue nil
610
+ # print $!.backtrace.map{|l| "\t#{l}"}.join("\n") rescue nil
611
+ ensure
612
+ @interface.close
613
+ end
614
+
615
+ # Return a prompt string to show before reading a command. Note: The
616
+ # _context_ parameter is not used. It must be provided so that the
617
+ # interface matches Debugger::CommandProcessor#prompt.
618
+ def prompt(context)
619
+ p = '(rdb:ctrl) '
620
+ p = afmt("pre-prompt")+p+"\n"+afmt("prompt") if
621
+ Trepan.annotate.to_i > 2
622
+ return p
623
+ end
624
+
625
+ class State # :nodoc:
626
+ attr_reader :commands, :interface, :frame_pos
627
+
628
+ def initialize(interface, commands)
629
+ @interface = interface
630
+ @commands = commands
631
+ @frame_pos = 0
632
+ end
633
+
634
+ def proceed
635
+ end
636
+
637
+ # Print a debugger error message; _args_ should be compatible
638
+ # with something you would pass to Kernel::print.
639
+ def errmsg(*args)
640
+ @interface.print(*args)
641
+ @interface.print "\n"
642
+ end
643
+
644
+ # Print a normal debugger message; _args_ should be compatible
645
+ # with something you would pass to Kernel::print.
646
+ #
647
+ # Callers of this routine should make sure to use comma to
648
+ # separate format argments rather than %. Otherwise it seems that
649
+ # if the string you want to print has format specifier, which
650
+ # could happen if you are trying to show say a source-code line
651
+ # with "puts" or "print" in it, this print routine will give an
652
+ # error saying it is looking for more arguments.
653
+ def print(*args)
654
+ @interface.print(*args)
655
+ @interface.print "\n"
656
+ end
657
+
658
+ # confirm is called before performing a dangerous action. In
659
+ # control processor we always return "yes" or "y".
660
+ def confirm(*args)
661
+ 'y'
662
+ end
663
+
664
+ def context
665
+ nil
666
+ end
667
+
668
+ def file
669
+ errmsg "No filename given."
670
+ throw :debug_error
671
+ end
672
+ end # State
673
+ end
674
+ end