rbx-trepanning 0.0.1-universal-rubinius
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.
- data/ChangeLog +376 -0
- data/LICENSE +25 -0
- data/NEWS +2 -0
- data/README.textile +28 -0
- data/Rakefile +165 -0
- data/THANKS +14 -0
- data/app/breakpoint.rb +218 -0
- data/app/breakpoint.rbc +3564 -0
- data/app/brkptmgr.rb +138 -0
- data/app/brkptmgr.rbc +2827 -0
- data/app/default.rb +61 -0
- data/app/default.rbc +1011 -0
- data/app/display.rb +35 -0
- data/app/display.rbc +968 -0
- data/app/frame.rb +98 -0
- data/app/frame.rbc +1808 -0
- data/app/irb.rb +112 -0
- data/app/irb.rbc +2111 -0
- data/app/iseq.rb +95 -0
- data/app/iseq.rbc +1801 -0
- data/app/method.rb +173 -0
- data/app/method.rbc +2492 -0
- data/app/mock.rb +13 -0
- data/app/mock.rbc +398 -0
- data/app/options.rb +123 -0
- data/app/options.rbc +2183 -0
- data/app/run.rb +86 -0
- data/app/run.rbc +1244 -0
- data/app/util.rb +49 -0
- data/app/util.rbc +1144 -0
- data/app/validate.rb +30 -0
- data/app/validate.rbc +676 -0
- data/bin/trepan.compiled.rbc +1043 -0
- data/bin/trepanx +63 -0
- data/bin/trepanx.compiled.rbc +985 -0
- data/interface/base_intf.rb +95 -0
- data/interface/base_intf.rbc +1742 -0
- data/interface/script.rb +104 -0
- data/interface/script.rbc +1642 -0
- data/interface/user.rb +91 -0
- data/interface/user.rbc +1418 -0
- data/io/base_io.rb +94 -0
- data/io/base_io.rbc +1404 -0
- data/io/input.rb +112 -0
- data/io/input.rbc +1979 -0
- data/io/null_output.rb +42 -0
- data/io/null_output.rbc +730 -0
- data/io/string_array.rb +156 -0
- data/io/string_array.rbc +2466 -0
- data/lib/trepanning.rb +398 -0
- data/lib/trepanning.rbc +6661 -0
- data/processor/breakpoint.rb +161 -0
- data/processor/command/alias.rb +55 -0
- data/processor/command/backtrace.rb +46 -0
- data/processor/command/base/cmd.rb +124 -0
- data/processor/command/base/subcmd.rb +213 -0
- data/processor/command/base/submgr.rb +179 -0
- data/processor/command/base/subsubcmd.rb +103 -0
- data/processor/command/base/subsubmgr.rb +184 -0
- data/processor/command/break.rb +100 -0
- data/processor/command/continue.rb +82 -0
- data/processor/command/delete.rb +30 -0
- data/processor/command/directory.rb +43 -0
- data/processor/command/disassemble.rb +103 -0
- data/processor/command/down.rb +54 -0
- data/processor/command/eval.rb +31 -0
- data/processor/command/exit.rb +58 -0
- data/processor/command/finish.rb +78 -0
- data/processor/command/frame.rb +89 -0
- data/processor/command/help.rb +146 -0
- data/processor/command/info.rb +28 -0
- data/processor/command/info_subcmd/breakpoints.rb +75 -0
- data/processor/command/info_subcmd/file.rb +153 -0
- data/processor/command/info_subcmd/method.rb +71 -0
- data/processor/command/info_subcmd/program.rb +59 -0
- data/processor/command/info_subcmd/variables.rb +40 -0
- data/processor/command/irb.rb +96 -0
- data/processor/command/kill.rb +70 -0
- data/processor/command/list.rb +296 -0
- data/processor/command/next.rb +66 -0
- data/processor/command/nexti.rb +59 -0
- data/processor/command/pr.rb +38 -0
- data/processor/command/ps.rb +40 -0
- data/processor/command/restart.rb +60 -0
- data/processor/command/set.rb +47 -0
- data/processor/command/set_subcmd/auto.rb +28 -0
- data/processor/command/set_subcmd/auto_subcmd/dis.rb +33 -0
- data/processor/command/set_subcmd/auto_subcmd/eval.rb +54 -0
- data/processor/command/set_subcmd/auto_subcmd/irb.rb +34 -0
- data/processor/command/set_subcmd/auto_subcmd/list.rb +34 -0
- data/processor/command/set_subcmd/basename.rb +26 -0
- data/processor/command/set_subcmd/debug.rb +27 -0
- data/processor/command/set_subcmd/debug_subcmd/dbgr.rb +36 -0
- data/processor/command/set_subcmd/debug_subcmd/skip.rb +23 -0
- data/processor/command/set_subcmd/debug_subcmd/step.rb +23 -0
- data/processor/command/set_subcmd/different.rb +60 -0
- data/processor/command/set_subcmd/hidelevel.rb +63 -0
- data/processor/command/set_subcmd/kernelstep.rb +61 -0
- data/processor/command/set_subcmd/max.rb +29 -0
- data/processor/command/set_subcmd/max_subcmd/list.rb +49 -0
- data/processor/command/set_subcmd/max_subcmd/stack.rb +50 -0
- data/processor/command/set_subcmd/max_subcmd/string.rb +54 -0
- data/processor/command/set_subcmd/max_subcmd/width.rb +49 -0
- data/processor/command/set_subcmd/substitute.rb +25 -0
- data/processor/command/set_subcmd/substitute_subcmd/path.rb +56 -0
- data/processor/command/set_subcmd/trace.rb +37 -0
- data/processor/command/set_subcmd/trace_subcmd/print.rb +57 -0
- data/processor/command/show.rb +27 -0
- data/processor/command/show_subcmd/alias.rb +43 -0
- data/processor/command/show_subcmd/args.rb +26 -0
- data/processor/command/show_subcmd/auto.rb +28 -0
- data/processor/command/show_subcmd/auto_subcmd/dis.rb +37 -0
- data/processor/command/show_subcmd/auto_subcmd/eval.rb +28 -0
- data/processor/command/show_subcmd/auto_subcmd/irb.rb +23 -0
- data/processor/command/show_subcmd/auto_subcmd/list.rb +22 -0
- data/processor/command/show_subcmd/basename.rb +22 -0
- data/processor/command/show_subcmd/debug.rb +27 -0
- data/processor/command/show_subcmd/debug_subcmd/dbgr.rb +21 -0
- data/processor/command/show_subcmd/debug_subcmd/skip.rb +22 -0
- data/processor/command/show_subcmd/debug_subcmd/step.rb +22 -0
- data/processor/command/show_subcmd/different.rb +27 -0
- data/processor/command/show_subcmd/hidelevel.rb +42 -0
- data/processor/command/show_subcmd/kernelstep.rb +37 -0
- data/processor/command/show_subcmd/max.rb +30 -0
- data/processor/command/show_subcmd/max_subcmd/list.rb +38 -0
- data/processor/command/show_subcmd/max_subcmd/stack.rb +36 -0
- data/processor/command/show_subcmd/max_subcmd/string.rb +42 -0
- data/processor/command/show_subcmd/max_subcmd/width.rb +37 -0
- data/processor/command/show_subcmd/trace.rb +29 -0
- data/processor/command/show_subcmd/trace_subcmd/print.rb +38 -0
- data/processor/command/source.rb +83 -0
- data/processor/command/step.rb +41 -0
- data/processor/command/tbreak.rb +19 -0
- data/processor/command/unalias.rb +44 -0
- data/processor/command/up.rb +87 -0
- data/processor/default.rb +56 -0
- data/processor/disassemble.rb +32 -0
- data/processor/eval.rb +96 -0
- data/processor/frame.rb +211 -0
- data/processor/help.rb +72 -0
- data/processor/hook.rb +133 -0
- data/processor/load_cmds.rb +101 -0
- data/processor/location.rb +128 -0
- data/processor/main.rb +394 -0
- data/processor/mock.rb +137 -0
- data/processor/msg.rb +28 -0
- data/processor/running.rb +230 -0
- data/processor/stepping.rb +115 -0
- data/processor/subcmd.rb +160 -0
- data/processor/validate.rb +355 -0
- data/test/data/enable.right +36 -0
- data/test/data/fname-with-blank.cmd +6 -0
- data/test/data/fname-with-blank.right +1 -0
- data/test/data/quit-Xdebug.right +3 -0
- data/test/data/quit.cmd +5 -0
- data/test/data/quit.right +0 -0
- data/test/example/fname with blank.rb +1 -0
- data/test/example/gcd-xx.rb +18 -0
- data/test/example/gcd.rb +19 -0
- data/test/example/gcd1.rb +24 -0
- data/test/example/null.rb +1 -0
- data/test/example/thread1.rb +3 -0
- data/test/functional/fn_helper.rb +112 -0
- data/test/functional/test-break-name.rb +52 -0
- data/test/functional/test-break.rb +51 -0
- data/test/functional/test-finish.rb +70 -0
- data/test/functional/test-fn_helper.rb +43 -0
- data/test/functional/test-list.rb +55 -0
- data/test/functional/test-next-bug.rb +49 -0
- data/test/functional/test-next.rb +101 -0
- data/test/functional/test-step.rb +272 -0
- data/test/functional/test-step2.rb +35 -0
- data/test/functional/test-tbreak.rb +41 -0
- data/test/integration/file-diff.rb +89 -0
- data/test/integration/helper.rb +78 -0
- data/test/integration/test-fname-with-blank.rb +12 -0
- data/test/integration/test-quit.rb +25 -0
- data/test/unit/cmd-helper.rb +46 -0
- data/test/unit/test-app-brkpt.rb +30 -0
- data/test/unit/test-app-brkptmgr.rb +51 -0
- data/test/unit/test-app-iseq.rb +49 -0
- data/test/unit/test-app-method.rb +54 -0
- data/test/unit/test-app-options.rb +61 -0
- data/test/unit/test-app-run.rb +16 -0
- data/test/unit/test-app-util.rb +28 -0
- data/test/unit/test-app-validate.rb +18 -0
- data/test/unit/test-base-subcmd.rb +61 -0
- data/test/unit/test-bin-trepanx.rb +48 -0
- data/test/unit/test-cmd-alias.rb +49 -0
- data/test/unit/test-cmd-break.rb +23 -0
- data/test/unit/test-cmd-exit.rb +27 -0
- data/test/unit/test-cmd-help.rb +101 -0
- data/test/unit/test-cmd-kill.rb +48 -0
- data/test/unit/test-intf-user.rb +46 -0
- data/test/unit/test-io-input.rb +27 -0
- data/test/unit/test-proc-eval.rb +37 -0
- data/test/unit/test-proc-frame.rb +79 -0
- data/test/unit/test-proc-help.rb +16 -0
- data/test/unit/test-proc-hook.rb +30 -0
- data/test/unit/test-proc-load_cmds.rb +41 -0
- data/test/unit/test-proc-location.rb +48 -0
- data/test/unit/test-proc-main.rb +96 -0
- data/test/unit/test-proc-validate.rb +91 -0
- data/test/unit/test-subcmd-help.rb +51 -0
- metadata +337 -0
@@ -0,0 +1,230 @@
|
|
1
|
+
# Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
|
2
|
+
require 'rubygems'; require 'require_relative'
|
3
|
+
require 'set'
|
4
|
+
## require_relative '../app/core'
|
5
|
+
class Trepan
|
6
|
+
class CmdProcessor
|
7
|
+
|
8
|
+
|
9
|
+
attr_accessor :ignore_file_re # Hash[file_re] -> String
|
10
|
+
# action. File re's we don't want
|
11
|
+
# to stop while stepping. Like
|
12
|
+
# ignore_methods. Skipping kernel methods
|
13
|
+
# is handled this way.
|
14
|
+
attr_accessor :ignore_methods # Hash[CompiledMethod] -> String:
|
15
|
+
# action. Methods we don't want to
|
16
|
+
# ever stop while stepping. action
|
17
|
+
# is 'step' or 'next'.
|
18
|
+
attr_accessor :stop_condition # String or nil. When not nil
|
19
|
+
# this has to eval non-nil
|
20
|
+
# in order to stop.
|
21
|
+
attr_accessor :stop_events # Set or nil. If not nil, only
|
22
|
+
# events in this set will be
|
23
|
+
# considered for stopping. This is
|
24
|
+
# like core.step_events (which
|
25
|
+
# could be used instead), but it is
|
26
|
+
# a set of event names rather than
|
27
|
+
# a bitmask and it is intended to
|
28
|
+
# be more temporarily changed via
|
29
|
+
# "step>" or "step!" commands.
|
30
|
+
attr_accessor :step_count
|
31
|
+
attr_accessor :to_method
|
32
|
+
|
33
|
+
# # Does whatever needs to be done to set to continue program
|
34
|
+
# # execution.
|
35
|
+
# # FIXME: turn line_number into a condition.
|
36
|
+
|
37
|
+
def continue(how_to_continue)
|
38
|
+
@next_thread = nil
|
39
|
+
@step_count = -1 # No more event stepping
|
40
|
+
if 'step-finish' == how_to_continue
|
41
|
+
step_to_return_or_yield
|
42
|
+
how_to_continue = 'step'
|
43
|
+
end
|
44
|
+
@return_to_program = how_to_continue
|
45
|
+
end
|
46
|
+
|
47
|
+
# Does whatever setup needs to be done to set to ignore stepping
|
48
|
+
# to the finish of the current method. Elsewhere in
|
49
|
+
# "skipping_step?" we do the checking.
|
50
|
+
def finish(level_count=0, opts={})
|
51
|
+
step_to_return_or_yield
|
52
|
+
continue('finish')
|
53
|
+
@next_thread = @current_thread
|
54
|
+
|
55
|
+
# # Try high-speed (run-time-assisted) method
|
56
|
+
# @frame.trace_off = true # No more tracing in this frame
|
57
|
+
# @frame.return_stop = true # don't need to
|
58
|
+
end
|
59
|
+
|
60
|
+
def step_finish
|
61
|
+
step_to_return_or_yield
|
62
|
+
continue('step')
|
63
|
+
@next_thread = @current_thread
|
64
|
+
end
|
65
|
+
|
66
|
+
# # Does whatever needs to be done to set to "next" program
|
67
|
+
# # execution.
|
68
|
+
# def next(step_count=1, opts={})
|
69
|
+
# step(step_count, opts)
|
70
|
+
# @next_thread = Thread.current
|
71
|
+
# end
|
72
|
+
|
73
|
+
# Does whatever needs to be done to set to step program
|
74
|
+
# execution.
|
75
|
+
def step(how_to_continue, step_count=1, opts={}, condition=nil)
|
76
|
+
continue(how_to_continue)
|
77
|
+
@step_count = step_count
|
78
|
+
@different_pos = opts[:different_pos] if
|
79
|
+
opts.keys.member?(:different_pos)
|
80
|
+
@stop_condition = condition
|
81
|
+
@stop_events = opts[:stop_events] if
|
82
|
+
opts.keys.member?(:stop_events)
|
83
|
+
@to_method = opts[:to_method]
|
84
|
+
end
|
85
|
+
|
86
|
+
def quit(cmd='exit')
|
87
|
+
@next_level = 32000 # I'm guessing the stack size can't
|
88
|
+
# ever reach this
|
89
|
+
@next_thread = nil
|
90
|
+
@step_count = -1 # No more event stepping
|
91
|
+
@leave_cmd_loop = true # Break out of the processor command loop.
|
92
|
+
@settings[:autoirb] = false
|
93
|
+
@cmdloop_prehooks.delete_by_name('autoirb')
|
94
|
+
@commands['exit'].run([cmd])
|
95
|
+
end
|
96
|
+
|
97
|
+
def parse_next_step_suffix(step_cmd)
|
98
|
+
opts = {}
|
99
|
+
case step_cmd[-1..-1]
|
100
|
+
when '-'
|
101
|
+
opts[:different_pos] = false
|
102
|
+
when '+'
|
103
|
+
opts[:different_pos] = 'nostack'
|
104
|
+
when '='
|
105
|
+
opts[:different_pos] = true
|
106
|
+
when '!'
|
107
|
+
opts[:stop_events] = Set.new(%w(raise))
|
108
|
+
when '<'
|
109
|
+
opts[:stop_events] = Set.new(%w(c-return return))
|
110
|
+
when '>'
|
111
|
+
opts[:stop_events] = Set.new(%w(c-call call))
|
112
|
+
if step_cmd.size > 1 && step_cmd[-2..-2] == '<'
|
113
|
+
opts[:stop_events] = Set.new(%w(c-call c-return call return))
|
114
|
+
else
|
115
|
+
opts[:stop_events] = Set.new(%w(c-call call))
|
116
|
+
end
|
117
|
+
end
|
118
|
+
return opts
|
119
|
+
end
|
120
|
+
|
121
|
+
def running_initialize
|
122
|
+
@ignore_file_re = {}
|
123
|
+
@ignore_methods = {}
|
124
|
+
|
125
|
+
@step_count = 0
|
126
|
+
@stop_condition = nil
|
127
|
+
@stop_events = nil
|
128
|
+
@to_method = nil
|
129
|
+
end
|
130
|
+
|
131
|
+
# If we are not in some kind of steppable event, return
|
132
|
+
# false. If we are in a steppable event, update step state
|
133
|
+
# and return true if the step count is 0 and other conditions
|
134
|
+
# like the @settings[:different] are met.
|
135
|
+
def stepping_skip?
|
136
|
+
|
137
|
+
debug_loc = "#{frame.vm_location.describe} #{frame.line}" if
|
138
|
+
@settings[:debugskip]
|
139
|
+
|
140
|
+
if @step_count < 0
|
141
|
+
# We may eventually stop for some other reason, but it's not
|
142
|
+
# because we were stepping here.
|
143
|
+
msg "skip: step_count < 0 #{debug_loc}" if @settings[:debugskip]
|
144
|
+
return false
|
145
|
+
end
|
146
|
+
|
147
|
+
@ignore_file_re.each_pair do |file_re, action|
|
148
|
+
if frame.vm_location.method.active_path =~ file_re
|
149
|
+
@return_to_program = action
|
150
|
+
msg "skip re: #{debug_loc}" if @settings[:debugskip]
|
151
|
+
return true
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
ms = frame.method.scope
|
156
|
+
@ignore_methods.each do |m, val|
|
157
|
+
# Guard against crap put into @ignore_methods
|
158
|
+
unless m.respond_to?(:scope)
|
159
|
+
@ignore_methods.delete(m)
|
160
|
+
next
|
161
|
+
end
|
162
|
+
if ms == m.scope
|
163
|
+
msg "skip ignore method: #{debug_loc}" if @settings[:debugskip]
|
164
|
+
@return_to_program = val
|
165
|
+
return true
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
# Only skip on these kinds of events
|
170
|
+
unless %w(step-call line).include?(@event)
|
171
|
+
msg "skip non-line: #{@event} #{debug_loc}" if @settings[:debugskip]
|
172
|
+
return false
|
173
|
+
end
|
174
|
+
|
175
|
+
# We are in some kind of stepping event, so do whatever we
|
176
|
+
# do to record that we've hit the step. Whether we decide
|
177
|
+
# to stop, will be done after recording the step took place.
|
178
|
+
@step_count -= 1 unless step_count == 0
|
179
|
+
new_pos = [@frame.file, @frame.line,
|
180
|
+
@stack_size, @current_thread, @event]
|
181
|
+
|
182
|
+
|
183
|
+
# Decide whether this step is skippable.
|
184
|
+
should_skip = false
|
185
|
+
|
186
|
+
if @settings[:debugskip]
|
187
|
+
msg("last: #{@last_pos.inspect}, ")
|
188
|
+
msg("new: #{new_pos.inspect}")
|
189
|
+
msg("skip: #{should_skip.inspect}, event: #{@event}")
|
190
|
+
end
|
191
|
+
|
192
|
+
@last_pos[2] = new_pos[2] if 'nostack' == @different_pos
|
193
|
+
condition_met = @step_count == 0
|
194
|
+
|
195
|
+
# if @stop_condition
|
196
|
+
# puts 'stop_cond' if @settings[:'debugskip']
|
197
|
+
# debug_eval_no_errmsg(@stop_condition)
|
198
|
+
# elsif @to_method
|
199
|
+
# puts "method #{@frame.method} #{@to_method}" if
|
200
|
+
# @settings[:'debugskip']
|
201
|
+
# @frame.method == @to_method
|
202
|
+
# else
|
203
|
+
# puts 'uncond' if @settings[:'debugskip']
|
204
|
+
# true
|
205
|
+
# end
|
206
|
+
|
207
|
+
# msg("condition_met: #{condition_met}, last: #{@last_pos}, " +
|
208
|
+
# "new: #{new_pos}, different #{@different_pos.inspect}") if
|
209
|
+
# @settings[:'debugskip']
|
210
|
+
|
211
|
+
should_skip = ((@last_pos[0..3] == new_pos[0..3] && @different_pos) ||
|
212
|
+
!condition_met)
|
213
|
+
|
214
|
+
msg("should_skip: #{should_skip}, #{debug_loc}") if @settings[:debugskip]
|
215
|
+
|
216
|
+
@last_pos = new_pos
|
217
|
+
|
218
|
+
unless should_skip
|
219
|
+
# Set up the default values for the
|
220
|
+
# next time we consider step skipping.
|
221
|
+
@different_pos = @settings[:different]
|
222
|
+
# @stop_events = nil
|
223
|
+
end
|
224
|
+
|
225
|
+
@return_to_program = 'step' if should_skip && !@return_to_program
|
226
|
+
return should_skip
|
227
|
+
end
|
228
|
+
|
229
|
+
end
|
230
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
require 'rubygems'; require 'require_relative'
|
2
|
+
require_relative '../app/iseq'
|
3
|
+
class Trepan
|
4
|
+
class CmdProcessor
|
5
|
+
include Trepanning::ISeq
|
6
|
+
|
7
|
+
# It might be interesting to allow stepping within a parent frame
|
8
|
+
def step_over_by(step, frame=@top_frame)
|
9
|
+
|
10
|
+
f = frame
|
11
|
+
|
12
|
+
ip = -1
|
13
|
+
|
14
|
+
meth = f.method
|
15
|
+
possible_line = f.line + step
|
16
|
+
fin_ip = meth.first_ip_on_line_after(possible_line, f.next_ip)
|
17
|
+
|
18
|
+
if fin_ip <= -1
|
19
|
+
return step_to_parent('line')
|
20
|
+
end
|
21
|
+
|
22
|
+
set_breakpoints_between(meth, f.next_ip, fin_ip)
|
23
|
+
end
|
24
|
+
|
25
|
+
def step_to_return_or_yield
|
26
|
+
f = @frame
|
27
|
+
unless f
|
28
|
+
msg 'Unable to find frame to finish'
|
29
|
+
return
|
30
|
+
end
|
31
|
+
|
32
|
+
meth = f.method
|
33
|
+
ip = -1
|
34
|
+
fin_ip = meth.lines.last
|
35
|
+
|
36
|
+
set_breakpoints_on_return_between(meth, f.next_ip, fin_ip)
|
37
|
+
end
|
38
|
+
|
39
|
+
def step_to_parent(event='return')
|
40
|
+
f = parent_frame
|
41
|
+
unless f
|
42
|
+
errmsg "Unable to find parent frame to step to next"
|
43
|
+
return nil
|
44
|
+
end
|
45
|
+
meth = f.method
|
46
|
+
ip = f.ip
|
47
|
+
|
48
|
+
bp = Trepanning::Breakpoint.for_ip(meth, ip,
|
49
|
+
{:event => event, :temp => true})
|
50
|
+
bp.scoped!(parent_frame.scope)
|
51
|
+
bp.activate
|
52
|
+
|
53
|
+
return bp
|
54
|
+
end
|
55
|
+
|
56
|
+
# Sets temporary breakpoints in met between start_ip and fin_ip.
|
57
|
+
# We also set a temporary breakpoint in the caller.
|
58
|
+
def set_breakpoints_between(meth, start_ip, fin_ip)
|
59
|
+
opts = {:event => 'line', :temp => true}
|
60
|
+
ips = goto_between(meth, start_ip, fin_ip)
|
61
|
+
bps = []
|
62
|
+
|
63
|
+
if ips.kind_of? Fixnum
|
64
|
+
if ips == -1
|
65
|
+
errmsg "No place to step to"
|
66
|
+
return nil
|
67
|
+
elsif ips == -2
|
68
|
+
bps << step_to_parent(event='line')
|
69
|
+
ips = []
|
70
|
+
else
|
71
|
+
ips = [ips]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
msg "temp ips: #{ips.inspect}" if settings[:debugstep]
|
76
|
+
ips.each do |ip|
|
77
|
+
bp = Trepanning::Breakpoint.for_ip(meth, ip, opts)
|
78
|
+
bp.scoped!(@frame.scope)
|
79
|
+
bp.activate
|
80
|
+
bps << bp
|
81
|
+
end
|
82
|
+
first_bp = bps[0]
|
83
|
+
bps[1..-1].each do |bp|
|
84
|
+
first_bp.related_with(bp)
|
85
|
+
end
|
86
|
+
return first_bp
|
87
|
+
end
|
88
|
+
|
89
|
+
def set_breakpoints_on_return_between(meth, start_ip, fin_ip)
|
90
|
+
ips = yield_or_return_between(meth, start_ip, fin_ip)
|
91
|
+
if ips.empty?
|
92
|
+
errmsg '"ret" or "yield_stack" opcode not found'
|
93
|
+
return []
|
94
|
+
end
|
95
|
+
|
96
|
+
bp1 = Trepanning::Breakpoint.for_ip(meth, ips[0],
|
97
|
+
{ :event => 'return',
|
98
|
+
:temp => true})
|
99
|
+
bp1.scoped!(@frame.scope)
|
100
|
+
bp1.activate
|
101
|
+
result = [bp1]
|
102
|
+
|
103
|
+
1.upto(ips.size-1) do |i|
|
104
|
+
bp2 = Trepanning::Breakpoint.for_ip(meth, ips[i],
|
105
|
+
{ :event => 'return',
|
106
|
+
:temp => true})
|
107
|
+
bp2.scoped!(@frame.scope)
|
108
|
+
bp1.related_with(bp2)
|
109
|
+
bp2.activate
|
110
|
+
result << bp2
|
111
|
+
end
|
112
|
+
return result
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
data/processor/subcmd.rb
ADDED
@@ -0,0 +1,160 @@
|
|
1
|
+
# Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
|
2
|
+
# gdb-like subcommand processing.
|
3
|
+
|
4
|
+
class Trepan
|
5
|
+
class Subcmd
|
6
|
+
|
7
|
+
attr_reader :subcmds
|
8
|
+
def initialize(cmd)
|
9
|
+
@cmd = cmd
|
10
|
+
@subcmds = {}
|
11
|
+
@cmdlist = []
|
12
|
+
end
|
13
|
+
|
14
|
+
# Find subcmd in self.subcmds
|
15
|
+
def lookup(subcmd_prefix, use_regexp=true)
|
16
|
+
compare = if use_regexp
|
17
|
+
lambda{|name| name.to_s =~ /^#{subcmd_prefix}/}
|
18
|
+
else
|
19
|
+
lambda{|name| 0 == name.to_s.index(subcmd_prefix)}
|
20
|
+
end
|
21
|
+
@subcmds.each do |subcmd_name, subcmd|
|
22
|
+
if compare.call(subcmd_name) &&
|
23
|
+
subcmd_prefix.size >= subcmd.class.const_get(:MIN_ABBREV)
|
24
|
+
return subcmd
|
25
|
+
end
|
26
|
+
end
|
27
|
+
return nil
|
28
|
+
end
|
29
|
+
|
30
|
+
# Show short help for a subcommand.
|
31
|
+
def short_help(subcmd_cb, subcmd_name, label=false)
|
32
|
+
entry = self.lookup(subcmd_name)
|
33
|
+
if entry
|
34
|
+
if label
|
35
|
+
prefix = entry.name
|
36
|
+
else
|
37
|
+
prefix = ''
|
38
|
+
end
|
39
|
+
if entry.respond_to?(:short_help)
|
40
|
+
prefix += ' -- ' if prefix
|
41
|
+
@proc.msg(prefix + entry.short_help)
|
42
|
+
end
|
43
|
+
else
|
44
|
+
@proc.undefined_subcmd("help", subcmd_name)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Add subcmd to the available subcommands for this object.
|
49
|
+
# It will have the supplied docstring, and subcmd_cb will be called
|
50
|
+
# when we want to run the command. min_len is the minimum length
|
51
|
+
# allowed to abbreviate the command. in_list indicates with the
|
52
|
+
# show command will be run when giving a list of all sub commands
|
53
|
+
# of this object. Some commands have long output like "show commands"
|
54
|
+
# so we might not want to show that.
|
55
|
+
def add(subcmd_cb, subcmd_name=nil)
|
56
|
+
subcmd_name ||= subcmd_cb.name
|
57
|
+
@subcmds[subcmd_name.to_s] = subcmd_cb
|
58
|
+
|
59
|
+
# We keep a list of subcommands to assist command completion
|
60
|
+
@cmdlist << subcmd_name
|
61
|
+
end
|
62
|
+
|
63
|
+
# Run subcmd_name with args using obj for the environent
|
64
|
+
def run( subcmd_name, arg)
|
65
|
+
entry=lookup(subcmd_name)
|
66
|
+
if entry
|
67
|
+
entry['callback'].send(arg)
|
68
|
+
else
|
69
|
+
@proc.undefined_cmd(entry.__class__.name, subcmd_name)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# help for subcommands
|
74
|
+
# Note: format of help is compatible with ddd.
|
75
|
+
def help(*args)
|
76
|
+
|
77
|
+
msg args
|
78
|
+
subcmd_prefix = args[0]
|
79
|
+
if not subcmd_prefix or subcmd_prefix.size == 0
|
80
|
+
@proc.msg(self.doc)
|
81
|
+
@proc.msg("\nList of %s subcommands:\n" % [@name])
|
82
|
+
@list.each do |subcmd_name|
|
83
|
+
subcmd_helper(subcmd_name, obj, true, true)
|
84
|
+
end
|
85
|
+
|
86
|
+
entry = lookup(subcmd_prefix)
|
87
|
+
if entry and entry.respond_to? :help
|
88
|
+
entry.help(args)
|
89
|
+
else
|
90
|
+
@proc.errmsg("Unknown 'help %s' subcommand %s" %
|
91
|
+
[@name, subcmd_prefix])
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def list
|
97
|
+
@subcmds.keys.sort
|
98
|
+
end
|
99
|
+
|
100
|
+
# Error message when a subcommand doesn't exist.
|
101
|
+
def undefined_subcmd(cmd, subcmd)
|
102
|
+
@proc.errmsg('Undefined "%s" command: "%s". Try "help".' %
|
103
|
+
[cmd, subcmd])
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# When invoked as main program, invoke the debugger on a script
|
109
|
+
if __FILE__ == $0
|
110
|
+
|
111
|
+
require 'rubygems'; require 'require_relative'
|
112
|
+
require_relative 'mock'
|
113
|
+
require_relative 'command/base/cmd'
|
114
|
+
|
115
|
+
class Trepan::TestCommand < Trepan::Command
|
116
|
+
|
117
|
+
HELP = 'Help string string for testing'
|
118
|
+
CATEGORY = 'data'
|
119
|
+
MIN_ARGS = 0
|
120
|
+
MAX_ARGS = 5
|
121
|
+
NAME_ALIASES = %w(test)
|
122
|
+
|
123
|
+
def initialize(proc); @proc = proc end
|
124
|
+
|
125
|
+
def run(args); puts 'test command run' end
|
126
|
+
end
|
127
|
+
|
128
|
+
class TestTestingSubcommand
|
129
|
+
HELP = 'Help string for test testing subcommand'
|
130
|
+
|
131
|
+
def initialize; @name = 'testing' end
|
132
|
+
|
133
|
+
SHORT_HELP = 'This is short help for test testing'
|
134
|
+
MIN_ABREV = 4
|
135
|
+
IN_LIST = true
|
136
|
+
def run(args); puts 'test testing run' end
|
137
|
+
end
|
138
|
+
|
139
|
+
d = MockDebugger::MockDebugger.new
|
140
|
+
testcmd = Trepan::TestCommand.new(nil)
|
141
|
+
# testcmd.debugger = d
|
142
|
+
# testcmd.proc = d.core.processor
|
143
|
+
# testcmdMgr = Subcmd.new('test', testcmd)
|
144
|
+
# testsub = TestTestingSubcommand.new
|
145
|
+
# testcmdMgr.add(testsub)
|
146
|
+
|
147
|
+
# %w(tes test testing testing1).each do |prefix|
|
148
|
+
# x = testcmdMgr.lookup(prefix)
|
149
|
+
# puts x ? x.name : 'Non'
|
150
|
+
# end
|
151
|
+
|
152
|
+
# testcmdMgr.short_help(testcmd, 'testing')
|
153
|
+
# testcmdMgr.short_help(testcmd, 'test', true)
|
154
|
+
# testcmdMgr.short_help(testcmd, 'tes')
|
155
|
+
# puts testcmdMgr.list()
|
156
|
+
# testsub2 = TestTestingSubcommand.new
|
157
|
+
# testsub2.name = 'foobar'
|
158
|
+
# testcmdMgr.add(testsub2)
|
159
|
+
# puts testcmdMgr.list()
|
160
|
+
end
|