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.
Files changed (181) hide show
  1. data/.gitignore +4 -0
  2. data/ChangeLog +1279 -235
  3. data/Makefile +13 -0
  4. data/NEWS +30 -0
  5. data/Rakefile +50 -14
  6. data/app/.gitignore +1 -0
  7. data/app/breakpoint.rb +7 -2
  8. data/app/brkptmgr.rb +12 -0
  9. data/app/cmd_parse.citrus +167 -0
  10. data/app/cmd_parse.kpeg +221 -0
  11. data/app/cmd_parse.rb +201 -0
  12. data/app/cmd_parser.rb +1914 -0
  13. data/app/complete.rb +79 -0
  14. data/app/condition.rb +1 -1
  15. data/app/core.rb +7 -11
  16. data/app/default.rb +1 -1
  17. data/app/disassemble.rb +3 -2
  18. data/app/file.rb +12 -36
  19. data/app/frame.rb +3 -2
  20. data/app/irb.rb +9 -5
  21. data/app/iseq.rb +46 -0
  22. data/app/options.rb +6 -30
  23. data/app/run.rb +5 -2
  24. data/app/util.rb +1 -2
  25. data/app/yarv.rb +11 -1
  26. data/bin/.gitignore +1 -0
  27. data/bin/trepan +6 -6
  28. data/data/.gitignore +1 -0
  29. data/interface/.gitignore +1 -0
  30. data/interface/base_intf.rb +9 -5
  31. data/interface/comcodes.rb +10 -8
  32. data/interface/user.rb +76 -17
  33. data/io/.gitignore +1 -0
  34. data/io/input.rb +39 -15
  35. data/io/tcpclient.rb +7 -1
  36. data/io/tcpfns.rb +5 -3
  37. data/io/tcpserver.rb +13 -10
  38. data/lib/.gitignore +1 -0
  39. data/lib/trepanning.rb +50 -13
  40. data/processor/.gitignore +1 -0
  41. data/processor/Makefile +7 -0
  42. data/processor/breakpoint.rb +7 -2
  43. data/processor/command/.gitignore +1 -0
  44. data/processor/command/Makefile +7 -0
  45. data/processor/command/alias.rb +2 -2
  46. data/processor/command/backtrace.rb +4 -0
  47. data/processor/command/base/cmd.rb +45 -2
  48. data/processor/command/base/subcmd.rb +4 -2
  49. data/processor/command/base/submgr.rb +23 -19
  50. data/processor/command/base/subsubcmd.rb +23 -1
  51. data/processor/command/base/subsubmgr.rb +13 -0
  52. data/processor/command/break.rb +34 -29
  53. data/processor/command/complete.rb +37 -0
  54. data/processor/command/condition.rb +2 -0
  55. data/processor/command/continue.rb +15 -18
  56. data/processor/command/disassemble.rb +5 -0
  57. data/processor/command/down.rb +1 -1
  58. data/processor/command/eval.rb +70 -0
  59. data/processor/command/exit.rb +4 -1
  60. data/processor/command/finish.rb +6 -4
  61. data/processor/command/frame.rb +6 -3
  62. data/processor/command/help.rb +97 -54
  63. data/processor/command/help/.gitignore +1 -0
  64. data/processor/command/help/README +10 -0
  65. data/processor/command/help/command.txt +48 -0
  66. data/processor/command/help/filename.txt +40 -0
  67. data/processor/command/help/location.txt +37 -0
  68. data/processor/command/info_subcmd/.gitignore +1 -0
  69. data/processor/command/info_subcmd/breakpoints.rb +9 -9
  70. data/processor/command/info_subcmd/{file.rb → files.rb} +92 -27
  71. data/processor/command/info_subcmd/frame.rb +41 -15
  72. data/processor/command/info_subcmd/iseq.rb +39 -17
  73. data/processor/command/info_subcmd/program.rb +2 -8
  74. data/processor/command/info_subcmd/registers.rb +12 -10
  75. data/processor/command/info_subcmd/registers_subcmd/.gitignore +1 -0
  76. data/processor/command/info_subcmd/ruby.rb +60 -0
  77. data/processor/command/irb.rb +26 -3
  78. data/processor/command/kill.rb +21 -10
  79. data/processor/command/list.rb +1 -1
  80. data/processor/command/macro.rb +37 -23
  81. data/processor/command/pr.rb +1 -1
  82. data/processor/command/reload.rb +4 -0
  83. data/processor/command/reload_subcmd/.gitignore +1 -0
  84. data/processor/command/restart.rb +9 -9
  85. data/processor/command/save.rb +29 -36
  86. data/processor/command/set_subcmd/.gitignore +1 -0
  87. data/processor/command/set_subcmd/auto_subcmd/.gitignore +1 -0
  88. data/processor/command/set_subcmd/confirm.rb +23 -0
  89. data/processor/command/set_subcmd/debug_subcmd/.gitignore +1 -0
  90. data/processor/command/set_subcmd/different.rb +2 -0
  91. data/processor/command/set_subcmd/events.rb +2 -0
  92. data/processor/command/set_subcmd/max.rb +9 -12
  93. data/processor/command/set_subcmd/max_subcmd/.gitignore +1 -0
  94. data/processor/command/set_subcmd/substitute_subcmd/.gitignore +1 -0
  95. data/processor/command/set_subcmd/trace.rb +7 -13
  96. data/processor/command/set_subcmd/trace_subcmd/.gitignore +1 -0
  97. data/processor/command/set_subcmd/trace_subcmd/buffer.rb +12 -27
  98. data/processor/command/set_subcmd/trace_subcmd/print.rb +10 -8
  99. data/processor/command/set_subcmd/trace_subcmd/var.rb +6 -10
  100. data/processor/command/show.rb +12 -1
  101. data/processor/command/show_subcmd/.gitignore +1 -0
  102. data/processor/command/show_subcmd/alias.rb +11 -15
  103. data/processor/command/show_subcmd/auto_subcmd/.gitignore +1 -0
  104. data/processor/command/show_subcmd/basename.rb +1 -9
  105. data/processor/command/show_subcmd/confirm.rb +25 -0
  106. data/processor/command/show_subcmd/debug_subcmd/.gitignore +1 -0
  107. data/processor/command/show_subcmd/macro.rb +32 -14
  108. data/processor/command/show_subcmd/max_subcmd/.gitignore +1 -0
  109. data/processor/command/show_subcmd/trace_subcmd/.gitignore +1 -0
  110. data/processor/command/show_subcmd/trace_subcmd/buffer.rb +11 -31
  111. data/processor/command/show_subcmd/trace_subcmd/print.rb +4 -20
  112. data/processor/command/source.rb +7 -1
  113. data/processor/command/up.rb +7 -4
  114. data/processor/default.rb +3 -1
  115. data/processor/eval.rb +13 -0
  116. data/processor/eventbuf.rb +3 -2
  117. data/processor/frame.rb +19 -0
  118. data/processor/help.rb +20 -0
  119. data/processor/load_cmds.rb +143 -24
  120. data/processor/location.rb +61 -10
  121. data/processor/main.rb +30 -11
  122. data/processor/mock.rb +5 -3
  123. data/processor/msg.rb +17 -0
  124. data/processor/running.rb +1 -1
  125. data/processor/subcmd.rb +3 -2
  126. data/processor/validate.rb +173 -185
  127. data/sample/.gitignore +1 -0
  128. data/sample/list-terminal-colors.rb +139 -0
  129. data/sample/rocky-dot-trepanrc +14 -0
  130. data/sample/rocky-trepan-colors.rb +47 -0
  131. data/test/Makefile +7 -0
  132. data/test/data/.gitignore +1 -0
  133. data/test/data/debugger-stop.cmd +3 -0
  134. data/test/data/debugger-stop.right +5 -0
  135. data/test/data/fname-with-blank.right +0 -3
  136. data/test/data/quit.right +0 -1
  137. data/test/data/quit2.cmd +6 -0
  138. data/test/data/quit2.right +3 -0
  139. data/test/data/testing.cmd +1 -0
  140. data/test/example/.gitignore +1 -0
  141. data/test/example/debugger-stop.rb +14 -0
  142. data/test/functional/.gitignore +2 -0
  143. data/test/functional/fn_helper.rb +7 -9
  144. data/test/functional/test-break-long.rb +7 -7
  145. data/test/functional/test-break.rb +7 -7
  146. data/test/functional/test-condition.rb +4 -4
  147. data/test/functional/test-delete.rb +6 -5
  148. data/test/functional/test-eval.rb +115 -0
  149. data/test/functional/test-raise.rb +1 -1
  150. data/test/functional/test-return.rb +1 -1
  151. data/test/integration/.gitignore +2 -0
  152. data/test/integration/helper.rb +6 -3
  153. data/test/integration/test-debugger-stop.rb +22 -0
  154. data/test/integration/test-quit.rb +8 -0
  155. data/test/unit/.gitignore +1 -0
  156. data/test/unit/Makefile +7 -0
  157. data/test/unit/test-app-brkpt.rb +0 -1
  158. data/test/unit/test-app-cmd_parse.rb +107 -0
  159. data/test/unit/test-app-cmd_parser.rb +22 -0
  160. data/test/unit/test-app-complete.rb +38 -0
  161. data/test/unit/test-app-condition.rb +20 -0
  162. data/test/unit/test-app-iseq.rb +31 -0
  163. data/test/unit/test-app-options.rb +9 -1
  164. data/test/unit/test-app-util.rb +0 -1
  165. data/test/unit/test-base-cmd.rb +46 -0
  166. data/test/unit/test-base-subcmd.rb +11 -2
  167. data/test/unit/test-base-submgr.rb +23 -0
  168. data/test/unit/test-base-subsubcmd.rb +20 -0
  169. data/test/unit/test-cmd-break.rb +22 -23
  170. data/test/unit/test-cmd-help.rb +4 -0
  171. data/test/unit/test-completion.rb +43 -0
  172. data/test/unit/test-io-tcpclient.rb +3 -2
  173. data/test/unit/test-proc-load_cmds.rb +10 -1
  174. data/test/unit/test-proc-location.rb +39 -0
  175. data/test/unit/test-proc-main.rb +1 -1
  176. data/test/unit/test-proc-validate.rb +47 -31
  177. data/trepanning.gemspec +45 -0
  178. metadata +247 -179
  179. data/app/core.rb-consider +0 -198
  180. data/test/functional/tmp/b3.rb +0 -5
  181. 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(program_to_debug) unless
