rb8-trepanning 0.1.3
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/.gitignore +3 -0
- data/CHANGES +34 -0
- data/ChangeLog +875 -0
- data/README.textile +59 -0
- data/Rakefile +215 -0
- data/app/.gitignore +1 -0
- data/app/cmd_parse.kpeg +241 -0
- data/app/cmd_parse.rb +212 -0
- data/app/cmd_parser.rb +1948 -0
- data/app/complete.rb +79 -0
- data/app/default.rb +90 -0
- data/app/display.rb +148 -0
- data/app/eventbuffer.rb +147 -0
- data/app/frame.rb +166 -0
- data/app/irb.rb +114 -0
- data/app/options.rb +200 -0
- data/app/run.rb +74 -0
- data/app/util.rb +65 -0
- data/bin/.gitignore +1 -0
- data/bin/trepan8 +115 -0
- data/data/.gitignore +1 -0
- data/data/irbrc +41 -0
- data/interface/.gitignore +1 -0
- data/interface/base_intf.rb +109 -0
- data/interface/client.rb +82 -0
- data/interface/comcodes.rb +20 -0
- data/interface/script.rb +110 -0
- data/interface/server.rb +147 -0
- data/interface/user.rb +165 -0
- data/io/base_io.rb +148 -0
- data/io/input.rb +158 -0
- data/io/null_output.rb +46 -0
- data/io/string_array.rb +156 -0
- data/io/tcpclient.rb +129 -0
- data/io/tcpfns.rb +33 -0
- data/io/tcpserver.rb +141 -0
- data/lib/debugger.rb +8 -0
- data/lib/trepanning.rb +283 -0
- data/processor/.gitignore +1 -0
- data/processor/command-ruby-debug/breakpoints.rb +155 -0
- data/processor/command-ruby-debug/catchpoint.rb +55 -0
- data/processor/command-ruby-debug/condition.rb +49 -0
- data/processor/command-ruby-debug/control.rb +31 -0
- data/processor/command-ruby-debug/display.rb +120 -0
- data/processor/command-ruby-debug/enable.rb +202 -0
- data/processor/command-ruby-debug/frame.rb +199 -0
- data/processor/command-ruby-debug/help.rb +63 -0
- data/processor/command-ruby-debug/info.rb +359 -0
- data/processor/command-ruby-debug/method.rb +84 -0
- data/processor/command-ruby-debug/reload.rb +40 -0
- data/processor/command-ruby-debug/save.rb +90 -0
- data/processor/command-ruby-debug/set.rb +237 -0
- data/processor/command-ruby-debug/show.rb +251 -0
- data/processor/command-ruby-debug/source.rb +36 -0
- data/processor/command-ruby-debug/threads.rb +189 -0
- data/processor/command-ruby-debug/trace.rb +57 -0
- data/processor/command-ruby-debug/variables.rb +199 -0
- data/processor/command.rb +270 -0
- data/processor/command/.gitignore +1 -0
- data/processor/command/alias.rb +54 -0
- data/processor/command/backtrace.rb +123 -0
- data/processor/command/base/cmd.rb +177 -0
- data/processor/command/base/subcmd.rb +230 -0
- data/processor/command/base/submgr.rb +188 -0
- data/processor/command/base/subsubcmd.rb +128 -0
- data/processor/command/base/subsubmgr.rb +199 -0
- data/processor/command/break.rb +114 -0
- data/processor/command/catch.rb +71 -0
- data/processor/command/complete.rb +39 -0
- data/processor/command/continue.rb +57 -0
- data/processor/command/directory.rb +50 -0
- data/processor/command/disable.rb +85 -0
- data/processor/command/display.rb +78 -0
- data/processor/command/down.rb +54 -0
- data/processor/command/edit.rb +79 -0
- data/processor/command/enable.rb +48 -0
- data/processor/command/eval.rb +90 -0
- data/processor/command/exit.rb +66 -0
- data/processor/command/finish.rb +59 -0
- data/processor/command/frame.rb +97 -0
- data/processor/command/help.rb +230 -0
- data/processor/command/help/.gitignore +1 -0
- data/processor/command/help/README +10 -0
- data/processor/command/help/command.txt +58 -0
- data/processor/command/help/examples.txt +16 -0
- data/processor/command/help/filename.txt +40 -0
- data/processor/command/help/location.txt +37 -0
- data/processor/command/help/suffixes.txt +17 -0
- data/processor/command/info.rb +28 -0
- data/processor/command/info_subcmd/.gitignore +1 -0
- data/processor/command/info_subcmd/args.rb +39 -0
- data/processor/command/info_subcmd/breakpoints.rb +80 -0
- data/processor/command/info_subcmd/catch.rb +36 -0
- data/processor/command/info_subcmd/files.rb +39 -0
- data/processor/command/info_subcmd/globals.rb +64 -0
- data/processor/command/info_subcmd/line.rb +30 -0
- data/processor/command/info_subcmd/locals.rb +69 -0
- data/processor/command/info_subcmd/macro.rb +62 -0
- data/processor/command/info_subcmd/program.rb +51 -0
- data/processor/command/info_subcmd/ruby.rb +57 -0
- data/processor/command/info_subcmd/source.rb +74 -0
- data/processor/command/info_subcmd/stack.rb +25 -0
- data/processor/command/info_subcmd/threads.rb +75 -0
- data/processor/command/kill.rb +78 -0
- data/processor/command/list.rb +117 -0
- data/processor/command/macro.rb +68 -0
- data/processor/command/next.rb +79 -0
- data/processor/command/parsetree.rb +56 -0
- data/processor/command/pp.rb +40 -0
- data/processor/command/pr.rb +37 -0
- data/processor/command/ps.rb +40 -0
- data/processor/command/restart.rb +86 -0
- data/processor/command/save.rb +58 -0
- data/processor/command/set.rb +47 -0
- data/processor/command/set_subcmd/.gitignore +1 -0
- data/processor/command/set_subcmd/abbrev.rb +25 -0
- data/processor/command/set_subcmd/auto.rb +27 -0
- data/processor/command/set_subcmd/auto_subcmd/.gitignore +1 -0
- data/processor/command/set_subcmd/auto_subcmd/eval.rb +53 -0
- data/processor/command/set_subcmd/auto_subcmd/irb.rb +33 -0
- data/processor/command/set_subcmd/auto_subcmd/list.rb +33 -0
- data/processor/command/set_subcmd/basename.rb +25 -0
- data/processor/command/set_subcmd/callstyle.rb +46 -0
- data/processor/command/set_subcmd/confirm.rb +24 -0
- data/processor/command/set_subcmd/debug.rb +47 -0
- data/processor/command/set_subcmd/different.rb +61 -0
- data/processor/command/set_subcmd/highlight.rb +43 -0
- data/processor/command/set_subcmd/max.rb +26 -0
- data/processor/command/set_subcmd/max_subcmd/list.rb +49 -0
- data/processor/command/set_subcmd/max_subcmd/stack.rb +50 -0
- data/processor/command/set_subcmd/max_subcmd/string.rb +76 -0
- data/processor/command/set_subcmd/max_subcmd/width.rb +49 -0
- data/processor/command/set_subcmd/reload.rb +42 -0
- data/processor/command/set_subcmd/timer.rb +58 -0
- data/processor/command/set_subcmd/trace.rb +37 -0
- data/processor/command/set_subcmd/trace_subcmd/buffer.rb +42 -0
- data/processor/command/set_subcmd/trace_subcmd/print.rb +41 -0
- data/processor/command/shell.rb +139 -0
- data/processor/command/show.rb +39 -0
- data/processor/command/show_subcmd/.gitignore +1 -0
- data/processor/command/show_subcmd/abbrev.rb +20 -0
- data/processor/command/show_subcmd/alias.rb +46 -0
- data/processor/command/show_subcmd/args.rb +34 -0
- data/processor/command/show_subcmd/auto.rb +28 -0
- data/processor/command/show_subcmd/auto_subcmd/eval.rb +27 -0
- data/processor/command/show_subcmd/auto_subcmd/irb.rb +23 -0
- data/processor/command/show_subcmd/auto_subcmd/list.rb +22 -0
- data/processor/command/show_subcmd/basename.rb +20 -0
- data/processor/command/show_subcmd/callstyle.rb +22 -0
- data/processor/command/show_subcmd/confirm.rb +18 -0
- data/processor/command/show_subcmd/debug.rb +26 -0
- data/processor/command/show_subcmd/debug_subcmd/dbgr.rb +21 -0
- data/processor/command/show_subcmd/debug_subcmd/skip.rb +22 -0
- data/processor/command/show_subcmd/debug_subcmd/step.rb +22 -0
- data/processor/command/show_subcmd/different.rb +26 -0
- data/processor/command/show_subcmd/directories.rb +22 -0
- data/processor/command/show_subcmd/highlight.rb +24 -0
- data/processor/command/show_subcmd/max.rb +27 -0
- data/processor/command/show_subcmd/max_subcmd/list.rb +38 -0
- data/processor/command/show_subcmd/max_subcmd/stack.rb +36 -0
- data/processor/command/show_subcmd/max_subcmd/string.rb +42 -0
- data/processor/command/show_subcmd/max_subcmd/width.rb +37 -0
- data/processor/command/show_subcmd/reload.rb +18 -0
- data/processor/command/show_subcmd/timer.rb +18 -0
- data/processor/command/show_subcmd/trace.rb +29 -0
- data/processor/command/show_subcmd/trace_subcmd/buffer.rb +65 -0
- data/processor/command/show_subcmd/trace_subcmd/print.rb +23 -0
- data/processor/command/show_subcmd/version.rb +23 -0
- data/processor/command/source.rb +134 -0
- data/processor/command/step.rb +81 -0
- data/processor/command/tbreak.rb +19 -0
- data/processor/command/unalias.rb +44 -0
- data/processor/command/undisplay.rb +59 -0
- data/processor/command/up.rb +72 -0
- data/processor/default.rb +56 -0
- data/processor/display.rb +17 -0
- data/processor/eval.rb +113 -0
- data/processor/eventbuf.rb +105 -0
- data/processor/frame.rb +172 -0
- data/processor/help.rb +92 -0
- data/processor/helper.rb +76 -0
- data/processor/hook.rb +134 -0
- data/processor/load_cmds.rb +258 -0
- data/processor/location.rb +174 -0
- data/processor/main.rb +455 -0
- data/processor/mock.rb +136 -0
- data/processor/msg.rb +61 -0
- data/processor/processor.rb +674 -0
- data/processor/running.rb +168 -0
- data/processor/stepping.rb +18 -0
- data/processor/subcmd.rb +161 -0
- data/processor/validate.rb +355 -0
- data/processor/virtual.rb +34 -0
- data/test/data/.gitignore +1 -0
- data/test/data/break_bad.cmd +19 -0
- data/test/data/break_bad.right +29 -0
- data/test/data/break_loop_bug.cmd +5 -0
- data/test/data/break_loop_bug.right +15 -0
- data/test/data/dollar-0.right +2 -0
- data/test/data/dollar-0a.right +2 -0
- data/test/data/dollar-0b.right +2 -0
- data/test/data/edit.cmd +14 -0
- data/test/data/edit.right +24 -0
- data/test/data/file-with-space.cmd +6 -0
- data/test/data/file-with-space.right +4 -0
- data/test/data/printvar.cmd +17 -0
- data/test/data/printvar.right +31 -0
- data/test/data/raise.cmd +11 -0
- data/test/data/raise.right +19 -0
- data/test/data/source.cmd +5 -0
- data/test/data/source.right +18 -0
- data/test/data/stepping-1.9.right +50 -0
- data/test/data/stepping.cmd +21 -0
- data/test/data/stepping.right +48 -0
- data/test/data/trepan8-save.1 +6 -0
- data/test/example/bp_loop_issue.rb +3 -0
- data/test/example/break-bug.rb +7 -0
- data/test/example/brkpt-class-bug.rb +8 -0
- data/test/example/classes.rb +11 -0
- data/test/example/dollar-0.rb +5 -0
- data/test/example/except-bug1.rb +4 -0
- data/test/example/except-bug2.rb +7 -0
- data/test/example/file with space.rb +1 -0
- data/test/example/gcd.rb +18 -0
- data/test/example/info-var-bug.rb +47 -0
- data/test/example/info-var-bug2.rb +2 -0
- data/test/example/null.rb +1 -0
- data/test/example/pm-bug.rb +3 -0
- data/test/example/pm.rb +11 -0
- data/test/example/raise.rb +3 -0
- data/test/integration/.gitignore +4 -0
- data/test/integration/config.yaml +8 -0
- data/test/integration/helper.rb +154 -0
- data/test/integration/test-break_bad.rb +26 -0
- data/test/integration/test-dollar-0.rb +31 -0
- data/test/integration/test-edit.rb +17 -0
- data/test/integration/test-file-with-space.rb +26 -0
- data/test/integration/test-printvar.rb +17 -0
- data/test/integration/test-raise.rb +21 -0
- data/test/integration/test-source.rb +16 -0
- data/test/integration/test-stepping.rb +24 -0
- data/test/unit/.gitignore +1 -0
- data/test/unit/cmd-helper.rb +52 -0
- data/test/unit/mock-helper.rb +12 -0
- data/test/unit/test-app-cmd_parse.rb +97 -0
- data/test/unit/test-app-cmd_parser.rb +23 -0
- data/test/unit/test-app-complete.rb +39 -0
- data/test/unit/test-app-frame.rb +32 -0
- data/test/unit/test-app-options.rb +92 -0
- data/test/unit/test-app-run.rb +14 -0
- data/test/unit/test-app-util.rb +44 -0
- data/test/unit/test-base-cmd.rb +45 -0
- data/test/unit/test-base-subcmd.rb +57 -0
- data/test/unit/test-base-submgr.rb +23 -0
- data/test/unit/test-base-subsubcmd.rb +17 -0
- data/test/unit/test-cmd-alias.rb +48 -0
- data/test/unit/test-cmd-exit.rb +27 -0
- data/test/unit/test-cmd-help.rb +104 -0
- data/test/unit/test-cmd-kill.rb +46 -0
- data/test/unit/test-cmd-source.rb +34 -0
- data/test/unit/test-completion.rb +42 -0
- data/test/unit/test-intf-user.rb +46 -0
- data/test/unit/test-io-input.rb +27 -0
- data/test/unit/test-io-tcp.rb +33 -0
- data/test/unit/test-io-tcpclient.rb +54 -0
- data/test/unit/test-io-tcpfns.rb +17 -0
- data/test/unit/test-io-tcpserver.rb +50 -0
- data/test/unit/test-proc-eval.rb +36 -0
- data/test/unit/test-proc-hook.rb +30 -0
- data/test/unit/test-proc-load_cmds.rb +50 -0
- data/test/unit/test-proc-location.rb +79 -0
- data/test/unit/test-subcmd-help.rb +44 -0
- data/trepan8.gemspec +52 -0
- metadata +391 -0
data/processor/mock.rb
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# Copyright (C) 2010, 2011 Rocky Bernstein <rockyb@rubyforge.net>
|
|
2
|
+
# Mock setup for commands.
|
|
3
|
+
require 'rubygems'; require 'require_relative'
|
|
4
|
+
require_relative 'virtual'
|
|
5
|
+
|
|
6
|
+
# require_relative '../app/core'
|
|
7
|
+
require_relative '../app/default'
|
|
8
|
+
require_relative '../interface/user' # user interface (includes I/O)
|
|
9
|
+
|
|
10
|
+
require 'ruby-debug-base'; Debugger.start(:init => true)
|
|
11
|
+
require_relative 'processor'
|
|
12
|
+
|
|
13
|
+
module MockDebugger
|
|
14
|
+
class MockDebugger
|
|
15
|
+
attr_accessor :trace_filter # Procs/Methods we ignore.
|
|
16
|
+
|
|
17
|
+
attr_accessor :frame # Actually a "Rubinius::Location object
|
|
18
|
+
attr_accessor :core # access to Debugger::Core instance
|
|
19
|
+
attr_accessor :intf # The way the outside world interfaces with us.
|
|
20
|
+
attr_reader :initial_dir # String. Current directory when program
|
|
21
|
+
# started. Used in restart program.
|
|
22
|
+
attr_accessor :restart_argv # How to restart us, empty or nil.
|
|
23
|
+
# Note restart[0] is typically $0.
|
|
24
|
+
attr_reader :settings # Hash[:symbol] of things you can configure
|
|
25
|
+
attr_accessor :processor
|
|
26
|
+
|
|
27
|
+
# FIXME: move more stuff of here and into Trepan::CmdProcessor
|
|
28
|
+
# These below should go into Trepan::CmdProcessor.
|
|
29
|
+
attr_reader :cmd_argstr, :cmd_name, :current_frame, :completion_proc
|
|
30
|
+
|
|
31
|
+
def initialize(settings={:start_frame=>1})
|
|
32
|
+
@before_cmdloop_hooks = []
|
|
33
|
+
@settings = Trepan::DEFAULT_SETTINGS.merge(settings)
|
|
34
|
+
@intf = [Trepan::UserInterface.new(nil, nil,
|
|
35
|
+
:history_save=>false)]
|
|
36
|
+
# @current_frame = Trepan::Frame.new(context)
|
|
37
|
+
@frames = []
|
|
38
|
+
|
|
39
|
+
@trace_filter = []
|
|
40
|
+
|
|
41
|
+
@completion_proc = Proc.new{|str| str}
|
|
42
|
+
|
|
43
|
+
# Don't allow user commands in mocks.
|
|
44
|
+
## @core.processor.settings[:user_cmd_dir] = nil
|
|
45
|
+
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def frame(num)
|
|
49
|
+
@frames[num] ||= caller
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Common Mock debugger setup
|
|
54
|
+
def setup(name=nil, show_constants=true)
|
|
55
|
+
unless name
|
|
56
|
+
file = caller.first.split(/:\d/,2).first
|
|
57
|
+
name = File.basename(File.basename(file), '.rb')
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
if ARGV.size > 0 && ARGV[0] == 'debug'
|
|
61
|
+
require_relative '../lib/trepanning'
|
|
62
|
+
dbgr = Trepan.new
|
|
63
|
+
dbgr.debugger
|
|
64
|
+
else
|
|
65
|
+
dbgr = MockDebugger.new(:start_frame=>2)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
cmdproc = Trepan::CmdProcessor.new(dbgr.intf)
|
|
69
|
+
state = Trepan::CommandProcessor::State.new(self) do |s|
|
|
70
|
+
s.context = Debugger.current_context
|
|
71
|
+
s.binding = binding
|
|
72
|
+
end
|
|
73
|
+
cmdproc.frame_setup(state.context, state)
|
|
74
|
+
dbgr.processor = cmdproc
|
|
75
|
+
|
|
76
|
+
cmdproc.interfaces = dbgr.intf
|
|
77
|
+
cmdproc.load_cmds_initialize
|
|
78
|
+
cmds = cmdproc.commands
|
|
79
|
+
cmd = cmds[name]
|
|
80
|
+
## cmd.proc.frame_setup
|
|
81
|
+
## cmd.proc.event = 'debugger-call'
|
|
82
|
+
show_special_class_constants(cmd) if show_constants
|
|
83
|
+
|
|
84
|
+
def cmd.confirm(prompt, default)
|
|
85
|
+
true
|
|
86
|
+
end
|
|
87
|
+
def cmd.msg_nocr(message, opts={})
|
|
88
|
+
print message
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
return dbgr, cmd
|
|
92
|
+
end
|
|
93
|
+
module_function :setup
|
|
94
|
+
|
|
95
|
+
def sub_setup(sub_class, run=true)
|
|
96
|
+
sub_name = sub_class.const_get('PREFIX')
|
|
97
|
+
dbgr, cmd = setup(sub_name[0], false)
|
|
98
|
+
sub_cmd = sub_class.new(cmd)
|
|
99
|
+
sub_cmd.summary_help(sub_cmd.name)
|
|
100
|
+
puts
|
|
101
|
+
sub_cmd.run([cmd.name]) if run
|
|
102
|
+
return sub_cmd
|
|
103
|
+
end
|
|
104
|
+
module_function :sub_setup
|
|
105
|
+
|
|
106
|
+
def subsub_setup(sub_class, subsub_class, run=true)
|
|
107
|
+
subsub_name = subsub_class.const_get('PREFIX')
|
|
108
|
+
dbgr, cmd = setup(subsub_name[0], false)
|
|
109
|
+
sub_cmd = sub_class.new(dbgr.processor, cmd)
|
|
110
|
+
subsub_cmd = subsub_class.new(cmd.proc, sub_cmd, subsub_name.join(''))
|
|
111
|
+
subsub_cmd.run([subsub_cmd.name]) if run
|
|
112
|
+
return subsub_cmd
|
|
113
|
+
end
|
|
114
|
+
module_function :subsub_setup
|
|
115
|
+
|
|
116
|
+
def show_special_class_constants(cmd)
|
|
117
|
+
puts 'ALIASES: %s' % [cmd.class.const_get('ALIASES').inspect] if
|
|
118
|
+
cmd.class.constants.member?(:ALIASES)
|
|
119
|
+
%w(CATEGORY MIN_ARGS MAX_ARGS
|
|
120
|
+
NAME NEED_STACK SHORT_HELP).each do |name|
|
|
121
|
+
puts '%s: %s' % [name, cmd.class.const_get(name).inspect]
|
|
122
|
+
end
|
|
123
|
+
puts '-' * 30
|
|
124
|
+
puts cmd.class.const_get('HELP')
|
|
125
|
+
puts '=' * 30
|
|
126
|
+
end
|
|
127
|
+
module_function :show_special_class_constants
|
|
128
|
+
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
if __FILE__ == $0
|
|
132
|
+
dbgr = MockDebugger::MockDebugger.new
|
|
133
|
+
p dbgr.settings
|
|
134
|
+
puts '=' * 10
|
|
135
|
+
# p dbgr.core.processor.settings
|
|
136
|
+
end
|
data/processor/msg.rb
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Copyright (C) 2010, 2011 Rocky Bernstein <rockyb@rubyforge.net>
|
|
2
|
+
# I/O related command processor methods
|
|
3
|
+
require 'rubygems'; require 'require_relative'
|
|
4
|
+
require_relative '../app/util'
|
|
5
|
+
require_relative 'virtual'
|
|
6
|
+
module Trepan
|
|
7
|
+
class CmdProcessor < VirtualCmdProcessor
|
|
8
|
+
attr_accessor :ruby_highlighter
|
|
9
|
+
|
|
10
|
+
def errmsg(message, opts={})
|
|
11
|
+
message = safe_rep(message) unless opts[:unlimited]
|
|
12
|
+
if @settings[:highlight] && defined?(Term::ANSIColor)
|
|
13
|
+
message =
|
|
14
|
+
Term::ANSIColor.italic + message + Term::ANSIColor.reset
|
|
15
|
+
end
|
|
16
|
+
@intf.errmsg(message)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def msg(message, opts={})
|
|
20
|
+
message = safe_rep(message) unless opts[:unlimited]
|
|
21
|
+
@intf.msg(message)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def msg_nocr(message, opts={})
|
|
25
|
+
message = safe_rep(message) unless opts[:unlimited]
|
|
26
|
+
@intf.msg_nocr(message)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def read_command()
|
|
30
|
+
@intf.read_command(@prompt)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def ruby_format(text)
|
|
34
|
+
return text unless settings[:highlight]
|
|
35
|
+
unless @ruby_highlighter
|
|
36
|
+
begin
|
|
37
|
+
require 'coderay'
|
|
38
|
+
require 'term/ansicolor'
|
|
39
|
+
@ruby_highlighter = CodeRay::Duo[:ruby, :term]
|
|
40
|
+
rescue LoadError
|
|
41
|
+
return text
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
return @ruby_highlighter.encode(text)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def safe_rep(str)
|
|
48
|
+
Util::safe_repr(str, @settings[:maxstring])
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def section(message, opts={})
|
|
52
|
+
message = safe_rep(message) unless opts[:unlimited]
|
|
53
|
+
if @settings[:highlight] && defined?(Term::ANSIColor)
|
|
54
|
+
message =
|
|
55
|
+
Term::ANSIColor.bold + message + Term::ANSIColor.reset
|
|
56
|
+
end
|
|
57
|
+
@intf.msg(message)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,674 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
require 'ruby-debug-base'
|
|
3
|
+
require 'require_relative'
|
|
4
|
+
require_relative '../interface/user'
|
|
5
|
+
require_relative './command'
|
|
6
|
+
require_relative './default'
|
|
7
|
+
require_relative './main'
|
|
8
|
+
require_relative '../app/frame'
|
|
9
|
+
|
|
10
|
+
# _Trepan_ is the module name space for this debugger.
|
|
11
|
+
module Trepan
|
|
12
|
+
|
|
13
|
+
# A processor handles the kind of front-end to program interaction.
|
|
14
|
+
# Debugger::Processor is the the base class with subclasses
|
|
15
|
+
# Debugger::CommandProcessor and Debugger::ControlCommandProcessor.
|
|
16
|
+
class Processor
|
|
17
|
+
attr_accessor :interface
|
|
18
|
+
attr_reader :processor
|
|
19
|
+
attr_reader :commands
|
|
20
|
+
|
|
21
|
+
attr_accessor :frame # FIXME: move to frame.rb
|
|
22
|
+
|
|
23
|
+
# optional argument passed passed in callback. For catchpoints it is
|
|
24
|
+
# the catch object. For breakpoints it is the breakpoint object.
|
|
25
|
+
attr_reader :event_arg
|
|
26
|
+
|
|
27
|
+
# Format _msg_ with gdb-style annotation header.
|
|
28
|
+
def afmt(msg, newline="\n")
|
|
29
|
+
"\032\032#{msg}#{newline}"
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Print "annotation" message _msg_. Annotation messages are used
|
|
33
|
+
# by the GNU-Emacs front-end to get status about stacks and
|
|
34
|
+
# the state of the debugger without having to poll it for information
|
|
35
|
+
def aprint(msg)
|
|
36
|
+
print afmt(msg) if Trepan.annotate.to_i > 2
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Print a debugger error message; _args_ should be compatible
|
|
40
|
+
# with something you would pass to Kernel::print.
|
|
41
|
+
def errmsg(*args)
|
|
42
|
+
@interface.errmsg(*args)
|
|
43
|
+
@interface.print("\n")
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Print a normal debugger message; _args_ should be compatible
|
|
47
|
+
# with something you would pass to Kernel::print.
|
|
48
|
+
#
|
|
49
|
+
# Callers of this routine should make sure to use comma to
|
|
50
|
+
# separate format argments rather than %. Otherwise it seems that
|
|
51
|
+
# if the string you want to print has format specifier, which
|
|
52
|
+
# could happen if you are trying to show say a source-code line
|
|
53
|
+
# with "puts" or "print" in it, this print routine will give an
|
|
54
|
+
# error saying it is looking for more arguments.
|
|
55
|
+
def print(*args)
|
|
56
|
+
@interface.msg(*args)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# A Debugger::CommandProcessor is the kind of Debugger::Processor
|
|
62
|
+
# used when you are running inside the same process as the debugged
|
|
63
|
+
# program.
|
|
64
|
+
class CommandProcessor < Processor
|
|
65
|
+
attr_reader :display
|
|
66
|
+
attr_accessor :frame
|
|
67
|
+
attr_reader :cmdproc
|
|
68
|
+
|
|
69
|
+
# FIXME: get from Command regexp method.
|
|
70
|
+
@@Show_breakpoints_postcmd = [
|
|
71
|
+
/^\s*b(?:reak)?/,
|
|
72
|
+
/^\s* cond(?:ition)? (?:\s+(\d+)\s*(.*))?$/ix,
|
|
73
|
+
/^\s*del(?:ete)?(?:\s+(.*))?$/ix,
|
|
74
|
+
/^\s* dis(?:able)? (?:\s+(.*))?$/ix,
|
|
75
|
+
/^\s* en(?:able)? (?:\s+(.*))?$/ix,
|
|
76
|
+
# "tbreak", "clear",
|
|
77
|
+
]
|
|
78
|
+
@@Show_annotations_run = [
|
|
79
|
+
/^\s*c(?:ont(?:inue)?)?(?:\s+(.*))?$/,
|
|
80
|
+
/^\s*fin(?:ish)?$/,
|
|
81
|
+
/^\s*n(?:ext)?([+-])?(?:\s+(.*))?$/,
|
|
82
|
+
/^\s*s(?:tep)?([+-])?(?:\s+(.*))?$/
|
|
83
|
+
]
|
|
84
|
+
|
|
85
|
+
@@Show_annotations_postcmd = [
|
|
86
|
+
/^\s* down (?:\s+(.*))? .*$/x,
|
|
87
|
+
/^\s* f(?:rame)? (?:\s+ (.*))? \s*$/x,
|
|
88
|
+
/^\s* u(?:p)? (?:\s+(.*))?$/x
|
|
89
|
+
]
|
|
90
|
+
|
|
91
|
+
def initialize(interfaces = [Trepan::UserInterface.new], settings={})
|
|
92
|
+
@interface = interfaces.first
|
|
93
|
+
@commands = []
|
|
94
|
+
@display = []
|
|
95
|
+
|
|
96
|
+
@mutex = Mutex.new
|
|
97
|
+
@last_cmd = nil
|
|
98
|
+
@last_file = nil # Filename the last time we stopped
|
|
99
|
+
@last_line = nil # line number the last time we stopped
|
|
100
|
+
@debugger_breakpoints_were_empty = false # Show breakpoints 1st time
|
|
101
|
+
@debugger_displays_were_empty = true # No display 1st time
|
|
102
|
+
@debugger_context_was_dead = true # Assume we haven't started.
|
|
103
|
+
@cmdproc = CmdProcessor.new(interfaces, settings)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def interface=(interface)
|
|
107
|
+
@mutex.synchronize do
|
|
108
|
+
@interface.close if @interface
|
|
109
|
+
@interface = interface
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
require 'pathname' # For cleanpath
|
|
114
|
+
|
|
115
|
+
# Regularize or "canonicalize" file name _filename_.
|
|
116
|
+
# This is also used as a common funnel place if basename is
|
|
117
|
+
# desired or if we are working remotely and want to change the
|
|
118
|
+
# basename. Or we are eliding filenames.
|
|
119
|
+
def self.canonic_file(filename)
|
|
120
|
+
# For now we want resolved filenames
|
|
121
|
+
if OldCommand.settings[:basename]
|
|
122
|
+
File.basename(filename)
|
|
123
|
+
else
|
|
124
|
+
# Cache this?
|
|
125
|
+
Pathname.new(filename).cleanpath.to_s
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def self.print_location_and_text(file, line)
|
|
130
|
+
file_line = "%s:%s\n%s" % [canonic_file(file), line,
|
|
131
|
+
Debugger.line_at(file, line)]
|
|
132
|
+
# FIXME: use annotations routines
|
|
133
|
+
if Trepan.annotate.to_i > 2
|
|
134
|
+
file_line = "\032\032source #{file_line}"
|
|
135
|
+
elsif Trepan.inside_emacs?
|
|
136
|
+
file_line = "\032\032#{file_line}"
|
|
137
|
+
end
|
|
138
|
+
print file_line
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# Create a "protected" version of method _mname_. A protected
|
|
142
|
+
# method handles all unhandled exceptions that would cause the
|
|
143
|
+
# program to terminate.
|
|
144
|
+
def self.protect(mname)
|
|
145
|
+
alias_method "__#{mname}", mname
|
|
146
|
+
module_eval %{
|
|
147
|
+
def #{mname}(*args)
|
|
148
|
+
@mutex.synchronize do
|
|
149
|
+
return unless @interface
|
|
150
|
+
__#{mname}(*args)
|
|
151
|
+
end
|
|
152
|
+
rescue IOError, Errno::EPIPE
|
|
153
|
+
self.interface = nil
|
|
154
|
+
rescue SignalException
|
|
155
|
+
raise
|
|
156
|
+
rescue Exception
|
|
157
|
+
print "INTERNAL ERROR!!! #\{$!\}\n" rescue nil
|
|
158
|
+
print $!.backtrace.map{|l| "\t#\{l\}"}.join("\n") rescue nil
|
|
159
|
+
end
|
|
160
|
+
}
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# This is a callback routine when the debugged program hits a
|
|
164
|
+
# breakpoint event. For example ruby-debug-base calls this method.
|
|
165
|
+
def at_breakpoint(context, breakpoint)
|
|
166
|
+
@event_arg = breakpoint
|
|
167
|
+
@cmdproc.event = 'brkpt'
|
|
168
|
+
aprint 'stopped' if Trepan.annotate.to_i > 2
|
|
169
|
+
n = Debugger.breakpoints.index(breakpoint) + 1
|
|
170
|
+
file = @cmdproc.canonic_file(breakpoint.source)
|
|
171
|
+
line = breakpoint.pos
|
|
172
|
+
if Trepan.annotate.to_i > 2
|
|
173
|
+
print afmt("source #{file}:#{line}")
|
|
174
|
+
end
|
|
175
|
+
@cmdproc.msg 'Breakpoint %d at %s:%s' % [n, file, line]
|
|
176
|
+
end
|
|
177
|
+
protect :at_breakpoint
|
|
178
|
+
|
|
179
|
+
# This is a callback routine when the debugged program raises an
|
|
180
|
+
# unhandled exception that we have arranged to catch.
|
|
181
|
+
# In particular, ruby-debug-base calls this method
|
|
182
|
+
def at_catchpoint(context, excpt)
|
|
183
|
+
@event_arg = excpt
|
|
184
|
+
@cmdproc.event = 'raise'
|
|
185
|
+
file = @cmdproc.canonic_file(context.frame_file(0))
|
|
186
|
+
line = context.frame_line(0)
|
|
187
|
+
@cmdproc.msg("Catchpoint at %s:%d: `%s' (%s)" %
|
|
188
|
+
[file, line, excpt, excpt.class])
|
|
189
|
+
process_commands(context, file, line)
|
|
190
|
+
end
|
|
191
|
+
protect :at_catchpoint
|
|
192
|
+
|
|
193
|
+
def at_tracing(context, file, line)
|
|
194
|
+
@cmdproc.event = 'tracing'
|
|
195
|
+
return if defined?(Debugger::RDEBUG_FILE) &&
|
|
196
|
+
Debugger::RDEBUG_FILE == file # Don't trace ourself
|
|
197
|
+
@last_file = CommandProcessor.canonic_file(file)
|
|
198
|
+
canonic_file = CommandProcessor.canonic_file(file)
|
|
199
|
+
unless canonic_file == @last_file and @last_line == line and
|
|
200
|
+
Command.settings[:tracing_plus]
|
|
201
|
+
print "Tracing(%d):%s:%s %s",
|
|
202
|
+
context.thnum, canonic_file, line, Debugger.line_at(file, line)
|
|
203
|
+
@last_file = canonic_file
|
|
204
|
+
@last_line = line
|
|
205
|
+
end
|
|
206
|
+
always_run(context, file, line, 2)
|
|
207
|
+
end
|
|
208
|
+
protect :at_tracing
|
|
209
|
+
|
|
210
|
+
# This is a callback routine when the debugged program hits a
|
|
211
|
+
# "line" (or statement boundary) event. For example
|
|
212
|
+
# ruby-debug-base calls this.
|
|
213
|
+
def at_line(context, file, line)
|
|
214
|
+
@cmdproc.event = 'line'
|
|
215
|
+
process_commands(context, file, line)
|
|
216
|
+
end
|
|
217
|
+
protect :at_line
|
|
218
|
+
|
|
219
|
+
# This is a callback routine when the debugged program hits a
|
|
220
|
+
# "return" event. For example ruby-debug-base calls this.
|
|
221
|
+
# Note: right now ruby-debug-base does not call this. Perhaps
|
|
222
|
+
# other bases routines such as the one in JRuby do.
|
|
223
|
+
def at_return(context, file, line)
|
|
224
|
+
@cmdproc.event = 'return'
|
|
225
|
+
context.stop_frame = -1
|
|
226
|
+
process_commands(context, file, line)
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
# Return the command object to run given input string _input_.
|
|
230
|
+
def lookup(input)
|
|
231
|
+
###########################################
|
|
232
|
+
## Test the waters with new-style commands
|
|
233
|
+
args = input.split
|
|
234
|
+
cmd_name = args[0]
|
|
235
|
+
run_cmd_name =
|
|
236
|
+
if @cmdproc.aliases.member?(cmd_name)
|
|
237
|
+
@cmdproc.aliases[cmd_name]
|
|
238
|
+
else
|
|
239
|
+
cmd_name
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
if @cmdproc.commands.member?(run_cmd_name)
|
|
243
|
+
cmd = @cmdproc.commands[run_cmd_name]
|
|
244
|
+
if @cmdproc.ok_for_running(cmd, run_cmd_name, args.size-1)
|
|
245
|
+
return cmd
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
###########################################
|
|
249
|
+
|
|
250
|
+
@commands.find{ |c| c.match(input) }
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
# Run a single command specified by string _input_; _commands_ is and
|
|
254
|
+
# Array of possible debugger command objects and _context_ is
|
|
255
|
+
# a Debugger::Context object.
|
|
256
|
+
def one_cmd(commands, context, input)
|
|
257
|
+
if cmd = lookup(input)
|
|
258
|
+
if cmd.kind_of?(Command)
|
|
259
|
+
if context.dead? && cmd.class.need_context
|
|
260
|
+
p cmd
|
|
261
|
+
print "Command is unavailable\n"
|
|
262
|
+
else
|
|
263
|
+
args = input.split
|
|
264
|
+
cmd_name = args[0]
|
|
265
|
+
@cmdproc.instance_variable_set('@cmd_argstr', input[cmd_name.size..-1].lstrip)
|
|
266
|
+
@cmdproc.instance_variable_set('@cmd_name', cmd_name)
|
|
267
|
+
begin
|
|
268
|
+
cmd.run(args)
|
|
269
|
+
rescue Exception
|
|
270
|
+
print "INTERNAL ERROR running command: #{cmd_name}\n"
|
|
271
|
+
print "#{$!}\n"
|
|
272
|
+
print $!.backtrace.map{|l| "\t#{l}"}.join("\n"), "\n" rescue nil
|
|
273
|
+
end
|
|
274
|
+
end
|
|
275
|
+
elsif context.dead? && cmd.class.need_context
|
|
276
|
+
p cmd
|
|
277
|
+
msg "Command is unavailable"
|
|
278
|
+
else
|
|
279
|
+
puts "Using old-style command" unless
|
|
280
|
+
@cmdproc.settings[:debuggertesting]
|
|
281
|
+
cmd.execute
|
|
282
|
+
end
|
|
283
|
+
else
|
|
284
|
+
unknown_cmd = commands.find{|cmd| cmd.class.unknown }
|
|
285
|
+
if unknown_cmd
|
|
286
|
+
unknown_cmd.execute
|
|
287
|
+
else
|
|
288
|
+
if @cmdproc.settings[:autoeval]
|
|
289
|
+
begin
|
|
290
|
+
@cmdproc.eval_code(input, @cmdproc.settings[:maxstring])
|
|
291
|
+
return
|
|
292
|
+
rescue NameError
|
|
293
|
+
end
|
|
294
|
+
end
|
|
295
|
+
errmsg "Unknown command: \"#{input.chomp}\". Try \"help\"."
|
|
296
|
+
end
|
|
297
|
+
end
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
private
|
|
301
|
+
|
|
302
|
+
# Return a prompt string to show before reading a command.
|
|
303
|
+
def prompt(context)
|
|
304
|
+
p = '(rdb:%s) ' % (context.dead? ? 'post-mortem' : context.thnum)
|
|
305
|
+
p = afmt("pre-prompt")+p+"\n"+afmt("prompt") if
|
|
306
|
+
Trepan.annotate.to_i > 2
|
|
307
|
+
return p
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
# Run commands that we always have to run before a entering a
|
|
311
|
+
# command loop. For example commands registered via debugger "set
|
|
312
|
+
# display", "set autolist", or set "autoirb". We return a list of
|
|
313
|
+
# commands that are acceptable to run bound to the current state.
|
|
314
|
+
def always_run(context, file, line, run_level)
|
|
315
|
+
event_cmds = OldCommand.commands.select{|cmd| cmd.event }
|
|
316
|
+
|
|
317
|
+
# Remove some commands if we are post mortem.
|
|
318
|
+
event_cmds = event_cmds.find_all do |cmd|
|
|
319
|
+
cmd.allow_in_post_mortem
|
|
320
|
+
end if !context || context.dead?
|
|
321
|
+
|
|
322
|
+
state = State.new(self) do |s|
|
|
323
|
+
s.context = context
|
|
324
|
+
s.file = file
|
|
325
|
+
s.line = line
|
|
326
|
+
s.display = display
|
|
327
|
+
s.commands = event_cmds
|
|
328
|
+
end
|
|
329
|
+
@interface.state = state if @interface.respond_to?('state=')
|
|
330
|
+
|
|
331
|
+
# Bind commands to the current state.
|
|
332
|
+
commands = event_cmds.map{|cmd| cmd.new(state)}
|
|
333
|
+
|
|
334
|
+
commands.select do |cmd|
|
|
335
|
+
cmd.class.always_run >= run_level
|
|
336
|
+
end.each {|cmd| cmd.execute}
|
|
337
|
+
return state, commands
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
# This the main debugger command-line loop. Here we read a
|
|
341
|
+
# debugger command, perform it, and ask for another one unless we
|
|
342
|
+
# are told to continue execution or terminate.
|
|
343
|
+
def process_commands(context, file, line)
|
|
344
|
+
@state, @commands = always_run(context, file, line, 1)
|
|
345
|
+
$rdebug_state = @state if @cmdproc.settings[:debuggertesting]
|
|
346
|
+
@cmdproc.process_commands(context, @state)
|
|
347
|
+
|
|
348
|
+
# @cmdproc.frame_setup(context, @state)
|
|
349
|
+
# splitter = lambda do |str|
|
|
350
|
+
# str.split(/;/).inject([]) do |m, v|
|
|
351
|
+
# if m.empty?
|
|
352
|
+
# m << v
|
|
353
|
+
# else
|
|
354
|
+
# if m.last[-1] == ?\\
|
|
355
|
+
# m.last[-1,1] = ''
|
|
356
|
+
# m.last << ';' << v
|
|
357
|
+
# else
|
|
358
|
+
# m << v
|
|
359
|
+
# end
|
|
360
|
+
# end
|
|
361
|
+
# m
|
|
362
|
+
# end
|
|
363
|
+
# end
|
|
364
|
+
|
|
365
|
+
# preloop(@commands, context)
|
|
366
|
+
# CommandProcessor.print_location_and_text(file, line)
|
|
367
|
+
# while !@state.proceed?
|
|
368
|
+
# input = if @interface.command_queue.empty?
|
|
369
|
+
# @interface.read_command(prompt(context))
|
|
370
|
+
# else
|
|
371
|
+
# @interface.command_queue.shift
|
|
372
|
+
# end
|
|
373
|
+
# break unless input
|
|
374
|
+
# next if input =~ /^\s*#/
|
|
375
|
+
# catch(:debug_error) do
|
|
376
|
+
# if input == ""
|
|
377
|
+
# next unless @last_cmd
|
|
378
|
+
# input = @last_cmd
|
|
379
|
+
# else
|
|
380
|
+
# @last_cmd = input
|
|
381
|
+
# end
|
|
382
|
+
# splitter[input].each do |cmd|
|
|
383
|
+
# one_cmd(@commands, context, cmd)
|
|
384
|
+
# postcmd(@commands, context, cmd)
|
|
385
|
+
# end
|
|
386
|
+
# end
|
|
387
|
+
# end
|
|
388
|
+
# postloop(@commands, context)
|
|
389
|
+
end # process_commands
|
|
390
|
+
|
|
391
|
+
# Things we do before entering the debugger command loop.
|
|
392
|
+
# Note: in the trepanning debuggers this and always_run have been
|
|
393
|
+
# merged. To do this and get the order right we add a priority level
|
|
394
|
+
# for each hook.
|
|
395
|
+
def preloop(commands, context)
|
|
396
|
+
aprint('stopped') if Trepan.annotate.to_i > 2
|
|
397
|
+
if context.dead?
|
|
398
|
+
unless @debugger_context_was_dead
|
|
399
|
+
if Trepan.annotate.to_i > 2
|
|
400
|
+
aprint('exited')
|
|
401
|
+
print "The program finished.\n"
|
|
402
|
+
end
|
|
403
|
+
@debugger_context_was_dead = true
|
|
404
|
+
end
|
|
405
|
+
end
|
|
406
|
+
|
|
407
|
+
if Trepan.annotate.to_i > 2
|
|
408
|
+
# if we are here, the stack frames have changed outside the
|
|
409
|
+
# command loop (e.g. after a "continue" command), so we show
|
|
410
|
+
# the annotations again
|
|
411
|
+
breakpoint_annotations(commands, context)
|
|
412
|
+
display_annotations(commands, context)
|
|
413
|
+
annotation('stack', commands, context, "where")
|
|
414
|
+
annotation('variables', commands, context, "info variables") unless
|
|
415
|
+
context.dead?
|
|
416
|
+
end
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
# Things we do after leaving the debugger command loop.
|
|
420
|
+
def postcmd(commands, context, cmd)
|
|
421
|
+
if Trepan.annotate.to_i > 0
|
|
422
|
+
cmd = @last_cmd unless cmd
|
|
423
|
+
breakpoint_annotations(commands, context) if
|
|
424
|
+
@@Show_breakpoints_postcmd.find{|pat| cmd =~ pat}
|
|
425
|
+
display_annotations(commands, context)
|
|
426
|
+
if @@Show_annotations_postcmd.find{|pat| cmd =~ pat}
|
|
427
|
+
annotation('stack', commands, context, "where") if
|
|
428
|
+
context.stack_size > 0
|
|
429
|
+
annotation('variables', commands, context, "info variables") unless
|
|
430
|
+
context.dead?
|
|
431
|
+
end
|
|
432
|
+
if not context.dead? and @@Show_annotations_run.find{|pat| cmd =~ pat}
|
|
433
|
+
aprint 'starting' if Trepan.annotate.to_i > 2
|
|
434
|
+
|
|
435
|
+
@debugger_context_was_dead = false
|
|
436
|
+
end
|
|
437
|
+
end
|
|
438
|
+
end
|
|
439
|
+
|
|
440
|
+
# Things we do after leaving the debugger command loop.
|
|
441
|
+
def postloop(commands, context)
|
|
442
|
+
end
|
|
443
|
+
|
|
444
|
+
# Run a command in String _cmd_, but tag output with annotation
|
|
445
|
+
# specified in String _label+. +commands_ is an Array of all
|
|
446
|
+
# possible debugger command objects, and _context_ is a
|
|
447
|
+
# Debugger::Context object.
|
|
448
|
+
def annotation(label, commands, context, cmd)
|
|
449
|
+
print afmt(label)
|
|
450
|
+
one_cmd(commands, context, cmd)
|
|
451
|
+
### FIXME ANNOTATE: the following line should be deleted
|
|
452
|
+
print "\032\032\n"
|
|
453
|
+
end
|
|
454
|
+
|
|
455
|
+
def breakpoint_annotations(commands, context)
|
|
456
|
+
unless Debugger.breakpoints.empty? and @debugger_breakpoints_were_empty
|
|
457
|
+
annotation('breakpoints', commands, context, "info breakpoints")
|
|
458
|
+
@debugger_breakpoints_were_empty = Debugger.breakpoints.empty?
|
|
459
|
+
end
|
|
460
|
+
end
|
|
461
|
+
|
|
462
|
+
def display_annotations(commands, context)
|
|
463
|
+
return if display.empty?
|
|
464
|
+
# have_display = display.find{|d| d[0]}
|
|
465
|
+
# return unless have_display and @debugger_displays_were_empty
|
|
466
|
+
# @debugger_displays_were_empty = have_display
|
|
467
|
+
annotation('display', commands, context, "display")
|
|
468
|
+
end
|
|
469
|
+
|
|
470
|
+
class State # :nodoc:
|
|
471
|
+
attr_accessor :context, :file, :line, :binding
|
|
472
|
+
attr_accessor :frame_pos, :previous_line, :display
|
|
473
|
+
attr_accessor :interface, :commands, :processor
|
|
474
|
+
|
|
475
|
+
def initialize(processor=nil)
|
|
476
|
+
super()
|
|
477
|
+
@frame_pos = 0
|
|
478
|
+
@previous_line = nil
|
|
479
|
+
@proceed = false
|
|
480
|
+
@processor = processor
|
|
481
|
+
yield self
|
|
482
|
+
end
|
|
483
|
+
|
|
484
|
+
# Print a debugger error message; _args_ should be compatible
|
|
485
|
+
# with something you would pass to Kernel::print.
|
|
486
|
+
def errmsg(*args)
|
|
487
|
+
@interface.errmsg(*args)
|
|
488
|
+
@interface.msg("\n")
|
|
489
|
+
end
|
|
490
|
+
|
|
491
|
+
# Print a normal debugger message; _args_ should be compatible
|
|
492
|
+
# with something you would pass to Kernel::print.
|
|
493
|
+
#
|
|
494
|
+
# Callers of this routine should make sure to use comma to
|
|
495
|
+
# separate format argments rather than %. Otherwise it seems that
|
|
496
|
+
# if the string you want to print has format specifier, which
|
|
497
|
+
# could happen if you are trying to show say a source-code line
|
|
498
|
+
# with "puts" or "print" in it, this print routine will give an
|
|
499
|
+
# error saying it is looking for more arguments.
|
|
500
|
+
def print(*args)
|
|
501
|
+
@interface.print(*args)
|
|
502
|
+
end
|
|
503
|
+
|
|
504
|
+
# confirm is called before performing a dangerous action.
|
|
505
|
+
def confirm(*args)
|
|
506
|
+
@interface.confirm(*args)
|
|
507
|
+
end
|
|
508
|
+
|
|
509
|
+
def proceed?
|
|
510
|
+
@proceed
|
|
511
|
+
end
|
|
512
|
+
|
|
513
|
+
def proceed
|
|
514
|
+
@proceed = true
|
|
515
|
+
end
|
|
516
|
+
end
|
|
517
|
+
end
|
|
518
|
+
|
|
519
|
+
# A Debugger::ControlCommandProcessor is the kind of Debugger::Processor
|
|
520
|
+
# used the debugged program is running remotely. It is also entered
|
|
521
|
+
# after the debugged program has terminated.
|
|
522
|
+
class ControlCommandProcessor < Processor
|
|
523
|
+
def initialize(interface)
|
|
524
|
+
super()
|
|
525
|
+
@interface = interface
|
|
526
|
+
@cmdproc = CmdProcessor.new([interface])
|
|
527
|
+
@debugger_context_was_dead = true # Assume we haven't started.
|
|
528
|
+
end
|
|
529
|
+
|
|
530
|
+
# Return the command object to run given input string _input_.
|
|
531
|
+
def lookup(input)
|
|
532
|
+
###########################################
|
|
533
|
+
## Test the waters with new-style commands
|
|
534
|
+
args = input.split
|
|
535
|
+
cmd_name = args[0]
|
|
536
|
+
run_cmd_name =
|
|
537
|
+
if @cmdproc.aliases.member?(cmd_name)
|
|
538
|
+
@cmdproc.aliases[cmd_name]
|
|
539
|
+
else
|
|
540
|
+
cmd_name
|
|
541
|
+
end
|
|
542
|
+
|
|
543
|
+
if @cmdproc.commands.member?(run_cmd_name)
|
|
544
|
+
cmd = @cmdproc.commands[run_cmd_name]
|
|
545
|
+
if @cmdproc.ok_for_running(cmd, run_cmd_name, args.size-1)
|
|
546
|
+
return cmd
|
|
547
|
+
end
|
|
548
|
+
end
|
|
549
|
+
###########################################
|
|
550
|
+
|
|
551
|
+
@commands.find{ |c| c.match(input) }
|
|
552
|
+
end
|
|
553
|
+
|
|
554
|
+
# This the main debugger command-line loop. Here we read a
|
|
555
|
+
# debugger command, perform it, and ask for another one unless we
|
|
556
|
+
# are told to continue execution or terminate.
|
|
557
|
+
def process_commands(verbose=false)
|
|
558
|
+
control_cmds = OldCommand.commands.select do |cmd|
|
|
559
|
+
cmd.allow_in_control
|
|
560
|
+
end
|
|
561
|
+
context = Debugger.current_context
|
|
562
|
+
@state = State.new(@interface, control_cmds)
|
|
563
|
+
@cmdproc.frame_setup(context, @state)
|
|
564
|
+
@commands = control_cmds.map{|cmd| cmd.new(@state) }
|
|
565
|
+
|
|
566
|
+
unless @debugger_context_was_dead
|
|
567
|
+
if Trepan.annotate.to_i > 2
|
|
568
|
+
aprint 'exited'
|
|
569
|
+
print "The program finished.\n"
|
|
570
|
+
end
|
|
571
|
+
@debugger_context_was_dead = true
|
|
572
|
+
end
|
|
573
|
+
|
|
574
|
+
while input = @interface.read_command(prompt(nil))
|
|
575
|
+
print "+#{input}\n" if true # verbose
|
|
576
|
+
catch(:debug_error) do
|
|
577
|
+
if cmd = lookup(input)
|
|
578
|
+
if cmd.kind_of?(Command)
|
|
579
|
+
args = input.split
|
|
580
|
+
cmd_name = args[0]
|
|
581
|
+
@cmdproc.instance_variable_set('@cmd_argstr', input[cmd_name.size..-1].lstrip)
|
|
582
|
+
@cmdproc.instance_variable_set('@cmd_name', cmd_name)
|
|
583
|
+
begin
|
|
584
|
+
cmd.run(args)
|
|
585
|
+
rescue Exception
|
|
586
|
+
print "INTERNAL ERROR running command: #{cmd_name}\n"
|
|
587
|
+
print "#{$!}\n"
|
|
588
|
+
print $!.backtrace.map{|l| "\t#{l}"}.join("\n"), "\n" rescue nil
|
|
589
|
+
end
|
|
590
|
+
else
|
|
591
|
+
puts "Using old-style command" unless
|
|
592
|
+
@cmdproc.settings[:debuggertesting]
|
|
593
|
+
cmd.execute
|
|
594
|
+
end
|
|
595
|
+
else
|
|
596
|
+
if @cmdproc.settings[:autoeval]
|
|
597
|
+
begin
|
|
598
|
+
@cmdproc.eval_code(input, @cmdproc.settings[:maxstring])
|
|
599
|
+
return
|
|
600
|
+
rescue NameError
|
|
601
|
+
end
|
|
602
|
+
end
|
|
603
|
+
errmsg "Unknown command: \"#{input.chomp}\". Try \"help\"."
|
|
604
|
+
end
|
|
605
|
+
end
|
|
606
|
+
end
|
|
607
|
+
rescue IOError, Errno::EPIPE
|
|
608
|
+
# rescue Exception
|
|
609
|
+
# print "INTERNAL ERROR!!! #{$!}\n" rescue nil
|
|
610
|
+
# print $!.backtrace.map{|l| "\t#{l}"}.join("\n") rescue nil
|
|
611
|
+
ensure
|
|
612
|
+
@interface.close
|
|
613
|
+
end
|
|
614
|
+
|
|
615
|
+
# Return a prompt string to show before reading a command. Note: The
|
|
616
|
+
# _context_ parameter is not used. It must be provided so that the
|
|
617
|
+
# interface matches Debugger::CommandProcessor#prompt.
|
|
618
|
+
def prompt(context)
|
|
619
|
+
p = '(rdb:ctrl) '
|
|
620
|
+
p = afmt("pre-prompt")+p+"\n"+afmt("prompt") if
|
|
621
|
+
Trepan.annotate.to_i > 2
|
|
622
|
+
return p
|
|
623
|
+
end
|
|
624
|
+
|
|
625
|
+
class State # :nodoc:
|
|
626
|
+
attr_reader :commands, :interface, :frame_pos
|
|
627
|
+
|
|
628
|
+
def initialize(interface, commands)
|
|
629
|
+
@interface = interface
|
|
630
|
+
@commands = commands
|
|
631
|
+
@frame_pos = 0
|
|
632
|
+
end
|
|
633
|
+
|
|
634
|
+
def proceed
|
|
635
|
+
end
|
|
636
|
+
|
|
637
|
+
# Print a debugger error message; _args_ should be compatible
|
|
638
|
+
# with something you would pass to Kernel::print.
|
|
639
|
+
def errmsg(*args)
|
|
640
|
+
@interface.print(*args)
|
|
641
|
+
@interface.print "\n"
|
|
642
|
+
end
|
|
643
|
+
|
|
644
|
+
# Print a normal debugger message; _args_ should be compatible
|
|
645
|
+
# with something you would pass to Kernel::print.
|
|
646
|
+
#
|
|
647
|
+
# Callers of this routine should make sure to use comma to
|
|
648
|
+
# separate format argments rather than %. Otherwise it seems that
|
|
649
|
+
# if the string you want to print has format specifier, which
|
|
650
|
+
# could happen if you are trying to show say a source-code line
|
|
651
|
+
# with "puts" or "print" in it, this print routine will give an
|
|
652
|
+
# error saying it is looking for more arguments.
|
|
653
|
+
def print(*args)
|
|
654
|
+
@interface.print(*args)
|
|
655
|
+
@interface.print "\n"
|
|
656
|
+
end
|
|
657
|
+
|
|
658
|
+
# confirm is called before performing a dangerous action. In
|
|
659
|
+
# control processor we always return "yes" or "y".
|
|
660
|
+
def confirm(*args)
|
|
661
|
+
'y'
|
|
662
|
+
end
|
|
663
|
+
|
|
664
|
+
def context
|
|
665
|
+
nil
|
|
666
|
+
end
|
|
667
|
+
|
|
668
|
+
def file
|
|
669
|
+
errmsg "No filename given."
|
|
670
|
+
throw :debug_error
|
|
671
|
+
end
|
|
672
|
+
end # State
|
|
673
|
+
end
|
|
674
|
+
end
|