trepanning 0.0.4

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 (219) hide show
  1. data/ChangeLog +4422 -0
  2. data/LICENSE +23 -0
  3. data/NEWS +12 -0
  4. data/README.textile +56 -0
  5. data/Rakefile +171 -0
  6. data/app/Makefile +7 -0
  7. data/app/breakpoint.rb +157 -0
  8. data/app/brkptmgr.rb +149 -0
  9. data/app/condition.rb +22 -0
  10. data/app/core.rb +203 -0
  11. data/app/default.rb +54 -0
  12. data/app/disassemble.rb +61 -0
  13. data/app/display.rb +148 -0
  14. data/app/file.rb +135 -0
  15. data/app/frame.rb +275 -0
  16. data/app/irb.rb +112 -0
  17. data/app/mock.rb +22 -0
  18. data/app/options.rb +122 -0
  19. data/app/run.rb +95 -0
  20. data/app/thread.rb +24 -0
  21. data/app/util.rb +32 -0
  22. data/bin/trepan +63 -0
  23. data/data/custom_require.rb +44 -0
  24. data/data/irbrc +55 -0
  25. data/data/prelude.rb +38 -0
  26. data/interface/base_intf.rb +95 -0
  27. data/interface/script.rb +103 -0
  28. data/interface/user.rb +90 -0
  29. data/io/base_io.rb +92 -0
  30. data/io/input.rb +111 -0
  31. data/io/string_array.rb +155 -0
  32. data/lib/Makefile +7 -0
  33. data/lib/trepanning.rb +277 -0
  34. data/processor/breakpoint.rb +108 -0
  35. data/processor/command/alias.rb +55 -0
  36. data/processor/command/backtrace.rb +95 -0
  37. data/processor/command/base/cmd.rb +97 -0
  38. data/processor/command/base/subcmd.rb +207 -0
  39. data/processor/command/base/submgr.rb +178 -0
  40. data/processor/command/base/subsubcmd.rb +102 -0
  41. data/processor/command/base/subsubmgr.rb +182 -0
  42. data/processor/command/break.rb +85 -0
  43. data/processor/command/condition.rb +64 -0
  44. data/processor/command/continue.rb +61 -0
  45. data/processor/command/debug.rb +85 -0
  46. data/processor/command/delete.rb +54 -0
  47. data/processor/command/directory.rb +43 -0
  48. data/processor/command/disable.rb +65 -0
  49. data/processor/command/disassemble.rb +103 -0
  50. data/processor/command/display.rb +81 -0
  51. data/processor/command/down.rb +56 -0
  52. data/processor/command/enable.rb +43 -0
  53. data/processor/command/exit.rb +54 -0
  54. data/processor/command/finish.rb +81 -0
  55. data/processor/command/frame.rb +117 -0
  56. data/processor/command/help.rb +146 -0
  57. data/processor/command/info.rb +28 -0
  58. data/processor/command/info_subcmd/args.rb +56 -0
  59. data/processor/command/info_subcmd/breakpoints.rb +162 -0
  60. data/processor/command/info_subcmd/file.rb +162 -0
  61. data/processor/command/info_subcmd/frame.rb +39 -0
  62. data/processor/command/info_subcmd/iseq.rb +83 -0
  63. data/processor/command/info_subcmd/locals.rb +88 -0
  64. data/processor/command/info_subcmd/program.rb +54 -0
  65. data/processor/command/info_subcmd/registers.rb +72 -0
  66. data/processor/command/info_subcmd/registers_subcmd/dfp.rb +38 -0
  67. data/processor/command/info_subcmd/registers_subcmd/helper.rb +40 -0
  68. data/processor/command/info_subcmd/registers_subcmd/lfp.rb +54 -0
  69. data/processor/command/info_subcmd/registers_subcmd/pc.rb +44 -0
  70. data/processor/command/info_subcmd/registers_subcmd/sp.rb +75 -0
  71. data/processor/command/info_subcmd/return.rb +40 -0
  72. data/processor/command/info_subcmd/thread.rb +106 -0
  73. data/processor/command/irb.rb +106 -0
  74. data/processor/command/kill.rb +58 -0
  75. data/processor/command/list.rb +327 -0
  76. data/processor/command/macro.rb +65 -0
  77. data/processor/command/next.rb +89 -0
  78. data/processor/command/nocache.rb +33 -0
  79. data/processor/command/print.rb +37 -0
  80. data/processor/command/ps.rb +40 -0
  81. data/processor/command/quit.rb +62 -0
  82. data/processor/command/raise.rb +47 -0
  83. data/processor/command/reload.rb +28 -0
  84. data/processor/command/reload_subcmd/command.rb +34 -0
  85. data/processor/command/restart.rb +57 -0
  86. data/processor/command/save.rb +60 -0
  87. data/processor/command/set.rb +47 -0
  88. data/processor/command/set_subcmd/auto.rb +27 -0
  89. data/processor/command/set_subcmd/auto_subcmd/eval.rb +67 -0
  90. data/processor/command/set_subcmd/auto_subcmd/irb.rb +49 -0
  91. data/processor/command/set_subcmd/auto_subcmd/list.rb +51 -0
  92. data/processor/command/set_subcmd/basename.rb +39 -0
  93. data/processor/command/set_subcmd/debug.rb +27 -0
  94. data/processor/command/set_subcmd/debug_subcmd/dbgr.rb +49 -0
  95. data/processor/command/set_subcmd/debug_subcmd/except.rb +35 -0
  96. data/processor/command/set_subcmd/debug_subcmd/macro.rb +35 -0
  97. data/processor/command/set_subcmd/debug_subcmd/skip.rb +35 -0
  98. data/processor/command/set_subcmd/debug_subcmd/stack.rb +45 -0
  99. data/processor/command/set_subcmd/different.rb +67 -0
  100. data/processor/command/set_subcmd/events.rb +71 -0
  101. data/processor/command/set_subcmd/max.rb +35 -0
  102. data/processor/command/set_subcmd/max_subcmd/list.rb +50 -0
  103. data/processor/command/set_subcmd/max_subcmd/stack.rb +60 -0
  104. data/processor/command/set_subcmd/max_subcmd/string.rb +53 -0
  105. data/processor/command/set_subcmd/max_subcmd/width.rb +50 -0
  106. data/processor/command/set_subcmd/return.rb +66 -0
  107. data/processor/command/set_subcmd/sp.rb +62 -0
  108. data/processor/command/set_subcmd/substitute.rb +25 -0
  109. data/processor/command/set_subcmd/substitute_subcmd/eval.rb +98 -0
  110. data/processor/command/set_subcmd/substitute_subcmd/path.rb +55 -0
  111. data/processor/command/set_subcmd/substitute_subcmd/string.rb +72 -0
  112. data/processor/command/set_subcmd/timer.rb +68 -0
  113. data/processor/command/set_subcmd/trace.rb +43 -0
  114. data/processor/command/set_subcmd/trace_subcmd/buffer.rb +56 -0
  115. data/processor/command/set_subcmd/trace_subcmd/print.rb +54 -0
  116. data/processor/command/set_subcmd/trace_subcmd/var.rb +61 -0
  117. data/processor/command/show.rb +27 -0
  118. data/processor/command/show_subcmd/alias.rb +50 -0
  119. data/processor/command/show_subcmd/args.rb +50 -0
  120. data/processor/command/show_subcmd/auto.rb +27 -0
  121. data/processor/command/show_subcmd/auto_subcmd/eval.rb +38 -0
  122. data/processor/command/show_subcmd/auto_subcmd/irb.rb +34 -0
  123. data/processor/command/show_subcmd/auto_subcmd/list.rb +36 -0
  124. data/processor/command/show_subcmd/basename.rb +28 -0
  125. data/processor/command/show_subcmd/debug.rb +27 -0
  126. data/processor/command/show_subcmd/debug_subcmd/dbgr.rb +31 -0
  127. data/processor/command/show_subcmd/debug_subcmd/except.rb +33 -0
  128. data/processor/command/show_subcmd/debug_subcmd/macro.rb +32 -0
  129. data/processor/command/show_subcmd/debug_subcmd/skip.rb +33 -0
  130. data/processor/command/show_subcmd/debug_subcmd/stack.rb +32 -0
  131. data/processor/command/show_subcmd/different.rb +37 -0
  132. data/processor/command/show_subcmd/events.rb +40 -0
  133. data/processor/command/show_subcmd/macro.rb +45 -0
  134. data/processor/command/show_subcmd/max.rb +31 -0
  135. data/processor/command/show_subcmd/max_subcmd/list.rb +39 -0
  136. data/processor/command/show_subcmd/max_subcmd/stack.rb +35 -0
  137. data/processor/command/show_subcmd/max_subcmd/string.rb +41 -0
  138. data/processor/command/show_subcmd/max_subcmd/width.rb +36 -0
  139. data/processor/command/show_subcmd/trace.rb +29 -0
  140. data/processor/command/show_subcmd/trace_subcmd/buffer.rb +84 -0
  141. data/processor/command/show_subcmd/trace_subcmd/print.rb +38 -0
  142. data/processor/command/source.rb +74 -0
  143. data/processor/command/step.rb +139 -0
  144. data/processor/command/stepi.rb +63 -0
  145. data/processor/command/unalias.rb +44 -0
  146. data/processor/command/undisplay.rb +63 -0
  147. data/processor/command/up.rb +92 -0
  148. data/processor/default.rb +45 -0
  149. data/processor/display.rb +17 -0
  150. data/processor/eval.rb +88 -0
  151. data/processor/eventbuf.rb +131 -0
  152. data/processor/frame.rb +230 -0
  153. data/processor/help.rb +72 -0
  154. data/processor/hook.rb +128 -0
  155. data/processor/load_cmds.rb +102 -0
  156. data/processor/location.rb +126 -0
  157. data/processor/main.rb +364 -0
  158. data/processor/mock.rb +100 -0
  159. data/processor/msg.rb +26 -0
  160. data/processor/running.rb +170 -0
  161. data/processor/subcmd.rb +159 -0
  162. data/processor/validate.rb +395 -0
  163. data/test/example/fname with blank.rb +1 -0
  164. data/test/example/gcd-xx.rb +18 -0
  165. data/test/example/gcd.rb +19 -0
  166. data/test/example/gcd1.rb +24 -0
  167. data/test/example/null.rb +1 -0
  168. data/test/example/thread1.rb +3 -0
  169. data/test/functional/fn_helper.rb +119 -0
  170. data/test/functional/test-break.rb +87 -0
  171. data/test/functional/test-condition.rb +59 -0
  172. data/test/functional/test-debugger-call-bug.rb +31 -0
  173. data/test/functional/test-delete.rb +71 -0
  174. data/test/functional/test-finish.rb +44 -0
  175. data/test/functional/test-immediate-step-bug.rb +35 -0
  176. data/test/functional/test-next.rb +77 -0
  177. data/test/functional/test-raise.rb +73 -0
  178. data/test/functional/test-return.rb +100 -0
  179. data/test/functional/test-step.rb +274 -0
  180. data/test/functional/test-stepbug.rb +40 -0
  181. data/test/functional/test-trace-var.rb +40 -0
  182. data/test/functional/tmp/b1.rb +5 -0
  183. data/test/functional/tmp/s1.rb +9 -0
  184. data/test/functional/tmp/t2.rb +6 -0
  185. data/test/integration/file-diff.rb +88 -0
  186. data/test/integration/helper.rb +52 -0
  187. data/test/integration/test-fname-with-blank.rb +11 -0
  188. data/test/integration/test-quit.rb +11 -0
  189. data/test/integration/try-test-enable.rb +11 -0
  190. data/test/unit/cmd-helper.rb +44 -0
  191. data/test/unit/test-app-brkpt.rb +30 -0
  192. data/test/unit/test-app-brkptmgr.rb +56 -0
  193. data/test/unit/test-app-disassemble.rb +60 -0
  194. data/test/unit/test-app-file.rb +46 -0
  195. data/test/unit/test-app-frame.rb +49 -0
  196. data/test/unit/test-app-options.rb +60 -0
  197. data/test/unit/test-app-run.rb +19 -0
  198. data/test/unit/test-app-thread.rb +25 -0
  199. data/test/unit/test-app-util.rb +17 -0
  200. data/test/unit/test-base-subcmd.rb +59 -0
  201. data/test/unit/test-bin-trepan.rb +48 -0
  202. data/test/unit/test-cmd-alias.rb +50 -0
  203. data/test/unit/test-cmd-break.rb +80 -0
  204. data/test/unit/test-cmd-endisable.rb +59 -0
  205. data/test/unit/test-cmd-help.rb +100 -0
  206. data/test/unit/test-cmd-kill.rb +47 -0
  207. data/test/unit/test-cmd-quit.rb +26 -0
  208. data/test/unit/test-cmd-step.rb +45 -0
  209. data/test/unit/test-intf-user.rb +45 -0
  210. data/test/unit/test-io-input.rb +26 -0
  211. data/test/unit/test-proc-eval.rb +26 -0
  212. data/test/unit/test-proc-frame.rb +77 -0
  213. data/test/unit/test-proc-help.rb +15 -0
  214. data/test/unit/test-proc-hook.rb +29 -0
  215. data/test/unit/test-proc-load_cmds.rb +40 -0
  216. data/test/unit/test-proc-main.rb +99 -0
  217. data/test/unit/test-proc-validate.rb +90 -0
  218. data/test/unit/test-subcmd-help.rb +48 -0
  219. metadata +358 -0
