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.
- data/ChangeLog +4422 -0
- data/LICENSE +23 -0
- data/NEWS +12 -0
- data/README.textile +56 -0
- data/Rakefile +171 -0
- data/app/Makefile +7 -0
- data/app/breakpoint.rb +157 -0
- data/app/brkptmgr.rb +149 -0
- data/app/condition.rb +22 -0
- data/app/core.rb +203 -0
- data/app/default.rb +54 -0
- data/app/disassemble.rb +61 -0
- data/app/display.rb +148 -0
- data/app/file.rb +135 -0
- data/app/frame.rb +275 -0
- data/app/irb.rb +112 -0
- data/app/mock.rb +22 -0
- data/app/options.rb +122 -0
- data/app/run.rb +95 -0
- data/app/thread.rb +24 -0
- data/app/util.rb +32 -0
- data/bin/trepan +63 -0
- data/data/custom_require.rb +44 -0
- data/data/irbrc +55 -0
- data/data/prelude.rb +38 -0
- data/interface/base_intf.rb +95 -0
- data/interface/script.rb +103 -0
- data/interface/user.rb +90 -0
- data/io/base_io.rb +92 -0
- data/io/input.rb +111 -0
- data/io/string_array.rb +155 -0
- data/lib/Makefile +7 -0
- data/lib/trepanning.rb +277 -0
- data/processor/breakpoint.rb +108 -0
- data/processor/command/alias.rb +55 -0
- data/processor/command/backtrace.rb +95 -0
- data/processor/command/base/cmd.rb +97 -0
- data/processor/command/base/subcmd.rb +207 -0
- data/processor/command/base/submgr.rb +178 -0
- data/processor/command/base/subsubcmd.rb +102 -0
- data/processor/command/base/subsubmgr.rb +182 -0
- data/processor/command/break.rb +85 -0
- data/processor/command/condition.rb +64 -0
- data/processor/command/continue.rb +61 -0
- data/processor/command/debug.rb +85 -0
- data/processor/command/delete.rb +54 -0
- data/processor/command/directory.rb +43 -0
- data/processor/command/disable.rb +65 -0
- data/processor/command/disassemble.rb +103 -0
- data/processor/command/display.rb +81 -0
- data/processor/command/down.rb +56 -0
- data/processor/command/enable.rb +43 -0
- data/processor/command/exit.rb +54 -0
- data/processor/command/finish.rb +81 -0
- data/processor/command/frame.rb +117 -0
- data/processor/command/help.rb +146 -0
- data/processor/command/info.rb +28 -0
- data/processor/command/info_subcmd/args.rb +56 -0
- data/processor/command/info_subcmd/breakpoints.rb +162 -0
- data/processor/command/info_subcmd/file.rb +162 -0
- data/processor/command/info_subcmd/frame.rb +39 -0
- data/processor/command/info_subcmd/iseq.rb +83 -0
- data/processor/command/info_subcmd/locals.rb +88 -0
- data/processor/command/info_subcmd/program.rb +54 -0
- data/processor/command/info_subcmd/registers.rb +72 -0
- data/processor/command/info_subcmd/registers_subcmd/dfp.rb +38 -0
- data/processor/command/info_subcmd/registers_subcmd/helper.rb +40 -0
- data/processor/command/info_subcmd/registers_subcmd/lfp.rb +54 -0
- data/processor/command/info_subcmd/registers_subcmd/pc.rb +44 -0
- data/processor/command/info_subcmd/registers_subcmd/sp.rb +75 -0
- data/processor/command/info_subcmd/return.rb +40 -0
- data/processor/command/info_subcmd/thread.rb +106 -0
- data/processor/command/irb.rb +106 -0
- data/processor/command/kill.rb +58 -0
- data/processor/command/list.rb +327 -0
- data/processor/command/macro.rb +65 -0
- data/processor/command/next.rb +89 -0
- data/processor/command/nocache.rb +33 -0
- data/processor/command/print.rb +37 -0
- data/processor/command/ps.rb +40 -0
- data/processor/command/quit.rb +62 -0
- data/processor/command/raise.rb +47 -0
- data/processor/command/reload.rb +28 -0
- data/processor/command/reload_subcmd/command.rb +34 -0
- data/processor/command/restart.rb +57 -0
- data/processor/command/save.rb +60 -0
- data/processor/command/set.rb +47 -0
- data/processor/command/set_subcmd/auto.rb +27 -0
- data/processor/command/set_subcmd/auto_subcmd/eval.rb +67 -0
- data/processor/command/set_subcmd/auto_subcmd/irb.rb +49 -0
- data/processor/command/set_subcmd/auto_subcmd/list.rb +51 -0
- data/processor/command/set_subcmd/basename.rb +39 -0
- data/processor/command/set_subcmd/debug.rb +27 -0
- data/processor/command/set_subcmd/debug_subcmd/dbgr.rb +49 -0
- data/processor/command/set_subcmd/debug_subcmd/except.rb +35 -0
- data/processor/command/set_subcmd/debug_subcmd/macro.rb +35 -0
- data/processor/command/set_subcmd/debug_subcmd/skip.rb +35 -0
- data/processor/command/set_subcmd/debug_subcmd/stack.rb +45 -0
- data/processor/command/set_subcmd/different.rb +67 -0
- data/processor/command/set_subcmd/events.rb +71 -0
- data/processor/command/set_subcmd/max.rb +35 -0
- data/processor/command/set_subcmd/max_subcmd/list.rb +50 -0
- data/processor/command/set_subcmd/max_subcmd/stack.rb +60 -0
- data/processor/command/set_subcmd/max_subcmd/string.rb +53 -0
- data/processor/command/set_subcmd/max_subcmd/width.rb +50 -0
- data/processor/command/set_subcmd/return.rb +66 -0
- data/processor/command/set_subcmd/sp.rb +62 -0
- data/processor/command/set_subcmd/substitute.rb +25 -0
- data/processor/command/set_subcmd/substitute_subcmd/eval.rb +98 -0
- data/processor/command/set_subcmd/substitute_subcmd/path.rb +55 -0
- data/processor/command/set_subcmd/substitute_subcmd/string.rb +72 -0
- data/processor/command/set_subcmd/timer.rb +68 -0
- data/processor/command/set_subcmd/trace.rb +43 -0
- data/processor/command/set_subcmd/trace_subcmd/buffer.rb +56 -0
- data/processor/command/set_subcmd/trace_subcmd/print.rb +54 -0
- data/processor/command/set_subcmd/trace_subcmd/var.rb +61 -0
- data/processor/command/show.rb +27 -0
- data/processor/command/show_subcmd/alias.rb +50 -0
- data/processor/command/show_subcmd/args.rb +50 -0
- data/processor/command/show_subcmd/auto.rb +27 -0
- data/processor/command/show_subcmd/auto_subcmd/eval.rb +38 -0
- data/processor/command/show_subcmd/auto_subcmd/irb.rb +34 -0
- data/processor/command/show_subcmd/auto_subcmd/list.rb +36 -0
- data/processor/command/show_subcmd/basename.rb +28 -0
- data/processor/command/show_subcmd/debug.rb +27 -0
- data/processor/command/show_subcmd/debug_subcmd/dbgr.rb +31 -0
- data/processor/command/show_subcmd/debug_subcmd/except.rb +33 -0
- data/processor/command/show_subcmd/debug_subcmd/macro.rb +32 -0
- data/processor/command/show_subcmd/debug_subcmd/skip.rb +33 -0
- data/processor/command/show_subcmd/debug_subcmd/stack.rb +32 -0
- data/processor/command/show_subcmd/different.rb +37 -0
- data/processor/command/show_subcmd/events.rb +40 -0
- data/processor/command/show_subcmd/macro.rb +45 -0
- data/processor/command/show_subcmd/max.rb +31 -0
- data/processor/command/show_subcmd/max_subcmd/list.rb +39 -0
- data/processor/command/show_subcmd/max_subcmd/stack.rb +35 -0
- data/processor/command/show_subcmd/max_subcmd/string.rb +41 -0
- data/processor/command/show_subcmd/max_subcmd/width.rb +36 -0
- data/processor/command/show_subcmd/trace.rb +29 -0
- data/processor/command/show_subcmd/trace_subcmd/buffer.rb +84 -0
- data/processor/command/show_subcmd/trace_subcmd/print.rb +38 -0
- data/processor/command/source.rb +74 -0
- data/processor/command/step.rb +139 -0
- data/processor/command/stepi.rb +63 -0
- data/processor/command/unalias.rb +44 -0
- data/processor/command/undisplay.rb +63 -0
- data/processor/command/up.rb +92 -0
- data/processor/default.rb +45 -0
- data/processor/display.rb +17 -0
- data/processor/eval.rb +88 -0
- data/processor/eventbuf.rb +131 -0
- data/processor/frame.rb +230 -0
- data/processor/help.rb +72 -0
- data/processor/hook.rb +128 -0
- data/processor/load_cmds.rb +102 -0
- data/processor/location.rb +126 -0
- data/processor/main.rb +364 -0
- data/processor/mock.rb +100 -0
- data/processor/msg.rb +26 -0
- data/processor/running.rb +170 -0
- data/processor/subcmd.rb +159 -0
- data/processor/validate.rb +395 -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 +119 -0
- data/test/functional/test-break.rb +87 -0
- data/test/functional/test-condition.rb +59 -0
- data/test/functional/test-debugger-call-bug.rb +31 -0
- data/test/functional/test-delete.rb +71 -0
- data/test/functional/test-finish.rb +44 -0
- data/test/functional/test-immediate-step-bug.rb +35 -0
- data/test/functional/test-next.rb +77 -0
- data/test/functional/test-raise.rb +73 -0
- data/test/functional/test-return.rb +100 -0
- data/test/functional/test-step.rb +274 -0
- data/test/functional/test-stepbug.rb +40 -0
- data/test/functional/test-trace-var.rb +40 -0
- data/test/functional/tmp/b1.rb +5 -0
- data/test/functional/tmp/s1.rb +9 -0
- data/test/functional/tmp/t2.rb +6 -0
- data/test/integration/file-diff.rb +88 -0
- data/test/integration/helper.rb +52 -0
- data/test/integration/test-fname-with-blank.rb +11 -0
- data/test/integration/test-quit.rb +11 -0
- data/test/integration/try-test-enable.rb +11 -0
- data/test/unit/cmd-helper.rb +44 -0
- data/test/unit/test-app-brkpt.rb +30 -0
- data/test/unit/test-app-brkptmgr.rb +56 -0
- data/test/unit/test-app-disassemble.rb +60 -0
- data/test/unit/test-app-file.rb +46 -0
- data/test/unit/test-app-frame.rb +49 -0
- data/test/unit/test-app-options.rb +60 -0
- data/test/unit/test-app-run.rb +19 -0
- data/test/unit/test-app-thread.rb +25 -0
- data/test/unit/test-app-util.rb +17 -0
- data/test/unit/test-base-subcmd.rb +59 -0
- data/test/unit/test-bin-trepan.rb +48 -0
- data/test/unit/test-cmd-alias.rb +50 -0
- data/test/unit/test-cmd-break.rb +80 -0
- data/test/unit/test-cmd-endisable.rb +59 -0
- data/test/unit/test-cmd-help.rb +100 -0
- data/test/unit/test-cmd-kill.rb +47 -0
- data/test/unit/test-cmd-quit.rb +26 -0
- data/test/unit/test-cmd-step.rb +45 -0
- data/test/unit/test-intf-user.rb +45 -0
- data/test/unit/test-io-input.rb +26 -0
- data/test/unit/test-proc-eval.rb +26 -0
- data/test/unit/test-proc-frame.rb +77 -0
- data/test/unit/test-proc-help.rb +15 -0
- data/test/unit/test-proc-hook.rb +29 -0
- data/test/unit/test-proc-load_cmds.rb +40 -0
- data/test/unit/test-proc-main.rb +99 -0
- data/test/unit/test-proc-validate.rb +90 -0
- data/test/unit/test-subcmd-help.rb +48 -0
- metadata +358 -0
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
# Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
|
|
2
|
+
|
|
3
|
+
# Trepan command input validation routines. A String type is
|
|
4
|
+
# usually passed in as the argument to validation routines.
|
|
5
|
+
|
|
6
|
+
require_relative '../app/condition'
|
|
7
|
+
require_relative '../app/file'
|
|
8
|
+
require_relative '../app/thread'
|
|
9
|
+
|
|
10
|
+
require_relative 'location' # for resolve_file_with_dir
|
|
11
|
+
require_relative 'msg' # for errmsg, msg
|
|
12
|
+
|
|
13
|
+
class Trepan
|
|
14
|
+
class CmdProcessor
|
|
15
|
+
|
|
16
|
+
attr_reader :dbgr_script_iseqs
|
|
17
|
+
attr_reader :dbgr_iseqs
|
|
18
|
+
|
|
19
|
+
include Trepanning
|
|
20
|
+
include Trepan::ThreadHelper
|
|
21
|
+
include Trepan::Condition
|
|
22
|
+
|
|
23
|
+
def confirm(msg, default)
|
|
24
|
+
@dbgr.intf[-1].confirm(msg, default)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Like cmdfns.get_an_int(), but if there's a stack frame use that
|
|
28
|
+
# in evaluation.
|
|
29
|
+
def get_an_int(arg, opts={})
|
|
30
|
+
ret_value = get_int_noerr(arg)
|
|
31
|
+
if !ret_value
|
|
32
|
+
if opts[:msg_on_error]
|
|
33
|
+
errmsg(opts[:msg_on_error])
|
|
34
|
+
else
|
|
35
|
+
errmsg("Expecting an integer, got: #{arg}.")
|
|
36
|
+
end
|
|
37
|
+
return nil
|
|
38
|
+
end
|
|
39
|
+
if opts[:min_value] and ret_value < opts[:min_value]
|
|
40
|
+
errmsg("Expecting integer value to be at least %d; got %d." %
|
|
41
|
+
[opts[:min_value], ret_value])
|
|
42
|
+
return nil
|
|
43
|
+
elsif opts[:max_value] and ret_value > opts[:max_value]
|
|
44
|
+
errmsg("Expecting integer value to be at most %d; got %d." %
|
|
45
|
+
[opts[:max_value], ret_value])
|
|
46
|
+
return nil
|
|
47
|
+
end
|
|
48
|
+
return ret_value
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
unless defined?(DEFAULT_GET_INT_OPTS)
|
|
52
|
+
DEFAULT_GET_INT_OPTS = {
|
|
53
|
+
:min_value => 0, :default => 1, :cmdname => nil, :max_value => nil}
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# If argument parameter 'arg' is not given, then use what is in
|
|
57
|
+
# opts[:default]. If String 'arg' evaluates to an integer between
|
|
58
|
+
# least min_value and at_most, use that. Otherwise report an
|
|
59
|
+
# error. If there's a stack frame use that for bindings in
|
|
60
|
+
# evaluation.
|
|
61
|
+
def get_int(arg, opts={})
|
|
62
|
+
|
|
63
|
+
return default unless arg
|
|
64
|
+
opts = DEFAULT_GET_INT_OPTS.merge(opts)
|
|
65
|
+
val = arg ? get_int_noerr(arg) : opts[:default]
|
|
66
|
+
unless val
|
|
67
|
+
if opts[:cmdname]
|
|
68
|
+
errmsg(("Command '%s' expects an integer; " +
|
|
69
|
+
"got: %s.") % [opts[:cmdname], arg])
|
|
70
|
+
else
|
|
71
|
+
errmsg('Expecting a positive integer, got: %s' % arg)
|
|
72
|
+
end
|
|
73
|
+
return nil
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
if val < opts[:min_value]
|
|
77
|
+
if cmdname
|
|
78
|
+
errmsg(("Command '%s' expects an integer at least" +
|
|
79
|
+
' %d; got: %d.') %
|
|
80
|
+
[cmdname, opts[:min_value], opts[:default]])
|
|
81
|
+
else
|
|
82
|
+
errmsg(("Expecting a positive integer at least" +
|
|
83
|
+
' %d; got: %d') %
|
|
84
|
+
[opts[:min_value], opts[:default]])
|
|
85
|
+
end
|
|
86
|
+
return nil
|
|
87
|
+
elsif opts[:max_value] and val > opts[:max_value]
|
|
88
|
+
if opts[:cmdname]
|
|
89
|
+
errmsg(("Command '%s' expects an integer at most" +
|
|
90
|
+
' %d; got: %d.') %
|
|
91
|
+
[opts[:cmdname], opts[:max_value], val])
|
|
92
|
+
else
|
|
93
|
+
errmsg(("Expecting an integer at most %d; got: %d") %
|
|
94
|
+
[opts[:max_value], val])
|
|
95
|
+
end
|
|
96
|
+
return nil
|
|
97
|
+
end
|
|
98
|
+
return val
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def get_int_list(args, opts={})
|
|
102
|
+
args.map{|arg| get_an_int(arg, opts)}.compact
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Eval arg and it is an integer return the value. Otherwise
|
|
106
|
+
# return nil
|
|
107
|
+
def get_int_noerr(arg)
|
|
108
|
+
b = @frame ? @frame.binding : nil
|
|
109
|
+
val = Integer(eval(arg, b))
|
|
110
|
+
rescue SyntaxError
|
|
111
|
+
nil
|
|
112
|
+
rescue
|
|
113
|
+
nil
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def get_thread_from_string(id_or_num_str)
|
|
117
|
+
if id_or_num_str == '.'
|
|
118
|
+
Thread.current
|
|
119
|
+
elsif id_or_num_str.downcase == 'm'
|
|
120
|
+
Thread.main
|
|
121
|
+
else
|
|
122
|
+
num = get_int_noerr(id_or_num_str)
|
|
123
|
+
if num
|
|
124
|
+
get_thread(num)
|
|
125
|
+
else
|
|
126
|
+
nil
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# Return the instruction sequence associated with string
|
|
132
|
+
# OBJECT_STRING or nil if no instruction sequence
|
|
133
|
+
def object_iseq(object_string)
|
|
134
|
+
iseqs = find_iseqs(ISEQS__, object_string)
|
|
135
|
+
# FIXME: do something if there is more than one.
|
|
136
|
+
if iseqs.size == 1
|
|
137
|
+
iseqs[-1]
|
|
138
|
+
elsif debug_eval_no_errmsg("#{object_string}.respond_to?('iseq')")
|
|
139
|
+
debug_eval_no_errmsg("#{object_string}.iseq")
|
|
140
|
+
else
|
|
141
|
+
parts = object_string.split(/[.]/)
|
|
142
|
+
string =
|
|
143
|
+
if parts.size < 2
|
|
144
|
+
"method(\"#{object_string}\").iseq"
|
|
145
|
+
else
|
|
146
|
+
parts[0..-2].join('.')+".method(\"#{parts[-1]}\").iseq"
|
|
147
|
+
end
|
|
148
|
+
debug_eval_no_errmsg(string)
|
|
149
|
+
end
|
|
150
|
+
rescue
|
|
151
|
+
nil
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
# Parse a breakpoint position. Return
|
|
155
|
+
# - the position - a Fixnum
|
|
156
|
+
# - the instruction sequence to use
|
|
157
|
+
# - whether the postion is an offset or a line number
|
|
158
|
+
# - the condition (by default 'true') to use for this breakpoint
|
|
159
|
+
# - the condition (by default 'true') to use for this breakpoint
|
|
160
|
+
def breakpoint_position(args)
|
|
161
|
+
first = args.shift
|
|
162
|
+
name, container, position = parse_position(first, nil, true)
|
|
163
|
+
if container && position
|
|
164
|
+
iseq = find_iseqs_with_lineno(container[1], position) || object_iseq(first)
|
|
165
|
+
unless iseq
|
|
166
|
+
if @frame.iseq &&
|
|
167
|
+
File.basename(@frame.iseq.source_container[1]) ==
|
|
168
|
+
File.basename(container[1])
|
|
169
|
+
iseq = @frame.iseq
|
|
170
|
+
else
|
|
171
|
+
errmsg "Unable to find instruction sequence for position #{position} in #{container[1]}"
|
|
172
|
+
return [nil, nil, nil, true]
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
use_offset = false
|
|
176
|
+
else
|
|
177
|
+
iseq = object_iseq(first)
|
|
178
|
+
position_str =
|
|
179
|
+
if iseq
|
|
180
|
+
# Got name and possibly position
|
|
181
|
+
name = first
|
|
182
|
+
if args.empty?
|
|
183
|
+
# FIXME: *Still* have a bug stopping at offset 0.
|
|
184
|
+
# So stop at next offset after 0.
|
|
185
|
+
# 'o0'
|
|
186
|
+
"o#{@frame.iseq.offsetlines.keys.sort[1]}"
|
|
187
|
+
else
|
|
188
|
+
args.shift
|
|
189
|
+
end
|
|
190
|
+
else
|
|
191
|
+
iseq = @frame.iseq unless container
|
|
192
|
+
first
|
|
193
|
+
end
|
|
194
|
+
use_offset =
|
|
195
|
+
if position_str.size > 0 && position_str[0].downcase == 'o'
|
|
196
|
+
position_str[0] = ''
|
|
197
|
+
true
|
|
198
|
+
else
|
|
199
|
+
false
|
|
200
|
+
end
|
|
201
|
+
opts = {
|
|
202
|
+
:msg_on_error =>
|
|
203
|
+
"argument '%s' does not seem to eval to a method or an integer." %
|
|
204
|
+
position_str,
|
|
205
|
+
:min_value => 0
|
|
206
|
+
}
|
|
207
|
+
position = get_an_int(position_str, opts)
|
|
208
|
+
end
|
|
209
|
+
condition = 'true'
|
|
210
|
+
if args.size > 0 && 'if' == args[0]
|
|
211
|
+
condition_try = args[1..-1].join(' ')
|
|
212
|
+
condition = condition_try if valid_condition?(condition_try)
|
|
213
|
+
end
|
|
214
|
+
return [position, iseq, use_offset, condition, name]
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
# Return true if arg is 'on' or 1 and false arg is 'off' or 0.
|
|
218
|
+
# Any other value is raises TypeError.
|
|
219
|
+
def get_onoff(arg, default=nil, print_error=true)
|
|
220
|
+
unless arg
|
|
221
|
+
if !default
|
|
222
|
+
if print_error
|
|
223
|
+
errmsg("Expecting 'on', 1, 'off', or 0. Got nothing.")
|
|
224
|
+
end
|
|
225
|
+
raise TypeError
|
|
226
|
+
end
|
|
227
|
+
return default
|
|
228
|
+
end
|
|
229
|
+
darg = arg.downcase
|
|
230
|
+
return true if arg == '1' || darg == 'on'
|
|
231
|
+
return false if arg == '0' || darg =='off'
|
|
232
|
+
|
|
233
|
+
errmsg("Expecting 'on', 1, 'off', or 0. Got: %s." % arg.to_s) if
|
|
234
|
+
print_error
|
|
235
|
+
raise TypeError
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
def method?(method_string)
|
|
239
|
+
obj, type, meth =
|
|
240
|
+
if method_string =~ /(.+)(#|::|\.)(.+)/
|
|
241
|
+
[$1, $2, $3]
|
|
242
|
+
else
|
|
243
|
+
['self', '.', method_string]
|
|
244
|
+
end
|
|
245
|
+
ret = debug_eval_no_errmsg("#{obj}.method(#{meth.inspect})")
|
|
246
|
+
return true if ret
|
|
247
|
+
return debug_eval_no_errmsg("#{obj}.is_a?(Class)") &&
|
|
248
|
+
debug_eval_no_errmsg("#{obj}.method_defined?(#{meth.inspect})")
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
# parse_position(self, arg)->(fn, container, lineno)
|
|
252
|
+
#
|
|
253
|
+
# Parse arg as [filename:]lineno | function | module
|
|
254
|
+
# Make sure it works for C:\foo\bar.py:12
|
|
255
|
+
def parse_position(arg, old_mod=nil, allow_offset = false)
|
|
256
|
+
colon = arg.rindex(':')
|
|
257
|
+
if colon
|
|
258
|
+
# First handle part before the colon
|
|
259
|
+
arg1 = arg[0...colon].rstrip
|
|
260
|
+
lineno_str = arg[colon+1..-1].lstrip
|
|
261
|
+
mf, container, lineno = parse_position_one_arg(arg1, old_mod, false, allow_offset)
|
|
262
|
+
return nil, nil, nil unless container
|
|
263
|
+
filename = canonic_file(arg1)
|
|
264
|
+
# Next handle part after the colon
|
|
265
|
+
val = get_an_int(lineno_str)
|
|
266
|
+
lineno = val if val
|
|
267
|
+
else
|
|
268
|
+
mf, container, lineno = parse_position_one_arg(arg, old_mod, true, allow_offset)
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
return mf, container, lineno
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
# parse_position_one_arg(self,arg)->(module/function, container, lineno)
|
|
275
|
+
#
|
|
276
|
+
# See if arg is a line number, function name, or module name.
|
|
277
|
+
# Return what we've found. nil can be returned as a value in
|
|
278
|
+
# the triple.
|
|
279
|
+
def parse_position_one_arg(arg, old_mod=nil, show_errmsg=true, allow_offset=false)
|
|
280
|
+
name, filename = nil, nil, nil
|
|
281
|
+
begin
|
|
282
|
+
# First see if argument is an integer
|
|
283
|
+
lineno = Integer(arg)
|
|
284
|
+
rescue
|
|
285
|
+
else
|
|
286
|
+
container = frame_container(@frame, false)
|
|
287
|
+
filename = container[1] unless old_mod
|
|
288
|
+
return nil, [container[0], canonic_file(filename)], lineno
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
# Next see if argument is a file name
|
|
292
|
+
found =
|
|
293
|
+
if arg[0..0] == File::SEPARATOR
|
|
294
|
+
LineCache::cached?(arg)
|
|
295
|
+
else
|
|
296
|
+
resolve_file_with_dir(arg)
|
|
297
|
+
end
|
|
298
|
+
if found
|
|
299
|
+
return nil, [container && container[0], canonic_file(arg)], 1
|
|
300
|
+
else
|
|
301
|
+
matches = find_scripts(arg)
|
|
302
|
+
if matches.size > 1
|
|
303
|
+
if show_errmsg
|
|
304
|
+
errmsg "#{arg} is matches several files:"
|
|
305
|
+
errmsg Columnize::columnize(matches.sort,
|
|
306
|
+
@settings[:width], ' ' * 4,
|
|
307
|
+
true, true, ' ' * 2).chomp
|
|
308
|
+
end
|
|
309
|
+
return nil, nil, nil
|
|
310
|
+
elsif matches.size == 1
|
|
311
|
+
LineCache::cache(matches[0])
|
|
312
|
+
return nil, ['file', matches[0]], 1
|
|
313
|
+
end
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
# How about a method name with an instruction sequence?
|
|
317
|
+
iseq = object_iseq(arg)
|
|
318
|
+
if iseq && iseq.source_container[0] == 'file'
|
|
319
|
+
filename = iseq.source_container[1]
|
|
320
|
+
line_no = iseq.offsetlines.values.flatten.min
|
|
321
|
+
return arg, ['file', canonic_file(filename)], line_no
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
if show_errmsg
|
|
325
|
+
unless (allow_offset && arg.size > 0 && arg[0].downcase == 'o')
|
|
326
|
+
errmsg("#{arg} is not a line number, read-in filename or method " +
|
|
327
|
+
"we can get location information about")
|
|
328
|
+
end
|
|
329
|
+
end
|
|
330
|
+
return nil, nil, nil
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
def validate_initialize
|
|
334
|
+
## top_srcdir = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
|
335
|
+
## @dbgr_script_iseqs, @dbgr_iseqs = filter_scripts(top_srcdir)
|
|
336
|
+
end
|
|
337
|
+
end
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
if __FILE__ == $0
|
|
341
|
+
# Demo it.
|
|
342
|
+
if !(ARGV.size == 1 && ARGV[0] == 'noload')
|
|
343
|
+
ARGV[0..-1] = ['noload']
|
|
344
|
+
load(__FILE__)
|
|
345
|
+
else
|
|
346
|
+
require 'thread_frame'
|
|
347
|
+
require_relative '../app/mock'
|
|
348
|
+
require_relative 'main' # Have to include before defining CmdProcessor!
|
|
349
|
+
# FIXME
|
|
350
|
+
|
|
351
|
+
proc = Trepan::CmdProcessor.new(Trepan::MockCore.new())
|
|
352
|
+
proc.settings[:directory] = '$cwd'
|
|
353
|
+
proc.frame_setup(RubyVM::ThreadFrame.current)
|
|
354
|
+
onoff = %w(1 0 on off)
|
|
355
|
+
onoff.each { |val| puts "onoff(#{val}) = #{proc.get_onoff(val)}" }
|
|
356
|
+
%w(1 1E bad 1+1 -5).each do |val|
|
|
357
|
+
puts "get_int_noerr(#{val}) = #{proc.get_int_noerr(val).inspect}"
|
|
358
|
+
end
|
|
359
|
+
def foo; 5 end
|
|
360
|
+
def proc.errmsg(msg)
|
|
361
|
+
puts msg
|
|
362
|
+
end
|
|
363
|
+
puts proc.object_iseq('food').inspect
|
|
364
|
+
puts proc.object_iseq('foo').inspect
|
|
365
|
+
|
|
366
|
+
puts proc.object_iseq('foo@validate.rb').inspect
|
|
367
|
+
puts proc.object_iseq('proc.object_iseq').inspect
|
|
368
|
+
|
|
369
|
+
puts proc.parse_position_one_arg('tmpdir.rb').inspect
|
|
370
|
+
|
|
371
|
+
puts '=' * 40
|
|
372
|
+
['Array#map', 'Trepan::CmdProcessor.new',
|
|
373
|
+
'foo', 'proc.errmsg'].each do |str|
|
|
374
|
+
puts "#{str} should be true: #{proc.method?(str).inspect}"
|
|
375
|
+
end
|
|
376
|
+
puts '=' * 40
|
|
377
|
+
# require_relative '../lib/trepanning'
|
|
378
|
+
# dbgr = Trepan.new(:set_restart => true)
|
|
379
|
+
# dbgr.debugger
|
|
380
|
+
|
|
381
|
+
# FIXME:
|
|
382
|
+
# Array#foo should be false: true
|
|
383
|
+
# Trepan::CmdProcessor.allocate should be false: true
|
|
384
|
+
|
|
385
|
+
['food', '.errmsg'].each do |str|
|
|
386
|
+
puts "#{str} should be false: #{proc.method?(str).inspect}"
|
|
387
|
+
end
|
|
388
|
+
puts '-' * 20
|
|
389
|
+
p proc.breakpoint_position(%w(O0))
|
|
390
|
+
p proc.breakpoint_position(%w(1))
|
|
391
|
+
p proc.breakpoint_position(%w(2 if a > b))
|
|
392
|
+
p proc.get_int_list(%w(1+0 3-1 3))
|
|
393
|
+
p proc.get_int_list(%w(a 2 3))
|
|
394
|
+
end
|
|
395
|
+
end
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
puts "Ha!"
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
|
|
2
|
+
# GCD. We assume positive numbers
|
|
3
|
+
def gcd(a, b)
|
|
4
|
+
# Make: a <= b
|
|
5
|
+
if a > b
|
|
6
|
+
a, b = [b, a]
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
return nil if a <= 0
|
|
10
|
+
addline
|
|
11
|
+
|
|
12
|
+
if a == 1 or b-a == 0
|
|
13
|
+
return a
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
a, b = ARGV[0..1].map {|arg| arg.to_i}
|
|
18
|
+
puts "The GCD of %d and %d is %d" % [a, b, gcd(a, b)]
|
data/test/example/gcd.rb
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
# GCD. We assume positive numbers
|
|
4
|
+
def gcd(a, b)
|
|
5
|
+
# Make: a <= b
|
|
6
|
+
if a > b
|
|
7
|
+
a, b = [b, a]
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
return nil if a <= 0
|
|
11
|
+
|
|
12
|
+
if a == 1 or b-a == 0
|
|
13
|
+
return a
|
|
14
|
+
end
|
|
15
|
+
return gcd(b-a, a)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
a, b = ARGV[0..1].map {|arg| arg.to_i}
|
|
19
|
+
puts "The GCD of %d and %d is %d" % [a, b, gcd(a, b)]
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
require 'thread_frame'
|
|
3
|
+
tf = RubyVM::ThreadFrame.current
|
|
4
|
+
iseq = tf.iseq
|
|
5
|
+
p iseq.child_iseqs
|
|
6
|
+
puts iseq.disassemble
|
|
7
|
+
|
|
8
|
+
# GCD. We assume positive numbers
|
|
9
|
+
def gcd(a, b)
|
|
10
|
+
# Make: a <= b
|
|
11
|
+
if a > b
|
|
12
|
+
a, b = [b, a]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
return nil if a <= 0
|
|
16
|
+
|
|
17
|
+
if a == 1 or b-a == 0
|
|
18
|
+
return a
|
|
19
|
+
end
|
|
20
|
+
return gcd(b-a, a)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
a, b = ARGV[0..1].map {|arg| arg.to_i}
|
|
24
|
+
puts "The GCD of %d and %d is %d" % [a, b, gcd(a, b)]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Nothing here. Move along.
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
require 'thread_frame'
|
|
2
|
+
require 'trace'
|
|
3
|
+
require_relative '../../lib/trepanning'
|
|
4
|
+
require_relative '../../io/string_array'
|
|
5
|
+
|
|
6
|
+
module FnTestHelper
|
|
7
|
+
include Trace
|
|
8
|
+
|
|
9
|
+
# Synchronous events without C frames or instructions
|
|
10
|
+
TEST_STEP_EVENT_MASK = LINE_EVENT_MASK | CLASS_EVENT_MASK | CALL_EVENT_MASK |
|
|
11
|
+
RETURN_EVENT_MASK
|
|
12
|
+
|
|
13
|
+
# Common setup to create a debugger with String Array I/O attached
|
|
14
|
+
def strarray_setup(debugger_cmds, insn_stepping=false)
|
|
15
|
+
stringin = Trepan::StringArrayInput.open(debugger_cmds)
|
|
16
|
+
stringout = Trepan::StringArrayOutput.open
|
|
17
|
+
d_opts = {:input => stringin, :output => stringout,
|
|
18
|
+
:nx => true}
|
|
19
|
+
d_opts[:core_opts] = {:step_events => TEST_STEP_EVENT_MASK}
|
|
20
|
+
d_opts[:core_opts][:step_events] ||= INSN_EVENT_MASK if insn_stepping
|
|
21
|
+
d = Trepan.new(d_opts)
|
|
22
|
+
|
|
23
|
+
# Remove vm and switch from unmaskable events to increase predictability
|
|
24
|
+
# of test results
|
|
25
|
+
d.core.instance_variable_set('@unmaskable_events', %w(brkpt raise))
|
|
26
|
+
|
|
27
|
+
d.settings[:basename] = true
|
|
28
|
+
d.settings[:different] = false
|
|
29
|
+
d.settings[:autoeval] = false
|
|
30
|
+
return d
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
unless defined?(TREPAN_PROMPT)
|
|
34
|
+
TREPAN_PROMPT = /^\(trepan\): /
|
|
35
|
+
TREPAN_LOC = /.. \(.+:\d+\)/
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Return the caller's line number
|
|
39
|
+
def get_lineno
|
|
40
|
+
RubyVM::ThreadFrame.current.prev.source_location[0]
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def compare_output(right, d, debugger_cmds)
|
|
44
|
+
# require_relative '../../lib/trepanning'
|
|
45
|
+
# Trepan.debug(:set_restart => true)
|
|
46
|
+
got = filter_line_cmd(d.intf[-1].output.output)
|
|
47
|
+
if got != right
|
|
48
|
+
got.each_with_index do |got_line, i|
|
|
49
|
+
if i < right.size and got_line != right[i]
|
|
50
|
+
# dbgr.debugger
|
|
51
|
+
puts "! #{got_line}"
|
|
52
|
+
else
|
|
53
|
+
puts " #{got_line}"
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
puts '-' * 10
|
|
57
|
+
right.each_with_index do |right_line, i|
|
|
58
|
+
if i < got.size and got[i] != right_line
|
|
59
|
+
# dbgr.debugger
|
|
60
|
+
puts "! #{right_line}"
|
|
61
|
+
else
|
|
62
|
+
puts " #{right_line}"
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
assert_equal(right, got, caller[0])
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Return output with source lines prompt and command removed
|
|
70
|
+
def filter_line_cmd(a, show_prompt=false)
|
|
71
|
+
# Remove debugger prompt
|
|
72
|
+
a = a.map do |s|
|
|
73
|
+
s =~ TREPAN_PROMPT ? nil : s
|
|
74
|
+
end.compact unless show_prompt
|
|
75
|
+
|
|
76
|
+
# Remove debugger location lines.
|
|
77
|
+
# For example:
|
|
78
|
+
# -- (/src/external-vcs/trepan/tmp/gcd.rb:4)
|
|
79
|
+
# becomes:
|
|
80
|
+
# --
|
|
81
|
+
a2 = a.map do |s|
|
|
82
|
+
s =~ TREPAN_LOC ? s.gsub(/\(.+:\d+\)\n/, '').chomp : s.chomp
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Remove VM offset locations.
|
|
86
|
+
# For example:
|
|
87
|
+
# VM offset 2 of instruction sequence "block in compare_output".
|
|
88
|
+
# becomes
|
|
89
|
+
# VM offset 55 of instruction sequence "block in compare_output".
|
|
90
|
+
a3 = a2.map do |s|
|
|
91
|
+
s.gsub(/VM offset \d+/, 'VM offset 55')
|
|
92
|
+
end
|
|
93
|
+
return a3
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# Demo it
|
|
99
|
+
if __FILE__ == $0
|
|
100
|
+
include FnTestHelper
|
|
101
|
+
strarray_setup(%w(eh bee see))
|
|
102
|
+
puts get_lineno()
|
|
103
|
+
p '-- (/src/external-vcs/trepan/tmp/gcd.rb:4)' =~ TREPAN_LOC
|
|
104
|
+
p '(trepan): exit' =~ TREPAN_PROMPT
|
|
105
|
+
output='
|
|
106
|
+
-- (/src/external-vcs/trepan/tmp/gcd.rb:4)
|
|
107
|
+
(trepan): s
|
|
108
|
+
-- (/src/external-vcs/trepan/tmp/gcd.rb:18)
|
|
109
|
+
(trepan): s
|
|
110
|
+
-- (/src/external-vcs/trepan/tmp/gcd.rb:19)
|
|
111
|
+
(trepan): s
|
|
112
|
+
.. (/src/external-vcs/trepan/tmp/gcd.rb:0)
|
|
113
|
+
(trepan): s
|
|
114
|
+
-> (/src/external-vcs/trepan/tmp/gcd.rb:4)
|
|
115
|
+
'.split(/\n/)
|
|
116
|
+
puts filter_line_cmd(output)
|
|
117
|
+
puts '-' * 10
|
|
118
|
+
puts filter_line_cmd(output, true)
|
|
119
|
+
end
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
require 'test/unit'
|
|
3
|
+
require 'trace'
|
|
4
|
+
require_relative 'fn_helper'
|
|
5
|
+
require_relative '../../app/breakpoint'
|
|
6
|
+
|
|
7
|
+
class TestBreak < Test::Unit::TestCase
|
|
8
|
+
|
|
9
|
+
include FnTestHelper
|
|
10
|
+
|
|
11
|
+
def setup
|
|
12
|
+
Trepanning::Breakpoint::reset
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def test_break_same_level
|
|
16
|
+
|
|
17
|
+
# See that we can stop at a breakpoint
|
|
18
|
+
cmds = ['set basename on',
|
|
19
|
+
'break ' + (__LINE__ + 7).to_s,
|
|
20
|
+
'continue']
|
|
21
|
+
d = strarray_setup(cmds)
|
|
22
|
+
d.start
|
|
23
|
+
########### b1 ###############
|
|
24
|
+
x = 5
|
|
25
|
+
y = 6
|
|
26
|
+
z = 7
|
|
27
|
+
##############################
|
|
28
|
+
d.stop
|
|
29
|
+
out = ['-- ',
|
|
30
|
+
'x = 5',
|
|
31
|
+
'basename is on.',
|
|
32
|
+
"Breakpoint 1 set at line 26 in file test-break.rb,\n" +
|
|
33
|
+
"\tVM offset 55 of instruction sequence \"test_break_same_level\".",
|
|
34
|
+
'xx ',
|
|
35
|
+
'z = 7']
|
|
36
|
+
compare_output(out, d, cmds)
|
|
37
|
+
|
|
38
|
+
# Try a disabling the breakpoint
|
|
39
|
+
cmds = ['set basename on',
|
|
40
|
+
'break ' + (__LINE__ + 8).to_s,
|
|
41
|
+
'break ' + (__LINE__ + 8).to_s,
|
|
42
|
+
'disable 1',
|
|
43
|
+
'continue']
|
|
44
|
+
d = strarray_setup(cmds)
|
|
45
|
+
d.start
|
|
46
|
+
########### b2 ###############
|
|
47
|
+
x = 7
|
|
48
|
+
y = 8
|
|
49
|
+
z = 8+1
|
|
50
|
+
##############################
|
|
51
|
+
d.stop
|
|
52
|
+
out = ['-- ',
|
|
53
|
+
'x = 7',
|
|
54
|
+
'basename is on.',
|
|
55
|
+
"Breakpoint 1 set at line 48 in file test-break.rb,\n" +
|
|
56
|
+
"\tVM offset 55 of instruction sequence \"test_break_same_level\".",
|
|
57
|
+
"Breakpoint 2 set at line 49 in file test-break.rb,\n" +
|
|
58
|
+
"\tVM offset 55 of instruction sequence \"test_break_same_level\".",
|
|
59
|
+
"Breakpoint 1 disabled.",
|
|
60
|
+
'xx ',
|
|
61
|
+
'z = 8+1']
|
|
62
|
+
compare_output(out, d, cmds)
|
|
63
|
+
|
|
64
|
+
# Stepping after a breakpoint should not stay at same location.
|
|
65
|
+
cmds = ['set basename on',
|
|
66
|
+
'continue ' + (__LINE__ + 8).to_s,
|
|
67
|
+
'continue']
|
|
68
|
+
dbg = strarray_setup(cmds)
|
|
69
|
+
dbg.start
|
|
70
|
+
########### b3 ###############
|
|
71
|
+
a = 1
|
|
72
|
+
b = 2
|
|
73
|
+
c = 3
|
|
74
|
+
d = 4
|
|
75
|
+
e = 5
|
|
76
|
+
##############################
|
|
77
|
+
dbg.stop
|
|
78
|
+
out = ['-- ',
|
|
79
|
+
'a = 1',
|
|
80
|
+
'basename is on.',
|
|
81
|
+
'xx ',
|
|
82
|
+
'd = 4' ]
|
|
83
|
+
compare_output(out, dbg, cmds)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
end
|
|
87
|
+
|