diff --git a/datastructures/go.mod b/datastructures/go.mod new file mode 100644 index 0000000..eb1324b --- /dev/null +++ b/datastructures/go.mod @@ -0,0 +1,3 @@ +module datastructures + +go 1.23.1 diff --git a/debugger/README.md b/debugger/README.md new file mode 100644 index 0000000..1dd9bb4 --- /dev/null +++ b/debugger/README.md @@ -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 \ No newline at end of file diff --git a/debugger/go.mod b/debugger/go.mod new file mode 100644 index 0000000..f905c7f --- /dev/null +++ b/debugger/go.mod @@ -0,0 +1,3 @@ +module debugger + +go 1.23.1 diff --git a/debugger/main.go b/debugger/main.go new file mode 100644 index 0000000..8bc639a --- /dev/null +++ b/debugger/main.go @@ -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() +}