Slide 1

Slide 1 text

Debugging Go Code with GDB kaneshin Go Conference 2015 summer

Slide 2

Slide 2 text

Shintaro Kaneko (kaneshin) - Senior Engineer @ eureka kaneshin kaneshinth shintaro.kaneko

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

What is eureka?

Slide 5

Slide 5 text

How do you Debug Go code?

Slide 6

Slide 6 text

Print Debugging?

Slide 7

Slide 7 text

func  main()  {     v  :=  map[string]string{"key":  "value"}     fmt.Println("DEBUG",  v)     for  _,  d  :=  range  v  {       ..     }   }

Slide 8

Slide 8 text

func  main()  {     v  :=  map[string]string{"key":  "value"}     fmt.Println("DEBUG",  v)     for  _,  d  :=  range  v  {       ..     }   }

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

The Disadvantages of Print Debugging fmt.Print

Slide 11

Slide 11 text

Ad-hoc Code is temporarily added

Slide 12

Slide 12 text

func  main()  {     v  :=  map[string]string{"key":  "value"}     for  _,  d  :=  range  v  {       ..     }   } If problems occur

Slide 13

Slide 13 text

func  main()  {     v  :=  map[string]string{"key":  "value"}     fmt.Println("DEBUG",  v)     for  _,  d  :=  range  v  {       ..     }     fmt.Println("DEBUG",  v)   } Add code temporarily

Slide 14

Slide 14 text

