-
Notifications
You must be signed in to change notification settings - Fork 4
Sample debug session
The below is a sample trepan session (with bugs and misfeatures included) to show what’s available at this early stage.
First here’s the program /tmp/gcd.rb:
def gcd(a, b)
# Make: a <= b
if a > b
a, b = [b, a]
end
return nil if a >= 0
if a == 1 or b-a == 0
return a
end
return gcd(b-a, a)
end
a, b = ARGV[0..1].map {|arg| arg.to_i} # line 18
puts "The GCD of %d and %d is %d" % [a, b, gcd(a, b)]Now let us run that…
$ ./bin/trepan tmp/gcd.rb 3 5 -- (/tmp/gcd.rb:4) def gcd(a, b) (trepan): info program Program stop event: line; PC offset 2 of instruction sequence <top (tmp/gcd.rb)>
Note:
In an unmodified Ruby 1.9.2 the instruction name is the less helpful name top (required). Down the line I need to create a unique object-id-like name for the instruction sequence so that it can be referred to where needed.
The debugger command step (“step into”) goes to next event set via the debugger command set events . step+ steps to a different line. step< will step to the next call (or c-call if that is in the event set)
The “--” in “-- (temp/gcd.rb 3 5)” above, indicates we are stopped at a line event which is also shown in more detail when I run info program.
(trepan): step
-- (/tmp/gcd.rb:18)
a, b = ARGV[0..1].map {|arg| arg.to_i}
(trepan): step
-- (/tmp/gcd.rb:19)
puts "The GCD of %d and %d is %d" % [a, b, gcd(a, b)]
There is extensive on-line help. Below we just show the available commands and subcommands for show
(trepan): help * All command names: alias directory finish macro reload stepi backtrace disable frame next restart unalias break disassemble help nocache save undisplay condition display info pr set up continue down irb ps show debug enable kill quit source delete exit list raise step (trepan): help d.* Command names matching /^d.*/: debug delete directory disable disassemble display down (trepan): help show * List of subcommands for command 'show': alias auto debug events macro trace args basename different hidelevel max (trepan): show events Trace events we may stop on: brkpt, call, class, end, insn, line, raise, return (trepan): set events call return line raise Trace events we may stop on: call, line, raise, return
Above we encountered the 2-character icons, -- which indicates a line event. You an find a list of event names and icons in Event Icons. Below we will see new one, -> for a call event.
(trepan): s
-> (./tmp/gcd.rb:4)
(trepan): where
--> #0 METHOD Object#gcd(a, b) in file ./tmp/gcd.rb at line 4
#1 TOP Object#<top (required)> in file ./tmp/gcd.rb at line 19
(trepan): [a, b]
[a, b]
3
5
Breakpoints are a bit different than ruby-debug. The main difference is that a breakpoint is associated with a particular VM instruction offset. The upside of this is that one can be very precise in specifying where to stop or where you are stopped. The downside is that the code you want to stop at needs to exist beforehand as Ruby VM instructions. Later on, I’ll probably have to add a symbolic breakpoint which is more or less how it is done in ruby-debug.
(trepan): break 10 Breakpoint 1 set at line 10 in file /tmp/gcd.rb, VM offset 24 of instruction sequence gcd.
We tell you where the breakpoint has been set, VM offset 24 here. If you know the VM-instruction offset you can use that instead of instead of a line number by prefacing the number with an ‘O’; For example instead of ‘break 10’ above, ‘break O24’.
Recall that when I ran help * , there was a disassemble command shown. I’ll use that. And note that I am just disassembling the function I’m currently in.
(trepan): disassemble
== disasm: <RubyVM::InstructionSequence:gcd@/tmp/gcd.rb>
local table (size: 3, argc: 2 [opts: 0, rest: -1, post: 0, block: -1] s1)
[ 3] a<Arg> [ 2] b<Arg>
0000 trace 8 ( 4)
--> 0002 trace 1 ( 6)
0004 getlocal a
0006 getlocal b
0008 opt_gt <ic>
0010 branchunless 22
0012 trace 1 ( 7)
0014 getlocal b
0016 getlocal a
0018 setlocal b
0020 setlocal a
0022 trace 1 ( 10)
B 0024 getlocal a
0026 putobject 0
...
Above the —> indicates VM offset the VM program counter will run next. A ‘B’ marks where a breakpoint is set. At the assembly language level it is not known whether a breakpoint is temporary, perminant or enabled or what breakpoint number we have at that point.
However in source listings via the list command, breakpoint status is shown:
(trepan): list 4 -> def gcd(a, b) 5 # Make: a <= b 6 if a > b 7 a, b = [b, a] 8 end 9 10 B01 return nil if a <= 0 11 12 if a == 1 or b-a == 0 13 return a 14 end (trepan): disable 1 (trepan): list 4 1 #!/usr/bin/env ruby 2 3 # GCD. We assume positive numbers 4 -> def gcd(a, b) 5 # Make: a <= b 6 if a > b 7 a, b = [b, a] 8 end 9 10 b01 return nil if a <= 0 11 (trepan)
And finally we show restarting execution and quitting.
(trepan): R Restart args: ["/usr/local/bin/ruby", "./bin/trepan", "tmp/gcd.rb", "3", "5" ] Restart (exec)? (N/y) Restarting... -- (/tmp/gcd.rb:4) def gcd(a, b) (trepan): exit Really quit? (N/y) Y $
Use q! to quit without prompting.