byebug 1.8.2 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +8 -1
  3. data/GUIDE.md +14 -22
  4. data/README.md +69 -6
  5. data/bin/byebug +3 -20
  6. data/ext/byebug/breakpoint.c +185 -101
  7. data/ext/byebug/byebug.c +393 -214
  8. data/ext/byebug/byebug.h +34 -15
  9. data/ext/byebug/context.c +327 -102
  10. data/ext/byebug/extconf.rb +1 -1
  11. data/ext/byebug/locker.c +54 -0
  12. data/ext/byebug/threads.c +113 -0
  13. data/lib/byebug.rb +19 -58
  14. data/lib/byebug/command.rb +18 -19
  15. data/lib/byebug/commands/breakpoints.rb +1 -4
  16. data/lib/byebug/commands/catchpoint.rb +1 -1
  17. data/lib/byebug/commands/condition.rb +1 -1
  18. data/lib/byebug/commands/control.rb +2 -3
  19. data/lib/byebug/commands/display.rb +2 -7
  20. data/lib/byebug/commands/edit.rb +1 -1
  21. data/lib/byebug/commands/enable.rb +12 -12
  22. data/lib/byebug/commands/eval.rb +4 -4
  23. data/lib/byebug/commands/finish.rb +1 -1
  24. data/lib/byebug/commands/frame.rb +12 -8
  25. data/lib/byebug/commands/info.rb +20 -52
  26. data/lib/byebug/commands/kill.rb +1 -5
  27. data/lib/byebug/commands/list.rb +2 -1
  28. data/lib/byebug/commands/quit.rb +1 -1
  29. data/lib/byebug/commands/repl.rb +2 -2
  30. data/lib/byebug/commands/save.rb +1 -1
  31. data/lib/byebug/commands/set.rb +84 -90
  32. data/lib/byebug/commands/show.rb +44 -53
  33. data/lib/byebug/commands/skip.rb +1 -1
  34. data/lib/byebug/commands/stepping.rb +5 -4
  35. data/lib/byebug/commands/threads.rb +202 -0
  36. data/lib/byebug/commands/trace.rb +1 -1
  37. data/lib/byebug/helper.rb +3 -3
  38. data/lib/byebug/interface.rb +2 -20
  39. data/lib/byebug/processor.rb +21 -100
  40. data/lib/byebug/remote.rb +3 -3
  41. data/lib/byebug/version.rb +1 -1
  42. data/old_doc/byebug.1 +0 -6
  43. data/old_doc/byebug.texi +29 -46
  44. data/test/breakpoints_test.rb +44 -65
  45. data/test/conditions_test.rb +0 -9
  46. data/test/continue_test.rb +2 -2
  47. data/test/display_test.rb +4 -23
  48. data/test/edit_test.rb +2 -16
  49. data/test/eval_test.rb +4 -13
  50. data/test/examples/thread.rb +32 -0
  51. data/test/finish_test.rb +1 -13
  52. data/test/frame_test.rb +5 -12
  53. data/test/help_test.rb +2 -12
  54. data/test/info_test.rb +8 -18
  55. data/test/kill_test.rb +1 -10
  56. data/test/list_test.rb +5 -14
  57. data/test/method_test.rb +1 -10
  58. data/test/post_mortem_test.rb +247 -14
  59. data/test/quit_test.rb +0 -9
  60. data/test/reload_test.rb +1 -15
  61. data/test/repl_test.rb +1 -9
  62. data/test/restart_test.rb +3 -18
  63. data/test/save_test.rb +1 -13
  64. data/test/set_test.rb +35 -32
  65. data/test/show_test.rb +8 -27
  66. data/test/source_test.rb +1 -8
  67. data/test/stepping_test.rb +65 -96
  68. data/test/support/test_dsl.rb +12 -17
  69. data/test/test_helper.rb +1 -1
  70. data/test/thread_test.rb +106 -0
  71. data/test/trace_test.rb +5 -17
  72. data/test/variables_test.rb +1 -10
  73. metadata +9 -7
  74. data/lib/byebug/commands/jump.rb +0 -52
  75. data/test/jump_test.rb +0 -77
  76. data/test/support/context.rb +0 -15
@@ -9,7 +9,7 @@ end
9
9
 
10
10
  if RbConfig::MAKEFILE_CONFIG['CC'] =~ /gcc/
11
11
  $CFLAGS = '-Wall -Werror'
