...

среда, 22 апреля 2015 г.

godebug — кроссплатформенный дебаггер для Go

Ребята из компании Mailgun презентовали новый кроссплатформенный дебаггер для Go, который использует оригинальную технологию, в корне отличающуюся от стандартных подходов. Забегая наперед — с помощью Gopherjs этот дебаггер работает даже в браузере.

image

Интро


All that stands in the way [of a good Go debugger] is the writing of a lot of non-portable low-level code talking to buggy undocumented interfaces.

— Rob Pike

Поддержка Go была в дебаггере gdb давно, но оставалось много мелких, но неприятных проблем, которые не давали возможности полноценно им пользоваться. Также есть проект delve, но о его популярности пока сложно сделать выводы. В любом случае, «классические» подходы к написанию дебаггера для Go неизменно сталкивались со сложностью реализации, особенно когда речь заходит о спецефичных для Go вещах вроде дебага горутин.

Абсолютно другой подход выбрал Jeremy Schlatter из компании Mailgun, которая использует Go достаточно активно — он взял за основу ту же идею, которая лежит в основе go coverage tool, встроенной системы тестов и некоторых других: изменение кода на лету перед компиляцией. Такой подход вообще стал возможен благодаря двум основным моментам — огромной скорости компиляции и простой грамматике языка. Встроенные в stdlib инструменты для разбора Go-грамматики (go/ast и go/parser) позволяют достаточно просто на лету модифицировать код компилируемой программы, а это открывает целый новый пласт возможностей.

Пример


К примеру, возьмем простую программу на Go:
package main

import "fmt"

func hello(text string) {
        fmt.Println(text)
}

func main() {
        fmt.Printf("Hello,")
        hello("world")
}



И запустим godebug с командой output, чтобы посмотреть сгенерированный код:
package main

import (
        "fmt"
        "http://ift.tt/1GicuKA"
)

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")
}
`


Не вдаваясь пока в подробности каждой функции, видно, что на каждой строчке расставлены функции-идентификаторы строк, входа и выхода из функций, декларации переменных и так далее. Рантайм дебаггера уже работает с этими, добавленными функциями, имея полную информацию о программе.

Демо


Этот подход, конечно же, не универсален и имеет свои ограничения и недостатки, но его относительная простота и преимущества очевидны. Одной из демонстраций сильных сторон такого подхода является возможность делать отладку прямо в браузере, с помощью gopherjs: http://ift.tt/1EroWr4 — попробуйте сами.

Есть некоторые нюансы с тем, что нарушается нативная нумерация строк — это может повлиять на, скажем, логгеры/трейсеры, которые репортят номер строки. Но в целом для большинства случаев этот подход работает на ура.

Установка


Установка дебаггера не отличается от установки любой другой Go-программы:
go install http://ift.tt/1zCVlUa

Использование


Пользоваться дебаггером очень просто:
$ 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 — компилирует с поддержкой дебага все исходники в текущей директории. Все дополнительные пакеты, используемые в коде, как свои, так и внешние — компилируются нативно, без дебага — это сделано специально, чтобы не замедлять код там, где это не нужно. Если нужно отлаживать и код в каких-то включенных пакетах, то они должны быть указаны с помощью флага -instrument:
godebug run -instrument http://ift.tt/1kNPaoi main.go

Брекпоинты в программе ставятся следующей конструкцией:
_ = "breakpoint"

При обычной сборке этот код ничего не делает, а godebug его распознает перед компиляцией и вставит инструкцию для остановки.

Статус


Проект уже готов для практического использования, хотя поддерживаются пока только самые базовые функции:
  • list
  • step
  • next
  • continue
  • print

В планах поддержка остановки/инспекции горутин и другие вещи, которые коммьюнити сочтет нужными/полезными.

Ссылки:


This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.

Комментариев нет:

Отправить комментарий