byebug 1.0.3 → 1.1.0

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 (52) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +5 -0
  3. data/README.md +13 -11
  4. data/Rakefile +0 -6
  5. data/bin/byebug +83 -136
  6. data/ext/byebug/byebug.c +182 -96
  7. data/ext/byebug/byebug.h +5 -7
  8. data/ext/byebug/context.c +52 -40
  9. data/lib/byebug.rb +81 -81
  10. data/lib/byebug/command.rb +18 -35
  11. data/lib/byebug/commands/control.rb +1 -1
  12. data/lib/byebug/commands/display.rb +0 -2
  13. data/lib/byebug/commands/enable.rb +4 -16
  14. data/lib/byebug/commands/eval.rb +5 -3
  15. data/lib/byebug/commands/frame.rb +68 -69
  16. data/lib/byebug/commands/help.rb +2 -1
  17. data/lib/byebug/commands/info.rb +43 -42
  18. data/lib/byebug/commands/method.rb +4 -3
  19. data/lib/byebug/commands/set.rb +10 -19
  20. data/lib/byebug/commands/show.rb +6 -13
  21. data/lib/byebug/interface.rb +1 -1
  22. data/lib/byebug/processor.rb +14 -17
  23. data/lib/byebug/version.rb +1 -2
  24. data/old_doc/byebug.texi +576 -847
  25. data/test/breakpoints_test.rb +0 -1
  26. data/test/conditions_test.rb +35 -33
  27. data/test/display_test.rb +14 -13
  28. data/test/edit_test.rb +28 -25
  29. data/test/eval_test.rb +0 -2
  30. data/test/finish_test.rb +4 -3
  31. data/test/frame_test.rb +20 -21
  32. data/test/help_test.rb +26 -23
  33. data/test/info_test.rb +105 -108
  34. data/test/irb_test.rb +26 -25
  35. data/test/kill_test.rb +19 -19
  36. data/test/list_test.rb +140 -156
  37. data/test/method_test.rb +21 -22
  38. data/test/post_mortem_test.rb +2 -5
  39. data/test/quit_test.rb +16 -17
  40. data/test/reload_test.rb +2 -2
  41. data/test/restart_test.rb +0 -1
  42. data/test/save_test.rb +31 -32
  43. data/test/set_test.rb +50 -47
  44. data/test/show_test.rb +67 -66
  45. data/test/source_test.rb +31 -34
  46. data/test/stepping_test.rb +32 -34
  47. data/test/support/test_dsl.rb +1 -1
  48. data/test/trace_test.rb +1 -2
  49. data/test/variables_test.rb +36 -34
  50. metadata +2 -4
  51. data/lib/byebug/commands/tmate.rb +0 -36
  52. data/test/tmate_test.rb +0 -44
@@ -24,8 +24,6 @@ typedef struct rb_trace_arg_struct rb_trace_point_t;
24
24
  #define CTX_FL_SET(c,f) do { (c)->flags |= (f); } while (0)
25
25
  #define CTX_FL_UNSET(c,f) do { (c)->flags &= ~(f); } while (0)
26
26
 
27
- #define IS_THREAD_ALIVE(t) (rb_funcall((t), idAlive, 0) == Qtrue)
28
-
29
27
  /* types */
