debugger

package
v0.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 18, 2025 License: Apache-2.0 Imports: 10 Imported by: 0

README

debugger

Package debugger implements a simple interactive debugger for starlark-go. It can be used in any starlark-go application, not necessarily one that uses skycfg.

Example session

❯ go test -c github.com/stripe/skycfg/debugger && ./debugger.test -example
[<prog>:6:19] breakpoint: Stopped
[<prog>:6:19] Available functions: c[ont[inue_]] (or Ctrl+D), q[uit], w[here]/b[ack]t[race], d[own], u[p], f[rame], vars, globals, locals
>>> bt()
Traceback (most recent call last):
   1. <prog>:10:4: in <toplevel>
>  0. <prog>:6:19: in f
>>> vars()
All predeclared symbols in frame 0 (f):
  predeclared: string = "value"
  breakpoint: builtin_function_or_method = <built-in function breakpoint>

All globals in frame 0 (f):
  g: function = <function g>

All free vars in frame 0 (f):
  closure (<prog>:3:5): list = [42]

All locals in frame 0 (f):
  local_var (<prog>:5:9): int = 1
>>> closure
[42]
>>> closure.append(local_var)
>>> closure
[42, 1]
Switch to a different frame
>>> f(1)
breakpoint: Stopped at <prog>:10:4: in <toplevel>
>>> bt()
Traceback (most recent call last):
>  1. <prog>:10:4: in <toplevel>
   0. <prog>:6:19: in f
>>> vars()
All predeclared symbols in frame 1 (<toplevel>):
  predeclared: string = "value"
  breakpoint: builtin_function_or_method = <built-in function breakpoint>

All globals in frame 1 (<toplevel>):
  g: function = <function g>

All free vars in frame 1 (<toplevel>):

All locals in frame 1 (<toplevel>):
Continue execution

Notice that the change to variable closure is persisted.

>>> cont()
closure=[42, 1]

Documentation

Overview

Package debugger implements a simple interactive debugger for starlark-go, aka go.starlark.net/starlark.

The debugger exposes a single breakpoint() function to ordinary Starlark code, which starts up an interactive REPL-style debugging session, in which users can examine the Starlark thread stack and manipulate values.

Stepping through code is not supported due to restrictions in starlark-go. See https://github.com/google/starlark-go/issues/304 for details.

Enabling and disabling breakpoints

By default, all breakpoints are enabled. All breakpoint() calls can be globally disabled by calling Debugger.GlobalDisable, or reenabled with Debugger.GlobalEnable.

Debugger commands

The debugger REPL has a few builtin commands implemented as functions:

Basic debugging:

where(), w()             - prints a backtrace
backtrace(), bt()        - prints a backtrace (same as where)
continue_(), c(), cont() - exits the debugger and continue Starlark execution
quit(), q()              - exits the debugger and fail Starlark execution

Variables:

vars()    - prints all available variables and their values in the current frame
globals() - returns a dict of global variables from the context of the code calling breakpoint()
locals()  - returns a dict of local variables from the context of the code calling breakpoint()

Frame manipulation:

frame(i), f(i) - switches the debugging context to the frame at the given index
up(), u()      - switches the debugging context to the upper frame (the caller of the current frame)
up(i), u(i)    - switches the debugging context to i'th upper frame (the i'th caller of the current frame)
down(), d()    - switches the debugging context to the lower frame (the callee of the current frame)
down(i), d(i)  - switches the debugging context to i'th lower frame (the i'th callee of the current frame)

Concurrency and reentrancy

Since each debugger session takes over the entire os.Stdin, concurrent debugger sessions don't make sense. As such, upon entering the debugging session, a lock is taken, in order to prevent new debugging sessions from launched, and also to wait for previous sessions to finish. This lock is shared across all Debuggers.

Reentrant calls to breakpoint() (i.e., calls to breakpoint() from within a debugging session) are not supported and will be ignored with a warning.

Example
package main

import (
	"bytes"
	"fmt"
	"io"
	"os"

	"go.starlark.net/starlark"
	"go.starlark.net/syntax"

	"github.com/stripe/skycfg/debugger"
)

func main() {
	// Run this example with
	//
	//	go test -c github.com/stripe/skycfg/debugger && ./debugger.test -example

	prog := `
def g():
    closure = [42]
    def f():
        local_var = 1
        breakpoint()
        print("closure=" + str(closure))
    return f

g()()
`

	dbg := debugger.New()
	thread := starlark.Thread{
		Print: printWithPos,
	}
	starlark.ExecFileOptions(&syntax.FileOptions{}, &thread, "<prog>", prog, starlark.StringDict{
		"predeclared": starlark.String("value"),
		"breakpoint":  dbg.Breakpoint(),
	})
}

func printWithPos(thread *starlark.Thread, msg string) {
	var buf bytes.Buffer
	if thread.CallStackDepth() > 1 {
		pos := thread.CallFrame(1).Pos
		fmt.Fprintf(&buf, "[%v] ", pos)
	}
	fmt.Fprintf(&buf, msg)
	buf.WriteByte('\n')

	io.Copy(os.Stdout, &buf)
}

Index

Examples

Constants

This section is empty.

Variables

View Source
var DefaultDebuggerSyntax = syntax.FileOptions{
	Set:               true,
	While:             true,
	TopLevelControl:   true,
	GlobalReassign:    true,
	LoadBindsGlobally: true,
	Recursion:         true,
}

DefaultDebuggerSyntax defines the set of Starlark language features available within a debugging session.

Functions

This section is empty.

Types

type Debugger

type Debugger struct {
	// contains filtered or unexported fields
}

A Debugger captures shared state across debugging sessions. The same Debugger can be used concurrently from multiple starlark.Threads and goroutines, though as mentioned in the package documentation, only one debug session can be active across all Debuggers at any given point in time.

A new Debugger must be created using New.

func New

func New() *Debugger

New creates a new Debugger.

func (*Debugger) Breakpoint

func (d *Debugger) Breakpoint() *starlark.Builtin

Breakpoint returns the breakpoint() Starlark builtin to be added as a global. Breakpoint always returns the same value for the same Debugger.

func (*Debugger) GlobalDisable

func (d *Debugger) GlobalDisable()

GlobalDisable disables all breakpoints.

func (*Debugger) GlobalEnable

func (d *Debugger) GlobalEnable()

GlobalEnable reverses Debugger.GlobalDisable and enables all breakpoints.

func (*Debugger) SetSyntax

func (d *Debugger) SetSyntax(opts *syntax.FileOptions)

SetSyntax sets the Starlark language options that can be used in a debugger session. If SetSyntax is never called, DefaultDebuggerSyntax is used.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL