DebugClients/Ruby/Debuggee.rb

changeset 0
de9c2efb9d02
child 13
1af94a91f439
equal deleted inserted replaced
-1:000000000000 0:de9c2efb9d02
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2005 - 2009 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 # Debuggee.rb is based in parts on debug.rb from Ruby and debuggee.rb.
7 # Original copyrights of these files follow below.
8 #
9 # debug.rb
10 # Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
11 # Copyright (C) 2000 Information-technology Promotion Agency, Japan
12 #
13 # debuggee.rb
14 # Copyright (c) 2000 NAKAMURA, Hiroshi
15
16 =begin edoc
17 File implementing the real debugger, which is connected to the IDE frontend.
18 =end
19
20 require 'DebugQuit'
21 require 'rbconfig'
22
23 class DEBUGGER__
24 =begin edoc
25 Class implementing the real debugger.
26 =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
86
87 class Context
88 =begin edoc
89 Class defining the current execution context.
90 =end
91 def initialize
92 =begin edoc
93 Constructor
94 =end
95 if Thread.current == Thread.main
96 @stop_next = 1
97 else
98 @stop_next = 0
99 end
100 @last_file = nil
101 @file = nil
102 @line = nil
103 @no_step = nil
104 @frames = []
105 @frame_pos = 0 #LJ - for FR
106 @finish_pos = 0
107 @trace = false
108 @catch = ["StandardError"] #LJ - for FR
109 @suspend_next = false
110 end
111
112 def stop_next(n=1)
113 =begin edoc
114 Method to set the next stop point (i.e. stop at next line).
115
116 @param counter defining the stop point (int)
117 =end
118 @stop_next = n
119 end
120
121 def step_over(n=1)
122 =begin edoc
123 Method to set the next stop point skipping function calls.
124
125 @param counter defining the stop point (int)
126 =end
127 @stop_next = n
128 @no_step = @frames.size - @frame_pos
129 end
130
131 def step_out
132 =begin edoc
133 Method to set the next stop point after the function call returns.
134 =end
135 if @frame_pos != @frames.size
136 @finish_pos = @frames.size - @frame_pos
137 @frame_pos = 0
138 @stop_next -= 1
139 end
140 end
141
142 def step_continue
143 =begin edoc
144 Method to continue execution until next breakpoint or watch expression.
145 =end
146 @stop_next = 1
147 @no_step = -1
148 end
149
150 def step_quit
151 =begin edoc
152 Method to stop debugging.
153 =end
154 raise DebugQuit.new
155 end
156
157 def set_suspend
158 =begin edoc
159 Method to suspend all threads.
160 =end
161 @suspend_next = true
162 end
163
164 def clear_suspend
165 =begin edoc
166 Method to clear the suspend state.
167 =end
168 @suspend_next = false
169 end
170
171 def suspend_all
172 =begin edoc
173 Method to suspend all threads.
174 =end
175 DEBUGGER__.suspend
176 end
177
178 def resume_all
179 =begin edoc
180 Method to resume all threads.
181 =end
182 DEBUGGER__.resume
183 end
184
185 def check_suspend
186 =begin edoc
187 Method to check the suspend state.
188 =end
189 while (Thread.critical = true; @suspend_next)
190 DEBUGGER__.waiting.push Thread.current
191 @suspend_next = false
192 Thread.stop
193 end
194 Thread.critical = false
195 end
196
197 def stdout
198 =begin edoc
199 Method returning the stdout object.
200
201 @return reference to the stdout object
202 =end
203 DEBUGGER__.stdout
204 end
205
206 def break_points
207 =begin edoc
208 Method to return the list of breakpoints
209
210 @return Array containing all breakpoints.
211 =end
212 DEBUGGER__.break_points
213 end
214
215 def context(th)
216 =begin edoc
217 Method returning the context of a thread.
218
219 @param th thread object to get the context for
220 @return the context for the thread
221 =end
222 DEBUGGER__.context(th)
223 end
224
225 def attached?
226 =begin edoc
227 Method returning the attached state.
228
229 @return flag indicating, whether the debugger is attached to the IDE.
230 =end
231 DEBUGGER__.attached?
232 end
233
234 def set_last_thread(th)
235 =begin edoc
236 Method to remember the last thread.
237
238 @param th thread to be remembered.
239 =end
240 DEBUGGER__.set_last_thread(th)
241 end
242
243 def debug_silent_eval(str, binding_)
244 =begin edoc
245 Method to eval a string without output.
246
247 @param str String containing the expression to be evaluated
248 @param binding_ the binding for the evaluation
249 @return the result of the evaluation
250 =end
251 val = eval(str, binding_)
252 val
253 end
254
255 def thnum
256 =begin edoc
257 Method returning the thread number of the current thread.
258
259 @return thread number of the current thread.
260 =end
261 num = DEBUGGER__.instance_eval{@thread_list[Thread.current]}
262 unless num
263 DEBUGGER__.make_thread_list
264 num = DEBUGGER__.instance_eval{@thread_list[Thread.current]}
265 end
266 num
267 end
268
269 def debug_command(file, line, id, binding_)
270 =begin edoc
271 Method to execute the next debug command.
272 =end
273 MUTEX.lock
274 set_last_thread(Thread.current)
275 unless attached?
276 MUTEX.unlock
277 resume_all
278 return
279 end
280 @frame_pos = 0
281 @frames[0] = [binding_, file, line, id]
282 stdout.printf_line(@frames)
283 MUTEX.unlock
284 resume_all
285 eventLoop
286 end
287
288 def frame_set_pos(file, line)
289 =begin edoc
290 Method to set the frame position of the current frame.
291 =end
292 if @frames[0]
293 @frames[0][1] = file
294 @frames[0][2] = line
295 end
296 end
297
298 def check_break_points(file, pos, binding_, id)
299 =begin edoc
300 Method to check, if the given position contains an active breakpoint.
301
302 @param file filename containing the currently executed line (String)
303 @param pos line number currently executed (int)
304 @param binding_ current binding object
305 @param id (ignored)
306 @return flag indicating an active breakpoint (boolean)
307 =end
308 # bp[0] enabled flag
309 # bp[1] 0 = breakpoint, 1 = watch expression
310 # bp[2] filename
311 # bp[3] linenumber
312 # bp[4] temporary flag
313 # bp[5] condition
314 # bp[6] ignore count
315 # bp[7] special condition
316 # bp[8] hash of special values
317 return false if break_points.empty?
318 for b in break_points
319 if b[0]
320 if b[1] == 0 and b[2] == file and b[3] == pos # breakpoint
321 # Evaluate condition
322 if b[5]
323 begin
324 if debug_silent_eval(b[5], binding_)
325 if b[6] == 0 # ignore count reached
326 # Delete once reached if temporary breakpoint
327 clear_break_point(file, pos) if b[4]
328 return true
329 else
330 b[6] -= 1
331 end
332 end
333 rescue StandardError, ScriptError
334 nil
335 end
336 else
337 if b[6] == 0 # ignore count reached
338 # Delete once reached if temporary breakpoint
339 clear_break_point(file, pos) if b[4]
340 return true
341 else
342 b[6] -= 1
343 end
344 end
345 elsif b[1] == 1 # watch expression
346 begin
347 bd = @frame_pos
348 val = debug_silent_eval(b[5], binding_)
349 if b[7].length() > 0
350 if b[7] == "??created??"
351 if b[8][bd][0] == false
352 b[8][bd][0] = true
353 b[8][bd][1] = val
354 return true
355 else
356 next
357 end
358 end
359 b[8][bd][0] = true
360 if b[7] == "??changed??"
361 if b[8][bd][1] != val
362 b[8][bd][1] = val
363 if b[8][bd][2] > 0
364 b[8][bd][2] -= 1
365 next
366 else
367 return true
368 end
369 else
370 next
371 end
372 end
373 next
374 end
375 if val
376 if b[6] == 0 # ignore count reached
377 # Delete once reached if temporary breakpoint
378 clear_watch_point(b[2]) if b[4]
379 return true
380 else
381 b[6] -= 1
382 end
383 end
384 rescue StandardError, ScriptError
385 if b[7].length() > 0
386 if b[8][bd]
387 b[8][bd][0] = false
388 else
389 b[8][bd] = [false, nil, b[6]]
390 end
391 else
392 val = nil
393 end
394 end
395 end
396 end
397 end
398 return false
399 end
400
401 def clear_break_point(file, pos)
402 =begin edoc
403 Method to delete a specific breakpoint.
404
405 @param file filename containing the breakpoint (String)
406 @param pos line number containing the breakpoint (int)
407 =end
408 delete_break_point(file, pos)
409 stdout.printf_clear_breakpoint(file, pos)
410 end
411
412 def add_break_point(file, pos, temp = false, cond = nil)
413 =begin edoc
414 Method to add a breakpoint.
415
416 @param file filename for the breakpoint (String)
417 @param pos line number for the breakpoint (int)
418 @param temp flag indicating a temporary breakpoint (boolean)
419 @param cond condition of a conditional breakpoint (String)
420 =end
421 break_points.push [true, 0, file, pos, temp, cond, 0]
422 end
423
424 def delete_break_point(file, pos)
425 =begin edoc
426 Method to delete a breakpoint.
427
428 @param file filename of the breakpoint (String)
429 @param pos line number of the breakpoint (int)
430 =end
431 break_points.delete_if { |bp|
432 bp[1] == 0 and bp[2] == file and bp[3] == pos
433 }
434 end
435
436 def enable_break_point(file, pos, enable)
437 =begin edoc
438 Method to set the enabled state of a breakpoint.
439
440 @param file filename of the breakpoint (String)
441 @param pos line number of the breakpoint (int)
442 @param enable flag indicating the new enabled state (boolean)
443 =end
444 for bp in break_points
445 if (bp[1] == 0 and bp[2] == file and bp[3] == pos)
446 bp[0] = enable
447 break
448 end
449 end
450 end
451
452 def ignore_break_point(file, pos, count)
453 =begin edoc
454 Method to set the ignore count of a breakpoint.
455
456 @param file filename of the breakpoint (String)
457 @param pos line number of the breakpoint (int)
458 @param count ignore count to be set (int)
459 =end
460 for bp in break_points
461 if (bp[2] == file and bp[3] == pos)
462 bp[6] = count
463 break
464 end
465 end
466 end
467
468 def clear_watch_point(cond)
469 =begin edoc
470 Method to delete a specific watch expression.
471
472 @param cond expression specifying the watch expression (String)
473 =end
474 delete_watch_point(cond)
475 stdout.printf_clear_watchexpression(cond)
476 end
477
478 def add_watch_point(cond, temp = false)
479 =begin edoc
480 Method to add a watch expression.
481
482 @param cond expression of the watch expression (String)
483 @param temp flag indicating a temporary watch expression (boolean)
484 =end
485 co1, co2 = cond.split()
486 if co2 == "??created??" or co2 == "??changed??"
487 break_points.push [true, 1, cond, 0, temp, co1, 0, co2, {}]
488 else
489 break_points.push [true, 1, cond, 0, temp, cond, 0, "", {}]
490 end
491 end
492
493 def delete_watch_point(cond)
494 =begin edoc
495 Method to delete a watch expression.
496
497 @param cond expression of the watch expression (String)
498 =end
499 break_points.delete_if { |bp|
500 bp[1] == 1 and bp[2] == cond
501 }
502 end
503
504 def enable_watch_point(cond, enable)
505 =begin edoc
506 Method to set the enabled state of a watch expression.
507
508 @param cond expression of the watch expression (String)
509 @param enable flag indicating the new enabled state (boolean)
510 =end
511 for bp in break_points
512 if (bp[1] == 1 and bp[2] == cond)
513 bp[0] = enable
514 break
515 end
516 end
517 end
518
519 def ignore_watch_point(cond, count)
520 =begin edoc
521 Method to set the ignore count of a watch expression.
522
523 @param cond expression of the watch expression (String)
524 @param count ignore count to be set (int)
525 =end
526 for bp in break_points
527 if (bp[1] == 1 and bp[2] == cond)
528 bp[6] = count
529 break
530 end
531 end
532 end
533
534 def excn_handle(file, line, id, binding_)
535 =begin edoc
536 Method to handle an exception
537
538 @param file filename containing the currently executed line (String)
539 @param pos line number currently executed (int)
540 @param id (ignored)
541 @param binding_ current binding object
542 =end
543 if $!.class <= SystemExit
544 set_trace_func nil
545 stdout.printf_exit($!.status)
546 return
547 elsif $!.class <= ScriptError
548 msgParts = $!.message.split(":", 3)
549 filename = File.expand_path(msgParts[0])
550 linenr = msgParts[1].to_i
551 exclist = ["", [filename, linenr, 0]]
552 stdout.printf_scriptExcn(exclist)
553 else
554 exclist = ["%s" % $!.class, "%s" % $!, [file, line]]
555 @frames.each do |_binding, _file, _line, _id|
556 next if [_file, _line] == exclist[-1]
557 exclist << [_file, _line]
558 end
559 stdout.printf_excn(exclist)
560 end
561 debug_command(file, line, id, binding_)
562 end
563
564 def skip_it?(file)
565 =begin edoc
566 Method to filter out debugger files.
567
568 Tracing is turned off for files that are part of the
569 debugger that are called from the application being debugged.
570
571 @param file name of the file to be checked (String)
572 @return flag indicating, whether the file should be skipped (boolean)
573 =end
574 if file =~ /\(eval\)/
575 return true
576 end
577
578 if not traceRuby? and
579 (file =~ /#{Config::CONFIG['sitelibdir']}/ or
580 file =~ /#{Config::CONFIG['rubylibdir']}/)
581 return true
582 end
583
584 if ["AsyncFile.rb", "AsyncIO.rb", "Config.rb", "DebugClient.rb",
585 "DebugClientBaseModule.rb", "DebugClientCapabilities.rb",
586 "DebugProtocol.rb", "DebugQuit.rb", "Debuggee.rb"].include?(\
587 File.basename(file))
588 return true
589 end
590 return false
591 end
592
593 def trace_func(event, file, line, id, binding_, klass)
594 =begin edoc
595 Method executed by the tracing facility.
596
597 @param event the tracing event (String)
598 @param file the name of the file being traced (String)
599 @param line the line number being traced (int)
600 @param id object id
601 @param binding_ a binding object
602 @param klass name of a class
603 =end
604 context(Thread.current).check_suspend
605
606 if skip_it?(file) and not ["call","return"].include?(event)
607 case event
608 when 'line'
609 frame_set_pos(file, line)
610
611 when 'call'
612 @frames.unshift [binding_, file, line, id]
613
614 when 'c-call'
615 frame_set_pos(file, line)
616
617 when 'class'
618 @frames.unshift [binding_, file, line, id]
619
620 when 'return', 'end'
621 @frames.shift
622
623 when 'end'
624 @frames.shift
625
626 when 'raise'
627 excn_handle(file, line, id, binding_)
628
629 end
630 @last_file = file
631 return
632 end
633
634 @file = file
635 @line = line
636
637 case event
638 when 'line'
639 frame_set_pos(file, line)
640 eventPoll
641 if !@no_step or @frames.size == @no_step
642 @stop_next -= 1
643 @stop_next = -1 if @stop_next < 0
644 elsif @frames.size < @no_step
645 @stop_next = 0 # break here before leaving...
646 else
647 # nothing to do. skipped.
648 end
649 if check_break_points(file, line, binding_, id) or @stop_next == 0
650 @no_step = nil
651 suspend_all
652 debug_command(file, line, id, binding_)
653 end
654
655 when 'call'
656 @frames.unshift [binding_, file, line, id]
657 if check_break_points(file, id.id2name, binding_, id) or
658 check_break_points(klass.to_s, id.id2name, binding_, id)
659 suspend_all
660 debug_command(file, line, id, binding_)
661 end
662
663 when 'c-call'
664 frame_set_pos(file, line)
665 if id == :require and klass == Kernel
666 @frames.unshift [binding_, file, line, id]
667 else
668 frame_set_pos(file, line)
669 end
670
671 when 'c-return'
672 if id == :require and klass == Kernel
673 if @frames.size == @finish_pos
674 @stop_next = 1
675 @finish_pos = 0
676 end
677 @frames.shift
678 end
679
680 when 'class'
681 @frames.unshift [binding_, file, line, id]
682
683 when 'return', 'end'
684 if @frames.size == @finish_pos
685 @stop_next = 1
686 @finish_pos = 0
687 end
688 @frames.shift
689
690 when 'end'
691 @frames.shift
692
693 when 'raise'
694 @no_step = nil
695 @stop_next = 0 # break here before leaving...
696 excn_handle(file, line, id, binding_)
697
698 end
699 @last_file = file
700 end
701 end
702
703 trap("INT") { DEBUGGER__.interrupt }
704 @last_thread = Thread::main
705 @max_thread = 1
706 @thread_list = {Thread::main => 1}
707 @break_points = []
708 @waiting = []
709 @stdout = STDOUT
710 @loaded_files = {}
711
712 class SilentObject
713 =begin edoc
714 Class defining an object that ignores all messages.
715 =end
716 def method_missing( msg_id, *a, &b )
717 =begin edoc
718 Method invoked for all messages it cannot handle.
719
720 @param msg_id symbol for the method called
721 @param *a arguments passed to the missing method
722 @param &b unknown
723 =end
724 end
725 end
726 SilentClient = SilentObject.new()
727 @client = SilentClient
728 @attached = false
729
730 class <<DEBUGGER__
731 =begin edoc
732 Class defining a singleton object for the debugger.
733 =end
734 def stdout
735 =begin edoc
736 Method returning the stdout object.
737
738 @return reference to the stdout object
739 =end
740 @stdout
741 end
742
743 def stdout=(s)
744 =begin edoc
745 Method to set the stdout object.
746
747 @param s reference to the stdout object
748 =end
749 @stdout = s
750 end
751
752 def break_points
753 =begin edoc
754 Method to return the list of breakpoints
755
756 @return Array containing all breakpoints.
757 =end
758 @break_points
759 end
760
761 def last_thread
762 =begin edoc
763 Method returning the last active thread.
764
765 @return active thread
766 =end
767 @last_thread
768 end
769
770 def attach( debugger )
771 =begin edoc
772 Method to connect the debugger to the IDE.
773
774 @param debugger reference to the object handling the
775 communication with the IDE.
776 =end
777 unless @attached
778 set_client( debugger )
779 @attached = true
780 interrupt
781 else
782 false
783 end
784 end
785
786 def client
787 =begin edoc
788 Method returning a reference to the client object.
789
790 @return reference to the client object.
791 =end
792 @client
793 end
794
795 def set_client( debugger )
796 =begin edoc
797 Method to set the client handling the connection.
798
799 @param debugger reference to the object handling the connection
800 =end
801 @client = Client.new( debugger )
802 DEBUGGER__.stdout = @client
803 end
804
805 def attached?
806 =begin edoc
807 Method returning the attached state.
808
809 @return flag indicating, whether the debugger is attached to the IDE.
810 =end
811 @attached
812 end
813
814 def quit(status = 0)
815 =begin edoc
816 Method to quit the debugger.
817
818 @param status exit status of the program
819 =end
820 @client.printf_exit(status)
821 STDERR.flush; STDOUT.flush
822 end
823
824 def waiting
825 =begin edoc
826 Method returning the waiting list.
827
828 @return the waiting list
829 =end
830 @waiting
831 end
832
833 def set_last_thread(th)
834 =begin edoc
835 Method to remember the last thread.
836
837 @param th thread to be remembered.
838 =end
839 @last_thread = th
840 end
841
842 def suspend
843 =begin edoc
844 Method to suspend the program being debugged.
845 =end
846 Thread.critical = true
847 make_thread_list
848 for th, in @thread_list
849 next if th == Thread.current
850 context(th).set_suspend
851 end
852 Thread.critical = false
853 # Schedule other threads to suspend as soon as possible.
854 Thread.pass
855 end
856
857 def resume
858 =begin edoc
859 Method to resume the program being debugged.
860 =end
861 Thread.critical = true
862 make_thread_list
863 for th, in @thread_list
864 next if th == Thread.current
865 context(th).clear_suspend
866 end
867 waiting.each do |th|
868 th.run
869 end
870 waiting.clear
871 Thread.critical = false
872 # Schedule other threads to restart as soon as possible.
873 Thread.pass
874 end
875
876 def context(thread=Thread.current)
877 =begin edoc
878 Method returning the context of a thread.
879
880 @param th threat the context is requested for
881 @return context object for the thread
882 =end
883 c = thread[:__debugger_data__]
884 unless c
885 thread[:__debugger_data__] = c = Context.new
886 end
887 c
888 end
889
890 def interrupt
891 =begin edoc
892 Method to stop execution at the next instruction.
893 =end
894 context(@last_thread).stop_next
895 end
896
897 def get_thread(num)
898 =begin edoc
899 Method returning a thread by number.
900
901 @param num thread number (int)
902 @return thread with the requested number
903 =end
904 th = @thread_list.index(num)
905 unless th
906 @stdout.print "No thread ##{num}\n"
907 throw :debug_error
908 end
909 th
910 end
911
912 def thread_list(num)
913 =begin edoc
914 Method to list the state of a thread.
915
916 @param num thread number (int)
917 =end
918 th = get_thread(num)
919 if th == Thread.current
920 @stdout.print "+"
921 else
922 @stdout.print " "
923 end
924 @stdout.printf "%d ", num
925 @stdout.print th.inspect, "\t"
926 file = context(th).instance_eval{@file}
927 if file
928 @stdout.print file,":",context(th).instance_eval{@line}
929 end
930 @stdout.print "\n"
931 end
932
933 def thread_list_all
934 =begin edoc
935 Method to list the state of all threads.
936 =end
937 for th in @thread_list.values.sort
938 thread_list(th)
939 end
940 end
941
942 def make_thread_list
943 =begin edoc
944 Method to create a thread list.
945 =end
946 hash = {}
947 for th in Thread::list
948 next if (th[:__debugger_hidden__])
949 if @thread_list.key? th
950 hash[th] = @thread_list[th]
951 else
952 @max_thread += 1
953 hash[th] = @max_thread
954 end
955 end
956 @thread_list = hash
957 end
958
959 def debug_thread_info(input, binding_)
960 =begin edoc
961 Method handling the thread related debug commands.
962
963 @param input debug command (String)
964 @param binding_ reference to the binding object
965 =end
966 case input
967 when /^l(?:ist)?/
968 make_thread_list
969 thread_list_all
970
971 when /^c(?:ur(?:rent)?)?$/
972 make_thread_list
973 thread_list(@thread_list[Thread.current])
974
975 when /^(?:sw(?:itch)?\s+)?(\d+)/
976 make_thread_list
977 th = get_thread($1.to_i)
978 if th == Thread.current
979 @stdout.print "It's the current thread.\n"
980 else
981 thread_list(@thread_list[th])
982 context(th).stop_next
983 th.run
984 return :cont
985 end
986
987 when /^stop\s+(\d+)/
988 make_thread_list
989 th = get_thread($1.to_i)
990 if th == Thread.current
991 @stdout.print "It's the current thread.\n"
992 elsif th.stop?
993 @stdout.print "Already stopped.\n"
994 else
995 thread_list(@thread_list[th])
996 context(th).suspend
997 end
998
999 when /^resume\s+(\d+)/
1000 make_thread_list
1001 th = get_thread($1.to_i)
1002 if th == Thread.current
1003 @stdout.print "It's the current thread.\n"
1004 elsif !th.stop?
1005 @stdout.print "Already running."
1006 else
1007 thread_list(@thread_list[th])
1008 th.run
1009 end
1010 end
1011 end
1012
1013 def eventLoop
1014 =begin edoc
1015 Method calling the main event loop.
1016 =end
1017 @client.eventLoop
1018 end
1019
1020 def eventPoll
1021 =begin edoc
1022 Method calling the main function polling for an event sent by the IDE.
1023 =end
1024 @client.eventPoll
1025 end
1026
1027 def traceRuby?
1028 =begin edoc
1029 Method to check, if we should trace into the Ruby interpreter libraries.
1030 =end
1031 @client.traceRuby?
1032 end
1033 end
1034
1035
1036 class Context
1037 def eventLoop
1038 =begin edoc
1039 Method calling the main event loop.
1040 =end
1041 DEBUGGER__.eventLoop
1042 end
1043
1044 def eventPoll
1045 =begin edoc
1046 Method calling the main function polling for an event sent by the IDE.
1047 =end
1048 DEBUGGER__.eventPoll
1049 end
1050
1051 def traceRuby?
1052 =begin edoc
1053 Method to check, if we should trace into the Ruby interpreter libraries.
1054 =end
1055 DEBUGGER__.traceRuby?
1056 end
1057 end
1058
1059 require 'DebugProtocol'
1060
1061 class Client
1062 =begin edoc
1063 Class handling the connection to the IDE.
1064 =end
1065 def initialize( debugger )
1066 =begin edoc
1067 Constructor
1068
1069 @param debugger reference to the object having the IDE connection.
1070 =end
1071 @debugger = debugger
1072 end
1073
1074 def eventLoop
1075 =begin edoc
1076 Method calling the main event loop.
1077 =end
1078 @debugger.eventLoop()
1079 end
1080
1081 def eventPoll
1082 =begin edoc
1083 Method calling the main function polling for an event sent by the IDE.
1084 =end
1085 @debugger.eventPoll()
1086 end
1087
1088 def traceRuby?
1089 =begin edoc
1090 Method to check, if we should trace into the Ruby interpreter libraries.
1091 =end
1092 @debugger.traceRuby
1093 end
1094
1095 def printf( *args )
1096 =begin edoc
1097 Method to print something to the IDE.
1098
1099 @param *args Arguments to be printed.
1100 =end
1101 @debugger.write("#{args.join(', ')}\n")
1102 end
1103
1104 def printf_line(frames)
1105 =begin edoc
1106 Method to report the current line and the current stack trace to the IDE.
1107
1108 @param frames reference to the array containing the stack trace.
1109 =end
1110 fr_list = []
1111 for bind, file, line, id in frames
1112 break unless bind
1113 break if file =~ /\(eval\)/
1114 fr_list << [file, line, id ? id.id2name : '']
1115 end
1116
1117 @debugger.write("%s%s\n" % [ResponseLine, fr_list.inspect])
1118 end
1119
1120 def printf_excn(exclist)
1121 =begin edoc
1122 Method to report an exception to the IDE.
1123
1124 @param exclist info about the exception to be reported
1125 =end
1126 @debugger.write("%s%s\n" % [ResponseException, exclist.inspect])
1127 end
1128
1129 def printf_scriptExcn(exclist)
1130 =begin edoc
1131 Method to report a ScriptError to the IDE.
1132
1133 @param exclist info about the exception to be reported
1134 =end
1135 @debugger.write("%s%s\n" % [ResponseSyntax, exclist.inspect])
1136 end
1137
1138 def printf_clear_breakpoint(file, line)
1139 =begin edoc
1140 Method to report the deletion of a temporary breakpoint to the IDE.
1141
1142 @param file filename of the breakpoint (String)
1143 @param line line number of the breakpoint (int)
1144 =end
1145 @debugger.write("%s%s,%d\n" % [ResponseClearBreak, file, line])
1146 end
1147
1148 def printf_clear_watchexpression(cond)
1149 =begin edoc
1150 Method to report the deletion of a temporary watch expression to the IDE.
1151
1152 @param cond expression of the watch expression (String)
1153 =end
1154 @debugger.write("%s%s\n" % [ResponseClearWatch, cond])
1155 end
1156
1157 def printf_exit(status)
1158 =begin edoc
1159 Method to report the exit status to the IDE.
1160
1161 @param status exit status of the program (int)
1162 =end
1163 @debugger.write("%s%d\n" % [ResponseExit, status])
1164 end
1165 end
1166
1167 class Context
1168 def current_frame
1169 =begin edoc
1170 Method returning the current execution frame.
1171
1172 @return current execution frame
1173 =end
1174 @frames[@frame_pos]
1175 end
1176
1177 def get_frame(frameno)
1178 =begin edoc
1179 Method returning a specific execution frame.
1180
1181 @param frameno frame number of the frame to be returned (int)
1182 @return the requested execution frame
1183 =end
1184 @frames[frameno]
1185 end
1186
1187 def current_binding
1188 =begin edoc
1189 Method returning the binding object of the current execution frame.
1190
1191 @return binding object of the current execution frame
1192 =end
1193 @frames[@frame_pos][0]
1194 end
1195
1196 def get_binding(frameno)
1197 =begin edoc
1198 Method returning the binding object of a specific execution frame.
1199
1200 @param frameno frame number of the frame (int)
1201 @return the requested binding object
1202 =end
1203 @frames[frameno][0]
1204 end
1205 end
1206
1207 Thread.main["name"] = 'Main'
1208 end

eric ide

mercurial