2016-04-18 19:20:20 +00:00
package rpc2
import (
"errors"
"fmt"
2023-09-18 15:59:58 +00:00
"regexp"
2020-07-07 13:21:18 +00:00
"sort"
2016-12-22 16:53:34 +00:00
"time"
2016-04-18 19:20:20 +00:00
2020-07-07 13:21:18 +00:00
"github.com/go-delve/delve/pkg/dwarf/op"
"github.com/go-delve/delve/pkg/proc"
2019-01-04 18:39:25 +00:00
"github.com/go-delve/delve/service"
"github.com/go-delve/delve/service/api"
"github.com/go-delve/delve/service/debugger"
2016-04-18 19:20:20 +00:00
)
type RPCServer struct {
// config is all the information necessary to start the debugger and server.
config * service . Config
// debugger is a debugger service.
debugger * debugger . Debugger
}
2016-06-19 06:43:29 +00:00
func NewServer ( config * service . Config , debugger * debugger . Debugger ) * RPCServer {
return & RPCServer { config , debugger }
2016-04-18 19:20:20 +00:00
}
type ProcessPidIn struct {
}
type ProcessPidOut struct {
Pid int
}
2016-04-24 17:18:02 +00:00
// ProcessPid returns the pid of the process we are debugging.
2016-04-18 19:20:20 +00:00
func ( s * RPCServer ) ProcessPid ( arg ProcessPidIn , out * ProcessPidOut ) error {
out . Pid = s . debugger . ProcessPid ( )
return nil
}
2016-12-22 16:53:34 +00:00
type LastModifiedIn struct {
}
type LastModifiedOut struct {
Time time . Time
}
func ( s * RPCServer ) LastModified ( arg LastModifiedIn , out * LastModifiedOut ) error {
out . Time = s . debugger . LastModified ( )
return nil
}
2016-04-18 19:20:20 +00:00
type DetachIn struct {
Kill bool
}
type DetachOut struct {
}
2016-04-24 17:18:02 +00:00
// Detach detaches the debugger, optionally killing the process.
2016-04-18 19:20:20 +00:00
func ( s * RPCServer ) Detach ( arg DetachIn , out * DetachOut ) error {
2021-04-19 18:12:51 +00:00
return s . debugger . Detach ( arg . Kill )
2016-04-18 19:20:20 +00:00
}
type RestartIn struct {
2017-05-05 22:17:52 +00:00
// Position to restart from, if it starts with 'c' it's a checkpoint ID,
// otherwise it's an event number. Only valid for recorded targets.
Position string
2018-01-18 22:16:11 +00:00
2020-08-21 14:14:02 +00:00
// ResetArgs tell whether NewArgs and NewRedirects should take effect.
2018-01-18 22:16:11 +00:00
ResetArgs bool
// NewArgs are arguments to launch a new process. They replace only the
// argv[1] and later. Argv[0] cannot be changed.
NewArgs [ ] string
2019-10-21 18:48:04 +00:00
// When Rerecord is set the target will be rerecorded
Rerecord bool
2020-06-05 18:03:09 +00:00
// When Rebuild is set the process will be build again
Rebuild bool
2020-08-21 14:14:02 +00:00
NewRedirects [ 3 ] string
2016-04-18 19:20:20 +00:00
}
type RestartOut struct {
2016-12-22 16:53:34 +00:00
DiscardedBreakpoints [ ] api . DiscardedBreakpoint
2016-04-18 19:20:20 +00:00
}
2016-04-24 17:18:02 +00:00
// Restart restarts program.
2020-03-24 16:09:28 +00:00
func ( s * RPCServer ) Restart ( arg RestartIn , cb service . RPCCallback ) {
2021-03-08 18:05:10 +00:00
close ( cb . SetupDoneChan ( ) )
2020-04-13 18:07:15 +00:00
if s . config . Debugger . AttachPid != 0 {
2020-03-24 16:09:28 +00:00
cb . Return ( nil , errors . New ( "cannot restart process Delve did not create" ) )
return
2016-04-18 19:20:20 +00:00
}
2020-03-24 16:09:28 +00:00
var out RestartOut
2016-12-22 16:53:34 +00:00
var err error
2020-08-21 14:14:02 +00:00
out . DiscardedBreakpoints , err = s . debugger . Restart ( arg . Rerecord , arg . Position , arg . ResetArgs , arg . NewArgs , arg . NewRedirects , arg . Rebuild )
2020-03-24 16:09:28 +00:00
cb . Return ( out , err )
2016-04-18 19:20:20 +00:00
}
type StateIn struct {
2018-06-21 11:07:37 +00:00
// If NonBlocking is true State will return immediately even if the target process is running.
NonBlocking bool
2016-04-18 19:20:20 +00:00
}
type StateOut struct {
State * api . DebuggerState
}
2016-04-24 17:18:02 +00:00
// State returns the current debugger state.
2020-03-24 16:09:28 +00:00
func ( s * RPCServer ) State ( arg StateIn , cb service . RPCCallback ) {
2021-03-08 18:05:10 +00:00
close ( cb . SetupDoneChan ( ) )
2020-03-24 16:09:28 +00:00
var out StateOut
2018-06-21 11:07:37 +00:00
st , err := s . debugger . State ( arg . NonBlocking )
2016-04-18 19:20:20 +00:00
if err != nil {
2020-03-24 16:09:28 +00:00
cb . Return ( nil , err )
return
2016-04-18 19:20:20 +00:00
}
out . State = st
2020-03-24 16:09:28 +00:00
cb . Return ( out , nil )
2016-04-18 19:20:20 +00:00
}
type CommandOut struct {
State api . DebuggerState
}
2016-04-24 17:18:02 +00:00
// Command interrupts, continues and steps through the program.
2016-06-19 06:43:29 +00:00
func ( s * RPCServer ) Command ( command api . DebuggerCommand , cb service . RPCCallback ) {
2024-06-12 19:31:46 +00:00
st , err := s . debugger . Command ( & command , cb . SetupDoneChan ( ) , cb . DisconnectChan ( ) )
2016-04-18 19:20:20 +00:00
if err != nil {
2016-06-19 06:43:29 +00:00
cb . Return ( nil , err )
return
2016-04-18 19:20:20 +00:00
}
2016-06-19 06:43:29 +00:00
var out CommandOut
2016-04-18 19:20:20 +00:00
out . State = * st
2016-06-19 06:43:29 +00:00
cb . Return ( out , nil )
2016-04-18 19:20:20 +00:00
}
2021-07-31 15:16:26 +00:00
type GetBufferedTracepointsIn struct {
}
type GetBufferedTracepointsOut struct {
TracepointResults [ ] api . TracepointResult
}
func ( s * RPCServer ) GetBufferedTracepoints ( arg GetBufferedTracepointsIn , out * GetBufferedTracepointsOut ) error {
out . TracepointResults = s . debugger . GetBufferedTracepoints ( )
return nil
}
2016-04-18 19:20:20 +00:00
type GetBreakpointIn struct {
Id int
Name string
}
type GetBreakpointOut struct {
Breakpoint api . Breakpoint
}
2016-04-24 17:18:02 +00:00
// GetBreakpoint gets a breakpoint by Name (if Name is not an empty string) or by ID.
2016-04-18 19:20:20 +00:00
func ( s * RPCServer ) GetBreakpoint ( arg GetBreakpointIn , out * GetBreakpointOut ) error {
var bp * api . Breakpoint
if arg . Name != "" {
bp = s . debugger . FindBreakpointByName ( arg . Name )
if bp == nil {
return fmt . Errorf ( "no breakpoint with name %s" , arg . Name )
}
} else {
bp = s . debugger . FindBreakpoint ( arg . Id )
if bp == nil {
return fmt . Errorf ( "no breakpoint with id %d" , arg . Id )
}
}
out . Breakpoint = * bp
return nil
}
type StacktraceIn struct {
2022-08-16 16:31:11 +00:00
Id int64
2018-07-06 07:37:31 +00:00
Depth int
Full bool
2019-09-25 17:21:20 +00:00
Defers bool // read deferred functions (equivalent to passing StacktraceReadDefers in Opts)
Opts api . StacktraceOptions
2018-07-06 07:37:31 +00:00
Cfg * api . LoadConfig
2016-04-18 19:20:20 +00:00
}
type StacktraceOut struct {
Locations [ ] api . Stackframe
}
2016-04-24 17:18:02 +00:00
// Stacktrace returns stacktrace of goroutine Id up to the specified Depth.
//
// If Full is set it will also the variable of all local variables
// and function arguments of all stack frames.
2016-04-18 19:20:20 +00:00
func ( s * RPCServer ) Stacktrace ( arg StacktraceIn , out * StacktraceOut ) error {
2016-04-24 17:15:39 +00:00
cfg := arg . Cfg
if cfg == nil && arg . Full {
2020-03-18 16:25:32 +00:00
cfg = & api . LoadConfig { FollowPointers : true , MaxVariableRecurse : 1 , MaxStringLen : 64 , MaxArrayValues : 64 , MaxStructFields : - 1 }
2016-04-24 17:15:39 +00:00
}
2019-09-25 17:21:20 +00:00
if arg . Defers {
arg . Opts |= api . StacktraceReadDefers
}
2020-07-07 13:21:18 +00:00
rawlocs , err := s . debugger . Stacktrace ( arg . Id , arg . Depth , arg . Opts )
if err != nil {
return err
}
out . Locations , err = s . debugger . ConvertStacktrace ( rawlocs , api . LoadConfigToProc ( cfg ) )
2019-03-16 13:50:18 +00:00
return err
}
type AncestorsIn struct {
2022-08-16 16:31:11 +00:00
GoroutineID int64
2019-03-16 13:50:18 +00:00
NumAncestors int
Depth int
}
type AncestorsOut struct {
Ancestors [ ] api . Ancestor
}
// Ancestors returns the stacktraces for the ancestors of a goroutine.
func ( s * RPCServer ) Ancestors ( arg AncestorsIn , out * AncestorsOut ) error {
var err error
out . Ancestors , err = s . debugger . Ancestors ( arg . GoroutineID , arg . NumAncestors , arg . Depth )
return err
2016-04-18 19:20:20 +00:00
}
type ListBreakpointsIn struct {
2021-08-09 17:41:25 +00:00
All bool
2016-04-18 19:20:20 +00:00
}
type ListBreakpointsOut struct {
Breakpoints [ ] * api . Breakpoint
}
2016-04-24 17:18:02 +00:00
// ListBreakpoints gets all breakpoints.
2016-04-18 19:20:20 +00:00
func ( s * RPCServer ) ListBreakpoints ( arg ListBreakpointsIn , out * ListBreakpointsOut ) error {
2021-08-09 17:41:25 +00:00
out . Breakpoints = s . debugger . Breakpoints ( arg . All )
2016-04-18 19:20:20 +00:00
return nil
}
type CreateBreakpointIn struct {
Breakpoint api . Breakpoint
2022-09-28 18:35:07 +00:00
LocExpr string
SubstitutePathRules [ ] [ 2 ] string
2022-10-04 15:07:05 +00:00
Suspended bool
2016-04-18 19:20:20 +00:00
}
type CreateBreakpointOut struct {
Breakpoint api . Breakpoint
}
2021-06-29 13:14:24 +00:00
// CreateBreakpoint creates a new breakpoint. The client is expected to populate `CreateBreakpointIn`
2023-05-23 16:21:36 +00:00
// with an `api.Breakpoint` struct describing where to set the breakpoint. For more information on
2021-06-29 13:14:24 +00:00
// how to properly request a breakpoint via the `api.Breakpoint` struct see the documentation for
// `debugger.CreateBreakpoint` here: https://pkg.go.dev/github.com/go-delve/delve/service/debugger#Debugger.CreateBreakpoint.
2016-04-18 19:20:20 +00:00
func ( s * RPCServer ) CreateBreakpoint ( arg CreateBreakpointIn , out * CreateBreakpointOut ) error {
2021-05-28 18:21:53 +00:00
if err := api . ValidBreakpointName ( arg . Breakpoint . Name ) ; err != nil {
return err
}
2022-10-04 15:07:05 +00:00
createdbp , err := s . debugger . CreateBreakpoint ( & arg . Breakpoint , arg . LocExpr , arg . SubstitutePathRules , arg . Suspended )
2016-04-18 19:20:20 +00:00
if err != nil {
return err
}
out . Breakpoint = * createdbp
return nil
}
2021-07-31 15:16:26 +00:00
type CreateEBPFTracepointIn struct {
FunctionName string
}
type CreateEBPFTracepointOut struct {
Breakpoint api . Breakpoint
}
func ( s * RPCServer ) CreateEBPFTracepoint ( arg CreateEBPFTracepointIn , out * CreateEBPFTracepointOut ) error {
return s . debugger . CreateEBPFTracepoint ( arg . FunctionName )
}
2016-04-18 19:20:20 +00:00
type ClearBreakpointIn struct {
Id int
Name string
}
type ClearBreakpointOut struct {
Breakpoint * api . Breakpoint
}
2016-04-24 17:18:02 +00:00
// ClearBreakpoint deletes a breakpoint by Name (if Name is not an
// empty string) or by ID.
2016-04-18 19:20:20 +00:00
func ( s * RPCServer ) ClearBreakpoint ( arg ClearBreakpointIn , out * ClearBreakpointOut ) error {
var bp * api . Breakpoint
if arg . Name != "" {
bp = s . debugger . FindBreakpointByName ( arg . Name )
if bp == nil {
return fmt . Errorf ( "no breakpoint with name %s" , arg . Name )
}
} else {
bp = s . debugger . FindBreakpoint ( arg . Id )
if bp == nil {
return fmt . Errorf ( "no breakpoint with id %d" , arg . Id )
}
}
deleted , err := s . debugger . ClearBreakpoint ( bp )
if err != nil {
return err
}
out . Breakpoint = deleted
return nil
}
2021-03-19 18:02:23 +00:00
type ToggleBreakpointIn struct {
Id int
Name string
}
type ToggleBreakpointOut struct {
Breakpoint * api . Breakpoint
}
// ToggleBreakpoint toggles on or off a breakpoint by Name (if Name is not an
// empty string) or by ID.
func ( s * RPCServer ) ToggleBreakpoint ( arg ToggleBreakpointIn , out * ToggleBreakpointOut ) error {
var bp * api . Breakpoint
if arg . Name != "" {
bp = s . debugger . FindBreakpointByName ( arg . Name )
if bp == nil {
return fmt . Errorf ( "no breakpoint with name %s" , arg . Name )
}
} else {
bp = s . debugger . FindBreakpoint ( arg . Id )
if bp == nil {
return fmt . Errorf ( "no breakpoint with id %d" , arg . Id )
}
}
bp . Disabled = ! bp . Disabled
2021-05-28 18:21:53 +00:00
if err := api . ValidBreakpointName ( bp . Name ) ; err != nil {
return err
}
2021-03-19 18:02:23 +00:00
if err := s . debugger . AmendBreakpoint ( bp ) ; err != nil {
return err
}
out . Breakpoint = bp
return nil
}
2016-04-18 19:20:20 +00:00
type AmendBreakpointIn struct {
Breakpoint api . Breakpoint
}
type AmendBreakpointOut struct {
}
2016-04-24 17:18:02 +00:00
// AmendBreakpoint allows user to update an existing breakpoint
// for example to change the information retrieved when the
// breakpoint is hit or to change, add or remove the break condition.
//
// arg.Breakpoint.ID must be a valid breakpoint ID
2016-04-18 19:20:20 +00:00
func ( s * RPCServer ) AmendBreakpoint ( arg AmendBreakpointIn , out * AmendBreakpointOut ) error {
2021-05-28 18:21:53 +00:00
if err := api . ValidBreakpointName ( arg . Breakpoint . Name ) ; err != nil {
return err
}
2016-04-18 19:20:20 +00:00
return s . debugger . AmendBreakpoint ( & arg . Breakpoint )
}
2016-04-24 23:20:02 +00:00
type CancelNextIn struct {
}
type CancelNextOut struct {
}
func ( s * RPCServer ) CancelNext ( arg CancelNextIn , out * CancelNextOut ) error {
return s . debugger . CancelNext ( )
}
2016-04-18 19:20:20 +00:00
type ListThreadsIn struct {
}
type ListThreadsOut struct {
Threads [ ] * api . Thread
}
2016-04-24 17:18:02 +00:00
// ListThreads lists all threads.
2016-04-18 19:20:20 +00:00
func ( s * RPCServer ) ListThreads ( arg ListThreadsIn , out * ListThreadsOut ) ( err error ) {
2020-07-07 13:21:18 +00:00
threads , err := s . debugger . Threads ( )
if err != nil {
return err
}
s . debugger . LockTarget ( )
defer s . debugger . UnlockTarget ( )
2022-05-25 20:58:26 +00:00
out . Threads = api . ConvertThreads ( threads , s . debugger . ConvertThreadBreakpoint )
2020-07-07 13:21:18 +00:00
return nil
2016-04-18 19:20:20 +00:00
}
type GetThreadIn struct {
Id int
}
type GetThreadOut struct {
Thread * api . Thread
}
2016-04-24 17:18:02 +00:00
// GetThread gets a thread by its ID.
2016-04-18 19:20:20 +00:00
func ( s * RPCServer ) GetThread ( arg GetThreadIn , out * GetThreadOut ) error {
t , err := s . debugger . FindThread ( arg . Id )
if err != nil {
return err
}
if t == nil {
return fmt . Errorf ( "no thread with id %d" , arg . Id )
}
2020-07-07 13:21:18 +00:00
s . debugger . LockTarget ( )
defer s . debugger . UnlockTarget ( )
2022-05-25 20:58:26 +00:00
out . Thread = api . ConvertThread ( t , s . debugger . ConvertThreadBreakpoint ( t ) )
2016-04-18 19:20:20 +00:00
return nil
}
type ListPackageVarsIn struct {
Filter string
2016-06-19 06:43:29 +00:00
Cfg api . LoadConfig
2016-04-18 19:20:20 +00:00
}
type ListPackageVarsOut struct {
Variables [ ] api . Variable
}
2016-04-24 17:18:02 +00:00
// ListPackageVars lists all package variables in the context of the current thread.
2016-04-18 19:20:20 +00:00
func ( s * RPCServer ) ListPackageVars ( arg ListPackageVarsIn , out * ListPackageVarsOut ) error {
2020-09-24 15:02:29 +00:00
vars , err := s . debugger . PackageVariables ( arg . Filter , * api . LoadConfigToProc ( & arg . Cfg ) )
2016-04-18 19:20:20 +00:00
if err != nil {
return err
}
2020-07-07 13:21:18 +00:00
out . Variables = api . ConvertVars ( vars )
2016-04-18 19:20:20 +00:00
return nil
}
type ListRegistersIn struct {
2016-11-15 16:16:33 +00:00
ThreadID int
IncludeFp bool
2020-02-24 18:47:02 +00:00
Scope * api . EvalScope
2016-04-18 19:20:20 +00:00
}
type ListRegistersOut struct {
Registers string
2016-11-15 16:16:33 +00:00
Regs api . Registers
2016-04-18 19:20:20 +00:00
}
2016-04-24 17:18:02 +00:00
// ListRegisters lists registers and their values.
2020-02-24 18:47:02 +00:00
// If ListRegistersIn.Scope is not nil the registers of that eval scope will
// be returned, otherwise ListRegistersIn.ThreadID will be used.
2016-04-18 19:20:20 +00:00
func ( s * RPCServer ) ListRegisters ( arg ListRegistersIn , out * ListRegistersOut ) error {
2020-02-24 18:47:02 +00:00
if arg . ThreadID == 0 && arg . Scope == nil {
2018-06-21 11:07:37 +00:00
state , err := s . debugger . State ( false )
2016-11-15 16:16:33 +00:00
if err != nil {
return err
}
arg . ThreadID = state . CurrentThread . ID
2016-04-18 19:20:20 +00:00
}
2020-07-07 13:21:18 +00:00
var regs * op . DwarfRegisters
var err error
if arg . Scope != nil {
2023-11-05 16:36:37 +00:00
regs , err = s . debugger . ScopeRegisters ( arg . Scope . GoroutineID , arg . Scope . Frame , arg . Scope . DeferredCall )
2020-07-07 13:21:18 +00:00
} else {
2023-11-05 16:36:37 +00:00
regs , err = s . debugger . ThreadRegisters ( arg . ThreadID )
2020-07-07 13:21:18 +00:00
}
2016-04-18 19:20:20 +00:00
if err != nil {
return err
}
2020-07-07 13:21:18 +00:00
out . Regs = api . ConvertRegisters ( regs , s . debugger . DwarfRegisterToString , arg . IncludeFp )
2016-11-15 16:16:33 +00:00
out . Registers = out . Regs . String ( )
2016-04-18 19:20:20 +00:00
return nil
}
type ListLocalVarsIn struct {
Scope api . EvalScope
2016-06-19 06:43:29 +00:00
Cfg api . LoadConfig
2016-04-18 19:20:20 +00:00
}
type ListLocalVarsOut struct {
Variables [ ] api . Variable
}
2016-04-24 17:18:02 +00:00
// ListLocalVars lists all local variables in scope.
2016-04-18 19:20:20 +00:00
func ( s * RPCServer ) ListLocalVars ( arg ListLocalVarsIn , out * ListLocalVarsOut ) error {
2020-07-07 13:21:18 +00:00
vars , err := s . debugger . LocalVariables ( arg . Scope . GoroutineID , arg . Scope . Frame , arg . Scope . DeferredCall , * api . LoadConfigToProc ( & arg . Cfg ) )
2016-04-18 19:20:20 +00:00
if err != nil {
return err
}
2020-07-07 13:21:18 +00:00
out . Variables = api . ConvertVars ( vars )
2016-04-18 19:20:20 +00:00
return nil
}
type ListFunctionArgsIn struct {
Scope api . EvalScope
2016-06-19 06:43:29 +00:00
Cfg api . LoadConfig
2016-04-18 19:20:20 +00:00
}
type ListFunctionArgsOut struct {
Args [ ] api . Variable
}
2016-04-24 17:18:02 +00:00
// ListFunctionArgs lists all arguments to the current function
2016-04-18 19:20:20 +00:00
func ( s * RPCServer ) ListFunctionArgs ( arg ListFunctionArgsIn , out * ListFunctionArgsOut ) error {
2020-07-07 13:21:18 +00:00
vars , err := s . debugger . FunctionArguments ( arg . Scope . GoroutineID , arg . Scope . Frame , arg . Scope . DeferredCall , * api . LoadConfigToProc ( & arg . Cfg ) )
2016-04-18 19:20:20 +00:00
if err != nil {
return err
}
2020-07-07 13:21:18 +00:00
out . Args = api . ConvertVars ( vars )
2016-04-18 19:20:20 +00:00
return nil
}
type EvalIn struct {
Scope api . EvalScope
Expr string
2016-06-19 06:43:29 +00:00
Cfg * api . LoadConfig
2016-04-18 19:20:20 +00:00
}
type EvalOut struct {
Variable * api . Variable
}
2021-09-28 19:07:42 +00:00
// Eval returns a variable in the specified context.
2016-04-24 17:18:02 +00:00
//
2021-03-15 14:54:13 +00:00
// See https://github.com/go-delve/delve/blob/master/Documentation/cli/expr.md
// for a description of acceptable values of arg.Expr.
2016-04-18 19:20:20 +00:00
func ( s * RPCServer ) Eval ( arg EvalIn , out * EvalOut ) error {
2016-04-24 17:15:39 +00:00
cfg := arg . Cfg
if cfg == nil {
2020-03-18 16:25:32 +00:00
cfg = & api . LoadConfig { FollowPointers : true , MaxVariableRecurse : 1 , MaxStringLen : 64 , MaxArrayValues : 64 , MaxStructFields : - 1 }
2016-04-24 17:15:39 +00:00
}
2023-08-23 20:02:34 +00:00
pcfg := * api . LoadConfigToProc ( cfg )
v , err := s . debugger . EvalVariableInScope ( arg . Scope . GoroutineID , arg . Scope . Frame , arg . Scope . DeferredCall , arg . Expr , pcfg )
2016-04-18 19:20:20 +00:00
if err != nil {
return err
}
2020-07-07 13:21:18 +00:00
out . Variable = api . ConvertVar ( v )
2016-04-18 19:20:20 +00:00
return nil
}
type SetIn struct {
Scope api . EvalScope
Symbol string
Value string
}
type SetOut struct {
}
2016-04-24 17:18:02 +00:00
// Set sets the value of a variable. Only numerical types and
// pointers are currently supported.
2016-04-18 19:20:20 +00:00
func ( s * RPCServer ) Set ( arg SetIn , out * SetOut ) error {
2020-07-07 13:21:18 +00:00
return s . debugger . SetVariableInScope ( arg . Scope . GoroutineID , arg . Scope . Frame , arg . Scope . DeferredCall , arg . Symbol , arg . Value )
2016-04-18 19:20:20 +00:00
}
type ListSourcesIn struct {
Filter string
}
type ListSourcesOut struct {
Sources [ ] string
}
2016-04-24 17:18:02 +00:00
// ListSources lists all source files in the process matching filter.
2016-04-18 19:20:20 +00:00
func ( s * RPCServer ) ListSources ( arg ListSourcesIn , out * ListSourcesOut ) error {
ss , err := s . debugger . Sources ( arg . Filter )
if err != nil {
return err
}
out . Sources = ss
return nil
}
type ListFunctionsIn struct {
2024-06-12 19:35:48 +00:00
Filter string
FollowCalls int
2016-04-18 19:20:20 +00:00
}
type ListFunctionsOut struct {
Funcs [ ] string
}
2016-04-24 17:18:02 +00:00
// ListFunctions lists all functions in the process matching filter.
2016-04-18 19:20:20 +00:00
func ( s * RPCServer ) ListFunctions ( arg ListFunctionsIn , out * ListFunctionsOut ) error {
2024-06-12 19:35:48 +00:00
fns , err := s . debugger . Functions ( arg . Filter , arg . FollowCalls )
2016-04-18 19:20:20 +00:00
if err != nil {
return err
}
out . Funcs = fns
return nil
}
type ListTypesIn struct {
Filter string
}
type ListTypesOut struct {
Types [ ] string
}
2016-04-24 17:18:02 +00:00
// ListTypes lists all types in the process matching filter.
2016-04-18 19:20:20 +00:00
func ( s * RPCServer ) ListTypes ( arg ListTypesIn , out * ListTypesOut ) error {
tps , err := s . debugger . Types ( arg . Filter )
if err != nil {
return err
}
out . Types = tps
return nil
}
type ListGoroutinesIn struct {
2018-11-19 14:18:10 +00:00
Start int
Count int
2021-07-01 18:25:33 +00:00
Filters [ ] api . ListGoroutinesFilter
api . GoroutineGroupingOptions
2023-08-23 20:02:34 +00:00
EvalScope * api . EvalScope
2016-04-18 19:20:20 +00:00
}
type ListGoroutinesOut struct {
2021-07-01 18:25:33 +00:00
Goroutines [ ] * api . Goroutine
Nextg int
Groups [ ] api . GoroutineGroup
TooManyGroups bool
2016-04-18 19:20:20 +00:00
}
2016-04-24 17:18:02 +00:00
// ListGoroutines lists all goroutines.
2018-12-06 09:42:59 +00:00
// If Count is specified ListGoroutines will return at the first Count
// goroutines and an index in Nextg, that can be passed as the Start
// parameter, to get more goroutines from ListGoroutines.
// Passing a value of Start that wasn't returned by ListGoroutines will skip
// an undefined number of goroutines.
2021-07-01 18:25:33 +00:00
//
// If arg.Filters are specified the list of returned goroutines is filtered
// applying the specified filters.
// For example:
2022-06-17 17:08:11 +00:00
//
// ListGoroutinesFilter{ Kind: ListGoroutinesFilterUserLoc, Negated: false, Arg: "afile.go" }
//
2021-07-01 18:25:33 +00:00
// will only return goroutines whose UserLoc contains "afile.go" as a substring.
// More specifically a goroutine matches a location filter if the specified
// location, formatted like this:
2022-06-17 17:08:11 +00:00
//
// filename:lineno in function
//
2021-07-01 18:25:33 +00:00
// contains Arg[0] as a substring.
//
// Filters can also be applied to goroutine labels:
2022-06-17 17:08:11 +00:00
//
// ListGoroutineFilter{ Kind: ListGoroutinesFilterLabel, Negated: false, Arg: "key=value" }
//
2021-07-01 18:25:33 +00:00
// this filter will only return goroutines that have a key=value label.
//
// If arg.GroupBy is not GoroutineFieldNone then the goroutines will
// be grouped with the specified criterion.
// If the value of arg.GroupBy is GoroutineLabel goroutines will
// be grouped by the value of the label with key GroupByKey.
2023-06-07 03:44:51 +00:00
// For each group a maximum of MaxGroupMembers example goroutines are
2021-07-01 18:25:33 +00:00
// returned, as well as the total number of goroutines in the group.
2016-04-18 19:20:20 +00:00
func ( s * RPCServer ) ListGoroutines ( arg ListGoroutinesIn , out * ListGoroutinesOut ) error {
2021-07-01 18:25:33 +00:00
//TODO(aarzilli): if arg contains a running goroutines filter (not negated)
// and start == 0 and count == 0 then we can optimize this by just looking
// at threads directly.
2023-08-23 20:02:34 +00:00
var gs [ ] * proc . G
var nextg int
var err error
var gsLoaded bool
for _ , filter := range arg . Filters {
if filter . Kind == api . GoroutineWaitingOnChannel {
if filter . Negated {
return errors . New ( "channel filter can not be negated" )
}
if arg . Count == 0 {
return errors . New ( "count == 0 not allowed with a channel filter" )
}
if arg . EvalScope == nil {
return errors . New ( "channel filter without eval scope" )
}
gs , err = s . debugger . ChanGoroutines ( arg . EvalScope . GoroutineID , arg . EvalScope . Frame , arg . EvalScope . DeferredCall , filter . Arg , arg . Start , arg . Count )
if len ( gs ) == arg . Count {
nextg = arg . Start + len ( gs )
} else {
nextg = - 1
}
gsLoaded = true
break
}
}
if ! gsLoaded {
gs , nextg , err = s . debugger . Goroutines ( arg . Start , arg . Count )
}
2016-04-18 19:20:20 +00:00
if err != nil {
return err
}
2021-07-01 18:25:33 +00:00
gs = s . debugger . FilterGoroutines ( gs , arg . Filters )
gs , out . Groups , out . TooManyGroups = s . debugger . GroupGoroutines ( gs , & arg . GoroutineGroupingOptions )
2020-07-07 13:21:18 +00:00
s . debugger . LockTarget ( )
defer s . debugger . UnlockTarget ( )
2021-07-08 15:47:53 +00:00
out . Goroutines = api . ConvertGoroutines ( s . debugger . Target ( ) , gs )
2018-11-19 14:18:10 +00:00
out . Nextg = nextg
2016-04-18 19:20:20 +00:00
return nil
}
type AttachedToExistingProcessIn struct {
}
type AttachedToExistingProcessOut struct {
Answer bool
}
2016-04-24 17:18:02 +00:00
// AttachedToExistingProcess returns whether we attached to a running process or not
2023-08-17 21:24:43 +00:00
func ( s * RPCServer ) AttachedToExistingProcess ( arg AttachedToExistingProcessIn , out * AttachedToExistingProcessOut ) error {
if s . config . Debugger . AttachPid != 0 {
2016-04-18 19:20:20 +00:00
out . Answer = true
}
return nil
}
type FindLocationIn struct {
2019-10-25 16:59:18 +00:00
Scope api . EvalScope
Loc string
IncludeNonExecutableLines bool
2020-10-26 12:36:52 +00:00
// SubstitutePathRules is a slice of source code path substitution rules,
// the first entry of each pair is the path of a directory as it appears in
// the executable file (i.e. the location of a source file when the program
// was compiled), the second entry of each pair is the location of the same
// directory on the client system.
SubstitutePathRules [ ] [ 2 ] string
2016-04-18 19:20:20 +00:00
}
type FindLocationOut struct {
2023-07-20 10:29:59 +00:00
Locations [ ] api . Location
SubstituteLocExpr string // if this isn't an empty string it should be passed as the location expression for CreateBreakpoint instead of the original location expression
2016-04-18 19:20:20 +00:00
}
2019-11-04 16:43:12 +00:00
// FindLocation returns concrete location information described by a location expression.
2016-04-24 17:18:02 +00:00
//
2022-06-17 17:08:11 +00:00
// loc ::= <filename>:<line> | <function>[:<line>] | /<regex>/ | (+|-)<offset> | <line> | *<address>
// * <filename> can be the full path of a file or just a suffix
// * <function> ::= <package>.<receiver type>.<name> | <package>.(*<receiver type>).<name> | <receiver type>.<name> | <package>.<name> | (*<receiver type>).<name> | <name>
// <function> must be unambiguous
// * /<regex>/ will return a location for each function matched by regex
// * +<offset> returns a location for the line that is <offset> lines after the current line
// * -<offset> returns a location for the line that is <offset> lines before the current line
// * <line> returns a location for a line in the current file
// * *<address> returns the location corresponding to the specified address
2016-04-24 17:18:02 +00:00
//
// NOTE: this function does not actually set breakpoints.
2023-08-17 21:24:43 +00:00
func ( s * RPCServer ) FindLocation ( arg FindLocationIn , out * FindLocationOut ) error {
2016-04-18 19:20:20 +00:00
var err error
2023-08-17 21:24:43 +00:00
out . Locations , out . SubstituteLocExpr , err = s . debugger . FindLocation ( arg . Scope . GoroutineID , arg . Scope . Frame , arg . Scope . DeferredCall , arg . Loc , arg . IncludeNonExecutableLines , arg . SubstitutePathRules )
2016-04-18 19:20:20 +00:00
return err
}
type DisassembleIn struct {
Scope api . EvalScope
StartPC , EndPC uint64
Flavour api . AssemblyFlavour
}
type DisassembleOut struct {
Disassemble api . AsmInstructions
}
2016-04-24 17:18:02 +00:00
// Disassemble code.
//
// If both StartPC and EndPC are non-zero the specified range will be disassembled, otherwise the function containing StartPC will be disassembled.
//
2018-03-20 10:05:35 +00:00
// Scope is used to mark the instruction the specified goroutine is stopped at.
2016-04-24 17:18:02 +00:00
//
// Disassemble will also try to calculate the destination address of an absolute indirect CALL if it happens to be the instruction the selected goroutine is stopped at.
2023-08-17 21:24:43 +00:00
func ( s * RPCServer ) Disassemble ( arg DisassembleIn , out * DisassembleOut ) error {
insts , err := s . debugger . Disassemble ( arg . Scope . GoroutineID , arg . StartPC , arg . EndPC )
2020-07-07 13:21:18 +00:00
if err != nil {
return err
}
out . Disassemble = make ( api . AsmInstructions , len ( insts ) )
for i := range insts {
2023-08-17 21:24:43 +00:00
out . Disassemble [ i ] = api . ConvertAsmInstruction ( insts [ i ] , s . debugger . AsmInstructionText ( & insts [ i ] , proc . AssemblyFlavour ( arg . Flavour ) ) )
2020-07-07 13:21:18 +00:00
}
return nil
2016-04-18 19:20:20 +00:00
}
2017-05-05 22:17:52 +00:00
type RecordedIn struct {
}
type RecordedOut struct {
Recorded bool
TraceDirectory string
}
func ( s * RPCServer ) Recorded ( arg RecordedIn , out * RecordedOut ) error {
out . Recorded , out . TraceDirectory = s . debugger . Recorded ( )
return nil
}
type CheckpointIn struct {
Where string
}
type CheckpointOut struct {
ID int
}
func ( s * RPCServer ) Checkpoint ( arg CheckpointIn , out * CheckpointOut ) error {
var err error
out . ID , err = s . debugger . Checkpoint ( arg . Where )
return err
}
type ListCheckpointsIn struct {
}
type ListCheckpointsOut struct {
Checkpoints [ ] api . Checkpoint
}
func ( s * RPCServer ) ListCheckpoints ( arg ListCheckpointsIn , out * ListCheckpointsOut ) error {
2020-07-07 13:21:18 +00:00
cps , err := s . debugger . Checkpoints ( )
if err != nil {
return err
}
out . Checkpoints = make ( [ ] api . Checkpoint , len ( cps ) )
for i := range cps {
out . Checkpoints [ i ] = api . Checkpoint ( cps [ i ] )
}
return nil
2017-05-05 22:17:52 +00:00
}
type ClearCheckpointIn struct {
ID int
}
type ClearCheckpointOut struct {
}
func ( s * RPCServer ) ClearCheckpoint ( arg ClearCheckpointIn , out * ClearCheckpointOut ) error {
return s . debugger . ClearCheckpoint ( arg . ID )
}
2018-06-21 11:07:37 +00:00
type IsMulticlientIn struct {
}
type IsMulticlientOut struct {
// IsMulticlient returns true if the headless instance was started with --accept-multiclient
IsMulticlient bool
}
func ( s * RPCServer ) IsMulticlient ( arg IsMulticlientIn , out * IsMulticlientOut ) error {
* out = IsMulticlientOut {
IsMulticlient : s . config . AcceptMulti ,
}
return nil
}
2018-10-16 15:49:20 +00:00
// FunctionReturnLocationsIn holds arguments for the
// FunctionReturnLocationsRPC call. It holds the name of
// the function for which all return locations should be
// given.
type FunctionReturnLocationsIn struct {
// FnName is the name of the function for which all
// return locations should be given.
FnName string
}
// FunctionReturnLocationsOut holds the result of the FunctionReturnLocations
// RPC call. It provides the list of addresses that the given function returns,
// for example with a `RET` instruction or `CALL runtime.deferreturn`.
type FunctionReturnLocationsOut struct {
// Addrs is the list of all locations where the given function returns.
Addrs [ ] uint64
}
// FunctionReturnLocations is the implements the client call of the same name. Look at client documentation for more information.
func ( s * RPCServer ) FunctionReturnLocations ( in FunctionReturnLocationsIn , out * FunctionReturnLocationsOut ) error {
addrs , err := s . debugger . FunctionReturnLocations ( in . FnName )
if err != nil {
return err
}
* out = FunctionReturnLocationsOut {
Addrs : addrs ,
}
return nil
}
2019-03-20 17:32:51 +00:00
// ListDynamicLibrariesIn holds the arguments of ListDynamicLibraries
type ListDynamicLibrariesIn struct {
}
// ListDynamicLibrariesOut holds the return values of ListDynamicLibraries
type ListDynamicLibrariesOut struct {
List [ ] api . Image
}
func ( s * RPCServer ) ListDynamicLibraries ( in ListDynamicLibrariesIn , out * ListDynamicLibrariesOut ) error {
2020-07-07 13:21:18 +00:00
imgs := s . debugger . ListDynamicLibraries ( )
out . List = make ( [ ] api . Image , 0 , len ( imgs ) )
for i := range imgs {
2021-07-14 16:28:54 +00:00
out . List = append ( out . List , api . ConvertImage ( imgs [ i ] ) )
2020-07-07 13:21:18 +00:00
}
2019-03-20 17:32:51 +00:00
return nil
}
2019-12-03 13:00:30 +00:00
2023-09-18 15:59:58 +00:00
// ListPackagesBuildInfoIn holds the arguments of ListPackagesBuildInfo.
2019-12-03 13:00:30 +00:00
type ListPackagesBuildInfoIn struct {
IncludeFiles bool
2023-09-18 15:59:58 +00:00
Filter string // if not empty, returns only packages matching the regexp.
2019-12-03 13:00:30 +00:00
}
2023-09-18 15:59:58 +00:00
// ListPackagesBuildInfoOut holds the return values of ListPackagesBuildInfo.
2019-12-03 13:00:30 +00:00
type ListPackagesBuildInfoOut struct {
List [ ] api . PackageBuildInfo
}
// ListPackagesBuildInfo returns the list of packages used by the program along with
// the directory where each package was compiled and optionally the list of
// files constituting the package.
// Note that the directory path is a best guess and may be wrong is a tool
// other than cmd/go is used to perform the build.
func ( s * RPCServer ) ListPackagesBuildInfo ( in ListPackagesBuildInfoIn , out * ListPackagesBuildInfoOut ) error {
2023-09-18 15:59:58 +00:00
var pattern * regexp . Regexp
if in . Filter != "" {
p , err := regexp . Compile ( in . Filter )
if err != nil {
return fmt . Errorf ( "invalid Filter pattern: %v" , err )
}
pattern = p
}
2020-07-07 13:21:18 +00:00
pkgs := s . debugger . ListPackagesBuildInfo ( in . IncludeFiles )
out . List = make ( [ ] api . PackageBuildInfo , 0 , len ( pkgs ) )
for _ , pkg := range pkgs {
2023-09-18 15:59:58 +00:00
if pattern != nil && ! pattern . MatchString ( pkg . ImportPath ) {
continue
}
2020-07-07 13:21:18 +00:00
var files [ ] string
if len ( pkg . Files ) > 0 {
files = make ( [ ] string , 0 , len ( pkg . Files ) )
for file := range pkg . Files {
files = append ( files , file )
}
}
sort . Strings ( files )
out . List = append ( out . List , api . PackageBuildInfo {
ImportPath : pkg . ImportPath ,
DirectoryPath : pkg . DirectoryPath ,
Files : files ,
} )
}
2019-12-03 13:00:30 +00:00
return nil
}
2020-02-13 17:29:21 +00:00
// ExamineMemoryIn holds the arguments of ExamineMemory
type ExamineMemoryIn struct {
2020-09-09 17:36:15 +00:00
Address uint64
2020-02-13 17:29:21 +00:00
Length int
}
// ExaminedMemoryOut holds the return values of ExamineMemory
type ExaminedMemoryOut struct {
2020-09-11 06:21:11 +00:00
Mem [ ] byte
IsLittleEndian bool
2020-02-13 17:29:21 +00:00
}
2024-10-03 21:09:38 +00:00
const ExamineMemoryLengthLimit = 1 << 16
2020-02-13 17:29:21 +00:00
func ( s * RPCServer ) ExamineMemory ( arg ExamineMemoryIn , out * ExaminedMemoryOut ) error {
2024-10-03 21:09:38 +00:00
if arg . Length > ExamineMemoryLengthLimit {
2024-10-31 15:26:47 +00:00
return fmt . Errorf ( "len must be less than or equal to %d" , ExamineMemoryLengthLimit )
2020-02-13 17:29:21 +00:00
}
Mem , err := s . debugger . ExamineMemory ( arg . Address , arg . Length )
if err != nil {
return err
}
out . Mem = Mem
2020-09-11 06:21:11 +00:00
out . IsLittleEndian = true //TODO: get byte order from debugger.target.BinInfo().Arch
2020-02-13 17:29:21 +00:00
return nil
}
2020-03-24 16:09:28 +00:00
type StopRecordingIn struct {
}
type StopRecordingOut struct {
}
func ( s * RPCServer ) StopRecording ( arg StopRecordingIn , cb service . RPCCallback ) {
2021-03-08 18:05:10 +00:00
close ( cb . SetupDoneChan ( ) )
2020-03-24 16:09:28 +00:00
var out StopRecordingOut
err := s . debugger . StopRecording ( )
if err != nil {
cb . Return ( nil , err )
return
}
cb . Return ( out , nil )
}
2021-01-29 21:39:33 +00:00
type DumpStartIn struct {
Destination string
}
type DumpStartOut struct {
State api . DumpState
}
// DumpStart starts a core dump to arg.Destination.
func ( s * RPCServer ) DumpStart ( arg DumpStartIn , out * DumpStartOut ) error {
err := s . debugger . DumpStart ( arg . Destination )
if err != nil {
return err
}
out . State = * api . ConvertDumpState ( s . debugger . DumpWait ( 0 ) )
return nil
}
type DumpWaitIn struct {
Wait int
}
type DumpWaitOut struct {
State api . DumpState
}
// DumpWait waits for the core dump to finish or for arg.Wait milliseconds.
// Wait == 0 means return immediately.
// Returns the core dump status
func ( s * RPCServer ) DumpWait ( arg DumpWaitIn , out * DumpWaitOut ) error {
out . State = * api . ConvertDumpState ( s . debugger . DumpWait ( time . Duration ( arg . Wait ) * time . Millisecond ) )
return nil
}
type DumpCancelIn struct {
}
type DumpCancelOut struct {
}
// DumpCancel cancels the core dump.
func ( s * RPCServer ) DumpCancel ( arg DumpCancelIn , out * DumpCancelOut ) error {
return s . debugger . DumpCancel ( )
}
2021-05-20 17:04:02 +00:00
type CreateWatchpointIn struct {
Scope api . EvalScope
Expr string
Type api . WatchType
}
type CreateWatchpointOut struct {
* api . Breakpoint
}
func ( s * RPCServer ) CreateWatchpoint ( arg CreateWatchpointIn , out * CreateWatchpointOut ) error {
var err error
out . Breakpoint , err = s . debugger . CreateWatchpoint ( arg . Scope . GoroutineID , arg . Scope . Frame , arg . Scope . DeferredCall , arg . Expr , arg . Type )
return err
}
2022-01-30 21:39:30 +00:00
type BuildIDIn struct {
}
type BuildIDOut struct {
BuildID string
}
func ( s * RPCServer ) BuildID ( arg BuildIDIn , out * BuildIDOut ) error {
out . BuildID = s . debugger . BuildID ( )
return nil
}
2023-04-24 21:37:31 +00:00
type ListTargetsIn struct {
}
type ListTargetsOut struct {
Targets [ ] api . Target
}
// ListTargets returns the list of targets we are currently attached to.
func ( s * RPCServer ) ListTargets ( arg ListTargetsIn , out * ListTargetsOut ) error {
s . debugger . LockTarget ( )
defer s . debugger . UnlockTarget ( )
out . Targets = [ ] api . Target { }
for _ , tgt := range s . debugger . TargetGroup ( ) . Targets ( ) {
if _ , err := tgt . Valid ( ) ; err == nil {
out . Targets = append ( out . Targets , * api . ConvertTarget ( tgt , s . debugger . ConvertThreadBreakpoint ) )
}
}
return nil
}
type FollowExecIn struct {
Enable bool
Regex string
}
type FollowExecOut struct {
}
// FollowExec enables or disables follow exec mode.
func ( s * RPCServer ) FollowExec ( arg FollowExecIn , out * FollowExecOut ) error {
return s . debugger . FollowExec ( arg . Enable , arg . Regex )
}
type FollowExecEnabledIn struct {
}
type FollowExecEnabledOut struct {
Enabled bool
}
// FollowExecEnabled returns true if follow exec mode is enabled.
func ( s * RPCServer ) FollowExecEnabled ( arg FollowExecEnabledIn , out * FollowExecEnabledOut ) error {
out . Enabled = s . debugger . FollowExecEnabled ( )
return nil
}
*: misc improvements to config command and substitute-path rules (#3335)
A series of interconnected changes to both the terminal command
'config', DAP command 'dlv config', quality of life improvements to how
substitute-path works, and better documentation.
- Let 'config substitute-path' show the current substitute path rules
- Add a -clear command to 'config substitute-path'
- Support 'config-debug-info-directories'
- rewrite SubstitutePath to be platform independent (see below)
- document path substitution more
Regarding the rewrite of SubstitutePath: the previous version used
runtime.GOOS and filepath.IsAbs to determine which filepath separator to use
and if matching should be case insensitive. This is wrong in all situations
where the client and server run on different OSes, when examining core files
and when cross-compilation is involved.
The new version of SubstitutePath checks the rules and the input path to
determine if Windows is involved in the process, if it looks like it is it
switches to case-insensitive matching. It uses a lax version of
filepath.IsAbs to determine if a path is absolute and tries to avoid having
to select a path separator as much as possible
Fixes #2891, #2890, #2889, #3179, #3332, #3343
2023-05-02 19:23:59 +00:00
type DebugInfoDirectoriesIn struct {
Set bool
List [ ] string
}
type DebugInfoDirectoriesOut struct {
List [ ] string
}
func ( s * RPCServer ) DebugInfoDirectories ( arg DebugInfoDirectoriesIn , out * DebugInfoDirectoriesOut ) error {
if arg . Set {
s . debugger . SetDebugInfoDirectories ( arg . List )
}
out . List = s . debugger . DebugInfoDirectories ( )
return nil
}
2024-10-31 17:19:08 +00:00
type GuessSubstitutePathIn struct {
Args api . GuessSubstitutePathIn
}
type GuessSubstitutePathOut struct {
List [ ] [ 2 ] string
}
func ( s * RPCServer ) GuessSubstitutePath ( arg GuessSubstitutePathIn , out * GuessSubstitutePathOut ) error {
m := s . debugger . GuessSubstitutePath ( & arg . Args )
for k , v := range m {
out . List = append ( out . List , [ 2 ] string { k , v } )
}
return nil
}