📜 ⬆️ ⬇️

godebug - cross-platform debugger for Go

The guys from Mailgun presented a new cross-platform debugger for Go , which uses the original technology, which is completely different from the standard approaches. Looking ahead - with Gopherjs, this debugger works even in the browser.

image

Intro


It goes without saying that it will be a good idea.

- Rob Pike

')
Go support has been in the gdb debugger for a long time, but there are still a lot of small but unpleasant problems that prevented it from being fully used. There is also a delve project, but it is difficult to draw conclusions about its popularity. In any case, the “classic” approaches to writing a debugger for Go invariably came up against the difficulty of implementation, especially when it comes to Go-specific things like debuggling Gourutine.

Jeremy Schlatter from Mailgun, which uses Go quite actively, chose a completely different approach - he took the same idea as the basis for the go coverage tool, the embedded test system and some others: changing the code on the fly before compiling. This approach was generally possible due to two main points - a huge compilation speed and simple grammar of the language. The tools for parsing go-grammar (go / ast and go / parser) built into stdlib make it easy to modify the code of a compiled program on the fly, which opens up a whole new layer of possibilities.

Example


For example, take a simple program on Go:
package main import "fmt" func hello(text string) { fmt.Println(text) } func main() { fmt.Printf("Hello,") hello("world") } 

And run godebug with the output command to view the generated code:
 package main import ( "fmt" "github.com/mailgun/godebug/lib" ) var main_go_scope = godebug.EnteringNewScope(main_go_contents) func hello(text string) { ctx, ok := godebug.EnterFunc(func() { hello(text) }) if !ok { return } defer godebug.ExitFunc(ctx) scope := main_go_scope.EnteringNewChildScope() scope.Declare("text", &text) godebug.Line(ctx, scope, 6) fmt.Println(text) } func main() { ctx, ok := godebug.EnterFunc(main) if !ok { return } godebug.Line(ctx, main_go_scope, 10) fmt.Printf("Hello,") godebug.Line(ctx, main_go_scope, 11) hello("world") } var main_go_contents = `package main import "fmt" func hello(text string) { fmt.Println(text) } func main() { fmt.Printf("Hello,") hello("world") } ` 

Without going into the details of each function, it is clear that on each line are the functions identifiers of strings, the input and output of functions, the declaration of variables, and so on. Runtime debugger is already working with these added functions, having full information about the program.

Demo


This approach, of course, is not universal and has its limitations and drawbacks, but its relative simplicity and advantages are obvious. One of the demonstrations of the strengths of this approach is the ability to debug directly in the browser using gopherjs: focused-sprite-91100.appspot.com/playground/blog-post - try it yourself.



There are some nuances to the fact that the native line numbering is broken - this can affect, say, loggers / tracers, which will report the line number. But in general, for most cases, this approach works with a bang.

Installation


Installing a debugger is no different than installing any other Go-program:
 go install github.com/mailgun/godebug 

Using


Using debugger is very simple:
 $ godebug godebug is a tool for debugging Go programs. Usage: godebug command [arguments] The commands are: run compile, run, and debug a Go program test compile, run, and debug Go package tests output generate debug source code, but do not build or run it Use "godebug help [command]" for more information about a command. 

godebug run * .go - compiles with debug support all sources in current directory. All additional packages used in the code, both their own and external - are compiled natively, without debugging - this is done on purpose so as not to slow down the code where it is not needed. If you need to debug the code in some included packages, they must be specified using the -instrument flag:

 godebug run -instrument github.com/go-sql-driver/mysql main.go 

The breakpoints in the program are set as follows:
 _ = "breakpoint" 

With a normal build, this code does nothing, and godebug will recognize it before compiling and insert a stop instruction.

Status


The project is ready for practical use, although only the most basic functions are supported so far:

The plans support stop / inspection gorutin and other things that the community deems necessary / useful.

References:


Source: https://habr.com/ru/post/256355/


All Articles