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,395 @@
1
+ # Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
2
+
3
+ # Trepan command input validation routines. A String type is
4
+ # usually passed in as the argument to validation routines.
5
+
6
+ require_relative '../app/condition'
7
+ require_relative '../app/file'
8
+ require_relative '../app/thread'
9
+
10
+ require_relative 'location' # for resolve_file_with_dir
11
+ require_relative 'msg' # for errmsg, msg
12
+
13
+ class Trepan
14
+ class CmdProcessor
15
+
16
+ attr_reader :dbgr_script_iseqs
17
+ attr_reader :dbgr_iseqs
18
+
19
+ include Trepanning
20
+ include Trepan::ThreadHelper
21
+ include Trepan::Condition
22
+
23
+ def confirm(msg, default)
24
+ @dbgr.intf[-1].confirm(msg, default)
25
+ end
26
+
27
+ # Like cmdfns.get_an_int(), but if there's a stack frame use that
28
+ # in evaluation.
29
+ def get_an_int(arg, opts={})
30
+ ret_value = get_int_noerr(arg)
31
+ if !ret_value
32
+ if opts[:msg_on_error]
33
+ errmsg(opts[:msg_on_error])
34
+ else
35
+ errmsg("Expecting an integer, got: #{arg}.")
36
+ end
37
+ return nil
38
+ end
39
+ if opts[:min_value] and ret_value < opts[:min_value]
40
+ errmsg("Expecting integer value to be at least %d; got %d." %
41
+ [opts[:min_value], ret_value])
42
+ return nil
43
+ elsif opts[:max_value] and ret_value > opts[:max_value]
44
+ errmsg("Expecting integer value to be at most %d; got %d." %
45
+ [opts[:max_value], ret_value])
46
+ return nil
47
+ end
48
+ return ret_value
49
+ end
50
+
51
+ unless defined?(DEFAULT_GET_INT_OPTS)
52
+ DEFAULT_GET_INT_OPTS = {
53
+ :min_value => 0, :default => 1, :cmdname => nil, :max_value => nil}
54
+ end
55
+
56
+ # If argument parameter 'arg' is not given, then use what is in
57
+ # opts[:default]. If String 'arg' evaluates to an integer between
58
+ # least min_value and at_most, use that. Otherwise report an
59
+ # error. If there's a stack frame use that for bindings in
60
+ # evaluation.
61
+ def get_int(arg, opts={})
62
+
63
+ return default unless arg
64
+ opts = DEFAULT_GET_INT_OPTS.merge(opts)
65
+ val = arg ? get_int_noerr(arg) : opts[:default]
66
+ unless val
67
+ if opts[:cmdname]
68
+ errmsg(("Command '%s' expects an integer; " +
69
+ "got: %s.") % [opts[:cmdname], arg])
70
+ else
71
+ errmsg('Expecting a positive integer, got: %s' % arg)
72
+ end
73
+ return nil
74
+ end
75
+
76
+ if val < opts[:min_value]
77
+ if cmdname
78
+ errmsg(("Command '%s' expects an integer at least" +
79
+ ' %d; got: %d.') %
80
+ [cmdname, opts[:min_value], opts[:default]])
81
+ else
82
+ errmsg(("Expecting a positive integer at least" +
83
+ ' %d; got: %d') %
84
+ [opts[:min_value], opts[:default]])
85
+ end
86
+ return nil
87
+ elsif opts[:max_value] and val > opts[:max_value]
88
+ if opts[:cmdname]
89
+ errmsg(("Command '%s' expects an integer at most" +
90
+ ' %d; got: %d.') %
91
+ [opts[:cmdname], opts[:max_value], val])
92
+ else
93
+ errmsg(("Expecting an integer at most %d; got: %d") %
94
+ [opts[:max_value], val])
95
+ end
96
+ return nil
97
+ end
98
+ return val
99
+ end
100
+
101
+ def get_int_list(args, opts={})
102
+ args.map{|arg| get_an_int(arg, opts)}.compact
103
+ end
104
+
105
+ # Eval arg and it is an integer return the value. Otherwise
106
+ # return nil
107
+ def get_int_noerr(arg)
108
+ b = @frame ? @frame.binding : nil
109
+ val = Integer(eval(arg, b))
110
+ rescue SyntaxError
111
+ nil
112
+ rescue
113
+ nil
114
+ end
115
+
116
+ def get_thread_from_string(id_or_num_str)
117
+ if id_or_num_str == '.'
118
+ Thread.current
119
+ elsif id_or_num_str.downcase == 'm'
120
+ Thread.main
121
+ else
122
+ num = get_int_noerr(id_or_num_str)
123
+ if num
124
+ get_thread(num)
125
+ else
126
+ nil
127
+ end
128
+ end
129
+ end
130
+
131
+ # Return the instruction sequence associated with string
132
+ # OBJECT_STRING or nil if no instruction sequence
133
+ def object_iseq(object_string)
134
+ iseqs = find_iseqs(ISEQS__, object_string)
135
+ # FIXME: do something if there is more than one.
136
+ if iseqs.size == 1
137
+ iseqs[-1]
138
+ elsif debug_eval_no_errmsg("#{object_string}.respond_to?('iseq')")
139
+ debug_eval_no_errmsg("#{object_string}.iseq")
140
+ else
141
+ parts = object_string.split(/[.]/)
142
+ string =
143
+ if parts.size < 2
144
+ "method(\"#{object_string}\").iseq"
145
+ else
146
+ parts[0..-2].join('.')+".method(\"#{parts[-1]}\").iseq"
147
+ end
148
+ debug_eval_no_errmsg(string)
149
+ end
150
+ rescue
151
+ nil
152
+ end
153
+
154
+ # Parse a breakpoint position. Return
155
+ # - the position - a Fixnum
156
+ # - the instruction sequence to use
157
+ # - whether the postion is an offset or a line number
158
+ # - the condition (by default 'true') to use for this breakpoint
159
+ # - the condition (by default 'true') to use for this breakpoint
160
+ def breakpoint_position(args)
161
+ first = args.shift
162
+ name, container, position = parse_position(first, nil, true)
163
+ if container && position
164
+ iseq = find_iseqs_with_lineno(container[1], position) || object_iseq(first)
165
+ unless iseq
166
+ if @frame.iseq &&
167
+ File.basename(@frame.iseq.source_container[1]) ==
168
+ File.basename(container[1])
169
+ iseq = @frame.iseq
170
+ else
171
+ errmsg "Unable to find instruction sequence for position #{position} in #{container[1]}"
172
+ return [nil, nil, nil, true]
173
+ end
174
+ end
175
+ use_offset = false
176
+ else
177
+ iseq = object_iseq(first)
178
+ position_str =
179
+ if iseq
180
+ # Got name and possibly position
181
+ name = first
182
+ if args.empty?
183
+ # FIXME: *Still* have a bug stopping at offset 0.
184
+ # So stop at next offset after 0.
185
+ # 'o0'
186
+ "o#{@frame.iseq.offsetlines.keys.sort[1]}"
187
+ else
188
+ args.shift
189
+ end
190
+ else
191
+ iseq = @frame.iseq unless container
192
+ first
193
+ end
194
+ use_offset =
195
+ if position_str.size > 0 && position_str[0].downcase == 'o'
196
+ position_str[0] = ''
197
+ true
198
+ else
199
+ false
200
+ end
201
+ opts = {
202
+ :msg_on_error =>
203
+ "argument '%s' does not seem to eval to a method or an integer." %
204
+ position_str,
205
+ :min_value => 0
206
+ }
207
+ position = get_an_int(position_str, opts)
208
+ end
209
+ condition = 'true'
210
+ if args.size > 0 && 'if' == args[0]
211
+ condition_try = args[1..-1].join(' ')
212
+ condition = condition_try if valid_condition?(condition_try)
213
+ end
214
+ return [position, iseq, use_offset, condition, name]
215
+ end
216
+
217
+ # Return true if arg is 'on' or 1 and false arg is 'off' or 0.
218
+ # Any other value is raises TypeError.
219
+ def get_onoff(arg, default=nil, print_error=true)
220
+ unless arg
221
+ if !default
222
+ if print_error
223
+ errmsg("Expecting 'on', 1, 'off', or 0. Got nothing.")
224
+ end
225
+ raise TypeError
226
+ end
227
+ return default
228
+ end
229
+ darg = arg.downcase
230
+ return true if arg == '1' || darg == 'on'
231
+ return false if arg == '0' || darg =='off'
232
+
233
+ errmsg("Expecting 'on', 1, 'off', or 0. Got: %s." % arg.to_s) if
234
+ print_error
235
+ raise TypeError
236
+ end
237
+
238
+ def method?(method_string)
239
+ obj, type, meth =
240
+ if method_string =~ /(.+)(#|::|\.)(.+)/
241
+ [$1, $2, $3]
242
+ else
243
+ ['self', '.', method_string]
244
+ end
245
+ ret = debug_eval_no_errmsg("#{obj}.method(#{meth.inspect})")
246
+ return true if ret
247
+ return debug_eval_no_errmsg("#{obj}.is_a?(Class)") &&
248
+ debug_eval_no_errmsg("#{obj}.method_defined?(#{meth.inspect})")
249
+ end
250
+
251
+ # parse_position(self, arg)->(fn, container, lineno)
252
+ #
253
+ # Parse arg as [filename:]lineno | function | module
254
+ # Make sure it works for C:\foo\bar.py:12
255
+ def parse_position(arg, old_mod=nil, allow_offset = false)
256
+ colon = arg.rindex(':')
257
+ if colon
258
+ # First handle part before the colon
259
+ arg1 = arg[0...colon].rstrip
260
+ lineno_str = arg[colon+1..-1].lstrip
261
+ mf, container, lineno = parse_position_one_arg(arg1, old_mod, false, allow_offset)
262
+ return nil, nil, nil unless container
263
+ filename = canonic_file(arg1)
264
+ # Next handle part after the colon
265
+ val = get_an_int(lineno_str)
266
+ lineno = val if val
267
+ else
268
+ mf, container, lineno = parse_position_one_arg(arg, old_mod, true, allow_offset)
269
+ end
270
+
271
+ return mf, container, lineno
272
+ end
273
+
274
+ # parse_position_one_arg(self,arg)->(module/function, container, lineno)
275
+ #
276
+ # See if arg is a line number, function name, or module name.
277
+ # Return what we've found. nil can be returned as a value in
278
+ # the triple.
279
+ def parse_position_one_arg(arg, old_mod=nil, show_errmsg=true, allow_offset=false)
280
+ name, filename = nil, nil, nil
281
+ begin
282
+ # First see if argument is an integer
283
+ lineno = Integer(arg)
284
+ rescue
285
+ else
286
+ container = frame_container(@frame, false)
287
+ filename = container[1] unless old_mod
288
+ return nil, [container[0], canonic_file(filename)], lineno
289
+ end
290
+
291
+ # Next see if argument is a file name
292
+ found =
293
+ if arg[0..0] == File::SEPARATOR
294
+ LineCache::cached?(arg)
295
+ else
296
+ resolve_file_with_dir(arg)
297
+ end
298
+ if found
299
+ return nil, [container && container[0], canonic_file(arg)], 1
300
+ else
301
+ matches = find_scripts(arg)
302
+ if matches.size > 1
303
+ if show_errmsg
304
+ errmsg "#{arg} is matches several files:"
305
+ errmsg Columnize::columnize(matches.sort,
306
+ @settings[:width], ' ' * 4,
307
+ true, true, ' ' * 2).chomp
308
+ end
309
+ return nil, nil, nil
310
+ elsif matches.size == 1
311
+ LineCache::cache(matches[0])
312
+ return nil, ['file', matches[0]], 1
313
+ end
314
+ end
315
+
316
+ # How about a method name with an instruction sequence?
317
+ iseq = object_iseq(arg)
318
+ if iseq && iseq.source_container[0] == 'file'
319
+ filename = iseq.source_container[1]
320
+ line_no = iseq.offsetlines.values.flatten.min
321
+ return arg, ['file', canonic_file(filename)], line_no
322
+ end
323
+
324
+ if show_errmsg
325
+ unless (allow_offset && arg.size > 0 && arg[0].downcase == 'o')
326
+ errmsg("#{arg} is not a line number, read-in filename or method " +
327
+ "we can get location information about")
328
+ end
329
+ end
330
+ return nil, nil, nil
331
+ end
332
+
333
+ def validate_initialize
334
+ ## top_srcdir = File.expand_path(File.join(File.dirname(__FILE__), '..'))
335
+ ## @dbgr_script_iseqs, @dbgr_iseqs = filter_scripts(top_srcdir)
336
+ end
337
+ end
338
+ end
339
+
340
+ if __FILE__ == $0
341
+ # Demo it.
342
+ if !(ARGV.size == 1 && ARGV[0] == 'noload')
343
+ ARGV[0..-1] = ['noload']
344
+ load(__FILE__)
345
+ else
346
+ require 'thread_frame'
347
+ require_relative '../app/mock'
348
+ require_relative 'main' # Have to include before defining CmdProcessor!
349
+ # FIXME
350
+
351
+ proc = Trepan::CmdProcessor.new(Trepan::MockCore.new())
352
+ proc.settings[:directory] = '$cwd'
353
+ proc.frame_setup(RubyVM::ThreadFrame.current)
354
+ onoff = %w(1 0 on off)
355
+ onoff.each { |val| puts "onoff(#{val}) = #{proc.get_onoff(val)}" }
356
+ %w(1 1E bad 1+1 -5).each do |val|
357
+ puts "get_int_noerr(#{val}) = #{proc.get_int_noerr(val).inspect}"
358
+ end
359
+ def foo; 5 end
360
+ def proc.errmsg(msg)
361
+ puts msg
362
+ end
363
+ puts proc.object_iseq('food').inspect
364
+ puts proc.object_iseq('foo').inspect
365
+
366
+ puts proc.object_iseq('foo@validate.rb').inspect
367
+ puts proc.object_iseq('proc.object_iseq').inspect
368
+
369
+ puts proc.parse_position_one_arg('tmpdir.rb').inspect
370
+
371
+ puts '=' * 40
372
+ ['Array#map', 'Trepan::CmdProcessor.new',
373
+ 'foo', 'proc.errmsg'].each do |str|
374
+ puts "#{str} should be true: #{proc.method?(str).inspect}"
375
+ end
376
+ puts '=' * 40
377
+ # require_relative '../lib/trepanning'
378
+ # dbgr = Trepan.new(:set_restart => true)
379
+ # dbgr.debugger
380
+
381
+ # FIXME:
382
+ # Array#foo should be false: true
383
+ # Trepan::CmdProcessor.allocate should be false: true
384
+
385
+ ['food', '.errmsg'].each do |str|
386
+ puts "#{str} should be false: #{proc.method?(str).inspect}"
387
+ end
388
+ puts '-' * 20
389
+ p proc.breakpoint_position(%w(O0))
390
+ p proc.breakpoint_position(%w(1))
391
+ p proc.breakpoint_position(%w(2 if a > b))
392
+ p proc.get_int_list(%w(1+0 3-1 3))
393
+ p proc.get_int_list(%w(a 2 3))
394
+ end
395
+ end
@@ -0,0 +1 @@
1
+ puts "Ha!"
@@ -0,0 +1,18 @@
1
+
2
+ # GCD. We assume positive numbers
3
+ def gcd(a, b)
4
+ # Make: a <= b
5
+ if a > b
6
+ a, b = [b, a]
7
+ end
8
+
9
+ return nil if a <= 0
10
+ addline
11
+
12
+ if a == 1 or b-a == 0
13
+ return a
14
+ end
15
+ end
16
+
17
+ a, b = ARGV[0..1].map {|arg| arg.to_i}
18
+ puts "The GCD of %d and %d is %d" % [a, b, gcd(a, b)]
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # GCD. We assume positive numbers
4
+ def gcd(a, b)
5
+ # Make: a <= b
6
+ if a > b
7
+ a, b = [b, a]
8
+ end
9
+
10
+ return nil if a <= 0
11
+
12
+ if a == 1 or b-a == 0
13
+ return a
14
+ end
15
+ return gcd(b-a, a)
16
+ end
17
+
18
+ a, b = ARGV[0..1].map {|arg| arg.to_i}
19
+ puts "The GCD of %d and %d is %d" % [a, b, gcd(a, b)]
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env ruby
2
+ require 'thread_frame'
3
+ tf = RubyVM::ThreadFrame.current
4
+ iseq = tf.iseq
5
+ p iseq.child_iseqs
6
+ puts iseq.disassemble
7
+
8
+ # GCD. We assume positive numbers
9
+ def gcd(a, b)
10
+ # Make: a <= b
11
+ if a > b
12
+ a, b = [b, a]
13
+ end
14
+
15
+ return nil if a <= 0
16
+
17
+ if a == 1 or b-a == 0
18
+ return a
19
+ end
20
+ return gcd(b-a, a)
21
+ end
22
+
23
+ a, b = ARGV[0..1].map {|arg| arg.to_i}
24
+ puts "The GCD of %d and %d is %d" % [a, b, gcd(a, b)]
@@ -0,0 +1 @@
1
+ # Nothing here. Move along.
@@ -0,0 +1,3 @@
1
+ Thread.new do
2
+ x = 1
3
+ end.join
@@ -0,0 +1,119 @@
1
+ require 'thread_frame'
2
+ require 'trace'
3
+ require_relative '../../lib/trepanning'
4
+ require_relative '../../io/string_array'
5
+
6
+ module FnTestHelper
7
+ include Trace
8
+
9
+ # Synchronous events without C frames or instructions
10
+ TEST_STEP_EVENT_MASK = LINE_EVENT_MASK | CLASS_EVENT_MASK | CALL_EVENT_MASK |
11
+ RETURN_EVENT_MASK
12
+
13
+ # Common setup to create a debugger with String Array I/O attached
14
+ def strarray_setup(debugger_cmds, insn_stepping=false)
15
+ stringin = Trepan::StringArrayInput.open(debugger_cmds)
16
+ stringout = Trepan::StringArrayOutput.open
17
+ d_opts = {:input => stringin, :output => stringout,
18
+ :nx => true}
19
+ d_opts[:core_opts] = {:step_events => TEST_STEP_EVENT_MASK}
20
+ d_opts[:core_opts][:step_events] ||= INSN_EVENT_MASK if insn_stepping
21
+ d = Trepan.new(d_opts)
22
+
23
+ # Remove vm and switch from unmaskable events to increase predictability
24
+ # of test results
25
+ d.core.instance_variable_set('@unmaskable_events', %w(brkpt raise))
26
+
27
+ d.settings[:basename] = true
28
+ d.settings[:different] = false
29
+ d.settings[:autoeval] = false
30
+ return d
31
+ end
32
+
33
+ unless defined?(TREPAN_PROMPT)
34
+ TREPAN_PROMPT = /^\(trepan\): /
35
+ TREPAN_LOC = /.. \(.+:\d+\)/
36
+ end
37
+
38
+ # Return the caller's line number
39
+ def get_lineno
40
+ RubyVM::ThreadFrame.current.prev.source_location[0]
41
+ end
42
+
43
+ def compare_output(right, d, debugger_cmds)
44
+ # require_relative '../../lib/trepanning'
45
+ # Trepan.debug(:set_restart => true)
46
+ got = filter_line_cmd(d.intf[-1].output.output)
47
+ if got != right
48
+ got.each_with_index do |got_line, i|
49
+ if i < right.size and got_line != right[i]
50
+ # dbgr.debugger
51
+ puts "! #{got_line}"
52
+ else
53
+ puts " #{got_line}"
54
+ end
55
+ end
56
+ puts '-' * 10
57
+ right.each_with_index do |right_line, i|
58
+ if i < got.size and got[i] != right_line
59
+ # dbgr.debugger
60
+ puts "! #{right_line}"
61
+ else
62
+ puts " #{right_line}"
63
+ end
64
+ end
65
+ end
66
+ assert_equal(right, got, caller[0])
67
+ end
68
+
69
+ # Return output with source lines prompt and command removed
70
+ def filter_line_cmd(a, show_prompt=false)
71
+ # Remove debugger prompt
72
+ a = a.map do |s|
73
+ s =~ TREPAN_PROMPT ? nil : s
74
+ end.compact unless show_prompt
75
+
76
+ # Remove debugger location lines.
77
+ # For example:
78
+ # -- (/src/external-vcs/trepan/tmp/gcd.rb:4)
79
+ # becomes:
80
+ # --
81
+ a2 = a.map do |s|
82
+ s =~ TREPAN_LOC ? s.gsub(/\(.+:\d+\)\n/, '').chomp : s.chomp
83
+ end
84
+
85
+ # Remove VM offset locations.
86
+ # For example:
87
+ # VM offset 2 of instruction sequence "block in compare_output".
88
+ # becomes
89
+ # VM offset 55 of instruction sequence "block in compare_output".
90
+ a3 = a2.map do |s|
91
+ s.gsub(/VM offset \d+/, 'VM offset 55')
92
+ end
93
+ return a3
94
+ end
95
+
96
+ end
97
+
98
+ # Demo it
99
+ if __FILE__ == $0
100
+ include FnTestHelper
101
+ strarray_setup(%w(eh bee see))
102
+ puts get_lineno()
103
+ p '-- (/src/external-vcs/trepan/tmp/gcd.rb:4)' =~ TREPAN_LOC
104
+ p '(trepan): exit' =~ TREPAN_PROMPT
105
+ output='
106
+ -- (/src/external-vcs/trepan/tmp/gcd.rb:4)
107
+ (trepan): s
108
+ -- (/src/external-vcs/trepan/tmp/gcd.rb:18)
109
+ (trepan): s
110
+ -- (/src/external-vcs/trepan/tmp/gcd.rb:19)
111
+ (trepan): s
112
+ .. (/src/external-vcs/trepan/tmp/gcd.rb:0)
113
+ (trepan): s
114
+ -> (/src/external-vcs/trepan/tmp/gcd.rb:4)
115
+ '.split(/\n/)
116
+ puts filter_line_cmd(output)
117
+ puts '-' * 10
118
+ puts filter_line_cmd(output, true)
119
+ end
@@ -0,0 +1,87 @@
1
+ #!/usr/bin/env ruby
2
+ require 'test/unit'
3
+ require 'trace'
4
+ require_relative 'fn_helper'
5
+ require_relative '../../app/breakpoint'
6
+
7
+ class TestBreak < Test::Unit::TestCase
8
+
9
+ include FnTestHelper
10
+
11
+ def setup
12
+ Trepanning::Breakpoint::reset
13
+ end
14
+
15
+ def test_break_same_level
16
+
17
+ # See that we can stop at a breakpoint
18
+ cmds = ['set basename on',
19
+ 'break ' + (__LINE__ + 7).to_s,
20
+ 'continue']
21
+ d = strarray_setup(cmds)
22
+ d.start
23
+ ########### b1 ###############
24
+ x = 5
25
+ y = 6
26
+ z = 7
27
+ ##############################
28
+ d.stop
29
+ out = ['-- ',
30
+ 'x = 5',
31
+ 'basename is on.',
32
+ "Breakpoint 1 set at line 26 in file test-break.rb,\n" +
33
+ "\tVM offset 55 of instruction sequence \"test_break_same_level\".",
34
+ 'xx ',
35
+ 'z = 7']
36
+ compare_output(out, d, cmds)
37
+
38
+ # Try a disabling the breakpoint
39
+ cmds = ['set basename on',
40
+ 'break ' + (__LINE__ + 8).to_s,
41
+ 'break ' + (__LINE__ + 8).to_s,
42
+ 'disable 1',
43
+ 'continue']
44
+ d = strarray_setup(cmds)
45
+ d.start
46
+ ########### b2 ###############
47
+ x = 7
48
+ y = 8
49
+ z = 8+1
50
+ ##############################
51
+ d.stop
52
+ out = ['-- ',
53
+ 'x = 7',
54
+ 'basename is on.',
55
+ "Breakpoint 1 set at line 48 in file test-break.rb,\n" +
56
+ "\tVM offset 55 of instruction sequence \"test_break_same_level\".",
57
+ "Breakpoint 2 set at line 49 in file test-break.rb,\n" +
58
+ "\tVM offset 55 of instruction sequence \"test_break_same_level\".",
59
+ "Breakpoint 1 disabled.",
60
+ 'xx ',
61
+ 'z = 8+1']
62
+ compare_output(out, d, cmds)
63
+
64
+ # Stepping after a breakpoint should not stay at same location.
65
+ cmds = ['set basename on',
66
+ 'continue ' + (__LINE__ + 8).to_s,
67
+ 'continue']
68
+ dbg = strarray_setup(cmds)
69
+ dbg.start
70
+ ########### b3 ###############
71
+ a = 1
72
+ b = 2
73
+ c = 3
74
+ d = 4
75
+ e = 5
76
+ ##############################
77
+ dbg.stop
78
+ out = ['-- ',
79
+ 'a = 1',
80
+ 'basename is on.',
81
+ 'xx ',
82
+ 'd = 4' ]
83
+ compare_output(out, dbg, cmds)
84
+ end
85
+
86
+ end
87
+