func  main()  {     v  :=  map[string]string{"key":  "value"}     //  fmt.Println("DEBUG",  v)     for  _,  d  :=  range  v  {       ..     }     //  fmt.Println("DEBUG",  v)   } Disable/Remove code as soon as solved

Slide 15

Slide 15 text

No content

Slide 16

Slide 16 text

Lost buffer in case of a crash

Slide 17

Slide 17 text

  r,  w,  _  :=  os.Pipe()     os.Stdout  =  w     oc  :=  make(chan  string)     go  func()  {       var  buf  bytes.Buffer       io.Copy(&buf,  r)       oc  <-­‐  buf.String()     }() Pipe STDOUT

Slide 18

Slide 18 text

  r,  w,  _  :=  os.Pipe()     os.Stdout  =  w     oc  :=  make(chan  string)     go  func()  {       var  buf  bytes.Buffer       io.Copy(&buf,  r)       oc  <-­‐  buf.String()     }() In case of io.Copy crash

Slide 19

Slide 19 text

  r,  w,  _  :=  os.Pipe()     os.Stdout  =  w     oc  :=  make(chan  string)     go  func()  {       var  buf  bytes.Buffer       io.Copy(&buf,  r)       oc  <-­‐  buf.String()     }() Maybe you add print code.. fmt.Println(buf)   fmt.Println(buf)

Slide 20

Slide 20 text

No content

Slide 21

Slide 21 text

Can’t interrupt processing program

Slide 22

Slide 22 text

func  main()  {     v  :=  map[string]string{"key":  "value",  ..}     for  _,  d  :=  range  v  {       ..       ..     }   } If problems occur

Slide 23

Slide 23 text

func  main()  {     v  :=  map[string]string{"key":  "value",  ..}     for  _,  d  :=  range  v  {       ..       fmt.Println("DEBUG",  d)       ..     }   } Add code temporarily

Slide 24

Slide 24 text

DEBUG  value   DEBUG  ..   DEBUG  ..   DEBUG  ..   DEBUG  ..   DEBUG  ..   DEBUG  ..   DEBUG  ..   DEBUG  ..   DEBUG  ..   DEBUG  ..   The Stream of the log..

Slide 25

Slide 25 text

No content

Slide 26

Slide 26 text

No more!

Slide 27

Slide 27 text

Do you debug with GDB, don’t you?

Slide 28

Slide 28 text

The Advantages of GDB over Print Debugging

Slide 29

Slide 29 text

Printable Variables directly Doesn’t need to add temp code

Slide 30

Slide 30 text

Interruptible/Attachable processing program

Slide 31

Slide 31 text

Remote debugging

Slide 32

Slide 32 text

How to execute GDB?

Slide 33

Slide 33 text

How to execute GDB? ‣ It’s very easy to debug code ‣ See "Debugging Go Code with GDB" ‣ https://golang.org/doc/gdb ‣ GDB debugger ver 7.1+ ‣ To inspect a live process or a core dump from DWARF ‣ Go ver 1.4+ ‣ Go v1.2~1.3.3 are not working (DWARF has been missing)

Slide 34

Slide 34 text

How to execute GDB? ‣ Compile Go Code to contain useful debugging information ‣ Pass `-gcflags "-N -l"` to disable optimizations of compile ‣ For example: `go build -gcflags "-N -l" /path/to/repo` ‣ Pass `-ldflags "-w"` to omit the debug information ‣ For example: `go build -ldflags "-w" /path/to/repo`

Slide 35

Slide 35 text

$  go  build  -­‐o  fib  github.com/kaneshin/go-­‐fibonacci                 $  go  build  -­‐gcflags  "-­‐N  -­‐l"  -­‐o  fib-­‐none  \                                      github.com/kaneshin/go-­‐fibonacci     $  go  build  -­‐ldflags  "-­‐w"  -­‐o  fib-­‐omit  \                                      github.com/kaneshin/go-­‐fibonacci           $  ls  -­‐al  |  grep  fib   -­‐rwxr-­‐xr-­‐x      1  root  root  6452704  Jun  20  11:19  fib*   -­‐rwxr-­‐xr-­‐x      1  root  root  6452744  Jun  20  11:24  fib-­‐none*   -­‐rwxr-­‐xr-­‐x      1  root  root  5128473  Jun  20  11:19  fib-­‐omit*

Slide 36

Slide 36 text

$ gdb main.go to execute GDB

Slide 37

Slide 37 text

I’m not talking about How to USE gdb I will if there is a next time

Slide 38

Slide 38 text

͜͜·Ͱத൫ ͪΐͬͱ͚ͩ೔ຊޠ͕ग़͖ͯ·͢

Slide 39

Slide 39 text

Struggled with GDB

Slide 40

Slide 40 text

1. Broken DWARF 2. An old GDB is in my GDB 3. Runtime Bug (runtime.py) 4. Web Application Framework: Revel

Slide 41

Slide 41 text

1. Broken DWARF

Slide 42

Slide 42 text

Broken DWARF ‣ Go 1.4+͸मਖ਼ࡁΈ ‣ Go 1.3.x Ͱ͸ਖ਼͍͠஋͕දࣔ͞Εͳ͍

Slide 43

Slide 43 text

Broken DWARF ‣ Go 1.4+͸मਖ਼ࡁΈ ‣ Go 1.3.x Ͱ͸ਖ਼͍͠஋͕දࣔ͞Εͳ͍    num  :=  r.URL.Query().Get("num")      n,  err  :=  strconv.Atoi(num)   >  if  err  !=  nil  {              fmt.Fprintln(os.Stderr,  err)

Slide 44

Slide 44 text

Broken DWARF ‣ Go 1.4+͸मਖ਼ࡁΈ ‣ Go 1.3.x Ͱ͸ਖ਼͍͠஋͕දࣔ͞Εͳ͍ (gdb)  info  locals   val  =  833358128335   n  =  3   num  =  0xc20803e4d3  "1000"   err  =  {tab  =  0xc20802e170,  data  =  0xc20802e160}   (gdb)        num  :=  r.URL.Query().Get("num")      n,  err  :=  strconv.Atoi(num)   >  if  err  !=  nil  {              fmt.Fprintln(os.Stderr,  err)

Slide 45

Slide 45 text

Broken DWARF ‣ Go 1.4+͸मਖ਼ࡁΈ ‣ Go 1.3.x Ͱ͸ਖ਼͍͠஋͕දࣔ͞Εͳ͍ (gdb)  info  locals   val  =  833358128335   n  =  3   num  =  0xc20803e4d3  "1000"   err  =  {tab  =  0xc20802e170,  data  =  0xc20802e160}   (gdb)        num  :=  r.URL.Query().Get("num")      n,  err  :=  strconv.Atoi(num)   >  if  err  !=  nil  {              fmt.Fprintln(os.Stderr,  err)

Slide 46

Slide 46 text

2. An old GDB is in my MBA

Slide 47

Slide 47 text

2. An old GDB is in my MBA ‣ Actually it was my fault. ‣ Be careful if you will install GDB

Slide 48

Slide 48 text

2. An old GDB is in my MBA ‣ Actually it was my fault. ‣ Be careful if you will install GDB How to Install GDB on OS X (Needs to sign your certification)    $  brew  install  homebrew/dupes/gdb

Slide 49

Slide 49 text

2. An old GDB is in my MBA ‣ Actually it was my fault. ‣ Be careful if you will install GDB How to Install GDB on OS X (Needs to sign your certification)    $  brew  install  homebrew/dupes/gdb      $  gdb  -­‐v  

Slide 50

Slide 50 text

2. An old GDB is in my MBA ‣ Actually it was my fault. ‣ Be careful if you will install GDB How to Install GDB on OS X (Needs to sign your certification)    $  brew  install  homebrew/dupes/gdb      $  gdb  -­‐v      GNU  gdb  6.3.50-­‐20050815  (Apple  version  gdb-­‐1824)      (Wed  Feb    6  22:51:23  UTC  2013)  

Slide 51

Slide 51 text

2. An old GDB is in my MBA ‣ Actually it was my fault. ‣ Be careful if you will install GDB How to Install GDB on OS X (Needs to sign your certification)    $  brew  install  homebrew/dupes/gdb      $  gdb  -­‐v      GNU  gdb  6.3.50-­‐20050815  (Apple  version  gdb-­‐1824)      (Wed  Feb    6  22:51:23  UTC  2013)  

Slide 52

Slide 52 text

2. An old GDB is in my MBA    $  which  gdb      /usr/bin/gdb  

Slide 53

Slide 53 text

2. An old GDB is in my MBA    $  which  gdb      /usr/bin/gdb            $  `brew  -­‐-­‐prefix  gdb`/bin/gdb  -­‐v      GNU  gdb  (GDB)  7.9.1  

Slide 54

Slide 54 text

3. Runtime Bug

Slide 55

Slide 55 text

3. Runtime Bug ‣ See "gdb: No struct type named runtime.rtype #9326" ‣ https://github.com/golang/go/issues/9326 gdb  main.go  -­‐d  $GOROOT   ...   (gdb)  source  /usr/local/go/src/runtime/runtime-­‐gdb.py     Loading  Go  Runtime  support.   Traceback  (most  recent  call  last):      File  "/usr/local/go/src/runtime/runtime-­‐gdb.py",  line  205,  in            _rctp_type  =  gdb.lookup_type("struct  runtime.rtype").pointer()   gdb.error:  No  struct  type  named  runtime.rtype.

Slide 56

Slide 56 text

3. Runtime Bug ‣ See "gdb: No struct type named runtime.rtype #9326" ‣ https://github.com/golang/go/issues/9326 gdb  main.go  -­‐d  $GOROOT   ...   (gdb)  source  /usr/local/go/src/runtime/runtime-­‐gdb.py     Loading  Go  Runtime  support.   Traceback  (most  recent  call  last):      File  "/usr/local/go/src/runtime/runtime-­‐gdb.py",  line  205,  in            _rctp_type  =  gdb.lookup_type("struct  reflect.rtype").pointer()   gdb.error:  No  struct  type  named  runtime.rtype.

Slide 57

Slide 57 text

4. WAF: Revel

Slide 58

Slide 58 text

4. WAF: Revel ‣ Revel is kind of Web Application Framework ‣ See "How to debug app with GDB?" #921 ‣ https://github.com/revel/revel/issues/921

Slide 59

Slide 59 text

GDBͱͷ૬ੑѱ͘ͳ͍Ͱ͔͢ʁ

Slide 60

Slide 60 text

GDBͱͷ૬ੑѱ͘ͳ͍Ͱ͔͢ʁ ͦ΋ͦ΋ɺGoͷGDBαϙʔτ͕ऑ͍͔ΒͶ

Slide 61

Slide 61 text

GDBͱͷ૬ੑѱ͘ͳ͍Ͱ͔͢ʁ ͦ΋ͦ΋ɺGoͷGDBαϙʔτ͕ऑ͍͔ΒͶ revelʹ͸ revel.DEBUG.Printf ͱ͍͏ૉ੖Β͍͠ Printؔ਺͕͋Δ͔Β

Slide 62

Slide 62 text

Printσόοάͯ͠Ͷˑ

Slide 63

Slide 63 text

No content

Slide 64

Slide 64 text

No content

Slide 65

Slide 65 text

OK, RevelͰGDBఘΊΔΘ

Slide 66

Slide 66 text

·ͱΊ ‣ Print Debugging͸΍Ίͨ΄͏͕͍͍͚Ͳ… ‣ GDBͱGo͸·ͩൃల్্ ‣ ਖ਼௚Ϗϧυ͕଎͍ ‣ Web Application ͱ૬ੑ͕ѱ͍

Slide 67

Slide 67 text

·ͱΊ ‣ Print Debugging͸΍Ίͨ΄͏͕͍͍͚Ͳ… ‣ GDBͱGo͸·ͩൃల్্ ‣ ਖ਼௚Ϗϧυ͕଎͍ ‣ Web Application ͱ૬ੑ͕ѱ͍ ‣ RevelΛ૬౰͍͡Γ·ͨ͠ɻ͕ɺRevelͷ։ൃ͕ਐΉͷ͕ਏ͍

Slide 68

Slide 68 text

·ͱΊ ‣ Print Debugging͸΍Ίͨ΄͏͕͍͍͚Ͳ… ‣ GDBͱGo͸·ͩൃల్্ ‣ ਖ਼௚Ϗϧυ͕଎͍ ‣ Web Application ͱ૬ੑ͕ѱ͍ ‣ RevelΛ૬౰͍͡Γ·ͨ͠ɻ͕ɺRevelͷ։ൃ͕ਐΉͷ͕ਏ͍ ‣ GDB࢖͏ʹͯ͠΋೜଱ڧ͘ͳ͍ͱਏ͍

Slide 69

Slide 69 text

Copyright © 2009-2015 eureka, Inc. All rights reserved. Thank you