ruby-debug19 0.11.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. data/AUTHORS +9 -0
  2. data/LICENSE +23 -0
  3. data/bin/rdebug +415 -0
  4. data/cli/ruby-debug.rb +176 -0
  5. data/cli/ruby-debug/command.rb +228 -0
  6. data/cli/ruby-debug/commands/breakpoints.rb +153 -0
  7. data/cli/ruby-debug/commands/catchpoint.rb +55 -0
  8. data/cli/ruby-debug/commands/condition.rb +49 -0
  9. data/cli/ruby-debug/commands/continue.rb +38 -0
  10. data/cli/ruby-debug/commands/control.rb +107 -0
  11. data/cli/ruby-debug/commands/display.rb +120 -0
  12. data/cli/ruby-debug/commands/edit.rb +48 -0
  13. data/cli/ruby-debug/commands/enable.rb +202 -0
  14. data/cli/ruby-debug/commands/eval.rb +176 -0
  15. data/cli/ruby-debug/commands/finish.rb +42 -0
  16. data/cli/ruby-debug/commands/frame.rb +301 -0
  17. data/cli/ruby-debug/commands/help.rb +56 -0
  18. data/cli/ruby-debug/commands/info.rb +469 -0
  19. data/cli/ruby-debug/commands/irb.rb +123 -0
  20. data/cli/ruby-debug/commands/kill.rb +51 -0
  21. data/cli/ruby-debug/commands/list.rb +94 -0
  22. data/cli/ruby-debug/commands/method.rb +84 -0
  23. data/cli/ruby-debug/commands/quit.rb +39 -0
  24. data/cli/ruby-debug/commands/reload.rb +40 -0
  25. data/cli/ruby-debug/commands/save.rb +90 -0
  26. data/cli/ruby-debug/commands/set.rb +237 -0
  27. data/cli/ruby-debug/commands/show.rb +253 -0
  28. data/cli/ruby-debug/commands/source.rb +36 -0
  29. data/cli/ruby-debug/commands/stepping.rb +81 -0
  30. data/cli/ruby-debug/commands/threads.rb +189 -0
  31. data/cli/ruby-debug/commands/tmate.rb +36 -0
  32. data/cli/ruby-debug/commands/trace.rb +57 -0
  33. data/cli/ruby-debug/commands/variables.rb +199 -0
  34. data/cli/ruby-debug/debugger.rb +5 -0
  35. data/cli/ruby-debug/helper.rb +69 -0
  36. data/cli/ruby-debug/interface.rb +232 -0
  37. data/cli/ruby-debug/processor.rb +474 -0
  38. data/rdbg.rb +33 -0
  39. metadata +122 -0
