From 6d33a556fdaf08cbfeca8750125807d7c44ca594 Mon Sep 17 00:00:00 2001 From: aarzilli Date: Tue, 20 Jun 2023 10:19:16 +0200 Subject: [PATCH] terminal: restore breakpoints set with line offset on restart Change FindLocation so it can return a substitute location expression and propagate it to pkg/terminal/command. When breakpoints are set using the syntax : or + produce a substitute location expression that doesn't depend on having a valid scope and can be used to restore the breakpoint. Fixes #3423 --- pkg/locspec/locations.go | 78 +++++++++++++++++-------------- pkg/terminal/command.go | 17 ++++--- pkg/terminal/command_test.go | 26 +++++++++++ service/client.go | 2 +- service/debugger/debugger.go | 23 +++++---- service/rpc1/server.go | 2 +- service/rpc2/client.go | 4 +- service/rpc2/server.go | 5 +- service/test/common_test.go | 4 +- service/test/integration2_test.go | 14 +++--- 10 files changed, 109 insertions(+), 66 deletions(-) diff --git a/pkg/locspec/locations.go b/pkg/locspec/locations.go index 92d83181e9..7ae05c4e72 100644 --- a/pkg/locspec/locations.go +++ b/pkg/locspec/locations.go @@ -20,7 +20,7 @@ const maxFindLocationCandidates = 5 // LocationSpec is an interface that represents a parsed location spec string. type LocationSpec interface { // Find returns all locations that match the location spec. - Find(t *proc.Target, processArgs []string, scope *proc.EvalScope, locStr string, includeNonExecutableLines bool, substitutePathRules [][2]string) ([]api.Location, error) + Find(t *proc.Target, processArgs []string, scope *proc.EvalScope, locStr string, includeNonExecutableLines bool, substitutePathRules [][2]string) ([]api.Location, string, error) } // NormalLocationSpec represents a basic location spec. @@ -269,15 +269,15 @@ func packageMatch(specPkg, symPkg string, packageMap map[string][]string) bool { // Find will search all functions in the target program and filter them via the // regex location spec. Only functions matching the regex will be returned. -func (loc *RegexLocationSpec) Find(t *proc.Target, _ []string, scope *proc.EvalScope, locStr string, includeNonExecutableLines bool, _ [][2]string) ([]api.Location, error) { +func (loc *RegexLocationSpec) Find(t *proc.Target, _ []string, scope *proc.EvalScope, locStr string, includeNonExecutableLines bool, _ [][2]string) ([]api.Location, string, error) { if scope == nil { //TODO(aarzilli): this needs only the list of function we should make it work - return nil, fmt.Errorf("could not determine location (scope is nil)") + return nil, "", fmt.Errorf("could not determine location (scope is nil)") } funcs := scope.BinInfo.Functions matches, err := regexFilterFuncs(loc.FuncRegex, funcs) if err != nil { - return nil, err + return nil, "", err } r := make([]api.Location, 0, len(matches)) for i := range matches { @@ -286,39 +286,39 @@ func (loc *RegexLocationSpec) Find(t *proc.Target, _ []string, scope *proc.EvalS r = append(r, addressesToLocation(addrs)) } } - return r, nil + return r, "", nil } // Find returns the locations specified via the address location spec. -func (loc *AddrLocationSpec) Find(t *proc.Target, _ []string, scope *proc.EvalScope, locStr string, includeNonExecutableLines bool, _ [][2]string) ([]api.Location, error) { +func (loc *AddrLocationSpec) Find(t *proc.Target, _ []string, scope *proc.EvalScope, locStr string, includeNonExecutableLines bool, _ [][2]string) ([]api.Location, string, error) { if scope == nil { addr, err := strconv.ParseInt(loc.AddrExpr, 0, 64) if err != nil { - return nil, fmt.Errorf("could not determine current location (scope is nil)") + return nil, "", fmt.Errorf("could not determine current location (scope is nil)") } - return []api.Location{{PC: uint64(addr)}}, nil + return []api.Location{{PC: uint64(addr)}}, "", nil } v, err := scope.EvalExpression(loc.AddrExpr, proc.LoadConfig{FollowPointers: true}) if err != nil { - return nil, err + return nil, "", err } if v.Unreadable != nil { - return nil, v.Unreadable + return nil, "", v.Unreadable } switch v.Kind { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: addr, _ := constant.Uint64Val(v.Value) - return []api.Location{{PC: addr}}, nil + return []api.Location{{PC: addr}}, "", nil case reflect.Func: fn := scope.BinInfo.PCToFunc(uint64(v.Base)) pc, err := proc.FirstPCAfterPrologue(t, fn, false) if err != nil { - return nil, err + return nil, "", err } - return []api.Location{{PC: pc}}, nil + return []api.Location{{PC: pc}}, v.Name, nil default: - return nil, fmt.Errorf("wrong expression kind: %v", v.Kind) + return nil, "", fmt.Errorf("wrong expression kind: %v", v.Kind) } } @@ -371,7 +371,7 @@ func (ale AmbiguousLocationError) Error() string { // Find will return a list of locations that match the given location spec. // This matches each other location spec that does not already have its own spec // implemented (such as regex, or addr). -func (loc *NormalLocationSpec) Find(t *proc.Target, processArgs []string, scope *proc.EvalScope, locStr string, includeNonExecutableLines bool, substitutePathRules [][2]string) ([]api.Location, error) { +func (loc *NormalLocationSpec) Find(t *proc.Target, processArgs []string, scope *proc.EvalScope, locStr string, includeNonExecutableLines bool, substitutePathRules [][2]string) ([]api.Location, string, error) { limit := maxFindLocationCandidates var candidateFiles []string for _, sourceFile := range t.BinInfo().Sources { @@ -396,19 +396,19 @@ func (loc *NormalLocationSpec) Find(t *proc.Target, processArgs []string, scope if matching := len(candidateFiles) + len(candidateFuncs); matching == 0 { if scope == nil { - return nil, fmt.Errorf("location %q not found", locStr) + return nil, "", fmt.Errorf("location %q not found", locStr) } // if no result was found this locations string could be an // expression that the user forgot to prefix with '*', try treating it as // such. addrSpec := &AddrLocationSpec{AddrExpr: locStr} - locs, err := addrSpec.Find(t, processArgs, scope, locStr, includeNonExecutableLines, nil) + locs, subst, err := addrSpec.Find(t, processArgs, scope, locStr, includeNonExecutableLines, nil) if err != nil { - return nil, fmt.Errorf("location %q not found", locStr) + return nil, "", fmt.Errorf("location %q not found", locStr) } - return locs, nil + return locs, subst, nil } else if matching > 1 { - return nil, AmbiguousLocationError{Location: locStr, CandidatesString: append(candidateFiles, candidateFuncs...)} + return nil, "", AmbiguousLocationError{Location: locStr, CandidatesString: append(candidateFiles, candidateFuncs...)} } // len(candidateFiles) + len(candidateFuncs) == 1 @@ -417,12 +417,12 @@ func (loc *NormalLocationSpec) Find(t *proc.Target, processArgs []string, scope if len(candidateFiles) == 1 { if loc.LineOffset < 0 { //lint:ignore ST1005 backwards compatibility - return nil, fmt.Errorf("Malformed breakpoint location, no line offset specified") + return nil, "", fmt.Errorf("Malformed breakpoint location, no line offset specified") } addrs, err = proc.FindFileLocation(t, candidateFiles[0], loc.LineOffset) if includeNonExecutableLines { if _, isCouldNotFindLine := err.(*proc.ErrCouldNotFindLine); isCouldNotFindLine { - return []api.Location{{File: candidateFiles[0], Line: loc.LineOffset}}, nil + return []api.Location{{File: candidateFiles[0], Line: loc.LineOffset}}, "", nil } } } else { // len(candidateFuncs) == 1 @@ -430,9 +430,9 @@ func (loc *NormalLocationSpec) Find(t *proc.Target, processArgs []string, scope } if err != nil { - return nil, err + return nil, "", err } - return []api.Location{addressesToLocation(addrs)}, nil + return []api.Location{addressesToLocation(addrs)}, "", nil } func (loc *NormalLocationSpec) findFuncCandidates(bi *proc.BinaryInfo, limit int) []string { @@ -585,42 +585,48 @@ func addressesToLocation(addrs []uint64) api.Location { } // Find returns the location after adding the offset amount to the current line number. -func (loc *OffsetLocationSpec) Find(t *proc.Target, _ []string, scope *proc.EvalScope, _ string, includeNonExecutableLines bool, _ [][2]string) ([]api.Location, error) { +func (loc *OffsetLocationSpec) Find(t *proc.Target, _ []string, scope *proc.EvalScope, _ string, includeNonExecutableLines bool, _ [][2]string) ([]api.Location, string, error) { if scope == nil { - return nil, fmt.Errorf("could not determine current location (scope is nil)") + return nil, "", fmt.Errorf("could not determine current location (scope is nil)") } + file, line, fn := scope.BinInfo.PCToLine(scope.PC) if loc.Offset == 0 { - return []api.Location{{PC: scope.PC}}, nil + subst := "" + if fn != nil { + subst = fmt.Sprintf("%s:%d", file, line) + } + return []api.Location{{PC: scope.PC}}, subst, nil } - file, line, fn := scope.BinInfo.PCToLine(scope.PC) if fn == nil { - return nil, fmt.Errorf("could not determine current location") + return nil, "", fmt.Errorf("could not determine current location") } + subst := fmt.Sprintf("%s:%d", file, line+loc.Offset) addrs, err := proc.FindFileLocation(t, file, line+loc.Offset) if includeNonExecutableLines { if _, isCouldNotFindLine := err.(*proc.ErrCouldNotFindLine); isCouldNotFindLine { - return []api.Location{{File: file, Line: line + loc.Offset}}, nil + return []api.Location{{File: file, Line: line + loc.Offset}}, subst, nil } } - return []api.Location{addressesToLocation(addrs)}, err + return []api.Location{addressesToLocation(addrs)}, subst, err } // Find will return the location at the given line in the current file. -func (loc *LineLocationSpec) Find(t *proc.Target, _ []string, scope *proc.EvalScope, _ string, includeNonExecutableLines bool, _ [][2]string) ([]api.Location, error) { +func (loc *LineLocationSpec) Find(t *proc.Target, _ []string, scope *proc.EvalScope, _ string, includeNonExecutableLines bool, _ [][2]string) ([]api.Location, string, error) { if scope == nil { - return nil, fmt.Errorf("could not determine current location (scope is nil)") + return nil, "", fmt.Errorf("could not determine current location (scope is nil)") } file, _, fn := scope.BinInfo.PCToLine(scope.PC) if fn == nil { - return nil, fmt.Errorf("could not determine current location") + return nil, "", fmt.Errorf("could not determine current location") } + subst := fmt.Sprintf("%s:%d", file, loc.Line) addrs, err := proc.FindFileLocation(t, file, loc.Line) if includeNonExecutableLines { if _, isCouldNotFindLine := err.(*proc.ErrCouldNotFindLine); isCouldNotFindLine { - return []api.Location{{File: file, Line: loc.Line}}, nil + return []api.Location{{File: file, Line: loc.Line}}, subst, nil } } - return []api.Location{addressesToLocation(addrs)}, err + return []api.Location{addressesToLocation(addrs)}, subst, err } func regexFilterFuncs(filter string, allFuncs []proc.Function) ([]string, error) { diff --git a/pkg/terminal/command.go b/pkg/terminal/command.go index aa4137b764..430b9b12e4 100644 --- a/pkg/terminal/command.go +++ b/pkg/terminal/command.go @@ -1634,7 +1634,7 @@ func clearAll(t *Term, ctx callContext, args string) error { var locPCs map[uint64]struct{} if args != "" { - locs, err := t.client.FindLocation(api.EvalScope{GoroutineID: -1, Frame: 0}, args, true, t.substitutePathRules()) + locs, _, err := t.client.FindLocation(api.EvalScope{GoroutineID: -1, Frame: 0}, args, true, t.substitutePathRules()) if err != nil { return err } @@ -1790,14 +1790,16 @@ func setBreakpoint(t *Term, ctx callContext, tracepoint bool, argstr string) ([] } requestedBp.Tracepoint = tracepoint - locs, findLocErr := t.client.FindLocation(ctx.Scope, spec, true, t.substitutePathRules()) + locs, substSpec, findLocErr := t.client.FindLocation(ctx.Scope, spec, true, t.substitutePathRules()) if findLocErr != nil && requestedBp.Name != "" { requestedBp.Name = "" spec = argstr var err2 error - locs, err2 = t.client.FindLocation(ctx.Scope, spec, true, t.substitutePathRules()) + var substSpec2 string + locs, substSpec2, err2 = t.client.FindLocation(ctx.Scope, spec, true, t.substitutePathRules()) if err2 == nil { findLocErr = nil + substSpec = substSpec2 } } if findLocErr != nil && shouldAskToSuspendBreakpoint(t) { @@ -1824,6 +1826,9 @@ func setBreakpoint(t *Term, ctx callContext, tracepoint bool, argstr string) ([] if findLocErr != nil { return nil, findLocErr } + if substSpec != "" { + spec = substSpec + } created := []*api.Breakpoint{} for _, loc := range locs { @@ -2431,7 +2436,7 @@ func getLocation(t *Term, ctx callContext, args string, showContext bool) (file return loc.File, loc.Line, true, nil default: - locs, err := t.client.FindLocation(ctx.Scope, args, false, t.substitutePathRules()) + locs, _, err := t.client.FindLocation(ctx.Scope, args, false, t.substitutePathRules()) if err != nil { return "", 0, false, err } @@ -2505,7 +2510,7 @@ func disassCommand(t *Term, ctx callContext, args string) error { switch cmd { case "": - locs, err := t.client.FindLocation(ctx.Scope, "+0", true, t.substitutePathRules()) + locs, _, err := t.client.FindLocation(ctx.Scope, "+0", true, t.substitutePathRules()) if err != nil { return err } @@ -2525,7 +2530,7 @@ func disassCommand(t *Term, ctx callContext, args string) error { } disasm, disasmErr = t.client.DisassembleRange(ctx.Scope, uint64(startpc), uint64(endpc), flavor) case "-l": - locs, err := t.client.FindLocation(ctx.Scope, rest, true, t.substitutePathRules()) + locs, _, err := t.client.FindLocation(ctx.Scope, rest, true, t.substitutePathRules()) if err != nil { return err } diff --git a/pkg/terminal/command_test.go b/pkg/terminal/command_test.go index 925568ac16..403c9e8da9 100644 --- a/pkg/terminal/command_test.go +++ b/pkg/terminal/command_test.go @@ -1419,3 +1419,29 @@ func TestCreateBreakpointByLocExpr(t *testing.T) { } }) } + +func TestRestartBreakpoints(t *testing.T) { + // Tests that breakpoints set using just a line number and with a line + // offset are preserved after restart. See issue #3423. + withTestTerminal("continuetestprog", t, func(term *FakeTerminal) { + term.MustExec("break main.main") + term.MustExec("continue") + term.MustExec("break 9") + term.MustExec("break +1") + out := term.MustExec("breakpoints") + t.Log("breakpoints before:\n", out) + term.MustExec("restart") + out = term.MustExec("breakpoints") + t.Log("breakpoints after:\n", out) + bps, err := term.client.ListBreakpoints(false) + assertNoError(t, err, "ListBreakpoints") + for _, bp := range bps { + if bp.ID < 0 { + continue + } + if bp.Addr == 0 { + t.Fatalf("breakpoint %d has address 0", bp.ID) + } + } + }) +} diff --git a/service/client.go b/service/client.go index 62a10c36f3..f0cdc668b4 100644 --- a/service/client.go +++ b/service/client.go @@ -143,7 +143,7 @@ type Client interface { // * *
returns the location corresponding to the specified address // NOTE: this function does not actually set breakpoints. // If findInstruction is true FindLocation will only return locations that correspond to instructions. - FindLocation(scope api.EvalScope, loc string, findInstruction bool, substitutePathRules [][2]string) ([]api.Location, error) + FindLocation(scope api.EvalScope, loc string, findInstruction bool, substitutePathRules [][2]string) ([]api.Location, string, error) // DisassembleRange disassemble code between startPC and endPC DisassembleRange(scope api.EvalScope, startPC, endPC uint64, flavour api.AssemblyFlavour) (api.AsmInstructions, error) diff --git a/service/debugger/debugger.go b/service/debugger/debugger.go index 57ece158e4..d8608cb1f9 100644 --- a/service/debugger/debugger.go +++ b/service/debugger/debugger.go @@ -737,7 +737,7 @@ func (d *Debugger) CreateBreakpoint(requestedBp *api.Breakpoint, locExpr string, return nil, err } setbp.Expr = func(t *proc.Target) []uint64 { - locs, err := loc.Find(t, d.processArgs, nil, locExpr, false, substitutePathRules) + locs, _, err := loc.Find(t, d.processArgs, nil, locExpr, false, substitutePathRules) if err != nil || len(locs) != 1 { logflags.DebuggerLogger().Debugf("could not evaluate breakpoint expression %q: %v (number of results %d)", locExpr, err, len(locs)) return nil @@ -1921,17 +1921,17 @@ func (d *Debugger) CurrentPackage() (string, error) { } // FindLocation will find the location specified by 'locStr'. -func (d *Debugger) FindLocation(goid int64, 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, string, error) { d.targetMutex.Lock() defer d.targetMutex.Unlock() if _, err := d.target.Valid(); err != nil { - return nil, err + return nil, "", err } loc, err := locspec.Parse(locStr) if err != nil { - return nil, err + return nil, "", err } return d.findLocation(goid, frame, deferredCall, locStr, loc, includeNonExecutableLines, substitutePathRules) @@ -1949,18 +1949,23 @@ func (d *Debugger) FindLocationSpec(goid int64, frame, deferredCall int, locStr return nil, err } - return d.findLocation(goid, frame, deferredCall, locStr, locSpec, includeNonExecutableLines, substitutePathRules) + locs, _, err := d.findLocation(goid, frame, deferredCall, locStr, locSpec, includeNonExecutableLines, substitutePathRules) + return locs, err } -func (d *Debugger) findLocation(goid int64, frame, deferredCall int, locStr string, locSpec locspec.LocationSpec, includeNonExecutableLines bool, substitutePathRules [][2]string) ([]api.Location, error) { +func (d *Debugger) findLocation(goid int64, frame, deferredCall int, locStr string, locSpec locspec.LocationSpec, includeNonExecutableLines bool, substitutePathRules [][2]string) ([]api.Location, string, error) { locations := []api.Location{} t := proc.ValidTargets{Group: d.target} + subst := "" for t.Next() { pid := t.Pid() s, _ := proc.ConvertEvalScope(t.Target, goid, frame, deferredCall) - locs, err := locSpec.Find(t.Target, d.processArgs, s, locStr, includeNonExecutableLines, substitutePathRules) + locs, s1, err := locSpec.Find(t.Target, d.processArgs, s, locStr, includeNonExecutableLines, substitutePathRules) + if s1 != "" { + subst = s1 + } if err != nil { - return nil, err + return nil, "", err } for i := range locs { if locs[i].PC == 0 { @@ -1977,7 +1982,7 @@ func (d *Debugger) findLocation(goid int64, frame, deferredCall int, locStr stri } locations = append(locations, locs...) } - return locations, nil + return locations, subst, nil } // Disassemble code between startPC and endPC. diff --git a/service/rpc1/server.go b/service/rpc1/server.go index fc6dd78245..98a508ea96 100644 --- a/service/rpc1/server.go +++ b/service/rpc1/server.go @@ -306,7 +306,7 @@ type FindLocationArgs struct { func (c *RPCServer) FindLocation(args FindLocationArgs, answer *[]api.Location) error { var err error - *answer, err = c.debugger.FindLocation(args.Scope.GoroutineID, args.Scope.Frame, args.Scope.DeferredCall, args.Loc, false, nil) + *answer, _, err = c.debugger.FindLocation(args.Scope.GoroutineID, args.Scope.Frame, args.Scope.DeferredCall, args.Loc, false, nil) return err } diff --git a/service/rpc2/client.go b/service/rpc2/client.go index f28d0de5ca..e05ae8fbb3 100644 --- a/service/rpc2/client.go +++ b/service/rpc2/client.go @@ -414,10 +414,10 @@ func (c *RPCClient) AttachedToExistingProcess() bool { return out.Answer } -func (c *RPCClient) FindLocation(scope api.EvalScope, loc string, findInstructions bool, substitutePathRules [][2]string) ([]api.Location, error) { +func (c *RPCClient) FindLocation(scope api.EvalScope, loc string, findInstructions bool, substitutePathRules [][2]string) ([]api.Location, string, error) { var out FindLocationOut err := c.call("FindLocation", FindLocationIn{scope, loc, !findInstructions, substitutePathRules}, &out) - return out.Locations, err + return out.Locations, out.SubstituteLocExpr, err } // DisassembleRange disassembles code between startPC and endPC diff --git a/service/rpc2/server.go b/service/rpc2/server.go index f90153980a..7097bdcac8 100644 --- a/service/rpc2/server.go +++ b/service/rpc2/server.go @@ -705,7 +705,8 @@ type FindLocationIn struct { } type FindLocationOut struct { - Locations []api.Location + Locations []api.Location + SubstituteLocExpr string // if this isn't an empty string it should be passed as the location expression for CreateBreakpoint instead of the original location expression } // FindLocation returns concrete location information described by a location expression. @@ -723,7 +724,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.GoroutineID, arg.Scope.Frame, arg.Scope.DeferredCall, arg.Loc, arg.IncludeNonExecutableLines, arg.SubstitutePathRules) + out.Locations, out.SubstituteLocExpr, err = c.debugger.FindLocation(arg.Scope.GoroutineID, arg.Scope.Frame, arg.Scope.DeferredCall, arg.Loc, arg.IncludeNonExecutableLines, arg.SubstitutePathRules) return err } diff --git a/service/test/common_test.go b/service/test/common_test.go index ef6338e0f4..a91b63dba8 100644 --- a/service/test/common_test.go +++ b/service/test/common_test.go @@ -89,7 +89,7 @@ type locationFinder1 interface { } type locationFinder2 interface { - FindLocation(api.EvalScope, string, bool, [][2]string) ([]api.Location, error) + FindLocation(api.EvalScope, string, bool, [][2]string) ([]api.Location, string, error) } func findLocationHelper(t *testing.T, c interface{}, loc string, shouldErr bool, count int, checkAddr uint64) []uint64 { @@ -100,7 +100,7 @@ func findLocationHelper(t *testing.T, c interface{}, loc string, shouldErr bool, case locationFinder1: locs, err = c.FindLocation(api.EvalScope{GoroutineID: -1}, loc) case locationFinder2: - locs, err = c.FindLocation(api.EvalScope{GoroutineID: -1}, loc, false, nil) + locs, _, err = c.FindLocation(api.EvalScope{GoroutineID: -1}, loc, false, nil) default: t.Errorf("unexpected type %T passed to findLocationHelper", c) } diff --git a/service/test/integration2_test.go b/service/test/integration2_test.go index adafb41dce..6aaa938ea2 100644 --- a/service/test/integration2_test.go +++ b/service/test/integration2_test.go @@ -997,14 +997,14 @@ func TestClientServer_FindLocations(t *testing.T) { findLocationHelper(t, c, `*amap["k"]`, false, 1, findLocationHelper(t, c, `amap["k"]`, false, 1, 0)[0]) - locsNoSubst, _ := c.FindLocation(api.EvalScope{GoroutineID: -1}, "_fixtures/locationsprog.go:35", false, nil) + locsNoSubst, _, _ := c.FindLocation(api.EvalScope{GoroutineID: -1}, "_fixtures/locationsprog.go:35", false, nil) sep := "/" if strings.Contains(locsNoSubst[0].File, "\\") { sep = "\\" } substRules := [][2]string{{strings.Replace(locsNoSubst[0].File, "locationsprog.go", "", 1), strings.Replace(locsNoSubst[0].File, "_fixtures"+sep+"locationsprog.go", "nonexistent", 1)}} t.Logf("substitute rules: %q -> %q", substRules[0][0], substRules[0][1]) - locsSubst, err := c.FindLocation(api.EvalScope{GoroutineID: -1}, "nonexistent/locationsprog.go:35", false, substRules) + locsSubst, _, err := c.FindLocation(api.EvalScope{GoroutineID: -1}, "nonexistent/locationsprog.go:35", false, substRules) if err != nil { t.Fatalf("FindLocation(locationsprog.go:35) with substitute rules: %v", err) } @@ -1114,7 +1114,7 @@ func TestClientServer_FindLocations(t *testing.T) { } func findLocationHelper2(t *testing.T, c service.Client, loc string, checkLoc *api.Location) *api.Location { - locs, err := c.FindLocation(api.EvalScope{GoroutineID: -1}, loc, false, nil) + locs, _, err := c.FindLocation(api.EvalScope{GoroutineID: -1}, loc, false, nil) if err != nil { t.Fatalf("FindLocation(%q) -> error %v", loc, err) } @@ -1360,7 +1360,7 @@ func TestIssue355(t *testing.T) { assertError(err, t, "ListGoroutines()") _, err = c.Stacktrace(gid, 10, 0, &normalLoadConfig) assertError(err, t, "Stacktrace()") - _, err = c.FindLocation(api.EvalScope{GoroutineID: gid}, "+1", false, nil) + _, _, err = c.FindLocation(api.EvalScope{GoroutineID: gid}, "+1", false, nil) assertError(err, t, "FindLocation()") _, err = c.DisassemblePC(api.EvalScope{GoroutineID: -1}, 0x40100, api.IntelFlavour) assertError(err, t, "DisassemblePC()") @@ -1380,7 +1380,7 @@ func TestDisasm(t *testing.T) { state := <-ch assertNoError(state.Err, t, "Continue()") - locs, err := c.FindLocation(api.EvalScope{GoroutineID: -1}, "main.main", false, nil) + locs, _, err := c.FindLocation(api.EvalScope{GoroutineID: -1}, "main.main", false, nil) assertNoError(err, t, "FindLocation()") if len(locs) != 1 { t.Fatalf("wrong number of locations for main.main: %d", len(locs)) @@ -1639,7 +1639,7 @@ func TestTypesCommand(t *testing.T) { func TestIssue406(t *testing.T) { protest.AllowRecording(t) withTestClient2("issue406", t, func(c service.Client) { - locs, err := c.FindLocation(api.EvalScope{GoroutineID: -1}, "issue406.go:146", false, nil) + locs, _, err := c.FindLocation(api.EvalScope{GoroutineID: -1}, "issue406.go:146", false, nil) assertNoError(err, t, "FindLocation()") _, err = c.CreateBreakpoint(&api.Breakpoint{Addr: locs[0].PC}) assertNoError(err, t, "CreateBreakpoint()") @@ -2253,7 +2253,7 @@ func TestUnknownMethodCall(t *testing.T) { func TestIssue1703(t *testing.T) { // Calling Disassemble when there is no current goroutine should work. withTestClient2("testnextprog", t, func(c service.Client) { - locs, err := c.FindLocation(api.EvalScope{GoroutineID: -1}, "main.main", true, nil) + locs, _, err := c.FindLocation(api.EvalScope{GoroutineID: -1}, "main.main", true, nil) assertNoError(err, t, "FindLocation") t.Logf("FindLocation: %#v", locs) text, err := c.DisassemblePC(api.EvalScope{GoroutineID: -1}, locs[0].PC, api.IntelFlavour)