-
Notifications
You must be signed in to change notification settings - Fork 2
Cool things
Not much here other than the fact that this debugger exists and it does in large part to the cool work of the go-tools ssa interpreter. I am curious how this fares with other debuggers, so let me know what cool features they have and maybe I'll add them.
When in the debugger, a lock is set so basically all threads and go routines are stopped. You can get a list of goroutines and their call stack using the goroutines (or gore) command.
When there is more than a single goroutine, that is displayed in the prompt after an "@" sign. For example
gub[4@2]:
The "4" refers to the number of command prompts that have been entered. The "2" refers to the fact that you are stopped in goroutine 2. The main goroutine is always 0, and if that is running, it is not shown. That is you will see:
gub[4]:
when the fourth command is about to be entered.
Thanks to go/token's fine-grained line/column position handling, we are able to reflect that inside the debugger. This means that you can distinguish which statement we are stopped at in a multi-statement line or distinguish between the initialization, condition and iteration parts of a for statement which are on the same line. And you can set breakpoints using both line and column number. The command locs will show all the locations we have registered.
You can change the program counter inside the bacic block with the debugger jump command.
The go.tools/ssa package collects lots of detailed and interesting information about Go programs and packages. One can have (large) bulk lists printed for you using various. But right now it doesn't give one a way of narrowing the information dumped.
With the debugger, not only can one narrow this information, one can also adapt queries based on previous queries, because the debugger is interactive.
Here is an example.
First get in the debugger:
$ ./gub.sh example/square.go
Running....
Gub version 0.1
Type 'h' for help
-> main()
example/square.go:15:6
gub[0]
Ok. Now let's see what we have regarding the package os:
os is a package: at /home/rocky/go/google-code/go/src/pkg/os
Members
Args Hostname O_CREATE Stdout
Chdir Interrupt O_EXCL Symlink
Chmod IsExist O_RDONLY SyscallError
Chown IsNotExist O_RDWR TempDir
Chtimes IsPathSeparator O_SYNC Truncate
Clearenv IsPermission O_TRUNC atime
...
gub[1]
Not only do you get where the package is located on my computer, in case I want to browse the source, but thanks to my columnize package, the list is nicley arranged compactly and sorted.
Ok, but now let's dill down based on this information.
gub[2] whatis os.Chown
os.Chown is a function at:
/home/rocky/go/google-code/go/src/pkg/os/file_posix.go:98:6-103:2
parameter name : string
parameter uid : int
parameter gid : int
Locals:
0: name~ string
1: uid~ int
2: gid~ int
3: e error
Again we get where this is located and very precise information about where in the file this function is. Under locals we see that in addition to the parameters, there is a local variable defined called e.
Want to know what os.O_RDWR
is?
gub[2] whatis os.O_RDWR
Constant O_RDWR is a constant at:
/home/rocky/go/google-code/go/src/pkg/os/file.go:60:2
int 2
It is a integer constant with value 2.
Of course we don't make a common debugger mistake of mistaking the first statement of a call for the call itself. The event that you are stopped at is shown in the as a little icon.
??? Unknown
:= Assignment statement
} Block end
<-X go "break" statement
xxx user-set breakpoint
-> call entry
<- call return
(.) Expression
if: go "if" initialization
if? go "if" condition
lo: go "for" loop initialization
lo? go "for" condition
lo+ go "for" interation
m() start of go main()
oX panic (My lame attempt at skull and cross bones)
... range statement
sel select type
sw? switch condition
--- beginning of a new statement
Because we have such fine grain control, stepping may be a little bit tedious. If you are familiar with my other debuggers that will be addressed, via set different, step suffixes, and possibly event masks.
Well, with the hooks added to the interpreter, you can write your own.
I've added a call-stack frame type which one can use to introspect about the call stack. You can register a function to get called tracing is enabled.
The main interface is:
type TraceHookFunc func(*interp.Frame, *ssa2.Instruction, ssa2.TraceEvent)
interp.SetTraceHook(hook TraceHookFunc)