trepanning 0.1.0 → 0.1.1
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 +4 -0
- data/ChangeLog +1279 -235
- data/Makefile +13 -0
- data/NEWS +30 -0
- data/Rakefile +50 -14
- data/app/.gitignore +1 -0
- data/app/breakpoint.rb +7 -2
- data/app/brkptmgr.rb +12 -0
- data/app/cmd_parse.citrus +167 -0
- data/app/cmd_parse.kpeg +221 -0
- data/app/cmd_parse.rb +201 -0
- data/app/cmd_parser.rb +1914 -0
- data/app/complete.rb +79 -0
- data/app/condition.rb +1 -1
- data/app/core.rb +7 -11
- data/app/default.rb +1 -1
- data/app/disassemble.rb +3 -2
- data/app/file.rb +12 -36
- data/app/frame.rb +3 -2
- data/app/irb.rb +9 -5
- data/app/iseq.rb +46 -0
- data/app/options.rb +6 -30
- data/app/run.rb +5 -2
- data/app/util.rb +1 -2
- data/app/yarv.rb +11 -1
- data/bin/.gitignore +1 -0
- data/bin/trepan +6 -6
- data/data/.gitignore +1 -0
- data/interface/.gitignore +1 -0
- data/interface/base_intf.rb +9 -5
- data/interface/comcodes.rb +10 -8
- data/interface/user.rb +76 -17
- data/io/.gitignore +1 -0
- data/io/input.rb +39 -15
- data/io/tcpclient.rb +7 -1
- data/io/tcpfns.rb +5 -3
- data/io/tcpserver.rb +13 -10
- data/lib/.gitignore +1 -0
- data/lib/trepanning.rb +50 -13
- data/processor/.gitignore +1 -0
- data/processor/Makefile +7 -0
- data/processor/breakpoint.rb +7 -2
- data/processor/command/.gitignore +1 -0
- data/processor/command/Makefile +7 -0
- data/processor/command/alias.rb +2 -2
- data/processor/command/backtrace.rb +4 -0
- data/processor/command/base/cmd.rb +45 -2
- data/processor/command/base/subcmd.rb +4 -2
- data/processor/command/base/submgr.rb +23 -19
- data/processor/command/base/subsubcmd.rb +23 -1
- data/processor/command/base/subsubmgr.rb +13 -0
- data/processor/command/break.rb +34 -29
- data/processor/command/complete.rb +37 -0
- data/processor/command/condition.rb +2 -0
- data/processor/command/continue.rb +15 -18
- data/processor/command/disassemble.rb +5 -0
- data/processor/command/down.rb +1 -1
- data/processor/command/eval.rb +70 -0
- data/processor/command/exit.rb +4 -1
- data/processor/command/finish.rb +6 -4
- data/processor/command/frame.rb +6 -3
- data/processor/command/help.rb +97 -54
- data/processor/command/help/.gitignore +1 -0
- data/processor/command/help/README +10 -0
- data/processor/command/help/command.txt +48 -0
- data/processor/command/help/filename.txt +40 -0
- data/processor/command/help/location.txt +37 -0
- data/processor/command/info_subcmd/.gitignore +1 -0
- data/processor/command/info_subcmd/breakpoints.rb +9 -9
- data/processor/command/info_subcmd/{file.rb → files.rb} +92 -27
- data/processor/command/info_subcmd/frame.rb +41 -15
- data/processor/command/info_subcmd/iseq.rb +39 -17
- data/processor/command/info_subcmd/program.rb +2 -8
- data/processor/command/info_subcmd/registers.rb +12 -10
- data/processor/command/info_subcmd/registers_subcmd/.gitignore +1 -0
- data/processor/command/info_subcmd/ruby.rb +60 -0
- data/processor/command/irb.rb +26 -3
- data/processor/command/kill.rb +21 -10
- data/processor/command/list.rb +1 -1
- data/processor/command/macro.rb +37 -23
- data/processor/command/pr.rb +1 -1
- data/processor/command/reload.rb +4 -0
- data/processor/command/reload_subcmd/.gitignore +1 -0
- data/processor/command/restart.rb +9 -9
- data/processor/command/save.rb +29 -36
- data/processor/command/set_subcmd/.gitignore +1 -0
- data/processor/command/set_subcmd/auto_subcmd/.gitignore +1 -0
- data/processor/command/set_subcmd/confirm.rb +23 -0
- data/processor/command/set_subcmd/debug_subcmd/.gitignore +1 -0
- data/processor/command/set_subcmd/different.rb +2 -0
- data/processor/command/set_subcmd/events.rb +2 -0
- data/processor/command/set_subcmd/max.rb +9 -12
- data/processor/command/set_subcmd/max_subcmd/.gitignore +1 -0
- data/processor/command/set_subcmd/substitute_subcmd/.gitignore +1 -0
- data/processor/command/set_subcmd/trace.rb +7 -13
- data/processor/command/set_subcmd/trace_subcmd/.gitignore +1 -0
- data/processor/command/set_subcmd/trace_subcmd/buffer.rb +12 -27
- data/processor/command/set_subcmd/trace_subcmd/print.rb +10 -8
- data/processor/command/set_subcmd/trace_subcmd/var.rb +6 -10
- data/processor/command/show.rb +12 -1
- data/processor/command/show_subcmd/.gitignore +1 -0
- data/processor/command/show_subcmd/alias.rb +11 -15
- data/processor/command/show_subcmd/auto_subcmd/.gitignore +1 -0
- data/processor/command/show_subcmd/basename.rb +1 -9
- data/processor/command/show_subcmd/confirm.rb +25 -0
- data/processor/command/show_subcmd/debug_subcmd/.gitignore +1 -0
- data/processor/command/show_subcmd/macro.rb +32 -14
- data/processor/command/show_subcmd/max_subcmd/.gitignore +1 -0
- data/processor/command/show_subcmd/trace_subcmd/.gitignore +1 -0
- data/processor/command/show_subcmd/trace_subcmd/buffer.rb +11 -31
- data/processor/command/show_subcmd/trace_subcmd/print.rb +4 -20
- data/processor/command/source.rb +7 -1
- data/processor/command/up.rb +7 -4
- data/processor/default.rb +3 -1
- data/processor/eval.rb +13 -0
- data/processor/eventbuf.rb +3 -2
- data/processor/frame.rb +19 -0
- data/processor/help.rb +20 -0
- data/processor/load_cmds.rb +143 -24
- data/processor/location.rb +61 -10
- data/processor/main.rb +30 -11
- data/processor/mock.rb +5 -3
- data/processor/msg.rb +17 -0
- data/processor/running.rb +1 -1
- data/processor/subcmd.rb +3 -2
- data/processor/validate.rb +173 -185
- data/sample/.gitignore +1 -0
- data/sample/list-terminal-colors.rb +139 -0
- data/sample/rocky-dot-trepanrc +14 -0
- data/sample/rocky-trepan-colors.rb +47 -0
- data/test/Makefile +7 -0
- data/test/data/.gitignore +1 -0
- data/test/data/debugger-stop.cmd +3 -0
- data/test/data/debugger-stop.right +5 -0
- data/test/data/fname-with-blank.right +0 -3
- data/test/data/quit.right +0 -1
- data/test/data/quit2.cmd +6 -0
- data/test/data/quit2.right +3 -0
- data/test/data/testing.cmd +1 -0
- data/test/example/.gitignore +1 -0
- data/test/example/debugger-stop.rb +14 -0
- data/test/functional/.gitignore +2 -0
- data/test/functional/fn_helper.rb +7 -9
- data/test/functional/test-break-long.rb +7 -7
- data/test/functional/test-break.rb +7 -7
- data/test/functional/test-condition.rb +4 -4
- data/test/functional/test-delete.rb +6 -5
- data/test/functional/test-eval.rb +115 -0
- data/test/functional/test-raise.rb +1 -1
- data/test/functional/test-return.rb +1 -1
- data/test/integration/.gitignore +2 -0
- data/test/integration/helper.rb +6 -3
- data/test/integration/test-debugger-stop.rb +22 -0
- data/test/integration/test-quit.rb +8 -0
- data/test/unit/.gitignore +1 -0
- data/test/unit/Makefile +7 -0
- data/test/unit/test-app-brkpt.rb +0 -1
- data/test/unit/test-app-cmd_parse.rb +107 -0
- data/test/unit/test-app-cmd_parser.rb +22 -0
- data/test/unit/test-app-complete.rb +38 -0
- data/test/unit/test-app-condition.rb +20 -0
- data/test/unit/test-app-iseq.rb +31 -0
- data/test/unit/test-app-options.rb +9 -1
- data/test/unit/test-app-util.rb +0 -1
- data/test/unit/test-base-cmd.rb +46 -0
- data/test/unit/test-base-subcmd.rb +11 -2
- data/test/unit/test-base-submgr.rb +23 -0
- data/test/unit/test-base-subsubcmd.rb +20 -0
- data/test/unit/test-cmd-break.rb +22 -23
- data/test/unit/test-cmd-help.rb +4 -0
- data/test/unit/test-completion.rb +43 -0
- data/test/unit/test-io-tcpclient.rb +3 -2
- data/test/unit/test-proc-load_cmds.rb +10 -1
- data/test/unit/test-proc-location.rb +39 -0
- data/test/unit/test-proc-main.rb +1 -1
- data/test/unit/test-proc-validate.rb +47 -31
- data/trepanning.gemspec +45 -0
- metadata +247 -179
- data/app/core.rb-consider +0 -198
- data/test/functional/tmp/b3.rb +0 -5
- data/test/functional/tmp/immediate-bug1.rb +0 -9
data/app/yarv.rb
CHANGED
@@ -107,6 +107,10 @@ module CodeRay
|
|
107
107
|
state = :expect_another_operand
|
108
108
|
if match = scan(/^(\d+)/)
|
109
109
|
tokens << [match, :integer]
|
110
|
+
if match = scan(/^[.]{2}\d+/)
|
111
|
+
tokens << ['..', :operator]
|
112
|
+
tokens << [match[2..-1], :integer]
|
113
|
+
end
|
110
114
|
elsif match = scan(/\/.*\//)
|
111
115
|
# Really a regular expression
|
112
116
|
tokens << [match, :entity]
|
@@ -118,6 +122,9 @@ module CodeRay
|
|
118
122
|
tokens << [match, :pre_constant]
|
119
123
|
elsif match = scan(/nil|true|false/)
|
120
124
|
tokens << [match, :pre_constant]
|
125
|
+
elsif match = scan(/block in (?:<.+>|[^,]+)/)
|
126
|
+
tokens << ["block in ", :variable]
|
127
|
+
tokens << [match['block in '.size..-1], :content]
|
121
128
|
elsif match = scan(/[A-Za-z_][_A-Za-z0-9?!]*/)
|
122
129
|
tokens << [match, :variable]
|
123
130
|
elsif match = scan(/^#[^, \n]*/)
|
@@ -157,7 +164,6 @@ if __FILE__ == $0
|
|
157
164
|
require 'term/ansicolor'
|
158
165
|
ruby_scanner = CodeRay.scanner :yarv
|
159
166
|
string='
|
160
|
-
0045 opt_regexpmatch1 /^-e$/
|
161
167
|
0000 trace 1 ( 9)
|
162
168
|
0002 putnil
|
163
169
|
0003 putstring "irb"
|
@@ -174,6 +180,10 @@ string='
|
|
174
180
|
0029 setinlinecache <ic:2>
|
175
181
|
0031 putstring "/usr/local/bin/irb"
|
176
182
|
0033 send :start, 1, nil, 0, <ic:3>
|
183
|
+
0026 putobject 0..1
|
184
|
+
0030 send :map, 0, block in <top gcd.rb>, 0, <ic:3>
|
185
|
+
0177 send :catch, 1, block in start, 8, <ic:23>
|
186
|
+
0045 opt_regexpmatch1 /^-e$/
|
177
187
|
'
|
178
188
|
yarv_scanner = CodeRay.scanner :yarv
|
179
189
|
tokens = yarv_scanner.tokenize(string)
|
data/bin/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
/*~
|
data/bin/trepan
CHANGED
@@ -48,18 +48,18 @@ if File.basename(__FILE__) == File.basename($0)
|
|
48
48
|
end
|
49
49
|
end
|
50
50
|
|
51
|
-
program_to_debug = ARGV.shift
|
52
|
-
program_to_debug = whence_file(
|
53
|
-
File.exist?(
|
51
|
+
program_to_debug = (Trepan::PROG_UNRESOLVED_SCRIPT = ARGV.shift).dup
|
52
|
+
program_to_debug = whence_file(Trepan::PROG_UNRESOLVED_SCRIPT) unless
|
53
|
+
File.exist?(Trepan::PROG_UNRESOLVED_SCRIPT)
|
54
54
|
Trepan::PROG_SCRIPT = program_to_debug
|
55
55
|
|
56
|
-
# Set global so others may use this debugger.
|
57
|
-
|
58
56
|
opts = {}
|
59
|
-
%w(cmdfiles initial_dir host nx port server
|
57
|
+
%w(cmdfiles highlight initial_dir host nx port readline server
|
58
|
+
).each do |opt|
|
60
59
|
opts[opt.to_sym] = options[opt.to_sym]
|
61
60
|
end
|
62
61
|
|
62
|
+
# Set global so others may use this debugger.
|
63
63
|
$trepan = Trepan.new(opts)
|
64
64
|
debug_program($trepan, Trepan::RUBY_PATH,
|
65
65
|
File.expand_path(program_to_debug))
|
data/data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
/*~
|
@@ -0,0 +1 @@
|
|
1
|
+
/*~
|
data/interface/base_intf.rb
CHANGED
@@ -16,7 +16,7 @@ class Trepan
|
|
16
16
|
# - another interface in another process or computer
|
17
17
|
class Interface
|
18
18
|
|
19
|
-
attr_accessor :interactive, :input, :output
|
19
|
+
attr_accessor :history_io, :history_save, :interactive, :input, :output
|
20
20
|
|
21
21
|
unless defined?(YES)
|
22
22
|
YES = %w(y yes oui si yep ja)
|
@@ -25,10 +25,14 @@ class Trepan
|
|
25
25
|
end
|
26
26
|
|
27
27
|
def initialize(inp=nil, out=nil, opts={})
|
28
|
-
@
|
29
|
-
@
|
30
|
-
@
|
31
|
-
@
|
28
|
+
@histfile = nil
|
29
|
+
@history_io = nil
|
30
|
+
@history_save = false
|
31
|
+
@histsize = nil
|
32
|
+
@input = inp || STDIN
|
33
|
+
@interactive = false
|
34
|
+
@opts = opts
|
35
|
+
@output = out || STDOUT
|
32
36
|
end
|
33
37
|
|
34
38
|
# Closes all input and/or output.
|
data/interface/comcodes.rb
CHANGED
@@ -6,13 +6,15 @@ module Trepanning
|
|
6
6
|
# Most of these go from debugged process to front-end
|
7
7
|
# client interface. COMMAND goes the other way.
|
8
8
|
module RemoteCommunication
|
9
|
-
PRINT
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
9
|
+
unless defined?(PRINT)
|
10
|
+
PRINT = '.'
|
11
|
+
COMMAND = 'C'
|
12
|
+
CONFIRM_TRUE = 'Y'
|
13
|
+
CONFIRM_FALSE = 'N'
|
14
|
+
CONFIRM_REPLY = '?'
|
15
|
+
QUIT = 'q'
|
16
|
+
PROMPT = 'p'
|
17
|
+
RESTART = 'r'
|
18
|
+
end
|
17
19
|
end
|
18
20
|
end
|
data/interface/user.rb
CHANGED
@@ -1,37 +1,47 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
|
-
# Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
|
2
|
+
# Copyright (C) 2010, 2011 Rocky Bernstein <rockyb@rubyforge.net>
|
3
3
|
|
4
|
-
# Interface when communicating with the user
|
5
|
-
# the debugged program.
|
4
|
+
# Interface when communicating with the user.
|
6
5
|
|
7
6
|
# Our local modules
|
8
|
-
|
9
7
|
require_relative 'base_intf'
|
10
8
|
require_relative '../io/input'
|
11
9
|
|
12
|
-
#
|
13
|
-
|
14
|
-
# Interface when communicating with the user in the same
|
15
|
-
# process as the debugged program.
|
10
|
+
# Interface when communicating with the user.
|
16
11
|
class Trepan::UserInterface < Trepan::Interface
|
17
12
|
|
18
|
-
|
13
|
+
DEFAULT_USER_OPTS = {
|
14
|
+
:readline => true, # Try to use GNU Readline?
|
15
|
+
|
16
|
+
# The below are only used if we want and have readline support.
|
17
|
+
# See method Trepan::GNU_readline? below.
|
18
|
+
:histsize => 256, # Use gdb's default setting
|
19
|
+
:file_history => '.trepan_hist', # where history file lives
|
20
|
+
# Note a directory will
|
21
|
+
# be appended
|
22
|
+
:history_save => true # do we save the history?
|
23
|
+
} unless defined?(DEFAULT_USER_OPTS)
|
19
24
|
|
20
25
|
def initialize(inp=nil, out=nil, opts={})
|
21
26
|
super(inp, out, opts)
|
27
|
+
@opts = DEFAULT_USER_OPTS.merge(opts)
|
22
28
|
@input = if inp.class.ancestors.member?(Trepan::InputBase)
|
23
29
|
inp
|
24
30
|
else
|
25
|
-
Trepan::UserInput.open(inp)
|
31
|
+
Trepan::UserInput.open(inp, {:readline => opts[:readline]})
|
26
32
|
end
|
33
|
+
if Trepan::GNU_readline? && @opts[:complete]
|
34
|
+
Readline.completion_proc = @opts[:complete]
|
35
|
+
read_history
|
36
|
+
end
|
37
|
+
at_exit { finalize }
|
27
38
|
end
|
28
39
|
|
29
|
-
# Closes both input and output
|
30
|
-
|
31
40
|
# Called when a dangerous action is about to be done, to make
|
32
41
|
# sure it's okay. Expect a yes/no answer to `prompt' which is printed,
|
33
42
|
# suffixed with a question mark and the default value. The user
|
34
43
|
# response converted to a boolean is returned.
|
44
|
+
# FIXME: make common routine for this and server.rb
|
35
45
|
def confirm(prompt, default)
|
36
46
|
default_str = default ? 'Y/n' : 'N/y'
|
37
47
|
while true do
|
@@ -50,19 +60,68 @@ class Trepan::UserInterface < Trepan::Interface
|
|
50
60
|
return YES.member?(response)
|
51
61
|
end
|
52
62
|
|
63
|
+
# Read a saved Readline history file into Readline. The history
|
64
|
+
# file will be created if it doesn't already exist.
|
65
|
+
# Much of this code follows what's done in ruby-debug.
|
66
|
+
def read_history
|
67
|
+
unless @histfile
|
68
|
+
dirname = ENV['HOME'] || ENV['HOMEPATH'] || File.expand_path('~')
|
69
|
+
@histfile = File.join(dirname, @opts[:file_history])
|
70
|
+
end
|
71
|
+
@histsize ||= (ENV['HISTSIZE'] ? ENV['HISTSIZE'].to_i : @opts[:histsize])
|
72
|
+
Readline.completion_proc = @opts[:complete]
|
73
|
+
if File.exists?(@histfile)
|
74
|
+
lines = IO::readlines(@histfile).last(@histsize).collect do
|
75
|
+
|line| line.chomp
|
76
|
+
end
|
77
|
+
Readline::HISTORY.push(*lines)
|
78
|
+
@history_io = File.new(@histfile, "a")
|
79
|
+
else
|
80
|
+
@history_io = File.new(@histfile, "w")
|
81
|
+
end
|
82
|
+
@history_io.sync = true
|
83
|
+
@history_save = @opts[:history_save]
|
84
|
+
end
|
85
|
+
|
86
|
+
def save_history
|
87
|
+
if @histfile
|
88
|
+
lines = Readline::HISTORY.to_a
|
89
|
+
lines = lines[-@histsize, @histsize] if lines.size > @histsize
|
90
|
+
begin
|
91
|
+
open(@histfile, 'w') do |file|
|
92
|
+
Readline::HISTORY.to_a.last(@histsize).each do |line|
|
93
|
+
file.puts line
|
94
|
+
end
|
95
|
+
end if defined?(@history_save) and @history_save
|
96
|
+
rescue
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
53
101
|
def finalize(last_wishes=nil)
|
54
|
-
# print exit annotation
|
55
|
-
|
102
|
+
# ?? print gdb-style exit annotation if annotate = 2?
|
103
|
+
if Trepan::GNU_readline? && @history_save
|
104
|
+
save_history
|
105
|
+
end
|
56
106
|
super
|
57
107
|
end
|
58
108
|
|
59
109
|
def interactive? ; @input.interactive? end
|
60
110
|
|
61
111
|
def read_command(prompt='')
|
62
|
-
|
63
|
-
# FIXME: Do something with history?
|
64
|
-
return line
|
112
|
+
readline(prompt)
|
65
113
|
end
|
114
|
+
|
115
|
+
def readline(prompt='')
|
116
|
+
@output.flush
|
117
|
+
if @input.line_edit && @opts[:readline]
|
118
|
+
@input.readline(prompt)
|
119
|
+
else
|
120
|
+
@output.write(prompt) if prompt and prompt.size > 0
|
121
|
+
@input.readline
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
66
125
|
end
|
67
126
|
|
68
127
|
# Demo
|
data/io/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
/*~
|
data/io/input.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
|
-
# Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
|
2
|
+
# Copyright (C) 2010, 2011 Rocky Bernstein <rockyb@rubyforge.net>
|
3
3
|
|
4
4
|
# Debugger user/command-oriented input possibly attached to IO-style
|
5
5
|
# input or GNU Readline.
|
@@ -13,10 +13,14 @@ class Trepan
|
|
13
13
|
# input or GNU Readline.
|
14
14
|
class UserInput < Trepan::InputBase
|
15
15
|
|
16
|
+
@@readline_finalized = false
|
17
|
+
|
16
18
|
def initialize(inp, opts={})
|
17
|
-
@opts
|
18
|
-
@input
|
19
|
-
@eof
|
19
|
+
@opts = DEFAULT_OPTS.merge(opts)
|
20
|
+
@input = inp || STDIN
|
21
|
+
@eof = false
|
22
|
+
@line_edit = @opts[:line_edit]
|
23
|
+
@use_readline = @opts[:readline]
|
20
24
|
end
|
21
25
|
|
22
26
|
def closed?; @input.closed? end
|
@@ -25,20 +29,24 @@ class Trepan
|
|
25
29
|
def interactive?
|
26
30
|
@input.respond_to?(:isatty) && @input.isatty
|
27
31
|
end
|
28
|
-
|
29
32
|
# Read a line of input. EOFError will be raised on EOF.
|
30
|
-
|
31
|
-
# Note that we don't support prompting first. Instead, arrange
|
32
|
-
# to call Trepan::Output.write() first with the prompt.
|
33
|
-
def readline
|
34
|
-
# FIXME we don't do command completion.
|
33
|
+
def readline(prompt='')
|
35
34
|
raise EOFError if eof?
|
36
35
|
begin
|
37
|
-
|
38
|
-
|
39
|
-
|
36
|
+
if @line_edit && @use_readline
|
37
|
+
line = Readline.readline(prompt, true)
|
38
|
+
else
|
39
|
+
line = @input.gets
|
40
|
+
end
|
41
|
+
rescue Interrupt
|
42
|
+
return ''
|
43
|
+
rescue EOFError
|
44
|
+
rescue => e
|
45
|
+
puts $!.backtrace
|
46
|
+
puts "Exception caught #{e.inspect}"
|
40
47
|
@eof = true
|
41
48
|
end
|
49
|
+
@eof = !line
|
42
50
|
raise EOFError if eof?
|
43
51
|
return line
|
44
52
|
end
|
@@ -52,17 +60,33 @@ class Trepan
|
|
52
60
|
def open(inp=nil, opts={})
|
53
61
|
inp ||= STDIN
|
54
62
|
inp = File.new(inp, 'r') if inp.is_a?(String)
|
55
|
-
opts[:line_edit] =
|
63
|
+
opts[:line_edit] = @line_edit =
|
56
64
|
inp.respond_to?(:isatty) && inp.isatty && Trepan::GNU_readline?
|
57
65
|
self.new(inp, opts)
|
58
66
|
end
|
67
|
+
|
68
|
+
def finalize
|
69
|
+
if defined?(RbReadline) && !@@readline_finalized
|
70
|
+
begin
|
71
|
+
RbReadline.rl_cleanup_after_signal()
|
72
|
+
rescue
|
73
|
+
end
|
74
|
+
begin
|
75
|
+
RbReadline.rl_deprep_terminal()
|
76
|
+
rescue
|
77
|
+
end
|
78
|
+
@@readline_finalized = true
|
79
|
+
end
|
80
|
+
end
|
59
81
|
end
|
60
82
|
end
|
61
83
|
end
|
62
84
|
|
63
85
|
def Trepan::GNU_readline?
|
64
86
|
begin
|
65
|
-
|
87
|
+
return @have_readline unless @have_readline.nil?
|
88
|
+
@have_readline = require 'readline'
|
89
|
+
at_exit { Trepan::UserInput::finalize }
|
66
90
|
return true
|
67
91
|
rescue LoadError
|
68
92
|
return false
|
data/io/tcpclient.rb
CHANGED
@@ -19,6 +19,8 @@ class Trepan
|
|
19
19
|
:port => 1027, # Arbitrary non-privileged port
|
20
20
|
}
|
21
21
|
|
22
|
+
attr_reader :state
|
23
|
+
|
22
24
|
def initialize(opts={})
|
23
25
|
@opts = CLIENT_SOCKET_OPTS.merge(opts)
|
24
26
|
@addr = nil
|
@@ -33,7 +35,11 @@ class Trepan
|
|
33
35
|
def close
|
34
36
|
@state = :closing
|
35
37
|
@inout.close if @inout
|
36
|
-
@state = :
|
38
|
+
@state = :disconnected
|
39
|
+
end
|
40
|
+
|
41
|
+
def disconnected?
|
42
|
+
:disconnected == @state
|
37
43
|
end
|
38
44
|
|
39
45
|
def open(opts={})
|
data/io/tcpfns.rb
CHANGED
@@ -5,9 +5,11 @@
|
|
5
5
|
module Trepanning
|
6
6
|
module TCPPacking
|
7
7
|
|
8
|
-
TCP_MAX_PACKET
|
9
|
-
|
10
|
-
|
8
|
+
unless defined?(TCP_MAX_PACKET)
|
9
|
+
TCP_MAX_PACKET = 8192 # Largest size for a recv
|
10
|
+
LOG_MAX_MSG = Math.log10(TCP_MAX_PACKET).ceil
|
11
|
+
end
|
12
|
+
|
11
13
|
def pack_msg(msg)
|
12
14
|
fmt = '%%%dd' % LOG_MAX_MSG # A funny way of writing: '%4d'
|
13
15
|
(fmt % msg.size) + msg
|
data/io/tcpserver.rb
CHANGED
@@ -12,16 +12,18 @@ class Trepan
|
|
12
12
|
class TCPDbgServer < Trepan::InOutBase
|
13
13
|
|
14
14
|
include Trepanning::TCPPacking
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
15
|
+
|
16
|
+
unless defined?(SERVER_SOCKET_OPTS)
|
17
|
+
DEFAULT_INIT_OPTS = {:open => true}
|
18
|
+
|
19
|
+
SERVER_SOCKET_OPTS = {
|
20
|
+
:host => Trepan::DEFAULT_SETTINGS[:host],
|
21
|
+
:port => Trepan::DEFAULT_SETTINGS[:port], # A non-privileged port
|
22
|
+
:timeout => 5, # FIXME: not used
|
23
|
+
:reuse => true, # FIXME: not used. Allow port to be resued on close?
|
24
|
+
# Python has: 'posix' == os.name
|
25
|
+
}
|
26
|
+
end
|
25
27
|
|
26
28
|
attr_reader :state
|
27
29
|
|
@@ -32,6 +34,7 @@ class Trepan
|
|
32
34
|
@state = :disconnected
|
33
35
|
@port = nil # Current port in use
|
34
36
|
@host = nil # current host in use
|
37
|
+
@line_edit = false
|
35
38
|
open(@opts) if @opts[:open]
|
36
39
|
end
|
37
40
|
|
data/lib/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
/*~
|
data/lib/trepanning.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
#
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
# Copyright (C) 2010, 2011 Rocky Bernstein <rockyb@rubyforge.net>
|
3
4
|
require 'trace' # Trace filtering
|
4
|
-
require 'thread_frame'
|
5
|
+
require 'thread_frame' # Stack frame introspection and more.
|
6
|
+
require_relative '../app/complete' # command completion
|
5
7
|
require_relative '../app/core' # core event-handling mechanism
|
6
8
|
require_relative '../app/default' # default debugger settings
|
7
9
|
require_relative '../interface/user' # user interface (includes I/O)
|
@@ -23,14 +25,15 @@ ISEQS__ = {} unless
|
|
23
25
|
|
24
26
|
class Trepan
|
25
27
|
|
28
|
+
attr_reader :completion_proc # GNU Readline completion proc
|
26
29
|
attr_accessor :core # access to Trepan::Core instance
|
27
30
|
attr_accessor :intf # Array. The way the outside world
|
28
31
|
# interfaces with us. An array, so that
|
29
32
|
# interfaces can be stacked.
|
30
|
-
|
31
|
-
#
|
32
|
-
|
33
|
-
#
|
33
|
+
attr_accessor :restart_argv # How to restart us, empty or nil.
|
34
|
+
# Note: restart_argv is typically C's
|
35
|
+
# **argv, not Ruby's ARGV. So
|
36
|
+
# restart_argv[0] is $0.
|
34
37
|
attr_reader :settings # Hash[:symbol] of things you can configure
|
35
38
|
attr_accessor :trace_filter # Procs/Methods we ignore.
|
36
39
|
|
@@ -45,11 +48,15 @@ class Trepan
|
|
45
48
|
@input = @settings[:input] || STDIN
|
46
49
|
@output = @settings[:output] || STDOUT
|
47
50
|
|
51
|
+
@completion_proc = method(:completion_method)
|
52
|
+
|
48
53
|
@intf =
|
49
54
|
if @settings[:server]
|
55
|
+
@completion_proc = nil
|
50
56
|
opts = Trepan::ServerInterface::DEFAULT_INIT_CONNECTION_OPTS.dup
|
51
57
|
opts[:port] = @settings[:port] if @settings[:port]
|
52
58
|
opts[:host] = @settings[:host] if @settings[:host]
|
59
|
+
opts[:readline] = false
|
53
60
|
puts("starting debugger in out-of-process mode port at " +
|
54
61
|
"#{opts[:host]}:#{opts[:port]}")
|
55
62
|
[Trepan::ServerInterface.new(nil, nil, opts)]
|
@@ -57,9 +64,13 @@ class Trepan
|
|
57
64
|
opts = Trepan::ClientInterface::DEFAULT_INIT_CONNECTION_OPTS.dup
|
58
65
|
opts[:port] = @settings[:port] if @settings[:port]
|
59
66
|
opts[:host] = @settings[:host] if @settings[:host]
|
67
|
+
opts[:complete] = @completion_proc
|
68
|
+
opts[:readline] ||= @settings[:readline]
|
60
69
|
[Trepan::ClientInterface.new(nil, nil, nil, nil, opts)]
|
61
70
|
else
|
62
|
-
|
71
|
+
opts = {:complete => @completion_proc,
|
72
|
+
:readline => @settings[:readline]}
|
73
|
+
[Trepan::UserInterface.new(@input, @output, opts)]
|
63
74
|
end
|
64
75
|
|
65
76
|
process_cmdfile_setting(@settings)
|
@@ -94,8 +105,6 @@ class Trepan
|
|
94
105
|
|
95
106
|
# Run user debugger command startup files.
|
96
107
|
add_startup_files unless @settings[:nx]
|
97
|
-
add_command_file(@settings[:restore_profile]) if
|
98
|
-
@settings[:restore_profile] && File.readable?(@settings[:restore_profile])
|
99
108
|
|
100
109
|
at_exit do
|
101
110
|
clear_trace_func
|
@@ -104,6 +113,29 @@ class Trepan
|
|
104
113
|
th.exec_event_tracing = false
|
105
114
|
end
|
106
115
|
|
116
|
+
# The method is called when we want to do debugger command completion
|
117
|
+
# such as called from GNU Readline with <TAB>.
|
118
|
+
def completion_method(last_token, leading=Readline.line_buffer)
|
119
|
+
completion = @core.processor.complete(leading, last_token)
|
120
|
+
if 1 == completion.size
|
121
|
+
completion_token = completion[0]
|
122
|
+
if last_token.end_with?(' ')
|
123
|
+
if last_token.rstrip == completion_token
|
124
|
+
# There is nothing more to complete
|
125
|
+
[]
|
126
|
+
else
|
127
|
+
[]
|
128
|
+
end
|
129
|
+
else
|
130
|
+
[completion_token]
|
131
|
+
end
|
132
|
+
else
|
133
|
+
# We have multiple completions. Get the last token so that will
|
134
|
+
# be presented as a list of completions.
|
135
|
+
completion
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
107
139
|
# To call from inside a Ruby program, there is one-time setup that
|
108
140
|
# needs to be done first:
|
109
141
|
# require 'trepanning'
|
@@ -148,6 +180,10 @@ class Trepan
|
|
148
180
|
@core.processor.hidelevels[Thread.current] =
|
149
181
|
RubyVM::ThreadFrame.current.stack_size
|
150
182
|
end
|
183
|
+
# unless defined?(PROG_UNRESOLVED_SCRIPT)
|
184
|
+
# # We may later do more sophisticated things...
|
185
|
+
# Trepan.const_set('PROG_UNRESOLVED_SCRIPT', RubyVM::OS_ARGV.index($0) ? $0 : nil)
|
186
|
+
# end
|
151
187
|
th = Thread.current
|
152
188
|
if block
|
153
189
|
start
|
@@ -193,11 +229,10 @@ class Trepan
|
|
193
229
|
return
|
194
230
|
else
|
195
231
|
stderr.puts "Command file '#{cmdfile}' does not exist."
|
196
|
-
stderr.puts caller
|
197
232
|
return
|
198
233
|
end
|
199
234
|
end
|
200
|
-
@intf << Trepan::ScriptInterface.new(cmdfile
|
235
|
+
@intf << Trepan::ScriptInterface.new(cmdfile)
|
201
236
|
end
|
202
237
|
|
203
238
|
def add_startup_files()
|
@@ -246,8 +281,9 @@ class Trepan
|
|
246
281
|
opts = {:hide_stack => false}.merge(opts)
|
247
282
|
unless defined?($trepanning) && $trepanning.is_a?(Trepan)
|
248
283
|
$trepanning = Trepan.new(opts)
|
249
|
-
$trepanning.trace_filter << self.method(:debug)
|
250
284
|
end
|
285
|
+
tf = $trepanning.trace_filter
|
286
|
+
tf << self.method(:debugger) unless tf.member? self.method(:debugger)
|
251
287
|
$trepanning.debugger(opts, &block)
|
252
288
|
end
|
253
289
|
|
@@ -267,8 +303,9 @@ module Kernel
|
|
267
303
|
opts = {:hide_stack => false}.merge(opts)
|
268
304
|
unless defined?($trepanning) && $trepanning.is_a?(Trepan)
|
269
305
|
$trepanning = Trepan.new(opts)
|
270
|
-
$trepanning.trace_filter << self.method(:debugger)
|
271
306
|
end
|
307
|
+
tf = $trepanning.trace_filter
|
308
|
+
tf << self.method(:debugger) unless tf.member? self.method(:debugger)
|
272
309
|
$trepanning.debugger(opts)
|
273
310
|
end
|
274
311
|
end
|