提交 6ef7aa87 编写于 作者: A aarzilli 提交者: Alessandro Arzilli

service: move some type conversions from service/debugger to rpc pkgs

Move the conversion of some 'proc' types from service/debugger into
service/rpc1 and service/rpc2. The methods of
service/debugger.(*Debugger) are also used by service/dap which
requires these types to be converted differently and converting them
twice is inefficent and doesn't make much sense.

Updates #2161
上级 e8dbbef3
......@@ -7,7 +7,9 @@ import (
"go/printer"
"go/token"
"reflect"
"sort"
"strconv"
"strings"
"github.com/go-delve/delve/pkg/dwarf/godwarf"
"github.com/go-delve/delve/pkg/dwarf/op"
......@@ -109,7 +111,16 @@ func ConvertThread(th proc.Thread) *Thread {
}
}
func prettyTypeName(typ godwarf.Type) string {
// ConvertThreads converts a slice of proc.Thread into a slice of api.Thread.
func ConvertThreads(threads []proc.Thread) []*Thread {
r := make([]*Thread, len(threads))
for i := range threads {
r[i] = ConvertThread(threads[i])
}
return r
}
func PrettyTypeName(typ godwarf.Type) string {
if typ == nil {
return ""
}
......@@ -152,29 +163,14 @@ func ConvertVar(v *proc.Variable) *Variable {
DeclLine: v.DeclLine,
}
r.Type = prettyTypeName(v.DwarfType)
r.RealType = prettyTypeName(v.RealType)
r.Type = PrettyTypeName(v.DwarfType)
r.RealType = PrettyTypeName(v.RealType)
if v.Unreadable != nil {
r.Unreadable = v.Unreadable.Error()
}
if v.Value != nil {
switch v.Kind {
case reflect.Float32:
r.Value = convertFloatValue(v, 32)
case reflect.Float64:
r.Value = convertFloatValue(v, 64)
case reflect.String, reflect.Func:
r.Value = constant.StringVal(v.Value)
default:
if cd := v.ConstDescr(); cd != "" {
r.Value = fmt.Sprintf("%s (%s)", cd, v.Value.String())
} else {
r.Value = v.Value.String()
}
}
}
r.Value = VariableValueAsString(v)
switch v.Kind {
case reflect.Complex64:
......@@ -230,6 +226,38 @@ func ConvertVar(v *proc.Variable) *Variable {
return &r
}
func VariableValueAsString(v *proc.Variable) string {
if v.Value == nil {
return ""
}
switch v.Kind {
case reflect.Float32:
return convertFloatValue(v, 32)
case reflect.Float64:
return convertFloatValue(v, 64)
case reflect.String, reflect.Func:
return constant.StringVal(v.Value)
default:
if cd := v.ConstDescr(); cd != "" {
return fmt.Sprintf("%s (%s)", cd, v.Value.String())
} else {
return v.Value.String()
}
}
}
// ConvertVars converts from []*proc.Variable to []api.Variable.
func ConvertVars(pv []*proc.Variable) []Variable {
if pv == nil {
return nil
}
vars := make([]Variable, 0, len(pv))
for _, v := range pv {
vars = append(vars, *ConvertVar(v))
}
return vars
}
// ConvertFunction converts from gosym.Func to
// api.Function.
func ConvertFunction(fn *proc.Function) *Function {
......@@ -271,6 +299,15 @@ func ConvertGoroutine(g *proc.G) *Goroutine {
}
}
// ConvertGoroutines converts from []*proc.G to []*api.Goroutine.
func ConvertGoroutines(gs []*proc.G) []*Goroutine {
goroutines := make([]*Goroutine, len(gs))
for i := range gs {
goroutines[i] = ConvertGoroutine(gs[i])
}
return goroutines
}
// ConvertLocation converts from proc.Location to api.Location.
func ConvertLocation(loc proc.Location) Location {
return Location{
......@@ -327,29 +364,55 @@ func LoadConfigFromProc(cfg *proc.LoadConfig) *LoadConfig {
}
}
var canonicalRegisterOrder = map[string]int{
// amd64
"rip": 0,
"rsp": 1,
"rax": 2,
"rbx": 3,
"rcx": 4,
"rdx": 5,
// arm64
"pc": 0,
"sp": 1,
}
// ConvertRegisters converts proc.Register to api.Register for a slice.
func ConvertRegisters(in op.DwarfRegisters, arch *proc.Arch, floatingPoint bool) (out []Register) {
if floatingPoint {
in.Reg(^uint64(0)) // force loading all registers
}
func ConvertRegisters(in *op.DwarfRegisters, dwarfRegisterToString func(int, *op.DwarfRegister) (string, bool, string), floatingPoint bool) (out []Register) {
out = make([]Register, 0, in.CurrentSize())
for i := 0; i < in.CurrentSize(); i++ {
reg := in.Reg(uint64(i))
if reg == nil {
continue
}
name, fp, repr := arch.DwarfRegisterToString(i, reg)
name, fp, repr := dwarfRegisterToString(i, reg)
if !floatingPoint && fp {
continue
}
out = append(out, Register{name, repr, i})
}
return
}
// Sort the registers in a canonical order we prefer, this is mostly
// because the DWARF register numbering for AMD64 is weird.
sort.Slice(out, func(i, j int) bool {
a, b := out[i], out[j]
an, aok := canonicalRegisterOrder[strings.ToLower(a.Name)]
bn, bok := canonicalRegisterOrder[strings.ToLower(b.Name)]
// Registers that don't appear in canonicalRegisterOrder sort after registers that do.
if !aok {
an = 1000
}
if !bok {
bn = 1000
}
if an == bn {
// keep registers that don't appear in canonicalRegisterOrder in DWARF order
return a.DwarfNumber < b.DwarfNumber
}
return an < bn
// ConvertCheckpoint converts proc.Chekcpoint to api.Checkpoint.
func ConvertCheckpoint(in proc.Checkpoint) (out Checkpoint) {
return Checkpoint(in)
})
return
}
func ConvertImage(image *proc.Image) Image {
......
package dap
import "github.com/go-delve/delve/pkg/proc"
const startHandle = 1000
// handlesMap maps arbitrary values to unique sequential ids.
......@@ -32,3 +34,27 @@ func (hs *handlesMap) get(handle int) (interface{}, bool) {
v, ok := hs.handleToVal[handle]
return v, ok
}
type variablesHandlesMap struct {
m *handlesMap
}
func newVariablesHandlesMap() *variablesHandlesMap {
return &variablesHandlesMap{newHandlesMap()}
}
func (hs *variablesHandlesMap) create(value *proc.Variable) int {
return hs.m.create(value)
}
func (hs *variablesHandlesMap) get(handle int) (*proc.Variable, bool) {
v, ok := hs.m.get(handle)
if !ok {
return nil, false
}
return v.(*proc.Variable), true
}
func (hs *variablesHandlesMap) reset() {
hs.m.reset()
}
......@@ -12,6 +12,7 @@ import (
"bufio"
"encoding/json"
"fmt"
"go/constant"
"io"
"net"
"os"
......@@ -59,7 +60,7 @@ type Server struct {
stackFrameHandles *handlesMap
// variableHandles maps compound variables to unique references within their stack frame.
// See also comment for convertVariable.
variableHandles *handlesMap
variableHandles *variablesHandlesMap
// args tracks special settings for handling debug session requests.
args launchAttachArgs
}
......@@ -93,7 +94,7 @@ func NewServer(config *service.Config) *Server {
stopChan: make(chan struct{}),
log: logger,
stackFrameHandles: newHandlesMap(),
variableHandles: newHandlesMap(),
variableHandles: newVariablesHandlesMap(),
args: defaultArgs,
}
}
......@@ -593,6 +594,9 @@ func (s *Server) onThreadsRequest(request *dap.ThreadsRequest) {
return
}
s.debugger.LockTarget()
defer s.debugger.UnlockTarget()
threads := make([]dap.Thread, len(gs))
if len(threads) == 0 {
// Depending on the debug session stage, goroutines information
......@@ -604,8 +608,9 @@ func (s *Server) onThreadsRequest(request *dap.ThreadsRequest) {
} else {
for i, g := range gs {
threads[i].Id = g.ID
if loc := g.UserCurrentLoc; loc.Function != nil {
threads[i].Name = loc.Function.Name()
loc := g.UserCurrent()
if loc.Fn != nil {
threads[i].Name = loc.Fn.Name
} else {
threads[i].Name = fmt.Sprintf("%s@%d", loc.File, loc.Line)
}
......@@ -668,17 +673,22 @@ type stackFrame struct {
// This is a mandatory request to support.
func (s *Server) onStackTraceRequest(request *dap.StackTraceRequest) {
goroutineID := request.Arguments.ThreadId
locs, err := s.debugger.Stacktrace(goroutineID, s.args.stackTraceDepth, 0, nil /*skip locals & args*/)
frames, err := s.debugger.Stacktrace(goroutineID, s.args.stackTraceDepth, 0)
if err != nil {
s.sendErrorResponse(request.Request, UnableToProduceStackTrace, "Unable to produce stack trace", err.Error())
return
}
stackFrames := make([]dap.StackFrame, len(locs))
for i, loc := range locs {
stackFrames := make([]dap.StackFrame, len(frames))
for i, frame := range frames {
loc := &frame.Call
uniqueStackFrameID := s.stackFrameHandles.create(stackFrame{goroutineID, i})
stackFrames[i] = dap.StackFrame{Id: uniqueStackFrameID, Line: loc.Line}
stackFrames[i].Name = loc.Function.Name()
if loc.Fn == nil {
stackFrames[i].Name = "???"
} else {
stackFrames[i].Name = loc.Fn.Name
}
if loc.File != "<autogenerated>" {
stackFrames[i].Source = dap.Source{Name: filepath.Base(loc.File), Path: loc.File}
}
......@@ -692,7 +702,7 @@ func (s *Server) onStackTraceRequest(request *dap.StackTraceRequest) {
}
response := &dap.StackTraceResponse{
Response: *newResponse(request.Request),
Body: dap.StackTraceResponseBody{StackFrames: stackFrames, TotalFrames: len(locs)},
Body: dap.StackTraceResponseBody{StackFrames: stackFrames, TotalFrames: len(frames)},
}
s.send(response)
}
......@@ -706,25 +716,26 @@ func (s *Server) onScopesRequest(request *dap.ScopesRequest) {
return
}
scope := api.EvalScope{GoroutineID: sf.(stackFrame).goroutineID, Frame: sf.(stackFrame).frameIndex}
goid := sf.(stackFrame).goroutineID
frame := sf.(stackFrame).frameIndex
// TODO(polina): Support setting config via launch/attach args
cfg := proc.LoadConfig{FollowPointers: true, MaxVariableRecurse: 1, MaxStringLen: 64, MaxArrayValues: 64, MaxStructFields: -1}
// Retrieve arguments
args, err := s.debugger.FunctionArguments(scope, cfg)
args, err := s.debugger.FunctionArguments(goid, frame, 0, cfg)
if err != nil {
s.sendErrorResponse(request.Request, UnableToListArgs, "Unable to list args", err.Error())
return
}
argScope := api.Variable{Name: "Arguments", Children: args}
argScope := &proc.Variable{Name: "Arguments", Children: slicePtrVarToSliceVar(args)}
// Retrieve local variables
locals, err := s.debugger.LocalVariables(scope, cfg)
locals, err := s.debugger.LocalVariables(goid, frame, 0, cfg)
if err != nil {
s.sendErrorResponse(request.Request, UnableToListLocals, "Unable to list local vars", err.Error())
return
}
locScope := api.Variable{Name: "Locals", Children: locals}
locScope := &proc.Variable{Name: "Locals", Children: slicePtrVarToSliceVar(locals)}
// TODO(polina): Annotate shadowed variables
// TODO(polina): Retrieve global variables
......@@ -740,15 +751,22 @@ func (s *Server) onScopesRequest(request *dap.ScopesRequest) {
s.send(response)
}
func slicePtrVarToSliceVar(vars []*proc.Variable) []proc.Variable {
r := make([]proc.Variable, len(vars))
for i := range vars {
r[i] = *vars[i]
}
return r
}
// onVariablesRequest handles 'variables' requests.
// This is a mandatory request to support.
func (s *Server) onVariablesRequest(request *dap.VariablesRequest) {
variable, ok := s.variableHandles.get(request.Arguments.VariablesReference)
v, ok := s.variableHandles.get(request.Arguments.VariablesReference)
if !ok {
s.sendErrorResponse(request.Request, UnableToLookupVariable, "Unable to lookup variable", fmt.Sprintf("unknown reference %d", request.Arguments.VariablesReference))
return
}
v := variable.(api.Variable)
children := make([]dap.Variable, 0)
// TODO(polina): check and handle if variable loaded incompletely
// https://github.com/go-delve/delve/blob/master/Documentation/api/ClientHowto.md#looking-into-variables
......@@ -759,8 +777,8 @@ func (s *Server) onVariablesRequest(request *dap.VariablesRequest) {
// A map will have twice as many children as there are key-value elements.
kvIndex := i / 2
// Process children in pairs: even indices are map keys, odd indices are values.
key, keyref := s.convertVariable(v.Children[i])
val, valref := s.convertVariable(v.Children[i+1])
key, keyref := s.convertVariable(&v.Children[i])
val, valref := s.convertVariable(&v.Children[i+1])
// If key or value or both are scalars, we can use
// a single variable to represet key:value format.
// Otherwise, we must return separate variables for both.
......@@ -792,7 +810,8 @@ func (s *Server) onVariablesRequest(request *dap.VariablesRequest) {
}
case reflect.Slice, reflect.Array:
children = make([]dap.Variable, len(v.Children))
for i, c := range v.Children {
for i := range v.Children {
c := &v.Children[i]
value, varref := s.convertVariable(c)
children[i] = dap.Variable{
Name: fmt.Sprintf("[%d]", i),
......@@ -802,7 +821,8 @@ func (s *Server) onVariablesRequest(request *dap.VariablesRequest) {
}
default:
children = make([]dap.Variable, len(v.Children))
for i, c := range v.Children {
for i := range v.Children {
c := &v.Children[i]
value, variablesReference := s.convertVariable(c)
children[i] = dap.Variable{
Name: c.Name,
......@@ -827,11 +847,12 @@ func (s *Server) onVariablesRequest(request *dap.VariablesRequest) {
// can be issued to get the elements of the compound variable. As a custom, a zero
// reference, reminiscent of a zero pointer, is used to indicate that a scalar
// variable cannot be "dereferenced" to get its elements (as there are none).
func (s *Server) convertVariable(v api.Variable) (value string, variablesReference int) {
if v.Unreadable != "" {
value = fmt.Sprintf("unreadable <%s>", v.Unreadable)
func (s *Server) convertVariable(v *proc.Variable) (value string, variablesReference int) {
if v.Unreadable != nil {
value = fmt.Sprintf("unreadable <%v>", v.Unreadable)
return
}
typeName := api.PrettyTypeName(v.DwarfType)
switch v.Kind {
case reflect.UnsafePointer:
if len(v.Children) == 0 {
......@@ -840,51 +861,51 @@ func (s *Server) convertVariable(v api.Variable) (value string, variablesReferen
value = fmt.Sprintf("unsafe.Pointer(%#x)", v.Children[0].Addr)
}
case reflect.Ptr:
if v.Type == "" || len(v.Children) == 0 {
if v.DwarfType == nil || len(v.Children) == 0 {
value = "nil"
} else if v.Children[0].Addr == 0 {
value = "nil <" + v.Type + ">"
} else if v.Children[0].Type == "void" {
value = "nil <" + typeName + ">"
} else if v.Children[0].Kind == reflect.Invalid {
value = "void"
} else {
value = fmt.Sprintf("<%s>(%#x)", v.Type, v.Children[0].Addr)
value = fmt.Sprintf("<%s>(%#x)", typeName, v.Children[0].Addr)
variablesReference = s.variableHandles.create(v)
}
case reflect.Array:
value = "<" + v.Type + ">"
value = "<" + typeName + ">"
if len(v.Children) > 0 {
variablesReference = s.variableHandles.create(v)
}
case reflect.Slice:
if v.Base == 0 {
value = "nil <" + v.Type + ">"
value = "nil <" + typeName + ">"
} else {
value = fmt.Sprintf("<%s> (length: %d, cap: %d)", v.Type, v.Len, v.Cap)
value = fmt.Sprintf("<%s> (length: %d, cap: %d)", typeName, v.Len, v.Cap)
if len(v.Children) > 0 {
variablesReference = s.variableHandles.create(v)
}
}
case reflect.Map:
if v.Base == 0 {
value = "nil <" + v.Type + ">"
value = "nil <" + typeName + ">"
} else {
value = fmt.Sprintf("<%s> (length: %d)", v.Type, v.Len)
value = fmt.Sprintf("<%s> (length: %d)", typeName, v.Len)
if len(v.Children) > 0 {
variablesReference = s.variableHandles.create(v)
}
}
case reflect.String:
lenNotLoaded := v.Len - int64(len(v.Value))
vvalue := v.Value
vvalue := constant.StringVal(v.Value)
lenNotLoaded := v.Len - int64(len(vvalue))
if lenNotLoaded > 0 {
vvalue += fmt.Sprintf("...+%d more", lenNotLoaded)
}
value = fmt.Sprintf("%q", vvalue)
case reflect.Chan:
if len(v.Children) == 0 {
value = "nil <" + v.Type + ">"
value = "nil <" + typeName + ">"
} else {
value = "<" + v.Type + ">"
value = "<" + typeName + ">"
variablesReference = s.variableHandles.create(v)
}
case reflect.Interface:
......@@ -896,16 +917,31 @@ func (s *Server) convertVariable(v api.Variable) (value string, variablesReferen
// happens to contain 0.
value = "nil"
} else if len(v.Children) == 0 || v.Children[0].Kind == reflect.Invalid && v.Children[0].Addr == 0 {
value = "nil <" + v.Type + ">"
value = "nil <" + typeName + ">"
} else {
value = "<" + v.Type + ">"
value = "<" + typeName + ">"
variablesReference = s.variableHandles.create(v)
}
case reflect.Complex64, reflect.Complex128:
v.Children = make([]proc.Variable, 2)
v.Children[0].Name = "real"
v.Children[0].Value = constant.Real(v.Value)
v.Children[1].Name = "imaginary"
v.Children[1].Value = constant.Imag(v.Value)
if v.Kind == reflect.Complex64 {
v.Children[0].Kind = reflect.Float32
v.Children[1].Kind = reflect.Float32
} else {
v.Children[0].Kind = reflect.Float64
v.Children[1].Kind = reflect.Float64
}
fallthrough
default: // Struct, complex, scalar
if v.Value != "" {
value = v.Value
vvalue := api.VariableValueAsString(v)
if vvalue != "" {
value = vvalue
} else {
value = "<" + v.Type + ">"
value = "<" + typeName + ">"
}
if len(v.Children) > 0 {
variablesReference = s.variableHandles.create(v)
......
......@@ -552,7 +552,7 @@ func (d *Debugger) state(retLoadCfg *proc.LoadConfig) (*api.DebuggerState, error
th := api.ConvertThread(thread)
if retLoadCfg != nil {
th.ReturnValues = convertVars(thread.Common().ReturnValues(*retLoadCfg))
th.ReturnValues = api.ConvertVars(thread.Common().ReturnValues(*retLoadCfg))
}
state.Threads = append(state.Threads, th)
......@@ -825,7 +825,7 @@ func (d *Debugger) findBreakpointByName(name string) *api.Breakpoint {
}
// Threads returns the threads of the target process.
func (d *Debugger) Threads() ([]*api.Thread, error) {
func (d *Debugger) Threads() ([]proc.Thread, error) {
d.targetMutex.Lock()
defer d.targetMutex.Unlock()
......@@ -833,15 +833,11 @@ func (d *Debugger) Threads() ([]*api.Thread, error) {
return nil, err
}
threads := []*api.Thread{}
for _, th := range d.target.ThreadList() {
threads = append(threads, api.ConvertThread(th))
}
return threads, nil
return d.target.ThreadList(), nil
}
// FindThread returns the thread for the given 'id'.
func (d *Debugger) FindThread(id int) (*api.Thread, error) {
func (d *Debugger) FindThread(id int) (proc.Thread, error) {
d.targetMutex.Lock()
defer d.targetMutex.Unlock()
......@@ -851,7 +847,7 @@ func (d *Debugger) FindThread(id int) (*api.Thread, error) {
for _, th := range d.target.ThreadList() {
if th.ThreadID() == id {
return api.ConvertThread(th), nil
return th, nil
}
}
return nil, nil
......@@ -1079,12 +1075,12 @@ func (d *Debugger) collectBreakpointInformation(state *api.DebuggerState) error
}
if bp.LoadArgs != nil {
if vars, err := s.FunctionArguments(*api.LoadConfigToProc(bp.LoadArgs)); err == nil {
bpi.Arguments = convertVars(vars)
bpi.Arguments = api.ConvertVars(vars)
}
}
if bp.LoadLocals != nil {
if locals, err := s.LocalVariables(*api.LoadConfigToProc(bp.LoadLocals)); err == nil {
bpi.Locals = convertVars(locals)
bpi.Locals = api.ConvertVars(locals)
}
}
}
......@@ -1157,7 +1153,7 @@ func (d *Debugger) Types(filter string) ([]string, error) {
// PackageVariables returns a list of package variables for the thread,
// optionally regexp filtered using regexp described in 'filter'.
func (d *Debugger) PackageVariables(threadID int, filter string, cfg proc.LoadConfig) ([]api.Variable, error) {
func (d *Debugger) PackageVariables(threadID int, filter string, cfg proc.LoadConfig) ([]*proc.Variable, error) {
d.targetMutex.Lock()
defer d.targetMutex.Unlock()
......@@ -1166,7 +1162,6 @@ func (d *Debugger) PackageVariables(threadID int, filter string, cfg proc.LoadCo
return nil, fmt.Errorf("invalid filter argument: %s", err.Error())
}
vars := []api.Variable{}
thread, found := d.target.FindThread(threadID)
if !found {
return nil, fmt.Errorf("couldn't find thread %d", threadID)
......@@ -1179,146 +1174,93 @@ func (d *Debugger) PackageVariables(threadID int, filter string, cfg proc.LoadCo
if err != nil {
return nil, err
}
for _, v := range pv {
if regex.Match([]byte(v.Name)) {
vars = append(vars, *api.ConvertVar(v))
pvr := pv[:0]
for i := range pv {
if regex.Match([]byte(pv[i].Name)) {
pvr = append(pvr, pv[i])
}
}
return vars, err
return pvr, nil
}
// Registers returns string representation of the CPU registers.
func (d *Debugger) Registers(threadID int, scope *api.EvalScope, floatingPoint bool) (api.Registers, error) {
// ThreadRegisters returns registers of the specified thread.
func (d *Debugger) ThreadRegisters(threadID int, floatingPoint bool) (*op.DwarfRegisters, error) {
d.targetMutex.Lock()
defer d.targetMutex.Unlock()
var dregs op.DwarfRegisters
if scope != nil {
s, err := proc.ConvertEvalScope(d.target, scope.GoroutineID, scope.Frame, scope.DeferredCall)
if err != nil {
return nil, err
}
dregs = s.Regs
} else {
thread, found := d.target.FindThread(threadID)
if !found {
return nil, fmt.Errorf("couldn't find thread %d", threadID)
}
regs, err := thread.Registers()
if err != nil {
return nil, err
}
dregs = d.target.BinInfo().Arch.RegistersToDwarfRegisters(0, regs)
thread, found := d.target.FindThread(threadID)
if !found {
return nil, fmt.Errorf("couldn't find thread %d", threadID)
}
r := api.ConvertRegisters(dregs, d.target.BinInfo().Arch, floatingPoint)
if floatingPoint && dregs.FloatLoadError != nil {
return nil, dregs.FloatLoadError
regs, err := thread.Registers()
if err != nil {
return nil, err
}
// Sort the registers in a canonical order we prefer, this is mostly
// because the DWARF register numbering for AMD64 is weird.
sort.Slice(r, func(i, j int) bool {
a, b := r[i], r[j]
an, aok := canonicalRegisterOrder[strings.ToLower(a.Name)]
bn, bok := canonicalRegisterOrder[strings.ToLower(b.Name)]
// Registers that don't appear in canonicalRegisterOrder sort after registers that do.
if !aok {
an = 1000
}
if !bok {
bn = 1000
}
if an == bn {
// keep registers that don't appear in canonicalRegisterOrder in DWARF order
return a.DwarfNumber < b.DwarfNumber
}
return an < bn
})
return r, nil
dregs := d.target.BinInfo().Arch.RegistersToDwarfRegisters(0, regs)
return &dregs, nil
}
var canonicalRegisterOrder = map[string]int{
// amd64
"rip": 0,
"rsp": 1,
"rax": 2,
"rbx": 3,
"rcx": 4,
"rdx": 5,
// ScopeRegisters returns registers for the specified scope.
func (d *Debugger) ScopeRegisters(goid, frame, deferredCall int, floatingPoint bool) (*op.DwarfRegisters, error) {
d.targetMutex.Lock()
defer d.targetMutex.Unlock()
// arm64
"pc": 0,
"sp": 1,
s, err := proc.ConvertEvalScope(d.target, goid, frame, deferredCall)
if err != nil {
return nil, err
}
return &s.Regs, nil
}
func convertVars(pv []*proc.Variable) []api.Variable {
if pv == nil {
return nil
}
vars := make([]api.Variable, 0, len(pv))
for _, v := range pv {
vars = append(vars, *api.ConvertVar(v))
}
return vars
// DwarfRegisterToString returns the name and value representation of the given register.
func (d *Debugger) DwarfRegisterToString(i int, reg *op.DwarfRegister) (string, bool, string) {
return d.target.BinInfo().Arch.DwarfRegisterToString(i, reg)
}
// LocalVariables returns a list of the local variables.
func (d *Debugger) LocalVariables(scope api.EvalScope, cfg proc.LoadConfig) ([]api.Variable, error) {
func (d *Debugger) LocalVariables(goid, frame, deferredCall int, cfg proc.LoadConfig) ([]*proc.Variable, error) {
d.targetMutex.Lock()
defer d.targetMutex.Unlock()
s, err := proc.ConvertEvalScope(d.target, scope.GoroutineID, scope.Frame, scope.DeferredCall)
if err != nil {
return nil, err
}
pv, err := s.LocalVariables(cfg)
s, err := proc.ConvertEvalScope(d.target, goid, frame, deferredCall)
if err != nil {
return nil, err
}
return convertVars(pv), err
return s.LocalVariables(cfg)
}
// FunctionArguments returns the arguments to the current function.
func (d *Debugger) FunctionArguments(scope api.EvalScope, cfg proc.LoadConfig) ([]api.Variable, error) {
func (d *Debugger) FunctionArguments(goid, frame, deferredCall int, cfg proc.LoadConfig) ([]*proc.Variable, error) {
d.targetMutex.Lock()
defer d.targetMutex.Unlock()
s, err := proc.ConvertEvalScope(d.target, scope.GoroutineID, scope.Frame, scope.DeferredCall)
if err != nil {
return nil, err
}
pv, err := s.FunctionArguments(cfg)
s, err := proc.ConvertEvalScope(d.target, goid, frame, deferredCall)
if err != nil {
return nil, err
}
return convertVars(pv), nil
return s.FunctionArguments(cfg)
}
// EvalVariableInScope will attempt to evaluate the variable represented by 'symbol'
// in the scope provided.
func (d *Debugger) EvalVariableInScope(scope api.EvalScope, symbol string, cfg proc.LoadConfig) (*api.Variable, error) {
func (d *Debugger) EvalVariableInScope(goid, frame, deferredCall int, symbol string, cfg proc.LoadConfig) (*proc.Variable, error) {
d.targetMutex.Lock()
defer d.targetMutex.Unlock()
s, err := proc.ConvertEvalScope(d.target, scope.GoroutineID, scope.Frame, scope.DeferredCall)
s, err := proc.ConvertEvalScope(d.target, goid, frame, deferredCall)
if err != nil {
return nil, err
}
v, err := s.EvalVariable(symbol, cfg)
if err != nil {
return nil, err
}
return api.ConvertVar(v), err
return s.EvalVariable(symbol, cfg)
}
// SetVariableInScope will set the value of the variable represented by
// 'symbol' to the value given, in the given scope.
func (d *Debugger) SetVariableInScope(scope api.EvalScope, symbol, value string) error {
func (d *Debugger) SetVariableInScope(goid, frame, deferredCall int, symbol, value string) error {
d.targetMutex.Lock()
defer d.targetMutex.Unlock()
s, err := proc.ConvertEvalScope(d.target, scope.GoroutineID, scope.Frame, scope.DeferredCall)
s, err := proc.ConvertEvalScope(d.target, goid, frame, deferredCall)
if err != nil {
return err
}
......@@ -1326,25 +1268,16 @@ func (d *Debugger) SetVariableInScope(scope api.EvalScope, symbol, value string)
}
// Goroutines will return a list of goroutines in the target process.
func (d *Debugger) Goroutines(start, count int) ([]*api.Goroutine, int, error) {
func (d *Debugger) Goroutines(start, count int) ([]*proc.G, int, error) {
d.targetMutex.Lock()
defer d.targetMutex.Unlock()
goroutines := []*api.Goroutine{}
gs, nextg, err := proc.GoroutinesInfo(d.target, start, count)
if err != nil {
return nil, 0, err
}
for _, g := range gs {
goroutines = append(goroutines, api.ConvertGoroutine(g))
}
return goroutines, nextg, err
return proc.GoroutinesInfo(d.target, start, count)
}
// Stacktrace returns a list of Stackframes for the given goroutine. The
// length of the returned list will be min(stack_len, depth).
// If 'full' is true, then local vars, function args, etc will be returned as well.
func (d *Debugger) Stacktrace(goroutineID, depth int, opts api.StacktraceOptions, cfg *proc.LoadConfig) ([]api.Stackframe, error) {
func (d *Debugger) Stacktrace(goroutineID, depth int, opts api.StacktraceOptions) ([]proc.Stackframe, error) {
d.targetMutex.Lock()
defer d.targetMutex.Unlock()
......@@ -1352,23 +1285,16 @@ func (d *Debugger) Stacktrace(goroutineID, depth int, opts api.StacktraceOptions
return nil, err
}
var rawlocs []proc.Stackframe
g, err := proc.FindGoroutine(d.target, goroutineID)
if err != nil {
return nil, err
}
if g == nil {
rawlocs, err = proc.ThreadStacktrace(d.target.CurrentThread(), depth)
return proc.ThreadStacktrace(d.target.CurrentThread(), depth)
} else {
rawlocs, err = g.Stacktrace(depth, proc.StacktraceOptions(opts))
}
if err != nil {
return nil, err
return g.Stacktrace(depth, proc.StacktraceOptions(opts))
}
return d.convertStacktrace(rawlocs, cfg)
}
// Ancestors returns the stacktraces for the ancestors of a goroutine.
......@@ -1413,6 +1339,15 @@ func (d *Debugger) Ancestors(goroutineID, numAncestors, depth int) ([]api.Ancest
return r, nil
}
// ConvertStacktrace converts a slice of proc.Stackframe into a slice of
// api.Stackframe, loading local variables and arguments of each frame if
// cfg is not nil.
func (d *Debugger) ConvertStacktrace(rawlocs []proc.Stackframe, cfg *proc.LoadConfig) ([]api.Stackframe, error) {
d.targetMutex.Lock()
defer d.targetMutex.Unlock()
return d.convertStacktrace(rawlocs, cfg)
}
func (d *Debugger) convertStacktrace(rawlocs []proc.Stackframe, cfg *proc.LoadConfig) ([]api.Stackframe, error) {
locations := make([]api.Stackframe, 0, len(rawlocs))
for i := range rawlocs {
......@@ -1441,8 +1376,8 @@ func (d *Debugger) convertStacktrace(rawlocs []proc.Stackframe, cfg *proc.LoadCo
return nil, err
}
frame.Locals = convertVars(locals)
frame.Arguments = convertVars(arguments)
frame.Locals = api.ConvertVars(locals)
frame.Arguments = api.ConvertVars(arguments)
}
locations = append(locations, frame)
}
......@@ -1481,7 +1416,7 @@ func (d *Debugger) convertDefers(defers []*proc.Defer) []api.Defer {
}
// FindLocation will find the location specified by 'locStr'.
func (d *Debugger) FindLocation(scope api.EvalScope, locStr string, includeNonExecutableLines bool) ([]api.Location, error) {
func (d *Debugger) FindLocation(goid, frame, deferredCall int, locStr string, includeNonExecutableLines bool) ([]api.Location, error) {
d.targetMutex.Lock()
defer d.targetMutex.Unlock()
......@@ -1494,7 +1429,7 @@ func (d *Debugger) FindLocation(scope api.EvalScope, locStr string, includeNonEx
return nil, err
}
s, _ := proc.ConvertEvalScope(d.target, scope.GoroutineID, scope.Frame, scope.DeferredCall)
s, _ := proc.ConvertEvalScope(d.target, goid, frame, deferredCall)
locs, err := loc.Find(d.target, d.processArgs, s, locStr, includeNonExecutableLines)
for i := range locs {
......@@ -1511,7 +1446,7 @@ func (d *Debugger) FindLocation(scope api.EvalScope, locStr string, includeNonEx
// Disassemble code between startPC and endPC.
// if endPC == 0 it will find the function containing startPC and disassemble the whole function.
func (d *Debugger) Disassemble(goroutineID int, addr1, addr2 uint64, flavour api.AssemblyFlavour) (api.AsmInstructions, error) {
func (d *Debugger) Disassemble(goroutineID int, addr1, addr2 uint64) ([]proc.AsmInstruction, error) {
d.targetMutex.Lock()
defer d.targetMutex.Unlock()
......@@ -1539,17 +1474,13 @@ func (d *Debugger) Disassemble(goroutineID int, addr1, addr2 uint64, flavour api
}
regs, _ := curthread.Registers()
insts, err := proc.Disassemble(curthread, regs, d.target.Breakpoints(), d.target.BinInfo(), addr1, addr2)
if err != nil {
return nil, err
}
disass := make(api.AsmInstructions, len(insts))
for i := range insts {
disass[i] = api.ConvertAsmInstruction(insts[i], insts[i].Text(proc.AssemblyFlavour(flavour), d.target.BinInfo()))
}
return proc.Disassemble(curthread, regs, d.target.Breakpoints(), d.target.BinInfo(), addr1, addr2)
}
return disass, nil
func (d *Debugger) AsmInstructionText(inst *proc.AsmInstruction, flavour proc.AssemblyFlavour) string {
d.targetMutex.Lock()
defer d.targetMutex.Unlock()
return inst.Text(flavour, d.target.BinInfo())
}
// Recorded returns true if the target is a recording.
......@@ -1567,18 +1498,10 @@ func (d *Debugger) Checkpoint(where string) (int, error) {
}
// Checkpoints will return a list of checkpoints.
func (d *Debugger) Checkpoints() ([]api.Checkpoint, error) {
func (d *Debugger) Checkpoints() ([]proc.Checkpoint, error) {
d.targetMutex.Lock()
defer d.targetMutex.Unlock()
cps, err := d.target.Checkpoints()
if err != nil {
return nil, err
}
r := make([]api.Checkpoint, len(cps))
for i := range cps {
r[i] = api.ConvertCheckpoint(cps[i])
}
return r, nil
return d.target.Checkpoints()
}
// ClearCheckpoint will clear the checkpoint of the given ID.
......@@ -1589,16 +1512,11 @@ func (d *Debugger) ClearCheckpoint(id int) error {
}
// ListDynamicLibraries returns a list of loaded dynamic libraries.
func (d *Debugger) ListDynamicLibraries() []api.Image {
func (d *Debugger) ListDynamicLibraries() []*proc.Image {
d.targetMutex.Lock()
defer d.targetMutex.Unlock()
bi := d.target.BinInfo()
r := make([]api.Image, 0, len(bi.Images)-1)
// skips the first image because it's the executable file
for i := range bi.Images[1:] {
r = append(r, api.ConvertImage(bi.Images[i+1]))
}
return r
return d.target.BinInfo().Images[1:] // skips the first image because it's the executable file
}
// ExamineMemory returns the raw memory stored at the given address.
......@@ -1652,30 +1570,10 @@ func (d *Debugger) GetVersion(out *api.GetVersionOut) error {
// 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.
func (d *Debugger) ListPackagesBuildInfo(includeFiles bool) []api.PackageBuildInfo {
func (d *Debugger) ListPackagesBuildInfo(includeFiles bool) []*proc.PackageBuildInfo {
d.targetMutex.Lock()
defer d.targetMutex.Unlock()
pkgs := d.target.BinInfo().ListPackagesBuildInfo(includeFiles)
r := 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)
r = append(r, api.PackageBuildInfo{
ImportPath: pkg.ImportPath,
DirectoryPath: pkg.DirectoryPath,
Files: files,
})
}
return r
return d.target.BinInfo().ListPackagesBuildInfo(includeFiles)
}
// StopRecording stops a recording (if one is in progress)
......@@ -1688,6 +1586,16 @@ func (d *Debugger) StopRecording() error {
return d.stopRecording()
}
// LockTarget acquires the target mutex.
func (d *Debugger) LockTarget() {
d.targetMutex.Lock()
}
// UnlockTarget releases the target mutex.
func (d *Debugger) UnlockTarget() {
d.targetMutex.Unlock()
}
func go11DecodeErrorCheck(err error) error {
if _, isdecodeerr := err.(dwarf.DecodeError); !isdecodeerr {
return err
......
......@@ -93,12 +93,12 @@ func (s *RPCServer) StacktraceGoroutine(args *StacktraceGoroutineArgs, locations
if args.Full {
loadcfg = &defaultLoadConfig
}
locs, err := s.debugger.Stacktrace(args.Id, args.Depth, 0, loadcfg)
locs, err := s.debugger.Stacktrace(args.Id, args.Depth, 0)
if err != nil {
return err
}
*locations = locs
return nil
*locations, err = s.debugger.ConvertStacktrace(locs, loadcfg)
return err
}
func (s *RPCServer) ListBreakpoints(arg interface{}, breakpoints *[]*api.Breakpoint) error {
......@@ -147,8 +147,14 @@ func (s *RPCServer) AmendBreakpoint(amend *api.Breakpoint, unused *int) error {
}
func (s *RPCServer) ListThreads(arg interface{}, threads *[]*api.Thread) (err error) {
*threads, err = s.debugger.Threads()
return err
pthreads, err := s.debugger.Threads()
if err != nil {
return err
}
s.debugger.LockTarget()
defer s.debugger.UnlockTarget()
*threads = api.ConvertThreads(pthreads)
return nil
}
func (s *RPCServer) GetThread(id int, thread *api.Thread) error {
......@@ -159,7 +165,9 @@ func (s *RPCServer) GetThread(id int, thread *api.Thread) error {
if t == nil {
return fmt.Errorf("no thread with id %d", id)
}
*thread = *t
s.debugger.LockTarget()
defer s.debugger.UnlockTarget()
*thread = *api.ConvertThread(t)
return nil
}
......@@ -178,7 +186,7 @@ func (s *RPCServer) ListPackageVars(filter string, variables *[]api.Variable) er
if err != nil {
return err
}
*variables = vars
*variables = api.ConvertVars(vars)
return nil
}
......@@ -200,7 +208,7 @@ func (s *RPCServer) ListThreadPackageVars(args *ThreadListArgs, variables *[]api
if err != nil {
return err
}
*variables = vars
*variables = api.ConvertVars(vars)
return nil
}
......@@ -210,29 +218,30 @@ func (s *RPCServer) ListRegisters(arg interface{}, registers *string) error {
return err
}
regs, err := s.debugger.Registers(state.CurrentThread.ID, nil, false)
dregs, err := s.debugger.ThreadRegisters(state.CurrentThread.ID, false)
if err != nil {
return err
}
regs := api.Registers(api.ConvertRegisters(dregs, s.debugger.DwarfRegisterToString, false))
*registers = regs.String()
return nil
}
func (s *RPCServer) ListLocalVars(scope api.EvalScope, variables *[]api.Variable) error {
vars, err := s.debugger.LocalVariables(scope, defaultLoadConfig)
vars, err := s.debugger.LocalVariables(scope.GoroutineID, scope.Frame, scope.DeferredCall, defaultLoadConfig)
if err != nil {
return err
}
*variables = vars
*variables = api.ConvertVars(vars)
return nil
}
func (s *RPCServer) ListFunctionArgs(scope api.EvalScope, variables *[]api.Variable) error {
vars, err := s.debugger.FunctionArguments(scope, defaultLoadConfig)
vars, err := s.debugger.FunctionArguments(scope.GoroutineID, scope.Frame, scope.DeferredCall, defaultLoadConfig)
if err != nil {
return err
}
*variables = vars
*variables = api.ConvertVars(vars)
return nil
}
......@@ -242,11 +251,11 @@ type EvalSymbolArgs struct {
}
func (s *RPCServer) EvalSymbol(args EvalSymbolArgs, variable *api.Variable) error {
v, err := s.debugger.EvalVariableInScope(args.Scope, args.Symbol, defaultLoadConfig)
v, err := s.debugger.EvalVariableInScope(args.Scope.GoroutineID, args.Scope.Frame, args.Scope.DeferredCall, args.Symbol, defaultLoadConfig)
if err != nil {
return err
}
*variable = *v
*variable = *api.ConvertVar(v)
return nil
}
......@@ -258,7 +267,7 @@ type SetSymbolArgs struct {
func (s *RPCServer) SetSymbol(args SetSymbolArgs, unused *int) error {
*unused = 0
return s.debugger.SetVariableInScope(args.Scope, args.Symbol, args.Value)
return s.debugger.SetVariableInScope(args.Scope.GoroutineID, args.Scope.Frame, args.Scope.DeferredCall, args.Symbol, args.Value)
}
func (s *RPCServer) ListSources(filter string, sources *[]string) error {
......@@ -293,7 +302,9 @@ func (s *RPCServer) ListGoroutines(arg interface{}, goroutines *[]*api.Goroutine
if err != nil {
return err
}
*goroutines = gs
s.debugger.LockTarget()
s.debugger.UnlockTarget()
*goroutines = api.ConvertGoroutines(gs)
return nil
}
......@@ -311,7 +322,7 @@ type FindLocationArgs struct {
func (c *RPCServer) FindLocation(args FindLocationArgs, answer *[]api.Location) error {
var err error
*answer, err = c.debugger.FindLocation(args.Scope, args.Loc, false)
*answer, err = c.debugger.FindLocation(args.Scope.GoroutineID, args.Scope.Frame, args.Scope.DeferredCall, args.Loc, false)
return err
}
......@@ -323,6 +334,13 @@ type DisassembleRequest struct {
func (c *RPCServer) Disassemble(args DisassembleRequest, answer *api.AsmInstructions) error {
var err error
*answer, err = c.debugger.Disassemble(args.Scope.GoroutineID, args.StartPC, args.EndPC, args.Flavour)
return err
insts, err := c.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], c.debugger.AsmInstructionText(&insts[i], proc.AssemblyFlavour(args.Flavour)))
}
return nil
}
......@@ -3,8 +3,11 @@ package rpc2
import (
"errors"
"fmt"
"sort"
"time"
"github.com/go-delve/delve/pkg/dwarf/op"
"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"
......@@ -189,7 +192,11 @@ func (s *RPCServer) Stacktrace(arg StacktraceIn, out *StacktraceOut) error {
arg.Opts |= api.StacktraceReadDefers
}
var err error
out.Locations, err = s.debugger.Stacktrace(arg.Id, arg.Depth, arg.Opts, api.LoadConfigToProc(cfg))
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))
return err
}
......@@ -320,8 +327,14 @@ type ListThreadsOut struct {
// ListThreads lists all threads.
func (s *RPCServer) ListThreads(arg ListThreadsIn, out *ListThreadsOut) (err error) {
out.Threads, err = s.debugger.Threads()
return err
threads, err := s.debugger.Threads()
if err != nil {
return err
}
s.debugger.LockTarget()
defer s.debugger.UnlockTarget()
out.Threads = api.ConvertThreads(threads)
return nil
}
type GetThreadIn struct {
......@@ -341,7 +354,9 @@ func (s *RPCServer) GetThread(arg GetThreadIn, out *GetThreadOut) error {
if t == nil {
return fmt.Errorf("no thread with id %d", arg.Id)
}
out.Thread = t
s.debugger.LockTarget()
defer s.debugger.UnlockTarget()
out.Thread = api.ConvertThread(t)
return nil
}
......@@ -370,7 +385,7 @@ func (s *RPCServer) ListPackageVars(arg ListPackageVarsIn, out *ListPackageVarsO
if err != nil {
return err
}
out.Variables = vars
out.Variables = api.ConvertVars(vars)
return nil
}
......@@ -397,11 +412,18 @@ func (s *RPCServer) ListRegisters(arg ListRegistersIn, out *ListRegistersOut) er
arg.ThreadID = state.CurrentThread.ID
}
regs, err := s.debugger.Registers(arg.ThreadID, arg.Scope, arg.IncludeFp)
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)
}
if err != nil {
return err
}
out.Regs = regs
out.Regs = api.ConvertRegisters(regs, s.debugger.DwarfRegisterToString, arg.IncludeFp)
out.Registers = out.Regs.String()
return nil
......@@ -418,11 +440,11 @@ type ListLocalVarsOut struct {
// ListLocalVars lists all local variables in scope.
func (s *RPCServer) ListLocalVars(arg ListLocalVarsIn, out *ListLocalVarsOut) error {
vars, err := s.debugger.LocalVariables(arg.Scope, *api.LoadConfigToProc(&arg.Cfg))
vars, err := s.debugger.LocalVariables(arg.Scope.GoroutineID, arg.Scope.Frame, arg.Scope.DeferredCall, *api.LoadConfigToProc(&arg.Cfg))
if err != nil {
return err
}
out.Variables = vars
out.Variables = api.ConvertVars(vars)
return nil
}
......@@ -437,11 +459,11 @@ type ListFunctionArgsOut struct {
// ListFunctionArgs lists all arguments to the current function
func (s *RPCServer) ListFunctionArgs(arg ListFunctionArgsIn, out *ListFunctionArgsOut) error {
vars, err := s.debugger.FunctionArguments(arg.Scope, *api.LoadConfigToProc(&arg.Cfg))
vars, err := s.debugger.FunctionArguments(arg.Scope.GoroutineID, arg.Scope.Frame, arg.Scope.DeferredCall, *api.LoadConfigToProc(&arg.Cfg))
if err != nil {
return err
}
out.Args = vars
out.Args = api.ConvertVars(vars)
return nil
}
......@@ -464,11 +486,11 @@ func (s *RPCServer) Eval(arg EvalIn, out *EvalOut) error {
if cfg == nil {
cfg = &api.LoadConfig{FollowPointers: true, MaxVariableRecurse: 1, MaxStringLen: 64, MaxArrayValues: 64, MaxStructFields: -1}
}
v, err := s.debugger.EvalVariableInScope(arg.Scope, arg.Expr, *api.LoadConfigToProc(cfg))
v, err := s.debugger.EvalVariableInScope(arg.Scope.GoroutineID, arg.Scope.Frame, arg.Scope.DeferredCall, arg.Expr, *api.LoadConfigToProc(cfg))
if err != nil {
return err
}
out.Variable = v
out.Variable = api.ConvertVar(v)
return nil
}
......@@ -484,7 +506,7 @@ type SetOut struct {
// Set sets the value of a variable. Only numerical types and
// pointers are currently supported.
func (s *RPCServer) Set(arg SetIn, out *SetOut) error {
return s.debugger.SetVariableInScope(arg.Scope, arg.Symbol, arg.Value)
return s.debugger.SetVariableInScope(arg.Scope.GoroutineID, arg.Scope.Frame, arg.Scope.DeferredCall, arg.Symbol, arg.Value)
}
type ListSourcesIn struct {
......@@ -562,7 +584,9 @@ func (s *RPCServer) ListGoroutines(arg ListGoroutinesIn, out *ListGoroutinesOut)
if err != nil {
return err
}
out.Goroutines = gs
s.debugger.LockTarget()
defer s.debugger.UnlockTarget()
out.Goroutines = api.ConvertGoroutines(gs)
out.Nextg = nextg
return nil
}
......@@ -607,7 +631,7 @@ type FindLocationOut struct {
// NOTE: this function does not actually set breakpoints.
func (c *RPCServer) FindLocation(arg FindLocationIn, out *FindLocationOut) error {
var err error
out.Locations, err = c.debugger.FindLocation(arg.Scope, arg.Loc, arg.IncludeNonExecutableLines)
out.Locations, err = c.debugger.FindLocation(arg.Scope.GoroutineID, arg.Scope.Frame, arg.Scope.DeferredCall, arg.Loc, arg.IncludeNonExecutableLines)
return err
}
......@@ -630,8 +654,15 @@ type DisassembleOut struct {
// 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.
func (c *RPCServer) Disassemble(arg DisassembleIn, out *DisassembleOut) error {
var err error
out.Disassemble, err = c.debugger.Disassemble(arg.Scope.GoroutineID, arg.StartPC, arg.EndPC, arg.Flavour)
return err
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
}
type RecordedIn struct {
......@@ -670,8 +701,15 @@ type ListCheckpointsOut struct {
func (s *RPCServer) ListCheckpoints(arg ListCheckpointsIn, out *ListCheckpointsOut) error {
var err error
out.Checkpoints, err = s.debugger.Checkpoints()
return err
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
}
type ClearCheckpointIn struct {
......@@ -740,7 +778,11 @@ type ListDynamicLibrariesOut struct {
}
func (s *RPCServer) ListDynamicLibraries(in ListDynamicLibrariesIn, out *ListDynamicLibrariesOut) error {
out.List = s.debugger.ListDynamicLibraries()
imgs := s.debugger.ListDynamicLibraries()
out.List = make([]api.Image, 0, len(imgs))
for i := range imgs {
out.List[i] = api.ConvertImage(imgs[i])
}
return nil
}
......@@ -760,7 +802,26 @@ type ListPackagesBuildInfoOut struct {
// 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 {
out.List = s.debugger.ListPackagesBuildInfo(in.IncludeFiles)
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,
})
}
return nil
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册