terminal: restore breakpoints set with line offset on restart (#3425)
Change FindLocation so it can return a substitute location expression and propagate it to pkg/terminal/command. When breakpoints are set using the syntax :<lineno> or +<lineno> produce a substitute location expression that doesn't depend on having a valid scope and can be used to restore the breakpoint. Fixes #3423
This commit is contained in:
parent
8023fa956e
commit
ca611db449
@ -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)")
|
||||
}
|
||||
if loc.Offset == 0 {
|
||||
return []api.Location{{PC: scope.PC}}, nil
|
||||
return nil, "", fmt.Errorf("could not determine current location (scope is nil)")
|
||||
}
|
||||
file, line, fn := scope.BinInfo.PCToLine(scope.PC)
|
||||
if fn == nil {
|
||||
return nil, fmt.Errorf("could not determine current location")
|
||||
if loc.Offset == 0 {
|
||||
subst := ""
|
||||
if fn != nil {
|
||||
subst = fmt.Sprintf("%s:%d", file, line)
|
||||
}
|
||||
return []api.Location{{PC: scope.PC}}, subst, nil
|
||||
}
|
||||
if fn == nil {
|
||||
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) {
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -143,7 +143,7 @@ type Client interface {
|
||||
// * *<address> 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)
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user