trepanning 0.0.4

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