delve/service/rpc1/server.go

330 lines
8.3 KiB
Go
Raw Normal View History

package rpc1
2015-06-21 03:47:44 +00:00
import (
"errors"
"fmt"
"github.com/go-delve/delve/pkg/proc"
"github.com/go-delve/delve/service"
"github.com/go-delve/delve/service/api"
"github.com/go-delve/delve/service/debugger"
2015-06-21 03:47:44 +00:00
)
var defaultLoadConfig = proc.LoadConfig{
FollowPointers: true,
MaxVariableRecurse: 1,
MaxStringLen: 64,
MaxArrayValues: 64,
MaxStructFields: -1,
}
2015-06-21 03:47:44 +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
}
func NewServer(config *service.Config, debugger *debugger.Debugger) *RPCServer {
return &RPCServer{config, debugger}
2015-06-21 03:47:44 +00:00
}
func (s *RPCServer) ProcessPid(arg1 interface{}, pid *int) error {
*pid = s.debugger.ProcessPid()
return nil
}
2015-06-21 03:47:44 +00:00
func (s *RPCServer) Detach(kill bool, ret *int) error {
return s.debugger.Detach(kill)
2015-06-21 03:47:44 +00:00
}
func (s *RPCServer) Restart(arg1 interface{}, arg2 *int) error {
if s.config.Debugger.AttachPid != 0 {
return errors.New("cannot restart process Delve did not create")
}
_, err := s.debugger.Restart(false, "", false, nil, [3]string{}, false)
return err
}
2015-06-21 03:47:44 +00:00
func (s *RPCServer) State(arg interface{}, state *api.DebuggerState) error {
st, err := s.debugger.State(false)
2015-06-21 03:47:44 +00:00
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.SetupDoneChan(), cb.DisconnectChan())
cb.Return(st, err)
2015-06-21 03:47:44 +00:00
}
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
}
2015-06-21 03:47:44 +00:00
type StacktraceGoroutineArgs struct {
Id int
Depth int
Full bool
2015-06-21 03:47:44 +00:00
}
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(int64(args.Id), args.Depth, 0)
2015-06-21 03:47:44 +00:00
if err != nil {
return err
}
*locations, err = s.debugger.ConvertStacktrace(locs, loadcfg)
return err
2015-06-21 03:47:44 +00:00
}
func (s *RPCServer) ListBreakpoints(arg interface{}, breakpoints *[]*api.Breakpoint) error {
*breakpoints = s.debugger.Breakpoints(false)
2015-06-21 03:47:44 +00:00
return nil
}
func (s *RPCServer) CreateBreakpoint(bp, newBreakpoint *api.Breakpoint) error {
if err := api.ValidBreakpointName(bp.Name); err != nil {
return err
}
createdbp, err := s.debugger.CreateBreakpoint(bp, "", nil, false)
2015-06-21 03:47:44 +00:00
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
if err := api.ValidBreakpointName(amend.Name); err != nil {
return err
}
return s.debugger.AmendBreakpoint(amend)
}
func (s *RPCServer) ListThreads(arg interface{}, threads *[]*api.Thread) (err error) {
pthreads, err := s.debugger.Threads()
if err != nil {
return err
}
s.debugger.LockTarget()
defer s.debugger.UnlockTarget()
*threads = api.ConvertThreads(pthreads, s.debugger.ConvertThreadBreakpoint)
return nil
2015-06-21 03:47:44 +00:00
}
func (s *RPCServer) GetThread(id int, thread *api.Thread) error {
t, err := s.debugger.FindThread(id)
if err != nil {
return err
}
2015-06-21 03:47:44 +00:00
if t == nil {
return fmt.Errorf("no thread with id %d", id)
}
s.debugger.LockTarget()
defer s.debugger.UnlockTarget()
*thread = *api.ConvertThread(t, s.debugger.ConvertThreadBreakpoint(t))
2015-06-21 03:47:44 +00:00
return nil
}
func (s *RPCServer) ListPackageVars(filter string, variables *[]api.Variable) error {
vars, err := s.debugger.PackageVariables(filter, defaultLoadConfig)
2015-06-21 03:47:44 +00:00
if err != nil {
return err
}
*variables = api.ConvertVars(vars)
2015-06-21 03:47:44 +00:00
return nil
}
type ThreadListArgs struct {
Id int
Filter string
}
func (s *RPCServer) ListThreadPackageVars(args *ThreadListArgs, variables *[]api.Variable) error {
vars, err := s.debugger.PackageVariables(args.Filter, defaultLoadConfig)
2015-06-21 03:47:44 +00:00
if err != nil {
return err
}
*variables = api.ConvertVars(vars)
2015-06-21 03:47:44 +00:00
return nil
}
func (s *RPCServer) ListRegisters(arg interface{}, registers *string) error {
state, err := s.debugger.State(false)
2015-06-21 03:47:44 +00:00
if err != nil {
return err
}
dregs, err := s.debugger.ThreadRegisters(state.CurrentThread.ID)
2015-06-21 03:47:44 +00:00
if err != nil {
return err
}
regs := api.Registers(api.ConvertRegisters(dregs, s.debugger.DwarfRegisterToString, false))
*registers = regs.String()
2015-06-21 03:47:44 +00:00
return nil
}
func (s *RPCServer) ListLocalVars(scope api.EvalScope, variables *[]api.Variable) error {
vars, err := s.debugger.LocalVariables(scope.GoroutineID, scope.Frame, scope.DeferredCall, defaultLoadConfig)
2015-06-21 03:47:44 +00:00
if err != nil {
return err
}
*variables = api.ConvertVars(vars)
2015-06-21 03:47:44 +00:00
return nil
}
func (s *RPCServer) ListFunctionArgs(scope api.EvalScope, variables *[]api.Variable) error {
vars, err := s.debugger.FunctionArguments(scope.GoroutineID, scope.Frame, scope.DeferredCall, defaultLoadConfig)
2015-06-21 03:47:44 +00:00
if err != nil {
return err
}
*variables = api.ConvertVars(vars)
2015-06-21 03:47:44 +00:00
return nil
}
type EvalSymbolArgs struct {
Scope api.EvalScope
2015-06-21 03:47:44 +00:00
Symbol string
}
func (s *RPCServer) EvalSymbol(args EvalSymbolArgs, variable *api.Variable) error {
v, err := s.debugger.EvalVariableInScope(args.Scope.GoroutineID, args.Scope.Frame, args.Scope.DeferredCall, args.Symbol, defaultLoadConfig)
2015-06-21 03:47:44 +00:00
if err != nil {
return err
}
*variable = *api.ConvertVar(v)
2015-06-21 03:47:44 +00:00
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.GoroutineID, args.Scope.Frame, args.Scope.DeferredCall, args.Symbol, args.Value)
}
2015-06-21 03:47:44 +00:00
func (s *RPCServer) ListSources(filter string, sources *[]string) error {
ss, err := s.debugger.Sources(filter)
if err != nil {
return err
}
*sources = ss
return nil
}
pkg/terminal,service/debugger: Support to add a new suboption --follow-calls to trace subcommand (#3594) * rebasing on master to implement --followcalls * in progress changes to enable --followcalls * rebase to master: modified function to add children to funcs array * modify main traversal loop * added tests to check different scenarios * added tests to check different scenarios * added tests to check different scenarios * add test to check for overlapping regular expression * modified type of strings array as a return only * changed depth to a simple integer instead of a global map * avoid calling traverse on recursive calls * Added tests for various call graphs to test trace followfuncs * Added tests for various call graphs to test trace followfuncs * Added tests for various call graphs to test trace followfuncs * made auxillary changes for build to go through for new option follow-calls * Add support to print depth of the function calls as well * Added two sample output files for checking * Bypass morestack_noctxt in output for verification testing * Corrected newline error by adding newlines only if the line does not match morestack_noctxt * Added more tests * Cleanup * Updated documentation * fixed error message in fmt.Errorf * Fixed result of Errorf not used error * Addressing review comments to fix depth reporting and other issues * dont invoke stacktrace if tracefollowcalls is enabled, compute depth from main regex root symbol than main.main * Addressing a part of review comments * Added changes to allow deferred functions to be picked up for tracing * Fix issue to avoid printing stack for a simple trace option * Moving most tests to integration2_test.go and keeping only one in dlv_test.go * Moving most tests to integration2_test.go and keeping only one in dlv_test.go * Adding panic-defer test case * Moved rest of the tests to integration2_test.go * addressing review comments: folding Functions and FunctionsDeep, reducing branches by using depth prefix, wrap using %w and other comments * Optimize traversal and parts of printing trace point function and modify trace output layout and adjust tests accordingly * Resolved error occurring due to staticcheck * Implemented traversal algorithm using breadth first search * Addressing review comments on the breadth first search implementation and other comments * Inline filterRuntimeFuncs and remove duplicate initialization
2024-06-12 19:35:48 +00:00
func (s *RPCServer) ListFunctions(filter string, followCalls int, funcs *[]string) error {
fns, err := s.debugger.Functions(filter, followCalls)
2015-06-21 03:47:44 +00:00
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
}
2015-06-21 03:47:44 +00:00
func (s *RPCServer) ListGoroutines(arg interface{}, goroutines *[]*api.Goroutine) error {
gs, _, err := s.debugger.Goroutines(0, 0)
2015-06-21 03:47:44 +00:00
if err != nil {
return err
}
s.debugger.LockTarget()
s.debugger.UnlockTarget()
Go 1.17 support branch (#2451) * proc: support new Go 1.17 panic/defer mechanism Go 1.17 will create wrappers for deferred calls that take arguments. Change defer reading code so that wrappers are automatically unwrapped. Also the deferred function is called directly by runtime.gopanic, without going through runtime.callN which means that sometimes when a panic happens the stack is either: 0. deferred function call 1. deferred call wrapper 2. runtime.gopanic or: 0. deferred function call 1. runtime.gopanic instead of always being: 0. deferred function call 1. runtime.callN 2. runtime.gopanic the isPanicCall check is changed accordingly. * test: miscellaneous minor test fixes for Go 1.17 * proc: resolve inlined calls when stepping out of runtime.breakpoint Calls to runtime.Breakpoint are inlined in Go 1.17 when inlining is enabled, resolve inlined calls in stepInstructionOut. * proc: add support for debugCallV2 with regabi This change adds support for the new debug call protocol which had to change for the new register ABI introduced in Go 1.17. Summary of changes: - Abstracts over the debug call version depending on the Go version found in the binary. - Uses R12 instead of RAX as the debug protocol register when the binary is from Go 1.17 or later. - Creates a variable directly from the DWARF entry for function arguments to support passing arguments however the ABI expects. - Computes a very conservative stack frame size for the call when injecting a call into a Go process whose version is >=1.17. Co-authored-by: Michael Anthony Knyszek <mknyszek@google.com> Co-authored-by: Alessandro Arzilli <alessandro.arzilli@gmail.com> * TeamCity: enable tests on go-tip * goversion: version compatibility bump * TeamCity: fix go-tip builds on macOS/arm64 Co-authored-by: Michael Anthony Knyszek <mknyszek@google.com>
2021-07-08 15:47:53 +00:00
*goroutines = api.ConvertGoroutines(s.debugger.Target(), gs)
2015-06-21 03:47:44 +00:00
return nil
}
2015-07-07 14:04:03 +00:00
func (s *RPCServer) AttachedToExistingProcess(arg interface{}, answer *bool) error {
if s.config.Debugger.AttachPid != 0 {
2015-07-07 14:04:03 +00:00
*answer = true
}
return nil
}
type FindLocationArgs struct {
Scope api.EvalScope
Loc string
}
func (s *RPCServer) FindLocation(args FindLocationArgs, answer *[]api.Location) error {
var err error
*answer, _, err = s.debugger.FindLocation(args.Scope.GoroutineID, args.Scope.Frame, args.Scope.DeferredCall, args.Loc, false, nil)
return err
}
2016-02-06 06:00:48 +00:00
type DisassembleRequest struct {
Scope api.EvalScope
StartPC, EndPC uint64
Flavour api.AssemblyFlavour
}
func (s *RPCServer) Disassemble(args DisassembleRequest, answer *api.AsmInstructions) error {
insts, err := s.debugger.Disassemble(args.Scope.GoroutineID, args.StartPC, args.EndPC)
if err != nil {
return err
}
*answer = make(api.AsmInstructions, len(insts))
for i := range insts {
(*answer)[i] = api.ConvertAsmInstruction(insts[i], s.debugger.AsmInstructionText(&insts[i], proc.AssemblyFlavour(args.Flavour)))
}
return nil
2016-02-06 06:00:48 +00:00
}