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/core.rb ADDED
@@ -0,0 +1,203 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
3
+ require 'thread_frame'
4
+ require 'trace'
5
+ # require_relative '../../rb-trace/app/trace'
6
+ require_relative '../processor/main'
7
+ class Trepan
8
+ # This class contains the Trepan core routines, such as an event
9
+ # processor which is responsible of handling what to do when an event is
10
+ # triggered.
11
+ #
12
+ # See also 'rdbgr' the top-level Trepan class and command-line routine
13
+ # which ultimately will call this.
14
+
15
+ class Core
16
+ attr_accessor :async_events # bitmask of asyncronous events - used all
17
+ # the time
18
+ attr_reader :dbgr # Trepan instance
19
+ attr_reader :event # String - event which triggering event
20
+ # processor
21
+ attr_reader :event_proc # Proc of method event_processor
22
+ attr_accessor :exception # Return exception to pass back. A 'raise'
23
+ # command can set this.
24
+ attr_reader :frame # ThreadFrame instance
25
+ attr_reader :hook_arg # 'arg' passed from trace hook
26
+ attr_accessor :mutex # mutex to lock out other threads from
27
+ # entering debugger while we are in it.
28
+ attr_accessor :processor # Trepan::CmdProc instance
29
+ attr_reader :settings # Hash of things you can configure
30
+ attr_accessor :step_count # Fixnum. Negative means no tracing,
31
+ # 0 means stop on next event, 1 means
32
+ # ignore one event. Step events gives the
33
+ # kind of things to count as a step.
34
+ attr_accessor :step_events # bitmask of events - used only when
35
+ # we are stepping
36
+ attr_accessor :unmaskable_events
37
+
38
+ include Trace
39
+
40
+ unless defined?(CORE_DEFAULT_SETTINGS)
41
+ # Synchronous events
42
+ STEPPING_EVENT_MASK =
43
+ LINE_EVENT_MASK | CLASS_EVENT_MASK | CALL_EVENT_MASK |
44
+ RETURN_EVENT_MASK | C_CALL_EVENT_MASK | C_RETURN_EVENT_MASK |
45
+ INSN_EVENT_MASK | BRKPT_EVENT_MASK
46
+
47
+ ASYNC_EVENT_MASK =
48
+ RAISE_EVENT_MASK | VM_EVENT_MASK | SWITCH_EVENT_MASK
49
+
50
+ CORE_DEFAULT_SETTINGS = {
51
+ :cmdproc_opts => {},
52
+ :debug_core_events => false,
53
+ :hook_name => :event_processor, # or :old_event_processor
54
+ :step_count => 0, # Stop at next event
55
+ :async_events => ASYNC_EVENT_MASK,
56
+
57
+ # FIXME:
58
+ # Somewhere inside the VM we allow I guess nested tracing which is messing
59
+ # up ThreadFrame pointers and information. When this is fixed we can do the below.
60
+ # Until then we need to at least remove C calls and returns and possibly other
61
+ # events as well.
62
+ # :step_events =>
63
+ # (DEFAULT_EVENT_MASK | INSN_EVENT_MASK)
64
+
65
+ :step_events =>
66
+ (DEFAULT_EVENT_MASK | INSN_EVENT_MASK) &
67
+ ~(C_CALL_EVENT_MASK | C_RETURN_EVENT_MASK)
68
+ }
69
+
70
+ end
71
+
72
+ def initialize(debugger, settings={})
73
+ @dbgr = debugger
74
+ @exception = nil
75
+ @mutex = Mutex.new
76
+ @settings = CORE_DEFAULT_SETTINGS.merge(settings)
77
+
78
+ @step_count = @settings[:step_count]
79
+ @step_events = @settings[:step_events]
80
+ @async_events = @settings[:async_events]
81
+ @debug_events = @settings[:debug_core_events]
82
+
83
+ hook_name = @settings[:hook_name]
84
+ @event_proc = self.method(hook_name).to_proc
85
+ @processor = CmdProcessor.new(self, @settings[:cmdproc_opts])
86
+ @unmaskable_events = %w(brkpt raise switch vm)
87
+ end
88
+
89
+ def step_events_list
90
+ if 0 == @step_events
91
+ return nil
92
+ else
93
+ Trace.bitmask2events(@step_events).join(', ')
94
+ end
95
+ end
96
+
97
+ # A trace-hook processor with the interface a trace hook should have.
98
+ def event_processor(event, frame, arg=nil)
99
+
100
+ return_exception = nil
101
+ # FIXME: check for breakpoints or other unmaskable events.
102
+ # For now there are none.
103
+
104
+ @mutex.synchronize do
105
+ @frame = frame
106
+ while @frame.type == 'IFUNC'
107
+ @frame = @frame.prev
108
+ end
109
+
110
+ if @step_count > 0
111
+ @step_count -= 1
112
+ break
113
+ elsif @step_count < 0 && ! @unmaskable_events.member?(event)
114
+ break
115
+ end
116
+
117
+ @event = event
118
+ @hook_arg = arg
119
+
120
+ ### debug:
121
+ ### puts "#{frame.source_container[1]}:#{frame.source_location[0]}:in `#{frame.method}' #{event}" # if %w(line).member?(event)
122
+ @processor.process_commands(@frame)
123
+
124
+ # FIXME: There should be a Trace.event_mask which should return the first
125
+ # mask that matches the given trace hook.
126
+ if @step_count < 0
127
+ # If we are continuing, no need to stop at stepping events.
128
+ Trace.event_masks[0] &= ~STEPPING_EVENT_MASK
129
+ else
130
+ # Set to trace only those events we are interested in.
131
+
132
+ # Don't step/trace into Ruby routines called from here in the code
133
+ # below (e.g. "trace_hooks").
134
+ step_count_save = step_count
135
+ @step_count = -1
136
+
137
+ unless @event_proc == dbgr.trace_filter.hook_proc
138
+ dbgr.trace_filter.add_trace_func(@event_proc)
139
+ ## debug: p '+++1', @event_proc, dbgr.trace_filter.hook_proc
140
+ end
141
+
142
+ # FIXME: this doesn't work. Bug in rb-trace?
143
+ # Trace.event_masks[0] = @step_events | @async_events
144
+ RubyVM::TraceHook::trace_hooks[0].event_mask =
145
+ @step_events | @async_events
146
+ @step_count = step_count_save
147
+ end
148
+
149
+ # Nil out variables just in case...
150
+
151
+ return_exception = @exception
152
+ @frame = @event = @arg = @exception = nil
153
+
154
+ end
155
+ return return_exception
156
+ end
157
+
158
+ # A Ruby 1.8-style event processor. We don't use file, line, id, bind.
159
+ def old_event_processor(event, file, line, id, bind, klass)
160
+ event_processor(event, RubyVM::ThreadFrame.current.prev)
161
+ end
162
+
163
+ # Call this from inside the program you want to get a synchronous
164
+ # call to the debugger. set prev_count to the number of levels
165
+ # *before* the caller you want to skip.
166
+ def debugger(prev_count=0)
167
+ while @frame && @frame.type == 'IFUNC'
168
+ @frame = @frame.prev
169
+ end
170
+ frame = RubyVM::ThreadFrame.current.prev(prev_count+1)
171
+ @step_count = 0 # Make event processor stop
172
+ event_processor('debugger-call', frame)
173
+ end
174
+
175
+ # A trace-hook processor for 'trace var'
176
+ def trace_var_processor(val)
177
+ frame = RubyVM::ThreadFrame.current.prev
178
+ if 'CFUNC' == frame.type
179
+ # Don't need the C call that got us here.
180
+ prev = frame.prev
181
+ frame = frame.prev if prev
182
+ end
183
+
184
+ # Stop future tracing into the debugger
185
+ Thread.current.tracing = true
186
+
187
+ @step_count = 0 # Make event processor stop
188
+ event_processor('trace-var', frame)
189
+ end
190
+
191
+ end
192
+ end
193
+ if __FILE__ == $0
194
+ require_relative '../lib/trepanning'
195
+ dbg = Trepan.new()
196
+ if ARGV.size > 0
197
+ def foo(dbg)
198
+ p 'foo here'
199
+ dbg.debugger(:immediate=>true)
200
+ end
201
+ foo(dbg)
202
+ end
203
+ end
data/app/default.rb ADDED
@@ -0,0 +1,54 @@
1
+ # Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
2
+ # A place for the default settings
3
+ # This could be put elsewhere but it is expected that this will grow
4
+ # get quite large.
5
+ module Trepanning
6
+
7
+ # I am not sure if we need to sets of hashes, but we'll start out
8
+ # that way.
9
+
10
+ # Default settings for a Trepan class object
11
+ DEFAULT_SETTINGS = {
12
+ :cmdproc_opts => {}, # Default Trepan::CmdProcessor settings
13
+ :core_opts => {}, # Default Trepan::Core settings
14
+ :delete_restore => true, # Delete restore profile after reading?
15
+ :initial_dir => nil, # Current directory run when "restart" is given
16
+ :nx => false, # Don't run user startup file (e.g. .rbdbgrc)
17
+ :restart_argv => [], # Command run when "restart" is given
18
+ :restore_profile => nil # Profile used to set/restore debugger state
19
+ } unless defined?(DEFAULT_SETTINGS)
20
+
21
+ # Default settings for Trepan run from the command line.
22
+ DEFAULT_CMDLINE_SETTINGS = {
23
+ :cmdfiles => [], # Initialization command files to run
24
+ :nx => false, # Don't run user startup file (e.g. .rbdbgrc)
25
+ :output => nil,
26
+ } unless defined?(DEFAULT_CMDLINE_SETTINGS)
27
+
28
+ DEFAULT_DEBUG_STR_SETTINGS = {
29
+ :core_opts => {
30
+ :cmdproc_opts => {:different => false}},
31
+ :hide_stack => true,
32
+ } unless defined?(DEFAULT_DEBUG_STR_SETTINGS)
33
+
34
+ CMD_INITFILE_BASE =
35
+ if RUBY_PLATFORM =~ /mswin/
36
+ # Of course MS Windows has to be different
37
+ HOME_DIR = (ENV['HOME'] ||
38
+ ENV['HOMEDRIVE'].to_s + ENV['HOMEPATH'].to_s).to_s
39
+ 'trepan.ini'
40
+ else
41
+ HOME_DIR = ENV['HOME'].to_s
42
+ '.trepanrc'
43
+ end unless defined?(CMD_INITFILE_BASE)
44
+ CMD_INITFILE = File.join(HOME_DIR, CMD_INITFILE_BASE) unless
45
+ defined?(CMD_INITFILE)
46
+ end
47
+
48
+ if __FILE__ == $0
49
+ # Show it:
50
+ require 'pp'
51
+ PP.pp(Trepanning::DEFAULT_SETTINGS)
52
+ puts '=' * 30
53
+ PP.pp(Trepanning::DEFAULT_CMDLINE_SETTINGS)
54
+ end
@@ -0,0 +1,61 @@
1
+ # Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
2
+ # Splits String dissasemble_str into an array for for each
3
+ # line. Line(s) that Fixnum pc_offset matches at the beginning of the
4
+ # line will have prefix "--> " added, otherwise the line will have " "
5
+ # added to the beginning. This array is returned.
6
+
7
+ class Trepan
8
+ module Disassemble
9
+ def mark_disassembly(disassembly_str, iseq_equal, pc_offset,
10
+ brkpt_offsets=[])
11
+ dis_array = disassembly_str.split(/\n/)
12
+ dis_array.map do |line|
13
+ prefix =
14
+ if line =~ /^(\d{4}) /
15
+ offset = $1.to_i
16
+ bp = brkpt_offsets && brkpt_offsets.member?(offset) ? 'B' : ' '
17
+ bp + if offset == pc_offset && iseq_equal
18
+ '--> '
19
+ else
20
+ ' '
21
+ end
22
+ else
23
+ ''
24
+ end
25
+ prefix + line
26
+ end
27
+ end
28
+ module_function :mark_disassembly
29
+
30
+ def disassemble_split(disassembly_str)
31
+ dis_array = disassembly_str.split(/\n/)
32
+ dis_hash = {}
33
+ dis_array.each do |line|
34
+ dis_hash[$1.to_i] = line if line =~ /^(\d{4}) /
35
+ end
36
+ dis_hash
37
+ end
38
+ module_function :disassemble_split
39
+
40
+ end
41
+ end
42
+
43
+ if __FILE__ == $0
44
+ # Demo it.
45
+ include Trepan::Disassemble
46
+ dis_string='
47
+ local table (size: 6, argc: 1 [opts: 0, rest: -1, post: 0, block: -1] s1)
48
+ [ 6] relative_feature<Arg>[ 5] c [ 4] e [ 3] file [ 2] absolute_feature
49
+ 0000 trace 8 ( 26)
50
+ 0002 trace 1 ( 27)
51
+ 0004 putnil
52
+ '
53
+ [[-1, []], [2, [2]], [10, [0, 4]]].each do |pc_offset, brkpts|
54
+ puts '-' * 40
55
+ puts mark_disassembly(dis_string, true, pc_offset, brkpts).join("\n")
56
+ end
57
+ puts mark_disassembly(dis_string, false, 2).join("\n")
58
+ puts '-' * 40
59
+ require 'pp'
60
+ PP.pp(disassemble_split(dis_string), $stdout)
61
+ end
data/app/display.rb ADDED
@@ -0,0 +1,148 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
3
+ # Classes to support gdb-like display/undisplay.
4
+
5
+ require_relative 'frame'
6
+
7
+ # return suitable frame signature to key display expressions off of.
8
+ def display_signature(frame)
9
+ return nil unless frame
10
+ frame.iseq.object_id
11
+ end
12
+
13
+ # Manage a list of display expressions.
14
+ class DisplayMgr
15
+
16
+ def initialize
17
+ @next = 0
18
+ @list = []
19
+ end
20
+
21
+ def add(frame, arg, fmt=nil)
22
+ return nil unless frame
23
+ begin
24
+ eval(arg, frame.binding)
25
+ rescue
26
+ return nil
27
+ end
28
+ @next += 1
29
+ d = Display.new(frame, arg, fmt, @next)
30
+ @list << d
31
+ d
32
+ end
33
+
34
+ # List all display items; return 0 if none
35
+ def all
36
+ s = []
37
+ unless @list.empty?
38
+ s << "Auto-display expressions now in effect:
39
+ Num Enb Expression"
40
+ @list.each do |display|
41
+ s << display.format
42
+ end
43
+ end
44
+ s
45
+ end
46
+
47
+ # Delete all display expressions"""
48
+ def clear
49
+ @list = []
50
+ end
51
+
52
+ # Delete display expression i
53
+ def delete_index(display_number)
54
+ @list.each_with_index do |display, i|
55
+ if display_number == display.number
56
+ @list[i..i] = []
57
+ return true
58
+ end
59
+ end
60
+ false
61
+ end
62
+
63
+ # display any items that are active'''
64
+ def display(frame)
65
+ return unless frame
66
+ s = []
67
+ sig = display_signature(frame)
68
+ @list.each do |display|
69
+ if display.enabled # && display.signature == sig
70
+ s << display.to_s(frame)
71
+ end
72
+ end
73
+ return s
74
+ end
75
+
76
+ def enable_disable(display_number, b_enable_disable)
77
+ @list.each do |display|
78
+ if display_number == display.number
79
+ display.enabled = b_enable_disable
80
+ return true
81
+ end
82
+ end
83
+ false
84
+ end
85
+ end
86
+
87
+ class Display
88
+ attr_reader :number
89
+ attr_reader :signature
90
+ attr_accessor :enabled
91
+
92
+ def initialize(frame, arg, fmt, number)
93
+ @signature = display_signature(frame)
94
+ @fmt = fmt
95
+ @arg = arg
96
+ @enabled = true
97
+ @number = number
98
+ end
99
+
100
+ def to_s(frame)
101
+ return 'No symbol "' + @arg + '" in current context.' unless frame
102
+
103
+ begin
104
+ val = eval(@arg, frame.binding)
105
+ rescue
106
+ return "No symbol \"#{@arg}\" in current context."
107
+ end
108
+ s = "#{self.format(false)} = #{val}"
109
+ return s
110
+ end
111
+
112
+ # format display item
113
+ def format(show_enabled=true)
114
+ what = ''
115
+ what += @enabled ? ' y ' : ' n ' if
116
+ show_enabled
117
+ what += (@fmt + ' ') if @fmt
118
+ what += @arg if @arg
119
+ '%3d: %s' % [@number, what]
120
+ end
121
+ end
122
+
123
+ if __FILE__ == $0
124
+ # Demo it.
125
+ mgr = DisplayMgr.new
126
+
127
+ def print_display(mgr)
128
+ mgr.all.each {|line| puts line}
129
+ puts '=' * 40
130
+ end
131
+
132
+ require 'thread_frame'
133
+ frame = RubyVM::ThreadFrame::current
134
+
135
+ x = 1
136
+ mgr.add(frame, 'x > 1')
137
+ print_display(mgr)
138
+
139
+ mgr.enable_disable(1, false)
140
+ print_display(mgr)
141
+
142
+ mgr.enable_disable(1, true)
143
+ print_display(mgr)
144
+
145
+ mgr.clear()
146
+ print_display(mgr)
147
+
148
+ end
data/app/file.rb ADDED
@@ -0,0 +1,135 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
3
+ # Things related to file/module status
4
+ require 'thread_frame'
5
+
6
+ SCRIPT_ISEQS__ = {} unless
7
+ defined?(SCRIPT_ISEQS__) && SCRIPT_ISEQS__.is_a?(Hash)
8
+ ISEQS__ = {} unless
9
+ defined?(ISEQS__) && ISEQS__.is_a?(Hash)
10
+
11
+ module Trepanning
12
+ def file_match_pat(filename)
13
+ prefix =
14
+ if filename[0..0] == File::SEPARATOR
15
+ # An absolute filename has to match at the beginning and
16
+ # the end.
17
+ '^'
18
+ else
19
+ # An nonabsolute filename has to match either at the
20
+ # beginning of the file name or have a path separator before
21
+ # the supplied part, e.g. "file.rb" does not match "myfile.rb"
22
+ # but matches "my/file.rb"
23
+ '(?:^|[/])'
24
+ end
25
+ "#{prefix}#{Regexp.escape(filename)}$"
26
+ end
27
+
28
+ def filter_scripts(dirname)
29
+ match_block = Proc.new{|filename, iseq| filename =~ /^#{dirname}/}
30
+ scripts = SCRIPT_ISEQS__.select(&match_block)
31
+ SCRIPT_ISEQS__.delete_if(&match_block)
32
+ match_block = Proc.new{|iseq|
33
+ iseq.source_container[1] =~ /^#{dirname}/
34
+ }
35
+ rejected = {}
36
+ # SCRIPT_ISEQS__ is updated automatically. Dup copy is to make
37
+ # sure we we aren't iterating over something that some other
38
+ # process, thread or hook is filling.
39
+ script_iseqs = SCRIPT_ISEQS__.dup
40
+ script_iseqs.each do |name, iseqs|
41
+ ary = iseqs.select(&match_block)
42
+ rejected[name] = ary unless ary.empty?
43
+ iseqs.delete_if(&match_block)
44
+ end
45
+ return [scripts, rejected]
46
+ end
47
+
48
+ def find_scripts(filename)
49
+ filename_pat = file_match_pat(filename)
50
+ return SCRIPT_ISEQS__.keys.grep(/#{filename_pat}/)
51
+ end
52
+
53
+ def find_iseqs(iseqs_hash, name)
54
+ iseq_name, filename = name.split(/@/)
55
+ return [] unless iseqs_hash.member?(iseq_name)
56
+ iseqs = iseqs_hash[iseq_name]
57
+ # FIXME: filter out debugger iseqs
58
+ if filename
59
+ filename_pat = file_match_pat(filename)
60
+ iseqs.select{|iseq| iseq.source_container[1] =~ /#{filename_pat}/}
61
+ else
62
+ return iseqs
63
+ end
64
+ end
65
+
66
+ def find_iseqs_with_lineno(filename, lineno)
67
+ files = find_scripts(filename)
68
+ files.each do |file|
69
+ found =
70
+ SCRIPT_ISEQS__[file].detect do |iseq|
71
+ iseq.offsetlines.values.flatten.uniq.member?(lineno)
72
+ end
73
+ return found if found
74
+ end
75
+ return nil
76
+ end
77
+
78
+ # parse_position(errmsg, arg)->(fn, name, lineno)
79
+ #
80
+ # Parse arg as [filename|module:]lineno
81
+ # Make sure it works for C:\foo\bar.rb:12
82
+ def parse_position(errmsg, arg)
83
+ colon = arg.rindex(':')
84
+ if colon
85
+ # FIXME: Handle double colons, e.g. File::open
86
+ filename = arg[0..colon-1].rstrip
87
+ m, f = lookupmodule(filename)
88
+ if not f
89
+ errmsg.call("'%s' not found using sys.path" % filename)
90
+ return nil, nil, nil
91
+ else
92
+ filename = f
93
+ arg = arg[colon+1..-1].lstrip
94
+ end
95
+ begin
96
+ lineno = Integer(arg)
97
+ rescue
98
+ errmsg.call("Bad line number: %s", arg)
99
+ return nil, filename, nil
100
+ end
101
+ return nil, filename, lineno
102
+ end
103
+ return nil, nil, nil
104
+ end
105
+ end
106
+ # Demo it
107
+ if __FILE__ == $0
108
+ include Trepanning
109
+ if !(ARGV.size == 1 && ARGV[0] == 'noload')
110
+ ISEQS__ = {}
111
+ SCRIPT_ISEQS__ = {}
112
+ ARGV[0..-1] = ['noload']
113
+ load(__FILE__)
114
+ else
115
+ load 'tmpdir.rb'
116
+ tmpdir_dir = File.dirname(find_scripts('tmpdir.rb')[0])
117
+ p tmpdir_dir
118
+ %w(tmpdir.rb /tmpdir.rb sometmpdir.rb).each do |filename|
119
+ p find_scripts(filename)
120
+ end
121
+ p find_scripts(__FILE__)
122
+ def tmpdir
123
+ 'to conflict with the other tmpdir'
124
+ end
125
+ p find_iseqs(ISEQS__, "tmpdir@#{__FILE__}")
126
+ puts '-' * 20
127
+ p SCRIPT_ISEQS__.keys
128
+ puts '-' * 20
129
+ scripts, rejected = filter_scripts(tmpdir_dir)
130
+ p scripts.keys
131
+ p rejected.keys
132
+ puts '-' * 20
133
+ p SCRIPT_ISEQS__.keys
134
+ end
135
+ end