byebug 0.0.1

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