ruby-debug 0.10.0 → 0.10.1

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 (152) hide show
  1. data/CHANGES +94 -2
  2. data/ChangeLog +5225 -0
  3. data/README +30 -1
  4. data/Rakefile +55 -24
  5. data/bin/rdebug +249 -128
  6. data/cli/ruby-debug/command.rb +30 -3
  7. data/cli/ruby-debug/commands/breakpoints.rb +54 -24
  8. data/cli/ruby-debug/commands/catchpoint.rb +13 -12
  9. data/cli/ruby-debug/commands/condition.rb +49 -0
  10. data/cli/ruby-debug/commands/continue.rb +32 -0
  11. data/cli/ruby-debug/commands/control.rb +19 -43
  12. data/cli/ruby-debug/commands/disassemble.RB +38 -0
  13. data/cli/ruby-debug/commands/display.rb +1 -1
  14. data/cli/ruby-debug/commands/edit.rb +48 -0
  15. data/cli/ruby-debug/commands/enable.rb +78 -35
  16. data/cli/ruby-debug/commands/eval.rb +6 -5
  17. data/cli/ruby-debug/commands/finish.rb +42 -0
  18. data/cli/ruby-debug/commands/frame.rb +64 -33
  19. data/cli/ruby-debug/commands/help.rb +19 -15
  20. data/cli/ruby-debug/commands/info.rb +295 -36
  21. data/cli/ruby-debug/commands/irb.rb +3 -1
  22. data/cli/ruby-debug/commands/list.rb +27 -50
  23. data/cli/ruby-debug/commands/quit.rb +38 -0
  24. data/cli/ruby-debug/commands/reload.rb +40 -0
  25. data/cli/ruby-debug/commands/save.rb +80 -0
  26. data/cli/ruby-debug/commands/{settings.rb → set.rb} +50 -12
  27. data/cli/ruby-debug/commands/show.rb +83 -27
  28. data/cli/ruby-debug/commands/source.rb +36 -0
  29. data/cli/ruby-debug/commands/stepping.rb +36 -72
  30. data/cli/ruby-debug/commands/threads.rb +32 -23
  31. data/cli/ruby-debug/commands/variables.rb +34 -4
  32. data/cli/ruby-debug/helper.rb +10 -75
  33. data/cli/ruby-debug/interface.rb +72 -9
  34. data/cli/ruby-debug/processor.rb +203 -100
  35. data/doc/rdebug.1 +7 -2
  36. data/rdbg.rb +33 -0
  37. data/test/{test-ruby-debug-base.rb → base/base.rb} +27 -29
  38. data/test/base/binding.rb +31 -0
  39. data/test/base/catchpoint.rb +26 -0
  40. data/test/base/load.rb +40 -0
  41. data/test/data/annotate.cmd +29 -0
  42. data/test/data/annotate.right +137 -0
  43. data/test/data/break_bad.cmd +18 -0
  44. data/test/data/break_bad.right +28 -0
  45. data/test/data/breakpoints.cmd +38 -0
  46. data/test/data/breakpoints.right +98 -0
  47. data/test/data/condition.cmd +28 -0
  48. data/test/data/condition.right +65 -0
  49. data/test/data/ctrl.cmd +23 -0
  50. data/test/data/ctrl.right +69 -0
  51. data/test/{display.cmd → data/display.cmd} +7 -1
  52. data/test/{display.right → data/display.right} +13 -6
  53. data/test/data/dollar-0.right +2 -0
  54. data/test/data/dollar-0a.right +2 -0
  55. data/test/data/dollar-0b.right +2 -0
  56. data/test/data/edit.cmd +12 -0
  57. data/test/data/edit.right +19 -0
  58. data/test/{breakpoints.cmd → data/emacs_basic.cmd} +0 -0
  59. data/test/{breakpoints.right → data/emacs_basic.right} +24 -12
  60. data/test/data/enable.cmd +20 -0
  61. data/test/data/enable.right +36 -0
  62. data/test/data/finish.cmd +16 -0
  63. data/test/data/finish.right +43 -0
  64. data/test/{frame.cmd → data/frame.cmd} +2 -0
  65. data/test/{frame.right → data/frame.right} +8 -2
  66. data/test/{help.cmd → data/help.cmd} +8 -0
  67. data/test/data/help.right +21 -0
  68. data/test/data/history.right +7 -0
  69. data/test/data/info-thread.cmd +13 -0
  70. data/test/data/info-thread.right +37 -0
  71. data/test/data/info-var-bug2.cmd +5 -0
  72. data/test/data/info-var-bug2.right +10 -0
  73. data/test/{info-var.cmd → data/info-var.cmd} +3 -3
  74. data/test/{info-var.right → data/info-var.right} +20 -15
  75. data/test/{info.cmd → data/info.cmd} +10 -1
  76. data/test/data/info.right +65 -0
  77. data/test/data/linetrace.cmd +6 -0
  78. data/test/data/linetrace.right +32 -0
  79. data/test/data/linetracep.cmd +7 -0
  80. data/test/data/linetracep.right +25 -0
  81. data/test/data/list.cmd +19 -0
  82. data/test/data/list.right +127 -0
  83. data/test/data/noquit.right +1 -0
  84. data/test/data/output.cmd +6 -0
  85. data/test/data/output.right +41 -0
  86. data/test/data/post-mortem-next.cmd +8 -0
  87. data/test/data/post-mortem-next.right +14 -0
  88. data/test/data/post-mortem-osx.right +31 -0
  89. data/test/data/post-mortem.cmd +13 -0
  90. data/test/data/post-mortem.right +31 -0
  91. data/test/{quit.cmd → data/quit.cmd} +2 -5
  92. data/test/data/quit.right +9 -0
  93. data/test/data/raise.cmd +11 -0
  94. data/test/data/raise.right +26 -0
  95. data/test/{setshow.cmd → data/setshow.cmd} +0 -1
  96. data/test/{setshow.right → data/setshow.right} +0 -1
  97. data/test/data/source.cmd +5 -0
  98. data/test/data/source.right +15 -0
  99. data/test/{stepping.cmd → data/stepping.cmd} +6 -2
  100. data/test/{stepping.right → data/stepping.right} +13 -3
  101. data/test/data/test-init-cygwin.right +7 -0
  102. data/test/data/test-init-osx.right +4 -0
  103. data/test/data/test-init.right +5 -0
  104. data/test/data/trace.right +23 -0
  105. data/test/dollar-0.rb +5 -0
  106. data/test/except-bug2.rb +7 -0
  107. data/test/gcd-dbg-nox.rb +31 -0
  108. data/test/gcd-dbg.rb +30 -0
  109. data/test/helper.rb +44 -14
  110. data/test/info-var-bug.rb +2 -0
  111. data/test/info-var-bug2.rb +2 -0
  112. data/test/null.rb +1 -0
  113. data/test/output.rb +2 -0
  114. data/test/pm-base.rb +22 -0
  115. data/test/pm.rb +11 -0
  116. data/test/raise.rb +3 -0
  117. data/test/tdebug.rb +88 -40
  118. data/test/test-annotate.rb +25 -0
  119. data/test/test-break-bad.rb +25 -0
  120. data/test/test-breakpoints.rb +14 -17
  121. data/test/test-condition.rb +25 -0
  122. data/test/test-ctrl.rb +54 -0
  123. data/test/test-display.rb +15 -15
  124. data/test/test-dollar-0.rb +39 -0
  125. data/test/test-edit.rb +26 -0
  126. data/test/test-emacs-basic.rb +26 -0
  127. data/test/test-enable.rb +25 -0
  128. data/test/test-finish.rb +34 -0
  129. data/test/test-frame.rb +15 -16
  130. data/test/test-help.rb +34 -18
  131. data/test/test-hist.rb +68 -0
  132. data/test/test-info-thread.rb +32 -0
  133. data/test/test-info-var.rb +28 -14
  134. data/test/test-info.rb +15 -17
  135. data/test/test-init.rb +41 -0
  136. data/test/test-list.rb +25 -0
  137. data/test/test-output.rb +26 -0
  138. data/test/test-pm.rb +46 -0
  139. data/test/test-quit.rb +19 -17
  140. data/test/test-raise.rb +25 -0
  141. data/test/test-setshow.rb +14 -13
  142. data/test/test-source.rb +25 -0
  143. data/test/test-stepping.rb +14 -14
  144. data/test/test-trace.rb +63 -0
  145. data/test/thread1.rb +26 -0
  146. metadata +125 -31
  147. data/cli/ruby-debug/commands/script.rb +0 -64
  148. data/runner.sh +0 -7
  149. data/test/help.right +0 -4
  150. data/test/info.right +0 -35
  151. data/test/quit.right +0 -22
  152. data/test/test-columnize.rb +0 -46
