15 |
15 |
16 =begin edoc |
16 =begin edoc |
17 File implementing the real debugger, which is connected to the IDE frontend. |
17 File implementing the real debugger, which is connected to the IDE frontend. |
18 =end |
18 =end |
19 |
19 |
|
20 require 'continuation' |
|
21 |
20 require 'DebugQuit' |
22 require 'DebugQuit' |
21 require 'rbconfig' |
23 require 'rbconfig' |
22 |
24 |
23 class DEBUGGER__ |
25 class DEBUGGER__ |
24 =begin edoc |
26 =begin edoc |
25 Class implementing the real debugger. |
27 Class implementing the real debugger. |
26 =end |
28 =end |
27 class Mutex |
|
28 =begin edoc |
|
29 Class implementing a mutex. |
|
30 =end |
|
31 def initialize |
|
32 =begin edoc |
|
33 Constructor |
|
34 =end |
|
35 @locker = nil |
|
36 @waiting = [] |
|
37 @locked = false; |
|
38 end |
|
39 |
|
40 def locked? |
|
41 =begin edoc |
|
42 Method returning the locked state. |
|
43 |
|
44 @return flag indicating the locked state (boolean) |
|
45 =end |
|
46 @locked |
|
47 end |
|
48 |
|
49 def lock |
|
50 =begin edoc |
|
51 Method to lock the mutex. |
|
52 |
|
53 @return the mutex |
|
54 =end |
|
55 return if @locker == Thread.current |
|
56 while (Thread.critical = true; @locked) |
|
57 @waiting.push Thread.current |
|
58 Thread.stop |
|
59 end |
|
60 @locked = true |
|
61 @locker = Thread.current |
|
62 Thread.critical = false |
|
63 self |
|
64 end |
|
65 |
|
66 def unlock |
|
67 =begin edoc |
|
68 Method to unlock the mutex. |
|
69 |
|
70 @return the mutex |
|
71 =end |
|
72 return unless @locked |
|
73 unless @locker == Thread.current |
|
74 raise RuntimeError, "unlocked by other" |
|
75 end |
|
76 Thread.critical = true |
|
77 t = @waiting.shift |
|
78 @locked = false |
|
79 @locker = nil |
|
80 Thread.critical = false |
|
81 t.run if t |
|
82 self |
|
83 end |
|
84 end |
|
85 MUTEX = Mutex.new |
29 MUTEX = Mutex.new |
86 |
30 |
87 class Context |
31 class Context |
88 =begin edoc |
32 =begin edoc |
89 Class defining the current execution context. |
33 Class defining the current execution context. |
184 |
128 |
185 def check_suspend |
129 def check_suspend |
186 =begin edoc |
130 =begin edoc |
187 Method to check the suspend state. |
131 Method to check the suspend state. |
188 =end |
132 =end |
189 while (Thread.critical = true; @suspend_next) |
133 while MUTEX.synchronize { |
190 DEBUGGER__.waiting.push Thread.current |
134 if @suspend_next |
191 @suspend_next = false |
135 DEBUGGER__.waiting.push Thread.current |
192 Thread.stop |
136 @suspend_next = false |
193 end |
137 true |
194 Thread.critical = false |
138 end |
|
139 } |
|
140 end |
195 end |
141 end |
196 |
142 |
197 def stdout |
143 def stdout |
198 =begin edoc |
144 =begin edoc |
199 Method returning the stdout object. |
145 Method returning the stdout object. |
313 # bp[5] condition |
259 # bp[5] condition |
314 # bp[6] ignore count |
260 # bp[6] ignore count |
315 # bp[7] special condition |
261 # bp[7] special condition |
316 # bp[8] hash of special values |
262 # bp[8] hash of special values |
317 return false if break_points.empty? |
263 return false if break_points.empty? |
318 for b in break_points |
264 break_points.each do |b| |
319 if b[0] |
265 if b[0] |
320 if b[1] == 0 and b[2] == file and b[3] == pos # breakpoint |
266 if b[1] == 0 and b[2] == file and b[3] == pos # breakpoint |
321 # Evaluate condition |
267 # Evaluate condition |
322 if b[5] |
268 if b[5] |
323 begin |
269 begin |
439 |
385 |
440 @param file filename of the breakpoint (String) |
386 @param file filename of the breakpoint (String) |
441 @param pos line number of the breakpoint (int) |
387 @param pos line number of the breakpoint (int) |
442 @param enable flag indicating the new enabled state (boolean) |
388 @param enable flag indicating the new enabled state (boolean) |
443 =end |
389 =end |
444 for bp in break_points |
390 break_points.each do |bp| |
445 if (bp[1] == 0 and bp[2] == file and bp[3] == pos) |
391 if (bp[1] == 0 and bp[2] == file and bp[3] == pos) |
446 bp[0] = enable |
392 bp[0] = enable |
447 break |
393 break |
448 end |
394 end |
449 end |
395 end |
455 |
401 |
456 @param file filename of the breakpoint (String) |
402 @param file filename of the breakpoint (String) |
457 @param pos line number of the breakpoint (int) |
403 @param pos line number of the breakpoint (int) |
458 @param count ignore count to be set (int) |
404 @param count ignore count to be set (int) |
459 =end |
405 =end |
460 for bp in break_points |
406 break_points.each do |bp| |
461 if (bp[2] == file and bp[3] == pos) |
407 if (bp[2] == file and bp[3] == pos) |
462 bp[6] = count |
408 bp[6] = count |
463 break |
409 break |
464 end |
410 end |
465 end |
411 end |
506 Method to set the enabled state of a watch expression. |
452 Method to set the enabled state of a watch expression. |
507 |
453 |
508 @param cond expression of the watch expression (String) |
454 @param cond expression of the watch expression (String) |
509 @param enable flag indicating the new enabled state (boolean) |
455 @param enable flag indicating the new enabled state (boolean) |
510 =end |
456 =end |
511 for bp in break_points |
457 break_points.each do |bp| |
512 if (bp[1] == 1 and bp[2] == cond) |
458 if (bp[1] == 1 and bp[2] == cond) |
513 bp[0] = enable |
459 bp[0] = enable |
514 break |
460 break |
515 end |
461 end |
516 end |
462 end |
521 Method to set the ignore count of a watch expression. |
467 Method to set the ignore count of a watch expression. |
522 |
468 |
523 @param cond expression of the watch expression (String) |
469 @param cond expression of the watch expression (String) |
524 @param count ignore count to be set (int) |
470 @param count ignore count to be set (int) |
525 =end |
471 =end |
526 for bp in break_points |
472 break_points.each do |bp| |
527 if (bp[1] == 1 and bp[2] == cond) |
473 if (bp[1] == 1 and bp[2] == cond) |
528 bp[6] = count |
474 bp[6] = count |
529 break |
475 break |
530 end |
476 end |
531 end |
477 end |
574 if file =~ /\(eval\)/ |
520 if file =~ /\(eval\)/ |
575 return true |
521 return true |
576 end |
522 end |
577 |
523 |
578 if not traceRuby? and |
524 if not traceRuby? and |
579 (file =~ /#{Config::CONFIG['sitelibdir']}/ or |
525 (file =~ /#{RbConfig::CONFIG['sitelibdir']}/ or |
580 file =~ /#{Config::CONFIG['rubylibdir']}/) |
526 file =~ /#{RbConfig::CONFIG['rubylibdir']}/) |
581 return true |
527 return true |
582 end |
528 end |
583 |
529 |
584 if ["AsyncFile.rb", "AsyncIO.rb", "Config.rb", "DebugClient.rb", |
530 if ["AsyncFile.rb", "AsyncIO.rb", "Config.rb", "DebugClient.rb", |
585 "DebugClientBaseModule.rb", "DebugClientCapabilities.rb", |
531 "DebugClientBaseModule.rb", "DebugClientCapabilities.rb", |
660 debug_command(file, line, id, binding_) |
603 debug_command(file, line, id, binding_) |
661 end |
604 end |
662 |
605 |
663 when 'c-call' |
606 when 'c-call' |
664 frame_set_pos(file, line) |
607 frame_set_pos(file, line) |
665 if id == :require and klass == Kernel |
608 ## if id == :require and klass == Kernel |
666 @frames.unshift [binding_, file, line, id] |
609 ## @frames.unshift [binding_, file, line, id] |
667 else |
610 ## else |
668 frame_set_pos(file, line) |
611 ## frame_set_pos(file, line) |
669 end |
612 ## end |
670 |
613 ## |
671 when 'c-return' |
614 ## when 'c-return' |
672 if id == :require and klass == Kernel |
615 ## if id == :require and klass == Kernel |
673 if @frames.size == @finish_pos |
616 ## if @frames.size == @finish_pos |
674 @stop_next = 1 |
617 ## @stop_next = 1 |
675 @finish_pos = 0 |
618 ## @finish_pos = 0 |
676 end |
619 ## end |
677 @frames.shift |
620 ## @frames.shift |
678 end |
621 ## end |
679 |
622 |
680 when 'class' |
623 when 'class' |
681 @frames.unshift [binding_, file, line, id] |
624 @frames.unshift [binding_, file, line, id] |
682 |
625 |
683 when 'return', 'end' |
626 when 'return', 'end' |
684 if @frames.size == @finish_pos |
627 if @frames.size == @finish_pos |
685 @stop_next = 1 |
628 @stop_next = 1 |
686 @finish_pos = 0 |
629 @finish_pos = 0 |
687 end |
630 end |
688 @frames.shift |
|
689 |
|
690 when 'end' |
|
691 @frames.shift |
631 @frames.shift |
692 |
632 |
693 when 'raise' |
633 when 'raise' |
694 @no_step = nil |
634 @no_step = nil |
695 @stop_next = 0 # break here before leaving... |
635 @stop_next = 0 # break here before leaving... |
841 |
781 |
842 def suspend |
782 def suspend |
843 =begin edoc |
783 =begin edoc |
844 Method to suspend the program being debugged. |
784 Method to suspend the program being debugged. |
845 =end |
785 =end |
846 Thread.critical = true |
786 MUTEX.synchronize do |
847 make_thread_list |
787 make_thread_list |
848 for th, in @thread_list |
788 for th, in @thread_list |
849 next if th == Thread.current |
789 next if th == Thread.current |
850 context(th).set_suspend |
790 context(th).set_suspend |
851 end |
791 end |
852 Thread.critical = false |
792 end |
853 # Schedule other threads to suspend as soon as possible. |
793 # Schedule other threads to suspend as soon as possible. |
854 Thread.pass |
794 Thread.pass |
855 end |
795 end |
856 |
796 |
857 def resume |
797 def resume |
858 =begin edoc |
798 =begin edoc |
859 Method to resume the program being debugged. |
799 Method to resume the program being debugged. |
860 =end |
800 =end |
861 Thread.critical = true |
801 MUTEX.synchronize do |
862 make_thread_list |
802 make_thread_list |
863 for th, in @thread_list |
803 for th, in @thread_list |
864 next if th == Thread.current |
804 next if th == Thread.current |
865 context(th).clear_suspend |
805 context(th).clear_suspend |
866 end |
806 end |
867 waiting.each do |th| |
807 waiting.each do |th| |
868 th.run |
808 th.run |
869 end |
809 end |
870 waiting.clear |
810 waiting.clear |
871 Thread.critical = false |
811 end |
872 # Schedule other threads to restart as soon as possible. |
812 # Schedule other threads to restart as soon as possible. |
873 Thread.pass |
813 Thread.pass |
874 end |
814 end |
875 |
815 |
876 def context(thread=Thread.current) |
816 def context(thread=Thread.current) |
899 Method returning a thread by number. |
839 Method returning a thread by number. |
900 |
840 |
901 @param num thread number (int) |
841 @param num thread number (int) |
902 @return thread with the requested number |
842 @return thread with the requested number |
903 =end |
843 =end |
904 th = @thread_list.index(num) |
844 th = @thread_list.key(num) |
905 unless th |
845 unless th |
906 @stdout.print "No thread ##{num}\n" |
846 @stdout.print "No thread ##{num}\n" |
907 throw :debug_error |
847 throw :debug_error |
908 end |
848 end |
909 th |
849 th |