trepanning 0.0.9 → 0.1.0

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