@@ -1,31 +1,35 @@
1
- # Display a list of strings as a compact set of columns.
2
- #
3
- # Each column is only as wide as necessary.
4
- # Columns are separated by two spaces (one was not legible enough).
5
- # Adapted from the routine of the same name in cmd.py
6
-
7
1
  module Debugger
8
- class HelpCommand < Command # :nodoc:
9
- self.control = true
2
+
3
+ # Implements debugger "help" command.
4
+ class HelpCommand < Command
5
+ self.allow_in_control = true
10
6
 
11
7
  def regexp
12
- /^\s*h(?:elp)?(?:\s+(.+))?$/
8
+ /^\s* h(?:elp)? (?:\s+(.+))? $/x
13
9
  end
14
10
 
15
11
  def execute
16
- print "ruby-debug help v#{Debugger::VERSION}\n" unless
17
- self.class.settings[:debuggertesting]
18
- cmds = @state.commands.select{ |cmd| [cmd.help_command].flatten.include?(@match[1]) }
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
19
21
  unless cmds.empty?
20
- help = cmds.map{ |cmd| cmd.help(@match[1]) }.join
22
+ help = cmds.map{ |cmd| cmd.help(args) }.join
21
23
  help = help.split("\n").map{|l| l.gsub(/^ +/, '')}
