rbx-trepanning 0.0.1-universal-rubinius

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 (205) hide show
  1. data/ChangeLog +376 -0
  2. data/LICENSE +25 -0
  3. data/NEWS +2 -0
  4. data/README.textile +28 -0
  5. data/Rakefile +165 -0
  6. data/THANKS +14 -0
  7. data/app/breakpoint.rb +218 -0
  8. data/app/breakpoint.rbc +3564 -0
  9. data/app/brkptmgr.rb +138 -0
  10. data/app/brkptmgr.rbc +2827 -0
  11. data/app/default.rb +61 -0
  12. data/app/default.rbc +1011 -0
  13. data/app/display.rb +35 -0
  14. data/app/display.rbc +968 -0
  15. data/app/frame.rb +98 -0
  16. data/app/frame.rbc +1808 -0
  17. data/app/irb.rb +112 -0
  18. data/app/irb.rbc +2111 -0
  19. data/app/iseq.rb +95 -0
  20. data/app/iseq.rbc +1801 -0
  21. data/app/method.rb +173 -0
  22. data/app/method.rbc +2492 -0
  23. data/app/mock.rb +13 -0
  24. data/app/mock.rbc +398 -0
  25. data/app/options.rb +123 -0
  26. data/app/options.rbc +2183 -0
  27. data/app/run.rb +86 -0
  28. data/app/run.rbc +1244 -0
  29. data/app/util.rb +49 -0
  30. data/app/util.rbc +1144 -0
  31. data/app/validate.rb +30 -0
  32. data/app/validate.rbc +676 -0
  33. data/bin/trepan.compiled.rbc +1043 -0
  34. data/bin/trepanx +63 -0
  35. data/bin/trepanx.compiled.rbc +985 -0
  36. data/interface/base_intf.rb +95 -0
  37. data/interface/base_intf.rbc +1742 -0
  38. data/interface/script.rb +104 -0
  39. data/interface/script.rbc +1642 -0
  40. data/interface/user.rb +91 -0
  41. data/interface/user.rbc +1418 -0
  42. data/io/base_io.rb +94 -0
  43. data/io/base_io.rbc +1404 -0
  44. data/io/input.rb +112 -0
  45. data/io/input.rbc +1979 -0
  46. data/io/null_output.rb +42 -0
  47. data/io/null_output.rbc +730 -0
  48. data/io/string_array.rb +156 -0
  49. data/io/string_array.rbc +2466 -0
  50. data/lib/trepanning.rb +398 -0
  51. data/lib/trepanning.rbc +6661 -0
  52. data/processor/breakpoint.rb +161 -0
  53. data/processor/command/alias.rb +55 -0
  54. data/processor/command/backtrace.rb +46 -0
  55. data/processor/command/base/cmd.rb +124 -0
  56. data/processor/command/base/subcmd.rb +213 -0
  57. data/processor/command/base/submgr.rb +179 -0
  58. data/processor/command/base/subsubcmd.rb +103 -0
  59. data/processor/command/base/subsubmgr.rb +184 -0
  60. data/processor/command/break.rb +100 -0
  61. data/processor/command/continue.rb +82 -0
  62. data/processor/command/delete.rb +30 -0
  63. data/processor/command/directory.rb +43 -0
  64. data/processor/command/disassemble.rb +103 -0
  65. data/processor/command/down.rb +54 -0
  66. data/processor/command/eval.rb +31 -0
  67. data/processor/command/exit.rb +58 -0
  68. data/processor/command/finish.rb +78 -0
  69. data/processor/command/frame.rb +89 -0
  70. data/processor/command/help.rb +146 -0
  71. data/processor/command/info.rb +28 -0
  72. data/processor/command/info_subcmd/breakpoints.rb +75 -0
  73. data/processor/command/info_subcmd/file.rb +153 -0
  74. data/processor/command/info_subcmd/method.rb +71 -0
  75. data/processor/command/info_subcmd/program.rb +59 -0
  76. data/processor/command/info_subcmd/variables.rb +40 -0
  77. data/processor/command/irb.rb +96 -0
  78. data/processor/command/kill.rb +70 -0
  79. data/processor/command/list.rb +296 -0
  80. data/processor/command/next.rb +66 -0
  81. data/processor/command/nexti.rb +59 -0
  82. data/processor/command/pr.rb +38 -0
  83. data/processor/command/ps.rb +40 -0
  84. data/processor/command/restart.rb +60 -0
  85. data/processor/command/set.rb +47 -0
  86. data/processor/command/set_subcmd/auto.rb +28 -0
  87. data/processor/command/set_subcmd/auto_subcmd/dis.rb +33 -0
  88. data/processor/command/set_subcmd/auto_subcmd/eval.rb +54 -0
  89. data/processor/command/set_subcmd/auto_subcmd/irb.rb +34 -0
  90. data/processor/command/set_subcmd/auto_subcmd/list.rb +34 -0
  91. data/processor/command/set_subcmd/basename.rb +26 -0
  92. data/processor/command/set_subcmd/debug.rb +27 -0
  93. data/processor/command/set_subcmd/debug_subcmd/dbgr.rb +36 -0
  94. data/processor/command/set_subcmd/debug_subcmd/skip.rb +23 -0
  95. data/processor/command/set_subcmd/debug_subcmd/step.rb +23 -0
  96. data/processor/command/set_subcmd/different.rb +60 -0
  97. data/processor/command/set_subcmd/hidelevel.rb +63 -0
  98. data/processor/command/set_subcmd/kernelstep.rb +61 -0
  99. data/processor/command/set_subcmd/max.rb +29 -0
  100. data/processor/command/set_subcmd/max_subcmd/list.rb +49 -0
  101. data/processor/command/set_subcmd/max_subcmd/stack.rb +50 -0
  102. data/processor/command/set_subcmd/max_subcmd/string.rb +54 -0
  103. data/processor/command/set_subcmd/max_subcmd/width.rb +49 -0
  104. data/processor/command/set_subcmd/substitute.rb +25 -0
  105. data/processor/command/set_subcmd/substitute_subcmd/path.rb +56 -0
  106. data/processor/command/set_subcmd/trace.rb +37 -0
  107. data/processor/command/set_subcmd/trace_subcmd/print.rb +57 -0
  108. data/processor/command/show.rb +27 -0
  109. data/processor/command/show_subcmd/alias.rb +43 -0
  110. data/processor/command/show_subcmd/args.rb +26 -0
  111. data/processor/command/show_subcmd/auto.rb +28 -0
  112. data/processor/command/show_subcmd/auto_subcmd/dis.rb +37 -0
  113. data/processor/command/show_subcmd/auto_subcmd/eval.rb +28 -0
  114. data/processor/command/show_subcmd/auto_subcmd/irb.rb +23 -0
  115. data/processor/command/show_subcmd/auto_subcmd/list.rb +22 -0
  116. data/processor/command/show_subcmd/basename.rb +22 -0
  117. data/processor/command/show_subcmd/debug.rb +27 -0
  118. data/processor/command/show_subcmd/debug_subcmd/dbgr.rb +21 -0
  119. data/processor/command/show_subcmd/debug_subcmd/skip.rb +22 -0
  120. data/processor/command/show_subcmd/debug_subcmd/step.rb +22 -0
  121. data/processor/command/show_subcmd/different.rb +27 -0
  122. data/processor/command/show_subcmd/hidelevel.rb +42 -0
  123. data/processor/command/show_subcmd/kernelstep.rb +37 -0
  124. data/processor/command/show_subcmd/max.rb +30 -0
  125. data/processor/command/show_subcmd/max_subcmd/list.rb +38 -0
  126. data/processor/command/show_subcmd/max_subcmd/stack.rb +36 -0
  127. data/processor/command/show_subcmd/max_subcmd/string.rb +42 -0
  128. data/processor/command/show_subcmd/max_subcmd/width.rb +37 -0
  129. data/processor/command/show_subcmd/trace.rb +29 -0
  130. data/processor/command/show_subcmd/trace_subcmd/print.rb +38 -0
  131. data/processor/command/source.rb +83 -0
  132. data/processor/command/step.rb +41 -0
  133. data/processor/command/tbreak.rb +19 -0
  134. data/processor/command/unalias.rb +44 -0
  135. data/processor/command/up.rb +87 -0
  136. data/processor/default.rb +56 -0
  137. data/processor/disassemble.rb +32 -0
  138. data/processor/eval.rb +96 -0
  139. data/processor/frame.rb +211 -0
  140. data/processor/help.rb +72 -0
  141. data/processor/hook.rb +133 -0
  142. data/processor/load_cmds.rb +101 -0
  143. data/processor/location.rb +128 -0
  144. data/processor/main.rb +394 -0
  145. data/processor/mock.rb +137 -0
  146. data/processor/msg.rb +28 -0
  147. data/processor/running.rb +230 -0
  148. data/processor/stepping.rb +115 -0
  149. data/processor/subcmd.rb +160 -0
  150. data/processor/validate.rb +355 -0
  151. data/test/data/enable.right +36 -0
  152. data/test/data/fname-with-blank.cmd +6 -0
  153. data/test/data/fname-with-blank.right +1 -0
  154. data/test/data/quit-Xdebug.right +3 -0
  155. data/test/data/quit.cmd +5 -0
  156. data/test/data/quit.right +0 -0
  157. data/test/example/fname with blank.rb +1 -0
  158. data/test/example/gcd-xx.rb +18 -0
  159. data/test/example/gcd.rb +19 -0
  160. data/test/example/gcd1.rb +24 -0
  161. data/test/example/null.rb +1 -0
  162. data/test/example/thread1.rb +3 -0
  163. data/test/functional/fn_helper.rb +112 -0
  164. data/test/functional/test-break-name.rb +52 -0
  165. data/test/functional/test-break.rb +51 -0
  166. data/test/functional/test-finish.rb +70 -0
  167. data/test/functional/test-fn_helper.rb +43 -0
  168. data/test/functional/test-list.rb +55 -0
  169. data/test/functional/test-next-bug.rb +49 -0
  170. data/test/functional/test-next.rb +101 -0
  171. data/test/functional/test-step.rb +272 -0
  172. data/test/functional/test-step2.rb +35 -0
  173. data/test/functional/test-tbreak.rb +41 -0
  174. data/test/integration/file-diff.rb +89 -0
  175. data/test/integration/helper.rb +78 -0
  176. data/test/integration/test-fname-with-blank.rb +12 -0
  177. data/test/integration/test-quit.rb +25 -0
  178. data/test/unit/cmd-helper.rb +46 -0
  179. data/test/unit/test-app-brkpt.rb +30 -0
  180. data/test/unit/test-app-brkptmgr.rb +51 -0
  181. data/test/unit/test-app-iseq.rb +49 -0
  182. data/test/unit/test-app-method.rb +54 -0
  183. data/test/unit/test-app-options.rb +61 -0
  184. data/test/unit/test-app-run.rb +16 -0
  185. data/test/unit/test-app-util.rb +28 -0
  186. data/test/unit/test-app-validate.rb +18 -0
  187. data/test/unit/test-base-subcmd.rb +61 -0
  188. data/test/unit/test-bin-trepanx.rb +48 -0
  189. data/test/unit/test-cmd-alias.rb +49 -0
  190. data/test/unit/test-cmd-break.rb +23 -0
  191. data/test/unit/test-cmd-exit.rb +27 -0
  192. data/test/unit/test-cmd-help.rb +101 -0
  193. data/test/unit/test-cmd-kill.rb +48 -0
  194. data/test/unit/test-intf-user.rb +46 -0
  195. data/test/unit/test-io-input.rb +27 -0
  196. data/test/unit/test-proc-eval.rb +37 -0
  197. data/test/unit/test-proc-frame.rb +79 -0
  198. data/test/unit/test-proc-help.rb +16 -0
  199. data/test/unit/test-proc-hook.rb +30 -0
  200. data/test/unit/test-proc-load_cmds.rb +41 -0
  201. data/test/unit/test-proc-location.rb +48 -0
  202. data/test/unit/test-proc-main.rb +96 -0
  203. data/test/unit/test-proc-validate.rb +91 -0
  204. data/test/unit/test-subcmd-help.rb +51 -0
  205. metadata +337 -0
