/[freeride]/freeride/plugins/rubyide_tools_debugger/debugger.rb
ViewVC logotype

Diff of /freeride/plugins/rubyide_tools_debugger/debugger.rb

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.10 by ljulliar, Sun Mar 9 08:54:51 2003 UTC revision 1.11 by ljulliar, Sun Mar 23 22:38:59 2003 UTC
# Line 16  Line 16 
16    
17  require 'open3'  require 'open3'
18  require 'drb/drb'  require 'drb/drb'
19    require 'singleton'
20    require 'rubyide_tools_debugger/breakpoint'
21    
22  module FreeRIDE; module GUI  module FreeRIDE; module GUI
23    
# Line 44  class Debugger < Component Line 46  class Debugger < Component
46      session = nil      session = nil
47      cmd = cmd_mgr.add("App/Run/Debugger", "&Debugger") do |cmd_slot|      cmd = cmd_mgr.add("App/Run/Debugger", "&Debugger") do |cmd_slot|
48        if debugger        if debugger
49          if debugger.manager.running?          if debugger.manager.running?
50            debugger.manager.show            debugger.manager.show
51          else          else
52            debugger.manager.start            debugger.manager.start
53          end          end
54        else        else
55          debugger = base_slot.manager.add          debugger = base_slot.manager.add
56        end        end
# Line 83  class Debugger < Component Line 85  class Debugger < Component
85    
86    include DRbUndumped    include DRbUndumped
87    
88    attr_reader :slot, :running    attr_reader :slot, :running, :debuggee, :plugin
89    
90    ##    ##
91    # Instantiate a new  debugger session . Only one session at a time for now    # Instantiate a new  debugger session . Only one session at a time for now
# Line 96  class Debugger < Component Line 98  class Debugger < Component
98      @plugin.log_info << "Debugger session created #{base_slot.path}"      @plugin.log_info << "Debugger session created #{base_slot.path}"
99   end   end
100    
101      ##
102      # Prompt a message in the status bar
103      #
104      def status(msg)
105        @plugin['/system/ui/current/StatusBar/actions/prompt'].invoke(msg)
106      end
107    
108    ##    ##
109    # Actually start the debugger session. Run the remote debugger,    # Actually start the debugger session. Run the remote debugger,
# Line 109  class Debugger < Component Line 117  class Debugger < Component
117      # initialize variables      # initialize variables
118      @loaded_files = Hash.new      @loaded_files = Hash.new
119      @running = false      @running = false
     @breakpoints = Array.new  
     @breakpoint_subscribers = Hash.new  
120      @action_queue = Array.new      @action_queue = Array.new
121    
122      # open the debugger command pipe      # open the debugger command pipe
# Line 124  class Debugger < Component Line 130  class Debugger < Component
130      @plugin.log_info << "File to debug : #{file}"      @plugin.log_info << "File to debug : #{file}"
131      debuggee_file = File.join("#{@plugin.plugin_configuration.base_path}","debuggee.rb")      debuggee_file = File.join("#{@plugin.plugin_configuration.base_path}","debuggee.rb")
132      command = "ruby -I. -Iso -Iredist -r #{debuggee_file} #{file}"      command = "ruby -I. -Iso -Iredist -r #{debuggee_file} #{file}"
133      puts command      puts command if DEBUG
134    
135      # On Windows/mswin32 build the popen3 method doesn't work because      # On Windows/mswin32 build the popen3 method doesn't work because
136      # the fork() is not supported      # the fork() is not supported
# Line 156  class Debugger < Component Line 162  class Debugger < Component
162        #  @debugSvr.thread.join        #  @debugSvr.thread.join
163      end      end
164    
165      @paused = true      @paused = true
166    
167        # create the watchpoint and breakpoint manager (only after
168        # debuggee is running)
169        @brk_mgr = BreakpointManager.new(self)
170        @watch_mgr = WatchpointManager.new(self)
171    
172      # attach process stdout and err to text console      # attach process stdout and err to text console
173      @actions['attach_stderr'].invoke(@err) unless @err.nil?      @actions['attach_stderr'].invoke(@err) unless @err.nil?
# Line 169  class Debugger < Component Line 180  class Debugger < Component
180      # are received we can act accordingly on the remote debugger      # are received we can act accordingly on the remote debugger
181      @plugin['/system/ui/components/EditPane'].subscribe { |event, slot|      @plugin['/system/ui/components/EditPane'].subscribe { |event, slot|
182        if (event == :notify_slot_add &&  slot.parent.name == 'EditPane')        if (event == :notify_slot_add &&  slot.parent.name == 'EditPane')
183          breakpoint_subscribe(slot)          @brk_mgr.subscribe(slot)
184        end        end
185      }      }
186    
187      # make sure that we also subscribe to existing  edit panes if any      # make sure that we also subscribe to existing  edit panes if any
     