22
24
  help.shift if help.first && help.first.empty?
23
25
  help.pop if help.last && help.last.empty?
24
26
  print help.join("\n")
25
27
  else
26
- if @match[1]
27
- print "Undefined command: \"#{@match[1]}\". Try \"help\"."
28
+ if args and args[0]
29
+ errmsg "Undefined command: \"#{args[0]}\". Try \"help\"."
28
30
  else
31
+ print "ruby-debug help v#{Debugger::VERSION}\n" unless
32
+ self.class.settings[:debuggertesting]
29
33
  print "Type 'help <command-name>' for help on a specific command\n\n"
30
34
  print "Available commands:\n"
31
35
  cmds = @state.commands.map{ |cmd| cmd.help_command }
@@ -1,51 +1,119 @@
1
1
  module Debugger
2
- class InfoCommand < Command # :nodoc:
3
- SubcmdStruct=Struct.new(:name, :min, :short_help) unless
4
- defined?(SubcmdStruct)
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.empty?
9
+ print "No exceptions set to be caught.\n"
10
+ else
11
+ # FIXME: show whether Exception is valid or not
12
+ # print "Exception: is_a?(Class)\n"
13
+ Debugger.catchpoints.each do |exception, hits|
14
+ # print "#{exception}: #{exception.is_a?(Class)}\n"
15
+ print "#{exception}\n"
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ # Implements debugger "info" command.
22
+ class InfoCommand < Command
23
+ self.allow_in_control = true
5
24
  Subcommands =
6
25
  [
7
- ['args', 1, "Argument variables of current stack frame"],
8
- ['breakpoints', 1, "Status of user-settable breakpoints"],
9
- ['display', 2, "Expressions to display when program stops"],
10
- ['file', 1, "File names and timestamps of files read in"],
11
- ['global_variables', 2, "global variables"],
12
- ['instance_variables', 2, "instance variables"],
13
- ['line', 2, "Line number and file name of current position in source"],
14
- ['locals', 2, "Local variables of the current stack frame"],
15
- ['program', 2, "Execution status of the program"],
16
- ['stack', 2, "Backtrace of the stack"],
17
- ['threads', 1, "IDs of currently known threads"],
18
- ['variables', 1, "local and instance variables"]
19
- ].map do |name, min, short_help|
20
- SubcmdStruct.new(name, min, short_help)
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)
21
63
  end unless defined?(Subcommands)
22
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
+
23
89
  def regexp
24
90
  /^\s* i(?:nfo)? (?:\s+(.*))?$/ix
25
91
  end
26
92
 
27
93
  def execute
28
- if not @match[1]
29
- print "\"info\" must be followed by the name of an info command:\n"
94
+ if @match[1].empty?
95
+ errmsg "\"info\" must be followed by the name of an info command:\n"
30
96
  print "List of info subcommands:\n\n"
31
97
  for subcmd in Subcommands do
32
98
  print "info #{subcmd.name} -- #{subcmd.short_help}\n"
33
99
  end
34
100
  else
35
- subcmd, args = @match[1].split(/[ \t]+/)
36
- subcmd.downcase!
37
- for try_subcmd in Subcommands do
38
- if (subcmd.size >= try_subcmd.min) and
39
- (try_subcmd.name[0..subcmd.size-1] == subcmd)
40
- send("info_#{try_subcmd.name}", args)
41
- return
42
- end
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"
43
108
  end
44
- print "Unknown info command #{subcmd}\n"
45
109
  end
46
110
  end
47
111
 
48
112
  def info_args(*args)
113
+ unless @state.context
114
+ print "No frame selected.\n"
115
+ return
116
+ end
49
117
  locals = @state.context.frame_locals(@state.frame_pos)
50
118
  args = @state.context.frame_args(@state.frame_pos)
51
119
  args.each do |name|
@@ -58,9 +126,22 @@ module Debugger
58
126
  end
59
127
 
60
128
  def info_breakpoints(*args)
129
+ unless @state.context
130
+ print "info breakpoints not available here.\n"
131
+ return
132
+ end
61
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
62
143
  print "Num Enb What\n"
63
- Debugger.breakpoints.sort_by{|b| b.id }.each do |b|
144
+ brkpts.each do |b|
64
145
  if b.expr.nil?
