arcadia 0.1.0

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.
@@ -0,0 +1,998 @@
1
+ # Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
2
+ # Copyright (C) 2000 Information-technology Promotion Agency, Japan
3
+ # Copyright (C) 2000-2003 NAKAMURA, Hiroshi <nahi@ruby-lang.org>
4
+ if $SAFE > 0
5
+ STDERR.print "-r debug.rb is not available in safe mode\n"
6
+ exit 1
7
+ end
8
+
9
+ require 'tracer'
10
+ require 'pp'
11
+
12
+ class Tracer
13
+ def Tracer.trace_func(*vars)
14
+ Single.trace_func(*vars)
15
+ end
16
+ end
17
+
18
+ SCRIPT_LINES__ = {} unless defined? SCRIPT_LINES__
19
+
20
+ class DEBUGGER__
21
+ class Mutex
22
+ def initialize
23
+ @locker = nil
24
+ @waiting = []
25
+ @locked = false;
26
+ end
27
+
28
+ def locked?
29
+ @locked
30
+ end
31
+
32
+ def lock
33
+ return if Thread.critical
34
+ return if @locker == Thread.current
35
+ while (Thread.critical = true; @locked)
36
+ @waiting.push Thread.current
37
+ Thread.stop
38
+ end
39
+ @locked = true
40
+ @locker = Thread.current
41
+ Thread.critical = false
42
+ self
43
+ end
44
+
45
+ def unlock
46
+ return if Thread.critical
47
+ return unless @locked
48
+ unless @locker == Thread.current
49
+ raise RuntimeError, "unlocked by other"
50
+ end
51
+ Thread.critical = true
52
+ t = @waiting.shift
53
+ @locked = false
54
+ @locker = nil
55
+ Thread.critical = false
56
+ t.run if t
57
+ self
58
+ end
59
+ end
60
+ MUTEX = Mutex.new
61
+
62
+ class Context
63
+ DEBUG_LAST_CMD = []
64
+ p 'Context'
65
+ begin
66
+ require 'readline'
67
+ def readline(prompt, hist)
68
+ Readline::readline(prompt, hist)
69
+ end
70
+ rescue LoadError
71
+ def readline(prompt, hist)
72
+ STDOUT.print prompt
73
+ STDOUT.flush
74
+ line = STDIN.gets
75
+ exit unless line
76
+ line.chomp!
77
+ line
78
+ end
79
+ USE_READLINE = false
80
+ end
81
+
82
+ def initialize
83
+ arcadia_initdbg
84
+
85
+ if Thread.current == Thread.main
86
+ @stop_next = 1
87
+ else
88
+ @stop_next = 0
89
+ end
90
+ @last_file = nil
91
+ @file = nil
92
+ @line = nil
93
+ @no_step = nil
94
+ @frames = []
95
+ @finish_pos = 0
96
+ @trace = false
97
+ @catch = "StandardError"
98
+ @suspend_next = false
99
+ end
100
+
101
+ def stop_next(n=1)
102
+ @stop_next = n
103
+ end
104
+
105
+ def set_suspend
106
+ @suspend_next = true
107
+ end
108
+
109
+ def clear_suspend
110
+ @suspend_next = false
111
+ end
112
+
113
+ def suspend_all
114
+ DEBUGGER__.suspend
115
+ end
116
+
117
+ def resume_all
118
+ DEBUGGER__.resume
119
+ end
120
+
121
+ def check_suspend
122
+ return if Thread.critical
123
+ while (Thread.critical = true; @suspend_next)
124
+ DEBUGGER__.waiting.push Thread.current
125
+ @suspend_next = false
126
+ Thread.stop
127
+ end
128
+ Thread.critical = false
129
+ end
130
+
131
+ def trace?
132
+ @trace
133
+ end
134
+
135
+ def set_trace(arg)
136
+ @trace = arg
137
+ end
138
+
139
+ def stdout
140
+ DEBUGGER__.stdout
141
+ end
142
+
143
+ def break_points
144
+ DEBUGGER__.break_points
145
+ end
146
+
147
+ def display
148
+ DEBUGGER__.display
149
+ end
150
+
151
+ def context(th)
152
+ DEBUGGER__.context(th)
153
+ end
154
+
155
+ def set_trace_all(arg)
156
+ DEBUGGER__.set_trace(arg)
157
+ end
158
+
159
+ def set_last_thread(th)
160
+ DEBUGGER__.set_last_thread(th)
161
+ end
162
+
163
+ def debug_eval(str, binding)
164
+ begin
165
+ val = eval(str, binding)
166
+ rescue StandardError, ScriptError => e
167
+ at = eval("caller(1)", binding)
168
+ stdout.printf "%s:%s\n", at.shift, e.to_s.sub(/\(eval\):1:(in `.*?':)?/, '')
169
+ for i in at
170
+ stdout.printf "\tfrom %s\n", i
171
+ end
172
+ throw :debug_error
173
+ end
174
+ end
175
+
176
+ def debug_silent_eval(str, binding)
177
+ begin
178
+ eval(str, binding)
179
+ rescue StandardError, ScriptError
180
+ nil
181
+ end
182
+ end
183
+
184
+ def var_list(ary, binding)
185
+ ary.sort!
186
+ @arcadia_dbg[:variables]=Hash.new
187
+ for v in ary
188
+ val = eval(v, binding).inspect
189
+ @arcadia_dbg[:variables][v]=val
190
+ stdout.printf " %s => %s\n", v, val
191
+ end
192
+ arcadia_transfer
193
+
194
+ end
195
+
196
+ def debug_variable_info(input, binding)
197
+ case input
198
+ when /^\s*g(?:lobal)?\s*$/
199
+ var_list(global_variables, binding)
200
+
201
+ when /^\s*l(?:ocal)?\s*$/
202
+ var_list(eval("local_variables", binding), binding)
203
+
204
+ when /^\s*i(?:nstance)?\s+/
205
+ obj = debug_eval($', binding)
206
+ var_list(obj.instance_variables, obj.instance_eval{binding()})
207
+
208
+ when /^\s*c(?:onst(?:ant)?)?\s+/
209
+ obj = debug_eval($', binding)
210
+ unless obj.kind_of? Module
211
+ stdout.print "Should be Class/Module: ", $', "\n"
212
+ else
213
+ var_list(obj.constants, obj.module_eval{binding()})
214
+ end
215
+ end
216
+ end
217
+
218
+ def debug_method_info(input, binding)
219
+ case input
220
+ when /^i(:?nstance)?\s+/
221
+ obj = debug_eval($', binding)
222
+
223
+ len = 0
224
+ for v in obj.methods.sort
225
+ len += v.size + 1
226
+ if len > 70
227
+ len = v.size + 1
228
+ stdout.print "\n"
229
+ end
230
+ stdout.print v, " "
231
+ end
232
+ stdout.print "\n"
233
+
234
+ else
235
+ obj = debug_eval(input, binding)
236
+ unless obj.kind_of? Module
237
+ stdout.print "Should be Class/Module: ", input, "\n"
238
+ else
239
+ len = 0
240
+ for v in obj.instance_methods(false).sort
241
+ len += v.size + 1
242
+ if len > 70
243
+ len = v.size + 1
244
+ stdout.print "\n"
245
+ end
246
+ stdout.print v, " "
247
+ end
248
+ stdout.print "\n"
249
+ end
250
+ end
251
+ end
252
+
253
+ def thnum
254
+ num = DEBUGGER__.instance_eval{@thread_list[Thread.current]}
255
+ unless num
256
+ DEBUGGER__.make_thread_list
257
+ num = DEBUGGER__.instance_eval{@thread_list[Thread.current]}
258
+ end
259
+ num
260
+ end
261
+
262
+ def debug_command(file, line, id, binding)
263
+ MUTEX.lock
264
+ unless defined?($debugger_restart) and $debugger_restart
265
+ callcc{|c| $debugger_restart = c}
266
+ end
267
+ set_last_thread(Thread.current)
268
+ frame_pos = 0
269
+ binding_file = file
270
+ binding_line = line
271
+ previous_line = nil
272
+ if ENV['EMACS']
273
+ stdout.printf "\032\032%s:%d:\n", binding_file, binding_line
274
+ else
275
+ stdout.printf "%s:%d:%s", binding_file, binding_line,
276
+ arcadia_line_at_to_file(file, line)
277
+ line_at(binding_file, binding_line)
278
+ end
279
+ @frames[0] = [binding, file, line, id]
280
+ display_expressions(binding)
281
+ arcadia_transfer
282
+ prompt = true
283
+ while prompt and input = readline("(rdb:%d) "%thnum(), true)
284
+ catch(:debug_error) do
285
+ if input == ""
286
+ next unless DEBUG_LAST_CMD[0]
287
+ input = DEBUG_LAST_CMD[0]
288
+ stdout.print input, "\n"
289
+ else
290
+ DEBUG_LAST_CMD[0] = input
291
+ end
292
+
293
+ case input
294
+ when /^\s*tr(?:ace)?(?:\s+(on|off))?(?:\s+(all))?$/
295
+ if defined?( $2 )
296
+ if $1 == 'on'
297
+ set_trace_all true
298
+ else
299
+ set_trace_all false
300
+ end
301
+ elsif defined?( $1 )
302
+ if $1 == 'on'
303
+ set_trace true
304
+ else
305
+ set_trace false
306
+ end
307
+ end
308
+ if trace?
309
+ stdout.print "Trace on.\n"
310
+ else
311
+ stdout.print "Trace off.\n"
312
+ end
313
+
314
+ when /^\s*b(?:reak)?\s+(?:(.+):)?([^.:]+)$/
315
+ pos = $2
316
+ if $1
317
+ klass = debug_silent_eval($1, binding)
318
+ file = $1
319
+ end
320
+ if pos =~ /^\d+$/
321
+ pname = pos
322
+ pos = pos.to_i
323
+ else
324
+ pname = pos = pos.intern.id2name
325
+ end
326
+ break_points.push [true, 0, klass || file, pos]
327
+ stdout.printf "Set breakpoint %d at %s:%s\n", break_points.size, klass || file, pname
328
+ arcadia_transfer
329
+ when /^\s*b(?:reak)?\s+(.+)[#.]([^.:]+)$/
330
+ pos = $2.intern.id2name
331
+ klass = debug_eval($1, binding)
332
+ break_points.push [true, 0, klass, pos]
333
+ stdout.printf "Set breakpoint %d at %s.%s\n", break_points.size, klass, pos
334
+
335
+ when /^\s*wat(?:ch)?\s+(.+)$/
336
+ exp = $1
337
+ break_points.push [true, 1, exp]
338
+ stdout.printf "Set watchpoint %d:%s\n", break_points.size, exp
339
+
340
+ when /^\s*b(?:reak)?$/
341
+ if break_points.find{|b| b[1] == 0}
342
+ n = 1
343
+ stdout.print "Breakpoints:\n"
344
+ for b in break_points
345
+ if b[0] and b[1] == 0
346
+ stdout.printf " %d %s:%s\n", n, b[2], b[3]
347
+ end
348
+ n += 1
349
+ end
350
+ end
351
+ if break_points.find{|b| b[1] == 1}
352
+ n = 1
353
+ stdout.print "\n"
354
+ stdout.print "Watchpoints:\n"
355
+ for b in break_points
356
+ if b[0] and b[1] == 1
357
+ stdout.printf " %d %s\n", n, b[2]
358
+ end
359
+ n += 1
360
+ end
361
+ end
362
+ if break_points.size == 0
363
+ stdout.print "No breakpoints\n"
364
+ else
365
+ stdout.print "\n"
366
+ end
367
+
368
+ when /^\s*del(?:ete)?(?:\s+(\d+))?$/
369
+ pos = $1
370
+ unless pos
371
+ input = readline("Clear all breakpoints? (y/n) ", false)
372
+ if input == "y"
373
+ for b in break_points
374
+ b[0] = false
375
+ end
376
+ end
377
+ else
378
+ pos = pos.to_i
379
+ if break_points[pos-1]
380
+ break_points[pos-1][0] = false
381
+ else
382
+ stdout.printf "Breakpoint %d is not defined\n", pos
383
+ end
384
+ end
385
+
386
+ when /^\s*disp(?:lay)?\s+(.+)$/
387
+ exp = $1
388
+ display.push [true, exp]
389
+ stdout.printf "%d: ", display.size
390
+ display_expression(exp, binding)
391
+
392
+ when /^\s*disp(?:lay)?$/
393
+ display_expressions(binding)
394
+
395
+ when /^\s*undisp(?:lay)?(?:\s+(\d+))?$/
396
+ pos = $1
397
+ unless pos
398
+ input = readline("Clear all expressions? (y/n) ", false)
399
+ if input == "y"
400
+ for d in display
401
+ d[0] = false
402
+ end
403
+ end
404
+ else
405
+ pos = pos.to_i
406
+ if display[pos-1]
407
+ display[pos-1][0] = false
408
+ else
409
+ stdout.printf "Display expression %d is not defined\n", pos
410
+ end
411
+ end
412
+
413
+ when /^\s*c(?:ont)?$/
414
+ prompt = false
415
+
416
+ when /^\s*s(?:tep)?(?:\s+(\d+))?$/
417
+ if $1
418
+ lev = $1.to_i
419
+ else
420
+ lev = 1
421
+ end
422
+ @stop_next = lev
423
+ prompt = false
424
+
425
+ when /^\s*n(?:ext)?(?:\s+(\d+))?$/
426
+ if $1
427
+ lev = $1.to_i
428
+ else
429
+ lev = 1
430
+ end
431
+ @stop_next = lev
432
+ @no_step = @frames.size - frame_pos
433
+ prompt = false
434
+
435
+ when /^\s*w(?:here)?$/, /^\s*f(?:rame)?$/
436
+ display_frames(frame_pos)
437
+
438
+ when /^\s*l(?:ist)?(?:\s+(.+))?$/
439
+ if not $1
440
+ b = previous_line ? previous_line + 10 : binding_line - 5
441
+ e = b + 9
442
+ elsif $1 == '-'
443
+ b = previous_line ? previous_line - 10 : binding_line - 5
444
+ e = b + 9
445
+ else
446
+ b, e = $1.split(/[-,]/)
447
+ if e
448
+ b = b.to_i
449
+ e = e.to_i
450
+ else
451
+ b = b.to_i - 5
452
+ e = b + 9
453
+ end
454
+ end
455
+ previous_line = b
456
+ display_list(b, e, binding_file, binding_line)
457
+
458
+ when /^\s*up(?:\s+(\d+))?$/
459
+ previous_line = nil
460
+ if $1
461
+ lev = $1.to_i
462
+ else
463
+ lev = 1
464
+ end
465
+ frame_pos += lev
466
+ if frame_pos >= @frames.size
467
+ frame_pos = @frames.size - 1
468
+ stdout.print "At toplevel\n"
469
+ end
470
+ binding, binding_file, binding_line = @frames[frame_pos]
471
+ stdout.print format_frame(frame_pos)
472
+
473
+ when /^\s*down(?:\s+(\d+))?$/
474
+ previous_line = nil
475
+ if $1
476
+ lev = $1.to_i
477
+ else
478
+ lev = 1
479
+ end
480
+ frame_pos -= lev
481
+ if frame_pos < 0
482
+ frame_pos = 0
483
+ stdout.print "At stack bottom\n"
484
+ end
485
+ binding, binding_file, binding_line = @frames[frame_pos]
486
+ stdout.print format_frame(frame_pos)
487
+
488
+ when /^\s*fin(?:ish)?$/
489
+ if frame_pos == @frames.size
490
+ stdout.print "\"finish\" not meaningful in the outermost frame.\n"
491
+ else
492
+ @finish_pos = @frames.size - frame_pos
493
+ frame_pos = 0
494
+ prompt = false
495
+ end
496
+
497
+ when /^\s*cat(?:ch)?(?:\s+(.+))?$/
498
+ if $1
499
+ excn = $1
500
+ if excn == 'off'
501
+ @catch = nil
502
+ stdout.print "Clear catchpoint.\n"
503
+ else
504
+ @catch = excn
505
+ stdout.printf "Set catchpoint %s.\n", @catch
506
+ end
507
+ else
508
+ if @catch
509
+ stdout.printf "Catchpoint %s.\n", @catch
510
+ else
511
+ stdout.print "No catchpoint.\n"
512
+ end
513
+ end
514
+
515
+ when /^\s*q(?:uit)?$/
516
+ input = readline("Really quit? (y/n) ", false)
517
+ if input == "y"
518
+ exit! # exit -> exit!: No graceful way to stop threads...
519
+ end
520
+
521
+ when /^\s*v(?:ar)?\s+/
522
+ debug_variable_info($', binding)
523
+
524
+ when /^\s*m(?:ethod)?\s+/
525
+ debug_method_info($', binding)
526
+
527
+ when /^\s*th(?:read)?\s+/
528
+ if DEBUGGER__.debug_thread_info($', binding) == :cont
529
+ prompt = false
530
+ end
531
+
532
+ when /^\s*pp\s+/
533
+ PP.pp(debug_eval($', binding), stdout)
534
+
535
+ when /^\s*p\s+/
536
+ stdout.printf "%s\n", debug_eval($', binding).inspect
537
+
538
+ when /^\s*r(?:estart)?$/
539
+ $debugger_restart.call
540
+
541
+ when /^\s*h(?:elp)?$/
542
+ debug_print_help()
543
+
544
+ else
545
+ v = debug_eval(input, binding)
546
+ stdout.printf "%s\n", v.inspect
547
+ end
548
+ end
549
+ end
550
+ MUTEX.unlock
551
+ resume_all
552
+ end
553
+
554
+ def debug_print_help
555
+ stdout.print <<EOHELP
556
+ Debugger help v.-0.002b
557
+ Commands
558
+ b[reak] [file:|class:]<line|method>
559
+ b[reak] [class.]<line|method>
560
+ set breakpoint to some position
561
+ wat[ch] <expression> set watchpoint to some expression
562
+ cat[ch] <an Exception> set catchpoint to an exception
563
+ b[reak] list breakpoints
564
+ cat[ch] show catchpoint
565
+ del[ete][ nnn] delete some or all breakpoints
566
+ disp[lay] <expression> add expression into display expression list
567
+ undisp[lay][ nnn] delete one particular or all display expressions
568
+ c[ont] run until program ends or hit breakpoint
569
+ s[tep][ nnn] step (into methods) one line or till line nnn
570
+ n[ext][ nnn] go over one line or till line nnn
571
+ w[here] display frames
572
+ f[rame] alias for where
573
+ l[ist][ (-|nn-mm)] list program, - lists backwards
574
+ nn-mm lists given lines
575
+ up[ nn] move to higher frame
576
+ down[ nn] move to lower frame
577
+ fin[ish] return to outer frame
578
+ tr[ace] (on|off) set trace mode of current thread
579
+ tr[ace] (on|off) all set trace mode of all threads
580
+ q[uit] exit from debugger
581
+ v[ar] g[lobal] show global variables
582
+ v[ar] l[ocal] show local variables
583
+ v[ar] i[nstance] <object> show instance variables of object
584
+ v[ar] c[onst] <object> show constants of object
585
+ m[ethod] i[nstance] <obj> show methods of object
586
+ m[ethod] <class|module> show instance methods of class or module
587
+ th[read] l[ist] list all threads
588
+ th[read] c[ur[rent]] show current thread
589
+ th[read] [sw[itch]] <nnn> switch thread context to nnn
590
+ th[read] stop <nnn> stop thread nnn
591
+ th[read] resume <nnn> resume thread nnn
592
+ p expression evaluate expression and print its value
593
+ h[elp] print this help
594
+ <everything else> evaluate
595
+ EOHELP
596
+ end
597
+
598
+ def display_expressions(binding)
599
+ n = 1
600
+ for d in display
601
+ if d[0]
602
+ stdout.printf "%d: ", n
603
+ display_expression(d[1], binding)
604
+ end
605
+ n += 1
606
+ end
607
+ end
608
+
609
+ def display_expression(exp, binding)
610
+ stdout.printf "%s = %s\n", exp, debug_silent_eval(exp, binding).to_s
611
+ end
612
+
613
+ def frame_set_pos(file, line)
614
+ if @frames[0]
615
+ @frames[0][1] = file
616
+ @frames[0][2] = line
617
+ end
618
+ end
619
+
620
+ def display_frames(pos)
621
+ 0.upto(@frames.size - 1) do |n|
622
+ if n == pos
623
+ stdout.print "--> "
624
+ else
625
+ stdout.print " "
626
+ end
627
+ stdout.print format_frame(n)
628
+ end
629
+ end
630
+
631
+ def format_frame(pos)
632
+ bind, file, line, id = @frames[pos]
633
+ sprintf "#%d %s:%s%s\n", pos + 1, file, line,
634
+ (id ? ":in `#{id.id2name}'" : "")
635
+ end
636
+
637
+ def display_list(b, e, file, line)
638
+ stdout.printf "[%d, %d] in %s\n", b, e, file
639
+ if lines = SCRIPT_LINES__[file] and lines != true
640
+ n = 0
641
+ b.upto(e) do |n|
642
+ if n > 0 && lines[n-1]
643
+ if n == line
644
+ stdout.printf "=> %d %s\n", n, lines[n-1].chomp
645
+ else
646
+ stdout.printf " %d %s\n", n, lines[n-1].chomp
647
+ end
648
+ end
649
+ end
650
+ else
651
+ stdout.printf "No sourcefile available for %s\n", file
652
+ end
653
+ end
654
+
655
+
656
+ def arcadia_initdbg
657
+ @arcadia_dbg = {
658
+ :file => nil,
659
+ :line => nil,
660
+ :error_text=> nil,
661
+ :error_class=> nil,
662
+ :callers=> nil,
663
+ :variables=>nil
664
+ }
665
+ end
666
+ def arcadia_transfer
667
+ begin
668
+ #p "arcadia_transfer \n"
669
+ #@transfer_file = ArcadiaDebugWrapper.transfer_file
670
+ @transfer_file = '~transfer-debug-file.tmp'
671
+ #p 'transfer_file= '+@transfer_file
672
+ while File.exist?(@transfer_file) && !File.stat(@transfer_file).writable?
673
+ end
674
+ if File.exist?(@transfer_file)
675
+ #File.new(@transfer_file, "w").close
676
+ File.delete(@transfer_file)
677
+ end
678
+ File.open('~'+@transfer_file,"w"){|f| Marshal.dump(@arcadia_dbg,f) }
679
+ File.rename('~'+@transfer_file,@transfer_file)
680
+ rescue
681
+ # .. handle error
682
+ ensure
683
+ arcadia_initdbg
684
+ end
685
+
686
+ end
687
+ def arcadia_line_at_to_file(file, line)
688
+ @arcadia_dbg[:file]=file
689
+ @arcadia_dbg[:line]=line
690
+ end
691
+
692
+
693
+ def line_at(file, line)
694
+ lines = SCRIPT_LINES__[file]
695
+ if lines
696
+ return "\n" if lines == true
697
+ line = lines[line-1]
698
+ return "\n" unless line
699
+ return line
700
+ end
701
+ return "\n"
702
+ end
703
+
704
+ def debug_funcname(id)
705
+ if id.nil?
706
+ "toplevel"
707
+ else
708
+ id.id2name
709
+ end
710
+ end
711
+
712
+ def check_break_points(file, klass, pos, binding, id)
713
+ return false if break_points.empty?
714
+ n = 1
715
+ for b in break_points
716
+ if b[0] # valid
717
+ if b[1] == 0 # breakpoint
718
+ if (b[2] == file and b[3] == pos) or
719
+ (klass and b[2] == klass and b[3] == pos)
720
+ stdout.printf "Breakpoint %d, %s at %s:%s\n", n, debug_funcname(id), file, pos
721
+ #arcadia_line_at_to_file(file, pos)
722
+ #arcadia_transfer
723
+ return true
724
+ end
725
+ elsif b[1] == 1 # watchpoint
726
+ if debug_silent_eval(b[2], binding)
727
+ stdout.printf "Watchpoint %d, %s at %s:%s\n", n, debug_funcname(id), file, pos
728
+ return true
729
+ end
730
+ end
731
+ end
732
+ n += 1
733
+ end
734
+ return false
735
+ end
736
+
737
+ def excn_handle(file, line, id, binding)
738
+ if $!.class <= SystemExit
739
+ set_trace_func nil
740
+ exit
741
+ end
742
+
743
+ if @catch and ($!.class.ancestors.find { |e| e.to_s == @catch })
744
+ stdout.printf "%s:%d: `%s' (%s)\n", file, line, $!, $!.class
745
+ @arcadia_dbg[:error_text] = $!.to_s
746
+ @arcadia_dbg[:error_class] = $!.class
747
+ fs = @frames.size
748
+ tb = caller(0)[-fs..-1]
749
+ if tb
750
+ @arcadia_dbg[:callers] = tb
751
+ for i in tb
752
+ stdout.printf "\tfrom %s\n", i
753
+ end
754
+ end
755
+ suspend_all
756
+ debug_command(file, line, id, binding)
757
+ end
758
+ end
759
+
760
+ def trace_func(event, file, line, id, binding, klass)
761
+ Tracer.trace_func(event, file, line, id, binding, klass) if trace?
762
+ context(Thread.current).check_suspend
763
+ @file = file
764
+ @line = line
765
+ case event
766
+ when 'line'
767
+ frame_set_pos(file, line)
768
+ if !@no_step or @frames.size == @no_step
769
+ @stop_next -= 1
770
+ @stop_next = -1 if @stop_next < 0
771
+ elsif @frames.size < @no_step
772
+ @stop_next = 0 # break here before leaving...
773
+ else
774
+ # nothing to do. skipped.
775
+ end
776
+ if @stop_next == 0 or check_break_points(file, nil, line, binding, id)
777
+ @no_step = nil
778
+ suspend_all
779
+ debug_command(file, line, id, binding)
780
+ end
781
+
782
+ when 'call'
783
+ @frames.unshift [binding, file, line, id]
784
+ if check_break_points(file, klass, id.id2name, binding, id)
785
+ suspend_all
786
+ debug_command(file, line, id, binding)
787
+ end
788
+
789
+ when 'c-call'
790
+ frame_set_pos(file, line)
791
+
792
+ when 'class'
793
+ @frames.unshift [binding, file, line, id]
794
+
795
+ when 'return', 'end'
796
+ if @frames.size == @finish_pos
797
+ @stop_next = 1
798
+ @finish_pos = 0
799
+ end
800
+ @frames.shift
801
+
802
+ when 'end'
803
+ @frames.shift
804
+
805
+ when 'raise'
806
+ excn_handle(file, line, id, binding)
807
+
808
+ end
809
+ @last_file = file
810
+ end
811
+ end
812
+
813
+ trap("INT") { DEBUGGER__.interrupt }
814
+ @last_thread = Thread::main
815
+ @max_thread = 1
816
+ @thread_list = {Thread::main => 1}
817
+ @break_points = []
818
+ @display = []
819
+ @waiting = []
820
+ @stdout = STDOUT
821
+
822
+ class << DEBUGGER__
823
+ def stdout
824
+ @stdout
825
+ end
826
+
827
+ def stdout=(s)
828
+ @stdout = s
829
+ end
830
+
831
+ def display
832
+ @display
833
+ end
834
+
835
+ def break_points
836
+ @break_points
837
+ end
838
+
839
+ def waiting
840
+ @waiting
841
+ end
842
+
843
+ def set_trace( arg )
844
+ saved_crit = Thread.critical
845
+ Thread.critical = true
846
+ make_thread_list
847
+ for th, in @thread_list
848
+ context(th).set_trace arg
849
+ end
850
+ Thread.critical = saved_crit
851
+ arg
852
+ end
853
+
854
+ def set_last_thread(th)
855
+ @last_thread = th
856
+ end
857
+
858
+ def suspend
859
+ saved_crit = Thread.critical
860
+ Thread.critical = true
861
+ make_thread_list
862
+ for th, in @thread_list
863
+ next if th == Thread.current
864
+ context(th).set_suspend
865
+ end
866
+ Thread.critical = saved_crit
867
+ # Schedule other threads to suspend as soon as possible.
868
+ Thread.pass unless Thread.critical
869
+ end
870
+
871
+ def resume
872
+ saved_crit = Thread.critical
873
+ Thread.critical = true
874
+ make_thread_list
875
+ for th, in @thread_list
876
+ next if th == Thread.current
877
+ context(th).clear_suspend
878
+ end
879
+ waiting.each do |th|
880
+ th.run
881
+ end
882
+ waiting.clear
883
+ Thread.critical = saved_crit
884
+ # Schedule other threads to restart as soon as possible.
885
+ Thread.pass
886
+ end
887
+
888
+ def context(thread=Thread.current)
889
+ c = thread[:__debugger_data__]
890
+ unless c
891
+ thread[:__debugger_data__] = c = Context.new
892
+ end
893
+ c
894
+ end
895
+
896
+ def interrupt
897
+ context(@last_thread).stop_next
898
+ end
899
+
900
+ def get_thread(num)
901
+ th = @thread_list.index(num)
902
+ unless th
903
+ @stdout.print "No thread ##{num}\n"
904
+ throw :debug_error
905
+ end
906
+ th
907
+ end
908
+
909
+ def thread_list(num)
910
+ th = get_thread(num)
911
+ if th == Thread.current
912
+ @stdout.print "+"
913
+ else
914
+ @stdout.print " "
915
+ end
916
+ @stdout.printf "%d ", num
917
+ @stdout.print th.inspect, "\t"
918
+ file = context(th).instance_eval{@file}
919
+ if file
920
+ @stdout.print file,":",context(th).instance_eval{@line}
921
+ end
922
+ @stdout.print "\n"
923
+ end
924
+
925
+ def thread_list_all
926
+ for th in @thread_list.values.sort
927
+ thread_list(th)
928
+ end
929
+ end
930
+
931
+ def make_thread_list
932
+ hash = {}
933
+ for th in Thread::list
934
+ if @thread_list.key? th
935
+ hash[th] = @thread_list[th]
936
+ else
937
+ @max_thread += 1
938
+ hash[th] = @max_thread
939
+ end
940
+ end
941
+ @thread_list = hash
942
+ end
943
+
944
+ def debug_thread_info(input, binding)
945
+ case input
946
+ when /^l(?:ist)?/
947
+ make_thread_list
948
+ thread_list_all
949
+
950
+ when /^c(?:ur(?:rent)?)?$/
951
+ make_thread_list
952
+ thread_list(@thread_list[Thread.current])
953
+
954
+ when /^(?:sw(?:itch)?\s+)?(\d+)/
955
+ make_thread_list
956
+ th = get_thread($1.to_i)
957
+ if th == Thread.current
958
+ @stdout.print "It's the current thread.\n"
959
+ else
960
+ thread_list(@thread_list[th])
961
+ context(th).stop_next
962
+ th.run
963
+ return :cont
964
+ end
965
+
966
+ when /^stop\s+(\d+)/
967
+ make_thread_list
968
+ th = get_thread($1.to_i)
969
+ if th == Thread.current
970
+ @stdout.print "It's the current thread.\n"
971
+ elsif th.stop?
972
+ @stdout.print "Already stopped.\n"
973
+ else
974
+ thread_list(@thread_list[th])
975
+ context(th).suspend
976
+ end
977
+
978
+ when /^resume\s+(\d+)/
979
+ make_thread_list
980
+ th = get_thread($1.to_i)
981
+ if th == Thread.current
982
+ @stdout.print "It's the current thread.\n"
983
+ elsif !th.stop?
984
+ @stdout.print "Already running."
985
+ else
986
+ thread_list(@thread_list[th])
987
+ th.run
988
+ end
989
+ end
990
+ end
991
+ end
992
+
993
+ stdout.printf "Debug.rb\n"
994
+ stdout.printf "Emacs support available.\n\n"
995
+ set_trace_func proc { |event, file, line, id, binding, klass, *rest|
996
+ DEBUGGER__.context.trace_func event, file, line, id, binding, klass
997
+ }
998
+ end