trepanning 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
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,131 @@
1
+ # Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
2
+ # For recording hook events in a buffer for review later. Make use of
3
+ # Trace::Buffer for this prupose.
4
+ require 'trace'
5
+ require 'linecache'
6
+
7
+ class Trepan
8
+ class CmdProcessor
9
+
10
+ attr_reader :eventbuf
11
+ attr_reader :event_tracefilter
12
+
13
+ def eventbuf_initialize(size=100)
14
+ @eventbuf = Trace::EventBuffer.new(size)
15
+ # @event_tracefilter = Trace::Filter.new
16
+ end
17
+
18
+ # def event_processor(event, frame, arg=nil)
19
+ # @eventbuf.append(event, frame, arg)
20
+ # end
21
+
22
+ # Print event buffer entries from FROM up to TO try to stay within
23
+ # WIDTH. We show source lines only the first time they are
24
+ # encountered. Also we use separators to indicate points that the
25
+ # debugger has stopped at.
26
+ def eventbuf_print(from=nil, to=nil, width=80)
27
+ sep = '-' * ((width - 7) / 2)
28
+ last_container, last_location = nil, nil
29
+ if from == nil || !@eventbuf.marks[-1]
30
+ mark_index = 0
31
+ else
32
+ mark_index = @eventbuf.marks.size-1
33
+ translated_from = @eventbuf.zero_pos + from
34
+ @eventbuf.marks.each_with_index do
35
+ |m, i|
36
+ if m > translated_from
37
+ mark_index = [0, i-1].max
38
+ break
39
+ elsif m == translated_from
40
+ mark_index = i
41
+ break
42
+ end
43
+ end
44
+ end
45
+
46
+ nextmark = @eventbuf.marks[mark_index]
47
+ @eventbuf.each_with_index(from, to) do |e, i|
48
+ if nextmark
49
+ if nextmark == i
50
+ msg "#{sep} %5d #{sep}" % (mark_index - @eventbuf.marks.size)
51
+ mark_index += 1 if mark_index < @eventbuf.marks.size - 1
52
+ nextmark = @eventbuf.marks[mark_index]
53
+ elsif nextmark < i
54
+ mark_index += 1 if mark_index < @eventbuf.marks.size - 1
55
+ nextmark = @eventbuf.marks[mark_index]
56
+ end
57
+ end
58
+ last_container, last_location, mess =
59
+ format_eventbuf_entry(e, last_container, last_location) if e
60
+ msg mess
61
+ end
62
+ end
63
+
64
+ # Show event buffer entry. If the location is the same as the previous
65
+ # location we don't show the duplicated location information.
66
+ def format_eventbuf_entry(item, last_container, last_location)
67
+ container =
68
+ if item.source_container[0] == 'file'
69
+ item.source_container[1]
70
+ else
71
+ item.source_container
72
+ end
73
+
74
+ location =
75
+ if 1 == item.source_location.size
76
+ item.source_location[0]
77
+ else
78
+ item.source_location
79
+ end
80
+
81
+ same_loc = (container == last_container && location == last_location)
82
+ mess = "#{item.event} "
83
+ mess +=
84
+ if %w(c-return return).member?(item.event)
85
+ "#{item.method} => #{item.arg.inspect}" + (same_loc ? '' : "\n\t")
86
+ elsif 'c-call' == item.event
87
+ "#{item.method} "
88
+ else
89
+ "#{item.type} #{item.method} "
90
+ end
91
+ mess += "#{container} at line #{location}" unless same_loc
92
+
93
+ if item.iseq # && long_format
94
+ mess += "\n\tVM offset #{item.pc_offset}"
95
+ end
96
+ unless same_loc
97
+ text = LineCache::getline(container, location, @reload_on_change)
98
+ mess += ":\n #{text.chomp}" if text
99
+ end
100
+ return container, location, mess
101
+ end
102
+
103
+ # FIXME: multiple hook mechanism needs work.
104
+ # def start_capture
105
+ # @event_tracefilter.add_trace_func(method(:event_processor).to_proc,
106
+ # Trace::DEFAULT_EVENT_MASK)
107
+ # end
108
+
109
+ # def stop_capture
110
+ # @event_tracefilter.set_trace_func(nil)
111
+ # end
112
+
113
+ end
114
+ end
115
+ if __FILE__ == $0
116
+ # Demo it.
117
+ cmdproc = Trepan::CmdProcessor.new
118
+ cmdproc.eventbuf_initialize(5)
119
+
120
+ def cmdproc.msg(mess)
121
+ puts mess
122
+ end
123
+ # cmdproc.start_capture
124
+ # z=5
125
+ # z.times do |i|
126
+ # x = i
127
+ # y = x+2
128
+ # end
129
+ # cmdproc.stop_capture
130
+ cmdproc.eventbuf_print
131
+ end
@@ -0,0 +1,230 @@
1
+ # Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
2
+ require 'tempfile'
3
+ require 'linecache'
4
+ require_relative '../app/frame'
5
+ class Trepan
6
+ class CmdProcessor
7
+
8
+ attr_reader :current_thread
9
+ attr_accessor :frame # ThreadFrame, current frame
10
+ attr_accessor :frame_index # frame index in a "where" command
11
+ attr_accessor :hide_level #
12
+ attr_accessor :hidelevels # Hash[thread_id] -> FixNum, the
13
+ # level of the last frame to
14
+ # show. If we called the debugger
15
+ # directly, then there is generally
16
+ # a portion of a backtrace we don't
17
+ # want to show. We don't need to
18
+ # store this for all threads, just
19
+ # those we want to hide frame on. A
20
+ # value of 1 means to hide just the
21
+ # oldest level. The default or
22
+ # showing all levels is 0.
23
+ attr_accessor :remap_container # Hash[container] -> file container
24
+ # Gives us a way to map non-file
25
+ # container objects to a file
26
+ # container for display.
27
+ attr_accessor :remap_iseq # Hash[iseq] -> file container
28
+
29
+ attr_accessor :top_frame # top frame of current thread. Since
30
+ # right now the ThreadFrame method has "prev"
31
+ # but no way to move in the other direction.
32
+ # So we store the top frame.
33
+ attr_reader :threads2frames # Hash[thread_id] -> top_frame
34
+
35
+
36
+ def adjust_frame(frame_num, absolute_pos)
37
+ frame, frame_num = get_frame(frame_num, absolute_pos)
38
+ if frame
39
+ @frame = frame
40
+ @frame_index = frame_num
41
+ frame_eval_remap if 'EVAL' == @frame.type
42
+ print_location
43
+ @line_no = frame_line() - 1
44
+ @frame
45
+ else
46
+ nil
47
+ end
48
+ end
49
+
50
+ def frame_container(frame, canonicalize=true)
51
+ container =
52
+ if @remap_container.member?(frame.source_container)
53
+ @remap_container[frame.source_container]
54
+ elsif frame.iseq && @remap_iseq.member?(frame.iseq.sha1)
55
+ @remap_iseq[frame.iseq.sha1]
56
+ else
57
+ frame.source_container
58
+ end
59
+
60
+ container[1] = canonic_file(container[1]) if canonicalize
61
+ container
62
+ end
63
+
64
+ # If frame type is EVAL, set up to remap the string to a temporary file.
65
+ def frame_eval_remap
66
+ to_str = Trepan::Frame::eval_string(@frame)
67
+ return nil unless to_str.is_a?(String)
68
+
69
+ # All systems go!
70
+ unless @remap_iseq.member?(@frame.iseq.sha1)
71
+ tempfile = Tempfile.new(['eval-', '.rb'])
72
+ tempfile.open.puts(to_str)
73
+
74
+ @remap_iseq[@frame.iseq.sha1] = ['file', tempfile.path]
75
+ tempfile.close
76
+ LineCache::cache(tempfile.path)
77
+ end
78
+ return true
79
+ end
80
+
81
+ def frame_line
82
+ if @event == 'vm-insn' && @frame.iseq
83
+ pc_offset = @frame.pc_offset
84
+ return 0 unless pc_offset
85
+ @frame.iseq.offset2lines(pc_offset)[0]
86
+ else
87
+ (@frame.source_location && @frame.source_location[0]) || 0
88
+ end
89
+ end
90
+
91
+ # Initializes the thread and frame variables: @frame, @top_frame,
92
+ # @frame_index, @current_thread, and @threads2frames
93
+ def frame_setup(frame_thread)
94
+ @frame_index = 0
95
+ @frame = @top_frame = frame_thread
96
+ @current_thread = @frame.thread
97
+ @stack_size = @frame.stack_size
98
+
99
+ @threads2frames ||= {}
100
+ @threads2frames[@current_thread] = @top_frame
101
+ @hide_level =
102
+ if @settings[:debugstack]
103
+ 0
104
+ else
105
+ @hidelevels[@current_thread]
106
+ end
107
+
108
+ frame_eval_remap if 'EVAL' == @frame.type
109
+ end
110
+
111
+ # Remove access to thread and frame variables
112
+ def frame_teardown
113
+ @top_frame = @frame = @frame_index = @current_thread = nil
114
+ @threads2frames = {}
115
+ end
116
+
117
+ def frame_initialize
118
+ @remap_container = {}
119
+ @remap_iseq = {}
120
+ @hidelevels = Hash.new(0) # Set default value to 0
121
+ @hide_level = 0
122
+ end
123
+
124
+ def get_frame(frame_num, absolute_pos)
125
+ stack_size = @top_frame.stack_size - @hide_level
126
+
127
+ if absolute_pos
128
+ frame_num += stack_size if frame_num < 0
129
+ else
130
+ frame_num += @frame_index
131
+ end
132
+
133
+ if frame_num < 0
134
+ errmsg('Adjusting would put us beyond the newest frame.')
135
+ return [nil, nil]
136
+ elsif frame_num >= stack_size
137
+ errmsg('Adjusting would put us beyond the oldest frame.')
138
+ return [nil, nil]
139
+ end
140
+
141
+ frame = @top_frame.prev(frame_num)
142
+ while 'IFUNC' == frame.type && frame.prev
143
+ frame = frame.prev
144
+ frame_num += 1
145
+ end
146
+
147
+ [frame, frame_num]
148
+ end
149
+
150
+ def get_nonsync_frame(tf)
151
+ if (tf.stack_size > 10)
152
+ check_frames = (0..5).map{|i| tf.prev(i).method}
153
+ if check_frames ==
154
+ %w(synchronize event_processor IFUNC call trace_hook IFUNC)
155
+ return tf.prev(6)
156
+ end
157
+ end
158
+ tf
159
+ end
160
+
161
+ def get_frame_from_thread(th)
162
+ if th == Thread.current
163
+ @threads2frames[th]
164
+ else
165
+ # FIXME: Check to see if we are blocked on entry to debugger.
166
+ # If so, walk back frames.
167
+ tf = get_nonsync_frame(th.threadframe)
168
+ @threads2frames = tf
169
+ end
170
+ end
171
+
172
+ # The dance we have to do to set debugger frame state to
173
+ # `frame', which is in the thread with id `thread_id'. We may
174
+ # need to the hide initial debugger frames.
175
+ def find_and_set_debugged_frame(th, position)
176
+
177
+ thread = threading._active[thread_id]
178
+ thread_name = thread.getName()
179
+ if (!@settings['dbg_pydbgr'] &&
180
+ thread_name == Mthread.current_thread_name())
181
+ # The frame we came in on ('current_thread_name') is
182
+ # the same as the one we want to switch to. In this case
183
+ # we need to some debugger frames are in this stack so
184
+ # we need to remove them.
185
+ newframe = Mthread.find_debugged_frame(frame)
186
+ frame = newframe unless newframe
187
+ end
188
+ ## FIXME: else: we might be blocked on other threads which are
189
+ # about to go into the debugger it not for the fact this one got there
190
+ # first. Possibly in the future we want
191
+ # to hide the blocks into threading of that locking code as well.
192
+
193
+ # Set stack to new frame
194
+ @frame, @curindex = Mcmdproc.get_stack(frame, nil, self.proc)
195
+ @proc.stack, @proc.curindex = self.stack, self.curindex
196
+
197
+ # @frame_thread_name = thread_name
198
+ end
199
+ end
200
+ end
201
+
202
+ if __FILE__ == $0
203
+ # Demo it.
204
+ require 'thread_frame'
205
+ require_relative '../app/mock'
206
+ require_relative 'main' # Have to include before defining CmdProcessor!
207
+ # FIXME
208
+ class Trepan::CmdProcessor
209
+ def errmsg(msg)
210
+ puts msg
211
+ end
212
+ def print_location
213
+ puts "#{@frame.source_container} #{frame.source_location[0]}"
214
+ end
215
+ end
216
+
217
+ proc = Trepan::CmdProcessor.new(Trepan::MockCore.new())
218
+ proc.frame_setup(RubyVM::ThreadFrame.current)
219
+ proc.hidelevels = {}
220
+ puts "stack size: #{proc.top_frame.stack_size}"
221
+ 0.upto(proc.top_frame.stack_size) { |i| proc.adjust_frame(i, true) }
222
+ puts '*' * 10
223
+ proc.adjust_frame(-1, true)
224
+ proc.adjust_frame(0, true)
225
+ puts '*' * 10
226
+ proc.top_frame.stack_size.times { proc.adjust_frame(1, false) }
227
+ proc.adjust_frame(proc.top_frame.stack_size-1, true)
228
+ proc.top_frame.stack_size.times { proc.adjust_frame(-1, false) }
229
+
230
+ end
data/processor/help.rb ADDED
@@ -0,0 +1,72 @@
1
+ # Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
2
+ class Trepan
3
+ module Help
4
+
5
+ def abbrev_stringify(name, min_abbrev)
6
+ "(#{name[0..min_abbrev-1]})#{name[min_abbrev..-1]}"
7
+ end
8
+
9
+ def summary_help(subcmd)
10
+ # Set class constant SHORT_HELP to be the first line of HELP
11
+ # unless it has been defined in the class already.
12
+ # The below was the simplest way I could find to do this since
13
+ # we are the super class but want to set the subclass's constant.
14
+ # defined? didn't seem to work here.
15
+ c = subcmd.class.constants
16
+ if c.member?(:HELP) and !c.member?(:SHORT_HELP)
17
+ short_help = subcmd.class.const_get('HELP').split("\n")[0].chomp('.')
18
+ subcmd.class.const_set(:SHORT_HELP, short_help)
19
+ end
20
+
21
+ ' %-12s -- %s' %
22
+ [abbrev_stringify(obj_const(subcmd, :NAME),
23
+ obj_const(subcmd, :MIN_ABBREV)),
24
+ obj_const(subcmd, :SHORT_HELP)]
25
+ end
26
+
27
+ # We were given cmd without a subcommand; cmd is something
28
+ # like "show", "info" or "set". Generally this means list
29
+ # all of the subcommands.
30
+ def summary_list(name, subcmds)
31
+ msg "List of #{name} commands (with minimum abbreviation in parenthesis):"
32
+ subcmds.list.each do |subcmd_name|
33
+ # Some commands have lots of output.
34
+ # they are excluded here because 'in_list' is false.
35
+ msg summary_help(subcmds.subcmds[subcmd_name])
36
+ end
37
+ end
38
+
39
+
40
+ # Error message when subcommand asked for but doesn't exist
41
+ def undefined_subcmd(cmd, subcmd)
42
+ errmsg(('Undefined "%s" subcommand: "%s". ' +
43
+ 'Try "help %s *".') % [cmd, subcmd, cmd])
44
+ end
45
+
46
+ end
47
+ end
48
+
49
+ if __FILE__ == $0
50
+ class TestClass
51
+ include Trepan::Help
52
+ HELP = 'TestClass HELP.
53
+
54
+ Long description goes here.'
55
+ MIN_ABBREV = 1
56
+ NAME = File.basename(__FILE__)
57
+ def obj_const(obj, name)
58
+ obj.class.const_get(name)
59
+ end
60
+ def msg(mess)
61
+ puts mess
62
+ end
63
+ def errmsg(mess)
64
+ puts "***#{mess}"
65
+ end
66
+ def initialize
67
+ puts summary_help(self)
68
+ undefined_subcmd('foo', 'bar')
69
+ end
70
+ end
71
+ TestClass.new
72
+ end
data/processor/hook.rb ADDED
@@ -0,0 +1,128 @@
1
+ # Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
2
+ class Trepan
3
+ class CmdProcessor
4
+ # Command processor hooks.
5
+ attr_reader :autoirb_hook
6
+ attr_reader :autolist_hook
7
+ attr_reader :debug_dbgr_hook
8
+ attr_reader :display_hook
9
+ attr_reader :timer_hook
10
+ attr_reader :trace_hook
11
+ attr_reader :tracebuf_hook
12
+ attr_reader :unconditional_prehooks
13
+ attr_reader :cmdloop_posthooks
14
+ attr_reader :cmdloop_prehooks
15
+
16
+ # Used to time how long a debugger action takes
17
+ attr_accessor :time_last
18
+
19
+ class Hook
20
+ attr_accessor :list
21
+
22
+ def initialize(list=[])
23
+ @list = list
24
+ end
25
+
26
+ def delete_by_name(delete_name)
27
+ @list.delete_if {|hook_name, priority, hook| hook_name == delete_name}
28
+ end
29
+
30
+ def empty?
31
+ @list.empty?
32
+ end
33
+
34
+ def insert(priority, name, hook)
35
+ insert_loc = @list.size # at end
36
+ @list.each_with_index do |entry, index|
37
+ n, p, h = entry
38
+ if priority > p
39
+ insert_loc = index
40
+ break
41
+ end
42
+ end
43
+ @list.insert(insert_loc, [name, priority, hook])
44
+ end
45
+
46
+ def insert_if_new(priority, name, hook)
47
+ insert(priority, name, hook) unless
48
+ @list.find {|try_name, try_priority, try_hook| try_name == name}
49
+ end
50
+
51
+ # Run each function in `hooks' with args
52
+ def run(*args)
53
+ @list.each do |name, priority, hook|
54
+ hook.call(name, *args)
55
+ end
56
+ end
57
+
58
+ # Could add delete_at and delete if necessary.
59
+ end
60
+
61
+ def hook_initialize(commands)
62
+ @cmdloop_posthooks = Hook.new
63
+ @cmdloop_prehooks = Hook.new
64
+ @unconditional_prehooks = Hook.new
65
+
66
+ irb_cmd = commands['irb']
67
+ @autoirb_hook = ['autoirb',
68
+ Proc.new{|*args| irb_cmd.run(['irb']) if irb_cmd}]
69
+
70
+ @debug_dbgr_hook = ['dbgdbgr',
71
+ Proc.new{|*args|
72
+ if settings[:debugdbgr]
73
+ $trepan_cmdproc = self
74
+ $trepan_frame = frame
75
+ else
76
+ $trepan_cmdproc = nil
77
+ $trepan_frame = nil
78
+ end}]
79
+
80
+ display_cmd = commands['display']
81
+ @display_hook = ['display',
82
+ Proc.new{|*args| display_cmd.run(['display']) if
83
+ display_cmd}]
84
+
85
+ list_cmd = commands['list']
86
+ @autolist_hook = ['autolist',
87
+ Proc.new{|*args| list_cmd.run(['list']) if list_cmd}]
88
+
89
+ @timer_hook = ['timer',
90
+ Proc.new{|*args|
91
+ now = Time.now
92
+ msg("%g seconds" %
93
+ (now - @time_last)) if @time_last
94
+ @time_last = now
95
+ }]
96
+ @timer_posthook = ['timer', Proc.new{|*args| @time_last = Time.now}]
97
+ @trace_hook = ['trace',
98
+ Proc.new{|*args| print_location}]
99
+ @tracebuf_hook = ['tracebuffer',
100
+ Proc.new{|*args| @eventbuf.append(@event, @frame,
101
+ @core.hook_arg)}]
102
+ end
103
+
104
+ end
105
+ end
106
+ if __FILE__ == $0
107
+ # Demo it.
108
+ hooks = Trepan::CmdProcessor::Hook.new
109
+ hooks.run(5)
110
+ hook1 = Proc.new {|name, a| puts "#{name} called with #{a}"}
111
+ hooks = Trepan::CmdProcessor::Hook.new()
112
+ hooks.insert(-1, 'hook1', hook1)
113
+ p hooks.list
114
+ hooks.insert_if_new(-1, 'hook1', hook1)
115
+ puts '-' * 30
116
+ p hooks.list
117
+ hooks.run(10)
118
+ puts '-' * 30
119
+ hooks.insert(-1, 'hook2', hook1)
120
+ hooks.run(20)
121
+ puts '-' * 30
122
+ hooks.delete_by_name('hook2')
123
+ hooks.run(30)
124
+ puts '-' * 30
125
+ hooks.delete_by_name('hook1')
126
+ hooks.run(30)
127
+ puts '-' * 30
128
+ end
@@ -0,0 +1,102 @@
1
+ # Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
2
+ # Trepan::CmdProcess that loads up debugger commands from builtin and
3
+ # user directories.
4
+ # Sets @commands, @aliases, @macros
5
+ class Trepan
6
+ class CmdProcessor
7
+
8
+ attr_reader :aliases # Hash[String] of command names
9
+ # indexed by alias name
10
+ attr_reader :commands # Hash[String] of command objects
11
+ # indexed by name
12
+ attr_reader :macros # Hash[String] of Proc objects
13
+ # indexed by macro name.
14
+
15
+ # "initialize" for multi-file class. Called from main.rb's "initialize".
16
+ def load_cmds_initialize
17
+ @commands = {}
18
+ @aliases = {}
19
+ @macros = {}
20
+
21
+ cmd_dirs = [ File.join(File.dirname(__FILE__), 'command') ]
22
+ cmd_dirs << @settings[:user_cmd_dir] if @settings[:user_cmd_dir]
23
+ cmd_dirs.each do |cmd_dir|
24
+ load_debugger_commands(cmd_dir) if File.directory?(cmd_dir)
25
+ end
26
+ end
27
+
28
+ # Loads in debugger commands by require'ing each ruby file in the
29
+ # 'command' directory. Then a new instance of each class of the
30
+ # form Trepan::xxCommand is added to @commands and that array
31
+ # is returned.
32
+
33
+ def load_debugger_commands(cmd_dir)
34
+ Dir.glob(File.join(cmd_dir, '*.rb')).each do |rb|
35
+ require rb
36
+ end if File.directory?(cmd_dir)
37
+ # Instantiate each Command class found by the above require(s).
38
+ ### p Trepan::Command.constants ## REMOVE ME
39
+ Trepan::Command.constants.grep(/.Command$/).each do |command|
40
+ # Note: there is probably a non-eval way to instantiate the
41
+ # command, but I don't know it. And eval works.
42
+ new_cmd = "Trepan::Command::#{command}.new(self)"
43
+ cmd = self.instance_eval(new_cmd)
44
+
45
+ # Add to list of commands and aliases.
46
+ cc = cmd.class
47
+ cmd_name = cc.const_get(:NAME)
48
+ if cc.constants.member?(:ALIASES)
49
+ aliases= cc.const_get(:ALIASES)
50
+ aliases.each {|a| @aliases[a] = cmd_name}
51
+ end
52
+ @commands[cmd_name] = cmd
53
+ end
54
+ end
55
+
56
+ # Looks up cmd_array[0] in @commands and runs that. We do lots of
57
+ # validity testing on cmd_array.
58
+ def run_cmd(cmd_array)
59
+ unless cmd_array.is_a?(Array)
60
+ errmsg "run_cmd argument should be an Array, got: #{cmd_array.class}"
61
+ return
62
+ end
63
+ if cmd_array.detect{|item| !item.is_a?(String)}
64
+ errmsg "run_cmd argument Array should only contain strings. " +
65
+ "Got #{cmd_array.inspect}"
66
+ return
67
+ end
68
+ if cmd_array.empty?
69
+ errmsg "run_cmd Array should have at least one item. " +
70
+ "Got: #{cmd_array.inspect}"
71
+ return
72
+ end
73
+ cmd_name = cmd_array[0]
74
+ if @commands.member?(cmd_name)
75
+ @commands[cmd_name].run(cmd_array)
76
+ end
77
+ end
78
+ end
79
+ end
80
+ if __FILE__ == $0
81
+ cmdproc = Trepan::CmdProcessor.new
82
+ cmddir = File.join(File.dirname(__FILE__), 'command')
83
+ cmdproc.instance_variable_set('@settings', {})
84
+ cmdproc.load_cmds_initialize
85
+ require 'columnize'
86
+ puts Columnize.columnize(cmdproc.commands.keys.sort)
87
+ puts '=' * 20
88
+ puts Columnize.columnize(cmdproc.aliases.keys.sort)
89
+ puts '=' * 20
90
+
91
+ def cmdproc.errmsg(mess)
92
+ puts "** #{mess}"
93
+ end
94
+
95
+ def cmdproc.msg(mess)
96
+ puts mess
97
+ end
98
+
99
+ cmdproc.run_cmd('foo') # Invalid - not an Array
100
+ cmdproc.run_cmd([]) # Invalid - empty Array
101
+ cmdproc.run_cmd(['list', 5]) # Invalid - nonstring arg
102
+ end