debug 0.2.1 → 1.0.0.alpha0
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.
- checksums.yaml +4 -4
- data/.gitignore +0 -1
- data/LICENSE.txt +19 -20
- data/README.md +142 -28
- data/Rakefile +9 -0
- data/debug.gemspec +20 -10
- data/exe/rdbg +3 -0
- data/lib/debug/bp.vim +68 -0
- data/lib/debug/breakpoint.rb +97 -0
- data/lib/debug/client.rb +135 -0
- data/lib/debug/config.rb +26 -0
- data/lib/debug/repl.rb +67 -0
- data/lib/debug/server.rb +119 -0
- data/lib/debug/session.rb +598 -0
- data/lib/debug/source_repository.rb +20 -0
- data/lib/debug/tcpserver.rb +23 -0
- data/lib/debug/thread_client.rb +402 -0
- data/lib/debug/unixserver.rb +19 -0
- data/lib/debug/version.rb +3 -0
- data/lib/debug.rb +11 -1116
- metadata +61 -21
- data/Gemfile +0 -8
data/lib/debug.rb
CHANGED
@@ -1,1120 +1,15 @@
|
|
1
|
-
|
2
|
-
# Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
|
3
|
-
# Copyright (C) 2000 Information-technology Promotion Agency, Japan
|
4
|
-
# Copyright (C) 2000-2003 NAKAMURA, Hiroshi <nahi@ruby-lang.org>
|
1
|
+
require_relative 'debug/repl'
|
5
2
|
|
6
|
-
|
7
|
-
|
8
|
-
|
3
|
+
# default break points
|
4
|
+
DEBUGGER__.add_catch_breakpoint 'RuntimeError'
|
5
|
+
class Binding
|
6
|
+
DEBUGGER__.add_line_breakpoint __FILE__, __LINE__ + 1
|
7
|
+
def bp; nil; end
|
9
8
|
end
|
10
9
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
Single.trace_func(*vars)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
SCRIPT_LINES__ = {} unless defined? SCRIPT_LINES__ # :nodoc:
|
21
|
-
|
22
|
-
##
|
23
|
-
# This library provides debugging functionality to Ruby.
|
24
|
-
#
|
25
|
-
# To add a debugger to your code, start by requiring +debug+ in your
|
26
|
-
# program:
|
27
|
-
#
|
28
|
-
# def say(word)
|
29
|
-
# require 'debug'
|
30
|
-
# puts word
|
31
|
-
# end
|
32
|
-
#
|
33
|
-
# This will cause Ruby to interrupt execution and show a prompt when the +say+
|
34
|
-
# method is run.
|
35
|
-
#
|
36
|
-
# Once you're inside the prompt, you can start debugging your program.
|
37
|
-
#
|
38
|
-
# (rdb:1) p word
|
39
|
-
# "hello"
|
40
|
-
#
|
41
|
-
# == Getting help
|
42
|
-
#
|
43
|
-
# You can get help at any time by pressing +h+.
|
44
|
-
#
|
45
|
-
# (rdb:1) h
|
46
|
-
# Debugger help v.-0.002b
|
47
|
-
# Commands
|
48
|
-
# b[reak] [file:|class:]<line|method>
|
49
|
-
# b[reak] [class.]<line|method>
|
50
|
-
# set breakpoint to some position
|
51
|
-
# wat[ch] <expression> set watchpoint to some expression
|
52
|
-
# cat[ch] (<exception>|off) set catchpoint to an exception
|
53
|
-
# b[reak] list breakpoints
|
54
|
-
# cat[ch] show catchpoint
|
55
|
-
# del[ete][ nnn] delete some or all breakpoints
|
56
|
-
# disp[lay] <expression> add expression into display expression list
|
57
|
-
# undisp[lay][ nnn] delete one particular or all display expressions
|
58
|
-
# c[ont] run until program ends or hit breakpoint
|
59
|
-
# s[tep][ nnn] step (into methods) one line or till line nnn
|
60
|
-
# n[ext][ nnn] go over one line or till line nnn
|
61
|
-
# w[here] display frames
|
62
|
-
# f[rame] alias for where
|
63
|
-
# l[ist][ (-|nn-mm)] list program, - lists backwards
|
64
|
-
# nn-mm lists given lines
|
65
|
-
# up[ nn] move to higher frame
|
66
|
-
# down[ nn] move to lower frame
|
67
|
-
# fin[ish] return to outer frame
|
68
|
-
# tr[ace] (on|off) set trace mode of current thread
|
69
|
-
# tr[ace] (on|off) all set trace mode of all threads
|
70
|
-
# q[uit] exit from debugger
|
71
|
-
# v[ar] g[lobal] show global variables
|
72
|
-
# v[ar] l[ocal] show local variables
|
73
|
-
# v[ar] i[nstance] <object> show instance variables of object
|
74
|
-
# v[ar] c[onst] <object> show constants of object
|
75
|
-
# m[ethod] i[nstance] <obj> show methods of object
|
76
|
-
# m[ethod] <class|module> show instance methods of class or module
|
77
|
-
# th[read] l[ist] list all threads
|
78
|
-
# th[read] c[ur[rent]] show current thread
|
79
|
-
# th[read] [sw[itch]] <nnn> switch thread context to nnn
|
80
|
-
# th[read] stop <nnn> stop thread nnn
|
81
|
-
# th[read] resume <nnn> resume thread nnn
|
82
|
-
# p expression evaluate expression and print its value
|
83
|
-
# h[elp] print this help
|
84
|
-
# <everything else> evaluate
|
85
|
-
#
|
86
|
-
# == Usage
|
87
|
-
#
|
88
|
-
# The following is a list of common functionalities that the debugger
|
89
|
-
# provides.
|
90
|
-
#
|
91
|
-
# === Navigating through your code
|
92
|
-
#
|
93
|
-
# In general, a debugger is used to find bugs in your program, which
|
94
|
-
# often means pausing execution and inspecting variables at some point
|
95
|
-
# in time.
|
96
|
-
#
|
97
|
-
# Let's look at an example:
|
98
|
-
#
|
99
|
-
# def my_method(foo)
|
100
|
-
# require 'debug'
|
101
|
-
# foo = get_foo if foo.nil?
|
102
|
-
# raise if foo.nil?
|
103
|
-
# end
|
104
|
-
#
|
105
|
-
# When you run this program, the debugger will kick in just before the
|
106
|
-
# +foo+ assignment.
|
107
|
-
#
|
108
|
-
# (rdb:1) p foo
|
109
|
-
# nil
|
110
|
-
#
|
111
|
-
# In this example, it'd be interesting to move to the next line and
|
112
|
-
# inspect the value of +foo+ again. You can do that by pressing +n+:
|
113
|
-
#
|
114
|
-
# (rdb:1) n # goes to next line
|
115
|
-
# (rdb:1) p foo
|
116
|
-
# nil
|
117
|
-
#
|
118
|
-
# You now know that the original value of +foo+ was nil, and that it
|
119
|
-
# still was nil after calling +get_foo+.
|
120
|
-
#
|
121
|
-
# Other useful commands for navigating through your code are:
|
122
|
-
#
|
123
|
-
# +c+::
|
124
|
-
# Runs the program until it either exists or encounters another breakpoint.
|
125
|
-
# You usually press +c+ when you are finished debugging your program and
|
126
|
-
# want to resume its execution.
|
127
|
-
# +s+::
|
128
|
-
# Steps into method definition. In the previous example, +s+ would take you
|
129
|
-
# inside the method definition of +get_foo+.
|
130
|
-
# +r+::
|
131
|
-
# Restart the program.
|
132
|
-
# +q+::
|
133
|
-
# Quit the program.
|
134
|
-
#
|
135
|
-
# === Inspecting variables
|
136
|
-
#
|
137
|
-
# You can use the debugger to easily inspect both local and global variables.
|
138
|
-
# We've seen how to inspect local variables before:
|
139
|
-
#
|
140
|
-
# (rdb:1) p my_arg
|
141
|
-
# 42
|
142
|
-
#
|
143
|
-
# You can also pretty print the result of variables or expressions:
|
144
|
-
#
|
145
|
-
# (rdb:1) pp %w{a very long long array containing many words}
|
146
|
-
# ["a",
|
147
|
-
# "very",
|
148
|
-
# "long",
|
149
|
-
# ...
|
150
|
-
# ]
|
151
|
-
#
|
152
|
-
# You can list all local variables with +v l+:
|
153
|
-
#
|
154
|
-
# (rdb:1) v l
|
155
|
-
# foo => "hello"
|
156
|
-
#
|
157
|
-
# Similarly, you can show all global variables with +v g+:
|
158
|
-
#
|
159
|
-
# (rdb:1) v g
|
160
|
-
# all global variables
|
161
|
-
#
|
162
|
-
# Finally, you can omit +p+ if you simply want to evaluate a variable or
|
163
|
-
# expression
|
164
|
-
#
|
165
|
-
# (rdb:1) 5**2
|
166
|
-
# 25
|
167
|
-
#
|
168
|
-
# === Going beyond basics
|
169
|
-
#
|
170
|
-
# Ruby Debug provides more advanced functionalities like switching
|
171
|
-
# between threads, setting breakpoints and watch expressions, and more.
|
172
|
-
# The full list of commands is available at any time by pressing +h+.
|
173
|
-
#
|
174
|
-
# == Staying out of trouble
|
175
|
-
#
|
176
|
-
# Make sure you remove every instance of +require 'debug'+ before
|
177
|
-
# shipping your code. Failing to do so may result in your program
|
178
|
-
# hanging unpredictably.
|
179
|
-
#
|
180
|
-
# Debug is not available in safe mode.
|
181
|
-
|
182
|
-
class DEBUGGER__
|
183
|
-
MUTEX = Thread::Mutex.new # :nodoc:
|
184
|
-
CONTINUATIONS_SUPPORTED = RUBY_ENGINE == 'ruby'
|
185
|
-
|
186
|
-
require 'continuation' if CONTINUATIONS_SUPPORTED
|
187
|
-
|
188
|
-
class Context # :nodoc:
|
189
|
-
DEBUG_LAST_CMD = []
|
190
|
-
|
191
|
-
begin
|
192
|
-
require 'readline'
|
193
|
-
def readline(prompt, hist)
|
194
|
-
Readline::readline(prompt, hist)
|
195
|
-
end
|
196
|
-
rescue LoadError
|
197
|
-
def readline(prompt, hist)
|
198
|
-
STDOUT.print prompt
|
199
|
-
STDOUT.flush
|
200
|
-
line = STDIN.gets
|
201
|
-
exit unless line
|
202
|
-
line.chomp!
|
203
|
-
line
|
204
|
-
end
|
205
|
-
USE_READLINE = false
|
206
|
-
end
|
207
|
-
|
208
|
-
def initialize
|
209
|
-
if Thread.current == Thread.main
|
210
|
-
@stop_next = 1
|
211
|
-
else
|
212
|
-
@stop_next = 0
|
213
|
-
end
|
214
|
-
@last_file = nil
|
215
|
-
@file = nil
|
216
|
-
@line = nil
|
217
|
-
@no_step = nil
|
218
|
-
@frames = []
|
219
|
-
@finish_pos = 0
|
220
|
-
@trace = false
|
221
|
-
@catch = "StandardError"
|
222
|
-
@suspend_next = false
|
223
|
-
end
|
224
|
-
|
225
|
-
def stop_next(n=1)
|
226
|
-
@stop_next = n
|
227
|
-
end
|
228
|
-
|
229
|
-
def set_suspend
|
230
|
-
@suspend_next = true
|
231
|
-
end
|
232
|
-
|
233
|
-
def clear_suspend
|
234
|
-
@suspend_next = false
|
235
|
-
end
|
236
|
-
|
237
|
-
def suspend_all
|
238
|
-
DEBUGGER__.suspend
|
239
|
-
end
|
240
|
-
|
241
|
-
def resume_all
|
242
|
-
DEBUGGER__.resume
|
243
|
-
end
|
244
|
-
|
245
|
-
def check_suspend
|
246
|
-
while MUTEX.synchronize {
|
247
|
-
if @suspend_next
|
248
|
-
DEBUGGER__.waiting.push Thread.current
|
249
|
-
@suspend_next = false
|
250
|
-
true
|
251
|
-
end
|
252
|
-
}
|
253
|
-
end
|
254
|
-
end
|
255
|
-
|
256
|
-
def trace?
|
257
|
-
@trace
|
258
|
-
end
|
259
|
-
|
260
|
-
def set_trace(arg)
|
261
|
-
@trace = arg
|
262
|
-
end
|
263
|
-
|
264
|
-
def stdout
|
265
|
-
DEBUGGER__.stdout
|
266
|
-
end
|
267
|
-
|
268
|
-
def break_points
|
269
|
-
DEBUGGER__.break_points
|
270
|
-
end
|
271
|
-
|
272
|
-
def display
|
273
|
-
DEBUGGER__.display
|
274
|
-
end
|
275
|
-
|
276
|
-
def context(th)
|
277
|
-
DEBUGGER__.context(th)
|
278
|
-
end
|
279
|
-
|
280
|
-
def set_trace_all(arg)
|
281
|
-
DEBUGGER__.set_trace(arg)
|
282
|
-
end
|
283
|
-
|
284
|
-
def set_last_thread(th)
|
285
|
-
DEBUGGER__.set_last_thread(th)
|
286
|
-
end
|
287
|
-
|
288
|
-
def debug_eval(str, binding)
|
289
|
-
begin
|
290
|
-
eval(str, binding)
|
291
|
-
rescue StandardError, ScriptError => e
|
292
|
-
at = eval("caller(1)", binding)
|
293
|
-
stdout.printf "%s:%s\n", at.shift, e.to_s.sub(/\(eval\):1:(in `.*?':)?/, '')
|
294
|
-
for i in at
|
295
|
-
stdout.printf "\tfrom %s\n", i
|
296
|
-
end
|
297
|
-
throw :debug_error
|
298
|
-
end
|
299
|
-
end
|
300
|
-
|
301
|
-
def debug_silent_eval(str, binding)
|
302
|
-
begin
|
303
|
-
eval(str, binding)
|
304
|
-
rescue StandardError, ScriptError
|
305
|
-
nil
|
306
|
-
end
|
307
|
-
end
|
308
|
-
|
309
|
-
def var_list(ary, binding)
|
310
|
-
ary.sort!
|
311
|
-
for v in ary
|
312
|
-
stdout.printf " %s => %s\n", v, eval(v.to_s, binding).inspect
|
313
|
-
end
|
314
|
-
end
|
315
|
-
|
316
|
-
def debug_variable_info(input, binding)
|
317
|
-
case input
|
318
|
-
when /^\s*g(?:lobal)?\s*$/
|
319
|
-
var_list(global_variables, binding)
|
320
|
-
|
321
|
-
when /^\s*l(?:ocal)?\s*$/
|
322
|
-
var_list(eval("local_variables", binding), binding)
|
323
|
-
|
324
|
-
when /^\s*i(?:nstance)?\s+/
|
325
|
-
obj = debug_eval($', binding)
|
326
|
-
var_list(obj.instance_variables, obj.instance_eval{binding()})
|
327
|
-
|
328
|
-
when /^\s*c(?:onst(?:ant)?)?\s+/
|
329
|
-
obj = debug_eval($', binding)
|
330
|
-
unless obj.kind_of? Module
|
331
|
-
stdout.print "Should be Class/Module: ", $', "\n"
|
332
|
-
else
|
333
|
-
var_list(obj.constants, obj.module_eval{binding()})
|
334
|
-
end
|
335
|
-
end
|
336
|
-
end
|
337
|
-
|
338
|
-
def debug_method_info(input, binding)
|
339
|
-
case input
|
340
|
-
when /^i(:?nstance)?\s+/
|
341
|
-
obj = debug_eval($', binding)
|
342
|
-
|
343
|
-
len = 0
|
344
|
-
for v in obj.methods.sort
|
345
|
-
len += v.size + 1
|
346
|
-
if len > 70
|
347
|
-
len = v.size + 1
|
348
|
-
stdout.print "\n"
|
349
|
-
end
|
350
|
-
stdout.print v, " "
|
351
|
-
end
|
352
|
-
stdout.print "\n"
|
353
|
-
|
354
|
-
else
|
355
|
-
obj = debug_eval(input, binding)
|
356
|
-
unless obj.kind_of? Module
|
357
|
-
stdout.print "Should be Class/Module: ", input, "\n"
|
358
|
-
else
|
359
|
-
len = 0
|
360
|
-
for v in obj.instance_methods(false).sort
|
361
|
-
len += v.size + 1
|
362
|
-
if len > 70
|
363
|
-
len = v.size + 1
|
364
|
-
stdout.print "\n"
|
365
|
-
end
|
366
|
-
stdout.print v, " "
|
367
|
-
end
|
368
|
-
stdout.print "\n"
|
369
|
-
end
|
370
|
-
end
|
371
|
-
end
|
372
|
-
|
373
|
-
def thnum
|
374
|
-
num = DEBUGGER__.instance_eval{@thread_list[Thread.current]}
|
375
|
-
unless num
|
376
|
-
DEBUGGER__.make_thread_list
|
377
|
-
num = DEBUGGER__.instance_eval{@thread_list[Thread.current]}
|
378
|
-
end
|
379
|
-
num
|
380
|
-
end
|
381
|
-
|
382
|
-
def debug_command(file, line, id, binding)
|
383
|
-
MUTEX.lock
|
384
|
-
if CONTINUATIONS_SUPPORTED
|
385
|
-
unless defined?($debugger_restart) and $debugger_restart
|
386
|
-
callcc{|c| $debugger_restart = c}
|
387
|
-
end
|
388
|
-
end
|
389
|
-
set_last_thread(Thread.current)
|
390
|
-
frame_pos = 0
|
391
|
-
binding_file = file
|
392
|
-
binding_line = line
|
393
|
-
previous_line = nil
|
394
|
-
if ENV['EMACS']
|
395
|
-
stdout.printf "\032\032%s:%d:\n", binding_file, binding_line
|
396
|
-
else
|
397
|
-
stdout.printf "%s:%d:%s", binding_file, binding_line,
|
398
|
-
line_at(binding_file, binding_line)
|
399
|
-
end
|
400
|
-
@frames[0] = [binding, file, line, id]
|
401
|
-
display_expressions(binding)
|
402
|
-
prompt = true
|
403
|
-
while prompt and input = readline("(rdb:%d) "%thnum(), true)
|
404
|
-
catch(:debug_error) do
|
405
|
-
if input == ""
|
406
|
-
next unless DEBUG_LAST_CMD[0]
|
407
|
-
input = DEBUG_LAST_CMD[0]
|
408
|
-
stdout.print input, "\n"
|
409
|
-
else
|
410
|
-
DEBUG_LAST_CMD[0] = input
|
411
|
-
end
|
412
|
-
|
413
|
-
case input
|
414
|
-
when /^\s*tr(?:ace)?(?:\s+(on|off))?(?:\s+(all))?$/
|
415
|
-
if defined?( $2 )
|
416
|
-
if $1 == 'on'
|
417
|
-
set_trace_all true
|
418
|
-
else
|
419
|
-
set_trace_all false
|
420
|
-
end
|
421
|
-
elsif defined?( $1 )
|
422
|
-
if $1 == 'on'
|
423
|
-
set_trace true
|
424
|
-
else
|
425
|
-
set_trace false
|
426
|
-
end
|
427
|
-
end
|
428
|
-
if trace?
|
429
|
-
stdout.print "Trace on.\n"
|
430
|
-
else
|
431
|
-
stdout.print "Trace off.\n"
|
432
|
-
end
|
433
|
-
|
434
|
-
when /^\s*b(?:reak)?\s+(?:(.+):)?([^.:]+)$/
|
435
|
-
pos = $2
|
436
|
-
if $1
|
437
|
-
klass = debug_silent_eval($1, binding)
|
438
|
-
file = File.expand_path($1)
|
439
|
-
end
|
440
|
-
if pos =~ /^\d+$/
|
441
|
-
pname = pos
|
442
|
-
pos = pos.to_i
|
443
|
-
else
|
444
|
-
pname = pos = pos.intern.id2name
|
445
|
-
end
|
446
|
-
break_points.push [true, 0, klass || file, pos]
|
447
|
-
stdout.printf "Set breakpoint %d at %s:%s\n", break_points.size, klass || file, pname
|
448
|
-
|
449
|
-
when /^\s*b(?:reak)?\s+(.+)[#.]([^.:]+)$/
|
450
|
-
pos = $2.intern.id2name
|
451
|
-
klass = debug_eval($1, binding)
|
452
|
-
break_points.push [true, 0, klass, pos]
|
453
|
-
stdout.printf "Set breakpoint %d at %s.%s\n", break_points.size, klass, pos
|
454
|
-
|
455
|
-
when /^\s*wat(?:ch)?\s+(.+)$/
|
456
|
-
exp = $1
|
457
|
-
break_points.push [true, 1, exp]
|
458
|
-
stdout.printf "Set watchpoint %d:%s\n", break_points.size, exp
|
459
|
-
|
460
|
-
when /^\s*b(?:reak)?$/
|
461
|
-
if break_points.find{|b| b[1] == 0}
|
462
|
-
n = 1
|
463
|
-
stdout.print "Breakpoints:\n"
|
464
|
-
break_points.each do |b|
|
465
|
-
if b[0] and b[1] == 0
|
466
|
-
stdout.printf " %d %s:%s\n", n, b[2], b[3]
|
467
|
-
end
|
468
|
-
n += 1
|
469
|
-
end
|
470
|
-
end
|
471
|
-
if break_points.find{|b| b[1] == 1}
|
472
|
-
n = 1
|
473
|
-
stdout.print "\n"
|
474
|
-
stdout.print "Watchpoints:\n"
|
475
|
-
for b in break_points
|
476
|
-
if b[0] and b[1] == 1
|
477
|
-
stdout.printf " %d %s\n", n, b[2]
|
478
|
-
end
|
479
|
-
n += 1
|
480
|
-
end
|
481
|
-
end
|
482
|
-
if break_points.size == 0
|
483
|
-
stdout.print "No breakpoints\n"
|
484
|
-
else
|
485
|
-
stdout.print "\n"
|
486
|
-
end
|
487
|
-
|
488
|
-
when /^\s*del(?:ete)?(?:\s+(\d+))?$/
|
489
|
-
pos = $1
|
490
|
-
unless pos
|
491
|
-
input = readline("Clear all breakpoints? (y/n) ", false)
|
492
|
-
if input == "y"
|
493
|
-
for b in break_points
|
494
|
-
b[0] = false
|
495
|
-
end
|
496
|
-
end
|
497
|
-
else
|
498
|
-
pos = pos.to_i
|
499
|
-
if break_points[pos-1]
|
500
|
-
break_points[pos-1][0] = false
|
501
|
-
else
|
502
|
-
stdout.printf "Breakpoint %d is not defined\n", pos
|
503
|
-
end
|
504
|
-
end
|
505
|
-
|
506
|
-
when /^\s*disp(?:lay)?\s+(.+)$/
|
507
|
-
exp = $1
|
508
|
-
display.push [true, exp]
|
509
|
-
stdout.printf "%d: ", display.size
|
510
|
-
display_expression(exp, binding)
|
511
|
-
|
512
|
-
when /^\s*disp(?:lay)?$/
|
513
|
-
display_expressions(binding)
|
514
|
-
|
515
|
-
when /^\s*undisp(?:lay)?(?:\s+(\d+))?$/
|
516
|
-
pos = $1
|
517
|
-
unless pos
|
518
|
-
input = readline("Clear all expressions? (y/n) ", false)
|
519
|
-
if input == "y"
|
520
|
-
for d in display
|
521
|
-
d[0] = false
|
522
|
-
end
|
523
|
-
end
|
524
|
-
else
|
525
|
-
pos = pos.to_i
|
526
|
-
if display[pos-1]
|
527
|
-
display[pos-1][0] = false
|
528
|
-
else
|
529
|
-
stdout.printf "Display expression %d is not defined\n", pos
|
530
|
-
end
|
531
|
-
end
|
532
|
-
|
533
|
-
when /^\s*c(?:ont)?$/
|
534
|
-
prompt = false
|
535
|
-
|
536
|
-
when /^\s*s(?:tep)?(?:\s+(\d+))?$/
|
537
|
-
if $1
|
538
|
-
lev = $1.to_i
|
539
|
-
else
|
540
|
-
lev = 1
|
541
|
-
end
|
542
|
-
@stop_next = lev
|
543
|
-
prompt = false
|
544
|
-
|
545
|
-
when /^\s*n(?:ext)?(?:\s+(\d+))?$/
|
546
|
-
if $1
|
547
|
-
lev = $1.to_i
|
548
|
-
else
|
549
|
-
lev = 1
|
550
|
-
end
|
551
|
-
@stop_next = lev
|
552
|
-
@no_step = @frames.size - frame_pos
|
553
|
-
prompt = false
|
554
|
-
|
555
|
-
when /^\s*w(?:here)?$/, /^\s*f(?:rame)?$/
|
556
|
-
display_frames(frame_pos)
|
557
|
-
|
558
|
-
when /^\s*l(?:ist)?(?:\s+(.+))?$/
|
559
|
-
if not $1
|
560
|
-
b = previous_line ? previous_line + 10 : binding_line - 5
|
561
|
-
e = b + 9
|
562
|
-
elsif $1 == '-'
|
563
|
-
b = previous_line ? previous_line - 10 : binding_line - 5
|
564
|
-
e = b + 9
|
565
|
-
else
|
566
|
-
b, e = $1.split(/[-,]/)
|
567
|
-
if e
|
568
|
-
b = b.to_i
|
569
|
-
e = e.to_i
|
570
|
-
else
|
571
|
-
b = b.to_i - 5
|
572
|
-
e = b + 9
|
573
|
-
end
|
574
|
-
end
|
575
|
-
previous_line = b
|
576
|
-
display_list(b, e, binding_file, binding_line)
|
577
|
-
|
578
|
-
when /^\s*up(?:\s+(\d+))?$/
|
579
|
-
previous_line = nil
|
580
|
-
if $1
|
581
|
-
lev = $1.to_i
|
582
|
-
else
|
583
|
-
lev = 1
|
584
|
-
end
|
585
|
-
frame_pos += lev
|
586
|
-
if frame_pos >= @frames.size
|
587
|
-
frame_pos = @frames.size - 1
|
588
|
-
stdout.print "At toplevel\n"
|
589
|
-
end
|
590
|
-
binding, binding_file, binding_line = @frames[frame_pos]
|
591
|
-
stdout.print format_frame(frame_pos)
|
592
|
-
|
593
|
-
when /^\s*down(?:\s+(\d+))?$/
|
594
|
-
previous_line = nil
|
595
|
-
if $1
|
596
|
-
lev = $1.to_i
|
597
|
-
else
|
598
|
-
lev = 1
|
599
|
-
end
|
600
|
-
frame_pos -= lev
|
601
|
-
if frame_pos < 0
|
602
|
-
frame_pos = 0
|
603
|
-
stdout.print "At stack bottom\n"
|
604
|
-
end
|
605
|
-
binding, binding_file, binding_line = @frames[frame_pos]
|
606
|
-
stdout.print format_frame(frame_pos)
|
607
|
-
|
608
|
-
when /^\s*fin(?:ish)?$/
|
609
|
-
if frame_pos == @frames.size
|
610
|
-
stdout.print "\"finish\" not meaningful in the outermost frame.\n"
|
611
|
-
else
|
612
|
-
@finish_pos = @frames.size - frame_pos
|
613
|
-
frame_pos = 0
|
614
|
-
prompt = false
|
615
|
-
end
|
616
|
-
|
617
|
-
when /^\s*cat(?:ch)?(?:\s+(.+))?$/
|
618
|
-
if $1
|
619
|
-
excn = $1
|
620
|
-
if excn == 'off'
|
621
|
-
@catch = nil
|
622
|
-
stdout.print "Clear catchpoint.\n"
|
623
|
-
else
|
624
|
-
@catch = excn
|
625
|
-
stdout.printf "Set catchpoint %s.\n", @catch
|
626
|
-
end
|
627
|
-
else
|
628
|
-
if @catch
|
629
|
-
stdout.printf "Catchpoint %s.\n", @catch
|
630
|
-
else
|
631
|
-
stdout.print "No catchpoint.\n"
|
632
|
-
end
|
633
|
-
end
|
634
|
-
|
635
|
-
when /^\s*q(?:uit)?$/
|
636
|
-
input = readline("Really quit? (y/n) ", false)
|
637
|
-
if input == "y"
|
638
|
-
exit! # exit -> exit!: No graceful way to stop threads...
|
639
|
-
end
|
640
|
-
|
641
|
-
when /^\s*v(?:ar)?\s+/
|
642
|
-
debug_variable_info($', binding)
|
643
|
-
|
644
|
-
when /^\s*m(?:ethod)?\s+/
|
645
|
-
debug_method_info($', binding)
|
646
|
-
|
647
|
-
when /^\s*th(?:read)?\s+/
|
648
|
-
if DEBUGGER__.debug_thread_info($', binding) == :cont
|
649
|
-
prompt = false
|
650
|
-
end
|
651
|
-
|
652
|
-
when /^\s*pp\s+/
|
653
|
-
PP.pp(debug_eval($', binding), stdout)
|
654
|
-
|
655
|
-
when /^\s*p\s+/
|
656
|
-
stdout.printf "%s\n", debug_eval($', binding).inspect
|
657
|
-
|
658
|
-
when /^\s*r(?:estart)?$/
|
659
|
-
if CONTINUATIONS_SUPPORTED
|
660
|
-
$debugger_restart.call
|
661
|
-
else
|
662
|
-
stdout.print "Restart requires continuations.\n"
|
663
|
-
end
|
664
|
-
|
665
|
-
when /^\s*h(?:elp)?$/
|
666
|
-
debug_print_help()
|
667
|
-
|
668
|
-
else
|
669
|
-
v = debug_eval(input, binding)
|
670
|
-
stdout.printf "%s\n", v.inspect
|
671
|
-
end
|
672
|
-
end
|
673
|
-
end
|
674
|
-
MUTEX.unlock
|
675
|
-
resume_all
|
676
|
-
end
|
677
|
-
|
678
|
-
def debug_print_help
|
679
|
-
stdout.print <<EOHELP
|
680
|
-
Debugger help v.-0.002b
|
681
|
-
Commands
|
682
|
-
b[reak] [file:|class:]<line|method>
|
683
|
-
b[reak] [class.]<line|method>
|
684
|
-
set breakpoint to some position
|
685
|
-
wat[ch] <expression> set watchpoint to some expression
|
686
|
-
cat[ch] (<exception>|off) set catchpoint to an exception
|
687
|
-
b[reak] list breakpoints
|
688
|
-
cat[ch] show catchpoint
|
689
|
-
del[ete][ nnn] delete some or all breakpoints
|
690
|
-
disp[lay] <expression> add expression into display expression list
|
691
|
-
undisp[lay][ nnn] delete one particular or all display expressions
|
692
|
-
c[ont] run until program ends or hit breakpoint
|
693
|
-
s[tep][ nnn] step (into methods) one line or till line nnn
|
694
|
-
n[ext][ nnn] go over one line or till line nnn
|
695
|
-
w[here] display frames
|
696
|
-
f[rame] alias for where
|
697
|
-
l[ist][ (-|nn-mm)] list program, - lists backwards
|
698
|
-
nn-mm lists given lines
|
699
|
-
up[ nn] move to higher frame
|
700
|
-
down[ nn] move to lower frame
|
701
|
-
fin[ish] return to outer frame
|
702
|
-
tr[ace] (on|off) set trace mode of current thread
|
703
|
-
tr[ace] (on|off) all set trace mode of all threads
|
704
|
-
q[uit] exit from debugger
|
705
|
-
v[ar] g[lobal] show global variables
|
706
|
-
v[ar] l[ocal] show local variables
|
707
|
-
v[ar] i[nstance] <object> show instance variables of object
|
708
|
-
v[ar] c[onst] <object> show constants of object
|
709
|
-
m[ethod] i[nstance] <obj> show methods of object
|
710
|
-
m[ethod] <class|module> show instance methods of class or module
|
711
|
-
th[read] l[ist] list all threads
|
712
|
-
th[read] c[ur[rent]] show current thread
|
713
|
-
th[read] [sw[itch]] <nnn> switch thread context to nnn
|
714
|
-
th[read] stop <nnn> stop thread nnn
|
715
|
-
th[read] resume <nnn> resume thread nnn
|
716
|
-
pp expression evaluate expression and pretty_print its value
|
717
|
-
p expression evaluate expression and print its value
|
718
|
-
r[estart] restart program
|
719
|
-
h[elp] print this help
|
720
|
-
<everything else> evaluate
|
721
|
-
EOHELP
|
722
|
-
end
|
723
|
-
|
724
|
-
def display_expressions(binding)
|
725
|
-
n = 1
|
726
|
-
for d in display
|
727
|
-
if d[0]
|
728
|
-
stdout.printf "%d: ", n
|
729
|
-
display_expression(d[1], binding)
|
730
|
-
end
|
731
|
-
n += 1
|
732
|
-
end
|
733
|
-
end
|
734
|
-
|
735
|
-
def display_expression(exp, binding)
|
736
|
-
stdout.printf "%s = %s\n", exp, debug_silent_eval(exp, binding).to_s
|
737
|
-
end
|
738
|
-
|
739
|
-
def frame_set_pos(file, line)
|
740
|
-
if @frames[0]
|
741
|
-
@frames[0][1] = file
|
742
|
-
@frames[0][2] = line
|
743
|
-
end
|
744
|
-
end
|
745
|
-
|
746
|
-
def display_frames(pos)
|
747
|
-
0.upto(@frames.size - 1) do |n|
|
748
|
-
if n == pos
|
749
|
-
stdout.print "--> "
|
750
|
-
else
|
751
|
-
stdout.print " "
|
752
|
-
end
|
753
|
-
stdout.print format_frame(n)
|
754
|
-
end
|
755
|
-
end
|
756
|
-
|
757
|
-
def format_frame(pos)
|
758
|
-
_, file, line, id = @frames[pos]
|
759
|
-
sprintf "#%d %s:%s%s\n", pos + 1, file, line,
|
760
|
-
(id ? ":in `#{id.id2name}'" : "")
|
761
|
-
end
|
762
|
-
|
763
|
-
def script_lines(file, line)
|
764
|
-
unless (lines = SCRIPT_LINES__[file]) and lines != true
|
765
|
-
Tracer::Single.get_line(file, line) if File.exist?(file)
|
766
|
-
lines = SCRIPT_LINES__[file]
|
767
|
-
lines = nil if lines == true
|
768
|
-
end
|
769
|
-
lines
|
770
|
-
end
|
771
|
-
|
772
|
-
def display_list(b, e, file, line)
|
773
|
-
if lines = script_lines(file, line)
|
774
|
-
stdout.printf "[%d, %d] in %s\n", b, e, file
|
775
|
-
b.upto(e) do |n|
|
776
|
-
if n > 0 && lines[n-1]
|
777
|
-
if n == line
|
778
|
-
stdout.printf "=> %d %s\n", n, lines[n-1].chomp
|
779
|
-
else
|
780
|
-
stdout.printf " %d %s\n", n, lines[n-1].chomp
|
781
|
-
end
|
782
|
-
end
|
783
|
-
end
|
784
|
-
else
|
785
|
-
stdout.printf "No sourcefile available for %s\n", file
|
786
|
-
end
|
787
|
-
end
|
788
|
-
|
789
|
-
def line_at(file, line)
|
790
|
-
lines = script_lines(file, line)
|
791
|
-
if lines and line = lines[line-1]
|
792
|
-
return line
|
793
|
-
end
|
794
|
-
return "\n"
|
795
|
-
end
|
796
|
-
|
797
|
-
def debug_funcname(id)
|
798
|
-
if id.nil?
|
799
|
-
"toplevel"
|
800
|
-
else
|
801
|
-
id.id2name
|
802
|
-
end
|
803
|
-
end
|
804
|
-
|
805
|
-
def check_break_points(file, klass, pos, binding, id)
|
806
|
-
return false if break_points.empty?
|
807
|
-
n = 1
|
808
|
-
for b in break_points
|
809
|
-
if b[0] # valid
|
810
|
-
if b[1] == 0 # breakpoint
|
811
|
-
if (b[2] == file and b[3] == pos) or
|
812
|
-
(klass and b[2] == klass and b[3] == pos)
|
813
|
-
stdout.printf "Breakpoint %d, %s at %s:%s\n", n, debug_funcname(id), file, pos
|
814
|
-
return true
|
815
|
-
end
|
816
|
-
elsif b[1] == 1 # watchpoint
|
817
|
-
if debug_silent_eval(b[2], binding)
|
818
|
-
stdout.printf "Watchpoint %d, %s at %s:%s\n", n, debug_funcname(id), file, pos
|
819
|
-
return true
|
820
|
-
end
|
821
|
-
end
|
822
|
-
end
|
823
|
-
n += 1
|
824
|
-
end
|
825
|
-
return false
|
826
|
-
end
|
827
|
-
|
828
|
-
def excn_handle(file, line, id, binding)
|
829
|
-
if $!.class <= SystemExit
|
830
|
-
set_trace_func nil
|
831
|
-
exit
|
832
|
-
end
|
833
|
-
|
834
|
-
if @catch and ($!.class.ancestors.find { |e| e.to_s == @catch })
|
835
|
-
stdout.printf "%s:%d: `%s' (%s)\n", file, line, $!, $!.class
|
836
|
-
fs = @frames.size
|
837
|
-
tb = caller(0)[-fs..-1]
|
838
|
-
if tb
|
839
|
-
for i in tb
|
840
|
-
stdout.printf "\tfrom %s\n", i
|
841
|
-
end
|
842
|
-
end
|
843
|
-
suspend_all
|
844
|
-
debug_command(file, line, id, binding)
|
845
|
-
end
|
846
|
-
end
|
847
|
-
|
848
|
-
def trace_func(event, file, line, id, binding, klass)
|
849
|
-
Tracer.trace_func(event, file, line, id, binding, klass) if trace?
|
850
|
-
context(Thread.current).check_suspend
|
851
|
-
@file = file
|
852
|
-
@line = line
|
853
|
-
case event
|
854
|
-
when 'line'
|
855
|
-
frame_set_pos(file, line)
|
856
|
-
if !@no_step or @frames.size == @no_step
|
857
|
-
@stop_next -= 1
|
858
|
-
@stop_next = -1 if @stop_next < 0
|
859
|
-
elsif @frames.size < @no_step
|
860
|
-
@stop_next = 0 # break here before leaving...
|
861
|
-
else
|
862
|
-
# nothing to do. skipped.
|
863
|
-
end
|
864
|
-
if @stop_next == 0 or check_break_points(file, nil, line, binding, id)
|
865
|
-
@no_step = nil
|
866
|
-
suspend_all
|
867
|
-
debug_command(file, line, id, binding)
|
868
|
-
end
|
869
|
-
|
870
|
-
when 'call'
|
871
|
-
@frames.unshift [binding, file, line, id]
|
872
|
-
if check_break_points(file, klass, id.id2name, binding, id)
|
873
|
-
suspend_all
|
874
|
-
debug_command(file, line, id, binding)
|
875
|
-
end
|
876
|
-
|
877
|
-
when 'c-call'
|
878
|
-
frame_set_pos(file, line)
|
879
|
-
|
880
|
-
when 'class'
|
881
|
-
@frames.unshift [binding, file, line, id]
|
882
|
-
|
883
|
-
when 'return', 'end'
|
884
|
-
if @frames.size == @finish_pos
|
885
|
-
@stop_next = 1
|
886
|
-
@finish_pos = 0
|
887
|
-
end
|
888
|
-
@frames.shift
|
889
|
-
|
890
|
-
when 'raise'
|
891
|
-
excn_handle(file, line, id, binding)
|
892
|
-
|
893
|
-
end
|
894
|
-
@last_file = file
|
895
|
-
end
|
896
|
-
end
|
897
|
-
|
898
|
-
trap("INT") { DEBUGGER__.interrupt }
|
899
|
-
@last_thread = Thread::main
|
900
|
-
@max_thread = 1
|
901
|
-
@thread_list = {Thread::main => 1}
|
902
|
-
@break_points = []
|
903
|
-
@display = []
|
904
|
-
@waiting = []
|
905
|
-
@stdout = STDOUT
|
906
|
-
|
907
|
-
class << DEBUGGER__
|
908
|
-
# Returns the IO used as stdout. Defaults to STDOUT
|
909
|
-
def stdout
|
910
|
-
@stdout
|
911
|
-
end
|
912
|
-
|
913
|
-
# Sets the IO used as stdout. Defaults to STDOUT
|
914
|
-
def stdout=(s)
|
915
|
-
@stdout = s
|
916
|
-
end
|
917
|
-
|
918
|
-
# Returns the display expression list
|
919
|
-
#
|
920
|
-
# See DEBUGGER__ for more usage
|
921
|
-
def display
|
922
|
-
@display
|
923
|
-
end
|
924
|
-
|
925
|
-
# Returns the list of break points where execution will be stopped.
|
926
|
-
#
|
927
|
-
# See DEBUGGER__ for more usage
|
928
|
-
def break_points
|
929
|
-
@break_points
|
930
|
-
end
|
931
|
-
|
932
|
-
# Returns the list of waiting threads.
|
933
|
-
#
|
934
|
-
# When stepping through the traces of a function, thread gets suspended, to
|
935
|
-
# be resumed later.
|
936
|
-
def waiting
|
937
|
-
@waiting
|
938
|
-
end
|
939
|
-
|
940
|
-
def set_trace( arg )
|
941
|
-
MUTEX.synchronize do
|
942
|
-
make_thread_list
|
943
|
-
for th, in @thread_list
|
944
|
-
context(th).set_trace arg
|
945
|
-
end
|
946
|
-
end
|
947
|
-
arg
|
948
|
-
end
|
949
|
-
|
950
|
-
def set_last_thread(th)
|
951
|
-
@last_thread = th
|
952
|
-
end
|
953
|
-
|
954
|
-
def suspend
|
955
|
-
MUTEX.synchronize do
|
956
|
-
make_thread_list
|
957
|
-
for th, in @thread_list
|
958
|
-
next if th == Thread.current
|
959
|
-
context(th).set_suspend
|
960
|
-
end
|
961
|
-
end
|
962
|
-
# Schedule other threads to suspend as soon as possible.
|
963
|
-
Thread.pass
|
964
|
-
end
|
965
|
-
|
966
|
-
def resume
|
967
|
-
MUTEX.synchronize do
|
968
|
-
make_thread_list
|
969
|
-
@thread_list.each do |th,|
|
970
|
-
next if th == Thread.current
|
971
|
-
context(th).clear_suspend
|
972
|
-
end
|
973
|
-
waiting.each do |th|
|
974
|
-
th.run
|
975
|
-
end
|
976
|
-
waiting.clear
|
977
|
-
end
|
978
|
-
# Schedule other threads to restart as soon as possible.
|
979
|
-
Thread.pass
|
980
|
-
end
|
981
|
-
|
982
|
-
def context(thread=Thread.current)
|
983
|
-
c = thread[:__debugger_data__]
|
984
|
-
unless c
|
985
|
-
thread[:__debugger_data__] = c = Context.new
|
986
|
-
end
|
987
|
-
c
|
988
|
-
end
|
989
|
-
|
990
|
-
def interrupt
|
991
|
-
context(@last_thread).stop_next
|
992
|
-
end
|
993
|
-
|
994
|
-
def get_thread(num)
|
995
|
-
th = @thread_list.key(num)
|
996
|
-
unless th
|
997
|
-
@stdout.print "No thread ##{num}\n"
|
998
|
-
throw :debug_error
|
999
|
-
end
|
1000
|
-
th
|
1001
|
-
end
|
1002
|
-
|
1003
|
-
def thread_list(num)
|
1004
|
-
th = get_thread(num)
|
1005
|
-
if th == Thread.current
|
1006
|
-
@stdout.print "+"
|
1007
|
-
else
|
1008
|
-
@stdout.print " "
|
1009
|
-
end
|
1010
|
-
@stdout.printf "%d ", num
|
1011
|
-
@stdout.print th.inspect, "\t"
|
1012
|
-
file = context(th).instance_eval{@file}
|
1013
|
-
if file
|
1014
|
-
@stdout.print file,":",context(th).instance_eval{@line}
|
1015
|
-
end
|
1016
|
-
@stdout.print "\n"
|
1017
|
-
end
|
1018
|
-
|
1019
|
-
# Prints all threads in @thread_list to @stdout. Returns a sorted array of
|
1020
|
-
# values from the @thread_list hash.
|
1021
|
-
#
|
1022
|
-
# While in the debugger you can list all of
|
1023
|
-
# the threads with: <b>DEBUGGER__.thread_list_all</b>
|
1024
|
-
#
|
1025
|
-
# (rdb:1) DEBUGGER__.thread_list_all
|
1026
|
-
# +1 #<Thread:0x007fb2320c03f0 run> debug_me.rb.rb:3
|
1027
|
-
# 2 #<Thread:0x007fb23218a538 debug_me.rb.rb:3 sleep>
|
1028
|
-
# 3 #<Thread:0x007fb23218b0f0 debug_me.rb.rb:3 sleep>
|
1029
|
-
# [1, 2, 3]
|
1030
|
-
#
|
1031
|
-
# Your current thread is indicated by a <b>+</b>
|
1032
|
-
#
|
1033
|
-
# Additionally you can list all threads with <b>th l</b>
|
1034
|
-
#
|
1035
|
-
# (rdb:1) th l
|
1036
|
-
# +1 #<Thread:0x007f99328c0410 run> debug_me.rb:3
|
1037
|
-
# 2 #<Thread:0x007f9932938230 debug_me.rb:3 sleep> debug_me.rb:3
|
1038
|
-
# 3 #<Thread:0x007f9932938e10 debug_me.rb:3 sleep> debug_me.rb:3
|
1039
|
-
#
|
1040
|
-
# See DEBUGGER__ for more usage.
|
1041
|
-
|
1042
|
-
def thread_list_all
|
1043
|
-
for th in @thread_list.values.sort
|
1044
|
-
thread_list(th)
|
1045
|
-
end
|
1046
|
-
end
|
1047
|
-
|
1048
|
-
def make_thread_list
|
1049
|
-
hash = {}
|
1050
|
-
for th in Thread::list
|
1051
|
-
if @thread_list.key? th
|
1052
|
-
hash[th] = @thread_list[th]
|
1053
|
-
else
|
1054
|
-
@max_thread += 1
|
1055
|
-
hash[th] = @max_thread
|
1056
|
-
end
|
1057
|
-
end
|
1058
|
-
@thread_list = hash
|
1059
|
-
end
|
1060
|
-
|
1061
|
-
def debug_thread_info(input, binding)
|
1062
|
-
case input
|
1063
|
-
when /^l(?:ist)?/
|
1064
|
-
make_thread_list
|
1065
|
-
thread_list_all
|
1066
|
-
|
1067
|
-
when /^c(?:ur(?:rent)?)?$/
|
1068
|
-
make_thread_list
|
1069
|
-
thread_list(@thread_list[Thread.current])
|
1070
|
-
|
1071
|
-
when /^(?:sw(?:itch)?\s+)?(\d+)/
|
1072
|
-
make_thread_list
|
1073
|
-
th = get_thread($1.to_i)
|
1074
|
-
if th == Thread.current
|
1075
|
-
@stdout.print "It's the current thread.\n"
|
1076
|
-
else
|
1077
|
-
thread_list(@thread_list[th])
|
1078
|
-
context(th).stop_next
|
1079
|
-
th.run
|
1080
|
-
return :cont
|
1081
|
-
end
|
1082
|
-
|
1083
|
-
when /^stop\s+(\d+)/
|
1084
|
-
make_thread_list
|
1085
|
-
th = get_thread($1.to_i)
|
1086
|
-
if th == Thread.current
|
1087
|
-
@stdout.print "It's the current thread.\n"
|
1088
|
-
elsif th.stop?
|
1089
|
-
@stdout.print "Already stopped.\n"
|
1090
|
-
else
|
1091
|
-
thread_list(@thread_list[th])
|
1092
|
-
context(th).suspend
|
1093
|
-
end
|
1094
|
-
|
1095
|
-
when /^resume\s+(\d+)/
|
1096
|
-
make_thread_list
|
1097
|
-
th = get_thread($1.to_i)
|
1098
|
-
if th == Thread.current
|
1099
|
-
@stdout.print "It's the current thread.\n"
|
1100
|
-
elsif !th.stop?
|
1101
|
-
@stdout.print "Already running."
|
1102
|
-
else
|
1103
|
-
thread_list(@thread_list[th])
|
1104
|
-
th.run
|
1105
|
-
end
|
1106
|
-
end
|
1107
|
-
end
|
1108
|
-
end
|
1109
|
-
|
1110
|
-
stdout.printf "Debug.rb\n"
|
1111
|
-
stdout.printf "Emacs support available.\n\n"
|
1112
|
-
if defined?(RubyVM::InstructionSequence)
|
1113
|
-
RubyVM::InstructionSequence.compile_option = {
|
1114
|
-
trace_instruction: true
|
1115
|
-
}
|
1116
|
-
end
|
1117
|
-
set_trace_func proc { |event, file, line, id, binding, klass, *rest|
|
1118
|
-
DEBUGGER__.context.trace_func event, file, line, id, binding, klass
|
1119
|
-
}
|
10
|
+
if $0 == __FILE__
|
11
|
+
# DEBUGGER__.add_line_breakpoint __dir__ + '/target.rb', 1
|
12
|
+
# load __dir__ + '/target.rb'
|
13
|
+
else
|
14
|
+
DEBUGGER__.add_line_breakpoint $0, 1
|
1120
15
|
end
|