ruby-debug 0.1.2
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.
- data/CHANGES +4 -0
- data/LICENSE +23 -0
- data/README +63 -0
- data/Rakefile +70 -0
- data/bin/rdebug +13 -0
- data/ext/extconf.rb +18 -0
- data/ext/ruby_debug.c +922 -0
- data/lib/ruby-debug.rb +610 -0
- metadata +53 -0
data/lib/ruby-debug.rb
ADDED
@@ -0,0 +1,610 @@
|
|
1
|
+
require 'ruby_debug.so'
|
2
|
+
require 'pp'
|
3
|
+
|
4
|
+
SCRIPT_LINES__ = {} unless defined? SCRIPT_LINES__
|
5
|
+
|
6
|
+
module Debugger
|
7
|
+
class Mutex
|
8
|
+
def initialize
|
9
|
+
@locker = nil
|
10
|
+
@waiting = []
|
11
|
+
@locked = false;
|
12
|
+
end
|
13
|
+
|
14
|
+
def locked?
|
15
|
+
@locked
|
16
|
+
end
|
17
|
+
|
18
|
+
def lock
|
19
|
+
return if Thread.critical
|
20
|
+
return if @locker == Thread.current
|
21
|
+
while (Thread.critical = true; @locked)
|
22
|
+
@waiting.push Thread.current
|
23
|
+
Thread.stop
|
24
|
+
end
|
25
|
+
@locked = true
|
26
|
+
@locker = Thread.current
|
27
|
+
Thread.critical = false
|
28
|
+
self
|
29
|
+
end
|
30
|
+
|
31
|
+
def unlock
|
32
|
+
return if Thread.critical
|
33
|
+
return unless @locked
|
34
|
+
unless @locker == Thread.current
|
35
|
+
raise RuntimeError, "unlocked by other"
|
36
|
+
end
|
37
|
+
Thread.critical = true
|
38
|
+
t = @waiting.shift
|
39
|
+
@locked = false
|
40
|
+
@locker = nil
|
41
|
+
Thread.critical = false
|
42
|
+
t.run if t
|
43
|
+
self
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
MUTEX = Mutex.new
|
48
|
+
|
49
|
+
@stdout = STDOUT
|
50
|
+
@display = []
|
51
|
+
@trace_proc = nil
|
52
|
+
|
53
|
+
class Context
|
54
|
+
private
|
55
|
+
|
56
|
+
begin
|
57
|
+
require 'readline'
|
58
|
+
def readline(prompt, hist)
|
59
|
+
Readline::readline(prompt, hist)
|
60
|
+
end
|
61
|
+
rescue LoadError
|
62
|
+
def readline(prompt, hist)
|
63
|
+
STDOUT.print prompt
|
64
|
+
STDOUT.flush
|
65
|
+
line = STDIN.gets
|
66
|
+
exit unless line
|
67
|
+
line.chomp!
|
68
|
+
line
|
69
|
+
end
|
70
|
+
USE_READLINE = false
|
71
|
+
end
|
72
|
+
|
73
|
+
def stdout
|
74
|
+
Debugger.stdout
|
75
|
+
end
|
76
|
+
|
77
|
+
def at_breakpoint(breakpoint, method_name)
|
78
|
+
n = Debugger.breakpoints.index(breakpoint) + 1
|
79
|
+
stdout.printf "Breakpoint %d, %s at %s:%s\n", n, method_name, breakpoint.source, breakpoint.pos
|
80
|
+
end
|
81
|
+
|
82
|
+
def at_catchpoint
|
83
|
+
frames = Debugger.current_context.frames
|
84
|
+
stdout.printf "%s:%d: `%s' (%s)\n", frames[0].file, frames[0].line, $!, $!.class
|
85
|
+
fs = frames.size
|
86
|
+
tb = caller(0)[-fs..-1]
|
87
|
+
if tb
|
88
|
+
for i in tb
|
89
|
+
stdout.printf "\tfrom %s\n", i
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def at_tracing(file, line)
|
95
|
+
if Debugger.trace_proc
|
96
|
+
Debugger.trace_proc.call(self.thnum, file, line)
|
97
|
+
else
|
98
|
+
stdout.puts sprintf("Tracing(%d):%s:%s", self.thnum, file, line)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def debug_command(file, line, id, binding)
|
103
|
+
MUTEX.lock
|
104
|
+
frame_pos = 0
|
105
|
+
binding_file = file
|
106
|
+
binding_line = line
|
107
|
+
previous_line = nil
|
108
|
+
stdout.printf "%s:%d:%s", binding_file, binding_line, line_at(binding_file, binding_line)
|
109
|
+
display_expressions(binding)
|
110
|
+
prompt = true
|
111
|
+
while prompt and input = readline("(rdb:%d) " % Debugger.thnum, true)
|
112
|
+
catch(:debug_error) do
|
113
|
+
next if input == ''
|
114
|
+
|
115
|
+
case input
|
116
|
+
when /^\s*s(?:tep)?(?:\s+(\d+))?$/
|
117
|
+
self.stop_next = $1 ? $1.to_i : 1
|
118
|
+
prompt = false
|
119
|
+
|
120
|
+
when /^\s*c(?:ont)?$|^\s*r(?:un)?$/
|
121
|
+
prompt = false
|
122
|
+
|
123
|
+
when /^\s*v(?:ar)?\s+/
|
124
|
+
debug_variable_info($', binding)
|
125
|
+
|
126
|
+
when /^\s*w(?:here)?$/, /^\s*f(?:rame)?$/
|
127
|
+
display_frames(frame_pos)
|
128
|
+
|
129
|
+
when /^\s*l(?:ist)?(?:\s+(.+))?$/
|
130
|
+
if not $1
|
131
|
+
b = previous_line ? previous_line + 10 : binding_line - 5
|
132
|
+
e = b + 9
|
133
|
+
elsif $1 == '-'
|
134
|
+
b = previous_line ? previous_line - 10 : binding_line - 5
|
135
|
+
e = b + 9
|
136
|
+
else
|
137
|
+
b, e = $1.split(/[-,]/)
|
138
|
+
if e
|
139
|
+
b = b.to_i
|
140
|
+
e = e.to_i
|
141
|
+
else
|
142
|
+
b = b.to_i - 5
|
143
|
+
e = b + 9
|
144
|
+
end
|
145
|
+
end
|
146
|
+
previous_line = b
|
147
|
+
display_list(b, e, binding_file, binding_line)
|
148
|
+
|
149
|
+
when /^\s*n(?:ext)?(?:\s+(\d+))?$/
|
150
|
+
steps = $1 ? $1.to_i : 1
|
151
|
+
self.step_over steps, self.frames.size - frame_pos
|
152
|
+
prompt = false
|
153
|
+
|
154
|
+
when /^\s*up(?:\s+(\d+))?$/
|
155
|
+
previous_line = nil
|
156
|
+
frame_pos += $1 ? $1.to_i : 1
|
157
|
+
if frame_pos >= self.frames.size
|
158
|
+
frame_pos = self.frames.size - 1
|
159
|
+
stdout.puts "At toplevel"
|
160
|
+
end
|
161
|
+
frame = self.frames[frame_pos]
|
162
|
+
binding, binding_file, binding_line = frame.binding, frame.file, frame.line
|
163
|
+
stdout.print format_frame(frame, frame_pos)
|
164
|
+
|
165
|
+
when /^\s*down(?:\s+(\d+))?$/
|
166
|
+
previous_line = nil
|
167
|
+
frame_pos -= $1 ? $1.to_i : 1
|
168
|
+
if frame_pos < 0
|
169
|
+
frame_pos = 0
|
170
|
+
stdout.print "At stack bottom\n"
|
171
|
+
end
|
172
|
+
frame = self.frames[frame_pos]
|
173
|
+
binding, binding_file, binding_line = frame.binding, frame.file, frame.line
|
174
|
+
stdout.print format_frame(frame, frame_pos)
|
175
|
+
|
176
|
+
when /^\s*fin(?:ish)?$/
|
177
|
+
if frame_pos == self.frames.size
|
178
|
+
stdout.print "\"finish\" not meaningful in the outermost frame.\n"
|
179
|
+
else
|
180
|
+
self.stop_frame = self.frames.size - frame_pos
|
181
|
+
frame_pos = 0
|
182
|
+
prompt = false
|
183
|
+
end
|
184
|
+
|
185
|
+
when /^\s*b(?:reak)?\s+(?:(.+):)?([^.:]+)$/
|
186
|
+
pos = $2
|
187
|
+
if $1
|
188
|
+
klass = debug_silent_eval($1, binding)
|
189
|
+
file = $1
|
190
|
+
end
|
191
|
+
if pos =~ /^\d+$/
|
192
|
+
pname = pos
|
193
|
+
pos = pos.to_i
|
194
|
+
else
|
195
|
+
pname = pos = pos.intern.id2name
|
196
|
+
end
|
197
|
+
Debugger.add_breakpoint klass || file, pos
|
198
|
+
stdout.printf "Set breakpoint %d at %s:%s\n", Debugger.breakpoints.size, klass || file, pname
|
199
|
+
|
200
|
+
when /^\s*b(?:reak)?\s+(.+)[#.]([^.:]+)$/
|
201
|
+
pos = $2.intern.id2name
|
202
|
+
klass = debug_eval($1, binding)
|
203
|
+
Debugger.add_breakpoint klass, pos
|
204
|
+
stdout.printf "Set breakpoint %d at %s.%s\n", Debugger.breakpoints.size, klass, pos
|
205
|
+
|
206
|
+
when /^\s*b(?:reak)?$/
|
207
|
+
unless Debugger.breakpoints.empty?
|
208
|
+
stdout.print "Breakpoints:\n"
|
209
|
+
Debugger.breakpoints.each_with_index do |b, n|
|
210
|
+
stdout.printf " %d %s:%s\n", n+1, b.source, b.pos
|
211
|
+
end
|
212
|
+
stdout.puts
|
213
|
+
else
|
214
|
+
stdout.print "No breakpoints\n"
|
215
|
+
end
|
216
|
+
when /^\s*del(?:ete)?(?:\s+(\d+))?$/
|
217
|
+
pos = $1
|
218
|
+
unless pos
|
219
|
+
input = readline("Clear all breakpoints? (y/n) ", false)
|
220
|
+
if input == "y"
|
221
|
+
Debugger.breakpoints.clear
|
222
|
+
end
|
223
|
+
else
|
224
|
+
pos = pos.to_i
|
225
|
+
unless Debugger.breakpoints.delete_at(pos-1)
|
226
|
+
stdout.printf "Breakpoint %d is not defined\n", pos
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
when /^\s*th(?:read)?\s+/
|
231
|
+
if Debugger.debug_thread_info($') == :cont
|
232
|
+
prompt = false
|
233
|
+
end
|
234
|
+
|
235
|
+
when /^\s*m(?:ethod)?\s+/
|
236
|
+
debug_method_info($', binding)
|
237
|
+
|
238
|
+
when /^\s*pp\s+/
|
239
|
+
PP.pp(debug_eval($', binding), stdout)
|
240
|
+
|
241
|
+
when /^\s*p\s+/
|
242
|
+
stdout.printf "%s\n", debug_eval($', binding).inspect
|
243
|
+
|
244
|
+
when /^\s*h(?:elp)?$/
|
245
|
+
debug_print_help()
|
246
|
+
|
247
|
+
when /^\s*q(?:uit)?$/
|
248
|
+
input = readline("Really quit? (y/n) ", false)
|
249
|
+
if input == "y"
|
250
|
+
exit! # exit -> exit!: No graceful way to stop threads...
|
251
|
+
end
|
252
|
+
|
253
|
+
when /^\s*disp(?:lay)?\s+(.+)$/
|
254
|
+
exp = $1
|
255
|
+
display.push [true, exp]
|
256
|
+
stdout.printf "%d: ", display.size
|
257
|
+
display_expression(exp, binding)
|
258
|
+
|
259
|
+
when /^\s*disp(?:lay)?$/
|
260
|
+
display_expressions(binding)
|
261
|
+
|
262
|
+
when /^\s*undisp(?:lay)?(?:\s+(\d+))?$/
|
263
|
+
pos = $1
|
264
|
+
unless pos
|
265
|
+
input = readline("Clear all expressions? (y/n) ", false)
|
266
|
+
if input == "y"
|
267
|
+
for d in display
|
268
|
+
d[0] = false
|
269
|
+
end
|
270
|
+
end
|
271
|
+
else
|
272
|
+
pos = pos.to_i
|
273
|
+
if display[pos-1]
|
274
|
+
display[pos-1][0] = false
|
275
|
+
else
|
276
|
+
stdout.printf "Display expression %d is not defined\n", pos
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
when /^\s*cat(?:ch)?(?:\s+(.+))?$/
|
281
|
+
if $1
|
282
|
+
excn = $1
|
283
|
+
if excn == 'off'
|
284
|
+
Debugger.catchpoint = nil
|
285
|
+
stdout.print "Clear catchpoint.\n"
|
286
|
+
else
|
287
|
+
Debugger.catchpoint = excn
|
288
|
+
stdout.printf "Set catchpoint %s.\n", excn
|
289
|
+
end
|
290
|
+
else
|
291
|
+
if Debugger.catchpoint
|
292
|
+
stdout.printf "Catchpoint %s.\n", Debugger.catchpoint
|
293
|
+
else
|
294
|
+
stdout.print "No catchpoint.\n"
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
when /^\s*tr(?:ace)?(?:\s+(on|off))?(?:\s+(all))?$/
|
299
|
+
if defined?( $2 )
|
300
|
+
Debugger.tracing = $1 == 'on'
|
301
|
+
elsif defined?( $1 )
|
302
|
+
self.tracing = $1 == 'on'
|
303
|
+
end
|
304
|
+
if Debugger.tracing || self.tracing
|
305
|
+
stdout.print "Trace on.\n"
|
306
|
+
else
|
307
|
+
stdout.print "Trace off.\n"
|
308
|
+
end
|
309
|
+
|
310
|
+
else
|
311
|
+
v = debug_eval(input, binding)
|
312
|
+
stdout.printf "%s\n", v.inspect
|
313
|
+
end
|
314
|
+
end
|
315
|
+
end
|
316
|
+
MUTEX.unlock
|
317
|
+
Debugger.resume
|
318
|
+
end
|
319
|
+
|
320
|
+
def debug_print_help
|
321
|
+
stdout.print <<EOHELP
|
322
|
+
Debugger help v.-0.002b
|
323
|
+
Commands
|
324
|
+
b[reak] [file|class:]<line|method>
|
325
|
+
b[reak] [class.]<line|method>
|
326
|
+
set breakpoint to some position
|
327
|
+
cat[ch] <an Exception> set catchpoint to an exception
|
328
|
+
disp[lay] <expression> add expression into display expression list
|
329
|
+
undisp[lay][ nnn] delete one particular or all display expressions
|
330
|
+
b[reak] list breakpoints
|
331
|
+
cat[ch] show catchpoint
|
332
|
+
del[ete][ nnn] delete some or all breakpoints
|
333
|
+
c[ont] run until program ends or hit breakpoint
|
334
|
+
s[tep][ nnn] step (into methods) one line or till line nnn
|
335
|
+
n[ext][ nnn] go over one line or till line nnn
|
336
|
+
w[here] display frames
|
337
|
+
f[rame] alias for where
|
338
|
+
l[ist][ (-|nn-mm)] list program, - lists backwards
|
339
|
+
nn-mm lists given lines
|
340
|
+
up[ nn] move to higher frame
|
341
|
+
down[ nn] move to lower frame
|
342
|
+
fin[ish] return to outer frame
|
343
|
+
q[uit] exit from debugger
|
344
|
+
v[ar] g[lobal] show global variables
|
345
|
+
v[ar] l[ocal] show local variables
|
346
|
+
v[ar] i[nstance] <object> show instance variables of object
|
347
|
+
v[ar] c[onst] <object> show constants of object
|
348
|
+
m[ethod] i[nstance] <obj> show methods of object
|
349
|
+
m[ethod] <class|module> show instance methods of class or module
|
350
|
+
th[read] l[ist] list all threads
|
351
|
+
th[read] c[ur[rent]] show current thread
|
352
|
+
th[read] [sw[itch]] <nnn> switch thread context to nnn
|
353
|
+
th[read] stop <nnn> stop thread nnn
|
354
|
+
th[read] resume <nnn> resume thread nnn
|
355
|
+
p expression evaluate expression and print its value
|
356
|
+
pp expression evaluate expression and print its value
|
357
|
+
h[elp] print this help
|
358
|
+
<everything else> evaluate
|
359
|
+
EOHELP
|
360
|
+
end
|
361
|
+
|
362
|
+
def display_expressions(binding)
|
363
|
+
n = 1
|
364
|
+
for d in display
|
365
|
+
if d[0]
|
366
|
+
stdout.printf "%d: ", n
|
367
|
+
display_expression(d[1], binding)
|
368
|
+
end
|
369
|
+
n += 1
|
370
|
+
end
|
371
|
+
end
|
372
|
+
|
373
|
+
def display_expression(exp, binding)
|
374
|
+
stdout.printf "%s = %s\n", exp, debug_silent_eval(exp, binding).to_s
|
375
|
+
end
|
376
|
+
|
377
|
+
def debug_eval(str, binding)
|
378
|
+
begin
|
379
|
+
val = eval(str, binding)
|
380
|
+
rescue StandardError, ScriptError => e
|
381
|
+
at = eval("caller(1)", binding)
|
382
|
+
stdout.printf "%s:%s\n", at.shift, e.to_s.sub(/\(eval\):1:(in `.*?':)?/, '')
|
383
|
+
for i in at
|
384
|
+
stdout.printf "\tfrom %s\n", i
|
385
|
+
end
|
386
|
+
throw :debug_error
|
387
|
+
end
|
388
|
+
end
|
389
|
+
|
390
|
+
def debug_silent_eval(str, binding)
|
391
|
+
begin
|
392
|
+
eval(str, binding)
|
393
|
+
rescue StandardError, ScriptError
|
394
|
+
nil
|
395
|
+
end
|
396
|
+
end
|
397
|
+
|
398
|
+
def debug_variable_info(input, binding)
|
399
|
+
case input
|
400
|
+
when /^\s*g(?:lobal)?\s*$/
|
401
|
+
var_list(global_variables, binding)
|
402
|
+
|
403
|
+
when /^\s*l(?:ocal)?\s*$/
|
404
|
+
var_list(eval("local_variables", binding), binding)
|
405
|
+
|
406
|
+
when /^\s*i(?:nstance)?\s+/
|
407
|
+
obj = debug_eval($', binding)
|
408
|
+
var_list(obj.instance_variables, obj.instance_eval{binding()})
|
409
|
+
|
410
|
+
when /^\s*c(?:onst(?:ant)?)?\s+/
|
411
|
+
obj = debug_eval($', binding)
|
412
|
+
unless obj.kind_of? Module
|
413
|
+
stdout.print "Should be Class/Module: ", $', "\n"
|
414
|
+
else
|
415
|
+
var_list(obj.constants, obj.module_eval{binding()})
|
416
|
+
end
|
417
|
+
end
|
418
|
+
end
|
419
|
+
|
420
|
+
def display_frames(pos)
|
421
|
+
self.frames.each_with_index do |frame, idx|
|
422
|
+
if idx == pos
|
423
|
+
stdout.print "--> "
|
424
|
+
else
|
425
|
+
stdout.print " "
|
426
|
+
end
|
427
|
+
stdout.print format_frame(frame, idx)
|
428
|
+
end
|
429
|
+
end
|
430
|
+
|
431
|
+
def format_frame(frame, pos)
|
432
|
+
bind, file, line, id = frame.binding, frame.file, frame.line, frame.id
|
433
|
+
sprintf "#%d %s:%s%s\n", pos + 1, file, line,
|
434
|
+
(id ? ":in `#{id.id2name}'" : "")
|
435
|
+
end
|
436
|
+
|
437
|
+
def var_list(ary, binding)
|
438
|
+
ary.sort!
|
439
|
+
for v in ary
|
440
|
+
stdout.printf " %s => %s\n", v, eval(v, binding).inspect
|
441
|
+
end
|
442
|
+
end
|
443
|
+
|
444
|
+
def display_list(b, e, file, line)
|
445
|
+
stdout.printf "[%d, %d] in %s\n", b, e, file
|
446
|
+
if lines = SCRIPT_LINES__[file] and lines != true
|
447
|
+
n = 0
|
448
|
+
b.upto(e) do |n|
|
449
|
+
if n > 0 && lines[n-1]
|
450
|
+
if n == line
|
451
|
+
stdout.printf "=> %d %s\n", n, lines[n-1].chomp
|
452
|
+
else
|
453
|
+
stdout.printf " %d %s\n", n, lines[n-1].chomp
|
454
|
+
end
|
455
|
+
end
|
456
|
+
end
|
457
|
+
else
|
458
|
+
stdout.printf "No sourcefile available for %s\n", file
|
459
|
+
end
|
460
|
+
end
|
461
|
+
|
462
|
+
def line_at(file, line)
|
463
|
+
lines = SCRIPT_LINES__[file]
|
464
|
+
if lines
|
465
|
+
return "\n" if lines == true
|
466
|
+
line = lines[line-1]
|
467
|
+
return "\n" unless line
|
468
|
+
return line
|
469
|
+
end
|
470
|
+
return "\n"
|
471
|
+
end
|
472
|
+
|
473
|
+
def display
|
474
|
+
Debugger.display
|
475
|
+
end
|
476
|
+
end
|
477
|
+
|
478
|
+
class << self
|
479
|
+
def stdout
|
480
|
+
@stdout
|
481
|
+
end
|
482
|
+
|
483
|
+
def stdout=(v)
|
484
|
+
@stdout = v
|
485
|
+
end
|
486
|
+
|
487
|
+
def set_trace_proc &block
|
488
|
+
@trace_proc = block
|
489
|
+
end
|
490
|
+
|
491
|
+
def trace_proc
|
492
|
+
@trace_proc
|
493
|
+
end
|
494
|
+
|
495
|
+
def display
|
496
|
+
@display
|
497
|
+
end
|
498
|
+
|
499
|
+
def debug_method_info(input, binding)
|
500
|
+
case input
|
501
|
+
when /^i(:?nstance)?\s+/
|
502
|
+
obj = debug_eval($', binding)
|
503
|
+
|
504
|
+
len = 0
|
505
|
+
for v in obj.methods.sort
|
506
|
+
len += v.size + 1
|
507
|
+
if len > 70
|
508
|
+
len = v.size + 1
|
509
|
+
stdout.print "\n"
|
510
|
+
end
|
511
|
+
stdout.print v, " "
|
512
|
+
end
|
513
|
+
stdout.print "\n"
|
514
|
+
|
515
|
+
else
|
516
|
+
obj = debug_eval(input, binding)
|
517
|
+
unless obj.kind_of? Module
|
518
|
+
stdout.print "Should be Class/Module: ", input, "\n"
|
519
|
+
else
|
520
|
+
len = 0
|
521
|
+
for v in obj.instance_methods(false).sort
|
522
|
+
len += v.size + 1
|
523
|
+
if len > 70
|
524
|
+
len = v.size + 1
|
525
|
+
stdout.print "\n"
|
526
|
+
end
|
527
|
+
stdout.print v, " "
|
528
|
+
end
|
529
|
+
stdout.print "\n"
|
530
|
+
end
|
531
|
+
end
|
532
|
+
end
|
533
|
+
|
534
|
+
def display_context(c)
|
535
|
+
if c.thread == Thread.current
|
536
|
+
stdout.print "+"
|
537
|
+
else
|
538
|
+
stdout.print " "
|
539
|
+
end
|
540
|
+
stdout.printf "%d ", c.thnum
|
541
|
+
stdout.print c.thread.inspect, "\t"
|
542
|
+
last_frame = c.frames.first
|
543
|
+
if last_frame
|
544
|
+
@stdout.print last_frame.file,":",last_frame.line
|
545
|
+
end
|
546
|
+
@stdout.print "\n"
|
547
|
+
end
|
548
|
+
|
549
|
+
def display_all_contexts
|
550
|
+
threads = contexts.sort_by{|c| c.thnum}.each do |c|
|
551
|
+
display_context(c)
|
552
|
+
end
|
553
|
+
end
|
554
|
+
|
555
|
+
def get_context(thnum)
|
556
|
+
contexts.find{|c| c.thnum = thnum}
|
557
|
+
end
|
558
|
+
|
559
|
+
def debug_thread_info(input)
|
560
|
+
case input
|
561
|
+
when /^l(?:ist)?/
|
562
|
+
display_all_contexts
|
563
|
+
|
564
|
+
when /^c(?:ur(?:rent)?)?$/
|
565
|
+
display_context(current_context)
|
566
|
+
|
567
|
+
when /^(?:sw(?:itch)?\s+)?(\d+)/
|
568
|
+
c = get_context($1.to_i)
|
569
|
+
if c == current_context
|
570
|
+
stdout.print "It's the current thread.\n"
|
571
|
+
else
|
572
|
+
display_context(c)
|
573
|
+
c.stop_next = 1
|
574
|
+
c.thread.run
|
575
|
+
return :cont
|
576
|
+
end
|
577
|
+
|
578
|
+
when /^stop\s+(\d+)/
|
579
|
+
c = get_context($1.to_i)
|
580
|
+
if c == current_context
|
581
|
+
stdout.print "It's the current thread.\n"
|
582
|
+
elsif c.thread.stop?
|
583
|
+
stdout.print "Already stopped.\n"
|
584
|
+
else
|
585
|
+
display_context(c)
|
586
|
+
c.set_suspend
|
587
|
+
end
|
588
|
+
|
589
|
+
when /^resume\s+(\d+)/
|
590
|
+
c = get_context($1.to_i)
|
591
|
+
if c == current_context
|
592
|
+
stdout.print "It's the current thread.\n"
|
593
|
+
elsif !c.thread.stop?
|
594
|
+
stdout.print "Already running."
|
595
|
+
else
|
596
|
+
display_context(c)
|
597
|
+
c.thread.run
|
598
|
+
end
|
599
|
+
end
|
600
|
+
end
|
601
|
+
end
|
602
|
+
end
|
603
|
+
|
604
|
+
module Kernel
|
605
|
+
def debugger(steps = 1)
|
606
|
+
Debugger.current_context.stop_next = steps
|
607
|
+
end
|
608
|
+
end
|
609
|
+
|
610
|
+
Debugger.start
|
metadata
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.9.0
|
3
|
+
specification_version: 1
|
4
|
+
name: ruby-debug
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 0.1.2
|
7
|
+
date: 2006-07-10 16:26:42 -04:00
|
8
|
+
summary: Fast Ruby debugger
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email: ksibilev@yahoo.com
|
12
|
+
homepage: http://rubyforge.org/projects/ruby-debug/
|
13
|
+
rubyforge_project: ruby-debug
|
14
|
+
description: ruby-debug is a fast implementation of the standard Ruby debugger debug.rb. It's implemented by utilizing a new hook Ruby C API.
|
15
|
+
autorequire: ruby-debug
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: false
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 1.8.2
|
24
|
+
version:
|
25
|
+
platform: ruby
|
26
|
+
signing_key:
|
27
|
+
cert_chain:
|
28
|
+
post_install_message:
|
29
|
+
authors:
|
30
|
+
- Kent Sibilev
|
31
|
+
files:
|
32
|
+
- Rakefile
|
33
|
+
- README
|
34
|
+
- LICENSE
|
35
|
+
- CHANGES
|
36
|
+
- lib/ruby-debug.rb
|
37
|
+
- ext/extconf.rb
|
38
|
+
- ext/ruby_debug.c
|
39
|
+
- bin/rdebug
|
40
|
+
test_files: []
|
41
|
+
|
42
|
+
rdoc_options: []
|
43
|
+
|
44
|
+
extra_rdoc_files: []
|
45
|
+
|
46
|
+
executables:
|
47
|
+
- rdebug
|
48
|
+
extensions:
|
49
|
+
- ext/extconf.rb
|
50
|
+
requirements: []
|
51
|
+
|
52
|
+
dependencies: []
|
53
|
+
|