trepanning 0.0.9 → 0.1.0

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 (108) hide show
  1. data/ChangeLog +237 -0
  2. data/NEWS +8 -0
  3. data/Rakefile +3 -2
  4. data/app/breakpoint.rb +8 -8
  5. data/app/brkptmgr.rb +86 -85
  6. data/app/client.rb +60 -0
  7. data/app/core.rb-consider +198 -0
  8. data/app/default.rb +17 -7
  9. data/app/disassemble.rb +12 -2
  10. data/app/options.rb +51 -20
  11. data/app/yarv.rb +183 -0
  12. data/bin/trepan +15 -9
  13. data/data/custom_require.rb +44 -0
  14. data/data/irbrc +41 -0
  15. data/data/prelude.rb +38 -0
  16. data/interface/base_intf.rb +10 -4
  17. data/interface/client.rb +79 -0
  18. data/interface/comcodes.rb +18 -0
  19. data/interface/server.rb +142 -0
  20. data/io/base_io.rb +57 -3
  21. data/io/tcpclient.rb +122 -0
  22. data/io/tcpfns.rb +31 -0
  23. data/io/tcpserver.rb +137 -0
  24. data/lib/trepanning.rb +57 -28
  25. data/processor/command/base/cmd.rb +10 -6
  26. data/processor/command/base/subcmd.rb +13 -1
  27. data/processor/command/directory.rb +15 -8
  28. data/processor/command/disassemble.rb +3 -2
  29. data/processor/command/help.rb +71 -19
  30. data/processor/command/info_subcmd/args.rb +2 -3
  31. data/processor/command/info_subcmd/breakpoints.rb +2 -3
  32. data/processor/command/info_subcmd/file.rb +2 -3
  33. data/processor/command/info_subcmd/frame.rb +2 -3
  34. data/processor/command/info_subcmd/iseq.rb +4 -5
  35. data/processor/command/info_subcmd/locals.rb +2 -3
  36. data/processor/command/info_subcmd/program.rb +2 -3
  37. data/processor/command/info_subcmd/registers.rb +2 -3
  38. data/processor/command/info_subcmd/return.rb +2 -3
  39. data/processor/command/info_subcmd/thread.rb +2 -3
  40. data/processor/command/list.rb +10 -6
  41. data/processor/command/reload.rb +1 -1
  42. data/processor/command/reload_subcmd/command.rb +29 -16
  43. data/processor/command/server.rb +70 -0
  44. data/processor/command/set_subcmd/auto.rb +2 -3
  45. data/processor/command/set_subcmd/basename.rb +2 -3
  46. data/processor/command/set_subcmd/debug.rb +2 -3
  47. data/processor/command/set_subcmd/different.rb +2 -3
  48. data/processor/command/set_subcmd/events.rb +2 -3
  49. data/processor/command/set_subcmd/hidelevel.rb +6 -7
  50. data/processor/command/set_subcmd/highlight.rb +32 -0
  51. data/processor/command/set_subcmd/max.rb +2 -3
  52. data/processor/command/set_subcmd/return.rb +2 -3
  53. data/processor/command/set_subcmd/sp.rb +2 -3
  54. data/processor/command/set_subcmd/substitute.rb +2 -3
  55. data/processor/command/set_subcmd/timer.rb +2 -3
  56. data/processor/command/set_subcmd/trace.rb +3 -4
  57. data/processor/command/show_subcmd/alias.rb +3 -3
  58. data/processor/command/show_subcmd/args.rb +2 -3
  59. data/processor/command/show_subcmd/auto.rb +1 -2
  60. data/processor/command/show_subcmd/basename.rb +2 -3
  61. data/processor/command/show_subcmd/debug.rb +1 -2
  62. data/processor/command/show_subcmd/different.rb +2 -1
  63. data/processor/command/show_subcmd/events.rb +2 -2
  64. data/processor/command/show_subcmd/hidelevel.rb +2 -3
  65. data/processor/command/show_subcmd/highlight.rb +23 -0
  66. data/processor/command/show_subcmd/macro.rb +2 -1
  67. data/processor/command/show_subcmd/max.rb +2 -3
  68. data/processor/command/show_subcmd/trace.rb +2 -3
  69. data/processor/command/source.rb +78 -28
  70. data/processor/default.rb +3 -2
  71. data/processor/load_cmds.rb +39 -19
  72. data/processor/location.rb +11 -7
  73. data/processor/main.rb +31 -15
  74. data/processor/mock.rb +22 -7
  75. data/processor/msg.rb +24 -8
  76. data/test/data/fname-with-blank.right +3 -0
  77. data/test/data/quit.right +2 -0
  78. data/test/functional/test-break-long.rb +87 -0
  79. data/test/functional/tmp/b3.rb +5 -0
  80. data/test/functional/tmp/immediate-bug1.rb +9 -0
  81. data/test/integration/helper.rb +14 -11
  82. data/test/integration/test-fname-with-blank.rb +5 -1
  83. data/test/integration/test-quit.rb +6 -2
  84. data/test/unit/cmd-helper.rb +9 -4
  85. data/test/unit/mock-helper.rb +9 -0
  86. data/test/unit/test-app-brkpt.rb +4 -4
  87. data/test/unit/test-app-brkptmgr.rb +2 -2
  88. data/test/unit/test-app-file.rb +0 -1
  89. data/test/unit/test-app-options.rb +26 -5
  90. data/test/unit/test-base-subcmd.rb +0 -1
  91. data/test/unit/test-cmd-alias.rb +0 -1
  92. data/test/unit/test-cmd-break.rb +0 -4
  93. data/test/unit/test-cmd-endisable.rb +1 -3
  94. data/test/unit/test-cmd-help.rb +0 -1
  95. data/test/unit/test-cmd-kill.rb +4 -5
  96. data/test/unit/test-cmd-quit.rb +4 -7
  97. data/test/unit/test-cmd-source.rb +33 -0
  98. data/test/unit/test-cmd-step.rb +0 -2
  99. data/test/unit/test-io-tcp.rb +32 -0
  100. data/test/unit/test-io-tcpclient.rb +53 -0
  101. data/test/unit/test-io-tcpserver.rb +49 -0
  102. data/test/unit/test-proc-main.rb +2 -2
  103. metadata +195 -175
  104. data/processor/command/stepi.rb +0 -63
  105. data/test/functional/tmp/b1.rb +0 -5
  106. data/test/functional/tmp/s1.rb +0 -9
  107. data/test/functional/tmp/t2.rb +0 -6
  108. data/test/integration/try-test-enable.rb +0 -11
