trepanning 0.0.4

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 (219) hide show
  1. data/ChangeLog +4422 -0
  2. data/LICENSE +23 -0
  3. data/NEWS +12 -0
  4. data/README.textile +56 -0
  5. data/Rakefile +171 -0
  6. data/app/Makefile +7 -0
  7. data/app/breakpoint.rb +157 -0
  8. data/app/brkptmgr.rb +149 -0
  9. data/app/condition.rb +22 -0
  10. data/app/core.rb +203 -0
  11. data/app/default.rb +54 -0
  12. data/app/disassemble.rb +61 -0
  13. data/app/display.rb +148 -0
  14. data/app/file.rb +135 -0
  15. data/app/frame.rb +275 -0
  16. data/app/irb.rb +112 -0
  17. data/app/mock.rb +22 -0
  18. data/app/options.rb +122 -0
  19. data/app/run.rb +95 -0
  20. data/app/thread.rb +24 -0
  21. data/app/util.rb +32 -0
  22. data/bin/trepan +63 -0
  23. data/data/custom_require.rb +44 -0
  24. data/data/irbrc +55 -0
  25. data/data/prelude.rb +38 -0
  26. data/interface/base_intf.rb +95 -0
  27. data/interface/script.rb +103 -0
  28. data/interface/user.rb +90 -0
  29. data/io/base_io.rb +92 -0
  30. data/io/input.rb +111 -0
  31. data/io/string_array.rb +155 -0
  32. data/lib/Makefile +7 -0
  33. data/lib/trepanning.rb +277 -0
  34. data/processor/breakpoint.rb +108 -0
  35. data/processor/command/alias.rb +55 -0
  36. data/processor/command/backtrace.rb +95 -0
  37. data/processor/command/base/cmd.rb +97 -0
  38. data/processor/command/base/subcmd.rb +207 -0
  39. data/processor/command/base/submgr.rb +178 -0
  40. data/processor/command/base/subsubcmd.rb +102 -0
  41. data/processor/command/base/subsubmgr.rb +182 -0
  42. data/processor/command/break.rb +85 -0
  43. data/processor/command/condition.rb +64 -0
  44. data/processor/command/continue.rb +61 -0
  45. data/processor/command/debug.rb +85 -0
  46. data/processor/command/delete.rb +54 -0
  47. data/processor/command/directory.rb +43 -0
  48. data/processor/command/disable.rb +65 -0
  49. data/processor/command/disassemble.rb +103 -0
  50. data/processor/command/display.rb +81 -0
  51. data/processor/command/down.rb +56 -0
  52. data/processor/command/enable.rb +43 -0
  53. data/processor/command/exit.rb +54 -0
  54. data/processor/command/finish.rb +81 -0
  55. data/processor/command/frame.rb +117 -0
  56. data/processor/command/help.rb +146 -0
  57. data/processor/command/info.rb +28 -0
  58. data/processor/command/info_subcmd/args.rb +56 -0
  59. data/processor/command/info_subcmd/breakpoints.rb +162 -0
  60. data/processor/command/info_subcmd/file.rb +162 -0
  61. data/processor/command/info_subcmd/frame.rb +39 -0
  62. data/processor/command/info_subcmd/iseq.rb +83 -0
  63. data/processor/command/info_subcmd/locals.rb +88 -0
  64. data/processor/command/info_subcmd/program.rb +54 -0
  65. data/processor/command/info_subcmd/registers.rb +72 -0
  66. data/processor/command/info_subcmd/registers_subcmd/dfp.rb +38 -0
  67. data/processor/command/info_subcmd/registers_subcmd/helper.rb +40 -0
  68. data/processor/command/info_subcmd/registers_subcmd/lfp.rb +54 -0
  69. data/processor/command/info_subcmd/registers_subcmd/pc.rb +44 -0
  70. data/processor/command/info_subcmd/registers_subcmd/sp.rb +75 -0
  71. data/processor/command/info_subcmd/return.rb +40 -0
  72. data/processor/command/info_subcmd/thread.rb +106 -0
  73. data/processor/command/irb.rb +106 -0
  74. data/processor/command/kill.rb +58 -0
  75. data/processor/command/list.rb +327 -0
  76. data/processor/command/macro.rb +65 -0
  77. data/processor/command/next.rb +89 -0
  78. data/processor/command/nocache.rb +33 -0
  79. data/processor/command/print.rb +37 -0
  80. data/processor/command/ps.rb +40 -0
  81. data/processor/command/quit.rb +62 -0
  82. data/processor/command/raise.rb +47 -0
  83. data/processor/command/reload.rb +28 -0
  84. data/processor/command/reload_subcmd/command.rb +34 -0
  85. data/processor/command/restart.rb +57 -0
  86. data/processor/command/save.rb +60 -0
  87. data/processor/command/set.rb +47 -0
  88. data/processor/command/set_subcmd/auto.rb +27 -0
  89. data/processor/command/set_subcmd/auto_subcmd/eval.rb +67 -0
  90. data/processor/command/set_subcmd/auto_subcmd/irb.rb +49 -0
  91. data/processor/command/set_subcmd/auto_subcmd/list.rb +51 -0
  92. data/processor/command/set_subcmd/basename.rb +39 -0
  93. data/processor/command/set_subcmd/debug.rb +27 -0
  94. data/processor/command/set_subcmd/debug_subcmd/dbgr.rb +49 -0
  95. data/processor/command/set_subcmd/debug_subcmd/except.rb +35 -0
  96. data/processor/command/set_subcmd/debug_subcmd/macro.rb +35 -0
  97. data/processor/command/set_subcmd/debug_subcmd/skip.rb +35 -0
  98. data/processor/command/set_subcmd/debug_subcmd/stack.rb +45 -0
  99. data/processor/command/set_subcmd/different.rb +67 -0
  100. data/processor/command/set_subcmd/events.rb +71 -0
  101. data/processor/command/set_subcmd/max.rb +35 -0
  102. data/processor/command/set_subcmd/max_subcmd/list.rb +50 -0
  103. data/processor/command/set_subcmd/max_subcmd/stack.rb +60 -0
  104. data/processor/command/set_subcmd/max_subcmd/string.rb +53 -0
  105. data/processor/command/set_subcmd/max_subcmd/width.rb +50 -0
  106. data/processor/command/set_subcmd/return.rb +66 -0
  107. data/processor/command/set_subcmd/sp.rb +62 -0
  108. data/processor/command/set_subcmd/substitute.rb +25 -0
  109. data/processor/command/set_subcmd/substitute_subcmd/eval.rb +98 -0
  110. data/processor/command/set_subcmd/substitute_subcmd/path.rb +55 -0
  111. data/processor/command/set_subcmd/substitute_subcmd/string.rb +72 -0
  112. data/processor/command/set_subcmd/timer.rb +68 -0
  113. data/processor/command/set_subcmd/trace.rb +43 -0
  114. data/processor/command/set_subcmd/trace_subcmd/buffer.rb +56 -0
  115. data/processor/command/set_subcmd/trace_subcmd/print.rb +54 -0
  116. data/processor/command/set_subcmd/trace_subcmd/var.rb +61 -0
  117. data/processor/command/show.rb +27 -0
  118. data/processor/command/show_subcmd/alias.rb +50 -0
  119. data/processor/command/show_subcmd/args.rb +50 -0
  120. data/processor/command/show_subcmd/auto.rb +27 -0
  121. data/processor/command/show_subcmd/auto_subcmd/eval.rb +38 -0
  122. data/processor/command/show_subcmd/auto_subcmd/irb.rb +34 -0
  123. data/processor/command/show_subcmd/auto_subcmd/list.rb +36 -0
  124. data/processor/command/show_subcmd/basename.rb +28 -0
  125. data/processor/command/show_subcmd/debug.rb +27 -0
  126. data/processor/command/show_subcmd/debug_subcmd/dbgr.rb +31 -0
  127. data/processor/command/show_subcmd/debug_subcmd/except.rb +33 -0
  128. data/processor/command/show_subcmd/debug_subcmd/macro.rb +32 -0
  129. data/processor/command/show_subcmd/debug_subcmd/skip.rb +33 -0
  130. data/processor/command/show_subcmd/debug_subcmd/stack.rb +32 -0
  131. data/processor/command/show_subcmd/different.rb +37 -0
  132. data/processor/command/show_subcmd/events.rb +40 -0
  133. data/processor/command/show_subcmd/macro.rb +45 -0
  134. data/processor/command/show_subcmd/max.rb +31 -0
  135. data/processor/command/show_subcmd/max_subcmd/list.rb +39 -0
  136. data/processor/command/show_subcmd/max_subcmd/stack.rb +35 -0
  137. data/processor/command/show_subcmd/max_subcmd/string.rb +41 -0
  138. data/processor/command/show_subcmd/max_subcmd/width.rb +36 -0
  139. data/processor/command/show_subcmd/trace.rb +29 -0
  140. data/processor/command/show_subcmd/trace_subcmd/buffer.rb +84 -0
  141. data/processor/command/show_subcmd/trace_subcmd/print.rb +38 -0
  142. data/processor/command/source.rb +74 -0
  143. data/processor/command/step.rb +139 -0
  144. data/processor/command/stepi.rb +63 -0
  145. data/processor/command/unalias.rb +44 -0
  146. data/processor/command/undisplay.rb +63 -0
  147. data/processor/command/up.rb +92 -0
  148. data/processor/default.rb +45 -0
  149. data/processor/display.rb +17 -0
  150. data/processor/eval.rb +88 -0
  151. data/processor/eventbuf.rb +131 -0
  152. data/processor/frame.rb +230 -0
  153. data/processor/help.rb +72 -0
  154. data/processor/hook.rb +128 -0
  155. data/processor/load_cmds.rb +102 -0
  156. data/processor/location.rb +126 -0
  157. data/processor/main.rb +364 -0
  158. data/processor/mock.rb +100 -0
  159. data/processor/msg.rb +26 -0
  160. data/processor/running.rb +170 -0
  161. data/processor/subcmd.rb +159 -0
  162. data/processor/validate.rb +395 -0
  163. data/test/example/fname with blank.rb +1 -0
  164. data/test/example/gcd-xx.rb +18 -0
  165. data/test/example/gcd.rb +19 -0
  166. data/test/example/gcd1.rb +24 -0
  167. data/test/example/null.rb +1 -0
  168. data/test/example/thread1.rb +3 -0
  169. data/test/functional/fn_helper.rb +119 -0
  170. data/test/functional/test-break.rb +87 -0
  171. data/test/functional/test-condition.rb +59 -0
  172. data/test/functional/test-debugger-call-bug.rb +31 -0
  173. data/test/functional/test-delete.rb +71 -0
  174. data/test/functional/test-finish.rb +44 -0
  175. data/test/functional/test-immediate-step-bug.rb +35 -0
  176. data/test/functional/test-next.rb +77 -0
  177. data/test/functional/test-raise.rb +73 -0
  178. data/test/functional/test-return.rb +100 -0
  179. data/test/functional/test-step.rb +274 -0
  180. data/test/functional/test-stepbug.rb +40 -0
  181. data/test/functional/test-trace-var.rb +40 -0
  182. data/test/functional/tmp/b1.rb +5 -0
  183. data/test/functional/tmp/s1.rb +9 -0
  184. data/test/functional/tmp/t2.rb +6 -0
  185. data/test/integration/file-diff.rb +88 -0
  186. data/test/integration/helper.rb +52 -0
  187. data/test/integration/test-fname-with-blank.rb +11 -0
  188. data/test/integration/test-quit.rb +11 -0
  189. data/test/integration/try-test-enable.rb +11 -0
  190. data/test/unit/cmd-helper.rb +44 -0
  191. data/test/unit/test-app-brkpt.rb +30 -0
  192. data/test/unit/test-app-brkptmgr.rb +56 -0
  193. data/test/unit/test-app-disassemble.rb +60 -0
  194. data/test/unit/test-app-file.rb +46 -0
  195. data/test/unit/test-app-frame.rb +49 -0
  196. data/test/unit/test-app-options.rb +60 -0
  197. data/test/unit/test-app-run.rb +19 -0
  198. data/test/unit/test-app-thread.rb +25 -0
  199. data/test/unit/test-app-util.rb +17 -0
  200. data/test/unit/test-base-subcmd.rb +59 -0
  201. data/test/unit/test-bin-trepan.rb +48 -0
  202. data/test/unit/test-cmd-alias.rb +50 -0
  203. data/test/unit/test-cmd-break.rb +80 -0
  204. data/test/unit/test-cmd-endisable.rb +59 -0
  205. data/test/unit/test-cmd-help.rb +100 -0
  206. data/test/unit/test-cmd-kill.rb +47 -0
  207. data/test/unit/test-cmd-quit.rb +26 -0
  208. data/test/unit/test-cmd-step.rb +45 -0
  209. data/test/unit/test-intf-user.rb +45 -0
  210. data/test/unit/test-io-input.rb +26 -0
  211. data/test/unit/test-proc-eval.rb +26 -0
  212. data/test/unit/test-proc-frame.rb +77 -0
  213. data/test/unit/test-proc-help.rb +15 -0
  214. data/test/unit/test-proc-hook.rb +29 -0
  215. data/test/unit/test-proc-load_cmds.rb +40 -0
  216. data/test/unit/test-proc-main.rb +99 -0
  217. data/test/unit/test-proc-validate.rb +90 -0
  218. data/test/unit/test-subcmd-help.rb +48 -0
  219. metadata +358 -0
