ruby-debug 0.1.5-mswin32

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