30
28
  typedef enum {
31
29
  CTX_STOP_NONE,
@@ -64,21 +62,21 @@ typedef struct {
64
62
 
65
63
  /* functions */
66
64
  extern VALUE Init_context(VALUE mByebug);
67
- extern VALUE context_create(VALUE thread, VALUE cDebugThread);
65
+ extern VALUE Context_create(VALUE thread, VALUE cDebugThread);
66
+ extern VALUE Context_dup(debug_context_t *context);
68
67
  extern void reset_stepping_stop_points(debug_context_t *context);
69
68
  extern VALUE Context_ignored(VALUE self);
70
69
 
71
- extern void push_frame(VALUE context_object, char* file, int lineno,
70
+ extern void push_frame(debug_context_t *context, char* file, int lineno,
72
71
  VALUE method_id, VALUE defined_class, VALUE binding,
73
72
  VALUE self);
74
73
 
75
- extern void pop_frame(VALUE context_object);
74
+ extern void pop_frame(debug_context_t *context);
76
75
 
77
- extern void update_frame(VALUE context_object, char* file, int lineno,
76
+ extern void update_frame(debug_frame_t *context, char* file, int lineno,
78
77
  VALUE method_id, VALUE defined_class, VALUE binding,
79
78
  VALUE self);
80
79
 
81
-
82
80
  /* locked threads container */
83
81
  typedef struct locked_thread_t {
84
82
  VALUE thread;
@@ -3,8 +3,6 @@
3
3
  static VALUE cContext;
4
4
  static int thnum_current = 0;
5
5
 
6
- static VALUE idAlive;
7
-
8
6
  static VALUE
9
7
  id2ref(VALUE id)
10
8
  {
@@ -45,9 +43,9 @@ delete_frame(debug_context_t *context)
45
43
  xfree(frame);
46
44
  }
47
45
 
48
- static inline void
49
- fill_frame(debug_frame_t *frame, char* file, int lineno, VALUE method_id,
50
- VALUE defined_class, VALUE binding, VALUE self)
46
+ extern void
47
+ update_frame(debug_frame_t *frame, char* file, int lineno, VALUE method_id,
48
+ VALUE defined_class, VALUE binding, VALUE self)
51
49
  {
52
50
  frame->file = file;
53
51
  frame->line = lineno;
@@ -78,7 +76,7 @@ Context_dead(VALUE self)
78
76
  {
79
77
  debug_context_t *context;
80
78
  Data_Get_Struct(self, debug_context_t, context);
81
- return IS_THREAD_ALIVE(context->thread) ? Qfalse : Qtrue;
79
+ return CTX_FL_TEST(context, CTX_FL_DEAD) ? Qtrue : Qfalse;
82
80
  }
83
81
 
84
82
  extern VALUE
@@ -92,54 +90,32 @@ Context_ignored(VALUE self)
92
90
  }
93
91
 
94
92
  extern void
95
- push_frame(VALUE context_object, char* file, int lineno, VALUE method_id,
93
+ push_frame(debug_context_t *context, char* file, int lineno, VALUE method_id,
96
94
  VALUE defined_class, VALUE binding, VALUE self)
97
95
  {
98
- debug_context_t *context;
99
96
  debug_frame_t *frame;
100
- Data_Get_Struct(context_object, debug_context_t, context);
101
97
 
102
98
  frame = ALLOC(debug_frame_t);
103
- fill_frame(frame, file, lineno, method_id, defined_class, binding, self);
99
+ update_frame(frame, file, lineno, method_id, defined_class, binding, self);
104
100
  frame->prev = context->stack;
105
101
  context->stack = frame;
106
102
  context->stack_size++;
107
103
  }
108
104
 
109
105
  extern void
110
- pop_frame(VALUE context_object)
106
+ pop_frame(debug_context_t *context)
111
107
  {
112
- debug_context_t *context;
113
- Data_Get_Struct(context_object, debug_context_t, context);
114
-
115
108
  if (context->stack_size > 0) {
116
109
  delete_frame(context);
117
110
  }
118
111
  }
119
112
 
120
- extern void
121
- update_frame(VALUE context_object, char* file, int lineno, VALUE method_id,
122
- VALUE defined_class, VALUE binding, VALUE self)
123
- {
124
- debug_context_t *context;
125
- Data_Get_Struct(context_object, debug_context_t, context);
126
-
127
- if (context->stack_size == 0) {
128
- push_frame(context_object, file, lineno, method_id, defined_class, binding,
129
- self);
130
- return;
131
- }
132
- fill_frame(context->stack, file, lineno, method_id, defined_class, binding,
133
- self);
134
-
135
- }
136
-
137
113
  static void
138
114
  Context_mark(debug_context_t *context)
139
115
  {
140
116
  debug_frame_t *frame;
141
117
 
142
- rb_gc_mark(context->thread);
118
+ //rb_gc_mark(context->thread);
143
119
  frame = context->stack;
144
120
  while (frame != NULL) {
145
121
  rb_gc_mark(frame->self);
@@ -150,14 +126,14 @@ Context_mark(debug_context_t *context)
150
126
 
151
127
  static void
152
128
  Context_free(debug_context_t *context) {
153
- while(context->stack_size > 0) {
129
+ while (context->stack_size > 0) {
154
130
  delete_frame(context);
155
131
  }
156
132
  xfree(context);
157
133
  }
158
134
 
159
135
  extern VALUE
160
- context_create(VALUE thread, VALUE cDebugThread) {
136
+ Context_create(VALUE thread, VALUE cDebugThread) {
161
137
  debug_context_t *context;
162
138
 
163
139
  context = ALLOC(debug_context_t);
@@ -174,6 +150,45 @@ context_create(VALUE thread, VALUE cDebugThread) {
174
150
  return Data_Wrap_Struct(cContext, Context_mark, Context_free, context);
175
151
  }
176
152
 
153
+ static void
154
+ frame_copy(debug_frame_t *new_frame, debug_frame_t *old_frame)
155
+ {
156
+ new_frame->file = old_frame->file;
157
+ new_frame->line = old_frame->line;
158
+ new_frame->method_id = old_frame->method_id;
159
+ new_frame->defined_class = old_frame->defined_class;
160
+ new_frame->binding = old_frame->binding;
161
+ new_frame->self = old_frame->self;
162
+ }
163
+
164
+ extern VALUE
165
+ Context_dup(debug_context_t *context)
166
+ {
167
+ debug_context_t *new_context;
168
+ debug_frame_t *source_frame = context->stack, *dest_frame, *new_frame;
169
+
170
+ new_context = ALLOC(debug_context_t);
171
+ memcpy(new_context, context, sizeof(debug_context_t));
172
+ new_context->dest_frame = -1;
173
+ new_context->stop_line = -1;
174
+ new_context->stop_frame = -1;
175
+ new_context->stop_next = -1;
176
+ new_context->stack_size = context->stack_size;
177
+ CTX_FL_SET(new_context, CTX_FL_DEAD);
178
+ new_context->stack = ALLOC(debug_frame_t);
179
+ frame_copy(new_context->stack, context->stack);
180
+
181
+ new_frame = new_context->stack;
182
+ while ((source_frame = source_frame->prev))
183
+ {
184
+ dest_frame = new_frame;
185
+ new_frame = ALLOC(debug_frame_t);
186
+ frame_copy(new_frame, source_frame);
187
+ dest_frame->prev = new_frame;
188
+ }
189
+ return Data_Wrap_Struct(cContext, 0, Context_free, new_context);
190
+ }
191
+
177
192
  static debug_frame_t*
178
193
  get_frame_no(debug_context_t *context, int frame_n)
179
194
  {
@@ -329,7 +344,9 @@ Context_stop_reason(VALUE self)
329
344
 
330
345
  Data_Get_Struct(self, debug_context_t, context);
331
346
 
332
- switch(context->stop_reason)
347
+ if (CTX_FL_TEST(context, CTX_FL_DEAD))
348
+ symbol = "post-mortem";
349
+ else switch (context->stop_reason)
333
350
  {
334
351
  case CTX_STOP_STEP:
335
352
  symbol = "step";
@@ -344,9 +361,6 @@ Context_stop_reason(VALUE self)
344
361
  default:
345
362
  symbol = "none";
346
363
  }
347
- if(CTX_FL_TEST(context, CTX_FL_DEAD))
348
- symbol = "post-mortem";
349
-
350
364
  return ID2SYM(rb_intern(symbol));
351
365
  }
352
366
 
@@ -505,7 +519,5 @@ Init_context(VALUE mByebug)
505
519
  rb_define_method(cContext, "step_over", Context_step_over, -1);
506
520
  rb_define_method(cContext, "stop_frame=", Context_stop_frame, 1);
507
521
 
508
- idAlive = rb_intern("alive?");
509
-
510
522
  return cContext;
511
523
  }
@@ -14,9 +14,9 @@ module Byebug
14
14
 
15
15
  # Default options to Byebug.start
16
16
  DEFAULT_START_SETTINGS = {
17
- :init => true, # Set $0 and save ARGV?
18
- :post_mortem => false, # post-mortem debugging on uncaught exception?
19
- :tracing => nil # Byebug.tracing value. true/false resets
17
+ init: true, # Set $0 and save ARGV?
18
+ post_mortem: false, # post-mortem debugging on uncaught exception?
19
+ tracing: nil # Byebug.tracing? value. true/false resets
20
20
  } unless defined?(DEFAULT_START_SETTINGS)
21
21
 
22
22
  # Port number used for remote debugging
@@ -101,11 +101,11 @@ module Byebug
101
101
  # If it's called without a block it returns +true+, unless byebug was
102
102
  # already started.
103
103
  #
104
- # If a block is given, it starts byebug and yields block. When the block is
104
+ # If a block is given, it starts byebug and yields block. After the block is
105
105
  # executed it stops byebug with Byebug.stop method. Inside the block you
106
106
  # will probably want to have a call to Byebug.byebug. For example:
107
107
  #
108
- # Byebug.start{byebug; foo} # Stop inside of foo
108
+ # Byebug.start { byebug; foo } # Stop inside of foo
109
109
  #
110
110
  # Also, byebug only allows one invocation of byebug at a time; nested
111
111
  # Byebug.start's have no effect and you can't use this inside byebug itself.
@@ -131,14 +131,15 @@ module Byebug
131
131
  Byebug.const_set('INITIAL_DIR', Dir.pwd) unless defined? Byebug::INITIAL_DIR
132
132
  end
133
133
  Byebug.tracing = options[:tracing] unless options[:tracing].nil?
134
+ Byebug.start_sentinal=caller(0)[1]
134
135
  if Byebug.started?
135
136
  retval = block && block.call(self)
136
137
  else
137
138
  retval = Byebug._start(&block)
138
139
  end
139
- #if options[:post_mortem]
140
- # post_mortem
141
- #end
140
+ if options[:post_mortem]
141
+ post_mortem
142
+ end
142
143
  return retval
143
144
  end
144
145
 
@@ -254,62 +255,62 @@ module Byebug
254
255
  processor.process_commands(verbose)
255
256
  end
256
257
 
257
- # XXX: Implement
258
-
259
- # # Activates the post-mortem mode. There are two ways of using it:
260
- # #
261
- # # == Global post-mortem mode
262
- # # By calling Byebug.post_mortem method without a block, you install
263
- # # at_exit hook that intercepts any unhandled by your script exceptions
264
- # # and enables post-mortem mode.
265
- # #
266
- # # == Local post-mortem mode
267
- # #
268
- # # If you know that a particular block of code raises an exception you can
269
- # # enable post-mortem mode by wrapping this block with Byebug.post_mortem, e.g.
270
- # #
271
- # # def offender
272
- # # raise 'error'
273
- # # end
274
- # # Byebug.post_mortem do
275
- # # ...
276
- # # offender
277
- # # ...
278
- # # end
279
- # def post_mortem
280
- # if block_given?
281
- # old_post_mortem = self.post_mortem?
282
- # begin
283
- # self.post_mortem = true
284
- # yield
285
- # rescue Exception => exp
286
- # handle_post_mortem(exp)
287
- # raise
288
- # ensure
289
- # self.post_mortem = old_post_mortem
290
- # end
291
- # else
292
- # return if post_mortem?
293
- # self.post_mortem = true
294
- # debug_at_exit do
295
- # handle_post_mortem($!) if $! && post_mortem?
296
- # end
297
- # end
258
+ ##
259
+ # Activates the post-mortem mode. There are two ways of using it:
260
+ #
261
+ # == Global post-mortem mode
262
+ # By calling Byebug.post_mortem method without a block, you install an
263
+ # at_exit hook that intercepts any exception not handled by your script
264
+ # and enables post-mortem mode.
265
+ #
266
+ # == Local post-mortem mode
267
+ #
268
+ # If you know that a particular block of code raises an exception you can
269
+ # enable post-mortem mode by wrapping this block with Byebug.post_mortem,
270
+ # e.g.
271
+ #
272
+ # def offender
273
+ # raise 'error'
298
274
  # end
299
-
300
- # def handle_post_mortem(exp)
301
- # return if !exp || !exp.__debug_context ||
302
- # exp.__debug_context.stack_size == 0
303
- # Byebug.suspend
304
- # orig_tracing = Byebug.tracing, Byebug.current_context.tracing
305
- # Byebug.tracing = Byebug.current_context.tracing = false
306
- # Byebug.last_exception = exp
307
- # handler.at_line(exp.__debug_context, exp.__debug_file, exp.__debug_line)
308
- # ensure
309
- # Byebug.tracing, Byebug.current_context.tracing = orig_tracing
310
- # Byebug.resume
275
+ # Byebug.post_mortem do
276
+ # ...
277
+ # offender
278
+ # ...
311
279
  # end
312
- # # private :handle_post_mortem
280
+ def post_mortem
281
+ if block_given?
282
+ old_post_mortem = self.post_mortem?
283
+ begin
284
+ self.post_mortem = true
285
+ yield
286
+ rescue Exception => exp
287
+ handle_post_mortem(exp)
288
+ raise
289
+ ensure
290
+ self.post_mortem = old_post_mortem
291
+ end
292
+ else
293
+ return if self.post_mortem?
294
+ self.post_mortem = true
295
+ debug_at_exit do
296
+ handle_post_mortem($!) if $! && post_mortem?
297
+ end
298
+ end
299
+ end
300
+
301
+ def handle_post_mortem(exp)
302
+ return if !exp || !exp.__debug_context ||
303
+ exp.__debug_context.stack_size == 0
304
+ #Byebug.suspend
305
+ orig_tracing = Byebug.tracing?, Byebug.current_context.tracing
306
+ Byebug.tracing = Byebug.current_context.tracing = false
307
+ Byebug.last_exception = exp
308
+ handler.at_line(exp.__debug_context, exp.__debug_file, exp.__debug_line)
309
+ ensure
310
+ Byebug.tracing, Byebug.current_context.tracing = orig_tracing
311
+ #Byebug.resume
312
+ end
313
+ private :handle_post_mortem
313
314
 
314
315
  end
315
316
 
@@ -321,7 +322,7 @@ module Byebug
321
322
 
322
323
  end
323
324
 
324
- class Exception # :nodoc:
325
+ class Exception
325
326
  attr_reader :__debug_file, :__debug_line, :__debug_binding, :__debug_context
326
327
  end
327
328
 
@@ -343,24 +344,23 @@ class Module
343
344
  EOD
344
345
  end
345
346
 
346
- # XXX: Implement
347
- # #
348
- # # Wraps the +meth+ method with Byebug.post_mortem {...} block.
349
- # #
350
- # def post_mortem_method(meth)
351
- # old_meth = "__postmortem_#{meth}"
352
- # old_meth = "#{$1}_set" if old_meth =~ /^(.+)=$/
353
- # alias_method old_meth.to_sym, meth
354
- # class_eval <<-EOD
355
- # def #{meth}(*args, &block)
356
- # Byebug.start do |dbg|
357
- # dbg.post_mortem do
358
- # #{old_meth}(*args, &block)
359
- # end
360
- # end
361
- # end
362
- # EOD
363
- # end
347
+ #
348
+ # Wraps the +meth+ method with Byebug.post_mortem {...} block.
349
+ #
350
+ def post_mortem_method(meth)
351
+ old_meth = "__postmortem_#{meth}"
352
+ old_meth = "#{$1}_set" if old_meth =~ /^(.+)=$/
353
+ alias_method old_meth.to_sym, meth
354
+ class_eval <<-EOD
355
+ def #{meth}(*args, &block)
356
+ Byebug.start do |dbg|
357
+ dbg.post_mortem do
358
+ #{old_meth}(*args, &block)
359
+ end
360
+ end
361
+ end
362
+ EOD
363
+ end
364
364
  end
365
365
 
366
366
  module Kernel
@@ -20,24 +20,23 @@ module Byebug
20
20
  defined?(BYEBUG_DIR)
21
21
 
22
22
  class Command
23
-
24
23
  SubcmdStruct = Struct.new(:name, :min, :short_help, :long_help) unless
25
24
  defined?(SubcmdStruct)
26
25
 
27
26
  ##
28
27
  # Print list of subcmds
29
28
  #
30
- def print_subcmds(subcmds)
29
+ def format_subcmds(subcmds)
31
30
  cmd_name = self.class.name[/Byebug::(.*)Command/, 1].downcase
32
- errmsg "\"#{cmd_name}\" must be followed by the name of a subcommand.\n"
33
- print "List of \"#{cmd_name}\" subcommands:\n"
31
+ s = "\n" \
32
+ "--\n" \
33
+ "List of \"#{cmd_name}\" subcommands:\n" \
34
+ "--\n"
34
35
  for subcmd in subcmds do
35
- print "#{cmd_name} #{subcmd.name} -- #{subcmd.short_help}\n"
36
+ s += "#{cmd_name} #{subcmd.name} -- #{subcmd.short_help}\n"
36
37
  end
37
38
  end
38
39
 
39
- include Columnize
40
-
41
40
  ##
42
41
  # Find param in subcmds.
43
42
  #
@@ -60,14 +59,12 @@ module Byebug
60
59
  @commands ||= []
61
60
  end
62
61
 
63
- DEF_OPTIONS = {
64
- :allow_in_control => false,
65
- :allow_in_post_mortem => false,
66
- :event => true ,
67
- :always_run => 0 ,
68
- :unknown => false,
69
- :need_context => false,
70
- } unless defined?(DEF_OPTIONS)
62
+ DEF_OPTIONS = { allow_in_control: false,
63
+ allow_in_post_mortem: true ,
64
+ event: true ,
65
+ always_run: 0 ,
66
+ unknown: false,
67
+ need_context: false } unless defined?(DEF_OPTIONS)
71
68
 
72
69
  def inherited(klass)
73
70
  DEF_OPTIONS.each do |o, v|
@@ -109,28 +106,14 @@ module Byebug
109
106
  @settings = Object.new
110
107
  map = settings_map
111
108
  c = class << @settings; self end
112
- if c.respond_to?(:funcall)
113
- c.funcall(:define_method, :[]) do |name|
114
- raise "No such setting #{name}" unless map.has_key?(name)
115
- map[name][:getter].call
116
- end
117
- else
118
- c.send(:define_method, :[]) do |name|
119
- raise "No such setting #{name}" unless map.has_key?(name)
120
- map[name][:getter].call
121
- end
109
+ c.send(:define_method, :[]) do |name|
110
+ raise "No such setting #{name}" unless map.has_key?(name)
111
+ map[name][:getter].call
122
112
  end
123
113
  c = class << @settings; self end
124
- if c.respond_to?(:funcall)
125
- c.funcall(:define_method, :[]=) do |name, value|
126
- raise "No such setting #{name}" unless map.has_key?(name)
127
- map[name][:setter].call(value)
128
- end
129
- else
130
- c.send(:define_method, :[]=) do |name, value|
131
- raise "No such setting #{name}" unless map.has_key?(name)
132
- map[name][:setter].call(value)
133
- end
114
+ c.send(:define_method, :[]=) do |name, value|
115
+ raise "No such setting #{name}" unless map.has_key?(name)
116
+ map[name][:setter].call(value)
134
117
  end
135
118
  end
136
119
  @settings