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
data/processor/eval.rb
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
# Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
|
2
|
+
class Trepan
|
3
|
+
class CmdProcessor
|
4
|
+
|
5
|
+
def debug_eval(str, max_fake_filename=15)
|
6
|
+
begin
|
7
|
+
debug_eval_with_exception(str, max_fake_filename)
|
8
|
+
rescue SyntaxError, StandardError, ScriptError => e
|
9
|
+
exception_dump(e, @settings[:stack_trace_on_error], $!.backtrace)
|
10
|
+
nil
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def debug_eval_with_exception(str, max_fake_filename=15)
|
15
|
+
@frame.run(str, fake_eval_filename(str, max_fake_filename))
|
16
|
+
end
|
17
|
+
|
18
|
+
def debug_eval_no_errmsg(str, max_fake_filename=15)
|
19
|
+
begin
|
20
|
+
debug_eval_with_exception(str, max_fake_filename)
|
21
|
+
rescue SyntaxError, StandardError, ScriptError => e
|
22
|
+
nil
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def eval_code(str, max_fake_filename)
|
27
|
+
obj = debug_eval(str, max_fake_filename)
|
28
|
+
|
29
|
+
idx = @user_variables
|
30
|
+
@user_variables += 1
|
31
|
+
|
32
|
+
str = "$d#{idx}"
|
33
|
+
Rubinius::Globals[str.to_sym] = obj
|
34
|
+
msg "#{str} = #{obj.inspect}"
|
35
|
+
obj
|
36
|
+
end
|
37
|
+
|
38
|
+
def exception_dump(e, stack_trace, backtrace)
|
39
|
+
str = "#{e.class} Exception:\n\t#{e.message}"
|
40
|
+
if stack_trace
|
41
|
+
str += "\n" + backtrace.map{|l| "\t#{l}"}.join("\n") rescue nil
|
42
|
+
end
|
43
|
+
msg str
|
44
|
+
# throw :debug_error
|
45
|
+
end
|
46
|
+
|
47
|
+
def fake_eval_filename(str, maxlen = 15)
|
48
|
+
fake_filename =
|
49
|
+
if maxlen < str.size
|
50
|
+
# FIXME: Guard against \" in positions 13..15?
|
51
|
+
str.inspect[0..maxlen-1] + '"...'
|
52
|
+
else
|
53
|
+
str.inspect
|
54
|
+
end
|
55
|
+
"(eval #{fake_filename})"
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
if __FILE__ == $0
|
62
|
+
# Demo it.
|
63
|
+
cmdp = Trepan::CmdProcessor.new
|
64
|
+
puts cmdp.fake_eval_filename('x = 1; y = 2')
|
65
|
+
puts cmdp.fake_eval_filename('x = 1; y = 2', 7)
|
66
|
+
def cmdp.errmsg(msg)
|
67
|
+
puts "** #{msg}"
|
68
|
+
end
|
69
|
+
def cmdp.msg(msg)
|
70
|
+
puts "#{msg}"
|
71
|
+
end
|
72
|
+
begin
|
73
|
+
1/0
|
74
|
+
rescue Exception => exc
|
75
|
+
cmdp.exception_dump(exc, true, $!.backtrace)
|
76
|
+
puts '=' * 40
|
77
|
+
end
|
78
|
+
|
79
|
+
x = 10
|
80
|
+
|
81
|
+
require 'rubygems'; require 'require_relative'
|
82
|
+
require_relative '../app/frame'
|
83
|
+
frame = Trepan::Frame.new(self, 1, Rubinius::VM.backtrace(0)[0])
|
84
|
+
cmdp.instance_variable_set('@frame', frame)
|
85
|
+
cmdp.instance_variable_set('@settings', {:stack_trace_on_error => true})
|
86
|
+
def cmdp.errmsg(mess) ; puts mess end
|
87
|
+
# require_relative '../lib/trepanning'
|
88
|
+
# Trepan.start
|
89
|
+
puts cmdp.debug_eval('x = "#{x}"')
|
90
|
+
puts '=' * 40
|
91
|
+
puts cmdp.debug_eval('x+')
|
92
|
+
puts cmdp.debug_eval_no_errmsg('y+')
|
93
|
+
puts '=' * 40
|
94
|
+
puts cmdp.debug_eval('x+')
|
95
|
+
puts cmdp.debug_eval('y = 1; x+', 4)
|
96
|
+
end
|
data/processor/frame.rb
ADDED
@@ -0,0 +1,211 @@
|
|
1
|
+
# Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
|
2
|
+
require 'rubygems'; require 'require_relative'
|
3
|
+
require_relative '../app/frame'
|
4
|
+
require_relative '../app/util'
|
5
|
+
class Trepan
|
6
|
+
class CmdProcessor
|
7
|
+
|
8
|
+
include Util
|
9
|
+
attr_reader :current_thread
|
10
|
+
|
11
|
+
# ThreadFrame, current frame
|
12
|
+
attr_accessor :frame
|
13
|
+
|
14
|
+
# frame index in a "backtrace" command
|
15
|
+
attr_accessor :frame_index
|
16
|
+
attr_reader :hide_level
|
17
|
+
|
18
|
+
# Hash[thread_id] -> FixNum, the level of the last frame to
|
19
|
+
# show. If we called the debugger directly, then there is
|
20
|
+
# generally a portion of a backtrace we don't want to show. We
|
21
|
+
# don't need to store this for all threads, just those we want to
|
22
|
+
# hide frame on. A value of 1 means to hide just the oldest
|
23
|
+
# level. The default or showing all levels is 0.
|
24
|
+
attr_accessor :hidelevels
|
25
|
+
|
26
|
+
# Hash[container] -> file container. This gives us a way to map non-file
|
27
|
+
# container objects to a file container for display.
|
28
|
+
attr_accessor :remap_container
|
29
|
+
|
30
|
+
attr_accessor :stack_size
|
31
|
+
|
32
|
+
# top frame of current thread.
|
33
|
+
attr_accessor :top_frame
|
34
|
+
# attr_reader :threads2frames # Hash[thread_id] -> top_frame
|
35
|
+
|
36
|
+
|
37
|
+
def adjust_frame(frame_num, absolute_pos)
|
38
|
+
frame, frame_num = get_frame(frame_num, absolute_pos)
|
39
|
+
if frame
|
40
|
+
@frame = @dbgr.frame(frame_num)
|
41
|
+
@frame_index = frame_num
|
42
|
+
print_location unless @settings[:traceprint]
|
43
|
+
@line_no = @frame.line
|
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
|
+
# Initializes the thread and frame variables: @frame, @top_frame,
|
65
|
+
# @frame_index, @current_thread, and @threads2frames
|
66
|
+
def frame_setup
|
67
|
+
@frame_index = 0
|
68
|
+
@frame = @top_frame = @dbgr.current_frame
|
69
|
+
@current_thread = @dbgr.debugee_thread
|
70
|
+
@line_no = @frame.line
|
71
|
+
|
72
|
+
@threads2frames ||= {}
|
73
|
+
@threads2frames[@current_thread] = @top_frame
|
74
|
+
set_hide_level
|
75
|
+
end
|
76
|
+
|
77
|
+
# Remove access to thread and frame variables
|
78
|
+
def frame_teardown
|
79
|
+
@top_frame = @frame = @frame_index = @current_thread = nil
|
80
|
+
@threads2frames = {}
|
81
|
+
end
|
82
|
+
|
83
|
+
def frame_initialize
|
84
|
+
@remap_container = {}
|
85
|
+
@remap_iseq = {}
|
86
|
+
@hidelevels = Hash.new(nil)
|
87
|
+
@hide_level = 0
|
88
|
+
end
|
89
|
+
|
90
|
+
def get_frame(frame_num, absolute_pos)
|
91
|
+
if absolute_pos
|
92
|
+
frame_num += @stack_size if frame_num < 0
|
93
|
+
else
|
94
|
+
frame_num += @frame_index
|
95
|
+
end
|
96
|
+
|
97
|
+
if frame_num < 0
|
98
|
+
errmsg('Adjusting would put us beyond the newest frame.')
|
99
|
+
return [nil, nil]
|
100
|
+
elsif frame_num >= @stack_size
|
101
|
+
errmsg('Adjusting would put us beyond the oldest frame.')
|
102
|
+
return [nil, nil]
|
103
|
+
end
|
104
|
+
|
105
|
+
[frame, frame_num]
|
106
|
+
end
|
107
|
+
|
108
|
+
def parent_frame
|
109
|
+
frame = @dbgr.frame(@frame.number + 1)
|
110
|
+
unless frame
|
111
|
+
errmsg "Unable to find parent frame at level #{@frame.number+1}"
|
112
|
+
return nil
|
113
|
+
end
|
114
|
+
frame
|
115
|
+
end
|
116
|
+
|
117
|
+
def set_hide_level
|
118
|
+
@hide_level =
|
119
|
+
if !@settings[:hidelevel] || @settings[:hidelevel] < 0
|
120
|
+
@settings[:hidelevel] = @hidelevels[@current_thread] =
|
121
|
+
find_main_script(@dbgr.vm_locations) || max_stack_size
|
122
|
+
else
|
123
|
+
@settings[:hidelevel]
|
124
|
+
end
|
125
|
+
max_stack_size = @dbgr.vm_locations.size
|
126
|
+
@stack_size = if @hide_level >= max_stack_size
|
127
|
+
max_stack_size else max_stack_size - @hide_level
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
# def get_nonsync_frame(tf)
|
132
|
+
# if (tf.stack_size > 10)
|
133
|
+
# check_frames = (0..5).map{|i| tf.prev(i).method}
|
134
|
+
# if check_frames ==
|
135
|
+
# %w(synchronize event_processor IFUNC call trace_hook IFUNC)
|
136
|
+
# return tf.prev(6)
|
137
|
+
# end
|
138
|
+
# end
|
139
|
+
# tf
|
140
|
+
# end
|
141
|
+
|
142
|
+
# def get_frame_from_thread(th)
|
143
|
+
# if th == Thread.current
|
144
|
+
# @threads2frames[th]
|
145
|
+
# else
|
146
|
+
# # FIXME: Check to see if we are blocked on entry to debugger.
|
147
|
+
# # If so, walk back frames.
|
148
|
+
# tf = get_nonsync_frame(th.threadframe)
|
149
|
+
# @threads2frames = tf
|
150
|
+
# end
|
151
|
+
# end
|
152
|
+
|
153
|
+
# # The dance we have to do to set debugger frame state to
|
154
|
+
# # `frame', which is in the thread with id `thread_id'. We may
|
155
|
+
# # need to the hide initial debugger frames.
|
156
|
+
# def find_and_set_debugged_frame(th, position)
|
157
|
+
|
158
|
+
# thread = threading._active[thread_id]
|
159
|
+
# thread_name = thread.getName()
|
160
|
+
# if (!@settings['dbg_pydbgr'] &&
|
161
|
+
# thread_name == Mthread.current_thread_name())
|
162
|
+
# # The frame we came in on ('current_thread_name') is
|
163
|
+
# # the same as the one we want to switch to. In this case
|
164
|
+
# # we need to some debugger frames are in this stack so
|
165
|
+
# # we need to remove them.
|
166
|
+
# newframe = Mthread.find_debugged_frame(frame)
|
167
|
+
# frame = newframe unless newframe
|
168
|
+
# end
|
169
|
+
# ## FIXME: else: we might be blocked on other threads which are
|
170
|
+
# # about to go into the debugger it not for the fact this one got there
|
171
|
+
# # first. Possibly in the future we want
|
172
|
+
# # to hide the blocks into threading of that locking code as well.
|
173
|
+
|
174
|
+
# # Set stack to new frame
|
175
|
+
# @frame, @curindex = Mcmdproc.get_stack(frame, nil, self.proc)
|
176
|
+
# @proc.stack, @proc.curindex = self.stack, self.curindex
|
177
|
+
|
178
|
+
# # @frame_thread_name = thread_name
|
179
|
+
# end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
if __FILE__ == $0
|
184
|
+
# Demo it.
|
185
|
+
require_relative 'main' # Have to include before defining CmdProcessor!
|
186
|
+
# FIXME
|
187
|
+
class Trepan::CmdProcessor
|
188
|
+
def errmsg(msg)
|
189
|
+
puts msg
|
190
|
+
end
|
191
|
+
def print_location
|
192
|
+
puts "frame location: #{frame.file} #{frame.line}"
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
require_relative './mock'
|
197
|
+
dbgr, cmd = MockDebugger::setup('exit', false)
|
198
|
+
# require_relative '../lib/trepanning'
|
199
|
+
# Trepan.start(:set_restart => true)
|
200
|
+
proc = cmd.proc
|
201
|
+
0.upto(proc.stack_size-1) { |i| proc.adjust_frame(i, true) }
|
202
|
+
puts '*' * 10
|
203
|
+
proc.adjust_frame(-1, true)
|
204
|
+
proc.adjust_frame(0, true)
|
205
|
+
puts '*' * 10
|
206
|
+
proc.stack_size.times { proc.adjust_frame(1, false) }
|
207
|
+
puts '*' * 10
|
208
|
+
proc.adjust_frame(proc.stack_size-1, true)
|
209
|
+
proc.stack_size.times { proc.adjust_frame(-1, false) }
|
210
|
+
|
211
|
+
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,133 @@
|
|
1
|
+
# Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
|
2
|
+
class Trepan
|
3
|
+
class CmdProcessor
|
4
|
+
# Command processor hooks.
|
5
|
+
attr_reader :autodis_hook
|
6
|
+
attr_reader :autoirb_hook
|
7
|
+
attr_reader :autolist_hook
|
8
|
+
attr_reader :debug_dbgr_hook
|
9
|
+
attr_reader :display_hook
|
10
|
+
attr_reader :timer_hook
|
11
|
+
attr_reader :trace_hook
|
12
|
+
attr_reader :tracebuf_hook
|
13
|
+
attr_reader :unconditional_prehooks
|
14
|
+
attr_reader :cmdloop_posthooks
|
15
|
+
attr_reader :cmdloop_prehooks
|
16
|
+
|
17
|
+
# Used to time how long a debugger action takes
|
18
|
+
attr_accessor :time_last
|
19
|
+
|
20
|
+
class Hook
|
21
|
+
attr_accessor :list
|
22
|
+
|
23
|
+
def initialize(list=[])
|
24
|
+
@list = list
|
25
|
+
end
|
26
|
+
|
27
|
+
def delete_by_name(delete_name)
|
28
|
+
@list.delete_if {|hook_name, priority, hook| hook_name == delete_name}
|
29
|
+
end
|
30
|
+
|
31
|
+
def empty?
|
32
|
+
@list.empty?
|
33
|
+
end
|
34
|
+
|
35
|
+
def insert(priority, name, hook)
|
36
|
+
insert_loc = @list.size # at end
|
37
|
+
@list.each_with_index do |entry, index|
|
38
|
+
n, p, h = entry
|
39
|
+
if priority > p
|
40
|
+
insert_loc = index
|
41
|
+
break
|
42
|
+
end
|
43
|
+
end
|
44
|
+
@list.insert(insert_loc, [name, priority, hook])
|
45
|
+
end
|
46
|
+
|
47
|
+
def insert_if_new(priority, name, hook)
|
48
|
+
insert(priority, name, hook) unless
|
49
|
+
@list.find {|try_name, try_priority, try_hook| try_name == name}
|
50
|
+
end
|
51
|
+
|
52
|
+
# Run each function in `hooks' with args
|
53
|
+
def run(*args)
|
54
|
+
@list.each do |name, priority, hook|
|
55
|
+
hook.call(name, *args)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# Could add delete_at and delete if necessary.
|
60
|
+
end
|
61
|
+
|
62
|
+
def hook_initialize(commands)
|
63
|
+
@cmdloop_posthooks = Hook.new
|
64
|
+
@cmdloop_prehooks = Hook.new
|
65
|
+
@unconditional_prehooks = Hook.new
|
66
|
+
|
67
|
+
irb_cmd = commands['irb']
|
68
|
+
@autoirb_hook = ['autoirb',
|
69
|
+
Proc.new{|*args| irb_cmd.run(['irb']) if irb_cmd}]
|
70
|
+
|
71
|
+
@debug_dbgr_hook = ['dbgdbgr',
|
72
|
+
Proc.new{|*args|
|
73
|
+
if settings[:debugdbgr]
|
74
|
+
$trepan_cmdproc = self
|
75
|
+
$trepan_frame = @frame
|
76
|
+
else
|
77
|
+
$trepan_cmdproc = nil
|
78
|
+
$trepan_frame = nil
|
79
|
+
end}]
|
80
|
+
|
81
|
+
display_cmd = commands['display']
|
82
|
+
@display_hook = ['display',
|
83
|
+
Proc.new{|*args| display_cmd.run(['display']) if display_cmd}]
|
84
|
+
|
85
|
+
# FIXME: generalize for any command run
|
86
|
+
dis_cmd = commands['disassemble']
|
87
|
+
@autodis_hook = ['autodis',
|
88
|
+
Proc.new{|*args| dis_cmd.run(['disassemble']) if dis_cmd}]
|
89
|
+
|
90
|
+
list_cmd = commands['list']
|
91
|
+
@autolist_hook = ['autolist',
|
92
|
+
Proc.new{|*args| list_cmd.run(['list']) if list_cmd}]
|
93
|
+
|
94
|
+
@timer_hook = ['timer',
|
95
|
+
Proc.new{|*args|
|
96
|
+
now = Time.now
|
97
|
+
msg("%g seconds" %
|
98
|
+
(now - @time_last)) if @time_last
|
99
|
+
@time_last = now
|
100
|
+
}]
|
101
|
+
@timer_posthook = ['timer', Proc.new{|*args| @time_last = Time.now}]
|
102
|
+
@trace_hook = ['trace',
|
103
|
+
Proc.new{|*args| print_location}]
|
104
|
+
@tracebuf_hook = ['tracebuffer',
|
105
|
+
Proc.new{|*args| @eventbuf.append(@core.event, @frame,
|
106
|
+
@core.hook_arg)}]
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
end
|
111
|
+
if __FILE__ == $0
|
112
|
+
# Demo it.
|
113
|
+
hooks = Trepan::CmdProcessor::Hook.new
|
114
|
+
hooks.run(5)
|
115
|
+
hook1 = Proc.new {|name, a| puts "#{name} called with #{a}"}
|
116
|
+
hooks = Trepan::CmdProcessor::Hook.new()
|
117
|
+
hooks.insert(-1, 'hook1', hook1)
|
118
|
+
p hooks.list
|
119
|
+
hooks.insert_if_new(-1, 'hook1', hook1)
|
120
|
+
puts '-' * 30
|
121
|
+
p hooks.list
|
122
|
+
hooks.run(10)
|
123
|
+
puts '-' * 30
|
124
|
+
hooks.insert(-1, 'hook2', hook1)
|
125
|
+
hooks.run(20)
|
126
|
+
puts '-' * 30
|
127
|
+
hooks.delete_by_name('hook2')
|
128
|
+
hooks.run(30)
|
129
|
+
puts '-' * 30
|
130
|
+
hooks.delete_by_name('hook1')
|
131
|
+
hooks.run(30)
|
132
|
+
puts '-' * 30
|
133
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
# Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net> Part of
|
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
|
+
Trepan::Command.constants.grep(/.Command$/).each do |command|
|
39
|
+
# Note: there is probably a non-eval way to instantiate the
|
40
|
+
# command, but I don't know it. And eval works.
|
41
|
+
new_cmd = "Trepan::Command::#{command}.new(self)"
|
42
|
+
cmd = self.instance_eval(new_cmd)
|
43
|
+
|
44
|
+
# Add to list of commands and aliases.
|
45
|
+
cc = cmd.class
|
46
|
+
cmd_name = cc.const_get(:NAME)
|
47
|
+
if cc.constants.member?('ALIASES')
|
48
|
+
aliases= cc.const_get('ALIASES')
|
49
|
+
aliases.each {|a| @aliases[a] = cmd_name}
|
50
|
+
end
|
51
|
+
@commands[cmd_name] = cmd
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# Looks up cmd_array[0] in @commands and runs that. We do lots of
|
56
|
+
# validity testing on cmd_array.
|
57
|
+
def run_cmd(cmd_array)
|
58
|
+
unless cmd_array.is_a?(Array)
|
59
|
+
errmsg "run_cmd argument should be an Array, got: #{cmd_array.class}"
|
60
|
+
return
|
61
|
+
end
|
62
|
+
if cmd_array.detect{|item| !item.is_a?(String)}
|
63
|
+
errmsg "run_cmd argument Array should only contain strings. " +
|
64
|
+
"Got #{cmd_array.inspect}"
|
65
|
+
return
|
66
|
+
end
|
67
|
+
if cmd_array.empty?
|
68
|
+
errmsg "run_cmd Array should have at least one item. " +
|
69
|
+
"Got: #{cmd_array.inspect}"
|
70
|
+
return
|
71
|
+
end
|
72
|
+
cmd_name = cmd_array[0]
|
73
|
+
if @commands.member?(cmd_name)
|
74
|
+
@commands[cmd_name].run(cmd_array)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
if __FILE__ == $0
|
80
|
+
cmdproc = Trepan::CmdProcessor.new
|
81
|
+
cmddir = File.join(File.dirname(__FILE__), 'command')
|
82
|
+
cmdproc.instance_variable_set('@settings', {})
|
83
|
+
cmdproc.load_cmds_initialize
|
84
|
+
require 'columnize'
|
85
|
+
puts Columnize.columnize(cmdproc.commands.keys.sort)
|
86
|
+
puts '=' * 20
|
87
|
+
puts Columnize.columnize(cmdproc.aliases.keys.sort)
|
88
|
+
puts '=' * 20
|
89
|
+
|
90
|
+
def cmdproc.errmsg(mess)
|
91
|
+
puts "** #{mess}"
|
92
|
+
end
|
93
|
+
|
94
|
+
def cmdproc.msg(mess)
|
95
|
+
puts mess
|
96
|
+
end
|
97
|
+
|
98
|
+
cmdproc.run_cmd('foo') # Invalid - not an Array
|
99
|
+
cmdproc.run_cmd([]) # Invalid - empty Array
|
100
|
+
cmdproc.run_cmd(['list', 5]) # Invalid - nonstring arg
|
101
|
+
end
|