Adding debugger notes
							parent
							
								
									c4e7f0d5ea
								
							
						
					
					
						commit
						49410fd49e
					
				@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					module datastructures
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					go 1.23.1
 | 
				
			||||||
@ -0,0 +1,297 @@
 | 
				
			|||||||
 | 
					# Using the Debugger
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Go doesn't ship with a debugger but you can use the delve package instead.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					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
 | 
				
			||||||
@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					module debugger
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					go 1.23.1
 | 
				
			||||||
@ -0,0 +1,51 @@
 | 
				
			|||||||
 | 
					package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"sync"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func One() {
 | 
				
			||||||
 | 
						Two()
 | 
				
			||||||
 | 
						fmt.Println("One!")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func Two() {
 | 
				
			||||||
 | 
						Three()
 | 
				
			||||||
 | 
						fmt.Println("Two!")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func Three() {
 | 
				
			||||||
 | 
						fmt.Println("Three!")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Used in the simple example
 | 
				
			||||||
 | 
					// func main() {
 | 
				
			||||||
 | 
					// 	msg := "Hello debugger"
 | 
				
			||||||
 | 
					// 	One()
 | 
				
			||||||
 | 
					// 	fmt.Println(msg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Used for Goroutine debugging
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func printMe(i int, wg *sync.WaitGroup) {
 | 
				
			||||||
 | 
						defer wg.Done()
 | 
				
			||||||
 | 
						fmt.Printf("I'm a go routine %d\n", i)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func main() {
 | 
				
			||||||
 | 
						i := 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var wg sync.WaitGroup
 | 
				
			||||||
 | 
						wg.Add(9)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for i < 10 {
 | 
				
			||||||
 | 
							go func(rI int) {
 | 
				
			||||||
 | 
								printMe(rI, &wg)
 | 
				
			||||||
 | 
							}(i)
 | 
				
			||||||
 | 
							i++
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wg.Wait()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
					Loading…
					
					
				
		Reference in New Issue