1package interp
2
3import (
4	"context"
5	"errors"
6	"fmt"
7	"go/token"
8	"reflect"
9	"sort"
10	"sync"
11)
12
13var (
14	// ErrNotLive indicates that the specified ID does not refer to a (live) Go
15	// routine.
16	ErrNotLive = errors.New("not live")
17
18	// ErrRunning indicates that the specified Go routine is running.
19	ErrRunning = errors.New("running")
20
21	// ErrNotRunning indicates that the specified Go routine is running.
22	ErrNotRunning = errors.New("not running")
23)
24
25var rNodeType = reflect.TypeOf((*node)(nil)).Elem()
26
27// A Debugger can be used to debug a Yaegi program.
28type Debugger struct {
29	interp  *Interpreter
30	events  func(*DebugEvent)
31	context context.Context
32	cancel  context.CancelFunc
33
34	gWait *sync.WaitGroup
35	gLock *sync.Mutex
36	gID   int
37	gLive map[int]*debugRoutine
38
39	result reflect.Value
40	err    error
41}
42
43// go routine debug state.
44type debugRoutine struct {
45	id int
46
47	mode    DebugEventReason
48	running bool
49	resume  chan struct{}
50
51	fDepth int
52	fStep  int
53}
54
55// node debug state.
56type nodeDebugData struct {
57	program     *Program
58	breakOnLine bool
59	breakOnCall bool
60}
61
62// frame debug state.
63type frameDebugData struct {
64	g     *debugRoutine
65	node  *node
66	name  string
67	kind  frameKind
68	scope *scope
69}
70
71// frame kind.
72type frameKind int
73
74const (
75	// interpreter root frame.
76	frameRoot frameKind = iota + 1
77
78	// function call frame.
79	frameCall
80
81	// closure capture frame.
82	frameClosure
83)
84
85// DebugOptions are the debugger options.
86type DebugOptions struct {
87	// If true, Go routine IDs start at 1 instead of 0.
88	GoRoutineStartAt1 bool
89}
90
91// A DebugEvent is an event generated by a debugger.
92type DebugEvent struct {
93	debugger *Debugger
94	reason   DebugEventReason
95	frame    *frame
96}
97
98// DebugFrame provides access to stack frame information while debugging a
99// program.
100type DebugFrame struct {
101	event  *DebugEvent
102	frames []*frame
103}
104
105// DebugFrameScope provides access to scoped variables while debugging a
106// program.
107type DebugFrameScope struct {
108	frame *frame
109}
110
111// DebugVariable is the name and value of a variable from a debug session.
112type DebugVariable struct {
113	Name  string
114	Value reflect.Value
115}
116
117// DebugGoRoutine provides access to information about a Go routine while
118// debugging a program.
119type DebugGoRoutine struct {
120	id int
121}
122
123// Breakpoint is the result of attempting to set a breakpoint.
124type Breakpoint struct {
125	// Valid indicates whether the breakpoint was successfully set.
126	Valid bool
127
128	// Position indicates the source position of the breakpoint.
129	Position token.Position
130}
131
132// DebugEventReason is the reason a debug event occurred.
133type DebugEventReason int
134
135const (
136	// continue execution normally.
137	debugRun DebugEventReason = iota
138
139	// DebugPause is emitted when a pause request is completed. Can be used with
140	// Interrupt to request a pause.
141	DebugPause
142
143	// DebugBreak is emitted when a debug target hits a breakpoint.
144	DebugBreak
145
146	// DebugEntry is emitted when a debug target starts executing. Can be used
147	// with Step to produce a corresponding event when execution starts.
148	DebugEntry
149
150	// DebugStepInto is emitted when a stepInto request is completed. Can be
151	// used with Step or Interrupt to request a stepInto.
152	DebugStepInto
153
154	// DebugStepOver is emitted when a stepOver request is completed. Can be
155	// used with Step or Interrupt to request a stepOver.
156	DebugStepOver
157
158	// DebugStepOut is emitted when a stepOut request is completed. Can be used
159	// with Step or Interrupt to request a stepOut.
160	DebugStepOut
161
162	// DebugTerminate is emitted when a debug target terminates. Can be used
163	// with Interrupt to attempt to terminate the program.
164	DebugTerminate
165
166	// DebugEnterGoRoutine is emitted when a Go routine is entered.
167	DebugEnterGoRoutine
168
169	// DebugExitGoRoutine is emitted when a Go routine is exited.
170	DebugExitGoRoutine
171)
172
173// Debug initializes a debugger for the given program.
174//
175// The program will not start running until Step or Continue has been called. If
176// Step is called with DebugEntry, an entry event will be generated before the
177// first statement is executed. Otherwise, the debugger will behave as usual.
178func (interp *Interpreter) Debug(ctx context.Context, prog *Program, events func(*DebugEvent), opts *DebugOptions) *Debugger {
179	dbg := new(Debugger)
180	dbg.interp = interp
181	dbg.events = events
182	dbg.context, dbg.cancel = context.WithCancel(ctx)
183	dbg.gWait = new(sync.WaitGroup)
184	dbg.gLock = new(sync.Mutex)
185	dbg.gLive = make(map[int]*debugRoutine, 1)
186
187	if opts == nil {
188		opts = new(DebugOptions)
189	}
190	if opts.GoRoutineStartAt1 {
191		dbg.gID = 1
192	}
193
194	mainG := dbg.enterGoRoutine()
195	mainG.mode = DebugEntry
196
197	interp.debugger = dbg
198	interp.frame.debug = &frameDebugData{kind: frameRoot, g: mainG}
199
200	prog.root.Walk(func(n *node) bool {
201		n.setProgram(prog)
202		return true
203	}, nil)
204
205	go func() {
206		defer func() { interp.debugger = nil }()
207		defer events(&DebugEvent{reason: DebugTerminate})
208		defer dbg.cancel()
209
210		<-mainG.resume
211		dbg.events(&DebugEvent{dbg, DebugEnterGoRoutine, interp.frame})
212		dbg.result, dbg.err = interp.ExecuteWithContext(ctx, prog)
213		dbg.exitGoRoutine(mainG)
214		dbg.events(&DebugEvent{dbg, DebugExitGoRoutine, interp.frame})
215		dbg.gWait.Wait()
216	}()
217
218	return dbg
219}
220
221// Wait blocks until all Go routines launched by the program have terminated.
222// Wait returns the results of `(*Interpreter).Execute`.
223func (dbg *Debugger) Wait() (reflect.Value, error) {
224	<-dbg.context.Done()
225	return dbg.result, dbg.err
226}
227
228// mark entry into a go routine.
229func (dbg *Debugger) enterGoRoutine() *debugRoutine {
230	g := new(debugRoutine)
231	g.resume = make(chan struct{})
232
233	dbg.gWait.Add(1)
234
235	dbg.gLock.Lock()
236	g.id = dbg.gID
237	dbg.gID++
238	dbg.gLive[g.id] = g
239	dbg.gLock.Unlock()
240
241	return g
242}
243
244// mark exit from a go routine.
245func (dbg *Debugger) exitGoRoutine(g *debugRoutine) {
246	dbg.gLock.Lock()
247	delete(dbg.gLive, g.id)
248	dbg.gLock.Unlock()
249
250	dbg.gWait.Done()
251}
252
253// get the state for a given go routine, if it's live.
254func (dbg *Debugger) getGoRoutine(id int) (*debugRoutine, bool) {
255	dbg.gLock.Lock()
256	g, ok := dbg.gLive[id]
257	dbg.gLock.Unlock()
258	return g, ok
259}
260
261// mark entry into a function call.
262func (dbg *Debugger) enterCall(nFunc, nCall *node, f *frame) {
263	if f.debug != nil {
264		f.debug.g.fDepth++
265		return
266	}
267
268	f.debug = new(frameDebugData)
269	f.debug.g = f.anc.debug.g
270	f.debug.scope = nFunc.scope
271
272	switch nFunc.kind {
273	case funcLit:
274		f.debug.kind = frameCall
275		if nFunc.frame != nil {
276			nFunc.frame.debug.kind = frameClosure
277			nFunc.frame.debug.node = nFunc
278		}
279
280	case funcDecl:
281		f.debug.kind = frameCall
282		f.debug.name = nFunc.child[1].ident
283	}
284
285	if nCall != nil && nCall.anc.kind == goStmt {
286		f.debug.g = dbg.enterGoRoutine()
287		dbg.events(&DebugEvent{dbg, DebugEnterGoRoutine, f})
288	}
289
290	f.debug.g.fDepth++
291}
292
293// mark exit from a function call.
294func (dbg *Debugger) exitCall(nFunc, nCall *node, f *frame) {
295	_ = nFunc // ignore unused, so exitCall can have the same signature as enterCall
296
297	f.debug.g.fDepth--
298
299	if nCall != nil && nCall.anc.kind == goStmt {
300		dbg.exitGoRoutine(f.debug.g)
301		dbg.events(&DebugEvent{dbg, DebugExitGoRoutine, f})
302	}
303}
304
305// called by the interpreter prior to executing the node.
306func (dbg *Debugger) exec(n *node, f *frame) (stop bool) {
307	f.debug.node = n
308
309	if n != nil && n.pos == token.NoPos {
310		return false
311	}
312
313	g := f.debug.g
314	defer func() { g.running = true }()
315
316	e := &DebugEvent{dbg, g.mode, f}
317	switch {
318	case g.mode == DebugTerminate:
319		dbg.cancel()
320		return true
321
322	case n.shouldBreak():
323		e.reason = DebugBreak
324
325	case g.mode == debugRun:
326		return false
327
328	case g.mode == DebugStepOut:
329		if g.fDepth >= g.fStep {
330			return false
331		}
332
333	case g.mode == DebugStepOver:
334		if g.fDepth > g.fStep {
335			return false
336		}
337	}
338	dbg.events(e)
339
340	g.running = false
341	select {
342	case <-g.resume:
343		return false
344	case <-dbg.context.Done():
345		return true
346	}
347}
348
349// Continue continues execution of the specified Go routine. Continue returns
350// ErrNotLive if there is no Go routine with the corresponding ID, or if it is not
351// live.
352func (dbg *Debugger) Continue(id int) error {
353	g, ok := dbg.getGoRoutine(id)
354	if !ok {
355		return ErrNotLive
356	}
357
358	g.mode = debugRun
359	g.resume <- struct{}{}
360	return nil
361}
362
363// update the exec mode of this routine.
364func (g *debugRoutine) setMode(reason DebugEventReason) {
365	if g.mode == DebugTerminate {
366		return
367	}
368
369	if g.mode == DebugEntry && reason == DebugEntry {
370		return
371	}
372
373	switch reason {
374	case DebugStepInto, DebugStepOver, DebugStepOut:
375		g.mode, g.fStep = reason, g.fDepth
376	default:
377		g.mode = DebugPause
378	}
379}
380
381// Step issues a stepInto, stepOver, or stepOut request to a stopped Go routine.
382// Step returns ErrRunning if the Go routine is running. Step returns ErrNotLive
383// if there is no Go routine with the corresponding ID, or if it is not live.
384func (dbg *Debugger) Step(id int, reason DebugEventReason) error {
385	g, ok := dbg.getGoRoutine(id)
386	if !ok {
387		return ErrNotLive
388	}
389
390	if g.running {
391		return ErrRunning
392	}
393
394	g.setMode(reason)
395	g.resume <- struct{}{}
396	return nil
397}
398
399// Interrupt issues a stepInto, stepOver, or stepOut request to a running Go
400// routine. Interrupt returns ErrRunning if the Go routine is running. Interrupt
401// returns ErrNotLive if there is no Go routine with the corresponding ID, or if
402// it is not live.
403func (dbg *Debugger) Interrupt(id int, reason DebugEventReason) bool {
404	g, ok := dbg.getGoRoutine(id)
405	if !ok {
406		return false
407	}
408
409	g.setMode(reason)
410	return true
411}
412
413// Terminate attempts to terminate the program.
414func (dbg *Debugger) Terminate() {
415	dbg.gLock.Lock()
416	g := dbg.gLive
417	dbg.gLive = nil
418	dbg.gLock.Unlock()
419
420	for _, g := range g {
421		g.mode = DebugTerminate
422		close(g.resume)
423	}
424}
425
426// BreakpointTarget is the target of a request to set breakpoints.
427type BreakpointTarget func(*Debugger, func(*node))
428
429// PathBreakpointTarget is used to set breapoints on compiled code by path. This
430// can be used to set breakpoints on code compiled with EvalPath, or source
431// packages loaded by Yaegi.
432func PathBreakpointTarget(path string) BreakpointTarget {
433	return func(dbg *Debugger, cb func(*node)) {
434		for _, r := range dbg.interp.roots {
435			f := dbg.interp.fset.File(r.pos)
436			if f != nil && f.Name() == path {
437				cb(r)
438				return
439			}
440		}
441	}
442}
443
444// ProgramBreakpointTarget is used to set breakpoints on a Program.
445func ProgramBreakpointTarget(prog *Program) BreakpointTarget {
446	return func(_ *Debugger, cb func(*node)) {
447		cb(prog.root)
448	}
449}
450
451// AllBreakpointTarget is used to set breakpoints on all compiled code. Do not
452// use with LineBreakpoint.
453func AllBreakpointTarget() BreakpointTarget {
454	return func(dbg *Debugger, cb func(*node)) {
455		for _, r := range dbg.interp.roots {
456			cb(r)
457		}
458	}
459}
460
461type breakpointSetup struct {
462	roots []*node
463	lines map[int]int
464	funcs map[string]int
465}
466
467// BreakpointRequest is a request to set a breakpoint.
468type BreakpointRequest func(*breakpointSetup, int)
469
470// LineBreakpoint requests a breakpoint on the given line.
471func LineBreakpoint(line int) BreakpointRequest {
472	return func(b *breakpointSetup, i int) {
473		b.lines[line] = i
474	}
475}
476
477// FunctionBreakpoint requests a breakpoint on the named function.
478func FunctionBreakpoint(name string) BreakpointRequest {
479	return func(b *breakpointSetup, i int) {
480		b.funcs[name] = i
481	}
482}
483
484// SetBreakpoints sets breakpoints for the given target. The returned array has
485// an entry for every request, in order. If a given breakpoint request cannot be
486// satisfied, the corresponding entry will be marked invalid. If the target
487// cannot be found, all entries will be marked invalid.
488func (dbg *Debugger) SetBreakpoints(target BreakpointTarget, requests ...BreakpointRequest) []Breakpoint {
489	// start with all breakpoints unverified
490	results := make([]Breakpoint, len(requests))
491
492	// prepare all the requests
493	setup := new(breakpointSetup)
494	target(dbg, func(root *node) {
495		setup.roots = append(setup.roots, root)
496		setup.lines = make(map[int]int, len(requests))
497		setup.funcs = make(map[string]int, len(requests))
498		for i, rq := range requests {
499			rq(setup, i)
500		}
501	})
502
503	// find breakpoints
504	for _, root := range setup.roots {
505		root.Walk(func(n *node) bool {
506			// function breakpoints
507			if len(setup.funcs) > 0 && n.kind == funcDecl {
508				// reset stale breakpoints
509				n.start.setBreakOnCall(false)
510
511				if i, ok := setup.funcs[n.child[1].ident]; ok && !results[i].Valid {
512					results[i].Valid = true
513					results[i].Position = dbg.interp.fset.Position(n.start.pos)
514					n.start.setBreakOnCall(true)
515					return true
516				}
517			}
518
519			// line breakpoints
520			if len(setup.lines) > 0 && n.pos.IsValid() && n.action != aNop && getExec(n) != nil {
521				// reset stale breakpoints
522				n.setBreakOnLine(false)
523
524				pos := dbg.interp.fset.Position(n.pos)
525				if i, ok := setup.lines[pos.Line]; ok && !results[i].Valid {
526					results[i].Valid = true
527					results[i].Position = pos
528					n.setBreakOnLine(true)
529					return true
530				}
531			}
532
533			return true
534		}, nil)
535	}
536
537	return results
538}
539
540// GoRoutines returns an array of live Go routines.
541func (dbg *Debugger) GoRoutines() []*DebugGoRoutine {
542	dbg.gLock.Lock()
543	r := make([]*DebugGoRoutine, 0, len(dbg.gLive))
544	for id := range dbg.gLive {
545		r = append(r, &DebugGoRoutine{id})
546	}
547	dbg.gLock.Unlock()
548	sort.Slice(r, func(i, j int) bool { return r[i].id < r[j].id })
549	return r
550}
551
552// ID returns the ID of the Go routine.
553func (r *DebugGoRoutine) ID() int { return r.id }
554
555// Name returns "Goroutine {ID}".
556func (r *DebugGoRoutine) Name() string { return fmt.Sprintf("Goroutine %d", r.id) }
557
558// GoRoutine returns the ID of the Go routine that generated the event.
559func (evt *DebugEvent) GoRoutine() int {
560	if evt.frame.debug == nil {
561		return 0
562	}
563	return evt.frame.debug.g.id
564}
565
566// Reason returns the reason for the event.
567func (evt *DebugEvent) Reason() DebugEventReason {
568	return evt.reason
569}
570
571// Walk the stack trace frames. The root frame is included if and only if it is
572// the only frame. Closure frames are rolled up into the following call frame.
573func (evt *DebugEvent) walkFrames(fn func([]*frame) bool) {
574	if evt.frame == evt.frame.root {
575		fn([]*frame{evt.frame})
576		return
577	}
578
579	var g *debugRoutine
580	if evt.frame.debug != nil {
581		g = evt.frame.debug.g
582	}
583
584	var frames []*frame
585	for f := evt.frame; f != nil && f != f.root && (f.debug == nil || f.debug.g == g); f = f.anc {
586		if f.debug == nil || f.debug.kind != frameCall {
587			frames = append(frames, f)
588			continue
589		}
590
591		if len(frames) > 0 {
592			if !fn(frames) {
593				return
594			}
595		}
596
597		frames = frames[:0]
598		frames = append(frames, f)
599	}
600
601	if len(frames) > 0 {
602		fn(frames)
603	}
604}
605
606// FrameDepth returns the number of call frames in the stack trace.
607func (evt *DebugEvent) FrameDepth() int {
608	if evt.frame == evt.frame.root {
609		return 1
610	}
611
612	var n int
613	evt.walkFrames(func([]*frame) bool { n++; return true })
614	return n
615}
616
617// Frames returns the call frames in the range [start, end).
618func (evt *DebugEvent) Frames(start, end int) []*DebugFrame {
619	count := end - start
620	if count < 0 {
621		return nil
622	}
623
624	frames := []*DebugFrame{}
625	evt.walkFrames(func(f []*frame) bool {
626		df := &DebugFrame{evt, make([]*frame, len(f))}
627		copy(df.frames, f)
628		frames = append(frames, df)
629		return len(frames) < count
630	})
631	return frames
632}
633
634// Name returns the name of the stack frame. For function calls to named
635// functions, this is the function name.
636func (f *DebugFrame) Name() string {
637	d := f.frames[0].debug
638	if d == nil {
639		return "<unknown>"
640	}
641	switch d.kind {
642	case frameRoot:
643		return "<init>"
644	case frameClosure:
645		return "<closure>"
646	case frameCall:
647		if d.name == "" {
648			return "<anonymous>"
649		}
650		return d.name
651	default:
652		return "<unknown>"
653	}
654}
655
656// Position returns the current position of the frame. This is effectively the
657// program counter/link register. May return `Position{}`.
658func (f *DebugFrame) Position() token.Position {
659	d := f.frames[0].debug
660	if d == nil || d.node == nil {
661		return token.Position{}
662	}
663	return f.event.debugger.interp.fset.Position(d.node.pos)
664}
665
666// Program returns the program associated with the current position of the
667// frame. May return nil.
668func (f *DebugFrame) Program() *Program {
669	d := f.frames[0].debug
670	if d == nil || d.node == nil {
671		return nil
672	}
673
674	return d.node.debug.program
675}
676
677// Scopes returns the variable scopes of the frame.
678func (f *DebugFrame) Scopes() []*DebugFrameScope {
679	s := make([]*DebugFrameScope, len(f.frames))
680	for i, f := range f.frames {
681		s[i] = &DebugFrameScope{f}
682	}
683	return s
684}
685
686// IsClosure returns true if this is the capture scope of a closure.
687func (f *DebugFrameScope) IsClosure() bool {
688	return f.frame.debug != nil && f.frame.debug.kind == frameClosure
689}
690
691// Variables returns the names and values of the variables of the scope.
692func (f *DebugFrameScope) Variables() []*DebugVariable {
693	d := f.frame.debug
694	if d == nil || d.scope == nil {
695		return nil
696	}
697
698	index := map[int]string{}
699	scanScope(d.scope, index)
700
701	m := make([]*DebugVariable, 0, len(f.frame.data))
702	for i, v := range f.frame.data {
703		if typ := v.Type(); typ.AssignableTo(rNodeType) || typ.Kind() == reflect.Ptr && typ.Elem().AssignableTo(rNodeType) {
704			continue
705		}
706		name, ok := index[i]
707		if !ok {
708			continue
709		}
710
711		m = append(m, &DebugVariable{name, v})
712	}
713	return m
714}
715
716func scanScope(sc *scope, index map[int]string) {
717	for name, sym := range sc.sym {
718		if _, ok := index[sym.index]; ok {
719			continue
720		}
721		index[sym.index] = name
722	}
723
724	for _, ch := range sc.child {
725		if ch.def != sc.def {
726			continue
727		}
728		scanScope(ch, index)
729	}
730}
731