# Using the Debugger

Go doesn't ship with a debugger but you can use the delve package instead.

https://www.youtube.com/watch?v=UA0SirX6Siw

```
go get github.com/go-delve/delve/cmd/dlv
```

```
dlv version
Delve Debugger
Version: 1.23.1
Build: $Id: 2eba762d75437d380e48fc42213853f13aa2904d $
```

## Using dlv

From within a go module run:

```
dlv debug

Type 'help' for list of commands.
(dlv)
```

Now set a breakpoint on the main function

```
break main.main
```

This breaks not at your main function but in the go runtime.

Now you can do something like set a break point at a line number in a file

```
break main.go:20
```

Now we can continue until we hit a breakpoint

```
c or continue


> [Breakpoint 1] main.main() ./main.go:19 (hits goroutine(1):1 total:1) (PC: 0x4ae66e)
    14:
    15: func Three() {
    16:         fmt.Println("Three!")
    17: }
    18:
=>  19: func main() {
    20:         msg := "Hello debugger"
    21:         One()
    22:         fmt.Println(msg)
    23:
    24: }
```

Now we can check for locals 

```
locals

(no locals)
```

No surprising there are no local variables at this point. 

```
n 
```

Will advance us to the next line. But again no locals because that hasn't been executed yet. So `n` again.

```
locals

msg = "Hello debugger"
```



```
ls

> main.main() ./main.go:21 (PC: 0x4ae687)
    16:         fmt.Println("Three!")
    17: }
    18:
    19: func main() {
    20:         msg := "Hello debugger"
=>  21:         One()
    22:         fmt.Println(msg)
    23:
    24: }
```

Now we can step into our function with `s`

```
s

> main.One() ./main.go:5 (PC: 0x4ae48a)
     1: package main
     2:
     3: import "fmt"
     4:
=>   5: func One() {
     6:         Two()
     7:         fmt.Println("One!")
     8: }
     9:
    10: func Two() {
```

You can se now we have stepped into the function.

We can `n` and `s` into `Two()`.

```
> main.Two() ./main.go:10 (PC: 0x4ae52a)
     5: func One() {
     6:         Two()
     7:         fmt.Println("One!")
     8: }
     9:
=>  10: func Two() {
    11:         Three()
    12:         fmt.Println("Two!")
    13: }
    14:
    15: func Three() {
```

How about we look at the stack trace at this point

```
stack
0  0x00000000004ae52a in main.Two
   at ./main.go:10
1  0x00000000004ae493 in main.One
   at ./main.go:6
2  0x00000000004ae68c in main.main
   at ./main.go:21
3  0x000000000043b647 in runtime.main
   at /usr/local/go/src/runtime/proc.go:272
4  0x0000000000474081 in runtime.goexit
   at /usr/local/go/src/runtime/asm_amd64.s:1700
```

Let's `n` and `s` one more time and check the stack trace.

```
0  0x00000000004ae5ca in main.Three
   at ./main.go:15
1  0x00000000004ae533 in main.Two
   at ./main.go:11
2  0x00000000004ae493 in main.One
   at ./main.go:6
3  0x00000000004ae68c in main.main
   at ./main.go:21
4  0x000000000043b647 in runtime.main
   at /usr/local/go/src/runtime/proc.go:272
5  0x0000000000474081 in runtime.goexit
   at /usr/local/go/src/runtime/asm_amd64.s:1700
```

If we needed to we could us `frame` to go back into the stack and and we can inspect the state of code at that point. 


```
frame 3

locals
```

But then we need to move back to `frame 0` and can continue debugging.

```
(dlv) ls
> main.Two() ./main.go:11 (PC: 0x4ae52e)
     6:         Two()
     7:         fmt.Println("One!")
     8: }
     9:
    10: func Two() {
=>  11:         Three()
    12:         fmt.Println("Two!")
    13: }
    14:
    15: func Three() {
    16:         fmt.Println("Three!")
```

Instead of stepping to `Three()` let's step out of Two.

```
(dlv) so
Three!
Two!
> main.One() ./main.go:7 (PC: 0x4ae493)
Values returned:

     2:
     3: import "fmt"
     4:
     5: func One() {
     6:         Two()
=>   7:         fmt.Println("One!")
     8: }
     9:
    10: func Two() {
    11:         Three()
    12:         fmt.Println("Two!")
```

We see out stdout messages now there is one to go.

```
(dlv) stack
0  0x00000000004ae493 in main.One
   at ./main.go:7
1  0x00000000004ae68c in main.main
   at ./main.go:21
2  0x000000000043b647 in runtime.main
   at /usr/local/go/src/runtime/proc.go:272
3  0x0000000000474081 in runtime.goexit
   at /usr/local/go/src/runtime/asm_amd64.s:1700
```

We can continue this until our process returns. But when we are back in our main function. Let's look at locals one more time.

```
    17: }
    18:
    19: func main() {
    20:         msg := "Hello debugger"
    21:         One()
=>  22:         fmt.Println(msg)
    23:
    24: }

locals

msg = "Hello debugger"
```

We can't change this variable because Delve wants to avoid operations itself that involves memory allocations, but if we had a 

```
func setMsg(value string) {
    msg = value
}
```

We could use `call` to set that variable 

```
call setMsg("dirp")
```

To close it could just `continue` until the process exits.

```
(dlv) c

Process 29036 has exited with status 0
```

## Wait there is more

Help has tons of stuff

```
help
```

Like

```
restart
```
Restarts the program of course. Our current breakpoints are still set. 

```
(dlv) print msg
"Hello debugger"
```

And hey this time we used print to check a value.

Technically you can edit code with `edit`.


## Debugging goroutines