2016-04-18 19:20:20 +00:00
|
|
|
package rpc2
|
2015-06-21 03:47:44 +00:00
|
|
|
|
|
|
|
import (
|
2024-10-31 17:19:08 +00:00
|
|
|
"bytes"
|
|
|
|
"encoding/json"
|
2015-06-21 03:47:44 +00:00
|
|
|
"fmt"
|
|
|
|
"log"
|
2018-09-03 08:00:30 +00:00
|
|
|
"net"
|
2015-06-21 03:47:44 +00:00
|
|
|
"net/rpc"
|
|
|
|
"net/rpc/jsonrpc"
|
2024-10-31 17:19:08 +00:00
|
|
|
"os/exec"
|
|
|
|
"path/filepath"
|
|
|
|
"strings"
|
2016-12-22 16:53:34 +00:00
|
|
|
"time"
|
2015-06-21 03:47:44 +00:00
|
|
|
|
2019-01-04 18:39:25 +00:00
|
|
|
"github.com/go-delve/delve/service"
|
|
|
|
"github.com/go-delve/delve/service/api"
|
2015-06-21 03:47:44 +00:00
|
|
|
)
|
|
|
|
|
2021-09-28 19:07:42 +00:00
|
|
|
// RPCClient is a RPC service.Client.
|
2015-06-21 03:47:44 +00:00
|
|
|
type RPCClient struct {
|
2017-08-19 20:20:47 +00:00
|
|
|
client *rpc.Client
|
2018-05-11 12:51:15 +00:00
|
|
|
|
|
|
|
retValLoadCfg *api.LoadConfig
|
2015-06-21 03:47:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure the implementation satisfies the interface.
|
|
|
|
var _ service.Client = &RPCClient{}
|
|
|
|
|
|
|
|
// NewClient creates a new RPCClient.
|
|
|
|
func NewClient(addr string) *RPCClient {
|
|
|
|
client, err := jsonrpc.Dial("tcp", addr)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal("dialing:", err)
|
|
|
|
}
|
2018-09-03 08:00:30 +00:00
|
|
|
return newFromRPCClient(client)
|
|
|
|
}
|
|
|
|
|
|
|
|
func newFromRPCClient(client *rpc.Client) *RPCClient {
|
|
|
|
c := &RPCClient{client: client}
|
2020-03-18 16:25:32 +00:00
|
|
|
c.call("SetApiVersion", api.SetAPIVersionIn{APIVersion: 2}, &api.SetAPIVersionOut{})
|
2016-06-19 06:43:29 +00:00
|
|
|
return c
|
2015-06-21 03:47:44 +00:00
|
|
|
}
|
|
|
|
|
2018-09-03 08:00:30 +00:00
|
|
|
// NewClientFromConn creates a new RPCClient from the given connection.
|
|
|
|
func NewClientFromConn(conn net.Conn) *RPCClient {
|
|
|
|
return newFromRPCClient(jsonrpc.NewClient(conn))
|
|
|
|
}
|
|
|
|
|
2015-07-03 20:35:22 +00:00
|
|
|
func (c *RPCClient) ProcessPid() int {
|
2016-04-18 19:20:20 +00:00
|
|
|
out := new(ProcessPidOut)
|
|
|
|
c.call("ProcessPid", ProcessPidIn{}, out)
|
|
|
|
return out.Pid
|
2015-07-03 20:35:22 +00:00
|
|
|
}
|
|
|
|
|
2022-01-30 21:39:30 +00:00
|
|
|
func (c *RPCClient) BuildID() string {
|
|
|
|
out := new(BuildIDOut)
|
|
|
|
c.call("BuildID", BuildIDIn{}, out)
|
|
|
|
return out.BuildID
|
|
|
|
}
|
|
|
|
|
2016-12-22 16:53:34 +00:00
|
|
|
func (c *RPCClient) LastModified() time.Time {
|
|
|
|
out := new(LastModifiedOut)
|
|
|
|
c.call("LastModified", LastModifiedIn{}, out)
|
|
|
|
return out.Time
|
|
|
|
}
|
|
|
|
|
2015-06-21 03:47:44 +00:00
|
|
|
func (c *RPCClient) Detach(kill bool) error {
|
2017-06-26 18:45:13 +00:00
|
|
|
defer c.client.Close()
|
2016-04-18 19:20:20 +00:00
|
|
|
out := new(DetachOut)
|
|
|
|
return c.call("Detach", DetachIn{kill}, out)
|
2015-06-21 03:47:44 +00:00
|
|
|
}
|
|
|
|
|
2020-06-05 18:03:09 +00:00
|
|
|
func (c *RPCClient) Restart(rebuild bool) ([]api.DiscardedBreakpoint, error) {
|
2016-04-18 19:20:20 +00:00
|
|
|
out := new(RestartOut)
|
2020-08-21 14:14:02 +00:00
|
|
|
err := c.call("Restart", RestartIn{"", false, nil, false, rebuild, [3]string{}}, out)
|
2017-05-05 22:17:52 +00:00
|
|
|
return out.DiscardedBreakpoints, err
|
|
|
|
}
|
|
|
|
|
2020-08-21 14:14:02 +00:00
|
|
|
func (c *RPCClient) RestartFrom(rerecord bool, pos string, resetArgs bool, newArgs []string, newRedirects [3]string, rebuild bool) ([]api.DiscardedBreakpoint, error) {
|
2017-05-05 22:17:52 +00:00
|
|
|
out := new(RestartOut)
|
2020-08-21 14:14:02 +00:00
|
|
|
err := c.call("Restart", RestartIn{pos, resetArgs, newArgs, rerecord, rebuild, newRedirects}, out)
|
2016-12-22 16:53:34 +00:00
|
|
|
return out.DiscardedBreakpoints, err
|
2015-07-03 20:35:22 +00:00
|
|
|
}
|
|
|
|
|
2015-06-21 03:47:44 +00:00
|
|
|
func (c *RPCClient) GetState() (*api.DebuggerState, error) {
|
2016-04-18 19:20:20 +00:00
|
|
|
var out StateOut
|
2018-11-20 15:13:09 +00:00
|
|
|
err := c.call("State", StateIn{NonBlocking: false}, &out)
|
2016-04-18 19:20:20 +00:00
|
|
|
return out.State, err
|
2015-06-21 03:47:44 +00:00
|
|
|
}
|
|
|
|
|
2018-06-21 11:07:37 +00:00
|
|
|
func (c *RPCClient) GetStateNonBlocking() (*api.DebuggerState, error) {
|
|
|
|
var out StateOut
|
|
|
|
err := c.call("State", StateIn{NonBlocking: true}, &out)
|
|
|
|
return out.State, err
|
|
|
|
}
|
|
|
|
|
2015-07-03 19:18:03 +00:00
|
|
|
func (c *RPCClient) Continue() <-chan *api.DebuggerState {
|
2017-05-05 22:17:52 +00:00
|
|
|
return c.continueDir(api.Continue)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *RPCClient) Rewind() <-chan *api.DebuggerState {
|
|
|
|
return c.continueDir(api.Rewind)
|
|
|
|
}
|
|
|
|
|
proc,terminal: Implement reverse step, next and stepout (#1785)
* proc: move defer breakpoint code into a function
Moves the code that sets a breakpoint on the first deferred function,
used by both next and StepOut, to its function.
* proc: implement reverse step/next/stepout
When the direction of execution is reversed (on a recording) Step, Next and
StepOut will behave similarly to their forward version. However there are
some subtle interactions between their behavior, prologue skipping, deferred
calls and normal calls. Specifically:
- when stepping backwards we need to set a breakpoint on the first
instruction after each CALL instruction, once this breakpoint is reached we
need to execute a single StepInstruction operation to reverse step into the
CALL.
- to insure that the prologue is skipped reverse next needs to check if it
is on the first instruction after the prologue, and if it is behave like
reverse stepout.
- there is no reason to set breakpoints on deferred calls when reverse
nexting or reverse stepping out, they will never be hit.
- reverse step out should generally place its breakpoint on the CALL
instruction that created the current stack frame (which will be the CALL
instruction immediately preceding the instruction at the return address).
- reverse step out needs to treat panic calls and deferreturn calls
specially.
* service,terminal: implement reverse step, next, stepout
2020-03-11 22:40:41 +00:00
|
|
|
func (c *RPCClient) DirectionCongruentContinue() <-chan *api.DebuggerState {
|
|
|
|
return c.continueDir(api.DirectionCongruentContinue)
|
|
|
|
}
|
|
|
|
|
2017-05-05 22:17:52 +00:00
|
|
|
func (c *RPCClient) continueDir(cmd string) <-chan *api.DebuggerState {
|
2015-06-28 15:00:56 +00:00
|
|
|
ch := make(chan *api.DebuggerState)
|
|
|
|
go func() {
|
|
|
|
for {
|
2016-04-18 19:20:20 +00:00
|
|
|
out := new(CommandOut)
|
2018-05-11 12:51:15 +00:00
|
|
|
err := c.call("Command", &api.DebuggerCommand{Name: cmd, ReturnInfoLoadConfig: c.retValLoadCfg}, &out)
|
2016-04-18 19:20:20 +00:00
|
|
|
state := out.State
|
2015-07-03 19:18:03 +00:00
|
|
|
if err != nil {
|
|
|
|
state.Err = err
|
|
|
|
}
|
|
|
|
if state.Exited {
|
2018-03-20 10:05:35 +00:00
|
|
|
// Error types apparently cannot be marshalled by Go correctly. Must reset error here.
|
2021-09-28 19:07:42 +00:00
|
|
|
//lint:ignore ST1005 backwards compatibility
|
2015-07-03 19:18:03 +00:00
|
|
|
state.Err = fmt.Errorf("Process %d has exited with status %d", c.ProcessPid(), state.ExitStatus)
|
|
|
|
}
|
2016-04-18 19:20:20 +00:00
|
|
|
ch <- &state
|
2015-10-29 09:59:22 +00:00
|
|
|
if err != nil || state.Exited {
|
|
|
|
close(ch)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
isbreakpoint := false
|
|
|
|
istracepoint := true
|
|
|
|
for i := range state.Threads {
|
|
|
|
if state.Threads[i].Breakpoint != nil {
|
|
|
|
isbreakpoint = true
|
2018-10-16 15:49:20 +00:00
|
|
|
istracepoint = istracepoint && (state.Threads[i].Breakpoint.Tracepoint || state.Threads[i].Breakpoint.TraceReturn)
|
2015-10-29 09:59:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if !isbreakpoint || !istracepoint {
|
2015-06-28 15:00:56 +00:00
|
|
|
close(ch)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
return ch
|
2015-06-21 03:47:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (c *RPCClient) Next() (*api.DebuggerState, error) {
|
2016-04-18 19:20:20 +00:00
|
|
|
var out CommandOut
|
2018-05-11 12:51:15 +00:00
|
|
|
err := c.call("Command", api.DebuggerCommand{Name: api.Next, ReturnInfoLoadConfig: c.retValLoadCfg}, &out)
|
2016-04-18 19:20:20 +00:00
|
|
|
return &out.State, err
|
2015-06-21 03:47:44 +00:00
|
|
|
}
|
|
|
|
|
proc,terminal: Implement reverse step, next and stepout (#1785)
* proc: move defer breakpoint code into a function
Moves the code that sets a breakpoint on the first deferred function,
used by both next and StepOut, to its function.
* proc: implement reverse step/next/stepout
When the direction of execution is reversed (on a recording) Step, Next and
StepOut will behave similarly to their forward version. However there are
some subtle interactions between their behavior, prologue skipping, deferred
calls and normal calls. Specifically:
- when stepping backwards we need to set a breakpoint on the first
instruction after each CALL instruction, once this breakpoint is reached we
need to execute a single StepInstruction operation to reverse step into the
CALL.
- to insure that the prologue is skipped reverse next needs to check if it
is on the first instruction after the prologue, and if it is behave like
reverse stepout.
- there is no reason to set breakpoints on deferred calls when reverse
nexting or reverse stepping out, they will never be hit.
- reverse step out should generally place its breakpoint on the CALL
instruction that created the current stack frame (which will be the CALL
instruction immediately preceding the instruction at the return address).
- reverse step out needs to treat panic calls and deferreturn calls
specially.
* service,terminal: implement reverse step, next, stepout
2020-03-11 22:40:41 +00:00
|
|
|
func (c *RPCClient) ReverseNext() (*api.DebuggerState, error) {
|
|
|
|
var out CommandOut
|
|
|
|
err := c.call("Command", api.DebuggerCommand{Name: api.ReverseNext, ReturnInfoLoadConfig: c.retValLoadCfg}, &out)
|
|
|
|
return &out.State, err
|
|
|
|
}
|
|
|
|
|
2015-06-21 03:47:44 +00:00
|
|
|
func (c *RPCClient) Step() (*api.DebuggerState, error) {
|
2016-04-18 19:20:20 +00:00
|
|
|
var out CommandOut
|
2018-05-11 12:51:15 +00:00
|
|
|
err := c.call("Command", api.DebuggerCommand{Name: api.Step, ReturnInfoLoadConfig: c.retValLoadCfg}, &out)
|
2016-04-18 19:20:20 +00:00
|
|
|
return &out.State, err
|
2015-06-21 03:47:44 +00:00
|
|
|
}
|
|
|
|
|
proc,terminal: Implement reverse step, next and stepout (#1785)
* proc: move defer breakpoint code into a function
Moves the code that sets a breakpoint on the first deferred function,
used by both next and StepOut, to its function.
* proc: implement reverse step/next/stepout
When the direction of execution is reversed (on a recording) Step, Next and
StepOut will behave similarly to their forward version. However there are
some subtle interactions between their behavior, prologue skipping, deferred
calls and normal calls. Specifically:
- when stepping backwards we need to set a breakpoint on the first
instruction after each CALL instruction, once this breakpoint is reached we
need to execute a single StepInstruction operation to reverse step into the
CALL.
- to insure that the prologue is skipped reverse next needs to check if it
is on the first instruction after the prologue, and if it is behave like
reverse stepout.
- there is no reason to set breakpoints on deferred calls when reverse
nexting or reverse stepping out, they will never be hit.
- reverse step out should generally place its breakpoint on the CALL
instruction that created the current stack frame (which will be the CALL
instruction immediately preceding the instruction at the return address).
- reverse step out needs to treat panic calls and deferreturn calls
specially.
* service,terminal: implement reverse step, next, stepout
2020-03-11 22:40:41 +00:00
|
|
|
func (c *RPCClient) ReverseStep() (*api.DebuggerState, error) {
|
|
|
|
var out CommandOut
|
|
|
|
err := c.call("Command", api.DebuggerCommand{Name: api.ReverseStep, ReturnInfoLoadConfig: c.retValLoadCfg}, &out)
|
|
|
|
return &out.State, err
|
|
|
|
}
|
|
|
|
|
2016-04-14 09:58:59 +00:00
|
|
|
func (c *RPCClient) StepOut() (*api.DebuggerState, error) {
|
|
|
|
var out CommandOut
|
2018-11-20 15:13:09 +00:00
|
|
|
err := c.call("Command", api.DebuggerCommand{Name: api.StepOut, ReturnInfoLoadConfig: c.retValLoadCfg}, &out)
|
2016-04-14 09:58:59 +00:00
|
|
|
return &out.State, err
|
|
|
|
}
|
|
|
|
|
proc,terminal: Implement reverse step, next and stepout (#1785)
* proc: move defer breakpoint code into a function
Moves the code that sets a breakpoint on the first deferred function,
used by both next and StepOut, to its function.
* proc: implement reverse step/next/stepout
When the direction of execution is reversed (on a recording) Step, Next and
StepOut will behave similarly to their forward version. However there are
some subtle interactions between their behavior, prologue skipping, deferred
calls and normal calls. Specifically:
- when stepping backwards we need to set a breakpoint on the first
instruction after each CALL instruction, once this breakpoint is reached we
need to execute a single StepInstruction operation to reverse step into the
CALL.
- to insure that the prologue is skipped reverse next needs to check if it
is on the first instruction after the prologue, and if it is behave like
reverse stepout.
- there is no reason to set breakpoints on deferred calls when reverse
nexting or reverse stepping out, they will never be hit.
- reverse step out should generally place its breakpoint on the CALL
instruction that created the current stack frame (which will be the CALL
instruction immediately preceding the instruction at the return address).
- reverse step out needs to treat panic calls and deferreturn calls
specially.
* service,terminal: implement reverse step, next, stepout
2020-03-11 22:40:41 +00:00
|
|
|
func (c *RPCClient) ReverseStepOut() (*api.DebuggerState, error) {
|
|
|
|
var out CommandOut
|
|
|
|
err := c.call("Command", api.DebuggerCommand{Name: api.ReverseStepOut, ReturnInfoLoadConfig: c.retValLoadCfg}, &out)
|
|
|
|
return &out.State, err
|
|
|
|
}
|
|
|
|
|
2022-08-16 16:31:11 +00:00
|
|
|
func (c *RPCClient) Call(goroutineID int64, expr string, unsafe bool) (*api.DebuggerState, error) {
|
2018-05-04 17:31:45 +00:00
|
|
|
var out CommandOut
|
2019-06-30 17:44:30 +00:00
|
|
|
err := c.call("Command", api.DebuggerCommand{Name: api.Call, ReturnInfoLoadConfig: c.retValLoadCfg, Expr: expr, UnsafeCall: unsafe, GoroutineID: goroutineID}, &out)
|
2018-05-04 17:31:45 +00:00
|
|
|
return &out.State, err
|
|
|
|
}
|
|
|
|
|
2024-02-28 08:28:33 +00:00
|
|
|
func (c *RPCClient) StepInstruction(skipCalls bool) (*api.DebuggerState, error) {
|
2016-04-18 19:20:20 +00:00
|
|
|
var out CommandOut
|
2024-02-28 08:28:33 +00:00
|
|
|
name := api.StepInstruction
|
|
|
|
if skipCalls {
|
|
|
|
name = api.NextInstruction
|
|
|
|
}
|
|
|
|
err := c.call("Command", api.DebuggerCommand{Name: name}, &out)
|
2016-04-18 19:20:20 +00:00
|
|
|
return &out.State, err
|
2016-01-24 05:25:46 +00:00
|
|
|
}
|
|
|
|
|
2024-02-28 08:28:33 +00:00
|
|
|
func (c *RPCClient) ReverseStepInstruction(skipCalls bool) (*api.DebuggerState, error) {
|
2019-07-09 01:01:00 +00:00
|
|
|
var out CommandOut
|
2024-02-28 08:28:33 +00:00
|
|
|
name := api.ReverseStepInstruction
|
|
|
|
if skipCalls {
|
|
|
|
name = api.ReverseNextInstruction
|
|
|
|
}
|
|
|
|
err := c.call("Command", api.DebuggerCommand{Name: name}, &out)
|
2019-07-09 01:01:00 +00:00
|
|
|
return &out.State, err
|
|
|
|
}
|
|
|
|
|
2015-06-21 03:47:44 +00:00
|
|
|
func (c *RPCClient) SwitchThread(threadID int) (*api.DebuggerState, error) {
|
2016-04-18 19:20:20 +00:00
|
|
|
var out CommandOut
|
|
|
|
cmd := api.DebuggerCommand{
|
2015-06-21 03:47:44 +00:00
|
|
|
Name: api.SwitchThread,
|
|
|
|
ThreadID: threadID,
|
|
|
|
}
|
2016-04-18 19:20:20 +00:00
|
|
|
err := c.call("Command", cmd, &out)
|
|
|
|
return &out.State, err
|
2015-06-21 03:47:44 +00:00
|
|
|
}
|
|
|
|
|
2022-08-16 16:31:11 +00:00
|
|
|
func (c *RPCClient) SwitchGoroutine(goroutineID int64) (*api.DebuggerState, error) {
|
2016-04-18 19:20:20 +00:00
|
|
|
var out CommandOut
|
|
|
|
cmd := api.DebuggerCommand{
|
2015-08-28 20:06:29 +00:00
|
|
|
Name: api.SwitchGoroutine,
|
|
|
|
GoroutineID: goroutineID,
|
|
|
|
}
|
2016-04-18 19:20:20 +00:00
|
|
|
err := c.call("Command", cmd, &out)
|
|
|
|
return &out.State, err
|
2015-08-28 20:06:29 +00:00
|
|
|
}
|
|
|
|
|
2015-06-21 03:47:44 +00:00
|
|
|
func (c *RPCClient) Halt() (*api.DebuggerState, error) {
|
2016-04-18 19:20:20 +00:00
|
|
|
var out CommandOut
|
|
|
|
err := c.call("Command", api.DebuggerCommand{Name: api.Halt}, &out)
|
|
|
|
return &out.State, err
|
2015-06-21 03:47:44 +00:00
|
|
|
}
|
|
|
|
|
2021-07-31 15:16:26 +00:00
|
|
|
func (c *RPCClient) GetBufferedTracepoints() ([]api.TracepointResult, error) {
|
|
|
|
var out GetBufferedTracepointsOut
|
|
|
|
err := c.call("GetBufferedTracepoints", GetBufferedTracepointsIn{}, &out)
|
|
|
|
return out.TracepointResults, err
|
|
|
|
}
|
|
|
|
|
2015-06-21 03:47:44 +00:00
|
|
|
func (c *RPCClient) GetBreakpoint(id int) (*api.Breakpoint, error) {
|
2016-04-18 19:20:20 +00:00
|
|
|
var out GetBreakpointOut
|
|
|
|
err := c.call("GetBreakpoint", GetBreakpointIn{id, ""}, &out)
|
|
|
|
return &out.Breakpoint, err
|
2015-06-21 03:47:44 +00:00
|
|
|
}
|
|
|
|
|
2016-01-24 08:16:45 +00:00
|
|
|
func (c *RPCClient) GetBreakpointByName(name string) (*api.Breakpoint, error) {
|
2016-04-18 19:20:20 +00:00
|
|
|
var out GetBreakpointOut
|
|
|
|
err := c.call("GetBreakpoint", GetBreakpointIn{0, name}, &out)
|
|
|
|
return &out.Breakpoint, err
|
2016-01-24 08:16:45 +00:00
|
|
|
}
|
|
|
|
|
2021-06-29 13:14:24 +00:00
|
|
|
// CreateBreakpoint will send a request to the RPC server to create a breakpoint.
|
|
|
|
// Please refer to the documentation for `Debugger.CreateBreakpoint` for a description of how
|
|
|
|
// the requested breakpoint parameters are interpreted and used:
|
|
|
|
// https://pkg.go.dev/github.com/go-delve/delve/service/debugger#Debugger.CreateBreakpoint
|
2015-06-21 03:47:44 +00:00
|
|
|
func (c *RPCClient) CreateBreakpoint(breakPoint *api.Breakpoint) (*api.Breakpoint, error) {
|
2016-04-18 19:20:20 +00:00
|
|
|
var out CreateBreakpointOut
|
2022-10-04 15:07:05 +00:00
|
|
|
err := c.call("CreateBreakpoint", CreateBreakpointIn{*breakPoint, "", nil, false}, &out)
|
2022-09-28 18:35:07 +00:00
|
|
|
return &out.Breakpoint, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// CreateBreakpointWithExpr is like CreateBreakpoint but will also set a
|
|
|
|
// location expression to be used to restore the breakpoint after it is
|
|
|
|
// disabled.
|
2022-10-04 15:07:05 +00:00
|
|
|
func (c *RPCClient) CreateBreakpointWithExpr(breakPoint *api.Breakpoint, locExpr string, substitutePathRules [][2]string, suspended bool) (*api.Breakpoint, error) {
|
2022-09-28 18:35:07 +00:00
|
|
|
var out CreateBreakpointOut
|
2022-10-04 15:07:05 +00:00
|
|
|
err := c.call("CreateBreakpoint", CreateBreakpointIn{*breakPoint, locExpr, substitutePathRules, suspended}, &out)
|
2016-04-18 19:20:20 +00:00
|
|
|
return &out.Breakpoint, err
|
2015-06-21 03:47:44 +00:00
|
|
|
}
|
|
|
|
|
2021-07-31 15:16:26 +00:00
|
|
|
func (c *RPCClient) CreateEBPFTracepoint(fnName string) error {
|
|
|
|
var out CreateEBPFTracepointOut
|
|
|
|
return c.call("CreateEBPFTracepoint", CreateEBPFTracepointIn{FunctionName: fnName}, &out)
|
|
|
|
}
|
|
|
|
|
2021-05-20 17:04:02 +00:00
|
|
|
func (c *RPCClient) CreateWatchpoint(scope api.EvalScope, expr string, wtype api.WatchType) (*api.Breakpoint, error) {
|
|
|
|
var out CreateWatchpointOut
|
|
|
|
err := c.call("CreateWatchpoint", CreateWatchpointIn{scope, expr, wtype}, &out)
|
|
|
|
return out.Breakpoint, err
|
|
|
|
}
|
|
|
|
|
2021-08-09 17:41:25 +00:00
|
|
|
func (c *RPCClient) ListBreakpoints(all bool) ([]*api.Breakpoint, error) {
|
2016-04-18 19:20:20 +00:00
|
|
|
var out ListBreakpointsOut
|
2021-08-09 17:41:25 +00:00
|
|
|
err := c.call("ListBreakpoints", ListBreakpointsIn{all}, &out)
|
2016-04-18 19:20:20 +00:00
|
|
|
return out.Breakpoints, err
|
2015-06-21 03:47:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (c *RPCClient) ClearBreakpoint(id int) (*api.Breakpoint, error) {
|
2016-04-18 19:20:20 +00:00
|
|
|
var out ClearBreakpointOut
|
|
|
|
err := c.call("ClearBreakpoint", ClearBreakpointIn{id, ""}, &out)
|
|
|
|
return out.Breakpoint, err
|
2015-06-21 03:47:44 +00:00
|
|
|
}
|
|
|
|
|
2016-01-24 08:16:45 +00:00
|
|
|
func (c *RPCClient) ClearBreakpointByName(name string) (*api.Breakpoint, error) {
|
2016-04-18 19:20:20 +00:00
|
|
|
var out ClearBreakpointOut
|
|
|
|
err := c.call("ClearBreakpoint", ClearBreakpointIn{0, name}, &out)
|
|
|
|
return out.Breakpoint, err
|
2016-01-24 08:16:45 +00:00
|
|
|
}
|
|
|
|
|
2021-03-19 18:02:23 +00:00
|
|
|
func (c *RPCClient) ToggleBreakpoint(id int) (*api.Breakpoint, error) {
|
|
|
|
var out ToggleBreakpointOut
|
|
|
|
err := c.call("ToggleBreakpoint", ToggleBreakpointIn{id, ""}, &out)
|
|
|
|
return out.Breakpoint, err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *RPCClient) ToggleBreakpointByName(name string) (*api.Breakpoint, error) {
|
|
|
|
var out ToggleBreakpointOut
|
|
|
|
err := c.call("ToggleBreakpoint", ToggleBreakpointIn{0, name}, &out)
|
|
|
|
return out.Breakpoint, err
|
|
|
|
}
|
|
|
|
|
2016-01-24 08:16:45 +00:00
|
|
|
func (c *RPCClient) AmendBreakpoint(bp *api.Breakpoint) error {
|
2016-04-18 19:20:20 +00:00
|
|
|
out := new(AmendBreakpointOut)
|
|
|
|
err := c.call("AmendBreakpoint", AmendBreakpointIn{*bp}, out)
|
2016-01-24 08:16:45 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2016-04-24 23:20:02 +00:00
|
|
|
func (c *RPCClient) CancelNext() error {
|
|
|
|
var out CancelNextOut
|
|
|
|
return c.call("CancelNext", CancelNextIn{}, &out)
|
|
|
|
}
|
|
|
|
|
2015-06-21 03:47:44 +00:00
|
|
|
func (c *RPCClient) ListThreads() ([]*api.Thread, error) {
|
2016-04-18 19:20:20 +00:00
|
|
|
var out ListThreadsOut
|
|
|
|
err := c.call("ListThreads", ListThreadsIn{}, &out)
|
|
|
|
return out.Threads, err
|
2015-06-21 03:47:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (c *RPCClient) GetThread(id int) (*api.Thread, error) {
|
2016-04-18 19:20:20 +00:00
|
|
|
var out GetThreadOut
|
|
|
|
err := c.call("GetThread", GetThreadIn{id}, &out)
|
|
|
|
return out.Thread, err
|
2015-06-21 03:47:44 +00:00
|
|
|
}
|
|
|
|
|
2016-04-24 17:15:39 +00:00
|
|
|
func (c *RPCClient) EvalVariable(scope api.EvalScope, expr string, cfg api.LoadConfig) (*api.Variable, error) {
|
2016-04-18 19:20:20 +00:00
|
|
|
var out EvalOut
|
2016-04-24 17:15:39 +00:00
|
|
|
err := c.call("Eval", EvalIn{scope, expr, &cfg}, &out)
|
2016-04-18 19:20:20 +00:00
|
|
|
return out.Variable, err
|
2015-06-21 03:47:44 +00:00
|
|
|
}
|
|
|
|
|
2015-09-28 10:01:18 +00:00
|
|
|
func (c *RPCClient) SetVariable(scope api.EvalScope, symbol, value string) error {
|
2016-04-18 19:20:20 +00:00
|
|
|
out := new(SetOut)
|
|
|
|
return c.call("Set", SetIn{scope, symbol, value}, out)
|
2015-09-28 10:01:18 +00:00
|
|
|
}
|
|
|
|
|
2015-06-21 03:47:44 +00:00
|
|
|
func (c *RPCClient) ListSources(filter string) ([]string, error) {
|
2016-04-18 19:20:20 +00:00
|
|
|
sources := new(ListSourcesOut)
|
|
|
|
err := c.call("ListSources", ListSourcesIn{filter}, sources)
|
|
|
|
return sources.Sources, err
|
2015-06-21 03:47:44 +00:00
|
|
|
}
|
|
|
|
|
2024-06-12 19:35:48 +00:00
|
|
|
func (c *RPCClient) ListFunctions(filter string, TraceFollow int) ([]string, error) {
|
2016-04-18 19:20:20 +00:00
|
|
|
funcs := new(ListFunctionsOut)
|
2024-06-12 19:35:48 +00:00
|
|
|
err := c.call("ListFunctions", ListFunctionsIn{filter, TraceFollow}, funcs)
|
2016-04-18 19:20:20 +00:00
|
|
|
return funcs.Funcs, err
|
2015-06-21 03:47:44 +00:00
|
|
|
}
|
|
|
|
|
2016-02-22 15:08:45 +00:00
|
|
|
func (c *RPCClient) ListTypes(filter string) ([]string, error) {
|
2016-04-18 19:20:20 +00:00
|
|
|
types := new(ListTypesOut)
|
|
|
|
err := c.call("ListTypes", ListTypesIn{filter}, types)
|
|
|
|
return types.Types, err
|
2016-02-22 15:08:45 +00:00
|
|
|
}
|
|
|
|
|
2016-04-24 17:15:39 +00:00
|
|
|
func (c *RPCClient) ListPackageVariables(filter string, cfg api.LoadConfig) ([]api.Variable, error) {
|
2016-04-18 19:20:20 +00:00
|
|
|
var out ListPackageVarsOut
|
2016-04-24 17:15:39 +00:00
|
|
|
err := c.call("ListPackageVars", ListPackageVarsIn{filter, cfg}, &out)
|
2016-04-18 19:20:20 +00:00
|
|
|
return out.Variables, err
|
2015-06-21 03:47:44 +00:00
|
|
|
}
|
|
|
|
|
2023-09-18 15:59:58 +00:00
|
|
|
func (c *RPCClient) ListPackagesBuildInfo(filter string, includeFiles bool) ([]api.PackageBuildInfo, error) {
|
|
|
|
var out ListPackagesBuildInfoOut
|
|
|
|
err := c.call("ListPackagesBuildInfo", ListPackagesBuildInfoIn{Filter: filter, IncludeFiles: includeFiles}, &out)
|
|
|
|
return out.List, err
|
|
|
|
}
|
|
|
|
|
2016-04-24 17:15:39 +00:00
|
|
|
func (c *RPCClient) ListLocalVariables(scope api.EvalScope, cfg api.LoadConfig) ([]api.Variable, error) {
|
2016-04-18 19:20:20 +00:00
|
|
|
var out ListLocalVarsOut
|
2016-04-24 17:15:39 +00:00
|
|
|
err := c.call("ListLocalVars", ListLocalVarsIn{scope, cfg}, &out)
|
2016-04-18 19:20:20 +00:00
|
|
|
return out.Variables, err
|
2015-06-21 03:47:44 +00:00
|
|
|
}
|
|
|
|
|
2020-02-24 18:47:02 +00:00
|
|
|
func (c *RPCClient) ListThreadRegisters(threadID int, includeFp bool) (api.Registers, error) {
|
2016-04-18 19:20:20 +00:00
|
|
|
out := new(ListRegistersOut)
|
2020-02-24 18:47:02 +00:00
|
|
|
err := c.call("ListRegisters", ListRegistersIn{ThreadID: threadID, IncludeFp: includeFp, Scope: nil}, out)
|
|
|
|
return out.Regs, err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *RPCClient) ListScopeRegisters(scope api.EvalScope, includeFp bool) (api.Registers, error) {
|
|
|
|
out := new(ListRegistersOut)
|
|
|
|
err := c.call("ListRegisters", ListRegistersIn{ThreadID: 0, IncludeFp: includeFp, Scope: &scope}, out)
|
2016-11-15 16:16:33 +00:00
|
|
|
return out.Regs, err
|
2015-06-21 03:47:44 +00:00
|
|
|
}
|
|
|
|
|
2016-04-24 17:15:39 +00:00
|
|
|
func (c *RPCClient) ListFunctionArgs(scope api.EvalScope, cfg api.LoadConfig) ([]api.Variable, error) {
|
2016-04-18 19:20:20 +00:00
|
|
|
var out ListFunctionArgsOut
|
2016-04-24 17:15:39 +00:00
|
|
|
err := c.call("ListFunctionArgs", ListFunctionArgsIn{scope, cfg}, &out)
|
2016-04-18 19:20:20 +00:00
|
|
|
return out.Args, err
|
2015-06-21 03:47:44 +00:00
|
|
|
}
|
|
|
|
|
2018-11-19 14:18:10 +00:00
|
|
|
func (c *RPCClient) ListGoroutines(start, count int) ([]*api.Goroutine, int, error) {
|
2016-04-18 19:20:20 +00:00
|
|
|
var out ListGoroutinesOut
|
2023-08-23 20:02:34 +00:00
|
|
|
err := c.call("ListGoroutines", ListGoroutinesIn{start, count, nil, api.GoroutineGroupingOptions{}, nil}, &out)
|
2018-11-19 14:18:10 +00:00
|
|
|
return out.Goroutines, out.Nextg, err
|
2015-06-21 03:47:44 +00:00
|
|
|
}
|
|
|
|
|
2023-08-23 20:02:34 +00:00
|
|
|
func (c *RPCClient) ListGoroutinesWithFilter(start, count int, filters []api.ListGoroutinesFilter, group *api.GoroutineGroupingOptions, scope *api.EvalScope) ([]*api.Goroutine, []api.GoroutineGroup, int, bool, error) {
|
2021-07-01 18:25:33 +00:00
|
|
|
if group == nil {
|
|
|
|
group = &api.GoroutineGroupingOptions{}
|
|
|
|
}
|
|
|
|
var out ListGoroutinesOut
|
2023-08-23 20:02:34 +00:00
|
|
|
err := c.call("ListGoroutines", ListGoroutinesIn{start, count, filters, *group, scope}, &out)
|
2021-07-01 18:25:33 +00:00
|
|
|
return out.Goroutines, out.Groups, out.Nextg, out.TooManyGroups, err
|
|
|
|
}
|
|
|
|
|
2022-08-16 16:31:11 +00:00
|
|
|
func (c *RPCClient) Stacktrace(goroutineId int64, depth int, opts api.StacktraceOptions, cfg *api.LoadConfig) ([]api.Stackframe, error) {
|
2016-04-18 19:20:20 +00:00
|
|
|
var out StacktraceOut
|
2019-09-25 17:21:20 +00:00
|
|
|
err := c.call("Stacktrace", StacktraceIn{goroutineId, depth, false, false, opts, cfg}, &out)
|
2016-04-18 19:20:20 +00:00
|
|
|
return out.Locations, err
|
2015-06-21 03:47:44 +00:00
|
|
|
}
|
|
|
|
|
2022-08-16 16:31:11 +00:00
|
|
|
func (c *RPCClient) Ancestors(goroutineID int64, numAncestors int, depth int) ([]api.Ancestor, error) {
|
2019-03-16 13:50:18 +00:00
|
|
|
var out AncestorsOut
|
|
|
|
err := c.call("Ancestors", AncestorsIn{goroutineID, numAncestors, depth}, &out)
|
|
|
|
return out.Ancestors, err
|
|
|
|
}
|
|
|
|
|
2015-07-07 14:04:03 +00:00
|
|
|
func (c *RPCClient) AttachedToExistingProcess() bool {
|
2016-04-18 19:20:20 +00:00
|
|
|
out := new(AttachedToExistingProcessOut)
|
|
|
|
c.call("AttachedToExistingProcess", AttachedToExistingProcessIn{}, out)
|
|
|
|
return out.Answer
|
2015-07-07 14:04:03 +00:00
|
|
|
}
|
|
|
|
|
2023-07-20 10:29:59 +00:00
|
|
|
func (c *RPCClient) FindLocation(scope api.EvalScope, loc string, findInstructions bool, substitutePathRules [][2]string) ([]api.Location, string, error) {
|
2016-04-18 19:20:20 +00:00
|
|
|
var out FindLocationOut
|
2020-10-26 12:36:52 +00:00
|
|
|
err := c.call("FindLocation", FindLocationIn{scope, loc, !findInstructions, substitutePathRules}, &out)
|
2023-07-20 10:29:59 +00:00
|
|
|
return out.Locations, out.SubstituteLocExpr, err
|
2015-08-07 16:50:14 +00:00
|
|
|
}
|
|
|
|
|
2021-09-28 19:07:42 +00:00
|
|
|
// DisassembleRange disassembles code between startPC and endPC
|
2016-02-06 06:00:48 +00:00
|
|
|
func (c *RPCClient) DisassembleRange(scope api.EvalScope, startPC, endPC uint64, flavour api.AssemblyFlavour) (api.AsmInstructions, error) {
|
2016-04-18 19:20:20 +00:00
|
|
|
var out DisassembleOut
|
|
|
|
err := c.call("Disassemble", DisassembleIn{scope, startPC, endPC, flavour}, &out)
|
|
|
|
return out.Disassemble, err
|
2016-02-06 06:00:48 +00:00
|
|
|
}
|
|
|
|
|
2021-09-28 19:07:42 +00:00
|
|
|
// DisassemblePC disassembles function containing pc
|
2016-02-06 06:00:48 +00:00
|
|
|
func (c *RPCClient) DisassemblePC(scope api.EvalScope, pc uint64, flavour api.AssemblyFlavour) (api.AsmInstructions, error) {
|
2016-04-18 19:20:20 +00:00
|
|
|
var out DisassembleOut
|
|
|
|
err := c.call("Disassemble", DisassembleIn{scope, pc, 0, flavour}, &out)
|
|
|
|
return out.Disassemble, err
|
2016-02-06 06:00:48 +00:00
|
|
|
}
|
|
|
|
|
2017-05-05 22:17:52 +00:00
|
|
|
// Recorded returns true if the debugger target is a recording.
|
|
|
|
func (c *RPCClient) Recorded() bool {
|
|
|
|
out := new(RecordedOut)
|
|
|
|
c.call("Recorded", RecordedIn{}, out)
|
|
|
|
return out.Recorded
|
|
|
|
}
|
|
|
|
|
|
|
|
// TraceDirectory returns the path to the trace directory for a recording.
|
|
|
|
func (c *RPCClient) TraceDirectory() (string, error) {
|
|
|
|
var out RecordedOut
|
|
|
|
err := c.call("Recorded", RecordedIn{}, &out)
|
|
|
|
return out.TraceDirectory, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Checkpoint sets a checkpoint at the current position.
|
|
|
|
func (c *RPCClient) Checkpoint(where string) (checkpointID int, err error) {
|
|
|
|
var out CheckpointOut
|
|
|
|
err = c.call("Checkpoint", CheckpointIn{where}, &out)
|
|
|
|
return out.ID, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// ListCheckpoints gets all checkpoints.
|
|
|
|
func (c *RPCClient) ListCheckpoints() ([]api.Checkpoint, error) {
|
|
|
|
var out ListCheckpointsOut
|
|
|
|
err := c.call("ListCheckpoints", ListCheckpointsIn{}, &out)
|
|
|
|
return out.Checkpoints, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// ClearCheckpoint removes a checkpoint
|
|
|
|
func (c *RPCClient) ClearCheckpoint(id int) error {
|
|
|
|
var out ClearCheckpointOut
|
|
|
|
err := c.call("ClearCheckpoint", ClearCheckpointIn{id}, &out)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2018-05-11 12:51:15 +00:00
|
|
|
func (c *RPCClient) SetReturnValuesLoadConfig(cfg *api.LoadConfig) {
|
|
|
|
c.retValLoadCfg = cfg
|
|
|
|
}
|
|
|
|
|
2018-10-16 15:49:20 +00:00
|
|
|
func (c *RPCClient) FunctionReturnLocations(fnName string) ([]uint64, error) {
|
|
|
|
var out FunctionReturnLocationsOut
|
|
|
|
err := c.call("FunctionReturnLocations", FunctionReturnLocationsIn{fnName}, &out)
|
|
|
|
return out.Addrs, err
|
|
|
|
}
|
|
|
|
|
2018-06-21 11:07:37 +00:00
|
|
|
func (c *RPCClient) IsMulticlient() bool {
|
|
|
|
var out IsMulticlientOut
|
|
|
|
c.call("IsMulticlient", IsMulticlientIn{}, &out)
|
|
|
|
return out.IsMulticlient
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *RPCClient) Disconnect(cont bool) error {
|
|
|
|
if cont {
|
|
|
|
out := new(CommandOut)
|
|
|
|
c.client.Go("RPCServer.Command", &api.DebuggerCommand{Name: api.Continue, ReturnInfoLoadConfig: c.retValLoadCfg}, &out, nil)
|
|
|
|
}
|
|
|
|
return c.client.Close()
|
|
|
|
}
|
|
|
|
|
2019-03-20 17:32:51 +00:00
|
|
|
func (c *RPCClient) ListDynamicLibraries() ([]api.Image, error) {
|
|
|
|
var out ListDynamicLibrariesOut
|
|
|
|
c.call("ListDynamicLibraries", ListDynamicLibrariesIn{}, &out)
|
|
|
|
return out.List, nil
|
|
|
|
}
|
|
|
|
|
2020-09-11 06:21:11 +00:00
|
|
|
func (c *RPCClient) ExamineMemory(address uint64, count int) ([]byte, bool, error) {
|
2020-02-13 17:29:21 +00:00
|
|
|
out := &ExaminedMemoryOut{}
|
|
|
|
|
|
|
|
err := c.call("ExamineMemory", ExamineMemoryIn{Length: count, Address: address}, out)
|
|
|
|
if err != nil {
|
2020-09-11 06:21:11 +00:00
|
|
|
return nil, false, err
|
2020-02-13 17:29:21 +00:00
|
|
|
}
|
2020-09-11 06:21:11 +00:00
|
|
|
return out.Mem, out.IsLittleEndian, nil
|
2020-02-13 17:29:21 +00:00
|
|
|
}
|
|
|
|
|
2020-03-24 16:09:28 +00:00
|
|
|
func (c *RPCClient) StopRecording() error {
|
|
|
|
return c.call("StopRecording", StopRecordingIn{}, &StopRecordingOut{})
|
|
|
|
}
|
|
|
|
|
2021-01-29 21:39:33 +00:00
|
|
|
func (c *RPCClient) CoreDumpStart(dest string) (api.DumpState, error) {
|
|
|
|
out := &DumpStartOut{}
|
|
|
|
err := c.call("DumpStart", DumpStartIn{Destination: dest}, out)
|
|
|
|
return out.State, err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *RPCClient) CoreDumpWait(msec int) api.DumpState {
|
|
|
|
out := &DumpWaitOut{}
|
|
|
|
_ = c.call("DumpWait", DumpWaitIn{Wait: msec}, out)
|
|
|
|
return out.State
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *RPCClient) CoreDumpCancel() error {
|
|
|
|
out := &DumpCancelOut{}
|
|
|
|
return c.call("DumpCancel", DumpCancelIn{}, out)
|
|
|
|
}
|
|
|
|
|
2023-04-24 21:37:31 +00:00
|
|
|
// ListTargets returns the current list of debug targets.
|
|
|
|
func (c *RPCClient) ListTargets() ([]api.Target, error) {
|
|
|
|
out := &ListTargetsOut{}
|
|
|
|
err := c.call("ListTargets", ListTargetsIn{}, out)
|
|
|
|
return out.Targets, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// FollowExec enabled or disabled follow exec mode. When follow exec is
|
|
|
|
// enabled Delve will automatically attach to new subprocesses with a
|
|
|
|
// command line matched by regex, if regex is nil all new subprocesses are
|
|
|
|
// automatically debugged.
|
|
|
|
func (c *RPCClient) FollowExec(v bool, regex string) error {
|
|
|
|
out := &FollowExecOut{}
|
|
|
|
err := c.call("FollowExec", FollowExecIn{Enable: v, Regex: regex}, out)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2023-04-27 20:39:33 +00:00
|
|
|
// FollowExecEnabled returns true if follow exec mode is enabled.
|
2023-04-24 21:37:31 +00:00
|
|
|
func (c *RPCClient) FollowExecEnabled() bool {
|
|
|
|
out := &FollowExecEnabledOut{}
|
|
|
|
_ = c.call("FollowExecEnabled", FollowExecEnabledIn{}, out)
|
|
|
|
return out.Enabled
|
|
|
|
}
|
|
|
|
|
*: 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
|
|
|
func (c *RPCClient) SetDebugInfoDirectories(v []string) error {
|
|
|
|
return c.call("DebugInfoDirectories", DebugInfoDirectoriesIn{Set: true, List: v}, &DebugInfoDirectoriesOut{})
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *RPCClient) GetDebugInfoDirectories() ([]string, error) {
|
|
|
|
out := &DebugInfoDirectoriesOut{}
|
|
|
|
err := c.call("DebugInfoDirectories", DebugInfoDirectoriesIn{Set: false, List: nil}, out)
|
|
|
|
return out.List, err
|
|
|
|
}
|
|
|
|
|
2024-10-31 17:19:08 +00:00
|
|
|
type goListEntry struct {
|
|
|
|
Dir string
|
|
|
|
ImportPath string
|
|
|
|
Name string
|
|
|
|
Module *goListModule
|
|
|
|
}
|
|
|
|
|
|
|
|
type goListModule struct {
|
|
|
|
Path string
|
|
|
|
}
|
|
|
|
|
|
|
|
// MakeGuessSusbtitutePathIn returns a mapping from modules to client
|
|
|
|
// directories using "go list".
|
|
|
|
func MakeGuessSusbtitutePathIn() (*api.GuessSubstitutePathIn, error) {
|
|
|
|
cmd := exec.Command("go", "list", "--json", "all")
|
|
|
|
buf, err := cmd.Output()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
importPathOfMainPackage := ""
|
|
|
|
importPathOfMainPackageOk := true
|
|
|
|
mod2dir := make(map[string]string)
|
|
|
|
d := json.NewDecoder(bytes.NewReader(buf))
|
|
|
|
for d.More() {
|
|
|
|
var e goListEntry
|
|
|
|
err := d.Decode(&e)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if e.Module == nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if !strings.HasPrefix(e.ImportPath, e.Module.Path) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
pkgWithoutModule := e.ImportPath[len(e.Module.Path):]
|
|
|
|
elems := 0
|
|
|
|
for _, c := range pkgWithoutModule {
|
|
|
|
if c == '/' {
|
|
|
|
elems++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
dir := e.Dir
|
|
|
|
for i := 0; i < elems; i++ {
|
|
|
|
dir = filepath.Dir(dir)
|
|
|
|
}
|
|
|
|
if mod2dir[e.Module.Path] != "" && mod2dir[e.Module.Path] != dir {
|
|
|
|
return nil, fmt.Errorf("could not determine path for module %s (got %q and %q)", e.Module.Path, mod2dir[e.Module.Path], dir)
|
|
|
|
}
|
|
|
|
mod2dir[e.Module.Path] = dir
|
|
|
|
if e.Name == "main" {
|
|
|
|
if importPathOfMainPackage != "" && importPathOfMainPackage != e.ImportPath {
|
|
|
|
importPathOfMainPackageOk = false
|
|
|
|
}
|
|
|
|
importPathOfMainPackage = e.ImportPath
|
|
|
|
}
|
|
|
|
}
|
|
|
|
buf, err = exec.Command("go", "env", "GOROOT").Output()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
clientGoroot := strings.TrimSpace(string(buf))
|
|
|
|
if !importPathOfMainPackageOk {
|
|
|
|
// There were multiple main packages
|
|
|
|
importPathOfMainPackage = ""
|
|
|
|
}
|
|
|
|
return &api.GuessSubstitutePathIn{ClientGOROOT: clientGoroot, ImportPathOfMainPackage: importPathOfMainPackage, ClientModuleDirectories: mod2dir}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *RPCClient) GuessSubstitutePath() ([][2]string, error) {
|
|
|
|
in, err := MakeGuessSusbtitutePathIn()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
out := &GuessSubstitutePathOut{}
|
|
|
|
err = c.call("GuessSubstitutePath", GuessSubstitutePathIn{*in}, out)
|
|
|
|
return out.List, err
|
|
|
|
}
|
|
|
|
|
2015-06-21 03:47:44 +00:00
|
|
|
func (c *RPCClient) call(method string, args, reply interface{}) error {
|
|
|
|
return c.client.Call("RPCServer."+method, args, reply)
|
|
|
|
}
|
2019-07-02 17:55:27 +00:00
|
|
|
|
|
|
|
func (c *RPCClient) CallAPI(method string, args, reply interface{}) error {
|
|
|
|
return c.call(method, args, reply)
|
|
|
|
}
|