@@ -0,0 +1,327 @@
1
+ # Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
2
+ # -*- coding: utf-8 -*-
3
+ require 'linecache'
4
+ require_relative 'base/cmd'
5
+
6
+ class Trepan::Command::ListCommand < Trepan::Command
7
+ unless defined?(HELP)
8
+ HELP =
9
+ "list[>] [MODULE] [FIRST [NUM]]
10
+ list[>] LOCATION [NUM]
11
+
12
+ List source code.
13
+
14
+ Without arguments, prints lines centered around the current
15
+ line. If this is the first list command issued since the debugger
16
+ command loop was entered, then the current line is the current
17
+ frame. If a subsequent list command was issued with no intervening
18
+ frame changing, then that is start the line after we last one
19
+ previously shown.
20
+
21
+ If the command has a '>' suffix, then lines centering is disabled and
22
+ listing begins at the specificed location.
23
+
24
+ The number of line to show is controled by the debugger listsize
25
+ setting. Use 'set listsize' or 'show listsize' to see or set the
26
+ value.
27
+
28
+ \"list -\" shows lines before a previous listing.
29
+
30
+ A LOCATION is a either
31
+ - number, e.g. 5,
32
+ - a function, e.g. join or os.path.join
33
+ - a module, e.g. os or os.path
34
+ - a filename, colon, and a number, e.g. foo.rb:5,
35
+ - or a module name and a number, e.g,. os.path:5.
36
+ - a '.' for the current line number
37
+ - a '-' for the lines before the current line number
38
+
39
+ If the location form is used with a subsequent parameter, the
40
+ parameter is the starting line number. When there two numbers are
41
+ given, the last number value is treated as a stopping line unless it
42
+ is less than the start line, in which case it is taken to mean the
43
+ number of lines to list instead.
44
+
45
+ Wherever a number is expected, it does not need to be a constant --
46
+ just something that evaluates to a positive integer.
47
+
48
+ Some examples:
49
+
50
+ list 5 # List centered around line 5
51
+ list 4+1 # Same as above.
52
+ list 5> # List starting at line 5
53
+ list foo.rb:5 # List centered around line 5 of foo.rb
54
+ list foo.rb 5 # Same as above.
55
+ list foo.rb:5> # List starting around line 5 of foo.rb
56
+ list foo.rb 5 6 # list lines 5 and 6 of foo.rb
57
+ list foo.rb 5 2 # Same as above, since 2 < 5.
58
+ list foo.rb:5 2 # Same as above
59
+ list FileUtils.cp # List lines around the FileUtils.cp function.
60
+ list . # List lines centered from where we currently are stopped
61
+ list - # List lines previous to those just shown
62
+
63
+ The output of the list command give a line number, and some status
64
+ information about the line and the text of the line. Here is some
65
+ hypothetical list output modeled roughly around line 251 of one
66
+ version of this code:
67
+
68
+ 251 cmd.proc.frame_setup(tf)
69
+ 252 -> brkpt_cmd.run(['break'])
70
+ 253 B01 line = __LINE__
71
+ 254 b02 cmd.run(['list', __LINE__.to_s])
72
+ 255 t03 puts '--' * 10
73
+
74
+ Line 251 has nothing special about it. Line 252 is where we are
75
+ currently stopped. On line 253 there is a breakpoint 1 which is
76
+ enabled, while at line 255 there is an breakpoint 2 which is
77
+ disabled."
78
+
79
+ ALIASES = %w(l list> l>)
80
+ CATEGORY = 'files'
81
+ MAX_ARGS = 3
82
+ NAME = File.basename(__FILE__, '.rb')
83
+ SHORT_HELP = 'List source code'
84
+ end
85
+
86
+ # What a f*cking mess. Necessitated I suppose because we want to
87
+ # allow somewhat flexible parsing with either module names, files or none
88
+ # and optional line counts or end-line numbers.
89
+
90
+ # Parses arguments for the "list" command and returns the tuple:
91
+ # filename, start, last
92
+ # or sets these to nil if there was some problem.
93
+ def parse_list_cmd(args, listsize, center_correction)
94
+
95
+ frame = @proc.frame
96
+
97
+ container = @proc.frame_container(frame, false)
98
+
99
+ # FIXME: put into a helper routine
100
+ # See also duplicate code in print_location
101
+ if container[0] != 'file'
102
+ try_container = container
103
+ while try_container[0] != 'file' && frame.prev do
104
+ frame = frame.prev
105
+ try_container = @proc.frame_container(frame, false)
106
+ end
107
+ container = try_container if try_container[0] == 'file'
108
+ end
109
+
110
+ filename = container[1]
111
+
112
+ last = nil
113
+ if args.empty? and not frame
114
+ errmsg("No Ruby program loaded.")
115
+ return nil, nil, nil
116
+ end
117
+
118
+ if args.size > 0
119
+ if args[0] == '-'
120
+ return no_frame_msg unless @proc.line_no
121
+ first = [1, @proc.line_no - 2*listsize - 1].max
122
+ elsif args[0] == '.'
123
+ return no_frame_msg unless @proc.line_no
124
+ first = [1, @proc.frame_line - center_correction].max
125
+ else
126
+ modfunc, container, first = @proc.parse_position(args[0])
127
+ if first == nil and modfunc == nil
128
+ # error should have been shown previously
129
+ return nil, nil, nil
130
+ end
131
+ if args.size == 1
132
+ first = 1 if !first and modfunc
133
+ first = [1, first - center_correction].max
134
+ elsif args.size == 2 or (args.size == 3 and modfunc)
135
+ opts = {
136
+ :msg_on_error =>
137
+ 'Starting line expected, got %s.' % args[-1]
138
+ }
139
+ num = @proc.get_an_int(args[1], opts)
140
+
141
+ return nil, nil, nil unless num
142
+ if modfunc
143
+ if first
144
+ first = num
145
+ if args.size == 3 and modfunc
146
+ opts[:msg_on_error] = ('last or count parameter expected, ' +
147
+ 'got: %s.' % args[2])
148
+ last = @proc.get_an_int(args[2], opts)
149
+ end
150
+ else
151
+ last = num
152
+ end
153
+ else
154
+ first = num - center_correction
155
+ end
156
+ if last and last < first
157
+ # Assume last is a count rather than an end line number
158
+ last = first + last - 1
159
+ end
160
+ elsif not modfunc
161
+ errmsg('At most 2 parameters allowed when no module' +
162
+ ' name is found/given. Saw: %d parameters' % args.size)
163
+ return nil, nil, nil
164
+ else
165
+ errmsg(('At most 3 parameters allowed when a module' +
166
+ ' name is given. Saw: %d parameters') % args.size)
167
+ return nil, nil, nil
168
+ end
169
+ end
170
+ elsif !@proc.line_no and frame
171
+ first = [1, @proc.frame_line - center_correction].max
172
+ else
173
+ first = [1, @proc.line_no - center_correction].max
174
+ end
175
+ last = first + listsize - 1 unless last
176
+
177
+ LineCache::cache(container[1]) unless
178
+ 'file' != container[0] || LineCache::cached?(container[1])
179
+ return container, first, last
180
+ end
181
+
182
+ def no_frame_msg
183
+ errmsg("No Ruby program loaded.")
184
+ return nil, nil, nil
185
+ end
186
+
187
+ def run(args)
188
+ listsize = settings[:maxlist]
189
+ center_correction =
190
+ if args[0][-1..-1] == '>'
191
+ 0
192
+ else
193
+ (listsize-1) / 2
194
+ end
195
+
196
+ container, first, last =
197
+ parse_list_cmd(args[1..-1], listsize, center_correction)
198
+ frame = @proc.frame
199
+ return unless container
200
+ breaklist = @proc.brkpts.line_breaks(container)
201
+
202
+ # We now have range information. Do the listing.
203
+ max_line = LineCache::size(container[1])
204
+ unless max_line
205
+ errmsg('File "%s" not found.' % container[1])
206
+ return
207
+ end
208
+
209
+ if first > max_line
210
+ errmsg('Bad line range [%d...%d]; file "%s" has only %d lines' %
211
+ [first, last, container[1], max_line])
212
+ return
213
+ end
214
+
215
+ if last > max_line
216
+ # msg('End position changed to last line %d ' % max_line)
217
+ last = max_line
218
+ end
219
+
220
+ begin
221
+ first.upto(last).each do |lineno|
222
+ line = LineCache::getline(container[1], lineno,
223
+ @proc.reload_on_change).chomp
224
+ unless line
225
+ msg('[EOF]')
226
+ break
227
+ end
228
+ s = '%3d' % lineno
229
+ s = s + ' ' if s.size < 4
230
+ s += if breaklist.member?(lineno)
231
+ bp = breaklist[lineno]
232
+ a_pad = '%02d' % bp.id
233
+ bp.icon_char
234
+ else
235
+ a_pad = ' '
236
+ ' '
237
+ end
238
+ s += (frame && lineno == @proc.frame_line &&
239
+ container == frame.source_container) ? '->' : a_pad
240
+ msg(s + "\t" + line)
241
+ @proc.line_no = lineno
242
+ end
243
+ rescue => e
244
+ errmsg e if settings[:debugexcept]
245
+ end
246
+ end
247
+ end
248
+
249
+ if __FILE__ == $0
250
+ if not (ARGV.size == 1 && ARGV[0] == 'noload')
251
+ ISEQS__ = {}
252
+ SCRIPT_ISEQS__ = {}
253
+ ARGV[0..-1] = ['noload']
254
+ load(__FILE__)
255
+ else
256
+ require_relative '../location'
257
+ require_relative '../mock'
258
+ require_relative '../frame'
259
+ name = File.basename(__FILE__, '.rb')
260
+ dbgr, cmd = MockDebugger::setup(name)
261
+ cmd.proc.send('frame_initialize')
262
+ LineCache::cache(__FILE__)
263
+ cmd.run(['list'])
264
+ cmd.run(['list', __FILE__ + ':10'])
265
+
266
+ def run_cmd(cmd, args)
267
+ seps = '--' * 10
268
+ puts "%s %s %s" % [seps, args.join(' '), seps]
269
+ cmd.run(args)
270
+ end
271
+
272
+
273
+ load 'tmpdir.rb'
274
+ run_cmd(cmd, %w(list tmpdir.rb 10))
275
+ run_cmd(cmd, %w(list tmpdir.rb))
276
+
277
+ # cmd.proc.frame = sys._getframe()
278
+ # cmd.proc.setup()
279
+ # cmd.run(['list'])
280
+
281
+ run_cmd(cmd, %w(list .))
282
+ run_cmd(cmd, %w(list 30))
283
+
284
+ # cmd.run(['list', '9+1'])
285
+
286
+ run_cmd(cmd, %w(list> 10))
287
+ run_cmd(cmd, %w(list 3000))
288
+ run_cmd(cmd, %w(list run_cmd))
289
+
290
+ p = Proc.new do
291
+ |x,y| x + y
292
+ end
293
+ run_cmd(cmd, %w(list p))
294
+
295
+ # Function from a file found via an instruction sequence
296
+ run_cmd(cmd, %w(list Columnize.columnize))
297
+
298
+ # Use Class/method name. 15 isn't in the function - should this be okay?
299
+ run_cmd(cmd, %w(list Columnize.columnize 15))
300
+
301
+ # Start line and count, since 3 < 30
302
+ run_cmd(cmd, %w(list Columnize.columnize 30 3))
303
+
304
+ # Start line finish line
305
+ run_cmd(cmd, %w(list Columnize.columnize 40 50))
306
+
307
+ # puts '--' * 10
308
+ # cmd.run(['list', os.path.abspath(__file__)+':3', '4'])
309
+ # puts '--' * 10
310
+ # cmd.run(['list', os.path.abspath(__file__)+':3', '12-10'])
311
+ # cmd.run(['list', 'os.path:5'])
312
+
313
+ require 'thread_frame'
314
+ tf = RubyVM::ThreadFrame.current
315
+ cmd.proc.frame_setup(tf)
316
+ brkpt_cmd = cmd.proc.instance_variable_get('@commands')['break']
317
+ brkpt_cmd.run(['break'])
318
+ line = __LINE__
319
+ run_cmd(cmd, ['list', __LINE__.to_s])
320
+
321
+ disable_cmd = cmd.proc.instance_variable_get('@commands')['disable']
322
+ disable_cmd.run(['disable', '1'])
323
+
324
+ run_cmd(cmd, ['list', line.to_s])
325
+ run_cmd(cmd, %w(list parse_list_cmd))
326
+ end
327
+ end
@@ -0,0 +1,65 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
3
+ require_relative 'base/cmd'
4
+ require_relative '../eval'
5
+ class Trepan::Command::MacroCommand < Trepan::Command
6
+
7
+ unless defined?(HELP)
8
+ HELP =
9
+ "macro NAME PROC-OBJECT
10
+
11
+ Define NAME as a debugger macro. Debugger macros get a list of arguments
12
+ and should return a command string to use in its place.
13
+
14
+ Here is a contrived example that shows how to issue 'finish' if we are in
15
+ method 'gcd' and 'step' otherwise:
16
+
17
+ macro step_unless_gcd Proc.new{|*args| \"$trepan_frame.method == 'gcd' ? 'finish' : 'step'\"}
18
+
19
+ Here is another real example. I use the following to debug a
20
+ debugger command, assuming 'set debug dbgr' is set:
21
+
22
+ macro dbgcmd Proc.new{|*args| \"debug $trepan_cmdproc.commands['\#{args[0]}'].run(\#{args.inspect})\"}
23
+
24
+ With the above, 'dbgcmd list 5' will debug the debugger 'list' command
25
+ on the command 'list 5'.
26
+
27
+ See also 'show macro'.
28
+ "
29
+
30
+ CATEGORY = 'support'
31
+ MIN_ARGS = 2 # Need at least this many
32
+ NAME = File.basename(__FILE__, '.rb')
33
+ SHORT_HELP = 'Define a macro'
34
+ end
35
+
36
+ def run(args)
37
+ macro_name = args[1]
38
+ proc_argstr = @proc.cmd_argstr[macro_name.size..-1].lstrip
39
+ proc_obj = @proc.debug_eval(proc_argstr, @proc.settings[:maxstring])
40
+ if proc_obj
41
+ if proc_obj.is_a?(Proc)
42
+ @proc.macros[macro_name] = proc_obj
43
+ msg "Macro \"#{macro_name}\" defined."
44
+ else
45
+ errmsg "Expecting a Proc object; got: #{proc_argstr}"
46
+ end
47
+ end
48
+ end
49
+ end
50
+
51
+ if __FILE__ == $0
52
+ require_relative '../mock'
53
+ name = File.basename(__FILE__, '.rb')
54
+ dbgr, cmd = MockDebugger::setup(name)
55
+ cmdproc = dbgr.core.processor
56
+ ['macro foo Proc.new{|x, y| x+y}',
57
+ 'macro bad x+1',
58
+ 'macro bad2 1+2'].each do |cmdline|
59
+ args = cmdline.split
60
+ cmd_argstr = cmdline[args[0].size..-1].lstrip
61
+ cmdproc.instance_variable_set('@cmd_argstr', cmd_argstr)
62
+ cmd.run(args)
63
+ end
64
+ p cmdproc.macros
65
+ end
@@ -0,0 +1,89 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
3
+ require_relative 'base/cmd'
4
+
5
+ class Trepan::Command::NextCommand < Trepan::Command
6
+
7
+ unless defined?(HELP)
8
+ HELP =
9
+ "next[+|=|-|<|>|!|<>] [EVENT-NAME...] [count]
10
+
11
+ Step one statement ignoring steps into function calls at this level.
12
+ Sometimes this is called 'step over'.
13
+
14
+ With an integer argument, perform 'next' that many times. However if
15
+ an exception occurs at this level, or we 'return' or 'yield' or the
16
+ thread changes, we stop regardless of count.
17
+
18
+ A suffix of '+' on the command or an alias to the command forces to
19
+ move to another line, while a suffix of '-' does the opposite and
20
+ disables the requiring a move to a new line. If no suffix is given,
21
+ the debugger setting 'different' determines this behavior.
22
+
23
+ If no suffix is given, the debugger setting 'different'
24
+ determines this behavior.
25
+
26
+ Examples:
27
+ next # next 1 event, *any* event
28
+ next 1 # same as above
29
+ next+ # same but force stopping on a new line
30
+ next= # same but force stopping on a new line a new frame added
31
+ next- # same but force stopping on a new line a new frame added
32
+ next 5/5+0 # same as above
33
+ next line # next using only line events
34
+ next call # next using only call call events
35
+ next<> # next using call return events at this level or below
36
+ "
37
+
38
+ ALIASES = %w(n next+ next- next< next> next<> next! n> n< n! n+ n-
39
+ n<> n=)
40
+ CATEGORY = 'running'
41
+ # execution_set = ['Running']
42
+ MAX_ARGS = 1 # Need at most this many. FIXME: will be eventually 2
43
+ NAME = File.basename(__FILE__, '.rb')
44
+ NEED_RUNNING = true
45
+ SHORT_HELP = 'Step program without entering called functions'
46
+ end
47
+
48
+ # This method runs the command
49
+ def run(args) # :nodoc
50
+ opts = @proc.parse_next_step_suffix(args[0])
51
+ if args.size == 1
52
+ # Form is: "next" which means "next 1"
53
+ step_count = 0
54
+ else
55
+ count_str = args[1]
56
+ opts = {
57
+ :msg_on_error =>
58
+ "The 'next' command argument must eval to an integer. Got: %s" %
59
+ count_str,
60
+ :min_value => 1
61
+ }
62
+ count = @proc.get_an_int(count_str, opts)
63
+ return unless count
64
+ # step 1 is core.step_count = 0 or "stop next event"
65
+ step_count = count - 1
66
+ end
67
+ @proc.next(step_count, opts)
68
+ end
69
+ end
70
+
71
+ if __FILE__ == $0
72
+ require_relative '../mock'
73
+ name = File.basename(__FILE__, '.rb')
74
+ dbgr, cmd = MockDebugger::setup(name)
75
+ [%w(n 5), %w(next 1+2), %w(n foo)].each do |c|
76
+ dbgr.core.step_count = 0
77
+ cmd.proc.leave_cmd_loop = false
78
+ result = cmd.run(c)
79
+ puts 'Run result: %s' % result
80
+ puts 'step_count %d, leave_cmd_loop: %s' % [dbgr.core.step_count,
81
+ cmd.proc.leave_cmd_loop]
82
+ end
83
+ [%w(n), %w(next+), %w(n-)].each do |c|
84
+ dbgr.core.step_count = 0
85
+ cmd.proc.leave_cmd_loop = false
86
+ result = cmd.run(c)
87
+ puts cmd.proc.different_pos
88
+ end
89
+ end
@@ -0,0 +1,33 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
3
+ require_relative 'base/cmd'
4
+ class Trepan::Command::NoCacheCommand < Trepan::Command
5
+
6
+ unless defined?(HELP)
7
+ HELP = "Remove getinlinecache instructions from instruction sequence."
8
+
9
+ CATEGORY = 'running'
10
+ MAX_ARGS = 0 # Need at most this many
11
+ NAME = File.basename(__FILE__, '.rb')
12
+ NEED_STACK = true
13
+ SHORT_HELP = 'Remove getinlinecache instructions from instruction sequence.'
14
+
15
+ end
16
+
17
+ # This method runs the command
18
+ def run(args) # :nodoc
19
+ if @proc.frame.iseq
20
+ puts @proc.frame.iseq.disassemble
21
+ count = @proc.frame.iseq.killcache
22
+ msg ("%d locations removed" % count)
23
+ # puts @proc.frame.iseq.disassemble
24
+ end
25
+ end
26
+ end
27
+
28
+ if __FILE__ == $0
29
+ require_relative '../mock'
30
+ name = File.basename(__FILE__, '.rb')
31
+ dbgr, cmd = MockDebugger::setup(name)
32
+ cmd.run([name])
33
+ end
@@ -0,0 +1,37 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
3
+ require_relative 'base/cmd'
4
+ require_relative '../eval'
5
+ class Trepan::Command::PrintCommand < Trepan::Command
6
+
7
+ unless defined?(HELP)
8
+ HELP =
9
+ "print EXPRESSION
10
+
11
+ Print the value of the EXPRESSION. Variables accessible are those of the
12
+ environment of the selected stack frame, plus globals.
13
+
14
+ If the length output string large, the first part of the value is
15
+ shown and ... indicates it has been truncated."
16
+
17
+ # ALIASES = %w(p)
18
+ CATEGORY = 'data'
19
+ NAME = File.basename(__FILE__, '.rb')
20
+ SHORT_HELP = 'Print expression'
21
+ end
22
+
23
+ def run(args)
24
+ msg @proc.debug_eval(@proc.cmd_argstr, @proc.settings[:maxstring])
25
+ end
26
+ end
27
+
28
+ if __FILE__ == $0
29
+ require_relative '../mock'
30
+ name = File.basename(__FILE__, '.rb')
31
+ dbgr, cmd = MockDebugger::setup(name)
32
+ arg_str = '1 + 2'
33
+ cmd.proc.instance_variable_set('@cmd_argstr', arg_str)
34
+ cmd.run([name, arg_str])
35
+ cmdproc = dbgr.core.processor
36
+ cmds = dbgr.core.processor.commands
37
+ end
@@ -0,0 +1,40 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
3
+ require_relative 'base/cmd'
4
+ require_relative '../eval'
5
+ class Trepan::Command::PsCommand < Trepan::Command
6
+
7
+ unless defined?(HELP)
8
+ HELP =
9
+ "ps ARRAY
10
+
11
+ Print the value of the ARRAY in columns and sorted."
12
+
13
+ CATEGORY = 'data'
14
+ MIN_ARGS = 1 # Need least this many
15
+ NAME = File.basename(__FILE__, '.rb')
16
+ SHORT_HELP = 'Print array sorted and in columns'
17
+ end
18
+
19
+ def run(args)
20
+ array = @proc.debug_eval(@proc.cmd_argstr, @proc.settings[:maxstring])
21
+ # FIXME: should test for enumerable
22
+ if array.is_a?(Array)
23
+ msg columnize_commands(array.sort)
24
+ else
25
+ errmsg "ps: #{@proc.cmd_argstr} should evaluate an Array not #{array.class}"
26
+ end
27
+ end
28
+ end
29
+
30
+ if __FILE__ == $0
31
+ require_relative '../mock'
32
+ name = File.basename(__FILE__, '.rb')
33
+ dbgr, cmd = MockDebugger::setup(name)
34
+ arg_str = '(1..30).to_a'
35
+ cmd.proc.instance_variable_set('@cmd_argstr', arg_str)
36
+ cmd.run([name, arg_str])
37
+ arg_str = '1'
38
+ cmd.proc.instance_variable_set('@cmd_argstr', arg_str)
39
+ cmd.run([name, arg_str])
40
+ end
@@ -0,0 +1,62 @@
1
+ # Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
2
+ require_relative 'base/cmd'
3
+ class Trepan::Command::QuitCommand < Trepan::Command
4
+
5
+ unless defined?(HELP)
6
+ HELP =
7
+ 'quit[!] [unconditionally] [exit code] - gentle termination
8
+
9
+ The program being debugged is exited via exit() which runs the Kernel
10
+ at_exit finalizers. If a return code is given, that is the return code
11
+ passed to exit() - presumably the return code that will be passed back
12
+ to the OS. If no exit code is given, 0 is used.
13
+
14
+ Examples:
15
+ quit # quit prompting if we are interactive
16
+ quit conditionally # quit without prompting
17
+ quit! # same as above
18
+ quit 0 # same as "quit"
19
+ quit! 1 # unconditional quit setting exit code 1
20
+
21
+ See also the commands "exit" and "kill".'
22
+
23
+ ALIASES = %w(quit! q q!)
24
+ CATEGORY = 'support'
25
+ NAME = File.basename(__FILE__, '.rb')
26
+ MAX_ARGS = 2 # Need at most this many
27
+ SHORT_HELP = 'Quit program - gently'
28
+ end
29
+
30
+ # FIXME: Combine 'quit' and 'exit'. The only difference is
31
+ # whether exit! or exit is used.
32
+
33
+ # This method runs the command
34
+ def run(args) # :nodoc
35
+ unconditional =
36
+ if args.size > 1 && args[1] == 'unconditionally'
37
+ args.shift
38
+ true
39
+ elsif args[0][-1] == '!'
40
+ true
41
+ else
42
+ false
43
+ end
44
+ unless unconditional || confirm('Really quit?', false)
45
+ msg('Quit not confirmed.')
46
+ return
47
+ end
48
+
49
+ exitrc = (args.size > 1) ? exitrc = Integer(args[1]) rescue 0 : 0
50
+ # No graceful way to stop threads...
51
+ exit exitrc
52
+ end
53
+ end
54
+
55
+ if __FILE__ == $0
56
+ require_relative '../mock'
57
+ name = File.basename(__FILE__, '.rb')
58
+ dbgr, cmd = MockDebugger::setup(name)
59
+ name = File.basename(__FILE__, '.rb')
60
+ fork { cmd.run([name]) }
61
+ cmd.run([name, '5'])
62
+ end
@@ -0,0 +1,47 @@
1
+ # Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
2
+ require_relative 'base/cmd'
3
+ class Trepan::Command::RaiseCommand < Trepan::Command
4
+
5
+ unless defined?(HELP)
6
+ HELP =
7
+ "raise EXCEPTION
8
+
9
+ Raise an exception in the debugged program."
10
+
11
+ CATEGORY = 'running'
12
+ MAX_ARGS = 1 # Need at most this many
13
+ NAME = File.basename(__FILE__, '.rb')
14
+ SHORT_HELP = 'Raise an exception in the debugged program'
15
+ end
16
+
17
+ # This method runs the command
18
+ def run(args) # :nodoc
19
+ exception =
20
+ if args.size > 1
21
+ except_str = args[1..-1].join(' ')
22
+ # Normally would need x.respond_to? && ..
23
+ # but since we catch errors with debug_eval.. not needed.
24
+ eval_str = ("%s.ancestors.include?(Exception)" %
25
+ [except_str])
26
+ unless @proc.debug_eval_no_errmsg(eval_str)
27
+ errmsg "\"#{except_str}\" does not inherit Exception."
28
+ return
29
+ end
30
+ @proc.debug_eval_no_errmsg(except_str)
31
+ else
32
+ RuntimeError
33
+ end
34
+ @proc.step(0)
35
+ @proc.leave_cmd_loop = true
36
+ @proc.core.exception = exception
37
+ end
38
+ end
39
+
40
+ if __FILE__ == $0
41
+ require_relative '../mock'
42
+ name = File.basename(__FILE__, '.rb')
43
+ dbgr, cmd = MockDebugger::setup(name)
44
+ puts cmd.run([name, 'NotanException'])
45
+ puts cmd.run([name, '[5]'])
46
+ puts cmd.run([name, 'RuntimeError'])
47
+ end