[ruby-talk:00448] Re: interactive ruby, debugger
From:
"NAKAMURA, Hiroshi" <nakahiro@...>
Date:
1999-07-10 08:54:16 UTC
List:
ruby-talk #448
Hi,
I am 'NaHi'.
I sent mail to ruby-list several times, but am newbie here.
I'm sorry for my poor English.(in advance :-)
> From: GOTO Kentaro [mailto:gotoken@math.sci.hokudai.ac.jp]
> Sent: Saturday, July 10, 1999 3:20 AM
> >o Why is the -debug flag special? When writing/running a dynamically
> > typed interactive program (like a gui), I *expect* errors, and
> > getting a full, traversible stack trace with source file and line
> > number information is *critical* (to me, at least).
>
> Well, a user can obtain trace stack by the global variable $@.
>
> > Shouldn't
> > the debugger be part of the ruby core?
>
> I think it is partially right. The debugger, indeed, is not part of a
> ruby interpreter. So, there exists degug.rb which is a gdb-like
> debugger.
>
> % ruby -r debug yourcode.rb
As gotoken-san saying, the debugger is not part of the interpreter,
but has a few interfaces which supports debugging or tracing
like set_trace_func(), caller(). You can see these used in debug.rb and trace.rb.
And then, using debug.rb and trace.rb,
ruby's debugging environment is powerful enough, I think.
> In debug.rb prompt, The following is available command list.
>
> b(reak)
Set breakpoint at specified line or function.
set breakpoint at line nn -> 'b nn'
at function foo -> 'b foo'
at function bar in baz.rb -> 'b baz.rb:bar'
see all breakpoint -> 'b(reak)' or 'info b(reak)'
> i(nfo)
Gotoken-san, I couldn't find it in debug.rb in ruby/1.3.4-990625...
Old spec? for example, in ruby-1.2 or younger?
> del(ete)
[snip]
> l(ist)
> p
Probably, of cource, Gotoken-san knows,
'p' is not a debug command but a ruby method.
debug.rb keeps binding objects of each stack frame,
and evaluate the unknown command in the suitable binding...
...(checking debug.rb by way of precaution)...Ah, that's not true!
'p' is certainly a debug command for putting value of then given command.
I'm sorry...
By the way, I made a patch since the action was more modeled on gdb.
'list' command lists just 10 line.
'list' command memorizes the line number listed before, for each target-file.
'list -' for listing previous 10 lines.
'list 0' does not cause error.
'up' and 'down' puts the stack frame where you are.
# Although NaHi imitated Cle, NaHi don't know the meaning of '\' in a head. :-)
\NaHi
/ / /
Index: debug.rb
===================================================================
RCS file: /home/cvs/ruby/lib/debug.rb,v
retrieving revision 1.1.1.2.2.3
diff -u -r1.1.1.2.2.3 debug.rb
--- debug.rb 1999/06/24 04:24:08 1.1.1.2.2.3
+++ debug.rb 1999/07/10 07:20:40
@@ -6,7 +6,7 @@
@break_points = []
@stop_next = 1
@frames = [nil]
- @frame_pos = nil
+ @frame_pos = nil # nil means not '0' but `unknown'.
@last_file = nil
@scripts = {}
end
@@ -32,10 +32,14 @@
end
def debug_command(file, line, id, binding)
+ binding_file = file
+ binding_line = line
+ debug_line = {}
if (ENV['EMACS'] == 't')
- printf "\032\032%s:%d:\n", file, line
+ printf "\032\032%s:%d:\n", binding_file, binding_line
else
- printf "%s:%d:%s", file, line, line_at(file, line)
+ printf "%s:%d:%s", binding_file, binding_line,
+ line_at(binding_file, binding_line)
end
@frames[-1] = binding
STDOUT.print "(rdb:-) "
@@ -120,9 +124,13 @@
@frame_pos -= lev
if @frame_pos < 0
STDOUT.print "at toplevel\n"
- @frame_pos = 0
+ @frame_pos = nil
else
binding = @frames[@frame_pos]
+ frame_info = caller(4)[-(@frame_pos+1)]
+ STDOUT.print "at ", frame_info, "\n"
+ frame_info.sub( /:in `.*'$/, '' ) =~ /^(.*):(\d+)$/
+ binding_file, binding_line = $1, $2.to_i
end
when /^down\s*(\d+)??$/
if $1
@@ -133,12 +141,16 @@
unless @frame_pos
@frame_pos = @frames.size - 1
end
- if lev >= @frames.size or @frame_pos and @frame_pos+lev >= @frames.size
+ @frame_pos += lev
+ if @frame_pos >= @frames.size
STDOUT.print "at stack bottom\n"
@frame_pos = nil
else
- @frame_pos += lev
binding = @frames[@frame_pos]
+ frame_info = caller(4)[-(@frame_pos+1)]
+ STDOUT.print "at ", frame_info, "\n"
+ frame_info.sub( /:in `.*'$/, '' ) =~ /^(.*):(\d+)$/
+ binding_file, binding_line = $1, $2.to_i
end
when /^fin(ish)?$/
@finish_pos = @frames.size
@@ -154,29 +166,36 @@
printf " %s\n", i
end
when /^l(ist)?(\s+(.*))?$/
- if $3
+ if !$3
+ b = debug_line[binding_file]? debug_line[binding_file] + 10 :
+ binding_line - 5
+ e = b + 9
+ elsif $3 == '-'
+ b = debug_line[binding_file]? debug_line[binding_file] - 10 :
+ binding_line - 5
+ e = b + 9
+ else
b, e = $3.split(/[-,]/)
- b = Integer(b)-1
if e
- e = Integer(e)-1
+ b = Integer(b)
+ e = Integer(e)
else
- e = b + 10
+ b = Integer(b)-5
+ e = b + 9
end
end
- unless b
- b = line - 1
- e = line + 9
- 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
+ debug_line[binding_file] = b
+ p [binding_file,b,e]
+ 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]
+ printf "%4d %s\n", n, lines[n-1].chomp
+ end
end
else
- printf "no sourcefile available for %s\n", file
+ printf "no sourcefile available for %s\n", binding_file
end
when /^p\s+/
p debug_eval($', binding) #'