summaryrefslogtreecommitdiff
path: root/lib/debug.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/debug.rb')
-rw-r--r--lib/debug.rb387
1 files changed, 259 insertions, 128 deletions
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
}