From 5b9f65dac28575a74daee46cb7724b5c62b68caa Mon Sep 17 00:00:00 2001 From: Alessandro Arzilli Date: Tue, 16 Aug 2022 18:31:11 +0200 Subject: [PATCH] *: switch to int64 for goroutine IDs (#3110) Go 1.20 switched to uint64 to represent goroutine IDs, we can't actually follow suit because we have allowed clients to use -1 to refer to the currently selected goroutine, however we should at least switch to int64 and also update the rtype check to accept the 1.20 type. --- _scripts/rtype-out.txt | 2 +- _scripts/rtype.go | 18 +++++++-- pkg/proc/breakpoints.go | 12 +++--- pkg/proc/eval.go | 2 +- pkg/proc/goroutine_cache.go | 4 +- pkg/proc/proc_test.go | 14 +++---- pkg/proc/target.go | 4 +- pkg/proc/variables.go | 20 +++++++--- pkg/terminal/command.go | 8 ++-- service/api/conversions.go | 4 +- service/api/types.go | 8 ++-- service/client.go | 8 ++-- service/dap/server.go | 63 ++++++++++++++++--------------- service/debugger/debugger.go | 32 ++++++++-------- service/rpc1/client.go | 2 +- service/rpc1/server.go | 2 +- service/rpc2/client.go | 8 ++-- service/rpc2/server.go | 4 +- service/test/integration1_test.go | 6 +-- 19 files changed, 122 insertions(+), 99 deletions(-) diff --git a/_scripts/rtype-out.txt b/_scripts/rtype-out.txt index b463d3c7..dbe473a0 100644 --- a/_scripts/rtype-out.txt +++ b/_scripts/rtype-out.txt @@ -21,7 +21,7 @@ type eface struct { type g struct { sched gobuf - goid int64 + goid int64|uint64 gopc uintptr startpc uintptr waitsince int64 diff --git a/_scripts/rtype.go b/_scripts/rtype.go index 88f38ce0..bb8076bc 100644 --- a/_scripts/rtype.go +++ b/_scripts/rtype.go @@ -50,8 +50,12 @@ // it must have type T). // // -// Anywhere a type is required anytype can be used to specify that we don't -// care about its type. +// Anywhere a type is required the following expressions can be used: +// +// - any builtin type +// - a type defined in the runtime package, without the 'runtime.' prefix +// - anytype to match all possible types +// - an expression of the form T1|T2 where both T1 and T2 can be arbitrary type expressions package main @@ -379,7 +383,7 @@ func processProcVariableUses(decl ast.Node, tinfo *types.Info, procVarIdent *ast } var methodName string if isParseG { - if xident, _ := fncall.Fun.(*ast.Ident); xident != nil && xident.Name == "loadInt64Maybe" { + if xident, _ := fncall.Fun.(*ast.Ident); xident != nil && (xident.Name == "loadInt64Maybe" || xident.Name == "loadUint64Maybe") { methodName = "loadInt64Maybe" } } @@ -630,6 +634,14 @@ func matchType(typ types.Type, T string) bool { if T == "anytype" { return true } + if strings.Index(T, "|") > 0 { + for _, t1 := range strings.Split(T, "|") { + if typeStr(typ) == t1 { + return true + } + } + return false + } return typeStr(typ) == T } diff --git a/pkg/proc/breakpoints.go b/pkg/proc/breakpoints.go index 2385aac0..2b596921 100644 --- a/pkg/proc/breakpoints.go +++ b/pkg/proc/breakpoints.go @@ -264,7 +264,7 @@ func (bpstate *BreakpointState) checkCond(tgt *Target, breaklet *Breaklet, threa switch breaklet.Kind { case UserBreakpoint: - var goroutineID int + var goroutineID int64 lbp := bpstate.Breakpoint.Logical if lbp != nil { if g, err := GetG(thread); err == nil { @@ -320,7 +320,7 @@ func (bpstate *BreakpointState) checkCond(tgt *Target, breaklet *Breaklet, threa } // checkHitCond evaluates bp's hit condition on thread. -func checkHitCond(lbp *LogicalBreakpoint, goroutineID int) bool { +func checkHitCond(lbp *LogicalBreakpoint, goroutineID int64) bool { if lbp == nil || lbp.HitCond == nil { return true } @@ -659,7 +659,7 @@ func (t *Target) setBreakpointInternal(logicalID int, addr uint64, kind Breakpoi lbp := bpmap.Logical[logicalID] if lbp == nil { lbp = &LogicalBreakpoint{LogicalID: logicalID} - lbp.HitCount = make(map[int]uint64) + lbp.HitCount = make(map[int64]uint64) lbp.Enabled = true bpmap.Logical[logicalID] = lbp } @@ -974,9 +974,9 @@ type LogicalBreakpoint struct { LoadArgs *LoadConfig LoadLocals *LoadConfig - HitCount map[int]uint64 // Number of times a breakpoint has been reached in a certain goroutine - TotalHitCount uint64 // Number of times a breakpoint has been reached - HitCondPerG bool // Use per goroutine hitcount as HitCond operand, instead of total hitcount + HitCount map[int64]uint64 // Number of times a breakpoint has been reached in a certain goroutine + TotalHitCount uint64 // Number of times a breakpoint has been reached + HitCondPerG bool // Use per goroutine hitcount as HitCond operand, instead of total hitcount // HitCond: if not nil the breakpoint will be triggered only if the evaluated HitCond returns // true with the TotalHitCount. diff --git a/pkg/proc/eval.go b/pkg/proc/eval.go index 12e13942..020ee83f 100644 --- a/pkg/proc/eval.go +++ b/pkg/proc/eval.go @@ -73,7 +73,7 @@ const ( // ConvertEvalScope returns a new EvalScope in the context of the // specified goroutine ID and stack frame. // If deferCall is > 0 the eval scope will be relative to the specified deferred call. -func ConvertEvalScope(dbp *Target, gid, frame, deferCall int) (*EvalScope, error) { +func ConvertEvalScope(dbp *Target, gid int64, frame, deferCall int) (*EvalScope, error) { if _, err := dbp.Valid(); err != nil { return nil, err } diff --git a/pkg/proc/goroutine_cache.go b/pkg/proc/goroutine_cache.go index 3e34fad9..70e7f61c 100644 --- a/pkg/proc/goroutine_cache.go +++ b/pkg/proc/goroutine_cache.go @@ -1,7 +1,7 @@ package proc type goroutineCache struct { - partialGCache map[int]*G + partialGCache map[int64]*G allGCache []*G allgentryAddr, allglenAddr uint64 @@ -41,7 +41,7 @@ func (gcache *goroutineCache) getRuntimeAllg(bi *BinaryInfo, mem MemoryReadWrite func (gcache *goroutineCache) addGoroutine(g *G) { if gcache.partialGCache == nil { - gcache.partialGCache = make(map[int]*G) + gcache.partialGCache = make(map[int64]*G) } gcache.partialGCache[g.ID] = g } diff --git a/pkg/proc/proc_test.go b/pkg/proc/proc_test.go index 5ae78aa5..57a3015c 100644 --- a/pkg/proc/proc_test.go +++ b/pkg/proc/proc_test.go @@ -1504,7 +1504,7 @@ func TestBreakpointCounts(t *testing.T) { func TestHardcodedBreakpointCounts(t *testing.T) { skipOn(t, "broken", "freebsd") withTestProcess("hcbpcountstest", t, func(p *proc.Target, fixture protest.Fixture) { - counts := map[int]int{} + counts := map[int64]int{} for { if err := p.Continue(); err != nil { if _, exited := err.(proc.ErrProcessExited); exited { @@ -2556,7 +2556,7 @@ func TestStepConcurrentPtr(t *testing.T) { } } - kvals := map[int]int64{} + kvals := map[int64]int64{} count := 0 for { err := p.Continue() @@ -2920,7 +2920,7 @@ func TestNextInDeferReturn(t *testing.T) { }) } -func getg(goid int, gs []*proc.G) *proc.G { +func getg(goid int64, gs []*proc.G) *proc.G { for _, g := range gs { if g.ID == goid { return g @@ -3432,7 +3432,7 @@ func TestCgoStacktrace(t *testing.T) { []string{"C.helloworld_pt4", "C.helloworld_pt3", "main.helloWorldS", "main.helloWorld", "C.helloworld_pt2", "C.helloworld", "main.main"}, []string{"main.helloWorld2", "C.helloworld_pt4", "C.helloworld_pt3", "main.helloWorldS", "main.helloWorld", "C.helloworld_pt2", "C.helloworld", "main.main"}} - var gid int + var gid int64 frameOffs := map[string]int64{} framePointerOffs := map[string]int64{} @@ -4449,7 +4449,7 @@ func TestIssue1469(t *testing.T) { setFileBreakpoint(p, t, fixture.Source, 13) assertNoError(p.Continue(), t, "Continue()") - gid2thread := make(map[int][]proc.Thread) + gid2thread := make(map[int64][]proc.Thread) for _, thread := range p.ThreadList() { g, _ := proc.GetG(thread) if g == nil { @@ -4582,7 +4582,7 @@ func TestAncestors(t *testing.T) { }) } -func testCallConcurrentCheckReturns(p *proc.Target, t *testing.T, gid1, gid2 int) int { +func testCallConcurrentCheckReturns(p *proc.Target, t *testing.T, gid1, gid2 int64) int { found := 0 for _, thread := range p.ThreadList() { g, _ := proc.GetG(thread) @@ -5138,7 +5138,7 @@ func TestStepOutPreservesGoroutine(t *testing.T) { logState := func() { g := p.SelectedGoroutine() - var goid int = -42 + var goid int64 = -42 if g != nil { goid = g.ID } diff --git a/pkg/proc/target.go b/pkg/proc/target.go index 5dc5d2ef..6d8ea2e4 100644 --- a/pkg/proc/target.go +++ b/pkg/proc/target.go @@ -59,7 +59,7 @@ type Target struct { selectedGoroutine *G // fncallForG stores a mapping of current active function calls. - fncallForG map[int]*callInjection + fncallForG map[int64]*callInjection asyncPreemptChanged bool // runtime/debug.asyncpreemptoff was changed asyncPreemptOff int64 // cached value of runtime/debug.asyncpreemptoff @@ -194,7 +194,7 @@ func NewTarget(p ProcessInternal, pid int, currentThread Thread, cfg NewTargetCo t := &Target{ Process: p, proc: p, - fncallForG: make(map[int]*callInjection), + fncallForG: make(map[int64]*callInjection), StopReason: cfg.StopReason, currentThread: currentThread, CanDump: cfg.CanDump, diff --git a/pkg/proc/variables.go b/pkg/proc/variables.go index 37d0213e..b46fdad0 100644 --- a/pkg/proc/variables.go +++ b/pkg/proc/variables.go @@ -196,7 +196,7 @@ const ( // G represents a runtime G (goroutine) structure (at least the // fields that Delve is interested in). type G struct { - ID int // Goroutine ID + ID int64 // Goroutine ID PC uint64 // PC of goroutine when it was parked. SP uint64 // SP of goroutine when it was parked. BP uint64 // BP of goroutine when it was parked (go >= 1.7). @@ -312,7 +312,7 @@ func GoroutinesInfo(dbp *Target, start, count int) ([]*G, int, error) { } var ( - threadg = map[int]*G{} + threadg = map[int64]*G{} allg []*G ) @@ -367,7 +367,7 @@ func GoroutinesInfo(dbp *Target, start, count int) ([]*G, int, error) { // FindGoroutine returns a G struct representing the goroutine // specified by `gid`. -func FindGoroutine(dbp *Target, gid int) (*G, error) { +func FindGoroutine(dbp *Target, gid int64) (*G, error) { if selg := dbp.SelectedGoroutine(); (gid == -1) || (selg != nil && selg.ID == gid) || (selg == nil && gid == 0) { // Return the currently selected goroutine in the following circumstances: // @@ -886,7 +886,17 @@ func (v *Variable) parseG() (*G, error) { return n } - id := loadInt64Maybe("goid") // +rtype int64 + loadUint64Maybe := func(name string) uint64 { + vv := v.loadFieldNamed(name) + if vv == nil { + unreadable = true + return 0 + } + n, _ := constant.Uint64Val(vv.Value) + return n + } + + id := loadUint64Maybe("goid") // +rtype int64|uint64 gopc := loadInt64Maybe("gopc") // +rtype uintptr startpc := loadInt64Maybe("startpc") // +rtype uintptr waitSince := loadInt64Maybe("waitsince") // +rtype int64 @@ -919,7 +929,7 @@ func (v *Variable) parseG() (*G, error) { v.Name = "runtime.curg" g := &G{ - ID: int(id), + ID: int64(id), GoPC: uint64(gopc), StartPC: uint64(startpc), PC: uint64(pc), diff --git a/pkg/terminal/command.go b/pkg/terminal/command.go index fdc71b86..9ed5d528 100644 --- a/pkg/terminal/command.go +++ b/pkg/terminal/command.go @@ -886,7 +886,7 @@ func (c *Commands) goroutines(t *Term, ctx callContext, argstr string) error { return nil } -func selectedGID(state *api.DebuggerState) int { +func selectedGID(state *api.DebuggerState) int64 { if state.SelectedGoroutine == nil { return 0 } @@ -908,7 +908,7 @@ func (c *Commands) goroutine(t *Term, ctx callContext, argstr string) error { if args[0] == "" { return printscope(t) } - gid, err := strconv.Atoi(argstr) + gid, err := strconv.ParseInt(argstr, 10, 64) if err != nil { return err } @@ -927,7 +927,7 @@ func (c *Commands) goroutine(t *Term, ctx callContext, argstr string) error { } var err error - ctx.Scope.GoroutineID, err = strconv.Atoi(args[0]) + ctx.Scope.GoroutineID, err = strconv.ParseInt(args[0], 10, 64) if err != nil { return err } @@ -2586,7 +2586,7 @@ func printcontextThread(t *Term, th *api.Thread) { return } - if hitCount, ok := th.Breakpoint.HitCount[strconv.Itoa(th.GoroutineID)]; ok { + if hitCount, ok := th.Breakpoint.HitCount[strconv.FormatInt(th.GoroutineID, 10)]; ok { fmt.Fprintf(t.stdout, "> %s%s(%s) %s:%d (hits goroutine(%d):%d total:%d) (PC: %#v)\n", bpname, fn.Name(), diff --git a/service/api/conversions.go b/service/api/conversions.go index f16a2645..fa5848b0 100644 --- a/service/api/conversions.go +++ b/service/api/conversions.go @@ -38,7 +38,7 @@ func ConvertLogicalBreakpoint(lbp *proc.LogicalBreakpoint) *Breakpoint { b.HitCount = map[string]uint64{} for idx := range lbp.HitCount { - b.HitCount[strconv.Itoa(idx)] = lbp.HitCount[idx] + b.HitCount[strconv.FormatInt(idx, 10)] = lbp.HitCount[idx] } if lbp.HitCond != nil { @@ -95,7 +95,7 @@ func ConvertThread(th proc.Thread, bp *Breakpoint) *Thread { file string line int pc uint64 - gid int + gid int64 ) loc, err := th.Location() diff --git a/service/api/types.go b/service/api/types.go index 852a3e7e..913ff4ea 100644 --- a/service/api/types.go +++ b/service/api/types.go @@ -168,7 +168,7 @@ type Thread struct { Function *Function `json:"function,omitempty"` // ID of the goroutine running on this thread - GoroutineID int `json:"goroutineID"` + GoroutineID int64 `json:"goroutineID"` // Breakpoint this thread is stopped at Breakpoint *Breakpoint `json:"breakPoint,omitempty"` @@ -358,7 +358,7 @@ type LoadConfig struct { // internal G structure. type Goroutine struct { // ID is a unique identifier for the goroutine. - ID int `json:"id"` + ID int64 `json:"id"` // Current location of the goroutine CurrentLoc Location `json:"currentLoc"` // Current location of the goroutine, excluding calls inside runtime @@ -391,7 +391,7 @@ type DebuggerCommand struct { ThreadID int `json:"threadID,omitempty"` // GoroutineID is used to specify which thread to use with the SwitchGoroutine // and Call commands. - GoroutineID int `json:"goroutineID,omitempty"` + GoroutineID int64 `json:"goroutineID,omitempty"` // When ReturnInfoLoadConfig is not nil it will be used to load the value // of any return variables. ReturnInfoLoadConfig *LoadConfig @@ -426,7 +426,7 @@ type BreakpointInfo struct { // EvalScope is the scope a command should // be evaluated in. Describes the goroutine and frame number. type EvalScope struct { - GoroutineID int + GoroutineID int64 Frame int DeferredCall int // when DeferredCall is n > 0 this eval scope is relative to the n-th deferred call in the current frame } diff --git a/service/client.go b/service/client.go index bfb35967..cccddd50 100644 --- a/service/client.go +++ b/service/client.go @@ -50,7 +50,7 @@ type Client interface { // ReverseStepOut continues backward to the calle rof the current function. ReverseStepOut() (*api.DebuggerState, error) // Call resumes process execution while making a function call. - Call(goroutineID int, expr string, unsafe bool) (*api.DebuggerState, error) + Call(goroutineID int64, expr string, unsafe bool) (*api.DebuggerState, error) // StepInstruction will step a single cpu instruction. StepInstruction() (*api.DebuggerState, error) @@ -59,7 +59,7 @@ type Client interface { // SwitchThread switches the current thread context. SwitchThread(threadID int) (*api.DebuggerState, error) // SwitchGoroutine switches the current goroutine (and the current thread as well) - SwitchGoroutine(goroutineID int) (*api.DebuggerState, error) + SwitchGoroutine(goroutineID int64) (*api.DebuggerState, error) // Halt suspends the process. Halt() (*api.DebuggerState, error) @@ -121,10 +121,10 @@ type Client interface { ListGoroutinesWithFilter(start, count int, filters []api.ListGoroutinesFilter, group *api.GoroutineGroupingOptions) ([]*api.Goroutine, []api.GoroutineGroup, int, bool, error) // Stacktrace returns stacktrace - Stacktrace(goroutineID int, depth int, opts api.StacktraceOptions, cfg *api.LoadConfig) ([]api.Stackframe, error) + Stacktrace(goroutineID int64, depth int, opts api.StacktraceOptions, cfg *api.LoadConfig) ([]api.Stackframe, error) // Ancestors returns ancestor stacktraces - Ancestors(goroutineID int, numAncestors int, depth int) ([]api.Ancestor, error) + Ancestors(goroutineID int64, numAncestors int, depth int) ([]api.Ancestor, error) // AttachedToExistingProcess returns whether we attached to a running process or not AttachedToExistingProcess() bool diff --git a/service/dap/server.go b/service/dap/server.go index 1f2991d4..a282f964 100644 --- a/service/dap/server.go +++ b/service/dap/server.go @@ -1689,7 +1689,7 @@ func (s *Session) onThreadsRequest(request *dap.ThreadsRequest) { // so no need to include them here. loc := g.UserCurrent() threads[i].Name = fmt.Sprintf("%s[Go %d] %s%s", selected, g.ID, fnName(&loc), thread) - threads[i].Id = g.ID + threads[i].Id = int(g.ID) } } @@ -1830,7 +1830,7 @@ func (s *Session) sendStepResponse(threadId int, message dap.Message) { s.send(message) } -func stoppedGoroutineID(state *api.DebuggerState) (id int) { +func stoppedGoroutineID(state *api.DebuggerState) (id int64) { if state.SelectedGoroutine != nil { id = state.SelectedGoroutine.ID } else if state.CurrentThread != nil { @@ -1841,7 +1841,7 @@ func stoppedGoroutineID(state *api.DebuggerState) (id int) { // stoppedOnBreakpointGoroutineID gets the goroutine id of the first goroutine // that is stopped on a real breakpoint, starting with the selected goroutine. -func (s *Session) stoppedOnBreakpointGoroutineID(state *api.DebuggerState) (int, *api.Breakpoint) { +func (s *Session) stoppedOnBreakpointGoroutineID(state *api.DebuggerState) (int64, *api.Breakpoint) { // Use the first goroutine that is stopped on a breakpoint. gs := s.stoppedGs(state) if len(gs) == 0 { @@ -1871,7 +1871,7 @@ func (s *Session) stoppedOnBreakpointGoroutineID(state *api.DebuggerState) (int, // due to an error, so the server is ready to receive new requests. func (s *Session) stepUntilStopAndNotify(command string, threadId int, granularity dap.SteppingGranularity, allowNextStateChange chan struct{}) { defer closeIfOpen(allowNextStateChange) - _, err := s.debugger.Command(&api.DebuggerCommand{Name: api.SwitchGoroutine, GoroutineID: threadId}, nil) + _, err := s.debugger.Command(&api.DebuggerCommand{Name: api.SwitchGoroutine, GoroutineID: int64(threadId)}, nil) if err != nil { s.config.log.Errorf("Error switching goroutines while stepping: %v", err) // If we encounter an error, we will have to send a stopped event @@ -1881,7 +1881,7 @@ func (s *Session) stepUntilStopAndNotify(command string, threadId int, granulari if state, err := s.debugger.State(false); err != nil { s.config.log.Errorf("Error retrieving state: %e", err) } else { - stopped.Body.ThreadId = stoppedGoroutineID(state) + stopped.Body.ThreadId = int(stoppedGoroutineID(state)) } stopped.Body.Reason = "error" stopped.Body.Text = err.Error() @@ -1951,7 +1951,7 @@ func (s *Session) onStackTraceRequest(request *dap.StackTraceRequest) { // Since the backend doesn't support paging, we load all frames up to // the requested depth and then slice them here per // `supportsDelayedStackTraceLoading` capability. - frames, err := s.debugger.Stacktrace(goroutineID, start+levels-1, 0) + frames, err := s.debugger.Stacktrace(int64(goroutineID), start+levels-1, 0) if err != nil { s.sendErrorResponse(request.Request, UnableToProduceStackTrace, "Unable to produce stack trace", err.Error()) return @@ -1959,7 +1959,7 @@ func (s *Session) onStackTraceRequest(request *dap.StackTraceRequest) { // Determine if the goroutine is a system goroutine. isSystemGoroutine := true - if g, _ := s.debugger.FindGoroutine(goroutineID); g != nil { + if g, _ := s.debugger.FindGoroutine(int64(goroutineID)); g != nil { isSystemGoroutine = g.System(s.debugger.Target()) } @@ -2012,7 +2012,7 @@ func (s *Session) onScopesRequest(request *dap.ScopesRequest) { frame := sf.(stackFrame).frameIndex // Check if the function is optimized. - fn, err := s.debugger.Function(goid, frame, 0, DefaultLoadConfig) + fn, err := s.debugger.Function(int64(goid), frame, 0, DefaultLoadConfig) if fn == nil || err != nil { s.sendErrorResponse(request.Request, UnableToListArgs, "Unable to find enclosing function", err.Error()) return @@ -2022,14 +2022,14 @@ func (s *Session) onScopesRequest(request *dap.ScopesRequest) { suffix = " (warning: optimized function)" } // Retrieve arguments - args, err := s.debugger.FunctionArguments(goid, frame, 0, DefaultLoadConfig) + args, err := s.debugger.FunctionArguments(int64(goid), frame, 0, DefaultLoadConfig) if err != nil { s.sendErrorResponse(request.Request, UnableToListArgs, "Unable to list args", err.Error()) return } // Retrieve local variables - locals, err := s.debugger.LocalVariables(goid, frame, 0, DefaultLoadConfig) + locals, err := s.debugger.LocalVariables(int64(goid), frame, 0, DefaultLoadConfig) if err != nil { s.sendErrorResponse(request.Request, UnableToListLocals, "Unable to list locals", err.Error()) return @@ -2075,7 +2075,7 @@ func (s *Session) onScopesRequest(request *dap.ScopesRequest) { if s.args.ShowRegisters { // Retrieve registers - regs, err := s.debugger.ScopeRegisters(goid, frame, 0, false) + regs, err := s.debugger.ScopeRegisters(int64(goid), frame, 0, false) if err != nil { s.sendErrorResponse(request.Request, UnableToListRegisters, "Unable to list registers", err.Error()) return @@ -2661,7 +2661,7 @@ func (s *Session) onEvaluateRequest(request *dap.EvaluateRequest) { } } } else { // {expression} - exprVar, err := s.debugger.EvalVariableInScope(goid, frame, 0, expr, DefaultLoadConfig) + exprVar, err := s.debugger.EvalVariableInScope(int64(goid), frame, 0, expr, DefaultLoadConfig) if err != nil { s.sendErrorResponseWithOpts(request.Request, UnableToEvaluateExpression, "Unable to evaluate expression", err.Error(), showErrorToUser) return @@ -2675,7 +2675,7 @@ func (s *Session) onEvaluateRequest(request *dap.EvaluateRequest) { // Reload the string value with a bigger limit. loadCfg := DefaultLoadConfig loadCfg.MaxStringLen = maxSingleStringLen - if v, err := s.debugger.EvalVariableInScope(goid, frame, 0, request.Arguments.Expression, loadCfg); err != nil { + if v, err := s.debugger.EvalVariableInScope(int64(goid), frame, 0, request.Arguments.Expression, loadCfg); err != nil { s.config.log.Debugf("Failed to load more for %v: %v", request.Arguments.Expression, err) } else { exprVar = v @@ -2725,7 +2725,7 @@ func (s *Session) doCall(goid, frame int, expr string) (*api.DebuggerState, []*p ReturnInfoLoadConfig: api.LoadConfigFromProc(&loadCfg), Expr: expr, UnsafeCall: false, - GoroutineID: goid, + GoroutineID: int64(goid), }, nil) if processExited(state, err) { e := &dap.TerminatedEvent{Event: *newEvent("terminated")} @@ -2794,7 +2794,7 @@ func (s *Session) doCall(goid, frame int, expr string) (*api.DebuggerState, []*p func (s *Session) sendStoppedEvent(state *api.DebuggerState) { stopped := &dap.StoppedEvent{Event: *newEvent("stopped")} stopped.Body.AllThreadsStopped = true - stopped.Body.ThreadId = stoppedGoroutineID(state) + stopped.Body.ThreadId = int(stoppedGoroutineID(state)) stopped.Body.Reason = s.debugger.StopReason().String() s.send(stopped) } @@ -2868,7 +2868,7 @@ func (s *Session) onSetVariableRequest(request *dap.SetVariableRequest) { // trying to update is valid and accessible from the top most frame & the // current goroutine. goid, frame := -1, 0 - evaluated, err := s.debugger.EvalVariableInScope(goid, frame, 0, evaluateName, DefaultLoadConfig) + evaluated, err := s.debugger.EvalVariableInScope(int64(goid), frame, 0, evaluateName, DefaultLoadConfig) if err != nil { s.sendErrorResponse(request.Request, UnableToSetVariable, "Unable to lookup variable", err.Error()) return @@ -2911,7 +2911,7 @@ func (s *Session) onSetVariableRequest(request *dap.SetVariableRequest) { return } } else { - if err := s.debugger.SetVariableInScope(goid, frame, 0, evaluateName, arg.Value); err != nil { + if err := s.debugger.SetVariableInScope(int64(goid), frame, 0, evaluateName, arg.Value); err != nil { s.sendErrorResponse(request.Request, UnableToSetVariable, "Unable to set variable", err.Error()) return } @@ -3189,7 +3189,7 @@ func (s *Session) onCancelRequest(request *dap.CancelRequest) { // onExceptionInfoRequest handles 'exceptionInfo' requests. // Capability 'supportsExceptionInfoRequest' is set in 'initialize' response. func (s *Session) onExceptionInfoRequest(request *dap.ExceptionInfoRequest) { - goroutineID := request.Arguments.ThreadId + goroutineID := int64(request.Arguments.ThreadId) var body dap.ExceptionInfoResponseBody // Get the goroutine and the current state. g, err := s.debugger.FindGoroutine(goroutineID) @@ -3273,7 +3273,7 @@ func (s *Session) onExceptionInfoRequest(request *dap.ExceptionInfoRequest) { s.send(response) } -func (s *Session) stacktrace(goroutineID int, g *proc.G) (string, error) { +func (s *Session) stacktrace(goroutineID int64, g *proc.G) (string, error) { frames, err := s.debugger.Stacktrace(goroutineID, s.args.StackTraceDepth, 0) if err != nil { return "", err @@ -3298,15 +3298,15 @@ func (s *Session) stacktrace(goroutineID int, g *proc.G) (string, error) { return buf.String(), nil } -func (s *Session) throwReason(goroutineID int) (string, error) { +func (s *Session) throwReason(goroutineID int64) (string, error) { return s.getExprString("s", goroutineID, 0) } -func (s *Session) panicReason(goroutineID int) (string, error) { +func (s *Session) panicReason(goroutineID int64) (string, error) { return s.getExprString("(*msgs).arg.(data)", goroutineID, 0) } -func (s *Session) getExprString(expr string, goroutineID, frame int) (string, error) { +func (s *Session) getExprString(expr string, goroutineID int64, frame int) (string, error) { exprVar, err := s.debugger.EvalVariableInScope(goroutineID, frame, 0, expr, DefaultLoadConfig) if err != nil { return "", err @@ -3495,7 +3495,7 @@ func (s *Session) runUntilStopAndNotify(command string, allowNextStateChange cha state.NextInProgress = false } } - stopped.Body.ThreadId = stoppedGoroutineID(state) + stopped.Body.ThreadId = int(stoppedGoroutineID(state)) switch stopReason { case proc.StopNextFinished: @@ -3508,17 +3508,18 @@ func (s *Session) runUntilStopAndNotify(command string, allowNextStateChange cha stopped.Body.Reason = "data breakpoint" default: stopped.Body.Reason = "breakpoint" - var bp *api.Breakpoint - if stopped.Body.ThreadId, bp = s.stoppedOnBreakpointGoroutineID(state); bp != nil { + goid, bp := s.stoppedOnBreakpointGoroutineID(state) + stopped.Body.ThreadId = int(goid) + if bp != nil { switch bp.Name { case proc.FatalThrow: stopped.Body.Reason = "exception" stopped.Body.Description = "fatal error" - stopped.Body.Text, _ = s.throwReason(stopped.Body.ThreadId) + stopped.Body.Text, _ = s.throwReason(int64(stopped.Body.ThreadId)) case proc.UnrecoveredPanic: stopped.Body.Reason = "exception" stopped.Body.Description = "panic" - stopped.Body.Text, _ = s.panicReason(stopped.Body.ThreadId) + stopped.Body.Text, _ = s.panicReason(int64(stopped.Body.ThreadId)) } if strings.HasPrefix(bp.Name, functionBpPrefix) { stopped.Body.Reason = "function breakpoint" @@ -3558,7 +3559,7 @@ func (s *Session) runUntilStopAndNotify(command string, allowNextStateChange cha state, err := s.debugger.State( /*nowait*/ true) if err == nil { - stopped.Body.ThreadId = stoppedGoroutineID(state) + stopped.Body.ThreadId = int(stoppedGoroutineID(state)) } } @@ -3632,7 +3633,7 @@ func (s *Session) handleLogPoints(state *api.DebuggerState) { } } -func (s *Session) stoppedGs(state *api.DebuggerState) (gs []int) { +func (s *Session) stoppedGs(state *api.DebuggerState) (gs []int64) { // Check the current thread first. There may be no selected goroutine. if state.CurrentThread.Breakpoint != nil && !state.CurrentThread.Breakpoint.Tracepoint { gs = append(gs, state.CurrentThread.GoroutineID) @@ -3662,7 +3663,7 @@ func (s *Session) stoppedGs(state *api.DebuggerState) (gs []int) { return gs } -func (s *Session) logBreakpointMessage(bp *api.Breakpoint, goid int) bool { +func (s *Session) logBreakpointMessage(bp *api.Breakpoint, goid int64) bool { if !bp.Tracepoint { return false } @@ -3683,7 +3684,7 @@ func (s *Session) logBreakpointMessage(bp *api.Breakpoint, goid int) bool { return true } -func (msg *logMessage) evaluate(s *Session, goid int) string { +func (msg *logMessage) evaluate(s *Session, goid int64) string { evaluated := make([]interface{}, len(msg.args)) for i := range msg.args { exprVar, err := s.debugger.EvalVariableInScope(goid, 0, 0, msg.args[i], DefaultLoadConfig) diff --git a/service/debugger/debugger.go b/service/debugger/debugger.go index 319aa29a..869bdd95 100644 --- a/service/debugger/debugger.go +++ b/service/debugger/debugger.go @@ -516,7 +516,7 @@ func (d *Debugger) Restart(rerecord bool, pos string, resetArgs bool, newArgs [] } if len(oldBp.File) > 0 { oldBp.TotalHitCount = 0 - oldBp.HitCount = make(map[int]uint64) + oldBp.HitCount = make(map[int64]uint64) err := d.createPhysicalBreakpoints(oldBp) if err != nil { discarded = append(discarded, api.DiscardedBreakpoint{Breakpoint: api.ConvertLogicalBreakpoint(oldBp), Reason: err.Error()}) @@ -735,7 +735,7 @@ func createLogicalBreakpoint(d *Debugger, addrs []uint64, requestedBp *api.Break if id <= 0 { d.breakpointIDCounter++ id = d.breakpointIDCounter - lbp = &proc.LogicalBreakpoint{LogicalID: id, HitCount: make(map[int]uint64), Enabled: true} + lbp = &proc.LogicalBreakpoint{LogicalID: id, HitCount: make(map[int64]uint64), Enabled: true} p.Breakpoints().Logical[id] = lbp } @@ -1114,7 +1114,7 @@ func (d *Debugger) findBreakpointByName(name string) *api.Breakpoint { } // CreateWatchpoint creates a watchpoint on the specified expression. -func (d *Debugger) CreateWatchpoint(goid, frame, deferredCall int, expr string, wtype api.WatchType) (*api.Breakpoint, error) { +func (d *Debugger) CreateWatchpoint(goid int64, frame, deferredCall int, expr string, wtype api.WatchType) (*api.Breakpoint, error) { if len(d.target.Targets()) != 1 { panic("multiple targets not implemented") } @@ -1165,7 +1165,7 @@ func (d *Debugger) FindThread(id int) (proc.Thread, error) { } // FindGoroutine returns the goroutine for the given 'id'. -func (d *Debugger) FindGoroutine(id int) (*proc.G, error) { +func (d *Debugger) FindGoroutine(id int64) (*proc.G, error) { d.targetMutex.Lock() defer d.targetMutex.Unlock() @@ -1548,7 +1548,7 @@ func (d *Debugger) ThreadRegisters(threadID int, floatingPoint bool) (*op.DwarfR } // ScopeRegisters returns registers for the specified scope. -func (d *Debugger) ScopeRegisters(goid, frame, deferredCall int, floatingPoint bool) (*op.DwarfRegisters, error) { +func (d *Debugger) ScopeRegisters(goid int64, frame, deferredCall int, floatingPoint bool) (*op.DwarfRegisters, error) { d.targetMutex.Lock() defer d.targetMutex.Unlock() @@ -1565,7 +1565,7 @@ func (d *Debugger) DwarfRegisterToString(i int, reg *op.DwarfRegister) (string, } // LocalVariables returns a list of the local variables. -func (d *Debugger) LocalVariables(goid, frame, deferredCall int, cfg proc.LoadConfig) ([]*proc.Variable, error) { +func (d *Debugger) LocalVariables(goid int64, frame, deferredCall int, cfg proc.LoadConfig) ([]*proc.Variable, error) { d.targetMutex.Lock() defer d.targetMutex.Unlock() @@ -1577,7 +1577,7 @@ func (d *Debugger) LocalVariables(goid, frame, deferredCall int, cfg proc.LoadCo } // FunctionArguments returns the arguments to the current function. -func (d *Debugger) FunctionArguments(goid, frame, deferredCall int, cfg proc.LoadConfig) ([]*proc.Variable, error) { +func (d *Debugger) FunctionArguments(goid int64, frame, deferredCall int, cfg proc.LoadConfig) ([]*proc.Variable, error) { d.targetMutex.Lock() defer d.targetMutex.Unlock() @@ -1589,7 +1589,7 @@ func (d *Debugger) FunctionArguments(goid, frame, deferredCall int, cfg proc.Loa } // Function returns the current function. -func (d *Debugger) Function(goid, frame, deferredCall int, cfg proc.LoadConfig) (*proc.Function, error) { +func (d *Debugger) Function(goid int64, frame, deferredCall int, cfg proc.LoadConfig) (*proc.Function, error) { d.targetMutex.Lock() defer d.targetMutex.Unlock() @@ -1602,7 +1602,7 @@ func (d *Debugger) Function(goid, frame, deferredCall int, cfg proc.LoadConfig) // EvalVariableInScope will attempt to evaluate the variable represented by 'symbol' // in the scope provided. -func (d *Debugger) EvalVariableInScope(goid, frame, deferredCall int, expr string, cfg proc.LoadConfig) (*proc.Variable, error) { +func (d *Debugger) EvalVariableInScope(goid int64, frame, deferredCall int, expr string, cfg proc.LoadConfig) (*proc.Variable, error) { d.targetMutex.Lock() defer d.targetMutex.Unlock() @@ -1623,7 +1623,7 @@ func (d *Debugger) LoadResliced(v *proc.Variable, start int, cfg proc.LoadConfig // SetVariableInScope will set the value of the variable represented by // 'symbol' to the value given, in the given scope. -func (d *Debugger) SetVariableInScope(goid, frame, deferredCall int, symbol, value string) error { +func (d *Debugger) SetVariableInScope(goid int64, frame, deferredCall int, symbol, value string) error { d.targetMutex.Lock() defer d.targetMutex.Unlock() @@ -1769,7 +1769,7 @@ func (d *Debugger) GroupGoroutines(gs []*proc.G, group *api.GoroutineGroupingOpt // 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) ([]proc.Stackframe, error) { +func (d *Debugger) Stacktrace(goroutineID int64, depth int, opts api.StacktraceOptions) ([]proc.Stackframe, error) { d.targetMutex.Lock() defer d.targetMutex.Unlock() @@ -1790,7 +1790,7 @@ func (d *Debugger) Stacktrace(goroutineID, depth int, opts api.StacktraceOptions } // Ancestors returns the stacktraces for the ancestors of a goroutine. -func (d *Debugger) Ancestors(goroutineID, numAncestors, depth int) ([]api.Ancestor, error) { +func (d *Debugger) Ancestors(goroutineID int64, numAncestors, depth int) ([]api.Ancestor, error) { d.targetMutex.Lock() defer d.targetMutex.Unlock() @@ -1928,7 +1928,7 @@ func (d *Debugger) CurrentPackage() (string, error) { } // FindLocation will find the location specified by 'locStr'. -func (d *Debugger) FindLocation(goid, frame, deferredCall int, locStr string, includeNonExecutableLines bool, substitutePathRules [][2]string) ([]api.Location, error) { +func (d *Debugger) FindLocation(goid int64, frame, deferredCall int, locStr string, includeNonExecutableLines bool, substitutePathRules [][2]string) ([]api.Location, error) { d.targetMutex.Lock() defer d.targetMutex.Unlock() @@ -1955,7 +1955,7 @@ func (d *Debugger) FindLocation(goid, frame, deferredCall int, locStr string, in // 'locSpec' should be the result of calling 'locspec.Parse(locStr)'. 'locStr' // is also passed, because it made be used to broaden the search criteria, if // the parsed result did not find anything. -func (d *Debugger) FindLocationSpec(goid, frame, deferredCall int, locStr string, locSpec locspec.LocationSpec, includeNonExecutableLines bool, substitutePathRules [][2]string) ([]api.Location, error) { +func (d *Debugger) FindLocationSpec(goid int64, frame, deferredCall int, locStr string, locSpec locspec.LocationSpec, includeNonExecutableLines bool, substitutePathRules [][2]string) ([]api.Location, error) { d.targetMutex.Lock() defer d.targetMutex.Unlock() @@ -1973,7 +1973,7 @@ func (d *Debugger) FindLocationSpec(goid, frame, deferredCall int, locStr string return d.findLocation(d.target.Selected, goid, frame, deferredCall, locStr, locSpec, includeNonExecutableLines, substitutePathRules) } -func (d *Debugger) findLocation(p *proc.Target, goid, frame, deferredCall int, locStr string, locSpec locspec.LocationSpec, includeNonExecutableLines bool, substitutePathRules [][2]string) ([]api.Location, error) { +func (d *Debugger) findLocation(p *proc.Target, goid int64, frame, deferredCall int, locStr string, locSpec locspec.LocationSpec, includeNonExecutableLines bool, substitutePathRules [][2]string) ([]api.Location, error) { s, _ := proc.ConvertEvalScope(p, goid, frame, deferredCall) locs, err := locSpec.Find(p, d.processArgs, s, locStr, includeNonExecutableLines, substitutePathRules) @@ -1991,7 +1991,7 @@ func (d *Debugger) findLocation(p *proc.Target, goid, frame, deferredCall int, l // 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) ([]proc.AsmInstruction, error) { +func (d *Debugger) Disassemble(goroutineID int64, addr1, addr2 uint64) ([]proc.AsmInstruction, error) { d.targetMutex.Lock() defer d.targetMutex.Unlock() diff --git a/service/rpc1/client.go b/service/rpc1/client.go index 9c24e7eb..06dfec60 100644 --- a/service/rpc1/client.go +++ b/service/rpc1/client.go @@ -146,7 +146,7 @@ func (c *RPCClient) SwitchGoroutine(goroutineID int) (*api.DebuggerState, error) state := new(api.DebuggerState) cmd := &api.DebuggerCommand{ Name: api.SwitchGoroutine, - GoroutineID: goroutineID, + GoroutineID: int64(goroutineID), } err := c.call("Command", cmd, state) return state, err diff --git a/service/rpc1/server.go b/service/rpc1/server.go index b4294309..57d46cac 100644 --- a/service/rpc1/server.go +++ b/service/rpc1/server.go @@ -89,7 +89,7 @@ func (s *RPCServer) StacktraceGoroutine(args *StacktraceGoroutineArgs, locations if args.Full { loadcfg = &defaultLoadConfig } - locs, err := s.debugger.Stacktrace(args.Id, args.Depth, 0) + locs, err := s.debugger.Stacktrace(int64(args.Id), args.Depth, 0) if err != nil { return err } diff --git a/service/rpc2/client.go b/service/rpc2/client.go index f01c0a97..d31f1cee 100644 --- a/service/rpc2/client.go +++ b/service/rpc2/client.go @@ -177,7 +177,7 @@ func (c *RPCClient) ReverseStepOut() (*api.DebuggerState, error) { return &out.State, err } -func (c *RPCClient) Call(goroutineID int, expr string, unsafe bool) (*api.DebuggerState, error) { +func (c *RPCClient) Call(goroutineID int64, expr string, unsafe bool) (*api.DebuggerState, error) { var out CommandOut err := c.call("Command", api.DebuggerCommand{Name: api.Call, ReturnInfoLoadConfig: c.retValLoadCfg, Expr: expr, UnsafeCall: unsafe, GoroutineID: goroutineID}, &out) return &out.State, err @@ -205,7 +205,7 @@ func (c *RPCClient) SwitchThread(threadID int) (*api.DebuggerState, error) { return &out.State, err } -func (c *RPCClient) SwitchGoroutine(goroutineID int) (*api.DebuggerState, error) { +func (c *RPCClient) SwitchGoroutine(goroutineID int64) (*api.DebuggerState, error) { var out CommandOut cmd := api.DebuggerCommand{ Name: api.SwitchGoroutine, @@ -387,13 +387,13 @@ func (c *RPCClient) ListGoroutinesWithFilter(start, count int, filters []api.Lis return out.Goroutines, out.Groups, out.Nextg, out.TooManyGroups, err } -func (c *RPCClient) Stacktrace(goroutineId, depth int, opts api.StacktraceOptions, cfg *api.LoadConfig) ([]api.Stackframe, error) { +func (c *RPCClient) Stacktrace(goroutineId int64, depth int, opts api.StacktraceOptions, cfg *api.LoadConfig) ([]api.Stackframe, error) { var out StacktraceOut err := c.call("Stacktrace", StacktraceIn{goroutineId, depth, false, false, opts, cfg}, &out) return out.Locations, err } -func (c *RPCClient) Ancestors(goroutineID int, numAncestors int, depth int) ([]api.Ancestor, error) { +func (c *RPCClient) Ancestors(goroutineID int64, numAncestors int, depth int) ([]api.Ancestor, error) { var out AncestorsOut err := c.call("Ancestors", AncestorsIn{goroutineID, numAncestors, depth}, &out) return out.Ancestors, err diff --git a/service/rpc2/server.go b/service/rpc2/server.go index fc97c0a6..495fdd29 100644 --- a/service/rpc2/server.go +++ b/service/rpc2/server.go @@ -176,7 +176,7 @@ func (s *RPCServer) GetBreakpoint(arg GetBreakpointIn, out *GetBreakpointOut) er } type StacktraceIn struct { - Id int + Id int64 Depth int Full bool Defers bool // read deferred functions (equivalent to passing StacktraceReadDefers in Opts) @@ -210,7 +210,7 @@ func (s *RPCServer) Stacktrace(arg StacktraceIn, out *StacktraceOut) error { } type AncestorsIn struct { - GoroutineID int + GoroutineID int64 NumAncestors int Depth int } diff --git a/service/test/integration1_test.go b/service/test/integration1_test.go index c3d46dce..a362ce52 100644 --- a/service/test/integration1_test.go +++ b/service/test/integration1_test.go @@ -737,7 +737,7 @@ func Test1ClientServer_FullStacktrace(t *testing.T) { assertNoError(err, t, "GoroutinesInfo()") found := make([]bool, 10) for _, g := range gs { - frames, err := c.Stacktrace(g.ID, 40, true) + frames, err := c.Stacktrace(int(g.ID), 40, true) assertNoError(err, t, fmt.Sprintf("Stacktrace(%d)", g.ID)) t.Logf("goroutine %d", g.ID) for i, frame := range frames { @@ -831,7 +831,7 @@ func Test1Issue355(t *testing.T) { assertErrorOrExited(s, err, t, "StepInstruction()") s, err = c.SwitchThread(tid) assertErrorOrExited(s, err, t, "SwitchThread()") - s, err = c.SwitchGoroutine(gid) + s, err = c.SwitchGoroutine(int(gid)) assertErrorOrExited(s, err, t, "SwitchGoroutine()") s, err = c.Halt() assertErrorOrExited(s, err, t, "Halt()") @@ -852,7 +852,7 @@ func Test1Issue355(t *testing.T) { assertError(err, t, "ListRegisters()") _, err = c.ListGoroutines() assertError(err, t, "ListGoroutines()") - _, err = c.Stacktrace(gid, 10, false) + _, err = c.Stacktrace(int(gid), 10, false) assertError(err, t, "Stacktrace()") _, err = c.FindLocation(api.EvalScope{GoroutineID: gid}, "+1") assertError(err, t, "FindLocation()")