2016-04-18 19:20:20 +00:00
package rpc2
import (
"errors"
"fmt"
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 ) {
2021-03-08 18:05:10 +00:00
st , err := s . debugger . Command ( & command , cb . SetupDoneChan ( ) )
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 {
2018-07-06 07:37:31 +00:00
Id int
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
}
2018-08-18 10:12:39 +00:00
var err error
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 {
GoroutineID int
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
}
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`
// with an `api.Breakpoint` struct describing where to set the breakpoing. For more information on
// 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
}
2016-04-18 19:20:20 +00:00
createdbp , err := s . debugger . CreateBreakpoint ( & arg . Breakpoint )
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 ( )
out . Threads = api . ConvertThreads ( threads )
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 ( )
out . Thread = api . ConvertThread ( 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 {
regs , err = s . debugger . ScopeRegisters ( arg . Scope . GoroutineID , arg . Scope . Frame , arg . Scope . DeferredCall , arg . IncludeFp )
} else {
regs , err = s . debugger . ThreadRegisters ( arg . ThreadID , arg . IncludeFp )
}
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
}
2020-07-07 13:21:18 +00:00
v , err := s . debugger . EvalVariableInScope ( arg . Scope . GoroutineID , arg . Scope . Frame , arg . Scope . DeferredCall , arg . Expr , * api . LoadConfigToProc ( cfg ) )
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 {
Filter string
}
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 {
fns , err := s . debugger . Functions ( arg . Filter )
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
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:
// ListGoroutinesFilter{ Kind: ListGoroutinesFilterUserLoc, Negated: false, Arg: "afile.go" }
// 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:
// filename:lineno in function
// contains Arg[0] as a substring.
//
// Filters can also be applied to goroutine labels:
// ListGoroutineFilter{ Kind: ListGoroutinesFilterLabel, Negated: false, Arg: "key=value" }
// 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.
// For each group a maximum of MaxExamples example goroutines are
// 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.
2018-11-19 14:18:10 +00:00
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
2016-04-18 19:20:20 +00:00
func ( c * RPCServer ) AttachedToExistingProcess ( arg AttachedToExistingProcessIn , out * AttachedToExistingProcessOut ) error {
2020-04-13 18:07:15 +00:00
if c . 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 {
Locations [ ] api . Location
}
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
//
// 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
//
// NOTE: this function does not actually set breakpoints.
2016-04-18 19:20:20 +00:00
func ( c * RPCServer ) FindLocation ( arg FindLocationIn , out * FindLocationOut ) error {
var err error
2020-10-26 12:36:52 +00:00
out . Locations , err = c . 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.
2016-04-18 19:20:20 +00:00
func ( c * RPCServer ) Disassemble ( arg DisassembleIn , out * DisassembleOut ) error {
var err error
2020-07-07 13:21:18 +00:00
insts , err := c . debugger . Disassemble ( arg . Scope . GoroutineID , arg . StartPC , arg . EndPC )
if err != nil {
return err
}
out . Disassemble = make ( api . AsmInstructions , len ( insts ) )
for i := range insts {
out . Disassemble [ i ] = api . ConvertAsmInstruction ( insts [ i ] , c . debugger . AsmInstructionText ( & insts [ i ] , proc . AssemblyFlavour ( arg . Flavour ) ) )
}
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 {
var err 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
// ListPackagesBuildInfoIn holds the arguments of ListPackages.
type ListPackagesBuildInfoIn struct {
IncludeFiles bool
}
// ListPackagesBuildInfoOut holds the return values of ListPackages.
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 {
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 {
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
}
func ( s * RPCServer ) ExamineMemory ( arg ExamineMemoryIn , out * ExaminedMemoryOut ) error {
if arg . Length > 1000 {
return fmt . Errorf ( "len must be less than or equal to 1000" )
}
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
}