byebug 0.0.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 (133) hide show
  1. data/.gitignore +10 -0
  2. data/.travis.yml +8 -0
  3. data/AUTHORS +10 -0
  4. data/CHANGELOG.md +2 -0
  5. data/CONTRIBUTING.md +1 -0
  6. data/Gemfile +3 -0
  7. data/LICENSE +20 -0
  8. data/README.md +5 -0
  9. data/Rakefile +28 -0
  10. data/bin/byebug +395 -0
  11. data/byebug.gemspec +29 -0
  12. data/doc/hanoi.rb +35 -0
  13. data/doc/primes.rb +28 -0
  14. data/doc/rdebug-emacs.texi +1030 -0
  15. data/doc/test-tri2.rb +18 -0
  16. data/doc/tri3.rb +8 -0
  17. data/doc/triangle.rb +12 -0
  18. data/ext/byebug/breakpoint.c +476 -0
  19. data/ext/byebug/byebug.c +512 -0
  20. data/ext/byebug/byebug.h +131 -0
  21. data/ext/byebug/context.c +424 -0
  22. data/ext/byebug/extconf.rb +21 -0
  23. data/ext/byebug/locker.c +53 -0
  24. data/lib/byebug.rb +404 -0
  25. data/lib/byebug/command.rb +232 -0
  26. data/lib/byebug/commands/breakpoints.rb +153 -0
  27. data/lib/byebug/commands/catchpoint.rb +56 -0
  28. data/lib/byebug/commands/condition.rb +49 -0
  29. data/lib/byebug/commands/continue.rb +38 -0
  30. data/lib/byebug/commands/control.rb +110 -0
  31. data/lib/byebug/commands/display.rb +122 -0
  32. data/lib/byebug/commands/edit.rb +48 -0
  33. data/lib/byebug/commands/enable.rb +202 -0
  34. data/lib/byebug/commands/eval.rb +176 -0
  35. data/lib/byebug/commands/finish.rb +43 -0
  36. data/lib/byebug/commands/frame.rb +303 -0
  37. data/lib/byebug/commands/help.rb +56 -0
  38. data/lib/byebug/commands/info.rb +462 -0
  39. data/lib/byebug/commands/irb.rb +123 -0
  40. data/lib/byebug/commands/jump.rb +66 -0
  41. data/lib/byebug/commands/kill.rb +51 -0
  42. data/lib/byebug/commands/list.rb +94 -0
  43. data/lib/byebug/commands/method.rb +84 -0
  44. data/lib/byebug/commands/quit.rb +39 -0
  45. data/lib/byebug/commands/reload.rb +40 -0
  46. data/lib/byebug/commands/save.rb +90 -0
  47. data/lib/byebug/commands/set.rb +210 -0
  48. data/lib/byebug/commands/show.rb +246 -0
  49. data/lib/byebug/commands/skip.rb +35 -0
  50. data/lib/byebug/commands/source.rb +36 -0
  51. data/lib/byebug/commands/stepping.rb +83 -0
  52. data/lib/byebug/commands/threads.rb +189 -0
  53. data/lib/byebug/commands/tmate.rb +36 -0
  54. data/lib/byebug/commands/trace.rb +56 -0
  55. data/lib/byebug/commands/variables.rb +199 -0
  56. data/lib/byebug/context.rb +58 -0
  57. data/lib/byebug/helper.rb +69 -0
  58. data/lib/byebug/interface.rb +223 -0
  59. data/lib/byebug/processor.rb +468 -0
  60. data/lib/byebug/version.rb +3 -0
  61. data/man/rdebug.1 +241 -0
  62. data/test/breakpoints_test.rb +357 -0
  63. data/test/conditions_test.rb +77 -0
  64. data/test/continue_test.rb +44 -0
  65. data/test/display_test.rb +141 -0
  66. data/test/edit_test.rb +56 -0
  67. data/test/eval_test.rb +92 -0
  68. data/test/examples/breakpoint1.rb +15 -0
  69. data/test/examples/breakpoint2.rb +7 -0
  70. data/test/examples/conditions.rb +4 -0
  71. data/test/examples/continue.rb +4 -0
  72. data/test/examples/display.rb +5 -0
  73. data/test/examples/edit.rb +3 -0
  74. data/test/examples/edit2.rb +3 -0
  75. data/test/examples/eval.rb +4 -0
  76. data/test/examples/finish.rb +20 -0
  77. data/test/examples/frame.rb +20 -0
  78. data/test/examples/frame_threads.rb +31 -0
  79. data/test/examples/help.rb +2 -0
  80. data/test/examples/info.rb +38 -0
  81. data/test/examples/info2.rb +3 -0
  82. data/test/examples/info_threads.rb +48 -0
  83. data/test/examples/irb.rb +6 -0
  84. data/test/examples/jump.rb +14 -0
  85. data/test/examples/kill.rb +2 -0
  86. data/test/examples/list.rb +12 -0
  87. data/test/examples/method.rb +15 -0
  88. data/test/examples/post_mortem.rb +19 -0
  89. data/test/examples/quit.rb +2 -0
  90. data/test/examples/reload.rb +6 -0
  91. data/test/examples/restart.rb +6 -0
  92. data/test/examples/save.rb +3 -0
  93. data/test/examples/set.rb +3 -0
  94. data/test/examples/set_annotate.rb +12 -0
  95. data/test/examples/settings.rb +1 -0
  96. data/test/examples/show.rb +2 -0
  97. data/test/examples/source.rb +3 -0
  98. data/test/examples/stepping.rb +21 -0
  99. data/test/examples/thread.rb +32 -0
  100. data/test/examples/tmate.rb +10 -0
  101. data/test/examples/trace.rb +7 -0
  102. data/test/examples/trace_threads.rb +20 -0
  103. data/test/examples/variables.rb +26 -0
  104. data/test/finish_test.rb +48 -0
  105. data/test/frame_test.rb +143 -0
  106. data/test/help_test.rb +50 -0
  107. data/test/info_test.rb +313 -0
  108. data/test/irb_test.rb +81 -0
  109. data/test/jump_test.rb +70 -0
  110. data/test/kill_test.rb +48 -0
  111. data/test/list_test.rb +145 -0
  112. data/test/method_test.rb +70 -0
  113. data/test/post_mortem_test.rb +27 -0
  114. data/test/quit_test.rb +56 -0
  115. data/test/reload_test.rb +44 -0
  116. data/test/restart_test.rb +164 -0
  117. data/test/save_test.rb +92 -0
  118. data/test/set_test.rb +177 -0
  119. data/test/show_test.rb +293 -0
  120. data/test/source_test.rb +45 -0
  121. data/test/stepping_test.rb +130 -0
  122. data/test/support/breakpoint.rb +13 -0
  123. data/test/support/context.rb +14 -0
  124. data/test/support/matchers.rb +67 -0
  125. data/test/support/mocha_extensions.rb +72 -0
  126. data/test/support/processor.rb +7 -0
  127. data/test/support/test_dsl.rb +206 -0
  128. data/test/support/test_interface.rb +68 -0
  129. data/test/test_helper.rb +10 -0
  130. data/test/tmate_test.rb +44 -0
  131. data/test/trace_test.rb +159 -0
  132. data/test/variables_test.rb +119 -0
  133. metadata +265 -0