65
146
  print "%3d %s at %s:%s\n",
66
147
  b.id, (b.enabled? ? 'y' : 'n'), b.source, b.pos
@@ -68,6 +149,11 @@ module Debugger
68
149
  print "%3d %s at %s:%s if %s\n",
69
150
  b.id, (b.enabled? ? 'y' : 'n'), b.source, b.pos, b.expr
70
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
71
157
  end
72
158
  else
73
159
  print "No breakpoints.\n"
@@ -75,7 +161,11 @@ module Debugger
75
161
  end
76
162
 
77
163
  def info_display(*args)
78
- if @state.display.size > 0
164
+ unless @state.context
165
+ print "info display not available here.\n"
166
+ return
167
+ end
168
+ if @state.display.find{|d| d[0]}
79
169
  print "Auto-display expressions now in effect:\n"
80
170
  print "Num Enb Expression\n"
81
171
  n = 1
@@ -90,21 +180,96 @@ module Debugger
90
180
  end
91
181
 
92
182
  def info_file(*args)
93
- SCRIPT_LINES__.each do |file, value|
94
- print "File %s %s\n", file, SCRIPT_TIMESTAMPS__[file]
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
95
248
  end
96
249
  end
97
250
 
98
251
  def info_instance_variables(*args)
252
+ unless @state.context
253
+ print "info instance_variables not available here.\n"
254
+ return
255
+ end
99
256
  obj = debug_eval('self')
100
257
  var_list(obj.instance_variables)
101
258
  end
102
259
 
103
260
  def info_line(*args)
261
+ unless @state.context
262
+ errmsg "info line not available here.\n"
263
+ return
264
+ end
104
265
  print "Line %d of \"%s\"\n", @state.line, @state.file
105
266
  end
106
267
 
107
268
  def info_locals(*args)
269
+ unless @state.context
270
+ errmsg "info line not available here.\n"
271
+ return
272
+ end
108
273
  locals = @state.context.frame_locals(@state.frame_pos)
109
274
  locals.keys.sort.each do |name|
110
275
  ### FIXME: make a common routine
@@ -125,10 +290,17 @@ module Debugger
125
290
  end
126
291
 
127
292
  def info_program(*args)
128
- if @state.context.dead?
293
+ if not @state.context
129
294
  print "The program being debugged is not being run.\n"
130
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
131
302
  end
303
+
132
304
  print "Program stopped. "
133
305
  case @state.context.stop_reason
134
306
  when :step
@@ -145,6 +317,10 @@ module Debugger
145
317
  end
146
318
 
147
319
  def info_stack(*args)
320
+ if not @state.context
321
+ errmsg "info stack not available here.\n"
322
+ return
323
+ end
148
324
  (0...@state.context.stack_size).each do |idx|
149
325
  if idx == @state.frame_pos
150
326
  print "--> "
@@ -154,20 +330,74 @@ module Debugger
154
330
  print_frame(idx)
155
331
  end
156
332
  end
157
-
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
+
158
353
  def info_threads(*args)
354
+ ok, verbose = info_thread_preamble(args[0])
355
+ return unless ok
159
356
  threads = Debugger.contexts.sort_by{|c| c.thnum}.each do |c|
160
- display_context(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
161
382
  end
162
383
  end
163
384
 
164
385
  def info_global_variables(*args)
386
+ unless @state.context
387
+ errmsg "info global_variables not available here.\n"
388
+ return
389
+ end
165
390
  var_list(global_variables)
166
391
  end
167
392
 
168
393
  def info_variables(*args)
394
+ if not @state.context
395
+ errmsg "info variables not available here.\n"
396
+ return
397
+ end
169
398
  obj = debug_eval('self')
170
399
  locals = @state.context.frame_locals(@state.frame_pos)
400
+ locals['self'] = @state.context.frame_self(@state.frame_pos)
171
401
  locals.keys.sort.each do |name|
172
402
  next if name =~ /^__dbg_/ # skip debugger pollution
173
403
  ### FIXME: make a common routine
@@ -183,9 +413,11 @@ module Debugger
183
413
  if s.size > self.class.settings[:width]
184
414
  s[self.class.settings[:width]-3 .. -1] = "..."
185
415
  end
416
+ s.gsub!('%', '%%') # protect against printf format strings
186
417
  print "#{s}\n"
187
418
  end
188
419
  var_list(obj.instance_variables, obj.instance_eval{binding()})
420
+ var_class_self
189
421
  end
190
422
 
191
423
  class << self
@@ -193,7 +425,34 @@ module Debugger
193
425
  'info'
194
426
  end
195
427
 
196
- def help(cmd)
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
197
456
  s = %{
198
457
  Generic command for showing things about the program being debugged.
199
458
  --