188      @plugin['/system/ui/components/EditPane'].each_slot { |slot|      @plugin['/system/ui/components/EditPane'].each_slot { |slot|
189        breakpoint_subscribe(slot)        @brk_mgr.subscribe(slot)
190      }      }
     
     @actions['start'].invoke  
     @running = true  
     @plugin.log_info << "Debugger session started #{@base_slot.path}"  
   
   end  
191    
192    ##      # start GUI
193    # Subscribe to the breakpoints event queue of an edit pane      @actions['start'].invoke
   #  
   def breakpoint_subscribe(slot)  
194    
195      # Make sure any pending add/delete brkpoints events that occured      # get the list of watches memorized in the GUI and set them up
196      # before this session is cleared      gui_idx=0
197      slot['breakpoints'].queue.clear      @actions['list_watchpoints'].invoke().each do |expr|
198              @watch_mgr.add(expr,gui_idx)
199      # Now subscribe        gui_idx = gui_idx.succ
     sub_id = slot['breakpoints'].subscribe do |event, slot|  
       if event == :notify_queue_join  
         while action = slot.queue.leave  
           cmd, line = action  
           file = slot.parent.data  
           if cmd == 'add'  
             add_breakpoint(file, line)  
           else  
             delete_breakpoint(file, line)  
           end  
         end  
       end  
200      end      end
     @breakpoint_subscribers[slot['breakpoints']] = sub_id  
     puts "dbg subscribe to #{slot.path} breakpoints" if DEBUG  
   end  
201    
202    ##      # All good now!
203    # Unsubscribe from all the  breakpoints event queue at once      @running = true
204    #      @plugin.log_info << "Debugger session started #{@base_slot.path}"
205    def breakpoint_unsubscribe      status("Debugger process started  (#{debugUri}, process id #{@pid})")
     @breakpoint_subscribers.each_pair do |slot,id|  
       slot.unsubscribe(id)  
     end  
     @breakpoint_subscribers = {}  
   end  
206    
207      end
208    
209    ##    ##
210    # Open the pipe where the remote debugger will make a blocking    # Open the pipe where the remote debugger will make a blocking
# Line 251  class Debugger < Component Line 234  class Debugger < Component
234      @actions['detach_stdin'].invoke(@inp)      @actions['detach_stdin'].invoke(@inp)
235      close_pipe()      close_pipe()
236      show_debugline(@file,nil)      show_debugline(@file,nil)
237      breakpoint_unsubscribe()      @brk_mgr.unsubscribe_all()
238      reset_loaded_file()      reset_loaded_file()
239      @running = false      @running = false
240        @debuggee = SilentDebuggee.instance
241      @plugin.log_info << "Debugger session stopped #{@base_slot.path}"      @plugin.log_info << "Debugger session stopped #{@base_slot.path}"
242        status("Debugger process exited")
243    end    end
244    
245    ##    ##
# Line 314  class Debugger < Component Line 299  class Debugger < Component
299    end    end
300    
301    ##    ##
302    # Set up all the break points placed on a given file in the debugger    # add a watch point
   # if it has never been loaded before. Subscribe to the break points slot  
   # of the edit pane so any future changes in the edit pane is  
   #  
   def set_all_breakpoints(file)  
     # Editpane properties keeps track of where the break points are placed  
     # from one FR session to another. So ask the edit pane for the breakpoints  
     lines = @cmd_mgr.command('EditPane/GetBreakpointsForFile').invoke(file)  
     unless lines.nil?  
       lines.each { |line| add_breakpoint(file,line) }  
     end  
   end  
   
   ##  
   # Add a breakpoint in the remote debugger only if it hasn't been set  
   # already  
   #  
   # temp = true means that when the breakpoint is reached we  
   # delete it (used by run to cursor function)  