12
- $CFLAGS += ' -g3' if ENV['debug']
12
+ $CFLAGS += ' -gdwarf-2 -g3' if ENV['debug']
13
13
  end
14
14
 
15
15
  dir_config("ruby")
@@ -0,0 +1,54 @@
1
+ #include <byebug.h>
2
+
3
+ typedef struct locked_thread_t {
4
+ VALUE thread;
5
+ struct locked_thread_t *next;
6
+ } locked_thread_t;
7
+
8
+ static locked_thread_t *locked_head = NULL;
9
+ static locked_thread_t *locked_tail = NULL;
10
+
11
+ extern int
12
+ is_in_locked(VALUE thread)
13
+ {
14
+ locked_thread_t *node;
15
+
16
+ if (!locked_head) return 0;
17
+
18
+ for (node = locked_head; node != locked_tail; node = node->next)
19
+ {
20
+ if (node->thread == thread) return 1;
21
+ }
22
+ return 0;
23
+ }
24
+
25
+ extern void
26
+ add_to_locked(VALUE thread)
27
+ {
28
+ locked_thread_t *node;
29
+
30
+ if (is_in_locked(thread)) return;
31
+
32
+ node = ALLOC(locked_thread_t);
33
+ node->thread = thread;
34
+ node->next = NULL;
35
+ if (locked_tail) locked_tail->next = node;
36
+ locked_tail = node;
37
+ if (!locked_head) locked_head = node;
38
+ }
39
+
40
+ extern VALUE
41
+ remove_from_locked()
42
+ {
43
+ VALUE thread;
44
+ locked_thread_t *node;
45
+
46
+ if (locked_head == NULL) return Qnil;
47
+
48
+ node = locked_head;
49
+ locked_head = locked_head->next;
50
+ if (locked_tail == node) locked_tail = NULL;
51
+ thread = node->thread;
52
+ xfree(node);
53
+ return thread;
54
+ }
@@ -0,0 +1,113 @@
1
+ #include <byebug.h>
2
+
3
+ static int
4
+ t_tbl_mark_keyvalue(st_data_t key, st_data_t value, st_data_t tbl)
5
+ {
6
+ VALUE thread = (VALUE)key;
7
+
8
+ if (!value) return ST_CONTINUE;
9
+
10
+ rb_gc_mark((VALUE)value);
11
+ rb_gc_mark(thread);
12
+
13
+ return ST_CONTINUE;
14
+ }
15
+
16
+ static void
17
+ t_tbl_mark(void* data)
18
+ {
19
+ threads_table_t *t_tbl = (threads_table_t *)data;
20
+ st_table *tbl = t_tbl->tbl;
21
+ st_foreach(tbl, t_tbl_mark_keyvalue, (st_data_t)tbl);
22
+ }
23
+
24
+ static void
25
+ t_tbl_free(void* data)
26
+ {
27
+ threads_table_t *t_tbl = (threads_table_t*)data;
28
+ st_free_table(t_tbl->tbl);
29
+ xfree(t_tbl);
30
+ }
31
+
32
+ VALUE
33
+ threads_create(void)
34
+ {
35
+ threads_table_t *t_tbl;
36
+
37
+ t_tbl = ALLOC(threads_table_t);
38
+ t_tbl->tbl = st_init_numtable();
39
+ return Data_Wrap_Struct(cThreadsTable, t_tbl_mark, t_tbl_free, t_tbl);
40
+ }
41
+
42
+ void
43
+ threads_clear(VALUE table)
44
+ {
45
+ threads_table_t *t_tbl;
46
+
47
+ Data_Get_Struct(table, threads_table_t, t_tbl);
48
+ st_clear(t_tbl->tbl);
49
+ }
50
+
51
+ static int
52
+ is_living_thread(VALUE thread)
53
+ {
54
+ return rb_funcall(thread, rb_intern("alive?"), 0) == Qtrue;
55
+ }
56
+
57
+ static int
58
+ t_tbl_check_i(st_data_t key, st_data_t value, st_data_t dummy)
59
+ {
60
+ VALUE thread;
61
+
62
+ if (!value) return ST_DELETE;
63
+
64
+ thread = (VALUE)key;
65
+
66
+ if (!is_living_thread(thread)) return ST_DELETE;
67
+
68
+ return ST_CONTINUE;
69
+ }
70
+
71
+ void
72
+ check_thread_contexts(void)
73
+ {
74
+ threads_table_t *t_tbl;
75
+
76
+ Data_Get_Struct(threads, threads_table_t, t_tbl);
77
+ st_foreach(t_tbl->tbl, t_tbl_check_i, 0);
78
+ }
79
+
80
+ void
81
+ thread_context_lookup(VALUE thread, VALUE *context)
82
+ {
83
+ threads_table_t *t_tbl;
84
+
85
+ Data_Get_Struct(threads, threads_table_t, t_tbl);
86
+ if (!st_lookup(t_tbl->tbl, thread, context) || !*context)
87
+ {
88
+ *context = context_create(thread);
89
+ st_insert(t_tbl->tbl, thread, *context);
90
+ }
91
+ }
92
+
93
+ void
94
+ halt_while_other_thread_is_active(debug_context_t *dc)
95
+ {
96
+ while (1)
97
+ {
98
+ /* halt execution of current thread if debugger is activated in another */
99
+ while (locker != Qnil && locker != rb_thread_current())
100
+ {
101
+ add_to_locked(rb_thread_current());
102
+ rb_thread_stop();
103
+ }
104
+
105
+ /* stop the current thread if it's marked as suspended */
106
+ if (CTX_FL_TEST(dc, CTX_FL_SUSPEND) && locker != rb_thread_current())
107
+ {
108
+ CTX_FL_SET(dc, CTX_FL_WAS_RUNNING);
109
+ rb_thread_stop();
110
+ }
111
+ else break;
112
+ }
113
+ }
@@ -29,9 +29,6 @@ module Byebug
29
29
  attr_accessor :last_exception
