LoginSignup
2
2

More than 5 years have passed since last update.

delve でデバッグをしてみる

Posted at

お疲れの皆さん、お疲れ様です。この記事は Okinawa.go Advent Calendar 2016 の 16 日目の記事になります。
前々から宣言していたように、この記事ではデバッグに関することを書きたいと思います。
今回は gdb より delve の方がいいよーとオススメされていたので使ってみることにしました。
しかもちょうど Fujitsu Advent Calendar 2016 で紹介されていたのでやるしかない...!!

インストール

各 OS ごとのインストール方法についてはここ に記載されてるので参考にしてください。

使ってみる

操作のドキュメントです。
デバッグに使ったソースコードです。

test.go
package main

func main() {
    ch := make(chan int)

    for i := 0; i < 10; i++ {
        go func(j int) {
            ch <- j
        }(i)
    }

    for i := 0; i < 10; i++ {
        println(<-ch)
    }
    close(ch)
}

dlv debug test.go でもできるみたいですが、今回は go build -gcflags="-N -l" test.go
でコンパイル済みのバイナリを dlv exec ./test を行いました。

$ dlv exec ./test
Type 'help' for list of commands.
(dlv) b main.main
Breakpoint 1 set at 0x2061 for main.main ./test.go:4
(dlv) c
> main.main() ./test.go:4 (hits goroutine(1):1 total:1)
     1: package main
     2: 
     3: func main() {
=>   4:     ch := make(chan int)
     5: 
     6:     for i := 0; i < 10; i++ {
     7:         go func(j int) {
     8:             ch <- j
     9:         }(i)
(dlv) goroutines
[3 goroutines]
* Goroutine 1 - User: ./test.go:4 main.main (0x2061)
  Goroutine 2 - User: /usr/local/opt/go/libexec/src/runtime/proc.go:260 runtime.gopark (0x2558a)
  Goroutine 3 - User: /usr/local/opt/go/libexec/src/runtime/proc.go:260 runtime.gopark (0x2558a)
(dlv) n
> main.main() ./test.go:6
     1: package main
     2: 
     3: func main() {
     4:     ch := make(chan int)
     5: 
=>   6:     for i := 0; i < 10; i++ {
     7:         go func(j int) {
     8:             ch <- j
     9:         }(i)
    10:     }
    11: 

こんな感じに見ていけそうです。
だいたいが gdb と同じように操作できますね!

(dlv) goroutine 10 list

とやると

   255:     mp.waittraceev = traceEv
   256:     mp.waittraceskip = traceskip
   257:     releasem(mp)
   258:     // can't do anything that might move the G between Ms here.
   259:     mcall(park_m)
=> 260: }
   261: 
   262: // Puts the current goroutine into a waiting state and unlocks the lock.
   263: // The goroutine can be made runnable again by calling goready(gp).
   264: func goparkunlock(lock *mutex, reason string, traceEv byte, traceskip int) {
   265:     gopark(parkunlock_c, unsafe.Pointer(lock), reason, traceEv, traceskip)

のように goroutine がどのように動いてるのかを確認することもできます。

(dlv) help
The following commands are available:
    help ------------------------ Prints the help message.
    break (alias: b) ------------ break <linespec> [-stack <n>|-goroutine|<variable name>]*
    trace (alias: t) ------------ Set tracepoint, takes the same arguments as break.
    restart (alias: r) ---------- Restart process.
    continue (alias: c) --------- Run until breakpoint or program termination.
    step (alias: s) ------------- Single step through program.
    step-instruction (alias: si)  Single step a single cpu instruction.
    next (alias: n) ------------- Step over to next source line.
    threads --------------------- Print out info for every traced thread.
    thread (alias: tr) ---------- Switch to the specified thread.
    clear ----------------------- Deletes breakpoint.
    clearall -------------------- clearall [<linespec>]. Deletes all breakpoints. If <linespec> is provided, only matching breakpoints will be deleted.
    goroutines ------------------ goroutines [-u (default: user location)|-r (runtime location)|-g (go statement location)] Print out info for every goroutine.
    goroutine ------------------- Sets current goroutine.
    breakpoints (alias: bp) ----- Print out info for active breakpoints.
    print (alias: p) ------------ Evaluate a variable.
    set ------------------------- Changes the value of a variable.
    sources --------------------- Print list of source files, optionally filtered by a regexp.
    funcs ----------------------- Print list of functions, optionally filtered by a regexp.
    args ------------------------ Print function arguments, optionally filtered by a regexp.
    locals ---------------------- Print function locals, optionally filtered by a regexp.
    vars ------------------------ Print package variables, optionally filtered by a regexp.
    regs ------------------------ Print contents of CPU registers.
    exit (alias: quit | q) ------ Exit the debugger.
    list (alias: ls) ------------ list <linespec>.  Show source around current point or provided linespec.
    stack (alias: bt) ----------- stack [<depth>] [-full]. Prints stack.
    frame ----------------------- Sets current stack frame (0 is the top of the stack)
    source ---------------------- Executes a file containing a list of delve commands

このような操作ができることが分かります。

感想

ある程度使ってみての感想ですが、正直慣れのせいか僕は gdb を使ってデバッグしていく方が好きです。この感想に惑わされず実際に自分で使ってみて判断した方がいいと思います。
ちなみに delve は IDE でも使えるそうです。
Visual Studio Code の場合だと以下のリンクのようにできるみたいです。参考までにどうぞ。
https://github.com/Microsoft/vscode-go#optional-debugging

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2