@@ -0,0 +1,176 @@
1
+ module Byebug
2
+ module EvalFunctions # :nodoc:
3
+ def run_with_binding
4
+ binding = @state.context ? get_binding : TOPLEVEL_BINDING
5
+ $__dbg_interface = @state.interface
6
+ eval(<<-EOC, binding)
7
+ __dbg_verbose_save=$VERBOSE; $VERBOSE=false
8
+ def dbg_print(*args)
9
+ $__dbg_interface.print(*args)
10
+ end
11
+ remove_method :puts if self.respond_to?(:puts) &&
12
+ defined?(remove_method)
13
+ def dbg_puts(*args)
14
+ $__dbg_interface.print(*args)
15
+ $__dbg_interface.print("\n")
16
+ end
17
+ $VERBOSE=__dbg_verbose_save
18
+ EOC
19
+ yield binding
20
+ ensure
21
+ $__dbg_interface = nil
22
+ end
23
+ end
24
+
25
+ class EvalCommand < Command # :nodoc:
26
+ self.allow_in_control = true
27
+
28
+ register_setting_get(:autoeval) do
29
+ EvalCommand.unknown
30
+ end
31
+ register_setting_set(:autoeval) do |value|
32
+ EvalCommand.unknown = value
33
+ end
34
+
35
+ def match(input)
36
+ @input = input
37
+ super
38
+ end
39
+
40
+ def regexp
41
+ /^\s*(p|e(?:val)?)\s+/
42
+ end
43
+
44
+ def execute
45
+ expr = @match ? @match.post_match : @input
46
+ run_with_binding do |b|
47
+ print "%s\n", debug_eval(expr, b).inspect
48
+ end
49
+ end
50
+
51
+ class << self
52
+ def help_command
53
+ %w|p eval|
54
+ end
55
+
56
+ def help(cmd)
57
+ if cmd == 'p'
58
+ %{
59
+ p expression\tevaluate expression and print its value
60
+ }
61
+ else
62
+ %{
63
+ e[val] expression\tevaluate expression and print its value,
64
+ \t\t\talias for p.
65
+ * NOTE - to turn on autoeval, use 'set autoeval'
66
+ }
67
+ end
68
+ end
69
+ end
70
+ end
71
+
72
+ class PPCommand < Command # :nodoc:
73
+ self.allow_in_control = true
74
+
75
+ def regexp
76
+ /^\s*pp\s+/
77
+ end
78
+
79
+ def execute
80
+ out = StringIO.new
81
+ run_with_binding do |b|
82
+ PP.pp(debug_eval(@match.post_match, b), out)
83
+ end
84
+ print out.string
85
+ rescue
86
+ out.puts $!.message
87
+ end
88
+
89
+ class << self
90
+ def help_command
91
+ 'pp'
92
+ end
93
+
94
+ def help(cmd)
95
+ %{
96
+ pp expression\tevaluate expression and pretty-print its value
97
+ }
98
+ end
99
+ end
100
+ end
101
+
102
+ class PutLCommand < Command # :nodoc:
103
+ self.allow_in_control = true
104
+
105
+ def regexp
106
+ /^\s*putl\s+/
107
+ end
108
+
109
+ def execute
110
+ out = StringIO.new
111
+ run_with_binding do |b|
112
+ vals = debug_eval(@match.post_match, b)
113
+ if vals.is_a?(Array)
114
+ vals = vals.map{|item| item.to_s}
115
+ print "%s\n", columnize(vals, self.class.settings[:width])
116
+ else
117
+ PP.pp(vals, out)
118
+ print out.string
119
+ end
120
+ end
121
+ rescue
122
+ out.puts $!.message
123
+ end
124
+
125
+ class << self
126
+ def help_command
127
+ 'putl'
128
+ end
129
+
130
+ def help(cmd)
131
+ %{
132
+ putl expression\t\tevaluate expression, an array, and columnize its value
133
+ }
134
+ end
135
+ end
136
+ end
137
+
138
+ class PSCommand < Command # :nodoc:
139
+ self.allow_in_control = true
140
+
141
+ include EvalFunctions
142
+
143
+ def regexp
144
+ /^\s*ps\s+/
145
+ end
146
+
147
+ def execute
148
+ out = StringIO.new
149
+ run_with_binding do |b|
150
+ vals = debug_eval(@match.post_match, b)
151
+ if vals.is_a?(Array)
152
+ vals = vals.map{|item| item.to_s}
153
+ print "%s\n", columnize(vals.sort!, self.class.settings[:width])
154
+ else
155
+ PP.pp(vals, out)
156
+ print out.string
157
+ end
158
+ end
159
+ rescue
160
+ out.puts $!.message
161
+ end
162
+
163
+ class << self
164
+ def help_command
165
+ 'ps'
166
+ end
167
+
168
+ def help(cmd)
169
+ %{
170
+ ps expression\tevaluate expression, an array, sort, and columnize its value
171
+ }
172
+ end
173
+ end
174
+ end
175
+
176
+ end
@@ -0,0 +1,43 @@
1
+ module Byebug
2
+
3
+ # Implements the byebug 'finish' command.
4
+ class FinishCommand < Command
5
+ self.allow_in_post_mortem = false
6
+ self.need_context = true
7
+
8
+ def regexp
9
+ /^\s*fin(?:ish)? (?:\s+(.*))?$/x
10
+ end
11
+
12
+ def execute
13
+ max_frame = @state.context.stack_size - @state.frame_pos
14
+ if !@match[1] or @match[1].empty?
15
+ frame_pos = @state.frame_pos
16
+ else
17
+ frame_pos = get_int(@match[1], "Finish", 0, max_frame-1, 0)
18
+ return nil unless frame_pos
19
+ end
20
+ @state.context.stop_frame = frame_pos
21
+ @state.frame_pos = 0
22
+ @state.proceed
23
+ end
24
+
25
+ class << self
26
+ def help_command
27
+ 'finish'
28
+ end
29
+
30
+ def help(cmd)
31
+ %{
32
+ fin[ish] [frame-number]\tExecute until selected stack frame returns.
33
+
34
+ If no frame number is given, we run until the currently selected frame
35
+ returns. The currently selected frame starts out the most-recent
36
+ frame or 0 if no frame positioning (e.g "up", "down" or "frame") has
37
+ been performed. If a frame number is given we run until that frame
38
+ returns.
39
+ }
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,303 @@
1
+ module Byebug
2
+
3
+ # Mix-in module to assist in command parsing.
4
+ module FrameFunctions # :nodoc:
5
+
6
+ def adjust_frame(frame_pos, absolute, context=@state.context)
7
+ @state.frame_pos = 0 if context != @state.context
8
+ if absolute
9
+ if frame_pos < 0
10
+ abs_frame_pos = context.stack_size + frame_pos
11
+ else
12
+ abs_frame_pos = frame_pos
13
+ end
14
+ else
15
+ abs_frame_pos = @state.frame_pos + frame_pos
16
+ end
17
+
18
+ if abs_frame_pos >= context.stack_size then
19
+ errmsg "Adjusting would put us beyond the oldest (initial) frame.\n"
20
+ return
21
+ elsif abs_frame_pos < 0 then
22
+ errmsg "Adjusting would put us beyond the newest (innermost) frame.\n"
23
+ return
24
+ end
25
+ if @state.frame_pos != abs_frame_pos then
26
+ @state.previous_line = nil
27
+ @state.frame_pos = abs_frame_pos
28
+ end
29
+
30
+ @state.file = context.frame_file(@state.frame_pos)
31
+ @state.line = context.frame_line(@state.frame_pos)
32
+
33
+ print_frame(@state.frame_pos, true)
34
+ end
35
+
36
+ # XXX: Implement args and locals for this to be used...
37
+ def get_frame_call(prefix, pos, context)
38
+ id = context.frame_method(pos)
39
+ klass = context.frame_class(pos)
40
+ call_str = ""
41
+ if id
42
+ args = context.frame_args(pos)
43
+ locals = context.frame_locals(pos)
44
+ if Command.settings[:callstyle] != :short && klass
45
+ if Command.settings[:callstyle] == :tracked
46
+ arg_info = context.frame_args_info(pos)
47
+ end
48
+ call_str << "#{klass}."
49
+ end
50
+ call_str << id.id2name
51
+ if args.any?
52
+ call_str << "("
53
+ args.each_with_index do |name, i|
54
+ case Command.settings[:callstyle]
55
+ when :short
56
+ call_str += "%s, " % [name]
57
+ when :last
58
+ klass = locals[name].class
59
+ if klass.inspect.size > 20+3
60
+ klass = klass.inspect[0..20]+"..."
61
+ end
62
+ call_str += "%s#%s, " % [name, klass]
63
+ when :tracked
64
+ if arg_info && arg_info.size > i
65
+ call_str += "#{name}: #{arg_info[i].inspect}, "
66
+ else
67
+ call_str += "%s, " % name
68
+ end
69
+ end
70
+ if call_str.size > self.class.settings[:width] - prefix.size
71
+ # Strip off trailing ', ' if any but add stuff for later trunc
72
+ call_str[-2..-1] = ",...XX"
73
+ break
74
+ end
75
+ end
76
+ call_str[-2..-1] = ")" # Strip off trailing ', ' if any
77
+ end
78
+ end
79
+ return call_str
80
+ end
81
+
82
+ def print_frame(pos, adjust = false, context=@state.context)
83
+ file = context.frame_file(pos)
84
+ line = context.frame_line(pos)
85
+ klass = context.frame_class(pos)
86
+
87
+ unless Command.settings[:full_path]
88
+ path_components = file.split(/[\\\/]/)
89
+ if path_components.size > 3
90
+ path_components[0...-3] = '...'
91
+ file = path_components.join(File::ALT_SEPARATOR || File::SEPARATOR)
92
+ end
93
+ end
94
+
95
+ frame_num = "#%d " % pos
96
+ #call_str = get_frame_call(frame_num, pos, context)
97
+ file_line = "at line %s:%d\n" % [CommandProcessor.canonic_file(file), line]
98
+ print frame_num
99
+ #unless call_str.empty?
100
+ # print call_str
101
+ # print ' '
102
+ # if call_str.size + frame_num.size + file_line.size > self.class.settings[:width]
103
+ # print "\n "
104
+ # end
105
+ #end
106
+ print file_line
107
+ if ENV['EMACS'] && adjust
108
+ fmt = (Byebug.annotate.to_i > 1 ?
109
+ "\032\032source %s:%d\n" : "\032\032%s:%d\n")
110
+ print fmt % [CommandProcessor.canonic_file(file), line]
111
+ end
112
+ end
113
+
114
+ # Check if call stack is truncated. This can happen if
115
+ # Byebug.start is not called low enough in the call stack. An
116
+ # array of additional callstack lines from caller is returned if
117
+ # definitely truncated, false if not, and nil if we don't know.
118
+ #
119
+ # We determine truncation based on a passed in sentinal set via
120
+ # caller which can be nil.
121
+ #
122
+ # First we see if we can find our position in caller. If so, then
123
+ # we compare context position to that in caller using sentinal
124
+ # as a place to start ignoring additional caller entries. sentinal
125
+ # is set by rdebug, but if it's not set, i.e. nil then additional
126
+ # entries are presumably ones that we haven't recorded in context
127
+ def truncated_callstack?(context, sentinal=nil, cs=caller)
128
+ recorded_size = context.stack_size
129
+ to_find_fl = "#{context.frame_file(0)}:#{context.frame_line(0)}"
130
+ top_discard = false
131
+ cs.each_with_index do |fl, i|
132
+ fl.gsub!(/in `.*'$/, '')
133
+ fl.gsub!(/:$/, '')
134
+ if fl == to_find_fl
135
+ top_discard = i
136
+ break
137
+ end
138
+ end
139
+ if top_discard
140
+ cs = cs[top_discard..-1]
141
+ return false unless cs
142
+ return cs unless sentinal
143
+ if cs.size > recorded_size+2 && cs[recorded_size+2] != sentinal
144
+ # caller seems to truncate recursive calls and we don't.
145
+ # See if we can find sentinal in the first 0..recorded_size+1 entries
146
+ return false if cs[0..recorded_size+1].any?{ |f| f==sentinal }
147
+ return cs
148
+ end
149
+ return false
150
+ end
151
+ return nil
152
+ end
153
+
154
+ end
155
+
156
+ # Implements byebug "where" or "backtrace" command.
157
+ class WhereCommand < Command
158
+ def regexp
159
+ /^\s*(?:w(?:here)?|bt|backtrace)$/
160
+ end
161
+
162
+ def execute
163
+ (0...@state.context.stack_size).each do |idx|
164
+ if idx == @state.frame_pos
165
+ print "--> "
166
+ else
167
+ print " "
168
+ end
169
+ print_frame(idx)
170
+
171
+ end
172
+ if truncated_callstack?(@state.context, Byebug.start_sentinal)
173
+ # print "Warning: saved frames may be incomplete; compare with caller(0).\n"
174
+ end
175
+ end
176
+
177
+ class << self
178
+ def help_command
179
+ %w|where backtrace|
180
+ end
181
+
182
+ def help(cmd)
183
+ s = if cmd == 'where'
184
+ %{
185
+ w[here]\tdisplay stack frames
186
+ }
187
+ else
188
+ %{
189
+ bt|backtrace\t\talias for where - display stack frames
190
+ }
191
+ end
192
+ s += %{
193
+ Print the entire stack frame. Each frame is numbered, the most recent
194
+ frame is 0. frame number can be referred to in the "frame" command;
195
+ "up" and "down" add or subtract respectively to frame numbers shown.
196
+ The position of the current frame is marked with -->. }
197
+ end
198
+ end
199
+ end
200
+
201
+ class UpCommand < Command # :nodoc:
202
+ def regexp
203
+ /^\s* u(?:p)? (?:\s+(.*))?$/x
204
+ end
205
+
206
+ def execute
207
+ pos = get_int(@match[1], "Up")
208
+ return unless pos
209
+ adjust_frame(pos, false)
210
+ end
211
+
212
+ class << self
213
+ def help_command
214
+ 'up'
215
+ end
216
+
217
+ def help(cmd)
218
+ %{
219
+ up[count]\tmove to higher frame
220
+ }
221
+ end
222
+ end
223
+ end
224
+
225
+ class DownCommand < Command # :nodoc:
226
+ def regexp
227
+ /^\s* down (?:\s+(.*))? .*$/x
228
+ end
229
+
230
+ def execute
231
+ pos = get_int(@match[1], "Down")
232
+ return unless pos
233
+ adjust_frame(-pos, false)
234
+ end
235
+
236
+ class << self
237
+ def help_command
238
+ 'down'
239
+ end
240
+
241
+ def help(cmd)
242
+ %{
243
+ down[count]\tmove to lower frame
244
+ }
245
+ end
246
+ end
247
+ end
248
+
249
+ class FrameCommand < Command # :nodoc:
250
+ def regexp
251
+ / ^\s*
252
+ f(?:rame)?
253
+ (?: \s+ (\S+))? \s*
254
+ (?: thread \s+ (.*))? \s*
255
+ $/x
256
+ end
257
+
258
+ def execute
259
+ if not @match[1]
260
+ pos = 0
261
+ else
262
+ pos = get_int(@match[1], "Frame")
263
+ return unless pos
264
+ end
265
+ #if @match[2]
266
+ # context = parse_thread_num('frame', @match[2])
267
+ # unless context
268
+ # errmsg "Thread #{@match[2]} doesn't exist.\n"
269
+ # return
270
+ # end
271
+ #else
272
+ context = @state.context
273
+ #end
274
+ adjust_frame(pos, true, context)
275
+ end
276
+
277
+ class << self
278
+ def help_command
279
+ 'frame'
280
+ end
281
+
282
+ def help(cmd)
283
+ %{
284
+ f[rame] [frame-number [thread thread-number]]
285
+ Move the current frame to the specified frame number, or the
286
+ 0 if no frame-number has been given.
287
+
288
+ A negative number indicates position from the other end. So
289
+ 'frame -1' moves to the oldest frame, and 'frame 0' moves to
290
+ the newest frame.
291
+
292
+ Without an argument, the command prints the current stack
293
+ frame. Since the current position is redisplayed, it may trigger a
294
+ resyncronization if there is a front end also watching over
295
+ things.
296
+
297
+ If a thread number is given then we set the context for evaluating
298
+ expressions to that frame of that thread.
299
+ }
300
+ end
301
+ end
302
+ end
303
+ end