30
30
  Byebug.last_exception = nil
31
31
 
32
- # gdb-style annotation mode. Used in GNU Emacs interface
33
- attr_accessor :annotate
34
-
35
32
  def source_reload
36
33
  Object.send(:remove_const, "SCRIPT_LINES__") if
37
34
  Object.const_defined?("SCRIPT_LINES__")
@@ -39,8 +36,11 @@ module Byebug
39
36
  LineCache::clear_file_cache
40
37
  end
41
38
 
39
+ #
42
40
  # Get line +line_number+ from file named +filename+.
41
+ #
43
42
  # @return "\n" if there was a problem. Leaking blanks are stripped off.
43
+ #
44
44
  def line_at(filename, line_number)
45
45
  @@autoreload = nil unless defined?(@@autoreload)
46
46
  line = LineCache::getline filename, line_number, @@autoreload
@@ -48,11 +48,13 @@ module Byebug
48
48
  return "#{line.gsub(/^\s+/, '').chomp}"
49
49
  end
50
50
 
51
- alias stop remove_tracepoints
52
-
51
+ #
52
+ # Add a new breakpoint
53
+ #
53
54
  # @param [String] file
54
55
  # @param [Fixnum] line
55
56
  # @param [String] expr
57
+ #
56
58
  def add_breakpoint(file, line, expr=nil)
57
59
  breakpoint = Breakpoint.new(file, line, expr)
58
60
  breakpoints << breakpoint
@@ -104,16 +106,12 @@ module Byebug
104
106
  Byebug.const_set('INITIAL_DIR', Dir.pwd) unless defined? Byebug::INITIAL_DIR
105
107
  end
106
108
  Byebug.tracing = options[:tracing] unless options[:tracing].nil?
107
- if Byebug.started?
108
- retval = block && block.call(self)
109
- else
110
- retval = Byebug._start(&block)
111
- end
109
+ retval = Byebug._start(&block)
112
110
  post_mortem if options[:post_mortem]
113
111
  return retval
114
112
  end
115
113
 
116
- ##
114
+ #
117
115
  # Runs normal byebug initialization scripts.
118
116
  #
119
117
  # Reads and executes the commands from init file (if any) in the current
@@ -132,7 +130,7 @@ module Byebug
132
130
  end
133
131
  end
134
132
 
135
- ##
133
+ #
136
134
  # Runs a script file
137
135
  #
138
136
  def run_script(file, out = handler.interface, verbose=false)
@@ -141,7 +139,7 @@ module Byebug
141
139
  processor.process_commands(verbose)
142
140
  end
143
141
 
144
- ##
142
+ #
145
143
  # Activates the post-mortem mode. There are two ways of using it:
146
144
  #
147
145
  # == Global post-mortem mode
@@ -185,70 +183,33 @@ module Byebug
185
183
  end