@@ -0,0 +1,183 @@
1
+ # Copyright (C) 2011 Rocky Bernstein <rockyb@rubyforge.net>
2
+ # A CodeRay Scanner for YARV
3
+ # FIXME: add unit test.
4
+ require 'rubygems'
5
+ require 'coderay'
6
+ module CodeRay
7
+ module Scanners
8
+
9
+ class YARV < Scanner
10
+
11
+ include Streamable
12
+
13
+ register_for :yarv
14
+ file_extension 'yarv'
15
+
16
+ def string_parse(tokens)
17
+ if match = scan(/^"[^"]*"/)
18
+ string = match.dup
19
+ while "\\" == match[-2..-2]
20
+ match = scan(/^.*"/)
21
+ break unless match
22
+ string << match
23
+ end
24
+ tokens << [string, :string]
25
+ true
26
+ else
27
+ false
28
+ end
29
+ end
30
+
31
+ def space_parse(tokens)
32
+ if match = scan(/^[ \t]*/)
33
+ tokens << [match, :space] if match
34
+ end
35
+ end
36
+
37
+ def scan_tokens(tokens, options)
38
+
39
+ state = :initial
40
+ number_expected = true
41
+
42
+ until eos?
43
+
44
+ kind = nil
45
+ match = nil
46
+
47
+ case state
48
+
49
+ when :initial
50
+ if match = scan(/^\s*/)
51
+ tokens << [match, :space] unless match.empty?
52
+ end
53
+ state =
54
+ if match = scan(/^$/)
55
+ :initial
56
+ else
57
+ :expect_label
58
+ end
59
+
60
+ when :expect_label
61
+ state =
62
+ if match = scan(/\d+/x)
63
+ tokens << [match, :label]
64
+ :expect_opcode
65
+ else
66
+ match = scan(/^.*$/)
67
+ tokens << [match, :error]
68
+ :initial
69
+ end
70
+
71
+ when :expect_opcode
72
+ state =
73
+ if match = scan(/(\s+)(\S+)/)
74
+ match =~ /(\s+)(\S+)/
75
+ tokens << [$1, :space]
76
+ opcode = $2
77
+ tokens << [opcode, :reserved]
78
+ :expect_operand
79
+ else
80
+ match = scan(/^(.*)$/)
81
+ tokens << [match, :error]
82
+ :initial
83
+ end
84
+
85
+ when :expect_literal
86
+ space_parse(tokens)
87
+ if match = scan(/^#<.+>/)
88
+ tokens << [match, :content]
89
+ elsif match = scan(/^(\d+)/)
90
+ tokens << [match, :integer]
91
+ elsif match = scan(/^([:][^: ,\n]+)/)
92
+ tokens << [match, :symbol]
93
+ elsif string_parse(tokens)
94
+ #
95
+ elsif match = scan(/nil|true|false/)
96
+ tokens << [match, :pre_constant]
97
+ elsif match = scan(/\/.*\//)
98
+ tokens << [match, :entity]
99
+ else
100
+ match = scan(/^.*$/)
101
+ tokens << [match, :error] unless match.empty?
102
+ end
103
+ state = :expect_opt_lineno
104
+
105
+ when :expect_operand
106
+ space_parse(tokens)
107
+ state = :expect_another_operand
108
+ if match = scan(/^(\d+)/)
109
+ tokens << [match, :integer]
110
+ elsif match = scan(/\/.*\//)
111
+ # Really a regular expression
112
+ tokens << [match, :entity]
113
+ elsif match = scan(/^([:][^: ,\n]+)/)
114
+ tokens << [match, :symbol]
115
+ elsif match = scan(/^([$][^ ,\n]+)/)
116
+ tokens << [match, :global_variable]
117
+ elsif match = scan(/nil|true|false/)
118
+ tokens << [match, :pre_constant]
119
+ elsif match = scan(/nil|true|false/)
120
+ tokens << [match, :pre_constant]
121
+ elsif match = scan(/[A-Za-z_][_A-Za-z0-9?!]*/)
122
+ tokens << [match, :variable]
123
+ elsif match = scan(/^#[^, \n]*/)
124
+ tokens << [match, :content]
125
+ elsif match = scan(/^<.+>/)
126
+ tokens << [match, :content]
127
+ elsif string_parse(tokens)
128
+ else
129
+ state = :expect_opt_lineno
130
+ end
131
+
132
+ when :expect_another_operand
133
+ state =
134
+ if match = scan(/^,/)
135
+ tokens << [match, :operator]
136
+ :expect_operand
137
+ else
138
+ :expect_opt_lineno
139
+ end
140
+ when :expect_opt_lineno
141
+ space_parse(tokens)
142
+ if match = scan(/^\(\s+\d+\)$/)
143
+ tokens << [match, :comment]
144
+ else
145
+ match = scan(/^.*$/)
146
+ tokens << [match, :error] unless match.empty?
147
+ end
148
+ state = :initial
149
+ end
150
+ end
151
+ tokens
152
+ end
153
+ end
154
+ end
155
+ end
156
+ if __FILE__ == $0
157
+ require 'term/ansicolor'
158
+ ruby_scanner = CodeRay.scanner :yarv
159
+ string='
160
+ 0045 opt_regexpmatch1 /^-e$/
161
+ 0000 trace 1 ( 9)
162
+ 0002 putnil
163
+ 0003 putstring "irb"
164
+ 0005 send :require, 1, nil, 8, <ic:0>
165
+ 0011 pop
166
+ 0012 trace 1 ( 11)
167
+ 0014 putstring "/usr/local/bin/irb"
168
+ 0016 getglobal $0
169
+ 0018 opt_eq <ic:8>
170
+ 0020 branchunless 41
171
+ 0022 trace 1 ( 12)
172
+ 0024 getinlinecache 31, <ic:2>
173
+ 0027 getconstant :IRB
174
+ 0029 setinlinecache <ic:2>
175
+ 0031 putstring "/usr/local/bin/irb"
176
+ 0033 send :start, 1, nil, 0, <ic:3>
177
+ '
178
+ yarv_scanner = CodeRay.scanner :yarv
179
+ tokens = yarv_scanner.tokenize(string)
180
+ p tokens
181
+ yarv_highlighter = CodeRay::Duo[:yarv, :term]
182
+ puts yarv_highlighter.encode(string)
183
+ end
data/bin/trepan CHANGED
@@ -1,8 +1,9 @@
1
1
  #!/usr/bin/env ruby
2
- # Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
2
+ # Copyright (C) 2010, 2011 Rocky Bernstein <rockyb@rubyforge.net>
3
3
  # Invoke debugger from the command line.
4
4
  require_relative '../app/run'
5
5
  require_relative '../app/options'
6
+ require_relative '../app/client'
6
7
  require_relative '../lib/trepanning'
7
8
 
8
9
  # FIXME: the figure out how to run via gem installation.
@@ -20,8 +21,8 @@ if File.basename(__FILE__) == File.basename($0)
20
21
  # options = DEFAULT_CMDLINE_SETTINGS.merge({}) seems to change up
21
22
  # DEFAULT_CMDLINE_SETTINGS when options[:key] is changed. The
22
23
  # below is the simplest thing I can come up with so far.
23
- options = copy_default_options
24
- opts = setup_options(options)
24
+ options = Trepan.copy_default_options
25
+ opts = Trepan.setup_options(options)
25
26
  Trepan::ARGV = ARGV.clone
26
27
  rest = opts.parse! ARGV
27
28
 
@@ -34,13 +35,15 @@ if File.basename(__FILE__) == File.basename($0)
34
35
  # FIXME: Should (some of) these be instance variables?
35
36
  Trepan::RUBY_PATH = ruby_path
36
37
  Trepan::TREPAN_PATH = trepan_path
37
- Trepan::RBDBGR_FILE = __FILE__
38
38
 
39
39
  if ARGV.empty?
40
40
  if options[:version] || options[:help]
41
41
  exit 100
42
+ elsif options[:client]
43
+ start_client(options)
44
+ exit
42
45
  else
43
- STDERR.puts 'Sorry - for now you must specify a Ruby script to debug.'
46
+ STDERR.puts 'Sorry - for now you must specify a Ruby script to debug or use the --client option.'
44
47
  exit(1)
45
48
  end
46
49
  end
@@ -51,10 +54,13 @@ if File.basename(__FILE__) == File.basename($0)
51
54
  Trepan::PROG_SCRIPT = program_to_debug
52
55
 
53
56
  # Set global so others may use this debugger.
54
- $trepan = Trepan.new(:cmdfiles => options[:cmdfiles],
55
- :initial_dir => options[:chdir],
56
- :nx => options[:nx]
57
- )
57
+
58
+ opts = {}
59
+ %w(cmdfiles initial_dir host nx port server highlight).each do |opt|
60
+ opts[opt.to_sym] = options[opt.to_sym]
61
+ end
62
+
63
+ $trepan = Trepan.new(opts)
58
64
  debug_program($trepan, Trepan::RUBY_PATH,
59
65
  File.expand_path(program_to_debug))
60
66
  end
@@ -0,0 +1,44 @@
1
+ #--
2
+ # Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
3
+ # All rights reserved.
4
+ # See LICENSE.txt for permissions.
5
+ #++
6
+
7
+ module Kernel
8
+
9
+ ##
10
+ # The Kernel#require from before RubyGems was loaded.
11
+
12
+ alias gem_original_require require
13
+
14
+ ##
15
+ # When RubyGems is required, Kernel#require is replaced with our own which
16
+ # is capable of loading gems on demand.
17
+ #
18
+ # When you call <tt>require 'x'</tt>, this is what happens:
19
+ # * If the file can be loaded from the existing Ruby loadpath, it
20
+ # is.
21
+ # * Otherwise, installed gems are searched for a file that matches.
22
+ # If it's found in gem 'y', that gem is activated (added to the
23
+ # loadpath).
24
+ #
25
+ # The normal <tt>require</tt> functionality of returning false if
26
+ # that file has already been loaded is preserved.
27
+
28
+ def require(path) # :doc:
29
+ gem_original_require path
30
+ rescue LoadError => load_error
31
+ if load_error.message.end_with?(path)
32
+ if Gem.try_activate(path)
33
+ return gem_original_require(path)
34
+ end
35
+ end
36
+
37
+ raise load_error
38
+ end
39
+
40
+ private :require
41
+ private :gem_original_require
42
+
43
+ end unless Kernel.private_method_defined?(:gem_original_require)
44
+
@@ -0,0 +1,41 @@
1
+ # -*- Ruby -*-
2
+ # Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
3
+ # We use this as the default startup file for irb inside trepan
4
+ # Down the line we will have a way for folks to add/override this
5
+ # with their own file.
6
+ IRB.conf[:PROMPT_MODE] = :SIMPLE
7
+ IRB.conf[:PROMPT][:SIMPLE] =
8
+ {:PROMPT_C=>"trepan ?> ",
9
+ :PROMPT_I=>"trepan >> ",
10
+ :PROMPT_N=>"trepan >> ",
11
+ :PROMPT_S=>nil,
12
+ :RETURN=>"=> %s\n"}
13
+
14
+ # Using dbgr to issue a debugger statement inside irb:
15
+ # dbgr %w(info program)
16
+ # dbgr 'info program' # also works
17
+ # But...
18
+ # dbgr info program # wrong!
19
+ #
20
+ puts "You are in a trepan session. You should have access to program scope."
21
+ puts "'dbgr', 'step', 'ne', 'q', 'cont' commands have been added."
22
+
23
+ if defined?($trepan) && $trepan
24
+ puts 'You should have access to debugger state via global variable $trepan'
25
+ end
26
+ if defined?($trepan_frame) && $trepan_frame
27
+ puts 'You should have access to the program frame via global variable $trepan_frame'
28
+ end
29
+ if defined?($trepan_cmdproc) && $trepan_cmdproc
30
+ puts 'You should have access to the command processor via global variable $trepan_cmdproc'
31
+ end
32
+
33
+ # Monkeypatch to save the current IRB statement to be run.
34
+ class IRB::Context
35
+ alias_method :_trepan_original_evaluate, :evaluate
36
+ def evaluate(line, line_no)
37
+ $trepan_irb_statements = line
38
+ _trepan_original_evaluate(line, line_no)
39
+ end
40
+ end
41
+
@@ -0,0 +1,38 @@
1
+
2
+ # Mutex
3
+
4
+ class Mutex
5
+ def synchronize
6
+ self.lock
7
+ begin
8
+ yield
9
+ ensure
10
+ self.unlock rescue nil
11
+ end
12
+ end
13
+ end
14
+
15
+ # Thread
16
+
17
+ class Thread
18
+ MUTEX_FOR_THREAD_EXCLUSIVE = Mutex.new
19
+ def self.exclusive
20
+ MUTEX_FOR_THREAD_EXCLUSIVE.synchronize{
21
+ yield
22
+ }
23
+ end
24
+ end
25
+
26
+ module Kernel
27
+ module_function
28
+ def require_relative(relative_feature)
29
+ c = caller.first
30
+ e = c.rindex(/:\d+:in /)
31
+ file = $`
32
+ if /\A\((.*)\)/ =~ file # eval, etc.
33
+ raise LoadError, "require_relative is called in #{$1}"
34
+ end
35
+ absolute_feature = File.expand_path(File.join(File.dirname(file), relative_feature))
36
+ require absolute_feature
37
+ end
38
+ end
@@ -33,8 +33,8 @@ class Trepan
33
33
 
34
34
  # Closes all input and/or output.
35
35
  def close
36
- @input.close unless @input.closed?
37
- @output.close unless @output.closed?
36
+ @input.close unless !@input || @input.closed?
37
+ @output.close unless !@output || @output.closed?
38
38
  end
39
39
 
40
40
  # Called when a dangerous action is about to be done to make sure
@@ -58,6 +58,10 @@ class Trepan
58
58
  close
59
59
  end
60
60
 
61
+ def input_eof?
62
+ @input.eof?
63
+ end
64
+
61
65
  # Return true if interface is interactive.
62
66
  def interactive?
63
67
  # Default false and making subclasses figure out how to determine
@@ -82,8 +86,10 @@ class Trepan
82
86
  @output.write(msg)
83
87
  end
84
88
 
85
- def read_command( prompt)
86
- raise RuntimeError, Trepan::NotImplementedMessage
89
+ def read_command(prompt='')
90
+ line = readline(prompt)
91
+ # FIXME: Do something with history?
92
+ return line
87
93
  end
88
94
 
89
95
  def readline(prompt='')
@@ -0,0 +1,79 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright (C) 2011 Rocky Bernstein <rockyb@rubyforge.net>
3
+
4
+ # Interface for client (i.e. user to communication-device) interaction.
5
+ # The debugged program is at the other end of the communcation.
6
+
7
+ require_relative 'user'
8
+ require_relative '../io/tcpclient'
9
+ require_relative 'comcodes'
10
+
11
+ # Mfifoclient = import_relative('fifoclient', '..io', 'pydbgr')
12
+
13
+ # Interface for a user which is attached to a debugged process via
14
+ # some sort of communication medium (e.g. socket, tty, FIFOs). This
15
+ # could be on the same computer in a different process or on a remote
16
+ # computer.
17
+ class Trepan::ClientInterface < Trepan::Interface
18
+
19
+ DEFAULT_INIT_CONNECTION_OPTS = {
20
+ :open => true,
21
+ :io => :tcp
22
+ }
23
+
24
+ def initialize(inp=nil, out=nil, inout=nil, user_opts={},
25
+ connection_opts={})
26
+
27
+ @connection_opts = DEFAULT_INIT_CONNECTION_OPTS.merge(connection_opts)
28
+
29
+ @user = Trepan::UserInterface.new(inp, out, user_opts)
30
+
31
+ @inout =
32
+ if inout
33
+ inout
34
+ else
35
+ # @server_type = @connection_opts[:io]
36
+ # if 'FIFO' == self.server_type
37
+ # Mfifoclient.FIFOClient(opts=@connection_opts)
38
+ # elsif :tcp == self.server_type
39
+ Trepan::TCPDbgClient.new(@connection_opts)
40
+ # else
41
+ # errmsg("Expecting server type TCP or FIFO. Got: %s." %
42
+ # self.server_type)
43
+ # return
44
+ # end
45
+ end
46
+ end
47
+
48
+ def confirm(prompt, default)
49
+ @user.confirm(prompt, default)
50
+ end
51
+
52
+ def read_command(prompt='')
53
+ @user.read_command(prompt)
54
+ end
55
+
56
+ # Send a message back to the server (in contrast to the local user
57
+ # output channel).
58
+ def read_remote
59
+ coded_line = nil
60
+ until coded_line
61
+ coded_line = @inout.read_msg
62
+ end
63
+ control = coded_line[0..0]
64
+ remote_line = coded_line[1..-1]
65
+ [control, remote_line]
66
+ end
67
+
68
+ # Send a message back to the server (in contrast to the local user
69
+ # output channel).
70
+ def write_remote(code, msg)
71
+ # FIXME change into write_xxx
72
+ @inout.writeline(code + msg)
73
+ end
74
+ end
75
+
76
+ # Demo
77
+ if __FILE__ == $0
78
+ intf = Trepan::ClientInterface.new
79
+ end