303    #    #
304    def add_breakpoint(file,line, temp = false)    def add_watchpoint(expr, gui_idx)
305      return unless breakpoint_index(file,line).nil?      @watch_mgr.add(expr,gui_idx)
     idx = @debuggee.add_break_point(file, line, temp)  
     @breakpoints[idx] = [file,line] if temp == false  
     @plugin.log_info << "Set breakpoint #{idx} at #{File.basename(file)}:#{line}"  
306    end    end
     
   ##  
   # Delete a breakpoint  
   #  
   def delete_breakpoint(file,line)  
     if (idx = breakpoint_index(file,line))  
       @breakpoints[idx] = nil  
       done = @debuggee.delete_break_point(idx)  
     end  
     if done  
       @plugin.log_info << "Breakpoint #{idx} deleted."  
     else  
       @plugin.log_info << "Breakpoint #{idx} is not defined."  
     end  
   end  
   
307    
308    ##    ##
309    # Given a file, line couple find the corresponding break point index in the    # Delete a watch point
   # @breakpoint Array. For breakpoints there is no real need to replicate the  
   # breakpoint list in this class because the file,line couples uniquely identifies  
   # a breakpoint. Watch points however have no file,line associated with it and  
   # we must keep track of their index number when created so that we can delete  
   # them later on.  
310    #    #
311    def breakpoint_index(file,line)    def delete_watchpoint(expr,gui_idx)
312      @breakpoints.index [file,line]      @watch_mgr.delete(expr,gui_idx)
313    end    end
314    
315    
316    ##    ##
317    # Run debugger up to where the cursor is. The only way to do this is    # Run debugger up to where the cursor is. The only way to do this is
318    # to place a temporary breakpoint on the targeted line. Using "next nnn"    # to place a temporary breakpoint on the targeted line. Using "next nnn"
# Line 378  class Debugger < Component Line 322  class Debugger < Component
322      line = cursor_line()      line = cursor_line()
323      return if line == @line      return if line == @line
324      file = @plugin['/system/ui/current/EditPane'].data      file = @plugin['/system/ui/current/EditPane'].data
325      add_breakpoint(file, line, true)      @brk_mgr.add(file, line, true)
326      send_command('cont')      send_command('cont')
327    end    end
328    
# Line 452  class Debugger < Component Line 396  class Debugger < Component
396    ##    ##
397    # Originally called by the remote debugger to print the debugger prompt and    # Originally called by the remote debugger to print the debugger prompt and
398    # wait for the next end user command typed on the keyboard. In the FreeRIDE    # wait for the next end user command typed on the keyboard. In the FreeRIDE
399    # version it simply waits for the next event to come on the "actions" pipe.    # version it simply waits for the next debugger command
400    #      #  
401    def prompt( str )    def prompt( str )
402    
# Line 485  class Debugger < Component Line 429  class Debugger < Component
429    end    end
430    
431    def printf( *args )    def printf( *args )
     stg = sprintf( *args )  
     if ( (stg =~ /(.*):(\d+):/) != nil)  
       prev_file = @file  
       @file = $1  
       @line = $2.to_i  
       puts "File: #{@file}, line: #{@line}" if DEBUG  
   
       clear_debugline(prev_file) unless prev_file == @file  
       show_debugline(@file, @line)  
432    
433        # first time we are stopping in this file? Then keep track of it      # See debugger output
434        add_loaded_file(@file) unless check_loaded_file(@file)      stdout.printf( *args ) if DEBUG
435    
436        stg = sprintf( *args )
437        case stg
438          when /(.*):(\d+):/
439            prev_file = @file
440            @file = $1
441            @line = $2.to_i
442            puts "File: #{@file}, line: #{@line}" if DEBUG
443    
444            clear_debugline(prev_file) unless prev_file == @file
445            show_debugline(@file, @line)
446    
447            # first time we are stopping in this file? Then keep track of it
448            add_loaded_file(@file) unless check_loaded_file(@file)
449    
450          when /^Breakpoint (\d+), (\w)/
451            idx = $1.to_i
452            method = $2
453            brkpt = @brk_mgr[idx]
454            status("Breakpoint reached at #{File.basename(brkpt.file)}, line #{brkpt.line}")
455            
456          when /^Watchpoint (\d+), (\w+) at (.*):(.*)$/
457            # caution!! sometimes the line number is instead the method
458            # name so we cannot use \d+ in the last ( )
459            idx = $1.to_i
460            method = $2
461            file = $3
462            pos = $4  
463            expr = @watch_mgr[idx].expr
464            status("Watchpoint reached at #{File.basename(file)}, line #{pos} (#{expr})")
465            
466      end      end
467      # LJ - Uncomment to see debugger output  
     # stdout.printf( *args )  
