ruby-debug 0.10.0 → 0.10.1

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