53
- File.exist?(program_to_debug)
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 highlight).each do |opt|
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
+ /*~
@@ -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
- @input = inp || STDIN
29
- @interactive = false
30
- @opts = opts
31
- @output = out || STDOUT
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.
@@ -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
- COMMAND = 'C'
11
- CONFIRM_TRUE = 'Y'
12
- CONFIRM_FALSE = 'N'
13
- CONFIRM_REPLY = '?'
14
- QUIT = 'q'
15
- PROMPT = 'p'
16
- RESTART = 'r'
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 in the same process as
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
- # Moutput = import_relative('dbg_output', '..io', 'pydbgr')
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
- FILE_HISTORY = '.trapan_hist' unless defined?(FILE_HISTORY)
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
- # save history
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
- line = readline(prompt)
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 = DEFAULT_OPTS.merge(opts)
18
- @input = inp || STDIN
19
- @eof = false
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
- line = @opts[:line_edit] ? Readline.readline : @input.gets
38
- @eof = !line
39
- rescue
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] = false unless
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
- require 'readline'
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 = :disconnnected
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 = 8192 # Largest size for a recv
9
- LOG_MAX_MSG = Math.log10(TCP_MAX_PACKET).ceil
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
- DEFAULT_INIT_OPTS = {:open => true}
17
-
18
- SERVER_SOCKET_OPTS = {
19
- :host => Trepan::DEFAULT_SETTINGS[:host],
20
- :port => Trepan::DEFAULT_SETTINGS[:port], # A non-privileged port
21
- :timeout => 5, # FIXME: not used
22
- :reuse => true, # FIXME: not used. Allow port to be resued on close?
23
- # Python has: 'posix' == os.name
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
- # Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
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
- attr_reader :initial_dir # String. Current directory when program
31
- # started. Used in restart program.
32
- attr_accessor :restart_argv # How to restart us, empty or nil.
33
- # Note restart[0] is typically $0.
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
- [Trepan::UserInterface.new(@input, @output)]
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, @output)
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