468    end    end
469    
470    def print( *args )    def print( *args )
# Line 509  class Debugger < Component Line 473  class Debugger < Component
473    end    end
474    
475    ##    ##
476      # Inform the debugger that the debuggee has just loaded a new file
477      # This method is called from the debuggee process
478      # For now we just set up breakpoints associated with this file
479      #
480      def file_loaded(file)
481        @brk_mgr.set_all(file)
482      end
483    
484      ##
485    # Update the local variable list and ask the renderer to reflect this in the UI    # Update the local variable list and ask the renderer to reflect this in the UI
486    #    #
487    def update_local_variables()    def update_local_variables()
# Line 559  class Debugger < Component Line 532  class Debugger < Component
532    #    #
533    def update_frame_list()    def update_frame_list()
534      @fr_list = @debuggee.fr_frame_list_all()      @fr_list = @debuggee.fr_frame_list_all()
     #puts "fr_info #{fr_info.inspect}"  
535      @actions['update_frame_list'].invoke(@fr_list)      @actions['update_frame_list'].invoke(@fr_list)
536    end    end
537    
# Line 570  class Debugger < Component Line 542  class Debugger < Component
542      level = @debuggee.fr_select_frame(fr_info[0])      level = @debuggee.fr_select_frame(fr_info[0])
543      if fr_info[0] != level      if fr_info[0] != level
544        error_msg = "ERROR!!! selected frame level #{fr_info[0]} could not be selected. Now #{level}"        error_msg = "ERROR!!! selected frame level #{fr_info[0]} could not be selected. Now #{level}"
       puts error_msg  
545        @plugin.log_error << error_msg        @plugin.log_error << error_msg
546      else      else
547        @file = fr_info[1]        @file = fr_info[1]
# Line 594  class Debugger < Component Line 565  class Debugger < Component
565      "#{fr_info[0]}- #{File.basename(fr_info[1])}:#{fr_info[2]} - #{fr_info[3]}"      "#{fr_info[0]}- #{File.basename(fr_info[1])}:#{fr_info[2]} - #{fr_info[3]}"
566    end    end
567    
568    # evaluate an expression in the current context    ##
569      # Evaluate an expression in the current context.
570      #
571      # Ouput: the inspected value (not the value itself)
572    def eval_expr(expr)    def eval_expr(expr)
573      @debuggee.fr_eval_expr(expr)      # rk: remove the leading and trailing quote
574    end      @debuggee.fr_eval_expr(expr)[1..-2]
   
   def breakpoint_reached(idx)  
     # FIXME: to be implemented (probably show a message in the status bar. Must also  
     # call this method from the debuggee.  
575    end    end
576    
577    ##    ##
# Line 620  class Debugger < Component Line 590  class Debugger < Component
590        close() if @action == 'CLOSE'        close() if @action == 'CLOSE'
591        # do this last because it kills the thread it runs in!!        # do this last because it kills the thread it runs in!!
592        @debugSvr.stop_service        @debugSvr.stop_service
593          @debuggee = SilentDebuggee.instance
594      end      end
595    end    end
596    
# Line 629  class Debugger < Component Line 600  class Debugger < Component
600      STDOUT      STDOUT
601    end    end
602    
603  end  # module Debugger  end  # class Debugger
604    
605    ##
606    # Silent Debuggee class used whenever the
607    # debuggee process is stopped and we still want to
608    # avoid exception if a remote method is called
609    class SilentDebuggee
610      include Singleton
611      
612      def fr_eval_expr(expr)
613        return '"can\'t eval - process stopped"'
614      end
615    
616      def method_missing(method_id, *args)
617        # capture all the missing methods and do nothing
618      end
619    end
620    
621  end; end  end; end

Legend:
Removed from v.1.10  
changed lines
  Added in v.1.11

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26