trepanning 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- 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
|