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,126 @@
|
|
|
1
|
+
# Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
|
|
2
|
+
require 'linecache'
|
|
3
|
+
require_relative 'msg'
|
|
4
|
+
require_relative '../app/frame'
|
|
5
|
+
class Trepan
|
|
6
|
+
class CmdProcessor
|
|
7
|
+
attr_accessor :reload_on_change
|
|
8
|
+
include Frame
|
|
9
|
+
|
|
10
|
+
def location_initialize
|
|
11
|
+
@reload_on_change = nil
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def resolve_file_with_dir(path_suffix)
|
|
15
|
+
settings[:directory].split(/:/).each do |dir|
|
|
16
|
+
dir =
|
|
17
|
+
if '$cwd' == dir
|
|
18
|
+
Dir.pwd
|
|
19
|
+
elsif '$cdir' == dir
|
|
20
|
+
@dbgr.initial_dir
|
|
21
|
+
else
|
|
22
|
+
dir
|
|
23
|
+
end
|
|
24
|
+
next unless dir && File.directory?(dir)
|
|
25
|
+
try_file = File.join(dir, path_suffix)
|
|
26
|
+
return try_file if File.readable?(try_file)
|
|
27
|
+
end
|
|
28
|
+
nil
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Get line +line_number+ from file named +filename+. Return "\n"
|
|
32
|
+
# there was a problem. Leading blanks are stripped off.
|
|
33
|
+
def line_at(filename, line_number) # :nodoc:
|
|
34
|
+
line = LineCache::getline(filename, line_number, @reload_on_change)
|
|
35
|
+
unless line
|
|
36
|
+
# Try using search directories (set with command "directory")
|
|
37
|
+
if filename[0..0] != File::SEPARATOR
|
|
38
|
+
try_filename = resolve_file_with_dir(filename)
|
|
39
|
+
if try_filename &&
|
|
40
|
+
line = LineCache::getline(try_filename, line_number,
|
|
41
|
+
@reload_on_change)
|
|
42
|
+
LineCache::remap_file(filename, try_filename)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
return "\n" unless line
|
|
47
|
+
return line.lstrip.chomp
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def loc_and_text(loc, frame, line_no, source_container)
|
|
51
|
+
if source_container[0] != 'file'
|
|
52
|
+
via = loc
|
|
53
|
+
while source_container[0] != 'file' && frame.prev do
|
|
54
|
+
frame = frame.prev
|
|
55
|
+
source_container = frame_container(frame, false)
|
|
56
|
+
end
|
|
57
|
+
if source_container[0] == 'file'
|
|
58
|
+
line_no = frame.source_location[0]
|
|
59
|
+
filename = source_container[1]
|
|
60
|
+
loc += " via #{canonic_file(filename)}:#{line_no}"
|
|
61
|
+
text = line_at(filename, line_no)
|
|
62
|
+
end
|
|
63
|
+
else
|
|
64
|
+
container = source_container[1]
|
|
65
|
+
map_file, map_line = LineCache::map_file_line(container, line_no)
|
|
66
|
+
if [container, line_no] != [map_file, map_line]
|
|
67
|
+
loc += " remapped #{canonic_file(map_file)}:#{map_line}"
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
text = line_at(container, line_no)
|
|
71
|
+
end
|
|
72
|
+
[loc, line_no, text]
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def print_location
|
|
76
|
+
if %w(c-call call).member?(@event)
|
|
77
|
+
# FIXME: Fix Ruby so we don't need this workaround?
|
|
78
|
+
# See also where.rb
|
|
79
|
+
opts = {}
|
|
80
|
+
opts[:class] = @core.hook_arg if
|
|
81
|
+
'CFUNC' == @frame.type && @core.hook_arg && 0 == @frame_index
|
|
82
|
+
msg format_stack_call(@frame, opts)
|
|
83
|
+
elsif 'raise' == @event
|
|
84
|
+
msg @core.hook_arg.inspect if @core.hook_arg # Exception object
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
text = nil
|
|
88
|
+
source_container = frame_container(@frame, false)
|
|
89
|
+
ev = if @event.nil? || 0 != @frame_index
|
|
90
|
+
' '
|
|
91
|
+
else
|
|
92
|
+
(EVENT2ICON[@event] || @event)
|
|
93
|
+
end
|
|
94
|
+
@line_no = frame_line
|
|
95
|
+
|
|
96
|
+
loc = source_location_info(source_container, @line_no, @frame)
|
|
97
|
+
loc, @line_no, text = loc_and_text(loc, @frame, @line_no,
|
|
98
|
+
source_container)
|
|
99
|
+
msg "#{ev} (#{loc})"
|
|
100
|
+
|
|
101
|
+
if %w(return c-return).member?(@event)
|
|
102
|
+
retval = Trepan::Frame.value_returned(@frame, @event)
|
|
103
|
+
msg 'R=> %s' % retval.inspect
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
if text && !text.strip.empty?
|
|
107
|
+
msg text
|
|
108
|
+
@line_no -= 1
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def source_location_info(source_container, line_no, frame)
|
|
113
|
+
filename = source_container[1]
|
|
114
|
+
canonic_filename =
|
|
115
|
+
if (0 == filename.index('(eval')) && frame.prev &&
|
|
116
|
+
(eval_str = Trepan::Frame.eval_string(frame.prev))
|
|
117
|
+
'eval ' + safe_repr(eval_str, 15)
|
|
118
|
+
else
|
|
119
|
+
canonic_file(filename)
|
|
120
|
+
end
|
|
121
|
+
loc = "#{canonic_filename}:#{line_no}"
|
|
122
|
+
return loc
|
|
123
|
+
end # source_location_info
|
|
124
|
+
|
|
125
|
+
end
|
|
126
|
+
end
|
data/processor/main.rb
ADDED
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
# Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
|
|
2
|
+
# The main "driver" class for a command processor. Other parts of the
|
|
3
|
+
# command class and debugger command objects are pulled in from here.
|
|
4
|
+
|
|
5
|
+
require 'linecache'
|
|
6
|
+
require 'set'
|
|
7
|
+
require 'pathname' # For cleanpath
|
|
8
|
+
|
|
9
|
+
%w(default breakpoint display eventbuf eval load_cmds location frame hook msg
|
|
10
|
+
running validate).each do
|
|
11
|
+
|mod_str|
|
|
12
|
+
require_relative mod_str
|
|
13
|
+
end
|
|
14
|
+
require_relative '../app/brkptmgr'
|
|
15
|
+
|
|
16
|
+
class Trepan
|
|
17
|
+
class CmdProcessor
|
|
18
|
+
|
|
19
|
+
# SEE ALSO attr's in require_relative's of loop above.
|
|
20
|
+
|
|
21
|
+
attr_reader :cmd_argstr # Current command args, a String.
|
|
22
|
+
# This is current_command with the command
|
|
23
|
+
# name removed from the beginning.
|
|
24
|
+
attr_reader :cmd_name # command name before alias or macro resolution
|
|
25
|
+
attr_reader :core # Trepan core object
|
|
26
|
+
attr_reader :current_command # Current command getting run, a String.
|
|
27
|
+
attr_reader :dbgr # Trepan instance (via
|
|
28
|
+
# Trepan::Core instance)
|
|
29
|
+
attr_accessor :debug_nest # Number of nested debugs. Used in showing
|
|
30
|
+
# prompt.
|
|
31
|
+
attr_accessor :different_pos # Same type as settings[:different]
|
|
32
|
+
# this is the temporary value for the
|
|
33
|
+
# next stop while settings is the default
|
|
34
|
+
# value to use.
|
|
35
|
+
attr_accessor :event # Stop event. Same as @core.event
|
|
36
|
+
attr_accessor :leave_cmd_loop # Commands set this to signal to leave
|
|
37
|
+
# the command loop (which often continues to
|
|
38
|
+
# run the debugged program).
|
|
39
|
+
attr_accessor :line_no # Last line shown in "list" command
|
|
40
|
+
attr_accessor :next_level # Fixnum. frame.stack_size has to
|
|
41
|
+
# be <= than this. If next'ing,
|
|
42
|
+
# this will be > 0.
|
|
43
|
+
attr_accessor :next_thread # Thread. If non-nil then in
|
|
44
|
+
# stepping the thread has to be
|
|
45
|
+
# this thread.
|
|
46
|
+
attr_accessor :pass_exception # Pass an exception back
|
|
47
|
+
attr_accessor :prompt # String print before requesting input
|
|
48
|
+
attr_reader :settings # Hash[:symbol] of command
|
|
49
|
+
# processor settings
|
|
50
|
+
|
|
51
|
+
# The following are used in to force stopping at a different line
|
|
52
|
+
# number. FIXME: could generalize to a position object.
|
|
53
|
+
attr_accessor :last_pos # Last position. 6-Tuple: of
|
|
54
|
+
# [location, container, stack_size,
|
|
55
|
+
# current_thread, pc_offset]
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
unless defined?(EVENT2ICON)
|
|
59
|
+
# We use event icons in printing locations.
|
|
60
|
+
EVENT2ICON = {
|
|
61
|
+
'brkpt' => 'xx',
|
|
62
|
+
'c-call' => 'C>',
|
|
63
|
+
'c-return' => '<C',
|
|
64
|
+
'call' => '->',
|
|
65
|
+
'class' => '::',
|
|
66
|
+
'coverage' => '[]',
|
|
67
|
+
'debugger-call' => ':o',
|
|
68
|
+
'end' => '-|',
|
|
69
|
+
'line' => '--',
|
|
70
|
+
'raise' => '!!',
|
|
71
|
+
'return' => '<-',
|
|
72
|
+
'switch' => 'sw',
|
|
73
|
+
'trace-var' => '$V',
|
|
74
|
+
'unknown' => '?!',
|
|
75
|
+
'vm' => 'VM',
|
|
76
|
+
'vm-insn' => '..',
|
|
77
|
+
}
|
|
78
|
+
# These events are important enough event that we always want to
|
|
79
|
+
# stop on them.
|
|
80
|
+
UNMASKABLE_EVENTS = Set.new(['end', 'raise', 'unknown'])
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def initialize(core, settings={})
|
|
84
|
+
@core = core
|
|
85
|
+
@debug_nest = 1
|
|
86
|
+
@dbgr = core.dbgr
|
|
87
|
+
@hidelevels = {}
|
|
88
|
+
@last_command = nil
|
|
89
|
+
@last_pos = [nil, nil, nil, nil, nil, nil]
|
|
90
|
+
@next_level = 32000
|
|
91
|
+
@next_thread = nil
|
|
92
|
+
|
|
93
|
+
start_cmds = settings.delete(:start_cmds)
|
|
94
|
+
start_file = settings.delete(:start_file)
|
|
95
|
+
|
|
96
|
+
@settings = settings.merge(DEFAULT_SETTINGS)
|
|
97
|
+
@different_pos = @settings[:different]
|
|
98
|
+
|
|
99
|
+
# FIXME: Rework using a general "set substitute file" command and
|
|
100
|
+
# a global default profile which gets read.
|
|
101
|
+
file = File.expand_path(File.join(File.dirname(__FILE__),
|
|
102
|
+
%w(.. data prelude.rb)))
|
|
103
|
+
LineCache::cache(file)
|
|
104
|
+
LineCache::remap_file('<internal:prelude>', file)
|
|
105
|
+
file = File.expand_path(File.join(File.dirname(__FILE__),
|
|
106
|
+
%w(.. data custom_require.rb)))
|
|
107
|
+
LineCache::cache(file)
|
|
108
|
+
LineCache::remap_file('<internal:lib/rubygems/custom_require>',
|
|
109
|
+
file)
|
|
110
|
+
|
|
111
|
+
# Start with empty thread and frame info.
|
|
112
|
+
frame_teardown
|
|
113
|
+
|
|
114
|
+
# Run initialization routines for each of the "submodule"s.
|
|
115
|
+
# load_cmds has to come first.
|
|
116
|
+
%w(load_cmds breakpoint display eventbuf frame running validate
|
|
117
|
+
).each do |submod|
|
|
118
|
+
self.send("#{submod}_initialize")
|
|
119
|
+
end
|
|
120
|
+
hook_initialize(commands)
|
|
121
|
+
|
|
122
|
+
# FIXME: run start file and start commands.
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def canonic_container(container)
|
|
126
|
+
[container[0], canonic_file(container[1])]
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def canonic_file(filename)
|
|
130
|
+
# For now we want resolved filenames
|
|
131
|
+
@settings[:basename] ? File.basename(filename) :
|
|
132
|
+
# Cache this?
|
|
133
|
+
Pathname.new(filename).cleanpath.to_s
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def compute_prompt
|
|
137
|
+
thread_str =
|
|
138
|
+
if 1 == Thread.list.size
|
|
139
|
+
''
|
|
140
|
+
elsif Thread.current == Thread.main
|
|
141
|
+
'@main'
|
|
142
|
+
else
|
|
143
|
+
"@#{Thread.current.object_id}"
|
|
144
|
+
end
|
|
145
|
+
"%s#{settings[:prompt]}%s%s: " %
|
|
146
|
+
['(' * @debug_nest, thread_str, ')' * @debug_nest]
|
|
147
|
+
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
# Check that we meed the criteria that cmd specifies it needs
|
|
151
|
+
def ok_for_running(cmd, name, nargs)
|
|
152
|
+
# TODO check execution_set against execution status.
|
|
153
|
+
# Check we have frame is not null
|
|
154
|
+
min_args = cmd.class.const_get(:MIN_ARGS)
|
|
155
|
+
if nargs < min_args
|
|
156
|
+
errmsg(("Command '%s' needs at least %d argument(s); " +
|
|
157
|
+
"got %d.") % [name, min_args, nargs])
|
|
158
|
+
return false
|
|
159
|
+
end
|
|
160
|
+
max_args = cmd.class.const_get(:MAX_ARGS)
|
|
161
|
+
if max_args and nargs > max_args
|
|
162
|
+
errmsg(("Command '%s' needs at most %d argument(s); " +
|
|
163
|
+
"got %d.") % [name, max_args, nargs])
|
|
164
|
+
return false
|
|
165
|
+
end
|
|
166
|
+
# if cmd.class.const_get(:NEED_RUNNING) && !...
|
|
167
|
+
# errmsg "Command '%s' requires a running program." % name
|
|
168
|
+
# return false
|
|
169
|
+
# end
|
|
170
|
+
|
|
171
|
+
if cmd.class.const_get(:NEED_STACK) && !@frame
|
|
172
|
+
errmsg "Command '%s' requires a running stack frame." % name
|
|
173
|
+
return false
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
return true
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
# Run one debugger command. True is returned if we want to quit.
|
|
180
|
+
def process_command_and_quit?()
|
|
181
|
+
intf = @dbgr.intf
|
|
182
|
+
return true if intf[-1].input.eof? && intf.size == 1
|
|
183
|
+
while !intf[-1].input.eof? || intf.size > 1
|
|
184
|
+
begin
|
|
185
|
+
@current_command = read_command().strip
|
|
186
|
+
if @current_command.empty?
|
|
187
|
+
if @last_command && intf[-1].interactive?
|
|
188
|
+
@current_command = @last_command
|
|
189
|
+
else
|
|
190
|
+
next
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
next if @current_command[0..0] == '#' # Skip comment lines
|
|
194
|
+
break
|
|
195
|
+
rescue IOError, Errno::EPIPE
|
|
196
|
+
if @dbgr.intf.size > 1
|
|
197
|
+
@dbgr.intf.pop
|
|
198
|
+
@last_command = nil
|
|
199
|
+
print_location
|
|
200
|
+
else
|
|
201
|
+
msg "EOF - Leaving"
|
|
202
|
+
## FIXME: think of something better.
|
|
203
|
+
quit('quit!')
|
|
204
|
+
return true
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
run_command(@current_command)
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
# This is the main entry point.
|
|
212
|
+
def process_commands(frame)
|
|
213
|
+
|
|
214
|
+
frame_setup(frame)
|
|
215
|
+
@event = @core.event
|
|
216
|
+
|
|
217
|
+
@unconditional_prehooks.run
|
|
218
|
+
if breakpoint?
|
|
219
|
+
@last_pos = [@frame.source_container, frame_line,
|
|
220
|
+
@stack_size, @current_thread, @event,
|
|
221
|
+
@frame.pc_offset]
|
|
222
|
+
else
|
|
223
|
+
return if stepping_skip? || @stack_size <= @hide_level
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
@prompt = compute_prompt
|
|
227
|
+
|
|
228
|
+
@leave_cmd_loop = false
|
|
229
|
+
print_location unless @settings[:traceprint]
|
|
230
|
+
if 'trace-var' == @event
|
|
231
|
+
msg "Note: we are stopped *after* the above location."
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
@eventbuf.add_mark if @settings[:tracebuffer]
|
|
235
|
+
|
|
236
|
+
@cmdloop_prehooks.run
|
|
237
|
+
while not @leave_cmd_loop do
|
|
238
|
+
begin
|
|
239
|
+
break if process_command_and_quit?()
|
|
240
|
+
rescue SystemExit
|
|
241
|
+
@dbgr.stop
|
|
242
|
+
raise
|
|
243
|
+
rescue Exception => exc
|
|
244
|
+
msg("Internal debugger error: #{exc.inspect}")
|
|
245
|
+
exception_dump(exc, @settings[:debugexcept], $!.backtrace)
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
@cmdloop_posthooks.run
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
# Run current_command, a String. @last_command is set after the
|
|
252
|
+
# command is run if it is a command.
|
|
253
|
+
def run_command(current_command)
|
|
254
|
+
eval_command =
|
|
255
|
+
if current_command[0..0] == '!'
|
|
256
|
+
current_command[0] = ''
|
|
257
|
+
else
|
|
258
|
+
false
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
unless eval_command
|
|
262
|
+
# Expand macros. FIXME: put in a procedure
|
|
263
|
+
args = current_command.split
|
|
264
|
+
while true do
|
|
265
|
+
macro_cmd_name = args[0]
|
|
266
|
+
return false if args.size == 0
|
|
267
|
+
break unless @macros.member?(macro_cmd_name)
|
|
268
|
+
current_command = @macros[macro_cmd_name].call(*args[1..-1])
|
|
269
|
+
msg current_command if settings[:debugmacro]
|
|
270
|
+
if current_command.is_a?(Array) &&
|
|
271
|
+
current_command.any {|val| !val.is_a?(String)}
|
|
272
|
+
args = current_command
|
|
273
|
+
elsif current_command.is_a?(String)
|
|
274
|
+
args = current_command.split
|
|
275
|
+
else
|
|
276
|
+
errmsg("macro #{macro_cmd_name} should return an Array " +
|
|
277
|
+
"of Strings or a String. Got #{current_command.inspect}")
|
|
278
|
+
return false
|
|
279
|
+
end
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
@cmd_name = args[0]
|
|
283
|
+
run_cmd_name =
|
|
284
|
+
if @aliases.member?(@cmd_name)
|
|
285
|
+
@aliases[@cmd_name]
|
|
286
|
+
else
|
|
287
|
+
@cmd_name
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
if @commands.member?(run_cmd_name)
|
|
291
|
+
cmd = @commands[run_cmd_name]
|
|
292
|
+
if ok_for_running(cmd, run_cmd_name, args.size-1)
|
|
293
|
+
@cmd_argstr = current_command[@cmd_name.size..-1].lstrip
|
|
294
|
+
cmd.run(args)
|
|
295
|
+
@last_command = current_command
|
|
296
|
+
end
|
|
297
|
+
return false
|
|
298
|
+
end
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
# Eval anything that's not a command or has been
|
|
302
|
+
# requested to be eval'd
|
|
303
|
+
if settings[:autoeval] || eval_command
|
|
304
|
+
## eval_code(current_command, @settings[:maxstring])
|
|
305
|
+
msg 'D=> ' + debug_eval(current_command).inspect
|
|
306
|
+
else
|
|
307
|
+
undefined_command(cmd_name)
|
|
308
|
+
end
|
|
309
|
+
return false
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
# Error message when a command doesn't exist
|
|
313
|
+
def undefined_command(cmd_name)
|
|
314
|
+
errmsg('Undefined command: "%s". Try "help".' % cmd_name)
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
# FIXME: Allow access to both Trepan::CmdProcessor and Trepan
|
|
318
|
+
# for index [] and []=.
|
|
319
|
+
# If there is a Trepan::CmdProcessor setting that would take precidence.
|
|
320
|
+
# def settings
|
|
321
|
+
# @settings.merge(@dbgr.settings) # wrong because this doesn't allow []=
|
|
322
|
+
# end
|
|
323
|
+
end
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
if __FILE__ == $0
|
|
327
|
+
$0 = 'foo' # So we don't get here again
|
|
328
|
+
require_relative '../lib/trepanning'
|
|
329
|
+
dbg = Trepan.new(:nx => true)
|
|
330
|
+
dbg.core.processor.msg('I am main')
|
|
331
|
+
cmdproc = dbg.core.processor
|
|
332
|
+
cmdproc.errmsg('Whoa!')
|
|
333
|
+
cmds = cmdproc.commands
|
|
334
|
+
p cmdproc.aliases
|
|
335
|
+
cmd_name, cmd_obj = cmds.first
|
|
336
|
+
puts cmd_obj.class.const_get(:HELP)
|
|
337
|
+
puts cmd_obj.class.const_get(:SHORT_HELP)
|
|
338
|
+
|
|
339
|
+
puts cmdproc.compute_prompt
|
|
340
|
+
Thread.new{ puts cmdproc.compute_prompt }.join
|
|
341
|
+
|
|
342
|
+
th = Thread.new{ Thread.pass; x = 1 }
|
|
343
|
+
puts cmdproc.compute_prompt
|
|
344
|
+
th.join
|
|
345
|
+
cmdproc.debug_nest += 1
|
|
346
|
+
puts cmdproc.compute_prompt
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
if ARGV.size > 0
|
|
350
|
+
dbg.core.processor.msg('Enter "q" to quit')
|
|
351
|
+
dbg.proc_process_commands
|
|
352
|
+
else
|
|
353
|
+
$input = []
|
|
354
|
+
class << dbg.core.processor
|
|
355
|
+
def read_command
|
|
356
|
+
$input.shift
|
|
357
|
+
end
|
|
358
|
+
end
|
|
359
|
+
$input = ['1+2']
|
|
360
|
+
dbg.core.processor.process_command_and_quit?
|
|
361
|
+
$input = ['!s = 5'] # ! means eval line
|
|
362
|
+
dbg.core.processor.process_command_and_quit?
|
|
363
|
+
end
|
|
364
|
+
end
|
data/processor/mock.rb
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
|
|
2
|
+
# Mock setup for commands.
|
|
3
|
+
require_relative 'main'
|
|
4
|
+
require_relative '../app/core'
|
|
5
|
+
require_relative '../app/default'
|
|
6
|
+
require_relative '../interface/user' # user interface (includes I/O)
|
|
7
|
+
|
|
8
|
+
SCRIPT_ISEQS__ = {} unless
|
|
9
|
+
defined?(SCRIPT_ISEQS__) && SCRIPT_ISEQS__.is_a?(Hash)
|
|
10
|
+
ISEQS__ = {} unless
|
|
11
|
+
defined?(ISEQS__) && ISEQS__.is_a?(Hash)
|
|
12
|
+
|
|
13
|
+
module MockDebugger
|
|
14
|
+
class MockDebugger
|
|
15
|
+
attr_accessor :trace_filter # Procs/Methods we ignore.
|
|
16
|
+
|
|
17
|
+
attr_accessor :core # access to Debugger::Core instance
|
|
18
|
+
attr_accessor :intf # The way the outside world interfaces with us.
|
|
19
|
+
attr_reader :initial_dir # String. Current directory when program
|
|
20
|
+
# started. Used in restart program.
|
|
21
|
+
attr_accessor :restart_argv # How to restart us, empty or nil.
|
|
22
|
+
# Note restart[0] is typically $0.
|
|
23
|
+
attr_reader :settings # Hash[:symbol] of things you can configure
|
|
24
|
+
|
|
25
|
+
def initialize(settings={})
|
|
26
|
+
@before_cmdloop_hooks = []
|
|
27
|
+
@settings = Trepanning::DEFAULT_SETTINGS.merge(settings)
|
|
28
|
+
@intf = [Trepan::UserInterface.new]
|
|
29
|
+
@core = Trepan::Core.new(self)
|
|
30
|
+
@trace_filter = []
|
|
31
|
+
|
|
32
|
+
# Don't allow user commands in mocks.
|
|
33
|
+
@core.processor.settings[:user_cmd_dir] = nil
|
|
34
|
+
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Common Mock debugger setup
|
|
40
|
+
def setup(name, show_constants=true)
|
|
41
|
+
if ARGV.size > 0 && ARGV[0] == 'debug'
|
|
42
|
+
require_relative '../lib/trepanning'
|
|
43
|
+
dbgr = Trepan.new
|
|
44
|
+
dbgr.debugger
|
|
45
|
+
else
|
|
46
|
+
dbgr = MockDebugger.new
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
cmds = dbgr.core.processor.commands
|
|
50
|
+
cmd = cmds[name]
|
|
51
|
+
cmd.proc.frame_setup(RubyVM::ThreadFrame::current.prev)
|
|
52
|
+
show_special_class_constants(cmd) if show_constants
|
|
53
|
+
|
|
54
|
+
def cmd.msg(message)
|
|
55
|
+
puts message
|
|
56
|
+
end
|
|
57
|
+
def cmd.msg_nocr(message)
|
|
58
|
+
print message
|
|
59
|
+
end
|
|
60
|
+
def cmd.errmsg(message)
|
|
61
|
+
puts "Error: #{message}"
|
|
62
|
+
end
|
|
63
|
+
def cmd.confirm(prompt, default)
|
|
64
|
+
true
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
return dbgr, cmd
|
|
68
|
+
end
|
|
69
|
+
module_function :setup
|
|
70
|
+
|
|
71
|
+
def show_special_class_constants(cmd)
|
|
72
|
+
puts 'ALIASES: %s' % [cmd.class.const_get('ALIASES').inspect] if
|
|
73
|
+
cmd.class.constants.member?(:ALIASES)
|
|
74
|
+
%w(CATEGORY HELP MIN_ARGS MAX_ARGS
|
|
75
|
+
NAME NEED_STACK SHORT_HELP).each do |name|
|
|
76
|
+
puts '%s: %s' % [name, cmd.class.const_get(name).inspect]
|
|
77
|
+
end
|
|
78
|
+
puts '- - -'
|
|
79
|
+
end
|
|
80
|
+
module_function :show_special_class_constants
|
|
81
|
+
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# To get Trepan::CmdProcessor defined and with the
|
|
85
|
+
# with the correct initialize parameters.
|
|
86
|
+
class Trepan
|
|
87
|
+
class << CmdProcessor
|
|
88
|
+
def initialize(core, settings={})
|
|
89
|
+
@core = core
|
|
90
|
+
@settings = settings
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
if __FILE__ == $0
|
|
96
|
+
dbgr = MockDebugger::MockDebugger.new
|
|
97
|
+
p dbgr.settings
|
|
98
|
+
puts '=' * 10
|
|
99
|
+
p dbgr.core.processor.settings
|
|
100
|
+
end
|
data/processor/msg.rb
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
|
|
2
|
+
# I/O related command processor methods
|
|
3
|
+
require_relative '../app/util'
|
|
4
|
+
class Trepan
|
|
5
|
+
class CmdProcessor
|
|
6
|
+
def errmsg(message)
|
|
7
|
+
@dbgr.intf[-1].errmsg(safe_rep(message))
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def msg(message)
|
|
11
|
+
@dbgr.intf[-1].msg(safe_rep(message))
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def msg_nocr(message)
|
|
15
|
+
@dbgr.intf[-1].msg_nocr(safe_rep(message))
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def read_command()
|
|
19
|
+
@dbgr.intf[-1].read_command(@prompt)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def safe_rep(str)
|
|
23
|
+
Trepan::Util::safe_repr(str, @settings[:maxstring])
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|