byebug 1.0.3 → 1.1.0

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