data/bin/trepan ADDED
@@ -0,0 +1,63 @@
1
+ #!/usr/bin/env ruby
2
+ # Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
3
+ # Invoke debugger from the command line.
4
+ require_relative '../app/run'
5
+ require_relative '../app/options'
6
+ require_relative '../lib/trepanning'
7
+
8
+ # FIXME: the figure out how to run via gem installation.
9
+ if File.basename(__FILE__) == File.basename($0)
10
+ include Trepanning
11
+
12
+ # One way to get local variables is to create a block which is run
13
+ # once.
14
+ #
15
+ # Note however that since there are constants below, we can't
16
+ # wrap all of this in a procedure as that would be defining
17
+ # constants dynamically.
18
+ 1.times do
19
+ | ; trepan_path, program_to_debug |
20
+ # options = DEFAULT_CMDLINE_SETTINGS.merge({}) seems to change up
21
+ # DEFAULT_CMDLINE_SETTINGS when options[:key] is changed. The
22
+ # below is the simplest thing I can come up with so far.
23
+ options = copy_default_options
24
+ opts = setup_options(options)
25
+ Trepan::ARGV = ARGV.clone
26
+ rest = opts.parse! ARGV
27
+
28
+ trepan_path = File.expand_path($0)
29
+ if RUBY_PLATFORM =~ /mswin/
30
+ trepan_path += '.cmd' unless trepan_path =~ /\.cmd$/i
31
+ end
32
+
33
+ # FIXME: do we need to test defined?
34
+ # FIXME: Should (some of) these be instance variables?
35
+ Trepan::RUBY_PATH = ruby_path
36
+ Trepan::TREPAN_PATH = trepan_path
37
+ Trepan::RBDBGR_FILE = __FILE__
38
+
39
+ if ARGV.empty?
40
+ if options[:version] || options[:help]
41
+ exit 100
42
+ else
43
+ STDERR.puts 'Sorry - for now you must specify a Ruby script to debug.'
44
+ exit(1)
45
+ end
46
+ end
47
+
48
+ program_to_debug = ARGV.shift
49
+ program_to_debug = whence_file(program_to_debug) unless
50
+ File.exist?(program_to_debug)
51
+ Trepan::PROG_SCRIPT = program_to_debug
52
+
53
+ # Set global so others may use this debugger.
54
+ $trepan = Trepan.new(:restart_argv =>
55
+ explicit_restart_argv(Trepan::ARGV),
56
+ :cmdfiles => options[:cmdfiles],
57
+ :initial_dir => options[:chdir],
58
+ :nx => options[:nx]
59
+ )
60
+ debug_program($trepan, Trepan::RUBY_PATH,
61
+ File.expand_path(program_to_debug))
62
+ end
63
+ 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
+
data/data/irbrc ADDED
@@ -0,0 +1,55 @@
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', 'n', '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 and make the instruction sequence
34
+ # "filename" unique. Possibly not needed.
35
+ class IRB::Context
36
+ def evaluate(line, line_no)
37
+ $trepan_irb_statements = line
38
+ @line_no = line_no
39
+ @eval_counter ||= 0
40
+ container =
41
+ if irb_path =~ /\((.+)\)/
42
+ # Note we originally had a colon below. This causes IRB to think
43
+ # tracebacks are IRB bugs since the regexp matching it uses here
44
+ # is now messed up. (irb:5): in ... vs (irb): in ...
45
+ "(#{$1}[#{@eval_counter}])"
46
+ else
47
+ irb_path
48
+ end
49
+ set_last_value(@workspace.evaluate(self, line, container, line_no))
50
+ # @workspace.evaluate("_ = IRB.conf[:MAIN_CONTEXT]._")
51
+ # @_ = @workspace.evaluate(line, irb_path, line_no)
52
+ @eval_counter += 1
53
+ end
54
+ end
55
+
data/data/prelude.rb ADDED
@@ -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
@@ -0,0 +1,95 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
3
+
4
+ # A base class for a debugger interface.
5
+
6
+ class Trepan
7
+
8
+ unless defined?(NotImplementedMessage)
9
+ NotImplementedMessage = 'This method must be overriden in a subclass'
10
+ end
11
+
12
+ # A debugger interface handles the communication or interaction with between
13
+ # the program and the outside portion which could be
14
+ # - a user,
15
+ # - a front-end that talks to a user, or
16
+ # - another interface in another process or computer
17
+ class Interface
18
+
19
+ attr_accessor :interactive, :input, :output
20
+
21
+ unless defined?(YES)
22
+ YES = %w(y yes oui si yep ja)
23
+ NO = %w(n no non nope nein)
24
+ YES_OR_NO = YES + NO
25
+ end
26
+
27
+ def initialize(inp=nil, out=nil, opts={})
28
+ @input = inp || STDIN
29
+ @interactive = false
30
+ @opts = opts
31
+ @output = out || STDOUT
32
+ end
33
+
34
+ # Closes all input and/or output.
35
+ def close
36
+ @input.close unless @input.closed?
37
+ @output.close unless @output.closed?
38
+ end
39
+
40
+ # Called when a dangerous action is about to be done to make sure
41
+ # it's okay. `prompt' is printed; user response is returned.
42
+ def confirm(prompt, default=false)
43
+ raise RuntimeError, Trepan::NotImplementedMessage
44
+ end
45
+
46
+ # Common routine for reporting debugger error messages.
47
+ def errmsg(str, prefix='** ')
48
+ if str.is_a?(Array)
49
+ str.each{|s| errmsg(s)}
50
+ else
51
+ str.split("\n").each do |s|
52
+ msg("%s%s" % [prefix, s])
53
+ end
54
+ end
55
+ end
56
+
57
+ def finalize(last_wishes=nil)
58
+ close
59
+ end
60
+
61
+ # Return true if interface is interactive.
62
+ def interactive?
63
+ # Default false and making subclasses figure out how to determine
64
+ # interactiveness.
65
+ false
66
+ end
67
+
68
+ # used to write to a debugger that is connected to this
69
+ # server; `str' written will have a newline added to it.
70
+ def msg(message)
71
+ if message.is_a?(Array)
72
+ message.each{|s| msg(s)}
73
+ else
74
+ message = message ? message.to_s + "\n" : ''
75
+ @output.write(message)
76
+ end
77
+ end
78
+
79
+ # used to write to a debugger that is connected to this
80
+ # server; `str' written will not have a newline added to it
81
+ def msg_nocr(msg)
82
+ @output.write(msg)
83
+ end
84
+
85
+ def read_command( prompt)
86
+ raise RuntimeError, Trepan::NotImplementedMessage
87
+ end
88
+
89
+ def readline(prompt='')
90
+ @output.flush
91
+ @output.write(prompt) if prompt and prompt.size > 0
92
+ @input.readline
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,103 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
3
+
4
+ # Module for reading debugger scripts
5
+
6
+ # Our local modules
7
+ require_relative 'base_intf'
8
+ require_relative '../io/input'
9
+ require_relative '../io/string_array'
10
+
11
+ # Interface when reading debugger scripts
12
+ class Trepan::ScriptInterface < Trepan::Interface
13
+
14
+ DEFAULT_OPTS = {
15
+ :abort_on_error => true,
16
+ :confirm_val => false,
17
+ :verbose => false
18
+ } unless defined?(DEFAULT_OPTS)
19
+
20
+ def initialize(script_name, out=nil, opts={})
21
+
22
+ @opts = DEFAULT_OPTS.merge(opts)
23
+
24
+ at_exit { finalize }
25
+ @script_name = script_name
26
+ @input_lineno = 0
27
+ @input = Trepan::UserInput.open(script_name,
28
+ :line_edit => false)
29
+ @buffer_output = []
30
+ unless opts[:verbose] or out
31
+ out = Trepan::StringArrayOutput.open(@buffer_output)
32
+ end
33
+ super(@input, out, @opts)
34
+ end
35
+
36
+ # Closes input only.
37
+ def close
38
+ @input.close
39
+ end
40
+
41
+ # Called when a dangerous action is about to be done, to make
42
+ # sure it's okay.
43
+ #
44
+ # Could look also look for interactive input and
45
+ # use that. For now, though we'll simplify.
46
+ def confirm(prompt, default)
47
+ @opts[:default_confirm]
48
+ end
49
+
50
+ # Common routine for reporting debugger error messages.
51
+ #
52
+ def errmsg(msg, prefix="*** ")
53
+ # self.verbose shows lines so we don't have to duplicate info
54
+ # here. Perhaps there should be a 'terse' mode to never show
55
+ # position info.
56
+ mess = if not @opts[:verbose]
57
+ location = ("%s:%s: Error in source command file" %
58
+ [@script_name, @input_lineno])
59
+ "%s%s:\n%s%s" % [prefix, location, prefix, msg]
60
+ else
61
+ "%s%s" % [prefix, msg]
62
+ end
63
+ msg(mess)
64
+ # FIXME: should we just set a flag and report eof? to be more
65
+ # consistent with File and IO?
66
+ raise IOError if @opts[:abort_on_error]
67
+ end
68
+
69
+ def interactive? ; false end
70
+
71
+ # Script interface to read a command. `prompt' is a parameter for
72
+ # compatibilty and is ignored.
73
+ def read_command(prompt='')
74
+ @input_lineno += 1
75
+ line = readline
76
+ if @opts[:verbose]
77
+ location = "%s line %s" % [@script_name, @input_lineno]
78
+ msg('+ %s: %s' % [location, line])
79
+ end
80
+ # Do something with history?
81
+ return line
82
+ end
83
+
84
+ # Script interface to read a line. `prompt' is a parameter for
85
+ # compatibilty and is ignored.
86
+ #
87
+ # Could decide make this look for interactive input?
88
+ def readline(prompt='')
89
+ begin
90
+ return input.readline().chomp
91
+ rescue EOFError
92
+ @eof = true
93
+ raise EOFError
94
+ end
95
+ end
96
+ end
97
+
98
+ # Demo
99
+ if __FILE__ == $0
100
+ intf = Trepan::ScriptInterface.new(__FILE__)
101
+ line = intf.readline()
102
+ print "Line read: ", line
103
+ end
data/interface/user.rb ADDED
@@ -0,0 +1,90 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
3
+
4
+ # Interface when communicating with the user in the same process as
5
+ # the debugged program.
6
+
7
+ # Our local modules
8
+
9
+ require_relative 'base_intf'
10
+ require_relative '../io/input'
11
+
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.
16
+ class Trepan::UserInterface < Trepan::Interface
17
+
18
+ FILE_HISTORY = '.trapan_hist' unless defined?(FILE_HISTORY)
19
+
20
+ def initialize(inp=nil, out=nil, opts={})
21
+ super(inp, out, opts)
22
+ @input = if inp.class.ancestors.member?(Trepan::InputBase)
23
+ inp
24
+ else
25
+ Trepan::UserInput.open(inp)
26
+ end
27
+ end
28
+
29
+ # Closes both input and output
30
+
31
+ # Called when a dangerous action is about to be done, to make
32
+ # sure it's okay. Expect a yes/no answer to `prompt' which is printed,
33
+ # suffixed with a question mark and the default value. The user
34
+ # response converted to a boolean is returned.
35
+ def confirm(prompt, default)
36
+ default_str = default ? 'Y/n' : 'N/y'
37
+ while true do
38
+ begin
39
+ response = readline('%s (%s) ' % [prompt, default_str])
40
+ rescue EOFError
41
+ return default
42
+ end
43
+ response = response.strip.downcase
44
+
45
+ # We don't catch "Yes, I'm sure" or "NO!", but I leave that
46
+ # as an exercise for the reader.
47
+ break if YES_OR_NO.member?(response)
48
+ msg "Please answer 'yes' or 'no'. Try again."
49
+ end
50
+ return YES.member?(response)
51
+ end
52
+
53
+ def finalize(last_wishes=nil)
54
+ # print exit annotation
55
+ # save history
56
+ super
57
+ end
58
+
59
+ def interactive? ; @input.interactive? end
60
+
61
+ def read_command(prompt='')
62
+ line = readline(prompt)
63
+ # FIXME: Do something with history?
64
+ return line
65
+ end
66
+ end
67
+
68
+ # Demo
69
+ if __FILE__ == $0
70
+ intf = Trepan::UserInterface.new
71
+ intf.errmsg("Houston, we have a problem here!")
72
+ if ARGV.size > 0
73
+ begin
74
+ line = intf.readline("Type something: ")
75
+ rescue EOFError
76
+ puts "No input, got EOF"
77
+ else
78
+ puts "You typed: #{line}"
79
+ end
80
+ puts "EOF is now: %s" % intf.input.eof?.inspect
81
+ unless intf.input.eof?
82
+ line = intf.confirm("Are you sure", false)
83
+ puts "You typed: #{line}"
84
+ puts "EOF is now: %s" % intf.input.eof?.inspect
85
+ line = intf.confirm("Are you not sure", true)
86
+ puts "You typed: #{line}"
87
+ puts "EOF is now: %s" % intf.input.eof?.inspect
88
+ end
89
+ end
90
+ end
data/io/base_io.rb ADDED
@@ -0,0 +1,92 @@
1
+ # Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
2
+ # classes to support communication to and from the debugger. This
3
+ # communcation might be to/from another process or another computer.
4
+ # And reading may be from a debugger command script.
5
+ #
6
+ # For example, we'd like to support Sockets, and serial lines and file
7
+ # reading, as well a readline-type input. Encryption and Authentication
8
+ # methods might decorate some of the communication channels.
9
+ #
10
+ # Some ideas originiated as part of Matt Fleming's 2006 Google Summer of
11
+ # Code project.
12
+
13
+ class Trepan
14
+
15
+ NotImplementedMessage = 'This method must be overriden in a subclass' unless
16
+ defined?(NotImplementedMessage)
17
+
18
+ class InputBase
19
+ attr_reader :input
20
+ attr_reader :line_edit
21
+
22
+ DEFAULT_OPTS = {
23
+ :line_edit => false,
24
+ } unless defined?(DEFAULT_OPTS)
25
+
26
+ def initialize(inp, opts={})
27
+ @opts = DEFAULT_OPTS.merge(opts)
28
+ @input = inp
29
+ @line_edit = opts[:line_edit]
30
+ end
31
+
32
+ def close
33
+ @input.close unless @input.closed?
34
+ end
35
+
36
+ def eof?
37
+ begin
38
+ @input.eof?
39
+ rescue IOError
40
+ true
41
+ end
42
+ end
43
+
44
+ # Read a line of input. EOFError will be raised on EOF.
45
+ #
46
+ # Note that we don't support prompting first. Instead, arrange
47
+ # to call Trepan::Output.write() first with the prompt. If
48
+ # `use_raw' is set raw_input() will be used in that is supported
49
+ # by the specific input input. If this option is left None as is
50
+ # normally expected the value from the class initialization is
51
+ # used.
52
+ def readline
53
+ @input.readline
54
+ end
55
+ end
56
+
57
+ # This is an abstract class that specifies debugger output.
58
+ class OutputBase
59
+ attr_accessor :flush_after_write
60
+ attr_reader :output
61
+ def initialize(out, opts={})
62
+ @output = out
63
+ @flush_after_write = false
64
+ end
65
+
66
+ def close
67
+ @output.close if @output
68
+ end
69
+
70
+ def eof?
71
+ @input.eof?
72
+ end
73
+
74
+ def flush
75
+ @output.flush
76
+ end
77
+
78
+ # Use this to set where to write to. output can be a
79
+ # file object or a string. This code raises IOError on error.
80
+ def write(*args)
81
+ @output.print(*args)
82
+ end
83
+
84
+ # used to write to a debugger that is connected to this
85
+ # `str' written will have a newline added to it
86
+ #
87
+ def writeline( msg)
88
+ @output.write("%s\n" % msg)
89
+ end
90
+ end
91
+ end
92
+
data/io/input.rb ADDED
@@ -0,0 +1,111 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
3
+
4
+ # Debugger user/command-oriented input possibly attached to IO-style
5
+ # input or GNU Readline.
6
+ #
7
+
8
+ require_relative 'base_io'
9
+
10
+ class Trepan
11
+
12
+ # Debugger user/command-oriented input possibly attached to IO-style
13
+ # input or GNU Readline.
14
+ class UserInput < Trepan::InputBase
15
+
16
+ def initialize(inp, opts={})
17
+ @opts = DEFAULT_OPTS.merge(opts)
18
+ @input = inp || STDIN
19
+ @eof = false
20
+ end
21
+
22
+ def closed?; @input.closed? end
23
+ def eof?; @eof end
24
+
25
+ def interactive?
26
+ @input.respond_to?(:isatty) && @input.isatty
27
+ end
28
+
29
+ # 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.
35
+ raise EOFError if eof?
36
+ begin
37
+ line = @opts[:line_edit] ? Readline.readline : @input.gets
38
+ @eof = !line
39
+ rescue
40
+ @eof = true
41
+ end
42
+ raise EOFError if eof?
43
+ return line
44
+ end
45
+
46
+ class << self
47
+ # Use this to set where to read from.
48
+ #
49
+ # Set opts[:line_edit] if you want this input to interact with
50
+ # GNU-like readline library. By default, we will assume to try
51
+ # using readline.
52
+ def open(inp=nil, opts={})
53
+ inp ||= STDIN
54
+ inp = File.new(inp, 'r') if inp.is_a?(String)
55
+ opts[:line_edit] = false unless
56
+ inp.respond_to?(:isatty) && inp.isatty && Trepan::GNU_readline?
57
+ self.new(inp, opts)
58
+ end
59
+ end
60
+ end
61
+ end
62
+
63
+ def Trepan::GNU_readline?
64
+ begin
65
+ require 'readline'
66
+ return true
67
+ rescue LoadError
68
+ return false
69
+ end
70
+ end
71
+
72
+ # Demo
73
+ if __FILE__ == $0
74
+ puts 'Have GNU is: %s' % Trepan::GNU_readline?
75
+ inp = Trepan::UserInput.open(__FILE__, :line_edit => false)
76
+ line = inp.readline
77
+ puts line
78
+ inp.close
79
+ filename = 'input.py'
80
+ begin
81
+ Trepan::UserInput.open(filename)
82
+ rescue
83
+ puts "Can't open #{filename} for reading: #{$!}"
84
+ end
85
+ inp = Trepan::UserInput.open(__FILE__, :line_edit => false)
86
+ while true
87
+ begin
88
+ inp.readline
89
+ rescue EOFError
90
+ break
91
+ end
92
+ end
93
+ begin
94
+ inp.readline
95
+ rescue EOFError
96
+ puts 'EOF handled correctly'
97
+ end
98
+
99
+ if ARGV.size > 0
100
+ inp = Trepan::UserInput.open
101
+ begin
102
+ print "Type some characters: "
103
+ line = inp.readline()
104
+ puts "You typed: %s" % line
105
+ rescue EOFError
106
+ puts 'Got EOF'
107
+ end
108
+ end
109
+ end
110
+
111
+