# Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
# Copyright (C) 2000 Information-technology Promotion Agency, Japan
# Copyright (C) 2000-2003 NAKAMURA, Hiroshi <nahi@ruby-lang.org>
require 'continuation' unless RUBY_ENGINE == 'jruby'
if $SAFE > 0
STDERR.print "-r debug.rb is not available in safe mode\n"
exit 1
end
require 'tracer'
require 'pp'
class Tracer
def Tracer.trace_func(*vars)
Single.trace_func(*vars)
end
end
SCRIPT_LINES__ = {} unless defined? SCRIPT_LINES__
class DEBUGGER__
MUTEX = Mutex.new
class Context
DEBUG_LAST_CMD = []
begin
require 'readline'
def readline(prompt, hist)
Readline::readline(prompt, hist)
end
rescue LoadError
def readline(prompt, hist)
STDOUT.print prompt
STDOUT.flush
line = STDIN.gets
exit unless line
line.chomp!
line
end
USE_READLINE = false
end
def initialize
if Thread.current == Thread.main
@stop_next = 1
else
@stop_next = 0
end
@last_file = nil
@file = nil
@line = nil
@no_step = nil
@frames = []
@finish_pos = 0
@trace = false
@catch = "StandardError"
@suspend_next = 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 suspend_all
DEBUGGER__.suspend
end
def resume_all
DEBUGGER__.resume
end
def check_suspend
while MUTEX.synchronize {
if @suspend_next
DEBUGGER__.waiting.push Thread.current
@suspend_next = false
true
end
}
end
end
def trace?
@trace
end
def set_trace(arg)
@trace = arg
end
def stdout
DEBUGGER__.stdout
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(str, binding)
begin
eval(str, binding)
rescue StandardError, ScriptError => e
at = eval("caller(1)", binding)
stdout.printf "%s:%s\n", at.shift, e.to_s.sub(/\(eval\):1:(in `.*?':)?/, '')
for i in at
stdout.printf "\tfrom %s\n", i
end
throw :debug_error
end
end
def debug_silent_eval(str, binding)
begin
eval(str, binding)
rescue StandardError, ScriptError
nil
end
end
def var_list(ary, binding)
ary.sort!
for v in ary
stdout.printf " %s => %s\n", v, eval(v.to_s, binding).inspect
end
end
def debug_variable_info(input, binding)
case input
when /^\s*g(?:lobal)?\s*$/
var_list(global_variables, binding)
when /^\s*l(?:ocal)?\s*$/
var_list(eval("local_variables", binding), binding)
when /^\s*i(?:nstance)?\s+/
obj = debug_eval($', binding)
var_list(obj.instance_variables, obj.instance_eval{binding()})
when /^\s*c(?:onst(?:ant)?)?\s+/
obj = debug_eval($', binding)
unless obj.kind_of? Module
stdout.print "Should be Class/Module: ", $', "\n"
else
var_list(obj.constants, obj.module_eval{binding()})
end
end
end
def debug_method_info(input, binding)
case input
when /^i(:?nstance)?\s+/
obj = debug_eval($', binding)
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(false).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
num = DEBUGGER__.instance_eval{@thread_list[Thread.current]}
unless num
DEBUGGER__.make_thread_list
num = DEBUGGER__.instance_eval{@thread_list[Thread.current]}
end
num
end
def debug_command(file, line, id, binding)
MUTEX.lock
unless RUBY_ENGINE == 'jruby'
unless defined?($debugger_restart) and $debugger_restart
callcc{|c| $debugger_restart = c}
end
end
set_last_thread(Thread.current)
frame_pos = 0
binding_file = file
binding_line = line
previous_line = nil
if ENV['EMACS']
stdout.printf "\032\032%s:%d:\n", binding_file, binding_line
else
stdout.printf "%s:%d:%s", binding_file, binding_line,
line_at(binding_file, binding_line)
end
@frames[0] = [binding, file, line, id]
display_expressions(binding)
prompt = true
while prompt and input = readline("(rdb:%d) "%thnum(), true)
catch(:debug_error) do
if input == ""
next unless DEBUG_LAST_CMD[0]
input = DEBUG_LAST_CMD[0]
stdout.print input, "\n"
else
DEBUG_LAST_CMD[0] = input
end
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(?:reak)?\s+(?:(.+):)?([^.:]+)$/
pos = $2
if $1
klass = debug_silent_eval($1, binding)
file = $1
end
if pos =~ /^\d+$/
pname = pos
pos = pos.to_i
else
pname = pos = pos.intern.id2name
end
break_points.push [true, 0, klass || file, pos]
stdout.printf "Set breakpoint %d at %s:%s\n", break_points.size, klass || file, pname
when /^\s*b(?:reak)?\s+(.+)[#.]([^.:]+)$/
pos = $2.intern.id2name
klass = debug_eval($1, binding)
break_points.push [true, 0, klass, pos]
stdout.printf "Set breakpoint %d at %s.%s\n", break_points.size, klass, pos
when /^\s*wat(?:ch)?\s+(.+)$/
exp = $1
break_points.push [true, 1, exp]
stdout.printf "Set watchpoint %d:%s\n", break_points.size, exp
when /^\s*b(?:reak)?$/
if break_points.find{|b| b[1] == 0}
n = 1
stdout.print "Breakpoints:\n"
break_points.each do |b|
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
Loading ...