From 65a5162550f58047974793cdc8067a970b2435c0 Mon Sep 17 00:00:00 2001 From: matz Date: Fri, 13 Aug 1999 05:45:20 +0000 Subject: 1.4.0 git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@520 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- lib/debug.rb | 387 +++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 259 insertions(+), 128 deletions(-) (limited to 'lib/debug.rb') diff --git a/lib/debug.rb b/lib/debug.rb index 90270a3fe7..d2f1da83ff 100644 --- a/lib/debug.rb +++ b/lib/debug.rb @@ -1,13 +1,29 @@ - class DEBUGGER__ + 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 + line.chomp! + line + end + USE_READLINE = false + end + trap("INT") { DEBUGGER__::CONTEXT.interrupt } - $DEBUG = TRUE + $DEBUG = true def initialize @break_points = [] + @display = [] @stop_next = 1 @frames = [nil] - @frame_pos = nil @last_file = nil + @last = [nil, nil] @scripts = {} end @@ -23,185 +39,271 @@ class DEBUGGER__ val rescue at = caller(0) - printf "%s:%s\n", at.shift, $! + STDOUT.printf "%s:%s\n", at.shift, $! for i in at break if i =~ /`debug_(eval|command)'$/ #` - printf "\tfrom %s\n", i + STDOUT.printf "\tfrom %s\n", i end end end def debug_command(file, line, id, binding) + frame_pos = 0 + binding_file = file + binding_line = line + previus_line = nil if (ENV['EMACS'] == 't') - printf "\032\032%s:%d:\n", file, line + STDOUT.printf "\032\032%s:%d:\n", binding_file, binding_line else - printf "%s:%d:%s", file, line, line_at(file, line) + STDOUT.printf "%s:%d:%s", binding_file, binding_line, + line_at(binding_file, binding_line) end - @frames[-1] = binding - STDOUT.print "(rdb:-) " - STDOUT.flush - while input = STDIN.gets - input.chop! + @frames[0] = binding + display_expressions(binding) + while input = readline("(rdb:-) ", true) if input == "" input = DEBUG_LAST_CMD[0] else DEBUG_LAST_CMD[0] = input end + case input - when /^b(reak)?\s+(([^:\n]+:)?.+)/ - pos = $2 - if pos.index ":" + when /^b(?:reak)?\s+((?:[^:\n]+:)?.+)$/ + pos = $1 + if pos.index(":") file, pos = pos.split(":") end file = File.basename(file) if pos =~ /^\d+$/ pname = pos - pos = Integer(pos) + pos = pos.to_i else pname = pos = pos.intern.id2name end - printf "Set breakpoint %d at %s:%s\n", @break_points.size, file, pname - @break_points.push [file, pos] - when /^b(reak)?$/, /^info b(reak)?$/ - n = 0 - for f, p in @break_points - printf "%d %s:%s\n", n, f, p + @break_points.push [true, 0, file, pos] + STDOUT.printf "Set breakpoint %d at %s:%s\n", @break_points.size, file, + pname + + when /^wat(?:ch)?\s+(.+)$/ + exp = $1 + @break_points.push [true, 1, exp] + STDOUT.printf "Set watchpoint %d\n", @break_points.size, exp + + when /^b(?:reak)?$/, /^info b(?:reak)?$/ + 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 - when /^del(ete)?(\s+(\d+))?$/ - pos = $3 + 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 + STDOUT.print "\n" + + when /^del(?:ete)?(?:\s+(\d+))?$/ + pos = $1 unless pos - STDOUT.print "clear all breakpoints? (y/n) " - STDOUT.flush - input = STDIN.gets.chop! + input = readline("clear all breakpoints? (y/n) ", false) if input == "y" - for n in @break_points.indexes - @break_points[n] = nil + for b in @break_points + b[0] = false end end else - pos = Integer(pos) - if @break_points[pos] - bp = @break_points[pos] - printf "Clear breakpoint %d at %s:%s\n", pos, bp[0], bp[1] - @break_points[pos] = nil + pos = pos.to_i + if @break_points[pos-1] + @break_points[pos-1][0] = false else - printf "Breakpoint %d is not defined\n", pos + STDOUT.printf "Breakpoint %d is not defined\n", pos end end - when /^c(ont)?$/ - return - when /^s(tep)?\s*(\d+)?$/ - if $1 - lev = Integer($1) + + when /^disp(?:lay)?\s+(.+)$/ + exp = $1 + @display.push.push [true, exp] + STDOUT.printf " %d: %s = %s\n", @display.size, exp, + debug_eval(exp, binding).to_s + + when /^disp(?:lay)?$/, /^info disp(?:lay)?$/ + display_expressions(binding) + + when /^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 - lev = 1 + 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 - @stop_next = lev + + when /^c(?:ont)?$/ return - when /^n(ext)?\s*(\d+)?$/ + + when /^s(?:tep)?(?:\s+(\d+))?$/ if $1 - lev = Integer($1) + lev = $1.to_i else lev = 1 end @stop_next = lev - @no_step = @frames.size return - when /^up\s*(\d+)?$/ - if $1 - lev = Integer($1) - else - lev = 1 - end - unless @frame_pos - @frame_pos = @frames.size - 1 - end - @frame_pos -= lev - if @frame_pos < 0 - STDOUT.print "at toplevel\n" - @frame_pos = 0 - else - binding = @frames[@frame_pos] - end - when /^down\s*(\d+)??$/ + + when /^n(?:ext)?(?:\s+(\d+))?$/ if $1 - lev = Integer($1) + lev = $1.to_i else lev = 1 end - if lev >= @frames.size or @frame_pos and @frame_pos+lev >= @frames.size - STDOUT.print "at stack bottom\n" - @frame_pos = nil - else - @frame_pos += lev - binding = @frames[@frame_pos] - end - when /^fin(ish)?$/ - @finish_pos = @frames.size + @stop_next = lev + @no_step = @frames.size - frame_pos return - when /^q(uit)?$/ - STDOUT.print "really quit? (y/n) " - STDOUT.flush - input = STDIN.gets.chop! - exit if input == "y" - when /^where$/ - at = caller(4) - for i in at - printf " %s\n", i - end - when /^l(ist)?(\s+(.*))?$/ - if $3 - b, e = $3.split(/[-,]/) - b = Integer(b)-1 - if e - e = Integer(e)-1 + + when /^w(?:here)?$/, /^f(?:rame)?$/ + at = caller(0) + 0.upto(@frames.size - 1) do |n| + if frame_pos == n + STDOUT.printf "--> #%d %s\n", n, at[-(@frames.size - n)] else - e = b + 10 + STDOUT.printf " #%d %s\n", n, at[-(@frames.size - n)] end end - unless b - b = line - 1 - e = line + 9 + + when /^l(?:ist)?(?:\s+(.+))?$/ + if not $1 + b = previus_line ? previus_line + 10 : binding_line - 5 + e = b + 9 + elsif $1 == '-' + b = previus_line ? previus_line - 10 : binding_line - 5 + e = b + 9 + else + b, e = $1.split(/[-,]/) + if e + b = b.to_i + e = e.to_i + else + b = b.to_i - 5 + e = b + 9 + end + end + previus_line = b + STDOUT.printf "[%d, %d] in %s\n", b, e, binding_file + line_at(binding_file, binding_line) + if lines = @scripts[binding_file] and lines != true + n = 0 + b.upto(e) do |n| + if n > 0 && lines[n-1] + if n == binding_line + STDOUT.printf "=> %d %s\n", n, lines[n-1].chomp + else + STDOUT.printf " %d %s\n", n, lines[n-1].chomp + end + end + end + else + STDOUT.printf "no sourcefile available for %s\n", binding_file + end + + when /^up(?:\s+(\d+))?$/ + previus_line = nil + if $1 + lev = $1.to_i + else + lev = 1 + end + frame_pos += lev + if frame_pos >= @frames.size + frame_pos = @frames.size - 1 + STDOUT.print "at toplevel\n" end - p [b,e] - line_at(file, line) - if lines = @scripts[file] and lines != TRUE - n = b+1 - for l in lines[b..e] - printf "%4d %s", n, l - n += 1 - end - else - printf "no sourcefile available for %s\n", file + binding = @frames[frame_pos] + info, binding_file, binding_line = frame_info(frame_pos) + STDOUT.printf "#%d %s\n", frame_pos, info + + when /^down(?:\s+(\d+))?$/ + previus_line = nil + if $1 + lev = $1.to_i + else + lev = 1 + end + frame_pos -= lev + if frame_pos < 0 + frame_pos = 0 + STDOUT.print "at stack bottom\n" end + binding = @frames[frame_pos] + info, binding_file, binding_line = frame_info(frame_pos) + STDOUT.printf "#%d %s\n", frame_pos, info + + when /^fi(?:nish)?$/ + @finish_pos = @frames.size - frame_pos + frame_pos = 0 + return + + when /^q(?:uit)?$/ + input = readline("really quit? (y/n) ", false) + exit if input == "y" + when /^p\s+/ - p debug_eval($', binding) #' + p debug_eval($', binding) + else v = debug_eval(input, binding) - p v unless v == nil + p v unless (v == nil) end - STDOUT.print "(rdb:-) " - STDOUT.flush end end + def display_expressions(binding) + n = 1 + for d in @display + if d[0] + STDOUT.printf "%d: %s = %s\n", n, d[1], debug_eval(d[1], binding).to_s + end + n += 1 + end + end + + def frame_info(pos = 0) + info = caller(0)[-(@frames.size - pos)] + info.sub(/:in `.*'$/, "") =~ /^(.*):(\d+)$/ #` + [info, $1, $2.to_i] + end + def line_at(file, line) lines = @scripts[file] if lines - return "\n" if lines == TRUE + return "\n" if lines == true line = lines[line-1] return "\n" unless line return line end save = $DEBUG begin - $DEBUG = FALSE + $DEBUG = false f = open(file) lines = @scripts[file] = f.readlines rescue $DEBUG = save - @scripts[file] = TRUE + @scripts[file] = true return "\n" end line = lines[line-1] @@ -219,19 +321,44 @@ class DEBUGGER__ def check_break_points(file, pos, binding, id) file = File.basename(file) - if @break_points.include? [file, pos] - index = @break_points.index([file, pos]) - printf "Breakpoint %d, %s at %s:%s\n", - index, debug_funcname(id), file, pos - return TRUE + n = 1 + for b in @break_points + if b[0] + if b[1] == 0 and b[2] == file and b[3] == pos + STDOUT.printf "breakpoint %d, %s at %s:%s\n", n, debug_funcname(id), + file, pos + return true + elsif b[1] == 1 and debug_eval(b[2], binding) + STDOUT.printf "watchpoint %d, %s at %s:%s\n", n, debug_funcname(id), + file, pos + return true + end + end + n += 1 + end + return false + end + + def excn_handle(file, line, id, binding) + fs = @frames.size + tb = caller(0)[-fs..-1] + + STDOUT.printf "%s\n", $! + for i in tb + STDOUT.printf "\tfrom %s\n", i end - return FALSE + debug_command(file, line, id, binding) end def trace_func(event, file, line, id, binding) - if event == 'line' - if @no_step == nil or @no_step >= @frames.size + case event + when 'line' + if !@no_step or @frames.size == @no_step @stop_next -= 1 + elsif @frames.size < @no_step + @stop_next = 0 # break here before leaving... + else + # nothing to do. skipped. end if @stop_next == 0 if [file, line] == @last @@ -245,21 +372,25 @@ class DEBUGGER__ if check_break_points(file, line, binding, id) debug_command(file, line, id, binding) end - end - if event == 'call' - @frames.push binding + + when 'call' + @frames.unshift binding if check_break_points(file, id.id2name, binding, id) debug_command(file, line, id, binding) end - end - if event == 'class' - @frames.push binding - end - if event == 'return' or event == 'end' - if @finish_pos == @frames.size + + when 'class' + @frames.unshift binding + + when 'return', 'end' + if @frames.size == @finish_pos @stop_next = 1 end - @frames.pop + @frames.shift + + when 'raise' + excn_handle(file, line, id, binding) + end @last_file = file end @@ -267,6 +398,6 @@ class DEBUGGER__ CONTEXT = new end -set_trace_func proc{|event, file, line, id, binding| +set_trace_func proc{|event, file, line, id, binding,*rest| DEBUGGER__::CONTEXT.trace_func event, file, line, id, binding } -- cgit v1.2.3