186
184
 
187
185
  def handle_post_mortem(exp)
188
- return if !exp || !exp.__debug_context ||
189
- exp.__debug_context.stack_size == 0
186
+ return if !exp || !exp.__bb_context || exp.__bb_context.stack_size == 0
190
187
  orig_tracing = Byebug.tracing?
191
188
  Byebug.tracing = false
192
189
  Byebug.last_exception = exp
193
- handler.at_line(exp.__debug_context, exp.__debug_file, exp.__debug_line)
190
+ handler.at_line(exp.__bb_context, exp.__bb_file, exp.__bb_line)
194
191
  ensure
195
192
  Byebug.tracing = orig_tracing
196
193
  end
197
194
  private :handle_post_mortem
198
-
199
195
  end
200
196
  end
201
197
 
202
198
  class Exception
203
- attr_reader :__debug_file, :__debug_line, :__debug_binding, :__debug_context
204
- end
205
-
206
- class Module
207
- #
208
- # Wraps the +meth+ method with Byebug.start {...} block.
209
- #
210
- def debug_method(meth)
211
- old_meth = "__debugee_#{meth}"
212
- old_meth = "#{$1}_set" if old_meth =~ /^(.+)=$/
213
- alias_method old_meth.to_sym, meth
214
- class_eval <<-EOD
215
- def #{meth}(*args, &block)
216
- Byebug.start do
217
- byebug 2
218
- #{old_meth}(*args, &block)
219
- end
220
- end
221
- EOD
222
- end
223
-
224
- #
225
- # Wraps the +meth+ method with Byebug.post_mortem {...} block.
226
- #
227
- def post_mortem_method(meth)
228
- old_meth = "__postmortem_#{meth}"
229
- old_meth = "#{$1}_set" if old_meth =~ /^(.+)=$/
230
- alias_method old_meth.to_sym, meth
231
- class_eval <<-EOD
232
- def #{meth}(*args, &block)
233
- Byebug.start do |dbg|
234
- dbg.post_mortem do
235
- #{old_meth}(*args, &block)
236
- end
237
- end
238
- end
239
- EOD
240
- end
199
+ attr_reader :__bb_file, :__bb_line, :__bb_binding, :__bb_context
241
200
  end
242
201
 
243
202
  module Kernel
244
- ##
203
+ #
245
204
  # Enters byebug after _steps_into_ line events and _steps_out_ return events
246
205
  # occur. Before entering byebug startup, the init script is read.
247
206
  #
248
207
  def byebug(steps_into = 1, steps_out = 2)
249
208
  Byebug.start
250
209
  Byebug.run_init_script(StringIO.new)
251
- Byebug.context.stop_return steps_out if steps_out >= 1
252
- Byebug.context.step_into steps_into if steps_into >= 0
210
+ if Byebug.current_context.stack_size > 2
211
+ Byebug.current_context.stop_return steps_out if steps_out >= 1
212
+ end
213
+ Byebug.current_context.step_into steps_into if steps_into >= 0
253
214
  end
254
215
  end
@@ -5,7 +5,7 @@ require_relative 'helper'
5
5
  module Byebug
6
6
 
7
7
  module CommandFunctions
8
- ##
8
+ #
9
9
  # Pad a string with dots at the end to fit :width setting
10
10
  #
11
11
  def pad_with_dots(string)
@@ -15,13 +15,8 @@ module Byebug
15
15
  end
16
16
  end
17
17
 
18
- # Root dir for byebug
19
- BYEBUG_DIR = File.expand_path(File.dirname(__FILE__)) unless
20
- defined?(BYEBUG_DIR)
21
-
22
18
  class Command
23
- SubcmdStruct = Struct.new(:name, :min, :short_help, :long_help) unless
24
- defined?(SubcmdStruct)
19
+ Subcmd = Struct.new(:name, :min, :short_help, :long_help)
25
20
 
26
21
  class << self
27
22
  def commands
@@ -88,8 +83,8 @@ module Byebug
88
83
  end
89
84
 
90
85
  def load_commands
91
- Dir[File.join(Byebug.const_get(:BYEBUG_DIR), 'commands', '*')].each {
92
- |file| require file if file =~ /\.rb$/ }
86
+ Dir[File.join(File.dirname(__FILE__), 'commands', '*')].each {
87
+ |file| require file }
93
88
  Byebug.constants.grep(/Functions$/).map {
94
89
  |name| Byebug.const_get(name) }.each { |mod| include mod }
