
Adds -defer flag to the stack command that decorates the stack traces by associating each stack frame with its deferred calls. Reworks proc.next to use this feature instead of using proc.DeferPC, laying the groundwork to implement #1240.
323 lines
7.3 KiB
Go
323 lines
7.3 KiB
Go
package rpc1
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
|
|
"github.com/derekparker/delve/pkg/proc"
|
|
"github.com/derekparker/delve/service"
|
|
"github.com/derekparker/delve/service/api"
|
|
"github.com/derekparker/delve/service/debugger"
|
|
)
|
|
|
|
var defaultLoadConfig = proc.LoadConfig{true, 1, 64, 64, -1}
|
|
|
|
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
|
|
}
|
|
|
|
func NewServer(config *service.Config, debugger *debugger.Debugger) *RPCServer {
|
|
return &RPCServer{config, debugger}
|
|
}
|
|
|
|
func (s *RPCServer) ProcessPid(arg1 interface{}, pid *int) error {
|
|
*pid = s.debugger.ProcessPid()
|
|
return nil
|
|
}
|
|
|
|
func (s *RPCServer) Detach(kill bool, ret *int) error {
|
|
err := s.debugger.Detach(kill)
|
|
if s.config.DisconnectChan != nil {
|
|
close(s.config.DisconnectChan)
|
|
}
|
|
return err
|
|
}
|
|
|
|
func (s *RPCServer) Restart(arg1 interface{}, arg2 *int) error {
|
|
if s.config.AttachPid != 0 {
|
|
return errors.New("cannot restart process Delve did not create")
|
|
}
|
|
_, err := s.debugger.Restart("", false, nil)
|
|
return err
|
|
}
|
|
|
|
func (s *RPCServer) State(arg interface{}, state *api.DebuggerState) error {
|
|
st, err := s.debugger.State(false)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
*state = *st
|
|
return nil
|
|
}
|
|
|
|
func (s *RPCServer) Command(command *api.DebuggerCommand, cb service.RPCCallback) {
|
|
st, err := s.debugger.Command(command)
|
|
cb.Return(st, err)
|
|
}
|
|
|
|
func (s *RPCServer) GetBreakpoint(id int, breakpoint *api.Breakpoint) error {
|
|
bp := s.debugger.FindBreakpoint(id)
|
|
if bp == nil {
|
|
return fmt.Errorf("no breakpoint with id %d", id)
|
|
}
|
|
*breakpoint = *bp
|
|
return nil
|
|
}
|
|
|
|
func (s *RPCServer) GetBreakpointByName(name string, breakpoint *api.Breakpoint) error {
|
|
bp := s.debugger.FindBreakpointByName(name)
|
|
if bp == nil {
|
|
return fmt.Errorf("no breakpoint with name %s", name)
|
|
}
|
|
*breakpoint = *bp
|
|
return nil
|
|
}
|
|
|
|
type StacktraceGoroutineArgs struct {
|
|
Id int
|
|
Depth int
|
|
Full bool
|
|
}
|
|
|
|
func (s *RPCServer) StacktraceGoroutine(args *StacktraceGoroutineArgs, locations *[]api.Stackframe) error {
|
|
var loadcfg *proc.LoadConfig = nil
|
|
if args.Full {
|
|
loadcfg = &defaultLoadConfig
|
|
}
|
|
locs, err := s.debugger.Stacktrace(args.Id, args.Depth, false, loadcfg)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
*locations = locs
|
|
return nil
|
|
}
|
|
|
|
func (s *RPCServer) ListBreakpoints(arg interface{}, breakpoints *[]*api.Breakpoint) error {
|
|
*breakpoints = s.debugger.Breakpoints()
|
|
return nil
|
|
}
|
|
|
|
func (s *RPCServer) CreateBreakpoint(bp, newBreakpoint *api.Breakpoint) error {
|
|
createdbp, err := s.debugger.CreateBreakpoint(bp)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
*newBreakpoint = *createdbp
|
|
return nil
|
|
}
|
|
|
|
func (s *RPCServer) ClearBreakpoint(id int, breakpoint *api.Breakpoint) error {
|
|
bp := s.debugger.FindBreakpoint(id)
|
|
if bp == nil {
|
|
return fmt.Errorf("no breakpoint with id %d", id)
|
|
}
|
|
deleted, err := s.debugger.ClearBreakpoint(bp)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
*breakpoint = *deleted
|
|
return nil
|
|
}
|
|
|
|
func (s *RPCServer) ClearBreakpointByName(name string, breakpoint *api.Breakpoint) error {
|
|
bp := s.debugger.FindBreakpointByName(name)
|
|
if bp == nil {
|
|
return fmt.Errorf("no breakpoint with name %s", name)
|
|
}
|
|
deleted, err := s.debugger.ClearBreakpoint(bp)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
*breakpoint = *deleted
|
|
return nil
|
|
}
|
|
|
|
func (s *RPCServer) AmendBreakpoint(amend *api.Breakpoint, unused *int) error {
|
|
*unused = 0
|
|
return s.debugger.AmendBreakpoint(amend)
|
|
}
|
|
|
|
func (s *RPCServer) ListThreads(arg interface{}, threads *[]*api.Thread) (err error) {
|
|
*threads, err = s.debugger.Threads()
|
|
return err
|
|
}
|
|
|
|
func (s *RPCServer) GetThread(id int, thread *api.Thread) error {
|
|
t, err := s.debugger.FindThread(id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if t == nil {
|
|
return fmt.Errorf("no thread with id %d", id)
|
|
}
|
|
*thread = *t
|
|
return nil
|
|
}
|
|
|
|
func (s *RPCServer) ListPackageVars(filter string, variables *[]api.Variable) error {
|
|
state, err := s.debugger.State(false)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
current := state.CurrentThread
|
|
if current == nil {
|
|
return fmt.Errorf("no current thread")
|
|
}
|
|
|
|
vars, err := s.debugger.PackageVariables(current.ID, filter, defaultLoadConfig)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
*variables = vars
|
|
return nil
|
|
}
|
|
|
|
type ThreadListArgs struct {
|
|
Id int
|
|
Filter string
|
|
}
|
|
|
|
func (s *RPCServer) ListThreadPackageVars(args *ThreadListArgs, variables *[]api.Variable) error {
|
|
thread, err := s.debugger.FindThread(args.Id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if thread == nil {
|
|
return fmt.Errorf("no thread with id %d", args.Id)
|
|
}
|
|
|
|
vars, err := s.debugger.PackageVariables(args.Id, args.Filter, defaultLoadConfig)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
*variables = vars
|
|
return nil
|
|
}
|
|
|
|
func (s *RPCServer) ListRegisters(arg interface{}, registers *string) error {
|
|
state, err := s.debugger.State(false)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
regs, err := s.debugger.Registers(state.CurrentThread.ID, false)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
*registers = regs.String()
|
|
return nil
|
|
}
|
|
|
|
func (s *RPCServer) ListLocalVars(scope api.EvalScope, variables *[]api.Variable) error {
|
|
vars, err := s.debugger.LocalVariables(scope, defaultLoadConfig)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
*variables = vars
|
|
return nil
|
|
}
|
|
|
|
func (s *RPCServer) ListFunctionArgs(scope api.EvalScope, variables *[]api.Variable) error {
|
|
vars, err := s.debugger.FunctionArguments(scope, defaultLoadConfig)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
*variables = vars
|
|
return nil
|
|
}
|
|
|
|
type EvalSymbolArgs struct {
|
|
Scope api.EvalScope
|
|
Symbol string
|
|
}
|
|
|
|
func (s *RPCServer) EvalSymbol(args EvalSymbolArgs, variable *api.Variable) error {
|
|
v, err := s.debugger.EvalVariableInScope(args.Scope, args.Symbol, defaultLoadConfig)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
*variable = *v
|
|
return nil
|
|
}
|
|
|
|
type SetSymbolArgs struct {
|
|
Scope api.EvalScope
|
|
Symbol string
|
|
Value string
|
|
}
|
|
|
|
func (s *RPCServer) SetSymbol(args SetSymbolArgs, unused *int) error {
|
|
*unused = 0
|
|
return s.debugger.SetVariableInScope(args.Scope, args.Symbol, args.Value)
|
|
}
|
|
|
|
func (s *RPCServer) ListSources(filter string, sources *[]string) error {
|
|
ss, err := s.debugger.Sources(filter)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
*sources = ss
|
|
return nil
|
|
}
|
|
|
|
func (s *RPCServer) ListFunctions(filter string, funcs *[]string) error {
|
|
fns, err := s.debugger.Functions(filter)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
*funcs = fns
|
|
return nil
|
|
}
|
|
|
|
func (s *RPCServer) ListTypes(filter string, types *[]string) error {
|
|
tps, err := s.debugger.Types(filter)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
*types = tps
|
|
return nil
|
|
}
|
|
|
|
func (s *RPCServer) ListGoroutines(arg interface{}, goroutines *[]*api.Goroutine) error {
|
|
gs, err := s.debugger.Goroutines()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
*goroutines = gs
|
|
return nil
|
|
}
|
|
|
|
func (c *RPCServer) AttachedToExistingProcess(arg interface{}, answer *bool) error {
|
|
if c.config.AttachPid != 0 {
|
|
*answer = true
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type FindLocationArgs struct {
|
|
Scope api.EvalScope
|
|
Loc string
|
|
}
|
|
|
|
func (c *RPCServer) FindLocation(args FindLocationArgs, answer *[]api.Location) error {
|
|
var err error
|
|
*answer, err = c.debugger.FindLocation(args.Scope, args.Loc)
|
|
return err
|
|
}
|
|
|
|
type DisassembleRequest struct {
|
|
Scope api.EvalScope
|
|
StartPC, EndPC uint64
|
|
Flavour api.AssemblyFlavour
|
|
}
|
|
|
|
func (c *RPCServer) Disassemble(args DisassembleRequest, answer *api.AsmInstructions) error {
|
|
var err error
|
|
*answer, err = c.debugger.Disassemble(args.Scope, args.StartPC, args.EndPC, args.Flavour)
|
|
return err
|
|
}
|