data/processor/eval.rb ADDED
@@ -0,0 +1,96 @@
1
+ # Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
2
+ class Trepan
3
+ class CmdProcessor
4
+
5
+ def debug_eval(str, max_fake_filename=15)
6
+ begin
7
+ debug_eval_with_exception(str, max_fake_filename)
8
+ rescue SyntaxError, StandardError, ScriptError => e
9
+ exception_dump(e, @settings[:stack_trace_on_error], $!.backtrace)
10
+ nil
11
+ end
12
+ end
13
+
14
+ def debug_eval_with_exception(str, max_fake_filename=15)
15
+ @frame.run(str, fake_eval_filename(str, max_fake_filename))
16
+ end
17
+
18
+ def debug_eval_no_errmsg(str, max_fake_filename=15)
19
+ begin
20
+ debug_eval_with_exception(str, max_fake_filename)
21
+ rescue SyntaxError, StandardError, ScriptError => e
22
+ nil
23
+ end
24
+ end
25
+
26
+ def eval_code(str, max_fake_filename)
27
+ obj = debug_eval(str, max_fake_filename)
28
+
29
+ idx = @user_variables
30
+ @user_variables += 1
31
+
32
+ str = "$d#{idx}"
33
+ Rubinius::Globals[str.to_sym] = obj
34
+ msg "#{str} = #{obj.inspect}"
35
+ obj
36
+ end
37
+
38
+ def exception_dump(e, stack_trace, backtrace)
39
+ str = "#{e.class} Exception:\n\t#{e.message}"
40
+ if stack_trace
41
+ str += "\n" + backtrace.map{|l| "\t#{l}"}.join("\n") rescue nil
42
+ end
43
+ msg str
44
+ # throw :debug_error
45
+ end
46
+
47
+ def fake_eval_filename(str, maxlen = 15)
48
+ fake_filename =
49
+ if maxlen < str.size
50
+ # FIXME: Guard against \" in positions 13..15?
51
+ str.inspect[0..maxlen-1] + '"...'
52
+ else
53
+ str.inspect
54
+ end
55
+ "(eval #{fake_filename})"
56
+ end
57
+
58
+ end
59
+ end
60
+
61
+ if __FILE__ == $0
62
+ # Demo it.
63
+ cmdp = Trepan::CmdProcessor.new
64
+ puts cmdp.fake_eval_filename('x = 1; y = 2')
65
+ puts cmdp.fake_eval_filename('x = 1; y = 2', 7)
66
+ def cmdp.errmsg(msg)
67
+ puts "** #{msg}"
68
+ end
69
+ def cmdp.msg(msg)
70
+ puts "#{msg}"
71
+ end
72
+ begin
73
+ 1/0
74
+ rescue Exception => exc
75
+ cmdp.exception_dump(exc, true, $!.backtrace)
76
+ puts '=' * 40
77
+ end
78
+
79
+ x = 10
80
+
81
+ require 'rubygems'; require 'require_relative'
82
+ require_relative '../app/frame'
83
+ frame = Trepan::Frame.new(self, 1, Rubinius::VM.backtrace(0)[0])
84
+ cmdp.instance_variable_set('@frame', frame)
85
+ cmdp.instance_variable_set('@settings', {:stack_trace_on_error => true})
86
+ def cmdp.errmsg(mess) ; puts mess end
87
+ # require_relative '../lib/trepanning'
88
+ # Trepan.start
89
+ puts cmdp.debug_eval('x = "#{x}"')
90
+ puts '=' * 40
91
+ puts cmdp.debug_eval('x+')
92
+ puts cmdp.debug_eval_no_errmsg('y+')
93
+ puts '=' * 40
94
+ puts cmdp.debug_eval('x+')
95
+ puts cmdp.debug_eval('y = 1; x+', 4)
96
+ end
@@ -0,0 +1,211 @@
1
+ # Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
2
+ require 'rubygems'; require 'require_relative'
3
+ require_relative '../app/frame'
4
+ require_relative '../app/util'
5
+ class Trepan
6
+ class CmdProcessor
7
+
8
+ include Util
9
+ attr_reader :current_thread
10
+
11
+ # ThreadFrame, current frame
12
+ attr_accessor :frame
13
+
14
+ # frame index in a "backtrace" command
15
+ attr_accessor :frame_index
16
+ attr_reader :hide_level
17
+
18
+ # Hash[thread_id] -> FixNum, the level of the last frame to
19
+ # show. If we called the debugger directly, then there is
20
+ # generally a portion of a backtrace we don't want to show. We
21
+ # don't need to store this for all threads, just those we want to
22
+ # hide frame on. A value of 1 means to hide just the oldest
23
+ # level. The default or showing all levels is 0.
24
+ attr_accessor :hidelevels
25
+
26
+ # Hash[container] -> file container. This gives us a way to map non-file
27
+ # container objects to a file container for display.
28
+ attr_accessor :remap_container
29
+
30
+ attr_accessor :stack_size
31
+
32
+ # top frame of current thread.
33
+ attr_accessor :top_frame
34
+ # attr_reader :threads2frames # Hash[thread_id] -> top_frame
35
+
36
+
37
+ def adjust_frame(frame_num, absolute_pos)
38
+ frame, frame_num = get_frame(frame_num, absolute_pos)
39
+ if frame
40
+ @frame = @dbgr.frame(frame_num)
41
+ @frame_index = frame_num
42
+ print_location unless @settings[:traceprint]
43
+ @line_no = @frame.line
44
+ @frame
45
+ else
46
+ nil
47
+ end
48
+ end
49
+
50
+ # def frame_container(frame, canonicalize=true)
51
+ # container =
52
+ # if @remap_container.member?(frame.source_container)
53
+ # @remap_container[frame.source_container]
54
+ # elsif frame.iseq && @remap_iseq.member?(frame.iseq.sha1)
55
+ # @remap_iseq[frame.iseq.sha1]
56
+ # else
57
+ # frame.source_container
58
+ # end
59
+
60
+ # container[1] = canonic_file(container[1]) if canonicalize
61
+ # container
62
+ # end
63
+
64
+ # Initializes the thread and frame variables: @frame, @top_frame,
65
+ # @frame_index, @current_thread, and @threads2frames
66
+ def frame_setup
67
+ @frame_index = 0
68
+ @frame = @top_frame = @dbgr.current_frame
69
+ @current_thread = @dbgr.debugee_thread
70
+ @line_no = @frame.line
71
+
72
+ @threads2frames ||= {}
73
+ @threads2frames[@current_thread] = @top_frame
74
+ set_hide_level
75
+ end
76
+
77
+ # Remove access to thread and frame variables
78
+ def frame_teardown
79
+ @top_frame = @frame = @frame_index = @current_thread = nil
80
+ @threads2frames = {}
81
+ end
82
+
83
+ def frame_initialize
84
+ @remap_container = {}
85
+ @remap_iseq = {}
86
+ @hidelevels = Hash.new(nil)
87
+ @hide_level = 0
88
+ end
89
+
90
+ def get_frame(frame_num, absolute_pos)
91
+ if absolute_pos
92
+ frame_num += @stack_size if frame_num < 0
93
+ else
94
+ frame_num += @frame_index
95
+ end
96
+
97
+ if frame_num < 0
98
+ errmsg('Adjusting would put us beyond the newest frame.')
99
+ return [nil, nil]
100
+ elsif frame_num >= @stack_size
101
+ errmsg('Adjusting would put us beyond the oldest frame.')
102
+ return [nil, nil]
103
+ end
104
+
105
+ [frame, frame_num]
106
+ end
107
+
108
+ def parent_frame
109
+ frame = @dbgr.frame(@frame.number + 1)
110
+ unless frame
111
+ errmsg "Unable to find parent frame at level #{@frame.number+1}"
112
+ return nil
113
+ end
114
+ frame
115
+ end
116
+
117
+ def set_hide_level
118
+ @hide_level =
119
+ if !@settings[:hidelevel] || @settings[:hidelevel] < 0
120
+ @settings[:hidelevel] = @hidelevels[@current_thread] =
121
+ find_main_script(@dbgr.vm_locations) || max_stack_size
122
+ else
123
+ @settings[:hidelevel]
124
+ end
125
+ max_stack_size = @dbgr.vm_locations.size
126
+ @stack_size = if @hide_level >= max_stack_size
127
+ max_stack_size else max_stack_size - @hide_level
128
+ end
129
+ end
130
+
131
+ # def get_nonsync_frame(tf)
132
+ # if (tf.stack_size > 10)
133
+ # check_frames = (0..5).map{|i| tf.prev(i).method}
134
+ # if check_frames ==
135
+ # %w(synchronize event_processor IFUNC call trace_hook IFUNC)
136
+ # return tf.prev(6)
137
+ # end
138
+ # end
139
+ # tf
140
+ # end
141
+
142
+ # def get_frame_from_thread(th)
143
+ # if th == Thread.current
144
+ # @threads2frames[th]
145
+ # else
146
+ # # FIXME: Check to see if we are blocked on entry to debugger.
147
+ # # If so, walk back frames.
148
+ # tf = get_nonsync_frame(th.threadframe)
149
+ # @threads2frames = tf
150
+ # end
151
+ # end
152
+
153
+ # # The dance we have to do to set debugger frame state to
154
+ # # `frame', which is in the thread with id `thread_id'. We may
155
+ # # need to the hide initial debugger frames.
156
+ # def find_and_set_debugged_frame(th, position)
157
+
158
+ # thread = threading._active[thread_id]
159
+ # thread_name = thread.getName()
160
+ # if (!@settings['dbg_pydbgr'] &&
161
+ # thread_name == Mthread.current_thread_name())
162
+ # # The frame we came in on ('current_thread_name') is
163
+ # # the same as the one we want to switch to. In this case
164
+ # # we need to some debugger frames are in this stack so
165
+ # # we need to remove them.
166
+ # newframe = Mthread.find_debugged_frame(frame)
167
+ # frame = newframe unless newframe
168
+ # end
169
+ # ## FIXME: else: we might be blocked on other threads which are
170
+ # # about to go into the debugger it not for the fact this one got there
171
+ # # first. Possibly in the future we want
172
+ # # to hide the blocks into threading of that locking code as well.
173
+
174
+ # # Set stack to new frame
175
+ # @frame, @curindex = Mcmdproc.get_stack(frame, nil, self.proc)
176
+ # @proc.stack, @proc.curindex = self.stack, self.curindex
177
+
178
+ # # @frame_thread_name = thread_name
179
+ # end
180
+ end
181
+ end
182
+
183
+ if __FILE__ == $0
184
+ # Demo it.
185
+ require_relative 'main' # Have to include before defining CmdProcessor!
186
+ # FIXME
187
+ class Trepan::CmdProcessor
188
+ def errmsg(msg)
189
+ puts msg
190
+ end
191
+ def print_location
192
+ puts "frame location: #{frame.file} #{frame.line}"
193
+ end
194
+ end
195
+
196
+ require_relative './mock'
197
+ dbgr, cmd = MockDebugger::setup('exit', false)
198
+ # require_relative '../lib/trepanning'
199
+ # Trepan.start(:set_restart => true)
200
+ proc = cmd.proc
201
+ 0.upto(proc.stack_size-1) { |i| proc.adjust_frame(i, true) }
202
+ puts '*' * 10
203
+ proc.adjust_frame(-1, true)
204
+ proc.adjust_frame(0, true)
205
+ puts '*' * 10
206
+ proc.stack_size.times { proc.adjust_frame(1, false) }
207
+ puts '*' * 10
208
+ proc.adjust_frame(proc.stack_size-1, true)
209
+ proc.stack_size.times { proc.adjust_frame(-1, false) }
210
+
211
+ end
data/processor/help.rb ADDED
@@ -0,0 +1,72 @@
1
+ # Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
2
+ class Trepan
3
+ module Help
4
+
5
+ def abbrev_stringify(name, min_abbrev)
6
+ "(#{name[0..min_abbrev-1]})#{name[min_abbrev..-1]}"
7
+ end
8
+
9
+ def summary_help(subcmd)
10
+ # Set class constant SHORT_HELP to be the first line of HELP
11
+ # unless it has been defined in the class already.
12
+ # The below was the simplest way I could find to do this since
13
+ # we are the super class but want to set the subclass's constant.
14
+ # defined? didn't seem to work here.
15
+ c = subcmd.class.constants
16
+ if c.member?('HELP') and !c.member?('SHORT_HELP')
17
+ short_help = subcmd.class.const_get('HELP').split("\n")[0].chomp('.')
18
+ subcmd.class.const_set(:SHORT_HELP, short_help)
19
+ end
20
+
21
+ ' %-12s -- %s' %
22
+ [abbrev_stringify(obj_const(subcmd, :NAME),
23
+ obj_const(subcmd, :MIN_ABBREV)),
24
+ obj_const(subcmd, :SHORT_HELP)]
25
+ end
26
+
27
+ # We were given cmd without a subcommand; cmd is something
28
+ # like "show", "info" or "set". Generally this means list
29
+ # all of the subcommands.
30
+ def summary_list(name, subcmds)
31
+ msg "List of #{name} commands (with minimum abbreviation in parenthesis):"
32
+ subcmds.list.each do |subcmd_name|
33
+ # Some commands have lots of output.
34
+ # they are excluded here because 'in_list' is false.
35
+ msg summary_help(subcmds.subcmds[subcmd_name])
36
+ end
37
+ end
38
+
39
+
40
+ # Error message when subcommand asked for but doesn't exist
41
+ def undefined_subcmd(cmd, subcmd)
42
+ errmsg(('Undefined "%s" subcommand: "%s". ' +
43
+ 'Try "help %s *".') % [cmd, subcmd, cmd])
44
+ end
45
+
46
+ end
47
+ end
48
+
49
+ if __FILE__ == $0
50
+ class TestClass
51
+ include Trepan::Help
52
+ HELP = 'TestClass HELP.
53
+
54
+ Long description goes here.'
55
+ MIN_ABBREV = 1
56
+ NAME = File.basename(__FILE__)
57
+ def obj_const(obj, name)
58
+ obj.class.const_get(name)
59
+ end
60
+ def msg(mess)
61
+ puts mess
62
+ end
63
+ def errmsg(mess)
64
+ puts "***#{mess}"
65
+ end
66
+ def initialize
67
+ puts summary_help(self)
68
+ undefined_subcmd('foo', 'bar')
69
+ end
70
+ end
71
+ TestClass.new
72
+ end
data/processor/hook.rb ADDED
@@ -0,0 +1,133 @@
1
+ # Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
2
+ class Trepan
3
+ class CmdProcessor
4
+ # Command processor hooks.
5
+ attr_reader :autodis_hook
6
+ attr_reader :autoirb_hook
7
+ attr_reader :autolist_hook
8
+ attr_reader :debug_dbgr_hook
9
+ attr_reader :display_hook
10
+ attr_reader :timer_hook
11
+ attr_reader :trace_hook
12
+ attr_reader :tracebuf_hook
13
+ attr_reader :unconditional_prehooks
14
+ attr_reader :cmdloop_posthooks
15
+ attr_reader :cmdloop_prehooks
16
+
17
+ # Used to time how long a debugger action takes
18
+ attr_accessor :time_last
19
+
20
+ class Hook
21
+ attr_accessor :list
22
+
23
+ def initialize(list=[])
24
+ @list = list
25
+ end
26
+
27
+ def delete_by_name(delete_name)
28
+ @list.delete_if {|hook_name, priority, hook| hook_name == delete_name}
29
+ end
30
+
31
+ def empty?
32
+ @list.empty?
33
+ end
34
+
35
+ def insert(priority, name, hook)
36
+ insert_loc = @list.size # at end
37
+ @list.each_with_index do |entry, index|
38
+ n, p, h = entry
39
+ if priority > p
40
+ insert_loc = index
41
+ break
42
+ end
43
+ end
44
+ @list.insert(insert_loc, [name, priority, hook])
45
+ end
46
+
47
+ def insert_if_new(priority, name, hook)
48
+ insert(priority, name, hook) unless
49
+ @list.find {|try_name, try_priority, try_hook| try_name == name}
50
+ end
51
+
52
+ # Run each function in `hooks' with args
53
+ def run(*args)
54
+ @list.each do |name, priority, hook|
55
+ hook.call(name, *args)
56
+ end
57
+ end
58
+
59
+ # Could add delete_at and delete if necessary.
60
+ end
61
+
62
+ def hook_initialize(commands)
63
+ @cmdloop_posthooks = Hook.new
64
+ @cmdloop_prehooks = Hook.new
65
+ @unconditional_prehooks = Hook.new
66
+
67
+ irb_cmd = commands['irb']
68
+ @autoirb_hook = ['autoirb',
69
+ Proc.new{|*args| irb_cmd.run(['irb']) if irb_cmd}]
70
+
71
+ @debug_dbgr_hook = ['dbgdbgr',
72
+ Proc.new{|*args|
73
+ if settings[:debugdbgr]
74
+ $trepan_cmdproc = self
75
+ $trepan_frame = @frame
76
+ else
77
+ $trepan_cmdproc = nil
78
+ $trepan_frame = nil
79
+ end}]
80
+
81
+ display_cmd = commands['display']
82
+ @display_hook = ['display',
83
+ Proc.new{|*args| display_cmd.run(['display']) if display_cmd}]
84
+
85
+ # FIXME: generalize for any command run
86
+ dis_cmd = commands['disassemble']
87
+ @autodis_hook = ['autodis',
88
+ Proc.new{|*args| dis_cmd.run(['disassemble']) if dis_cmd}]
89
+
90
+ list_cmd = commands['list']
91
+ @autolist_hook = ['autolist',
92
+ Proc.new{|*args| list_cmd.run(['list']) if list_cmd}]
93
+
94
+ @timer_hook = ['timer',
95
+ Proc.new{|*args|
96
+ now = Time.now
97
+ msg("%g seconds" %
98
+ (now - @time_last)) if @time_last
99
+ @time_last = now
100
+ }]
101
+ @timer_posthook = ['timer', Proc.new{|*args| @time_last = Time.now}]
102
+ @trace_hook = ['trace',
103
+ Proc.new{|*args| print_location}]
104
+ @tracebuf_hook = ['tracebuffer',
105
+ Proc.new{|*args| @eventbuf.append(@core.event, @frame,
106
+ @core.hook_arg)}]
107
+ end
108
+
109
+ end
110
+ end
111
+ if __FILE__ == $0
112
+ # Demo it.
113
+ hooks = Trepan::CmdProcessor::Hook.new
114
+ hooks.run(5)
115
+ hook1 = Proc.new {|name, a| puts "#{name} called with #{a}"}
116
+ hooks = Trepan::CmdProcessor::Hook.new()
117
+ hooks.insert(-1, 'hook1', hook1)
118
+ p hooks.list
119
+ hooks.insert_if_new(-1, 'hook1', hook1)
120
+ puts '-' * 30
121
+ p hooks.list
122
+ hooks.run(10)
123
+ puts '-' * 30
124
+ hooks.insert(-1, 'hook2', hook1)
125
+ hooks.run(20)
126
+ puts '-' * 30
127
+ hooks.delete_by_name('hook2')
128
+ hooks.run(30)
129
+ puts '-' * 30
130
+ hooks.delete_by_name('hook1')
131
+ hooks.run(30)
132
+ puts '-' * 30
133
+ end
@@ -0,0 +1,101 @@
1
+ # Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net> Part of
2
+ # Trepan::CmdProcess that loads up debugger commands from builtin and
3
+ # user directories.
4
+ # Sets @commands, @aliases, @macros
5
+ class Trepan
6
+ class CmdProcessor
7
+
8
+ attr_reader :aliases # Hash[String] of command names
9
+ # indexed by alias name
10
+ attr_reader :commands # Hash[String] of command objects
11
+ # indexed by name
12
+ attr_reader :macros # Hash[String] of Proc objects
13
+ # indexed by macro name.
14
+
15
+ # "initialize" for multi-file class. Called from main.rb's "initialize".
16
+ def load_cmds_initialize
17
+ @commands = {}
18
+ @aliases = {}
19
+ @macros = {}
20
+
21
+ cmd_dirs = [ File.join(File.dirname(__FILE__), 'command') ]
22
+ cmd_dirs << @settings[:user_cmd_dir] if @settings[:user_cmd_dir]
23
+ cmd_dirs.each do |cmd_dir|
24
+ load_debugger_commands(cmd_dir) if File.directory?(cmd_dir)
25
+ end
26
+ end
27
+
28
+ # Loads in debugger commands by require'ing each ruby file in the
29
+ # 'command' directory. Then a new instance of each class of the
30
+ # form Trepan::xxCommand is added to @commands and that array
31
+ # is returned.
32
+
33
+ def load_debugger_commands(cmd_dir)
34
+ Dir.glob(File.join(cmd_dir, '*.rb')).each do |rb|
35
+ require rb
36
+ end if File.directory?(cmd_dir)
37
+ # Instantiate each Command class found by the above require(s).
38
+ Trepan::Command.constants.grep(/.Command$/).each do |command|
39
+ # Note: there is probably a non-eval way to instantiate the
40
+ # command, but I don't know it. And eval works.
41
+ new_cmd = "Trepan::Command::#{command}.new(self)"
42
+ cmd = self.instance_eval(new_cmd)
43
+
44
+ # Add to list of commands and aliases.
45
+ cc = cmd.class
46
+ cmd_name = cc.const_get(:NAME)
47
+ if cc.constants.member?('ALIASES')
48
+ aliases= cc.const_get('ALIASES')
49
+ aliases.each {|a| @aliases[a] = cmd_name}
50
+ end
51
+ @commands[cmd_name] = cmd
52
+ end
53
+ end
54
+
55
+ # Looks up cmd_array[0] in @commands and runs that. We do lots of
56
+ # validity testing on cmd_array.
57
+ def run_cmd(cmd_array)
58
+ unless cmd_array.is_a?(Array)
59
+ errmsg "run_cmd argument should be an Array, got: #{cmd_array.class}"
60
+ return
61
+ end
62
+ if cmd_array.detect{|item| !item.is_a?(String)}
63
+ errmsg "run_cmd argument Array should only contain strings. " +
64
+ "Got #{cmd_array.inspect}"
65
+ return
66
+ end
67
+ if cmd_array.empty?
68
+ errmsg "run_cmd Array should have at least one item. " +
69
+ "Got: #{cmd_array.inspect}"
70
+ return
71
+ end
72
+ cmd_name = cmd_array[0]
73
+ if @commands.member?(cmd_name)
74
+ @commands[cmd_name].run(cmd_array)
75
+ end
76
+ end
77
+ end
78
+ end
79
+ if __FILE__ == $0
80
+ cmdproc = Trepan::CmdProcessor.new
81
+ cmddir = File.join(File.dirname(__FILE__), 'command')
82
+ cmdproc.instance_variable_set('@settings', {})
83
+ cmdproc.load_cmds_initialize
84
+ require 'columnize'
85
+ puts Columnize.columnize(cmdproc.commands.keys.sort)
86
+ puts '=' * 20
87
+ puts Columnize.columnize(cmdproc.aliases.keys.sort)
88
+ puts '=' * 20
89
+
90
+ def cmdproc.errmsg(mess)
91
+ puts "** #{mess}"
92
+ end
93
+
94
+ def cmdproc.msg(mess)
95
+ puts mess
96
+ end
97
+
98
+ cmdproc.run_cmd('foo') # Invalid - not an Array
99
+ cmdproc.run_cmd([]) # Invalid - empty Array
100
+ cmdproc.run_cmd(['list', 5]) # Invalid - nonstring arg
101
+ end