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
data/app/frame.rb ADDED
@@ -0,0 +1,275 @@
1
+ # Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
2
+ require_relative 'util'
3
+
4
+ class Trepan
5
+
6
+ module Frame
7
+
8
+ DEFAULT_STACK_TRACE_SETTINGS = {
9
+ :basename => false, # Basename only for files?
10
+ :maxstack => 16, # How many entries to show? nil means all
11
+ :count => nil, # How many entries to show? nil means all
12
+ :current_pos => 0, # Where are we in the stack?
13
+ :show_pc => false, # Show PC offset?
14
+ } unless defined?(DEFAULT_STACK_TRACE_SETTINGS)
15
+
16
+ include Trepan::Util
17
+
18
+ def all_param_names(iseq, delineate=true)
19
+ return '' unless iseq
20
+ params = param_names(iseq, 0, iseq.argc-1, '')
21
+ if iseq.arg_opts > 0
22
+ opt_params = param_names(iseq, iseq.argc,
23
+ iseq.argc + iseq.arg_opts-2, '')
24
+ opt_params[0] = "optional: #{opt_params[0]}" if delineate
25
+ params += opt_params
26
+ end
27
+ params += param_names(iseq, iseq.arg_rest, iseq.arg_rest, '*') if
28
+ iseq.arg_rest != -1
29
+ if iseq.arg_post_len > 0
30
+ # Manditory arguments after optional ones - new in Ruby 1.9
31
+ post_params = param_names(iseq, iseq.arg_post_start,
32
+ iseq.post_start + iseq.arg_post_len, '')
33
+ post_params[0] = "post: #{post_params[0]}" if delineate
34
+ params += post_params
35
+ end
36
+ params += param_names(iseq, iseq.arg_block, iseq.arg_block, '&') if
37
+ iseq.arg_block != -1
38
+
39
+ return params
40
+ end
41
+
42
+ def c_params(frame, maxstring=20)
43
+ argc = frame.argc
44
+ # FIXME should figure out why exception is raised.
45
+ begin
46
+ args =
47
+ if 0 == argc
48
+ ''
49
+ elsif frame
50
+ 1.upto(argc).map do
51
+ |i|
52
+ safe_repr(frame.sp(argc-i+3).inspect, 10)
53
+ end.join(', ')
54
+ else
55
+ '??'
56
+ end
57
+ safe_repr(args, maxstring)
58
+ rescue NotImplementedError
59
+ '??'
60
+ end
61
+ end
62
+
63
+ # Return the eval string. We get this as the
64
+ # parameter to the eval C call. A bit of checking is done
65
+ # to make sure everything is okay:
66
+ # - we have to be in an EVAL type frame which has an iseq
67
+ # - we have to have a prev frame which is a CFUNC
68
+ # - the prev method name has to be 'eval'
69
+ def eval_string(frame)
70
+ return nil unless 'EVAL' == frame.type && frame.iseq
71
+ prev = frame.prev
72
+ return nil unless prev && 'CFUNC' == prev.type && 'eval' == prev.method
73
+ retval = prev.sp 3
74
+ retval = $1 if retval =~ /^\(eval "(.+)"\)/
75
+ retval
76
+ end
77
+ module_function :eval_string
78
+
79
+ def format_stack_call(frame, opts)
80
+ # FIXME: prettify
81
+ s = "#{frame.type}"
82
+ s += if opts[:class]
83
+ " #{opts[:class]}#"
84
+ else
85
+ begin
86
+ obj = eval('self', frame.binding)
87
+ rescue
88
+ ''
89
+ else
90
+ if obj
91
+ " #{obj.class}#"
92
+ else
93
+ ''
94
+ end
95
+ end
96
+ end
97
+ meth = frame.method
98
+ if meth and frame.type != 'IFUNC'
99
+ iseq = frame.iseq
100
+ args = if 'CFUNC' == frame.type
101
+ c_params(frame)
102
+ elsif iseq
103
+ all_param_names(iseq).join(', ')
104
+ end
105
+ s += meth
106
+ if %w(CFUNC METHOD).member?(frame.type)
107
+ s += "(#{args})"
108
+ elsif %w(BLOCK LAMBDA TOP EVAL).member?(frame.type)
109
+ s += " |#{args}|" unless args.nil? || args.empty?
110
+ else
111
+ s += "(#{all_param_names(iseq)})"
112
+ end
113
+ end
114
+ s
115
+ rescue ThreadFrameError
116
+ 'invalid frame'
117
+ end
118
+
119
+ def format_stack_entry(frame, opts={})
120
+ return 'invalid frame' if frame.invalid?
121
+ s = format_stack_call(frame, opts)
122
+ s += " in #{frame.source_container[0]} "
123
+ s +=
124
+ if (eval_str = eval_string(frame))
125
+ safe_repr(eval_str.inspect, 15)
126
+ else
127
+ if 'file' == frame.source_container[0] &&
128
+ opts[:basename]
129
+ File.basename(frame.source_container[1])
130
+ else
131
+ frame.source_container[1]
132
+ end
133
+ end
134
+ if frame.source_location
135
+ s +=
136
+ if opts[:maxwidth] && s.size > opts[:maxwidth]
137
+ "\n\t"
138
+ else
139
+ ' '
140
+ end
141
+ if frame.source_location.size == 1
142
+ s += "at line #{frame.source_location[0]}" if
143
+ frame.source_location[0] != 0
144
+ else
145
+ s += " at lines #{frame.source_location}"
146
+ end
147
+ end
148
+ s += ", pc: #{frame.pc_offset}" if
149
+ frame.pc_offset > 0 && opts[:show_pc]
150
+ return s
151
+ end
152
+
153
+ def offset_for_return(event)
154
+ raise RuntimeError unless %w(return c-return).member?(event)
155
+ 'return' == event ? 1 : 2
156
+ end
157
+ module_function :offset_for_return
158
+
159
+ def param_names(iseq, start, stop, prefix='')
160
+ start.upto(stop).map do |i|
161
+ begin
162
+ prefix + iseq.local_name(i)
163
+ rescue
164
+ nil
165
+ end
166
+ end.compact
167
+ end
168
+
169
+ def print_stack_entry(frame, i, prefix=' ', opts={})
170
+ opts[:class] = nil unless i == 0
171
+ msg "%s%s" % [prefix, format_stack_entry(frame, opts)]
172
+ end
173
+
174
+ def print_stack_trace_from_to(from, to, frame, opts)
175
+ from.upto(to) do |i|
176
+ prefix = (i == opts[:current_pos]) ? '-->' : ' '
177
+ prefix += ' #%d ' % [i]
178
+ print_stack_entry(frame, i, prefix, opts)
179
+ frame = frame.prev
180
+ end
181
+ end
182
+
183
+ # Print `count' frame entries
184
+ def print_stack_trace(frame, opts={})
185
+ opts = DEFAULT_STACK_TRACE_SETTINGS.merge(opts)
186
+ halfstack = opts[:maxstack] / 2
187
+ n = frame.stack_size
188
+ n = [n, opts[:count]].min if opts[:count]
189
+ if n > (halfstack * 2)
190
+ print_stack_trace_from_to(0, halfstack-1, frame, opts)
191
+ msg "... %d levels ..." % (n - halfstack*2)
192
+ print_stack_trace_from_to(n - halfstack, n-1, frame, opts)
193
+ else
194
+ print_stack_trace_from_to(0, n-1, frame, opts)
195
+ end
196
+ end
197
+
198
+ def set_return_value(frame, event, value)
199
+ offset = offset_for_return(event)
200
+ frame.sp_set(offset, value)
201
+ end
202
+ module_function :set_return_value
203
+
204
+ def value_returned(frame, event)
205
+ frame.sp(offset_for_return(event))
206
+ end
207
+ module_function :value_returned
208
+ end
209
+ end
210
+
211
+ if __FILE__ == $0
212
+ # Demo it.
213
+ require 'thread_frame'
214
+ include Trepan::Frame
215
+ def msg(msg)
216
+ puts msg
217
+ end
218
+ print_stack_trace(RubyVM::ThreadFrame.current, :basename => true)
219
+ def foo
220
+ puts '=' * 10
221
+ print_stack_trace(RubyVM::ThreadFrame.current, :show_pc => true)
222
+ end
223
+ foo
224
+
225
+ def bar(a, b, c)
226
+ puts '=' * 10
227
+ print_stack_trace(RubyVM::ThreadFrame.current,
228
+ )
229
+ end
230
+ bar(1, 2, 3)
231
+
232
+ def baz(a, b, c=5)
233
+ puts '=' * 10
234
+ print_stack_trace(RubyVM::ThreadFrame.current)
235
+ end
236
+ baz(1, 2)
237
+
238
+ def bat(a, b, &block)
239
+ puts '=' * 10
240
+ print_stack_trace(RubyVM::ThreadFrame.current)
241
+ end
242
+ bat(1, 2)
243
+
244
+ def babe(a, b, *rest)
245
+ puts '=' * 10
246
+ print_stack_trace(RubyVM::ThreadFrame.current)
247
+ end
248
+ babe(1, 2)
249
+
250
+ puts '=' * 10
251
+ x = lambda { |a,b| print_stack_trace(RubyVM::ThreadFrame::current) }
252
+ x.call(1,2)
253
+ puts '=' * 10
254
+ x = Proc.new do |a|
255
+ print_stack_trace(RubyVM::ThreadFrame::current)
256
+ end
257
+ x.call(1,2)
258
+ class C
259
+ def initialize(a)
260
+ print_stack_trace(RubyVM::ThreadFrame::current)
261
+ end
262
+ end
263
+ puts '=' * 30
264
+ C.new('Hi')
265
+ puts '=' * 30
266
+ eval("print_stack_trace(RubyVM::ThreadFrame.current)")
267
+ puts '=' * 30
268
+ eval("eval('print_stack_trace(RubyVM::ThreadFrame.current)')")
269
+ puts '=' * 30
270
+ eval("eval('print_stack_trace(RubyVM::ThreadFrame.current, :maxstack => 2)')")
271
+ puts '=' * 30
272
+ 1.times do |a; b|
273
+ print_stack_trace(RubyVM::ThreadFrame::current)
274
+ end
275
+ end
data/app/irb.rb ADDED
@@ -0,0 +1,112 @@
1
+ # Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
2
+ # This code comes more or less from ruby-debug.
3
+ require 'irb'
4
+ module IRB # :nodoc:
5
+ module ExtendCommand # :nodoc:
6
+ # FIXME: should we read these out of a directory to
7
+ # make this more user-customizable?
8
+
9
+ # A base command class that resume execution
10
+ class DebuggerResumeCommand
11
+ def self.execute(conf, *opts)
12
+ name =
13
+ if self.name =~ /IRB::ExtendCommand::(\S+)/
14
+ $1.downcase
15
+ else
16
+ 'unknown'
17
+ end
18
+ $trepan_args = opts
19
+ $trepan_command =
20
+ if $trepan_irb_statements
21
+ $trepan_irb_statements
22
+ else
23
+ ([name] + opts).join(' ')
24
+ end
25
+
26
+ throw :IRB_EXIT, name.to_sym
27
+ end
28
+ end
29
+
30
+ class Continue < DebuggerResumeCommand ; end
31
+ class Finish < DebuggerResumeCommand ; end
32
+ class Next < DebuggerResumeCommand ; end
33
+ class Quit < DebuggerResumeCommand ; end
34
+ class Step < DebuggerResumeCommand ; end
35
+
36
+ # Issues a comamnd to the debugger without continuing
37
+ # execution.
38
+ class Dbgr
39
+ def self.execute(conf, *opts)
40
+ $trepan_command =
41
+ if opts.size == 1 && opts[0].is_a?(String)
42
+ $trepan_args = opts[0]
43
+ else
44
+ opts.join(' ')
45
+ end
46
+ dbg_cmdproc = conf.workspace.instance_variable_get('@dbg_cmdproc')
47
+ dbg_cmdproc.run_command($trepan_command)
48
+ end
49
+ end
50
+
51
+ end
52
+ if defined?(ExtendCommandBundle)
53
+ # New irb Commands which are the same name as their debugger
54
+ # counterpart
55
+ %w(Dbgr Finish Step).each do |name|
56
+ command = name.downcase
57
+ sym = name.to_sym
58
+ ExtendCommandBundle.def_extend_command command, sym
59
+ end
60
+ # New irb Commands which are the slightly different from their
61
+ # debugger counterpart
62
+ [['cont', :Continue],
63
+ ['n', :Next],
64
+ ['q', :Quit]].each do |command, sym|
65
+ ExtendCommandBundle.def_extend_command command, sym
66
+ end
67
+ end
68
+
69
+ def self.start_session(binding, dbg_cmdproc, conf={})
70
+ unless @__initialized
71
+
72
+ # Set to run the standard rbdbgr IRB profile
73
+ irbrc = File.expand_path(File.join(File.dirname(__FILE__),
74
+ %w(.. data irbrc)))
75
+ ENV['IRBRC'] = irbrc
76
+
77
+ args = ARGV.dup
78
+ ARGV.replace([])
79
+ IRB.setup(nil)
80
+ ARGV.replace(args)
81
+
82
+ # If the user has a IRB profile, run that now.
83
+ if ENV['RBDBGR_IRB']
84
+ ENV['IRBRC'] = ENV['RBDBGR_IRB']
85
+ @CONF[:RC_NAME_GENERATOR]=nil
86
+ IRB.run_config
87
+ end
88
+
89
+ @__initialized = true
90
+ end
91
+
92
+ workspace = WorkSpace.new(binding)
93
+ workspace.instance_variable_set('@dbg_cmdproc', dbg_cmdproc)
94
+
95
+ irb = Irb.new(workspace)
96
+
97
+ @CONF[:IRB_RC].call(irb.context) if @CONF[:IRB_RC]
98
+ @CONF[:MAIN_CONTEXT] = irb.context
99
+ conf.each {|k, v| @CONF[k] = v}
100
+ # A copy of this back_trace_limit is already active. How?
101
+ IRB.CurrentContext.back_trace_limit = @CONF[:BACK_TRACE_LIMIT]
102
+
103
+ catch(:IRB_EXIT) do
104
+ irb.eval_input
105
+ end
106
+ end
107
+ end
108
+
109
+ if __FILE__ == $0
110
+ # Demo it.
111
+ IRB.start_session(binding, nil) if ARGV.size > 0
112
+ end
data/app/mock.rb ADDED
@@ -0,0 +1,22 @@
1
+ # Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
2
+ class Trepan
3
+ attr_accessor :trace_filter # Procs/Methods we ignore.
4
+ def initialize(opts={})
5
+ @trace_filter = []
6
+ end
7
+ class MockDebugger
8
+ attr_reader :initial_dir
9
+ def initialize(settings={})
10
+ @initial_dir = '.'
11
+ end
12
+ end
13
+ class MockCore
14
+ attr_accessor :dbgr
15
+ attr_reader :core
16
+ def initialize
17
+ @dbgr = MockDebugger.new
18
+ end
19
+ def event; 'line' end
20
+ end
21
+ end
22
+
data/app/options.rb ADDED
@@ -0,0 +1,122 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- coding: utf-8 -*-
3
+ # Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
4
+ #=== Summary
5
+ # Parses command-line options.
6
+ #=== Options
7
+ #
8
+ #<tt>--cd=DIR</tt>
9
+ # Change current directory to DIR.
10
+ #
11
+ #<tt>--command</tt> <i>file</i>::
12
+ # Run debugger command file <i>file</i>
13
+ #
14
+ #<tt>--nx</tt>::
15
+ # Don’t execute commands found in any initialization
16
+ # files, e.g. <tt>.rdebugrc</tt>.
17
+ #
18
+ #<tt>--restore=PROFILE</tt>::
19
+ # Debugger command file which restores debugger settings,
20
+ # resumably saved before a 'restart' debugger command.
21
+ #
22
+ #<tt>--version</tt>::
23
+ # Show the version number.
24
+ #
25
+ #<tt>--help</tt>::
26
+ # Show invocation help and exit.
27
+
28
+ require 'optparse'
29
+ module Trepanning
30
+ require_relative 'default'
31
+
32
+ Trepanning::VERSION = '0.0.4.git' unless defined?(Trepanning::VERSION)
33
+ Trepanning::PROGRAM = 'trepan' unless defined?(Rbdbgr::PROGRAM)
34
+
35
+ def show_version
36
+ "#{PROGRAM} version #{VERSION}"
37
+ end
38
+
39
+ def copy_default_options
40
+ options = {}
41
+ DEFAULT_CMDLINE_SETTINGS.each do |key, value|
42
+ begin
43
+ options[key] = value.clone
44
+ rescue TypeError
45
+ options[key] = value
46
+ end
47
+ end
48
+ options
49
+ end
50
+
51
+ def setup_options(options, stdout=$stdout, stderr=$stderr)
52
+ OptionParser.new do |opts|
53
+ opts.banner = <<EOB
54
+ #{show_version}
55
+ Usage: #{PROGRAM} [options] <script.rb> -- <script.rb parameters>
56
+ EOB
57
+ opts.on('--command FILE', String,
58
+ "Execute debugger commnds from FILE") do |cmdfile|
59
+ if File.readable?(cmdfile)
60
+ options[:cmdfiles] << cmdfile
61
+ elsif File.exists?(cmdfile)
62
+ stderr.puts "Command file '#{cmdfile}' is not readable."
63
+ else
64
+ stderr.puts "Command file '#{cmdfile}' does not exist."
65
+ end
66
+ end
67
+ opts.on('--nx',
68
+ "Do not run debugger initialization files (e.g. #{CMD_INITFILE}") do
69
+ options[:nx] = true
70
+ end
71
+ # opts.on('--output FILE', String, "Name of file to record output") do |outfile|
72
+ # options[:outfile] = outfile
73
+ # end
74
+ opts.on("--cd DIR", String, "Change current directory to DIR") do |dir|
75
+ if File.directory?(dir)
76
+ if File.executable?(dir)
77
+ options[:chdir] = dir
78
+ else
79
+ stderr.puts "Can't cd to #{dir}. Option --cd ignored."
80
+ end
81
+ else
82
+ stderr.puts "\"#{dir}\" is not a directory. Option --cd ignored."
83
+ end
84
+ end
85
+ opts.on("--restore PROFILE", String,
86
+ "Restore debugger state using PROFILE") do |profile|
87
+ if File.readable?(profile)
88
+ options[:restore_profile] = profile
89
+ stderr.puts "Debugger command file #{profile} is not readable. --restore option ignored."
90
+ end
91
+ end
92
+ opts.on_tail("--help", "Show this message") do
93
+ options[:help] = true
94
+ stdout.puts opts
95
+ end
96
+ opts.on_tail("--version",
97
+ "print the version") do
98
+ options[:version] = true
99
+ stdout.puts show_version
100
+ end
101
+ end
102
+ end
103
+ end
104
+
105
+ if __FILE__ == $0
106
+ include Rbdbgr
107
+ opts = {}
108
+ options ={}
109
+ [%w(--help), %w(--version)].each do |o|
110
+ options = copy_default_options
111
+ opts = setup_options(options)
112
+ rest = opts.parse o
113
+ puts options
114
+ puts '=' * 10
115
+ end
116
+ rest = opts.parse! ARGV
117
+ puts opts.to_s
118
+ puts '=' * 10
119
+ puts options
120
+ puts '=' * 10
121
+ puts Rbdbgr::DEFAULT_CMDLINE_SETTINGS
122
+ end
data/app/run.rb ADDED
@@ -0,0 +1,95 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
3
+ require 'rbconfig'
4
+ module Trepanning
5
+
6
+ :module_function # All functions below are easily publically accessible
7
+
8
+ # Given a Ruby interpreter and program we are to debug, debug it.
9
+ # The caller must ensure that ARGV is set up to remove any debugger
10
+ # arguments or things that the debugged program isn't supposed to
11
+ # see. FIXME: Should we make ARGV an explicit parameter?
12
+ def debug_program(dbgr, ruby_path, program_to_debug)
13
+
14
+ # Make sure Ruby script syntax checks okay.
15
+ # Otherwise we get a load message that looks like trepanning has
16
+ # a problem.
17
+ output = `#{ruby_path} -c #{program_to_debug.inspect} 2>&1`
18
+ if $?.exitstatus != 0 and RUBY_PLATFORM !~ /mswin/
19
+ puts output
20
+ exit $?.exitstatus
21
+ end
22
+ # print "\032\032starting\n" if Trepan.annotate and Trepan.annotate > 2
23
+
24
+ dbgr.trace_filter << self.method(:debug_program)
25
+ dbgr.trace_filter << Kernel.method(:load)
26
+
27
+ old_dollar_0 = $0
28
+
29
+ # Without the dance below to set $0, setting it to a signifcantly
30
+ # longer value will truncate it in some OS's. See
31
+ # http://www.ruby-forum.com/topic/187083
32
+ $progname = program_to_debug
33
+ alias $0 $progname
34
+ dollar_0_tracker = lambda {|val| $program_name = val}
35
+ trace_var(:$0, dollar_0_tracker)
36
+
37
+ dbgr.debugger(:hide_stack=>true) do
38
+ dbgr.core.processor.hidelevels[Thread.current] =
39
+ RubyVM::ThreadFrame.current.stack_size + 1
40
+ Kernel::load program_to_debug
41
+ end
42
+
43
+ # The dance we have to undo to restore $0 and undo the mess created
44
+ # above.
45
+ $0 = old_dollar_0
46
+ untrace_var(:$0, dollar_0_tracker)
47
+ end
48
+
49
+ # Return an ARRAY which makes explicit what array is needed to pass
50
+ # to system() to reinvoke this debugger using the same Ruby
51
+ # interpreter. Therefore, We want to the full path of both the Ruby
52
+ # interpreter and the debugger file ($0). We do this so as not to
53
+ # rely on an OS search lookup and/or the current working directory
54
+ # not getting changed from the initial invocation.
55
+ #
56
+ # Hmmm, perhaps it is better to also save the initial working
57
+ # directory? Yes, but on the other hand we can't assume that it
58
+ # still exists so we might still need to have the full paths.
59
+ #
60
+ # It is the caller's responsibility to ensure that argv is the same
61
+ # as ARGV when the debugger was invokes.
62
+ def explicit_restart_argv(argv)
63
+ [ruby_path, File.expand_path($0)] + argv
64
+ end
65
+
66
+ # Path name of Ruby interpreter we were invoked with.
67
+ def ruby_path
68
+ File.join(%w(bindir RUBY_INSTALL_NAME).map{|k| RbConfig::CONFIG[k]})
69
+ end
70
+ module_function :ruby_path
71
+
72
+ # Do a shell-like path lookup for prog_script and return the results.
73
+ # If we can't find anything return prog_script.
74
+ def whence_file(prog_script)
75
+ if prog_script.index(File::SEPARATOR)
76
+ # Don't search since this name has path separator components
77
+ return prog_script
78
+ end
79
+ for dirname in ENV['PATH'].split(File::PATH_SEPARATOR) do
80
+ prog_script_try = File.join(dirname, prog_script)
81
+ return prog_script_try if File.readable?(prog_script_try)
82
+ end
83
+ # Failure
84
+ return prog_script
85
+ end
86
+ end
87
+
88
+ if __FILE__ == $0
89
+ # Demo it.
90
+ include Trepanning
91
+ puts whence_file('irb')
92
+ puts whence_file('probably-does-not-exist')
93
+ puts ruby_path
94
+ p explicit_restart_argv(ARGV)
95
+ end
data/app/thread.rb ADDED
@@ -0,0 +1,24 @@
1
+ # Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
2
+ class Trepan
3
+ module ThreadHelper
4
+ # Return the thread at position num or object_id num.
5
+ def get_thread(num)
6
+ Thread.list.at(num) ||
7
+ Thread.list.detect {|t| t.object_id == num}
8
+ end
9
+ module_function :get_thread
10
+ end
11
+ end
12
+
13
+ # Demo it.
14
+ if __FILE__ == $0
15
+ include Trepan::ThreadHelper
16
+ Object::Thread.new do
17
+ [2, -2, 0, 1, -1,
18
+ Thread.main.object_id,
19
+ Thread.current.object_id].each do |th_num|
20
+ puts "get_thread(#{th_num}) = #{get_thread(th_num).inspect}"
21
+ end
22
+ end.join
23
+
24
+ end
data/app/util.rb ADDED
@@ -0,0 +1,32 @@
1
+ # Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
2
+ class Trepan
3
+ module Util
4
+
5
+ def safe_repr(str, max, suffix='...')
6
+ if str.is_a?(String) && str.size > max && !str.index("\n")
7
+ char = str[0..0]
8
+ opt_quote =
9
+ if '"' == char || "'" == char
10
+ max -= 1
11
+ char
12
+ else
13
+ ''
14
+ end
15
+ "%s%s%s" % [ str[0...max], opt_quote, suffix ]
16
+ else
17
+ str
18
+ end
19
+ end
20
+ module_function :safe_repr
21
+
22
+ end
23
+ end
24
+
25
+ if __FILE__ == $0
26
+ include Trepan::Util
27
+ string = 'The time has come to talk of many things.'
28
+ puts safe_repr(string, 50)
29
+ puts safe_repr(string, 17)
30
+ puts safe_repr(string.inspect, 17)
31
+ puts safe_repr(string.inspect, 17, '')
32
+ end