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
@@ -0,0 +1,126 @@
1
+ # Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
2
+ require 'linecache'
3
+ require_relative 'msg'
4
+ require_relative '../app/frame'
5
+ class Trepan
6
+ class CmdProcessor
7
+ attr_accessor :reload_on_change
8
+ include Frame
9
+
10
+ def location_initialize
11
+ @reload_on_change = nil
12
+ end
13
+
14
+ def resolve_file_with_dir(path_suffix)
15
+ settings[:directory].split(/:/).each do |dir|
16
+ dir =
17
+ if '$cwd' == dir
18
+ Dir.pwd
19
+ elsif '$cdir' == dir
20
+ @dbgr.initial_dir
21
+ else
22
+ dir
23
+ end
24
+ next unless dir && File.directory?(dir)
25
+ try_file = File.join(dir, path_suffix)
26
+ return try_file if File.readable?(try_file)
27
+ end
28
+ nil
29
+ end
30
+
31
+ # Get line +line_number+ from file named +filename+. Return "\n"
32
+ # there was a problem. Leading blanks are stripped off.
33
+ def line_at(filename, line_number) # :nodoc:
34
+ line = LineCache::getline(filename, line_number, @reload_on_change)
35
+ unless line
36
+ # Try using search directories (set with command "directory")
37
+ if filename[0..0] != File::SEPARATOR
38
+ try_filename = resolve_file_with_dir(filename)
39
+ if try_filename &&
40
+ line = LineCache::getline(try_filename, line_number,
41
+ @reload_on_change)
42
+ LineCache::remap_file(filename, try_filename)
43
+ end
44
+ end
45
+ end
46
+ return "\n" unless line
47
+ return line.lstrip.chomp
48
+ end
49
+
50
+ def loc_and_text(loc, frame, line_no, source_container)
51
+ if source_container[0] != 'file'
52
+ via = loc
53
+ while source_container[0] != 'file' && frame.prev do
54
+ frame = frame.prev
55
+ source_container = frame_container(frame, false)
56
+ end
57
+ if source_container[0] == 'file'
58
+ line_no = frame.source_location[0]
59
+ filename = source_container[1]
60
+ loc += " via #{canonic_file(filename)}:#{line_no}"
61
+ text = line_at(filename, line_no)
62
+ end
63
+ else
64
+ container = source_container[1]
65
+ map_file, map_line = LineCache::map_file_line(container, line_no)
66
+ if [container, line_no] != [map_file, map_line]
67
+ loc += " remapped #{canonic_file(map_file)}:#{map_line}"
68
+ end
69
+
70
+ text = line_at(container, line_no)
71
+ end
72
+ [loc, line_no, text]
73
+ end
74
+
75
+ def print_location
76
+ if %w(c-call call).member?(@event)
77
+ # FIXME: Fix Ruby so we don't need this workaround?
78
+ # See also where.rb
79
+ opts = {}
80
+ opts[:class] = @core.hook_arg if
81
+ 'CFUNC' == @frame.type && @core.hook_arg && 0 == @frame_index
82
+ msg format_stack_call(@frame, opts)
83
+ elsif 'raise' == @event
84
+ msg @core.hook_arg.inspect if @core.hook_arg # Exception object
85
+ end
86
+
87
+ text = nil
88
+ source_container = frame_container(@frame, false)
89
+ ev = if @event.nil? || 0 != @frame_index
90
+ ' '
91
+ else
92
+ (EVENT2ICON[@event] || @event)
93
+ end
94
+ @line_no = frame_line
95
+
96
+ loc = source_location_info(source_container, @line_no, @frame)
97
+ loc, @line_no, text = loc_and_text(loc, @frame, @line_no,
98
+ source_container)
99
+ msg "#{ev} (#{loc})"
100
+
101
+ if %w(return c-return).member?(@event)
102
+ retval = Trepan::Frame.value_returned(@frame, @event)
103
+ msg 'R=> %s' % retval.inspect
104
+ end
105
+
106
+ if text && !text.strip.empty?
107
+ msg text
108
+ @line_no -= 1
109
+ end
110
+ end
111
+
112
+ def source_location_info(source_container, line_no, frame)
113
+ filename = source_container[1]
114
+ canonic_filename =
115
+ if (0 == filename.index('(eval')) && frame.prev &&
116
+ (eval_str = Trepan::Frame.eval_string(frame.prev))
117
+ 'eval ' + safe_repr(eval_str, 15)
118
+ else
119
+ canonic_file(filename)
120
+ end
121
+ loc = "#{canonic_filename}:#{line_no}"
122
+ return loc
123
+ end # source_location_info
124
+
125
+ end
126
+ end
data/processor/main.rb ADDED
@@ -0,0 +1,364 @@
1
+ # Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
2
+ # The main "driver" class for a command processor. Other parts of the
3
+ # command class and debugger command objects are pulled in from here.
4
+
5
+ require 'linecache'
6
+ require 'set'
7
+ require 'pathname' # For cleanpath
8
+
9
+ %w(default breakpoint display eventbuf eval load_cmds location frame hook msg
10
+ running validate).each do
11
+ |mod_str|
12
+ require_relative mod_str
13
+ end
14
+ require_relative '../app/brkptmgr'
15
+
16
+ class Trepan
17
+ class CmdProcessor
18
+
19
+ # SEE ALSO attr's in require_relative's of loop above.
20
+
21
+ attr_reader :cmd_argstr # Current command args, a String.
22
+ # This is current_command with the command
23
+ # name removed from the beginning.
24
+ attr_reader :cmd_name # command name before alias or macro resolution
25
+ attr_reader :core # Trepan core object
26
+ attr_reader :current_command # Current command getting run, a String.
27
+ attr_reader :dbgr # Trepan instance (via
28
+ # Trepan::Core instance)
29
+ attr_accessor :debug_nest # Number of nested debugs. Used in showing
30
+ # prompt.
31
+ attr_accessor :different_pos # Same type as settings[:different]
32
+ # this is the temporary value for the
33
+ # next stop while settings is the default
34
+ # value to use.
35
+ attr_accessor :event # Stop event. Same as @core.event
36
+ attr_accessor :leave_cmd_loop # Commands set this to signal to leave
37
+ # the command loop (which often continues to
38
+ # run the debugged program).
39
+ attr_accessor :line_no # Last line shown in "list" command
40
+ attr_accessor :next_level # Fixnum. frame.stack_size has to
41
+ # be <= than this. If next'ing,
42
+ # this will be > 0.
43
+ attr_accessor :next_thread # Thread. If non-nil then in
44
+ # stepping the thread has to be
45
+ # this thread.
46
+ attr_accessor :pass_exception # Pass an exception back
47
+ attr_accessor :prompt # String print before requesting input
48
+ attr_reader :settings # Hash[:symbol] of command
49
+ # processor settings
50
+
51
+ # The following are used in to force stopping at a different line
52
+ # number. FIXME: could generalize to a position object.
53
+ attr_accessor :last_pos # Last position. 6-Tuple: of
54
+ # [location, container, stack_size,
55
+ # current_thread, pc_offset]
56
+
57
+
58
+ unless defined?(EVENT2ICON)
59
+ # We use event icons in printing locations.
60
+ EVENT2ICON = {
61
+ 'brkpt' => 'xx',
62
+ 'c-call' => 'C>',
63
+ 'c-return' => '<C',
64
+ 'call' => '->',
65
+ 'class' => '::',
66
+ 'coverage' => '[]',
67
+ 'debugger-call' => ':o',
68
+ 'end' => '-|',
69
+ 'line' => '--',
70
+ 'raise' => '!!',
71
+ 'return' => '<-',
72
+ 'switch' => 'sw',
73
+ 'trace-var' => '$V',
74
+ 'unknown' => '?!',
75
+ 'vm' => 'VM',
76
+ 'vm-insn' => '..',
77
+ }
78
+ # These events are important enough event that we always want to
79
+ # stop on them.
80
+ UNMASKABLE_EVENTS = Set.new(['end', 'raise', 'unknown'])
81
+ end
82
+
83
+ def initialize(core, settings={})
84
+ @core = core
85
+ @debug_nest = 1
86
+ @dbgr = core.dbgr
87
+ @hidelevels = {}
88
+ @last_command = nil
89
+ @last_pos = [nil, nil, nil, nil, nil, nil]
90
+ @next_level = 32000
91
+ @next_thread = nil
92
+
93
+ start_cmds = settings.delete(:start_cmds)
94
+ start_file = settings.delete(:start_file)
95
+
96
+ @settings = settings.merge(DEFAULT_SETTINGS)
97
+ @different_pos = @settings[:different]
98
+
99
+ # FIXME: Rework using a general "set substitute file" command and
100
+ # a global default profile which gets read.
101
+ file = File.expand_path(File.join(File.dirname(__FILE__),
102
+ %w(.. data prelude.rb)))
103
+ LineCache::cache(file)
104
+ LineCache::remap_file('<internal:prelude>', file)
105
+ file = File.expand_path(File.join(File.dirname(__FILE__),
106
+ %w(.. data custom_require.rb)))
107
+ LineCache::cache(file)
108
+ LineCache::remap_file('<internal:lib/rubygems/custom_require>',
109
+ file)
110
+
111
+ # Start with empty thread and frame info.
112
+ frame_teardown
113
+
114
+ # Run initialization routines for each of the "submodule"s.
115
+ # load_cmds has to come first.
116
+ %w(load_cmds breakpoint display eventbuf frame running validate
117
+ ).each do |submod|
118
+ self.send("#{submod}_initialize")
119
+ end
120
+ hook_initialize(commands)
121
+
122
+ # FIXME: run start file and start commands.
123
+ end
124
+
125
+ def canonic_container(container)
126
+ [container[0], canonic_file(container[1])]
127
+ end
128
+
129
+ def canonic_file(filename)
130
+ # For now we want resolved filenames
131
+ @settings[:basename] ? File.basename(filename) :
132
+ # Cache this?
133
+ Pathname.new(filename).cleanpath.to_s
134
+ end
135
+
136
+ def compute_prompt
137
+ thread_str =
138
+ if 1 == Thread.list.size
139
+ ''
140
+ elsif Thread.current == Thread.main
141
+ '@main'
142
+ else
143
+ "@#{Thread.current.object_id}"
144
+ end
145
+ "%s#{settings[:prompt]}%s%s: " %
146
+ ['(' * @debug_nest, thread_str, ')' * @debug_nest]
147
+
148
+ end
149
+
150
+ # Check that we meed the criteria that cmd specifies it needs
151
+ def ok_for_running(cmd, name, nargs)
152
+ # TODO check execution_set against execution status.
153
+ # Check we have frame is not null
154
+ min_args = cmd.class.const_get(:MIN_ARGS)
155
+ if nargs < min_args
156
+ errmsg(("Command '%s' needs at least %d argument(s); " +
157
+ "got %d.") % [name, min_args, nargs])
158
+ return false
159
+ end
160
+ max_args = cmd.class.const_get(:MAX_ARGS)
161
+ if max_args and nargs > max_args
162
+ errmsg(("Command '%s' needs at most %d argument(s); " +
163
+ "got %d.") % [name, max_args, nargs])
164
+ return false
165
+ end
166
+ # if cmd.class.const_get(:NEED_RUNNING) && !...
167
+ # errmsg "Command '%s' requires a running program." % name
168
+ # return false
169
+ # end
170
+
171
+ if cmd.class.const_get(:NEED_STACK) && !@frame
172
+ errmsg "Command '%s' requires a running stack frame." % name
173
+ return false
174
+ end
175
+
176
+ return true
177
+ end
178
+
179
+ # Run one debugger command. True is returned if we want to quit.
180
+ def process_command_and_quit?()
181
+ intf = @dbgr.intf
182
+ return true if intf[-1].input.eof? && intf.size == 1
183
+ while !intf[-1].input.eof? || intf.size > 1
184
+ begin
185
+ @current_command = read_command().strip
186
+ if @current_command.empty?
187
+ if @last_command && intf[-1].interactive?
188
+ @current_command = @last_command
189
+ else
190
+ next
191
+ end
192
+ end
193
+ next if @current_command[0..0] == '#' # Skip comment lines
194
+ break
195
+ rescue IOError, Errno::EPIPE
196
+ if @dbgr.intf.size > 1
197
+ @dbgr.intf.pop
198
+ @last_command = nil
199
+ print_location
200
+ else
201
+ msg "EOF - Leaving"
202
+ ## FIXME: think of something better.
203
+ quit('quit!')
204
+ return true
205
+ end
206
+ end
207
+ end
208
+ run_command(@current_command)
209
+ end
210
+
211
+ # This is the main entry point.
212
+ def process_commands(frame)
213
+
214
+ frame_setup(frame)
215
+ @event = @core.event
216
+
217
+ @unconditional_prehooks.run
218
+ if breakpoint?
219
+ @last_pos = [@frame.source_container, frame_line,
220
+ @stack_size, @current_thread, @event,
221
+ @frame.pc_offset]
222
+ else
223
+ return if stepping_skip? || @stack_size <= @hide_level
224
+ end
225
+
226
+ @prompt = compute_prompt
227
+
228
+ @leave_cmd_loop = false
229
+ print_location unless @settings[:traceprint]
230
+ if 'trace-var' == @event
231
+ msg "Note: we are stopped *after* the above location."
232
+ end
233
+
234
+ @eventbuf.add_mark if @settings[:tracebuffer]
235
+
236
+ @cmdloop_prehooks.run
237
+ while not @leave_cmd_loop do
238
+ begin
239
+ break if process_command_and_quit?()
240
+ rescue SystemExit
241
+ @dbgr.stop
242
+ raise
243
+ rescue Exception => exc
244
+ msg("Internal debugger error: #{exc.inspect}")
245
+ exception_dump(exc, @settings[:debugexcept], $!.backtrace)
246
+ end
247
+ end
248
+ @cmdloop_posthooks.run
249
+ end
250
+
251
+ # Run current_command, a String. @last_command is set after the
252
+ # command is run if it is a command.
253
+ def run_command(current_command)
254
+ eval_command =
255
+ if current_command[0..0] == '!'
256
+ current_command[0] = ''
257
+ else
258
+ false
259
+ end
260
+
261
+ unless eval_command
262
+ # Expand macros. FIXME: put in a procedure
263
+ args = current_command.split
264
+ while true do
265
+ macro_cmd_name = args[0]
266
+ return false if args.size == 0
267
+ break unless @macros.member?(macro_cmd_name)
268
+ current_command = @macros[macro_cmd_name].call(*args[1..-1])
269
+ msg current_command if settings[:debugmacro]
270
+ if current_command.is_a?(Array) &&
271
+ current_command.any {|val| !val.is_a?(String)}
272
+ args = current_command
273
+ elsif current_command.is_a?(String)
274
+ args = current_command.split
275
+ else
276
+ errmsg("macro #{macro_cmd_name} should return an Array " +
277
+ "of Strings or a String. Got #{current_command.inspect}")
278
+ return false
279
+ end
280
+ end
281
+
282
+ @cmd_name = args[0]
283
+ run_cmd_name =
284
+ if @aliases.member?(@cmd_name)
285
+ @aliases[@cmd_name]
286
+ else
287
+ @cmd_name
288
+ end
289
+
290
+ if @commands.member?(run_cmd_name)
291
+ cmd = @commands[run_cmd_name]
292
+ if ok_for_running(cmd, run_cmd_name, args.size-1)
293
+ @cmd_argstr = current_command[@cmd_name.size..-1].lstrip
294
+ cmd.run(args)
295
+ @last_command = current_command
296
+ end
297
+ return false
298
+ end
299
+ end
300
+
301
+ # Eval anything that's not a command or has been
302
+ # requested to be eval'd
303
+ if settings[:autoeval] || eval_command
304
+ ## eval_code(current_command, @settings[:maxstring])
305
+ msg 'D=> ' + debug_eval(current_command).inspect
306
+ else
307
+ undefined_command(cmd_name)
308
+ end
309
+ return false
310
+ end
311
+
312
+ # Error message when a command doesn't exist
313
+ def undefined_command(cmd_name)
314
+ errmsg('Undefined command: "%s". Try "help".' % cmd_name)
315
+ end
316
+
317
+ # FIXME: Allow access to both Trepan::CmdProcessor and Trepan
318
+ # for index [] and []=.
319
+ # If there is a Trepan::CmdProcessor setting that would take precidence.
320
+ # def settings
321
+ # @settings.merge(@dbgr.settings) # wrong because this doesn't allow []=
322
+ # end
323
+ end
324
+ end
325
+
326
+ if __FILE__ == $0
327
+ $0 = 'foo' # So we don't get here again
328
+ require_relative '../lib/trepanning'
329
+ dbg = Trepan.new(:nx => true)
330
+ dbg.core.processor.msg('I am main')
331
+ cmdproc = dbg.core.processor
332
+ cmdproc.errmsg('Whoa!')
333
+ cmds = cmdproc.commands
334
+ p cmdproc.aliases
335
+ cmd_name, cmd_obj = cmds.first
336
+ puts cmd_obj.class.const_get(:HELP)
337
+ puts cmd_obj.class.const_get(:SHORT_HELP)
338
+
339
+ puts cmdproc.compute_prompt
340
+ Thread.new{ puts cmdproc.compute_prompt }.join
341
+
342
+ th = Thread.new{ Thread.pass; x = 1 }
343
+ puts cmdproc.compute_prompt
344
+ th.join
345
+ cmdproc.debug_nest += 1
346
+ puts cmdproc.compute_prompt
347
+
348
+
349
+ if ARGV.size > 0
350
+ dbg.core.processor.msg('Enter "q" to quit')
351
+ dbg.proc_process_commands
352
+ else
353
+ $input = []
354
+ class << dbg.core.processor
355
+ def read_command
356
+ $input.shift
357
+ end
358
+ end
359
+ $input = ['1+2']
360
+ dbg.core.processor.process_command_and_quit?
361
+ $input = ['!s = 5'] # ! means eval line
362
+ dbg.core.processor.process_command_and_quit?
363
+ end
364
+ end
data/processor/mock.rb ADDED
@@ -0,0 +1,100 @@
1
+ # Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
2
+ # Mock setup for commands.
3
+ require_relative 'main'
4
+ require_relative '../app/core'
5
+ require_relative '../app/default'
6
+ require_relative '../interface/user' # user interface (includes I/O)
7
+
8
+ SCRIPT_ISEQS__ = {} unless
9
+ defined?(SCRIPT_ISEQS__) && SCRIPT_ISEQS__.is_a?(Hash)
10
+ ISEQS__ = {} unless
11
+ defined?(ISEQS__) && ISEQS__.is_a?(Hash)
12
+
13
+ module MockDebugger
14
+ class MockDebugger
15
+ attr_accessor :trace_filter # Procs/Methods we ignore.
16
+
17
+ attr_accessor :core # access to Debugger::Core instance
18
+ attr_accessor :intf # The way the outside world interfaces with us.
19
+ attr_reader :initial_dir # String. Current directory when program
20
+ # started. Used in restart program.
21
+ attr_accessor :restart_argv # How to restart us, empty or nil.
22
+ # Note restart[0] is typically $0.
23
+ attr_reader :settings # Hash[:symbol] of things you can configure
24
+
25
+ def initialize(settings={})
26
+ @before_cmdloop_hooks = []
27
+ @settings = Trepanning::DEFAULT_SETTINGS.merge(settings)
28
+ @intf = [Trepan::UserInterface.new]
29
+ @core = Trepan::Core.new(self)
30
+ @trace_filter = []
31
+
32
+ # Don't allow user commands in mocks.
33
+ @core.processor.settings[:user_cmd_dir] = nil
34
+
35
+ end
36
+
37
+ end
38
+
39
+ # Common Mock debugger setup
40
+ def setup(name, show_constants=true)
41
+ if ARGV.size > 0 && ARGV[0] == 'debug'
42
+ require_relative '../lib/trepanning'
43
+ dbgr = Trepan.new
44
+ dbgr.debugger
45
+ else
46
+ dbgr = MockDebugger.new
47
+ end
48
+
49
+ cmds = dbgr.core.processor.commands
50
+ cmd = cmds[name]
51
+ cmd.proc.frame_setup(RubyVM::ThreadFrame::current.prev)
52
+ show_special_class_constants(cmd) if show_constants
53
+
54
+ def cmd.msg(message)
55
+ puts message
56
+ end
57
+ def cmd.msg_nocr(message)
58
+ print message
59
+ end
60
+ def cmd.errmsg(message)
61
+ puts "Error: #{message}"
62
+ end
63
+ def cmd.confirm(prompt, default)
64
+ true
65
+ end
66
+
67
+ return dbgr, cmd
68
+ end
69
+ module_function :setup
70
+
71
+ def show_special_class_constants(cmd)
72
+ puts 'ALIASES: %s' % [cmd.class.const_get('ALIASES').inspect] if
73
+ cmd.class.constants.member?(:ALIASES)
74
+ %w(CATEGORY HELP MIN_ARGS MAX_ARGS
75
+ NAME NEED_STACK SHORT_HELP).each do |name|
76
+ puts '%s: %s' % [name, cmd.class.const_get(name).inspect]
77
+ end
78
+ puts '- - -'
79
+ end
80
+ module_function :show_special_class_constants
81
+
82
+ end
83
+
84
+ # To get Trepan::CmdProcessor defined and with the
85
+ # with the correct initialize parameters.
86
+ class Trepan
87
+ class << CmdProcessor
88
+ def initialize(core, settings={})
89
+ @core = core
90
+ @settings = settings
91
+ end
92
+ end
93
+ end
94
+
95
+ if __FILE__ == $0
96
+ dbgr = MockDebugger::MockDebugger.new
97
+ p dbgr.settings
98
+ puts '=' * 10
99
+ p dbgr.core.processor.settings
100
+ end
data/processor/msg.rb ADDED
@@ -0,0 +1,26 @@
1
+ # Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
2
+ # I/O related command processor methods
3
+ require_relative '../app/util'
4
+ class Trepan
5
+ class CmdProcessor
6
+ def errmsg(message)
7
+ @dbgr.intf[-1].errmsg(safe_rep(message))
8
+ end
9
+
10
+ def msg(message)
11
+ @dbgr.intf[-1].msg(safe_rep(message))
12
+ end
13
+
14
+ def msg_nocr(message)
15
+ @dbgr.intf[-1].msg_nocr(safe_rep(message))
16
+ end
17
+
18
+ def read_command()
19
+ @dbgr.intf[-1].read_command(@prompt)
20
+ end
21
+
22
+ def safe_rep(str)
23
+ Trepan::Util::safe_repr(str, @settings[:maxstring])
24
+ end
25
+ end
26
+ end