|
From: <caw...@us...> - 2007-02-20 14:10:16
|
Revision: 1986
http://svn.sourceforge.net/rubyeclipse/?rev=1986&view=rev
Author: cawilliams
Date: 2007-02-20 06:10:08 -0800 (Tue, 20 Feb 2007)
Log Message:
-----------
renamed debugger files, apply Martin' classic-debug patch
Added Paths:
-----------
trunk/org.rubypeople.rdt.launching/ruby/classic-debug-verbose.rb
trunk/org.rubypeople.rdt.launching/ruby/classic-debug.rb
Added: trunk/org.rubypeople.rdt.launching/ruby/classic-debug-verbose.rb
===================================================================
--- trunk/org.rubypeople.rdt.launching/ruby/classic-debug-verbose.rb (rev 0)
+++ trunk/org.rubypeople.rdt.launching/ruby/classic-debug-verbose.rb 2007-02-20 14:10:08 UTC (rev 1986)
@@ -0,0 +1,3 @@
+module DebugVerbose
+end
+require 'eclipseDebug'
\ No newline at end of file
Added: trunk/org.rubypeople.rdt.launching/ruby/classic-debug.rb
===================================================================
--- trunk/org.rubypeople.rdt.launching/ruby/classic-debug.rb (rev 0)
+++ trunk/org.rubypeople.rdt.launching/ruby/classic-debug.rb 2007-02-20 14:10:08 UTC (rev 1986)
@@ -0,0 +1,1189 @@
+# Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
+# Copyright (C) 2000 Information-technology Promotion Agency, Japan
+require 'cgi'
+require 'thread'
+
+# REMOTE_DEBUG_PORT is the port on which the debugger waits for commands from a
+# front-end.
+#
+# RDT note: if you change this, you must also change the corresponding port in
+# org.rubypeople.rdt.internal.debug.core.RubyDebuggerProxy
+REMOTE_DEBUG_PORT = (defined? $RemoteDebugPort) ? $RemoteDebugPort : 1098
+
+# VERBOSE_DEBUGGER prints the communication between a front-end and ruby
+# debugger on stderr. If you have started a front-end debug session (and use
+# default preferences for colors of streams), the communication will be printed
+# in red letters to the front-end console.
+VERBOSE_DEBUGGER = defined? DebugVerbose
+
+class PrinterMultiplexer
+ def initialize
+ @printers = []
+ end
+
+ def addPrinter(printer)
+ @printers << printer
+ end
+
+ def method_missing(methodName, *args)
+ @printers.each { |printer|
+ printer.send(methodName, *args)
+ }
+ end
+end
+
+class XmlPrinter
+
+ def initialize(socket)
+ @socket = socket
+ end
+
+ def out(*params)
+ debugIntern(false, *params)
+ if @socket then
+ @socket.printf(*params)
+ end
+ end
+
+ def printXml(s, *params)
+ out(s, *params)
+ end
+
+ def printError(s, *params)
+ out("<error>" + s + "</error>", *params)
+ end
+
+ def printVariable(name, binding, kind)
+ printVariableValue(name, eval(name, binding), kind)
+ end
+
+ def printVariableValue(name, value, kind)
+ if value == nil then
+ out("<variable name=\"%s\" kind=\"%s\"/>", CGI.escapeHTML(name), kind)
+ return
+ end
+ if value.class().name == "Array" or value.class().name == "Hash" then
+ hasChildren = value.length > 0
+ if value.length == 0 then
+ valueString = "Empty " + value.class().name
+ else
+ valueString = value.class().name + " (" + value.length.to_s + " element(s))"
+ end
+ else
+ hasChildren = value.instance_variables.length > 0 || value.class.class_variables.length > 0
+ valueString = value.to_s
+ if valueString =~ /^\"/ then
+ valueString.slice!(1..(valueString.length)-2)
+ end
+ end
+ out("<variable name=\"%s\" kind=\"%s\" value=\"%s\" type=\"%s\" hasChildren=\"%s\" objectId=\"%#+x\"/>", CGI.escapeHTML(name), kind, CGI.escapeHTML(valueString), value.class(), hasChildren, value.respond_to?(:object_id) ? value.object_id : value.id)
+ end
+
+ def printBreakpoint(n, debugFuncName, file, pos)
+ out("<breakpoint file=\"%s\" line=\"%s\" threadId=\"%s\"/>", file, pos, DEBUGGER__.get_thread_num())
+ end
+
+ def printException(file, pos, exception)
+ out("<exception file=\"%s\" line=\"%s\" type=\"%s\" message=\"%s\" threadId=\"%s\"/>", file, pos, exception.class, CGI.escapeHTML(exception.to_s), DEBUGGER__.get_thread_num())
+ end
+
+ def printStepEnd(file, line, framesCount)
+ out("<suspended file=\"%s\" line=\"%s\" frames=\"%s\" threadId=\"%s\"/>", file, line, framesCount, DEBUGGER__.get_thread_num())
+ end
+
+ def printFrame(pos, n, file, line, id)
+ out("<frame no=\"%s\" file=\"%s\" line=\"%s\"/>", n, file, line)
+ end
+
+ def printThread(num, thread)
+ out("<thread id=\"%s\" status=\"%s\"/>", num, thread.status)
+ end
+
+ def printLoadResult(file, exception=nil)
+ if exception then
+ out("<loadResult file=\"%s\" exceptionType=\"%s\" exceptionMessage=\"%s\"/>", file, exception.class, CGI.escapeHTML(exception.to_s))
+ else
+ out("<loadResult file=\"%s\" status=\"OK\"/>", file)
+ end
+ end
+
+ def debug(*params)
+ debugIntern(true, *params)
+ end
+
+ def debugIntern(escape, *params)
+ if VERBOSE_DEBUGGER then
+ output = sprintf(*params)
+ output = CGI.escapeHTML(output) if escape
+ STDERR.print(output)
+# STDERR.print(' [[' + caller(0)[2].sub(/[^:]*:/, '') + ' ')
+# STDERR.print(Thread.current.to_s + ']]')
+ STDERR.print("\n")
+ end
+ end
+end
+
+#multiplex = PrinterMultiplexer.new
+#multiplex.addPrinter(XmlPrinter.new(nil))
+#multiplex.addPrinter(XmlPrinter.new(nil))
+#multiplex.printXml("TEST")
+
+require 'socket'
+require 'tracer'
+
+class Tracer
+ def Tracer.trace_func(*vars)
+ Single.trace_func(*vars)
+ end
+end
+
+SCRIPT_LINES__ = {} unless defined? SCRIPT_LINES__
+
+class DEBUGGER__
+
+ class CommandLinePrinter
+ def printXml(s)
+ # print XML only
+ end
+
+ def printVariable(name, binding, kind)
+ stdout.printf " %s => %s\n", name, eval(name, binding).inspect
+ end
+
+ def printBreakpoint(n, debugFuncName, file, pos)
+ stdout.printf "Breakpoint %d, %s at %s:%s\n", n, debugFuncName, file, pos
+ stdout.flush
+ end
+
+ def printFrame(pos, n, file, line, id)
+ if pos == n
+ stdout.printf "--> #%d %s:%s%s\n", n, file, line, id ? ":in `#{id.id2name}'":""
+ else
+ stdout.printf " #%d %s:%s%s\n", n, file, line, id ? ":in `#{id.id2name}'":""
+ end
+ end
+
+ def printException(file, line, exception)
+ stdout.printf "%s:%d: `%s' (%s)\n", file, line, exception, exception.class
+ stdout.flush
+ end
+
+ def printThread(num, thread)
+ if thread == Thread.current
+ stdout.print "+"
+ else
+ stdout.print " "
+ end
+ stdout.printf "%d ", num
+ stdout.print thread.inspect, "\t"
+ file = DEBUGGER__.context(thread).instance_eval{@file}
+ if file
+ stdout.print file, ":", DEBUGGER__.context(thread).instance_eval{@line}
+ end
+ stdout.print "\n"
+ end
+
+
+ def printStepEnd(file, line, framesCount)
+
+ end
+
+ def debug(*params)
+
+ end
+
+ def stdout
+ DEBUGGER__.stdout
+ end
+ end
+
+ class Context
+ attr_reader :shouldResume
+ def initialize
+ @printer = DEBUGGER__.printer
+ @socket = DEBUGGER__.socket
+ @stop_next = 0
+ @last_file = nil
+ @file = nil
+ @line = nil
+ @no_step = nil
+ @frames = []
+ @current_frame = -1
+ @finish_pos = 0
+ @trace = false
+ @catch = nil # "StandardError"
+ @suspend_next = false
+ @shouldResume = false
+ end
+
+ def stop_next(n=1)
+ @stop_next = n
+ end
+
+ def set_suspend
+ @suspend_next = true
+ end
+
+ def clear_suspend
+ @suspend_next = false
+ end
+
+ def stopCurrentThread
+ @printer.debug("Suspending : %s", Thread.current)
+ Thread.stop()
+ @printer.debug("Resumed : %s", Thread.current)
+ end
+
+ def trace?
+ @trace
+ end
+
+ def set_trace(arg)
+ @trace = arg
+ end
+
+ def stdout
+ if @socket then
+ @socket
+ else
+ DEBUGGER__.stdout
+ end
+ end
+
+ def break_points
+ DEBUGGER__.break_points
+ end
+
+ def display
+ DEBUGGER__.display
+ end
+
+ def context(th)
+ DEBUGGER__.context(th)
+ end
+
+ def set_trace_all(arg)
+ DEBUGGER__.set_trace(arg)
+ end
+
+ def set_last_thread(th)
+ DEBUGGER__.set_last_thread(th)
+ end
+
+ def debug_eval_private(str, binding)
+ # evaluates str like "var.@instance_var.@instance_var"
+ # and "var.privateMethod"
+ # return value might be nil
+ # the scan must detect array and hash accesses, which might
+ # themselves contain point separated expressions, e.g.
+ # array[Test.getX].y
+ names = str.scan(/[^\[\]]*(?=\.)|.*\[.*\](?=\.)|.*$/)
+ # names can contain empty strings
+ obj = eval(names[0], binding)
+ (1..names.length-1).each { |i|
+ if names[i] != "" then
+ if names[i].length > 2 && names[i][0..1] == '@@' then
+ @printer.debug("Evaluating (class_var): %s on %s", names[i], obj )
+ obj = obj.class.class_eval("#{names[i]}")
+ else
+ @printer.debug("Evaluating (instance_var): %s on %s", names[i], obj )
+ obj = obj.instance_eval("#{names[i]}")
+ end
+ end
+ }
+ return obj
+ end
+
+ def debug_eval(str, binding, noPrivateInstanceVars = false)
+ begin
+ if noPrivateInstanceVars then
+ val = eval(str, binding)
+ else
+ val = debug_eval_private(str, binding)
+ end
+ val
+ rescue ScriptError, StandardError => error
+ if error.to_s =~ /private method .* called for/ then
+ return debug_eval(str, binding, true)
+ end
+ @printer.debug("Error in debug_eval (noPrivateInstancsVars=%s): %s", noPrivateInstanceVars, error)
+ raise error
+ end
+ end
+
+ def debug_silent_eval(str, binding)
+ begin
+ val = eval(str, binding)
+ val
+ rescue StandardError, ScriptError
+ nil
+ end
+ end
+
+ def var_list(ary, binding, kind)
+ ary.sort!
+ @printer.printXml("<variables>")
+ for v in ary
+ @printer.printVariable(v,binding, kind)
+ end
+ @printer.printXml("</variables>")
+ end
+
+ def printArrayElements(array)
+ index = 0
+ array.each { |e|
+ @printer.printVariableValue('[' + index.to_s + ']', e, 'instance')
+ index += 1
+ }
+ end
+
+ def printHashElements(hash)
+ hash.keys.each { | k |
+ if k.class.name == "String"
+ name = '\'' + k + '\''
+ else
+ name = k.to_s
+ end
+ @printer.printVariableValue(name, hash[k], 'instance')
+ }
+ end
+
+
+ def getConstantsInClass(aClass)
+ constants = aClass.constants() - Object.constants
+ return constants.delete_if { |c| ! aClass.const_defined? c }
+ end
+
+
+ def getBinding(pos)
+ # returns frame info of frame pos, if pos is within bound, nil otherwise
+ pos = @current_frame unless pos
+ pos = pos.to_i - 1
+ if pos < 0 then
+ @printer.debug("ERROR: illegal stack frame, using top frame.")
+ pos = 0
+ end
+ if pos >= @frames.size then
+ @printer.debug("ERROR: given stack frame number %i too high.", pos + 1)
+ pos = @frames.size - 1
+ end
+ @printer.debug("Using frame %s (1-based) for evaluation of variable.", pos + 1)
+ return @frames[pos][0]
+ end
+
+
+ def debug_variable_info(input, binding)
+
+ case input
+ when /^\s*g(?:lobal)?$/
+ var_list(global_variables, binding, 'global')
+
+ when /^\s*l(?:ocal)?\s*(\d+)?$/
+ @printer.debug("Getting binding for frame #{$1}")
+ new_binding = getBinding($1)
+ if new_binding then
+ binding = new_binding
+ end
+ begin
+ #@printer.debug("binding=%s", binding)
+ localVars = eval("local_variables", binding)
+ # v 1.8.1 dies in eval @printer.debug("HERE")
+ if eval('self.to_s', binding) !~ /main/ then
+ localVars << "self"
+ end
+ var_list(localVars, binding, 'local')
+ rescue StandardError => bang
+ @printer.debug("Exception while evaluating local_variables: %s", bang)
+ var_list([], binding, 'local')
+ end
+
+ when /^\s*i(?:nstance)?\s*(\d+)?\s+((?:[\\+-]0x)[\dabcdef]+)?/
+ new_binding = getBinding($1)
+ if new_binding then
+ binding = new_binding
+ end
+ begin
+ @printer.printXml("<variables>")
+ if $2 then
+ obj = ObjectSpace._id2ref($2.hex)
+ if (!obj) then
+ @printer.debug("unknown object id : %s", $2)
+ end
+ else
+ obj = debug_eval($', binding)
+ end
+ if (obj.class.name == "Array") then
+ printArrayElements(obj)
+ return
+ end
+ if (obj.class.name == "Hash") then
+ printHashElements(obj)
+ return
+ end
+ @printer.debug("%s", obj)
+ instanceBinding = obj.instance_eval{binding()}
+ obj.instance_variables.each {
+ | instanceVar |
+ @printer.printVariable(instanceVar, instanceBinding, 'instance')
+ }
+ classBinding = obj.class.class_eval('binding()')
+ obj.class.class_variables.each {
+ | classVar |
+ @printer.printVariable(classVar, classBinding, 'class')
+ }
+ # I'd like to optimize getting the constants, but they are more dynamic
+ # than one would expect from true constants.
+ getConstantsInClass(obj.class).each {
+ | constant |
+ @printer.printVariable(constant, classBinding, 'constant')
+ }
+ rescue StandardError => error
+ @printer.debug("%s", error)
+ ensure
+ @printer.printXml("</variables>")
+ end
+
+
+ when /^\s*inspect\s*(\d+)?\s+/
+ new_binding = getBinding($1)
+ if new_binding then
+ binding = new_binding
+ end
+ begin
+ obj = debug_eval($', binding, true)
+ rescue ScriptError, StandardError => error
+ @printer.printXml("<processingException type=\"%s\" message=\"%s\"/>", error.class, error.message)
+ return
+ end
+ @printer.debug("%s", obj)
+ @printer.printXml("<variables>")
+ @printer.printVariableValue($', obj, "local")
+ @printer.printXml("</variables>")
+
+
+ end
+ end
+
+ def debug_method_info(input, binding)
+ case input
+ when /^i(:?nstance)?\s+/
+ obj = debug_eval($', binding) # correct highlighting since RDT editor does not recognize $'
+
+ len = 0
+ for v in obj.methods.sort
+ len += v.size + 1
+ if len > 70
+ len = v.size + 1
+ stdout.print "\n"
+ end
+ stdout.print v, " "
+ end
+ stdout.print "\n"
+
+ else
+ obj = debug_eval(input, binding)
+ unless obj.kind_of? Module
+ stdout.print "Should be Class/Module: ", input, "\n"
+ else
+ len = 0
+ for v in obj.instance_methods.sort
+ len += v.size + 1
+ if len > 70
+ len = v.size + 1
+ stdout.print "\n"
+ end
+ stdout.print v, " "
+ end
+ stdout.print "\n"
+ end
+ end
+ end
+
+ def thnum(thread=Thread.current)
+ num = DEBUGGER__.instance_eval{@thread_list[thread]}
+ unless num
+ DEBUGGER__.make_thread_list
+ num = DEBUGGER__.instance_eval{@thread_list[thread]}
+ end
+ num
+ end
+
+ def processInput(input)
+ binding, file, line, id = @frames[0]
+ input.split(";").each {
+ | singleCommand |
+ readUserInput(binding, file, line, singleCommand.strip)
+ }
+ end
+
+ def readUserInput(binding, binding_file, binding_line, input)
+
+ @printer.debug("Processing #{input}, binding=%s", binding)
+ @shouldResume = false
+ frame_pos = 0
+ previous_line = nil
+ display_expressions(binding)
+
+
+
+ case input
+ when /^\s*tr(?:ace)?(?:\s+(on|off))?(?:\s+(all))?$/
+ if defined?( $2 )
+ if $1 == 'on'
+ set_trace_all true
+ else
+ set_trace_all false
+ end
+ elsif defined?( $1 )
+ if $1 == 'on'
+ set_trace true
+ else
+ set_trace false
+ end
+ end
+ if trace?
+ stdout.print "Trace on.\n"
+ else
+ stdout.print "Trace off.\n"
+ end
+
+ when /^\s*b\s+((?:.*?:)?.+)$/
+ #@printer.debug("S")
+ pos = $1
+ if pos.index(":")
+ file, pos = pos.split(":")
+ end
+ file = File.basename(file)
+ if pos =~ /^\d+$/
+ pname = pos
+ pos = pos.to_i
+ else
+ pname = pos = pos.intern.id2name
+ end
+ # TODO: pname is not used
+ break_points.push [true, 0, file, pos]
+ @printer.printXml("<breakpointAdded no=\"%d\" location=\"%s:%s\"/>", break_points.size, file, pos)
+
+ when /^\s*delete\s+(\d+)$/
+ pos = $1.to_i
+ if pos < 1 || pos > break_points.length
+ @printer.printXml("<error>Breakpoint number out of bounds: %d. There are currently %d breakpoints defined.</error>", pos, break_points.length )
+ else
+ break_points.delete_at(pos-1)
+ @printer.printXml("<breakpointDeleted no=\"%d\"/>", pos)
+ end
+
+ # when /^\s*wat(?:ch)?\s+(.+)$/
+ # exp = $1
+ # break_points.push [true, 1, exp]
+ # stdout.printf "Set watchpoint %d\n", break_points.size, exp
+
+ # when /^\s*b(?:reak)?$/
+ # if break_points.find{|b| b[1] == 0}
+ # n = 1
+ # stdout.print "Breakpoints:\n"
+ # for b in break_points
+ # if b[0] and b[1] == 0
+ # stdout.printf " %d %s:%s\n", n, b[2], b[3]
+ # end
+ # n += 1
+ # end
+ # end
+ # if break_points.find{|b| b[1] == 1}
+ # n = 1
+ # stdout.print "\n"
+ # stdout.print "Watchpoints:\n"
+ # for b in break_points
+ # if b[0] and b[1] == 1
+ # stdout.printf " %d %s\n", n, b[2]
+ # end
+ # n += 1
+ # end
+ # end
+ # if break_points.size == 0
+ # stdout.print "No breakpoints\n"
+ # else
+ # stdout.print "\n"
+ # end
+
+ # when /^\s*del(?:ete)?(?:\s+(\d+))?$/
+ # pos = $1
+ # unless pos
+ # input = readline("Clear all breakpoints? (y/n) ", false)
+ # if input == "y"
+ # for b in break_points
+ # b[0] = false
+ # end
+ # end
+ # else
+ # pos = pos.to_i
+ # if break_points[pos-1]
+ # break_points[pos-1][0] = false
+ # else
+ # stdout.printf "Breakpoint %d is not defined\n", pos
+ # end
+ # end
+
+ # when /^\s*disp(?:lay)?\s+(.+)$/
+ # exp = $1
+ # display.push [true, exp]
+ # stdout.printf "%d: ", display.size
+ # display_expression(exp, binding)
+ #
+ # when /^\s*disp(?:lay)?$/
+ # display_expressions(binding)
+ #
+ # when /^\s*undisp(?:lay)?(?:\s+(\d+))?$/
+ # pos = $1
+ # unless pos
+ # input = readline("Clear all expressions? (y/n) ", false)
+ # if input == "y"
+ # for d in display
+ # d[0] = false
+ # end
+ # end
+ # else
+ # pos = pos.to_i
+ # if display[pos-1]
+ # display[pos-1][0] = false
+ # else
+ # stdout.printf "Display expression %d is not defined\n", pos
+ # end
+ # end
+
+ when /^\s*c(?:ont)?$/
+ @shouldResume = true
+
+ when /^\s*s(?:tep)?(?:\s+(\d+))?$/
+ if $1
+ lev = $1.to_i
+ else
+ lev = 1
+ end
+ @stop_next = lev
+ @shouldResume = true
+
+ when /^\s*n(?:ext)?(?:\s+(\d+))?$/
+ if $1
+ lev = $1.to_i
+ else
+ lev = 1
+ end
+ @stop_next = lev
+ @no_step = @frames.size - frame_pos
+ @shouldResume = true
+
+ when /^\s*w(?:here)?$/, /^\s*f(?:rame)?$/
+ display_frames(frame_pos)
+
+ # when /^\s*fin(?:ish)?$/
+ # if frame_pos == @frames.size
+ # stdout.print "\"finish\" not meaningful in the outermost frame.\n"
+ # else
+ # @finish_pos = @frames.size - frame_pos
+ # frame_pos = 0
+ # prompt = false
+ # end
+ when /^\s*f(?:rame)?\s+(\d+)\s*$/
+ @printer.debug("Setting frame to #{$1}")
+ @current_frame = $1.to_i
+
+
+ when /^\s*cat(?:ch)?(?:\s+(.+))?$/
+ # $1 can also be nil
+ @catch = $1
+ @catch = nil if @catch == 'off'
+ if @catch then
+ @printer.debug("Catchpoint set to #{@catch}")
+ else
+ @printer.debug("Catchpoints disabled")
+ end
+
+
+ when /^\s*v(?:ar)?\s+/
+ debug_variable_info($', binding)
+
+ when /^\s*m(?:ethod)?\s+/
+ debug_method_info($', binding)
+
+ when /^\s*th(?:read)?\s+/
+ DEBUGGER__.debug_thread_info($', binding)
+
+ when /^\s*p\s+/
+ stdout.printf "%s\n", debug_eval($', binding).inspect
+
+ when /^\s*load\s+/
+ @printer.debug("loading file: %s", $')
+ begin
+ load $'
+ @printer.printLoadResult($')
+ rescue Exception => error
+ @printer.printLoadResult($', error)
+ end
+
+ else
+ @printer.debug("Unknown input : %s", input)
+ end
+
+
+
+ end
+
+
+
+ def display_expressions(binding)
+ n = 1
+ for d in display
+ if d[0]
+ stdout.printf "%d: ", n
+ display_expression(d[1], binding)
+ end
+ n += 1
+ end
+ end
+
+ def display_expression(exp, binding)
+ stdout.printf "%s = %s\n", exp, debug_silent_eval(exp, binding).to_s
+ end
+
+ def frame_set_pos(binding, file, line, id)
+ if @frames[0] then
+ @frames[0][0] = binding
+ @frames[0][1] = file
+ @frames[0][2] = line
+ @frames[0][3] = id
+ else
+ @frames[0] = [binding, file, line, id]
+ end
+ end
+
+ def display_frames(pos)
+ pos += 1
+ n = 0
+ at = @frames
+ @printer.printXml("<frames>")
+ for bind, file, line, id in at
+ n += 1
+ break unless bind
+ @printer.printFrame(pos, n, file, line, id)
+ end
+ @printer.printXml("</frames>")
+ end
+
+ def debug_funcname(id)
+ if id.nil?
+ "toplevel"
+ else
+ id.id2name
+ end
+ end
+
+ def debug_command(file, line, id, binding)
+ @printer.debug("debug_command, @stop_next=%s, @frames.size=%s", @stop_next, @frames.size)
+ if @stop_next == 0 && @frames.size > 0 then
+ # write suspended only if the suspension was originated by stepping and not before the start
+ # of the program
+ @printer.printStepEnd(file, line, @frames.size)
+ end
+ set_last_thread(Thread.current)
+
+ #readUserInput(binding, file, line )
+ #Thread.stop
+ end
+
+ def check_break_points(file, pos, binding, id)
+ return false if break_points.empty?
+ file = File.basename(file)
+ n = 1
+ for b in break_points
+ @printer.debug("file=%s, pos=%s; breakpoint: %s, %s, %s, %s.\n ", file, pos, b[0], b[1], b[2], b[3])
+ if b[0] # valid
+ if b[1] == 0 and b[2] == file and b[3] == pos # breakpoint
+ @printer.printBreakpoint(n, debug_funcname(id), file, pos)
+ return true
+ elsif b[1] == 1 # watchpoint
+ if debug_silent_eval(b[2], binding)
+ stdout.printf "Watchpoint %d, %s at %s:%s\n", n, debug_funcname(id), file, pos
+ return true
+ end
+ end
+ end
+ n += 1
+ end
+ return false
+ end
+
+ def excn_handle(file, line, id, binding)
+
+ if $!.class <= SystemExit
+ @printer.debug( "SystemExit at %s:%d: `%s' (%s)\n", file, line, $!, $!.class )
+ set_trace_func nil
+ exit
+ end
+ if @catch and ($!.class.ancestors.find { |e| e.to_s == @catch })
+ @printer.printException(file, line, $!)
+ fs = @frames.size
+ tb = caller(0)[-fs..-1]
+ stopCurrentThread
+ @frames[0] = [binding, file, line, id]
+ debug_command(file, line, id, binding)
+ end
+
+ end
+
+ def trace_func(event, file, line, id, binding, klass)
+ Tracer.trace_func(event, file, line, id, binding, klass) if trace?
+
+ @file = file
+ @line = line
+ case event
+ when 'line'
+ DEBUGGER__.printer().debug("trace line, file=%s, line=%s, stop_next=%d, binding=%s", file, line, @stop_next, binding)
+ frame_set_pos(binding, file, line, id)
+ if !@no_step or @frames.size == @no_step
+ @stop_next -= 1
+ @stop_next = -1 if @stop_next < 0
+ elsif @frames.size < @no_step
+ @stop_next = 0 # break here before leaving...
+ else
+ # nothing to do. skipped
+ end
+ if @stop_next == 0 or check_break_points(file, line, binding, id)
+ @no_step = nil
+ debug_command(file, line, id, binding)
+ stopCurrentThread
+ end
+
+ when 'call'
+ DEBUGGER__.printer().debug("trace call, file=%s, line=%s, method=%s", file, line, id.id2name)
+ @frames.unshift [binding, file, line, id]
+ if check_break_points(file, id.id2name, binding, id) or
+ check_break_points(klass.to_s, id.id2name, binding, id) then
+ stopCurrentThread
+ debug_command(file, line, id, binding)
+ end
+
+ when 'c-call'
+ if @frames[0] then
+ @frames[0][1] = file
+ @frames[0][2] = line
+ else
+ @frames[0] = [binding, file, line, id]
+ end
+
+ when 'class'
+ @frames.unshift [binding, file, line, id]
+
+ when 'return', 'end'
+ DEBUGGER__.printer().debug("trace return and end, file=%s, line=%s", file, line)
+ if @frames.size == @finish_pos
+ @stop_next = 1
+ @finish_pos = 0
+ end
+ @frames.shift
+
+ when 'end'
+ DEBUGGER__.printer().debug("trace end, file=%s, line=%s", file, line)
+ @frames.shift
+
+ when 'raise'
+ excn_handle(file, line, id, binding)
+
+ end
+ @last_file = file
+ end
+ end
+
+ trap("INT") { DEBUGGER__.interrupt }
+ @last_thread = Thread::main
+ @max_thread = 1
+ @thread_list = {Thread::main => 1}
+ # break_points' one entry: [valid, type, file, pos]
+ # type: 0 - breakpoint, 1 - watchpoint
+ @break_points = []
+ @display = []
+ @waiting = []
+ @stdout = STDOUT
+
+ class << DEBUGGER__
+ def stdout
+ @stdout
+ end
+
+ def stdout=(s)
+ @stdout = s
+ end
+
+ def display
+ @display
+ end
+
+ def break_points
+ @break_points
+ end
+
+ def waiting
+ @waiting
+ end
+
+ def set_trace( arg )
+ Thread.critical = true
+ make_thread_list
+ for th in @thread_list
+ context(th[0]).set_trace arg
+ end
+ Thread.critical = false
+ end
+
+ def set_last_thread(th)
+ @last_thread = th
+ end
+
+ def suspend
+ printer.debug("Suspending all")
+ Thread.critical = true
+ make_thread_list
+ for th in @thread_list
+ next if th[0] == Thread.current
+ context(th[0]).set_suspend
+ end
+ Thread.critical = false
+ # Schedule other threads to suspend as soon as possible.
+ Thread.pass
+ end
+
+ def resume
+ Thread.critical = true
+ make_thread_list
+ for th in @thread_list
+ next if th[0] == Thread.current
+ context(th[0]).clear_suspend
+ end
+ waiting.each do |th|
+ th.run
+ end
+ waiting.clear
+ Thread.critical = false
+ # Schedule other threads to restart as soon as possible.
+ Thread.pass
+ end
+
+ def context(thread=Thread.current)
+ c = thread[:__debugger_data__]
+ unless c
+ thread[:__debugger_data__] = c = Context.new
+ end
+ c
+ end
+
+ def findThread(context)
+ for thread in Thread::list
+ if context == thread[:__debugger_data__]
+ return thread
+ end
+ end
+ end
+
+ def interrupt
+ context(@last_thread).stop_next
+ end
+
+ def get_thread(num)
+ th = @thread_list.index(num)
+ unless th
+ printer.debug("No thread ##{num}\n")
+ end
+ th
+ end
+
+ def get_thread_num(thread=Thread.current)
+ make_thread_list
+ @thread_list[thread]
+ end
+
+ def print_thread(thread)
+ num = @thread_list[thread]
+ printer.printThread(num, thread)
+ end
+
+ def thread_list_all
+ printer.printXml("<threads>")
+ for num in @thread_list.values.sort
+ printer.printThread(num, get_thread(num))
+ end
+ printer.printXml("</threads>")
+ end
+
+ def make_thread_list
+ hash = {}
+ for th in Thread::list
+ next if th == @@inputReader
+ if @thread_list.key? th
+ hash[th] = @thread_list[th]
+ else
+ @max_thread += 1
+ hash[th] = @max_thread
+ end
+ end
+ @thread_list = hash
+ end
+
+ def debug_thread_info(input, binding)
+ case input
+ when /^l(?:ist)?/
+ make_thread_list
+ thread_list_all
+
+ when /^c(?:ur(?:rent)?)?$/
+ make_thread_list
+ print_thread()
+
+ when /^(?:sw(?:itch)?\s+)?(\d+)/
+ make_thread_list
+ th = get_thread($1.to_i)
+ if th == Thread.current
+ @stdout.print "It's the current thread.\n"
+ else
+ print_thread(th)
+ context(th).stop_next
+ th.run
+ return
+ end
+
+ when /^stop\s+(\d+)/
+ make_thread_list
+ th = get_thread($1.to_i)
+ if th == Thread.current
+ @stdout.print "It's the current thread.\n"
+ elsif th.stop?
+ @stdout.print "Already stopped.\n"
+ else
+ print_thread(th)
+ context(th).suspend
+ end
+
+ when /^resume\s+(\d+)/
+ make_thread_list
+ th = get_thread($1.to_i)
+ if th == Thread.current
+ @stdout.print "It's the current thread.\n"
+ elsif !th.stop?
+ @stdout.print "Already running."
+ else
+ print_thread(th)
+ th.run
+ end
+
+ when /^change\s+(\d+)/
+ make_thread_list
+ th = get_thread($1.to_i)
+ print_thread(th)
+ return context(th)
+ end
+ end
+ end
+
+ @@socket = nil
+ @@printer = nil
+ @@inputReader = nil
+ @@isStarted = false
+
+ def DEBUGGER__.printer
+ @@printer
+ end
+
+ def DEBUGGER__.socket
+ @@socket
+ end
+
+ def DEBUGGER__.isStarted
+ @@isStarted
+ end
+
+ def DEBUGGER__.setStarted
+ @@isStarted = true
+ end
+
+
+ def DEBUGGER__.inputReader
+ @@inputReader
+ end
+
+ def DEBUGGER__.traceOn()
+ set_trace_func @@traceProc
+ Thread.critical = false
+ end
+
+ def DEBUGGER__.traceOff()
+ Thread.critical = true
+ set_trace_func nil
+ end
+
+ def DEBUGGER__.readCommandLoop()
+ sleep(1.0) # workaround for large files with ruby 1.6.8, otherwise parse exceptions
+ loop do
+ sleep(0.1)
+ newData, x, y = IO.select( [socket], nil, nil, 0.001 )
+ next unless newData
+ DEBUGGER__.traceOff()
+ input = newData[0].gets.chomp!
+ input.strip!
+ @@printer.debug("READ #{input}")
+ if !DEBUGGER__.isStarted && input == "cont" then
+ DEBUGGER__.setStarted()
+ DEBUGGER__.traceOn()
+ next
+ end
+ input =~ /^th\s+(\d+)\s*;\s*/
+ if $~ then
+ @@printer.debug("Using context for thread: %s", $1.to_i)
+ context = DEBUGGER__.context(get_thread($1.to_i))
+ input = input[$~[0].length..input.length]
+ else
+ @@printer.debug("Using context for main thread : %s", Thread.main)
+ context = DEBUGGER__.context(Thread.main)
+ end
+ context.processInput(input)
+ if context.shouldResume then
+ threadToResume = DEBUGGER__.findThread(context)
+ end
+ DEBUGGER__.traceOn()
+ next unless threadToResume
+ threadToResume.run()
+ end
+ end
+
+ # use 127.0.0.1 instead of localhost because OSX 10.4
+ server = TCPServer.new('127.0.0.1', REMOTE_DEBUG_PORT)
+ puts "ruby #{RUBY_VERSION} debugger listens on port #{REMOTE_DEBUG_PORT}"
+ $stdout.flush
+ STDERR.sync = true
+ @@socket = server.accept
+ @@printer = XmlPrinter.new(@@socket)
+ @@printer.debug("Socket connection established.")
+
+ @@printer.debug("Starting command reader loop.")
+ @@inputReader = Thread.new {
+ begin
+ DEBUGGER__.readCommandLoop()
+ rescue ScriptError, StandardError => error
+ puts error
+ end
+ }
+
+ @@traceProc = proc { |event, file, line, id, binding, klass, *rest|
+
+ #@@printer.debug("trace %s, %s:%s", event, file, line)
+ next if Thread.current == DEBUGGER__.inputReader
+ next if file =~ /classic-debug.rb$/
+ #@@printer.debug("trace %s, %s:%s", event, file, line)
+ while (!DEBUGGER__.isStarted) do
+ @@printer.debug("Debugging not yet started.")
+ sleep(1)
+ end
+ DEBUGGER__.context.trace_func event, file, line, id, binding, klass
+ }
+
+ @@printer.debug("Setting trace func: %s", @@traceProc)
+ set_trace_func @@traceProc
+end
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|