95
90
  end
@@ -170,11 +165,11 @@ module Byebug
170
165
  register_setting_var(:basename, false)
171
166
  register_setting_var(:callstyle, :long)
172
167
  register_setting_var(:testing, false)
173
- register_setting_var(:force_stepping, false)
174
- register_setting_var(:frame_fullpath, true)
168
+ register_setting_var(:forcestep, false)
169
+ register_setting_var(:fullpath, true)
175
170
  register_setting_var(:listsize, 10)
176
171
  register_setting_var(:stack_trace_on_error, false)
177
- register_setting_var(:tracing_plus, false)
172
+ register_setting_var(:linetrace_plus, false)
178
173
  cols = terminal_width || 160
179
174
  register_setting_var(:width, cols > 10 ? cols : 160)
180
175
  Byebug::ARGV = ARGV.clone unless defined? Byebug::ARGV
@@ -232,6 +227,10 @@ module Byebug
232
227
  def get_binding pos = @state.frame_pos
233
228
  @state.context ? @state.context.frame_binding(pos) : TOPLEVEL_BINDING
234
229
  end
230
+
231
+ def get_context(thnum)
232
+ Byebug.contexts.find {|c| c.thnum == thnum}
233
+ end
235
234
  end
236
235
 
237
236
  Command.load_commands
@@ -241,18 +240,18 @@ module Byebug
241
240
  # Use Byebug.settings[] and Byebug.settings[]= methods to query and set
242
241
  # byebug settings. These settings are available:
243
242
  #
244
- # :autolist - automatically calls 'list' command on breakpoint
245
243
  # :autoeval - evaluates input in the current binding if it's not
246
244
  # recognized as a byebug command
247
245
  # :autoirb - automatically calls 'irb' command on breakpoint
248
- # :stack_trace_on_error - shows full stack trace if eval command results in
249
- # an exception
250
- # :frame_fullpath - displays full paths when showing frame stack
251
- # :frame_class_names - displays method's class name when showing frame
252
- # stack
246
+ # :autolist - automatically calls 'list' command on breakpoint
253
247
  # :autoreload - makes 'list' command always display up-to-date
254
248
  # source code
255
- # :force_stepping - stepping command always move to the new line
249
+ # :frame_class_names - displays method's class name when showing frame
250
+ # stack
251
+ # :forcestep - stepping command always move to the new line
252
+ # :fullpath - displays full paths when showing frame stack
253
+ # :stack_trace_on_error - shows full stack trace if eval command results in
254
+ # an exception
256
255
  #
257
256
  def self.settings
258
257
  Command.settings
@@ -66,9 +66,6 @@ module Byebug
66
66
  return unless confirm("Set breakpoint anyway? (y/n) ")
67
67
  end
68
68
 
69
- return errmsg "We are not in a state we can add breakpoints.\n" unless
70
- @state.context
71
-
72
69
  b = Byebug.add_breakpoint brkpt_filename, line, expr
73
70
  print "Created breakpoint #{b.id} at " \
74
71
  "#{CommandProcessor.canonic_file(brkpt_filename)}:#{line.to_s}\n"
@@ -103,7 +100,7 @@ module Byebug
103
100
  self.allow_in_control = true
104
101
 
105
102
  def regexp
106
- /^\s *del(?:ete)? (?:\s+(.*))?$/ix
103
+ /^\s* del(?:ete)? (?:\s+(.*))?$/x
107
104
  end
108
105
 
109
106
  def execute
@@ -4,7 +4,7 @@ module Byebug
4
4
  self.allow_in_control = true
5
5
 
6
6
  def regexp
7
- /^\s* cat(?:ch)? (?:\s+(\S+))? (?:\s+(off))? \s*$/ix
7
+ /^\s* cat(?:ch)? (?:\s+(\S+))? (?:\s+(off))? \s*$/x
8
8
  end
9
9
 
10
10
  def execute
@@ -3,7 +3,7 @@ module Byebug
3
3
  class ConditionCommand < Command
4
4
 
5
5
  def regexp
6
- /^\s* cond(?:ition)? (?:\s+(\d+)(?:\s+(.*))?)? \s*$/ix
6
+ /^\s* cond(?:ition)? (?:\s+(\d+)(?:\s+(.*))?)? \s*$/x
7
7
  end
8
8
 
9
9
  def execute