@@ -0,0 +1,56 @@
1
+ module Debugger
2
+
3
+ # Implements debugger "help" command.
4
+ class HelpCommand < Command
5
+ self.allow_in_control = true
6
+
7
+ def regexp
8
+ /^\s* h(?:elp)? (?:\s+(.+))? $/x
9
+ end
10
+
11
+ def execute
12
+ if @match[1]
13
+ args = @match[1].split
14
+ cmds = @state.commands.select do |cmd|
15
+ [cmd.help_command].flatten.include?(args[0])
16
+ end
17
+ else
18
+ args = @match[1]
19
+ cmds = []
20
+ end
21
+ unless cmds.empty?
22
+ help = cmds.map{ |cmd| cmd.help(args) }.join
23
+ help = help.split("\n").map{|l| l.gsub(/^ +/, '')}
24
+ help.shift if help.first && help.first.empty?
25
+ help.pop if help.last && help.last.empty?
26
+ print help.join("\n")
27
+ else
28
+ if args and args[0]
29
+ errmsg "Undefined command: \"#{args[0]}\". Try \"help\"."
30
+ else
31
+ print "ruby-debug help v#{Debugger::VERSION}\n" unless
32
+ self.class.settings[:debuggertesting]
33
+ print "Type 'help <command-name>' for help on a specific command\n\n"
34
+ print "Available commands:\n"
35
+ cmds = @state.commands.map{ |cmd| cmd.help_command }
36
+ cmds = cmds.flatten.uniq.sort
37
+ print columnize(cmds, self.class.settings[:width])
38
+ end
39
+ end
40
+ print "\n"
41
+ end
42
+
43
+ class << self
44
+ def help_command
45
+ 'help'
46
+ end
47
+
48
+ def help(cmd)
49
+ %{
50
+ h[elp]\t\tprint this help
51
+ h[elp] command\tprint help on command
52
+ }
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,469 @@
1
+ module Debugger
2
+ module InfoFunctions # :nodoc:
3
+ def info_catch(*args)
4
+ unless @state.context
5
+ print "No frame selected.\n"
6
+ return
7
+ end
8
+ if Debugger.catchpoints and not Debugger.catchpoints.empty?
9
+ # FIXME: show whether Exception is valid or not
10
+ # print "Exception: is_a?(Class)\n"
11
+ Debugger.catchpoints.each do |exception, hits|
12
+ # print "#{exception}: #{exception.is_a?(Class)}\n"
13
+ print "#{exception}\n"
14
+ end
15
+ else
16
+ print "No exceptions set to be caught.\n"
17
+ end
18
+ end
19
+ end
20
+
21
+ # Implements debugger "info" command.
22
+ class InfoCommand < Command
23
+ self.allow_in_control = true
24
+ Subcommands =
25
+ [
26
+ ['args', 1, 'Argument variables of current stack frame'],
27
+ ['breakpoints', 1, 'Status of user-settable breakpoints',
28
+ 'Without argument, list info about all breakpoints. With an
29
+ integer argument, list info on that breakpoint.'],
30
+ ['catch', 3, 'Exceptions that can be caught in the current stack frame'],
31
+ ['display', 2, 'Expressions to display when program stops'],
32
+ ['file', 4, 'Info about a particular file read in',
33
+ '
34
+ After the file name is supplied, you can list file attributes that
35
+ you wish to see.
36
+
37
+ Attributes include: "all", "basic", "breakpoint", "lines", "mtime", "path"
38
+ and "sha1".'],
39
+ ['files', 5, 'File names and timestamps of files read in'],
40
+ ['global_variables', 2, 'Global variables'],
41
+ ['instance_variables', 2,
42
+ 'Instance variables of the current stack frame'],
43
+ ['line', 2,
44
+ 'Line number and file name of current position in source file'],
45
+ ['locals', 2, 'Local variables of the current stack frame'],
46
+ ['program', 2, 'Execution status of the program'],
47
+ ['stack', 2, 'Backtrace of the stack'],
48
+ ['thread', 6, 'List info about thread NUM', '
49
+ If no thread number is given, we list info for all threads. \'terse\' and \'verbose\'
50
+ options are possible. If terse, just give summary thread name information. See
51
+ "help info threads" for more detail about this summary information.
52
+
53
+ If \'verbose\' appended to the end of the command, then the entire
54
+ stack trace is given for each thread.'],
55
+ ['threads', 7, 'information of currently-known threads', '
56
+ This information includes whether the thread is current (+), if it is
57
+ suspended ($), or ignored (!). The thread number and the top stack
58
+ item. If \'verbose\' is given then the entire stack frame is shown.'],
59
+ ['variables', 1,
60
+ 'Local and instance variables of the current stack frame']
61
+ ].map do |name, min, short_help, long_help|
62
+ SubcmdStruct.new(name, min, short_help, long_help)
63
+ end unless defined?(Subcommands)
64
+
65
+ InfoFileSubcommands =
66
+ [
67
+ ['all', 1,
68
+ 'All file information available - breakpoints, lines, mtime, path, and sha1'],
69
+ ['basic', 2,
70
+ 'basic information - path, number of lines'],
71
+ ['breakpoints', 2, 'Show trace line numbers',
72
+ 'These are the line number where a breakpoint can be set.'],
73
+ ['lines', 1, 'Show number of lines in the file'],
74
+ ['mtime', 1, 'Show modification time of file'],
75
+ ['path', 4, 'Show full file path name for file'],
76
+ ['sha1', 1, 'Show SHA1 hash of contents of the file']
77
+ ].map do |name, min, short_help, long_help|
78
+ SubcmdStruct.new(name, min, short_help, long_help)
79
+ end unless defined?(InfoFileSubcommands)
80
+
81
+ InfoThreadSubcommands =
82
+ [
83
+ ['terse', 1, 'summary information'],
84
+ ['verbose', 1, 'summary information and stack frame info'],
85
+ ].map do |name, min, short_help, long_help|
86
+ SubcmdStruct.new(name, min, short_help, long_help)
87
+ end unless defined?(InfoThreadSubcommands)
88
+
89
+ def regexp
90
+ /^\s* i(?:nfo)? (?:\s+(.*))?$/ix
91
+ end
92
+
93
+ def execute
94
+ if @match[1].empty?
95
+ errmsg "\"info\" must be followed by the name of an info command:\n"
96
+ print "List of info subcommands:\n\n"
97
+ for subcmd in Subcommands do
98
+ print "info #{subcmd.name} -- #{subcmd.short_help}\n"
99
+ end
100
+ else
101
+ args = @match[1].split(/[ \t]+/)
102
+ param = args.shift
103
+ subcmd = find(Subcommands, param)
104
+ if subcmd
105
+ send("info_#{subcmd.name}", *args)
106
+ else
107
+ errmsg "Unknown info command #{param}\n"
108
+ end
109
+ end
110
+ end
111
+
112
+ def info_args(*args)
113
+ unless @state.context
114
+ print "No frame selected.\n"
115
+ return
116
+ end
117
+ locals = @state.context.frame_locals(@state.frame_pos)
118
+ args = @state.context.frame_args(@state.frame_pos)
119
+ args.each do |name|
120
+ s = "#{name} = #{locals[name].inspect}"
121
+ if s.size > self.class.settings[:width]
122
+ s[self.class.settings[:width]-3 .. -1] = "..."
123
+ end
124
+ print "#{s}\n"
125
+ end
126
+ end
127
+
128
+ def info_breakpoints(*args)
129
+ unless @state.context
130
+ print "info breakpoints not available here.\n"
131
+ return
132
+ end
133
+ unless Debugger.breakpoints.empty?
134
+ brkpts = Debugger.breakpoints.sort_by{|b| b.id}
135
+ unless args.empty?
136
+ a = args.map{|a| a.to_i}
137
+ brkpts = brkpts.select{|b| a.member?(b.id)}
138
+ if brkpts.empty?
139
+ errmsg "No breakpoints found among list given.\n"
140
+ return
141
+ end
142
+ end
143
+ print "Num Enb What\n"
144
+ brkpts.each do |b|
145
+ if b.expr.nil?
146
+ print "%3d %s at %s:%s\n",
147
+ b.id, (b.enabled? ? 'y' : 'n'), b.source, b.pos
148
+ else
149
+ print "%3d %s at %s:%s if %s\n",
150
+ b.id, (b.enabled? ? 'y' : 'n'), b.source, b.pos, b.expr
151
+ end
152
+ hits = b.hit_count
153
+ if hits > 0
154
+ s = (hits > 1) ? 's' : ''
155
+ print "\tbreakpoint already hit #{hits} time#{s}\n"
156
+ end
157
+ end
158
+ else
159
+ print "No breakpoints.\n"
160
+ end
161
+ end
162
+
163
+ def info_display(*args)
164
+ unless @state.context
165
+ print "info display not available here.\n"
166
+ return
167
+ end
168
+ if @state.display.find{|d| d[0]}
169
+ print "Auto-display expressions now in effect:\n"
170
+ print "Num Enb Expression\n"
171
+ n = 1
172
+ for d in @state.display
173
+ print "%3d: %s %s\n", n, (d[0] ? 'y' : 'n'), d[1] if
174
+ d[0] != nil
175
+ n += 1
176
+ end
177
+ else
178
+ print "There are no auto-display expressions now.\n"
179
+ end
180
+ end
181
+
182
+ def info_file(*args)
183
+ unless args[0]
184
+ info_files
185
+ return
186
+ end
187
+ file = args[0]
188
+ param = args[1]
189
+
190
+ param = 'basic' unless param
191
+ subcmd = find(InfoFileSubcommands, param)
192
+ unless subcmd
193
+ errmsg "Invalid parameter #{param}\n"
194
+ return
195
+ end
196
+
197
+ unless LineCache::cached?(file)
198
+ unless LineCache::cached_script?(file)
199
+ print "File #{file} is not cached\n"
200
+ return
201
+ end
202
+ LineCache::cache(file, Command.settings[:reload_source_on_change])
203
+ end
204
+
205
+ print "File %s", file
206
+ path = LineCache.path(file)
207
+ if %w(all basic path).member?(subcmd.name) and path != file
208
+ print " - %s\n", path
209
+ else
210
+ print "\n"
211
+ end
212
+
213
+ if %w(all basic lines).member?(subcmd.name)
214
+ lines = LineCache.size(file)
215
+ print "\t %d lines\n", lines if lines
216
+ end
217
+
218
+ if %w(all breakpoints).member?(subcmd.name)
219
+ breakpoints = LineCache.trace_line_numbers(file)
220
+ if breakpoints
221
+ print "\tbreakpoint line numbers:\n"
222
+ print columnize(breakpoints.to_a.sort, self.class.settings[:width])
223
+ end
224
+ end
225
+
226
+ if %w(all mtime).member?(subcmd.name)
227
+ stat = LineCache.stat(file)
228
+ print "\t%s\n", stat.mtime if stat
229
+ end
230
+ if %w(all sha1).member?(subcmd.name)
231
+ print "\t%s\n", LineCache.sha1(file)
232
+ end
233
+ end
234
+
235
+ def info_files(*args)
236
+ files = LineCache::cached_files
237
+ files += SCRIPT_LINES__.keys unless 'stat' == args[0]
238
+ files.uniq.sort.each do |file|
239
+ stat = LineCache::stat(file)
240
+ path = LineCache::path(file)
241
+ print "File %s", file
242
+ if path and path != file
243
+ print " - %s\n", path
244
+ else
245
+ print "\n"
246
+ end
247
+ print "\t%s\n", stat.mtime if stat
248
+ end
249
+ end
250
+
251
+ def info_instance_variables(*args)
252
+ unless @state.context
253
+ print "info instance_variables not available here.\n"
254
+ return
255
+ end
256
+ obj = debug_eval('self')
257
+ var_list(obj.instance_variables)
258
+ end
259
+
260
+ def info_line(*args)
261
+ unless @state.context
262
+ errmsg "info line not available here.\n"
263
+ return
264
+ end
265
+ print "Line %d of \"%s\"\n", @state.line, @state.file
266
+ end
267
+
268
+ def info_locals(*args)
269
+ unless @state.context
270
+ errmsg "info line not available here.\n"
271
+ return
272
+ end
273
+ locals = @state.context.frame_locals(@state.frame_pos)
274
+ locals.keys.sort.each do |name|
275
+ ### FIXME: make a common routine
276
+ begin
277
+ s = "#{name} = #{locals[name].inspect}"
278
+ rescue
279
+ begin
280
+ s = "#{name} = #{locals[name].to_s}"
281
+ rescue
282
+ s = "*Error in evaluation*"
283
+ end
284
+ end
285
+ if s.size > self.class.settings[:width]
286
+ s[self.class.settings[:width]-3 .. -1] = "..."
287
+ end
288
+ print "#{s}\n"
289
+ end
290
+ end
291
+
292
+ def info_program(*args)
293
+ if not @state.context
294
+ print "The program being debugged is not being run.\n"
295
+ return
296
+ elsif @state.context.dead?
297
+ print "The program crashed.\n"
298
+ if Debugger.last_exception
299
+ print("Exception: #{Debugger.last_exception.inspect}\n")
300
+ end
301
+ return
302
+ end
303
+
304
+ print "Program stopped. "
305
+ case @state.context.stop_reason
306
+ when :step
307
+ print "It stopped after stepping, next'ing or initial start.\n"
308
+ when :breakpoint
309
+ print("It stopped at a breakpoint.\n")
310
+ when :catchpoint
311
+ print("It stopped at a catchpoint.\n")
312
+ when :catchpoint
313
+ print("It stopped at a catchpoint.\n")
314
+ else
315
+ print "unknown reason: %s\n" % @state.context.stop_reason.to_s
316
+ end
317
+ end
318
+
319
+ def info_stack(*args)
320
+ if not @state.context
321
+ errmsg "info stack not available here.\n"
322
+ return
323
+ end
324
+ (0...@state.context.stack_size).each do |idx|
325
+ if idx == @state.frame_pos
326
+ print "--> "
327
+ else
328
+ print " "
329
+ end
330
+ print_frame(idx)
331
+ end
332
+ end
333
+
334
+ def info_thread_preamble(arg)
335
+ if not @state.context
336
+ errmsg "info threads not available here.\n"
337
+ return false, false
338
+ end
339
+ verbose = if arg
340
+ subcmd = find(InfoThreadSubcommands, arg)
341
+ unless subcmd
342
+ errmsg "'terse' or 'verbose' expected. Got '#{arg}'\n"
343
+ return false, false
344
+ end
345
+ 'verbose' == subcmd.name
346
+ else
347
+ false
348
+ end
349
+ return true, verbose
350
+ end
351
+ private :info_thread_preamble
352
+
353
+ def info_threads(*args)
354
+ ok, verbose = info_thread_preamble(args[0])
355
+ return unless ok
356
+ threads = Debugger.contexts.sort_by{|c| c.thnum}.each do |c|
357
+ display_context(c, !verbose)
358
+ if verbose and not c.ignored?
359
+ (0...c.stack_size).each do |idx|
360
+ print "\t"
361
+ print_frame(idx, false, c)
362
+ end
363
+ end
364
+ end
365
+ end
366
+
367
+ def info_thread(*args)
368
+ unless args[0]
369
+ info_threads(args[0])
370
+ return
371
+ end
372
+ ok, verbose = info_thread_preamble(args[1])
373
+ return unless ok
374
+ c = parse_thread_num("info thread" , args[0])
375
+ return unless c
376
+ display_context(c, !verbose)
377
+ if verbose and not c.ignored?
378
+ (0...c.stack_size).each do |idx|
379
+ print "\t"
380
+ print_frame(idx, false, c)
381
+ end
382
+ end
383
+ end
384
+
385
+ def info_global_variables(*args)
386
+ unless @state.context
387
+ errmsg "info global_variables not available here.\n"
388
+ return
389
+ end
390
+ var_list(global_variables)
391
+ end
392
+
393
+ def info_variables(*args)
394
+ if not @state.context
395
+ errmsg "info variables not available here.\n"
396
+ return
397
+ end
398
+ obj = debug_eval('self')
399
+ locals = @state.context.frame_locals(@state.frame_pos)
400
+ locals['self'] = @state.context.frame_self(@state.frame_pos)
401
+ locals.keys.sort.each do |name|
402
+ next if name =~ /^__dbg_/ # skip debugger pollution
403
+ ### FIXME: make a common routine
404
+ begin
405
+ s = "#{name} = #{locals[name].inspect}"
406
+ rescue
407
+ begin
408
+ s = "#{name} = #{locals[name].to_s}"
409
+ rescue
410
+ s = "#{name} = *Error in evaluation*"
411
+ end
412
+ end
413
+ if s.size > self.class.settings[:width]
414
+ s[self.class.settings[:width]-3 .. -1] = "..."
415
+ end
416
+ s.gsub!('%', '%%') # protect against printf format strings
417
+ print "#{s}\n"
418
+ end
419
+ var_list(obj.instance_variables, obj.instance_eval{binding()})
420
+ var_class_self
421
+ end
422
+
423
+ class << self
424
+ def help_command
425
+ 'info'
426
+ end
427
+
428
+ def help(args)
429
+ if args[1]
430
+ s = args[1]
431
+ subcmd = Subcommands.find do |try_subcmd|
432
+ (s.size >= try_subcmd.min) and
433
+ (try_subcmd.name[0..s.size-1] == s)
434
+ end
435
+ if subcmd
436
+ str = subcmd.short_help + '.'
437
+ if 'file' == subcmd.name and args[2]
438
+ s = args[2]
439
+ subsubcmd = InfoFileSubcommands.find do |try_subcmd|
440
+ (s.size >= try_subcmd.min) and
441
+ (try_subcmd.name[0..s.size-1] == s)
442
+ end
443
+ if subsubcmd
444
+ str += "\n" + subsubcmd.short_help + '.'
445
+ else
446
+ str += "\nInvalid file attribute #{args[2]}."
447
+ end
448
+ else
449
+ str += "\n" + subcmd.long_help if subcmd.long_help
450
+ end
451
+ return str
452
+ else
453
+ return "Invalid 'info' subcommand '#{args[1]}'."
454
+ end
455
+ end
456
+ s = %{
457
+ Generic command for showing things about the program being debugged.
458
+ --
459
+ List of info subcommands:
460
+ --
461
+ }
462
+ for subcmd in Subcommands do
463
+ s += "info #{subcmd.name} -- #{subcmd.short_help}\n"
464
+ end
465
+ return s
466
+ end
467
+ end
468
+ end
469
+ end