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.
|
// LocationSpec is an interface that represents a parsed location spec string.
|
||||||
type LocationSpec interface {
|
type LocationSpec interface {
|
||||||
// Find returns all locations that match the location spec.
|
// 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.
|
// 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
|
// 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.
|
// 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 {
|
if scope == nil {
|
||||||
//TODO(aarzilli): this needs only the list of function we should make it work
|
//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
|
funcs := scope.BinInfo.Functions
|
||||||
matches, err := regexFilterFuncs(loc.FuncRegex, funcs)
|
matches, err := regexFilterFuncs(loc.FuncRegex, funcs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, "", err
|
||||||
}
|
}
|
||||||
r := make([]api.Location, 0, len(matches))
|
r := make([]api.Location, 0, len(matches))
|
||||||
for i := range 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))
|
r = append(r, addressesToLocation(addrs))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return r, nil
|
return r, "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find returns the locations specified via the address location spec.
|
// 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 {
|
if scope == nil {
|
||||||
addr, err := strconv.ParseInt(loc.AddrExpr, 0, 64)
|
addr, err := strconv.ParseInt(loc.AddrExpr, 0, 64)
|
||||||
if err != nil {
|
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})
|
v, err := scope.EvalExpression(loc.AddrExpr, proc.LoadConfig{FollowPointers: true})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, "", err
|
||||||
}
|
}
|
||||||
if v.Unreadable != nil {
|
if v.Unreadable != nil {
|
||||||
return nil, v.Unreadable
|
return nil, "", v.Unreadable
|
||||||
}
|
}
|
||||||
switch v.Kind {
|
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:
|
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)
|
addr, _ := constant.Uint64Val(v.Value)
|
||||||
return []api.Location{{PC: addr}}, nil
|
return []api.Location{{PC: addr}}, "", nil
|
||||||
case reflect.Func:
|
case reflect.Func:
|
||||||
fn := scope.BinInfo.PCToFunc(uint64(v.Base))
|
fn := scope.BinInfo.PCToFunc(uint64(v.Base))
|
||||||
pc, err := proc.FirstPCAfterPrologue(t, fn, false)
|
pc, err := proc.FirstPCAfterPrologue(t, fn, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, "", err
|
||||||
}
|
}
|
||||||
return []api.Location{{PC: pc}}, nil
|
return []api.Location{{PC: pc}}, v.Name, nil
|
||||||
default:
|
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.
|
// 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
|
// This matches each other location spec that does not already have its own spec
|
||||||
// implemented (such as regex, or addr).
|
// 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
|
limit := maxFindLocationCandidates
|
||||||
var candidateFiles []string
|
var candidateFiles []string
|
||||||
for _, sourceFile := range t.BinInfo().Sources {
|
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 matching := len(candidateFiles) + len(candidateFuncs); matching == 0 {
|
||||||
if scope == nil {
|
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
|
// if no result was found this locations string could be an
|
||||||
// expression that the user forgot to prefix with '*', try treating it as
|
// expression that the user forgot to prefix with '*', try treating it as
|
||||||
// such.
|
// such.
|
||||||
addrSpec := &AddrLocationSpec{AddrExpr: locStr}
|
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 {
|
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 {
|
} 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
|
// len(candidateFiles) + len(candidateFuncs) == 1
|
||||||
@ -417,12 +417,12 @@ func (loc *NormalLocationSpec) Find(t *proc.Target, processArgs []string, scope
|
|||||||
if len(candidateFiles) == 1 {
|
if len(candidateFiles) == 1 {
|
||||||
if loc.LineOffset < 0 {
|
if loc.LineOffset < 0 {
|
||||||
//lint:ignore ST1005 backwards compatibility
|
//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)
|
addrs, err = proc.FindFileLocation(t, candidateFiles[0], loc.LineOffset)
|
||||||
if includeNonExecutableLines {
|
if includeNonExecutableLines {
|
||||||
if _, isCouldNotFindLine := err.(*proc.ErrCouldNotFindLine); isCouldNotFindLine {
|
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
|
} else { // len(candidateFuncs) == 1
|
||||||
@ -430,9 +430,9 @@ func (loc *NormalLocationSpec) Find(t *proc.Target, processArgs []string, scope
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
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 {
|
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.
|
// 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 {
|
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)")
|
||||||
}
|
|
||||||
if loc.Offset == 0 {
|
|
||||||
return []api.Location{{PC: scope.PC}}, nil
|
|
||||||
}
|
}
|
||||||
file, line, fn := scope.BinInfo.PCToLine(scope.PC)
|
file, line, fn := scope.BinInfo.PCToLine(scope.PC)
|
||||||
if fn == nil {
|
if loc.Offset == 0 {
|
||||||
return nil, fmt.Errorf("could not determine current location")
|
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)
|
addrs, err := proc.FindFileLocation(t, file, line+loc.Offset)
|
||||||
if includeNonExecutableLines {
|
if includeNonExecutableLines {
|
||||||
if _, isCouldNotFindLine := err.(*proc.ErrCouldNotFindLine); isCouldNotFindLine {
|
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.
|
// 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 {
|
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)
|
file, _, fn := scope.BinInfo.PCToLine(scope.PC)
|
||||||
if fn == nil {
|
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)
|
addrs, err := proc.FindFileLocation(t, file, loc.Line)
|
||||||
if includeNonExecutableLines {
|
if includeNonExecutableLines {
|
||||||
if _, isCouldNotFindLine := err.(*proc.ErrCouldNotFindLine); isCouldNotFindLine {
|
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) {
|
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{}
|
var locPCs map[uint64]struct{}
|
||||||
if args != "" {
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -1790,14 +1790,16 @@ func setBreakpoint(t *Term, ctx callContext, tracepoint bool, argstr string) ([]
|
|||||||
}
|
}
|
||||||
|
|
||||||
requestedBp.Tracepoint = tracepoint
|
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 != "" {
|
if findLocErr != nil && requestedBp.Name != "" {
|
||||||
requestedBp.Name = ""
|
requestedBp.Name = ""
|
||||||
spec = argstr
|
spec = argstr
|
||||||
var err2 error
|
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 {
|
if err2 == nil {
|
||||||
findLocErr = nil
|
findLocErr = nil
|
||||||
|
substSpec = substSpec2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if findLocErr != nil && shouldAskToSuspendBreakpoint(t) {
|
if findLocErr != nil && shouldAskToSuspendBreakpoint(t) {
|
||||||
@ -1824,6 +1826,9 @@ func setBreakpoint(t *Term, ctx callContext, tracepoint bool, argstr string) ([]
|
|||||||
if findLocErr != nil {
|
if findLocErr != nil {
|
||||||
return nil, findLocErr
|
return nil, findLocErr
|
||||||
}
|
}
|
||||||
|
if substSpec != "" {
|
||||||
|
spec = substSpec
|
||||||
|
}
|
||||||
|
|
||||||
created := []*api.Breakpoint{}
|
created := []*api.Breakpoint{}
|
||||||
for _, loc := range locs {
|
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
|
return loc.File, loc.Line, true, nil
|
||||||
|
|
||||||
default:
|
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 {
|
if err != nil {
|
||||||
return "", 0, false, err
|
return "", 0, false, err
|
||||||
}
|
}
|
||||||
@ -2505,7 +2510,7 @@ func disassCommand(t *Term, ctx callContext, args string) error {
|
|||||||
|
|
||||||
switch cmd {
|
switch cmd {
|
||||||
case "":
|
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 {
|
if err != nil {
|
||||||
return err
|
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)
|
disasm, disasmErr = t.client.DisassembleRange(ctx.Scope, uint64(startpc), uint64(endpc), flavor)
|
||||||
case "-l":
|
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 {
|
if err != nil {
|
||||||
return err
|
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
|
// * *<address> returns the location corresponding to the specified address
|
||||||
// NOTE: this function does not actually set breakpoints.
|
// NOTE: this function does not actually set breakpoints.
|
||||||
// If findInstruction is true FindLocation will only return locations that correspond to instructions.
|
// 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 disassemble code between startPC and endPC
|
||||||
DisassembleRange(scope api.EvalScope, startPC, endPC uint64, flavour api.AssemblyFlavour) (api.AsmInstructions, error)
|
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
|
return nil, err
|
||||||
}
|
}
|
||||||
setbp.Expr = func(t *proc.Target) []uint64 {
|
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 {
|
if err != nil || len(locs) != 1 {
|
||||||
logflags.DebuggerLogger().Debugf("could not evaluate breakpoint expression %q: %v (number of results %d)", locExpr, err, len(locs))
|
logflags.DebuggerLogger().Debugf("could not evaluate breakpoint expression %q: %v (number of results %d)", locExpr, err, len(locs))
|
||||||
return nil
|
return nil
|
||||||
@ -1921,17 +1921,17 @@ func (d *Debugger) CurrentPackage() (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FindLocation will find the location specified by 'locStr'.
|
// 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()
|
d.targetMutex.Lock()
|
||||||
defer d.targetMutex.Unlock()
|
defer d.targetMutex.Unlock()
|
||||||
|
|
||||||
if _, err := d.target.Valid(); err != nil {
|
if _, err := d.target.Valid(); err != nil {
|
||||||
return nil, err
|
return nil, "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
loc, err := locspec.Parse(locStr)
|
loc, err := locspec.Parse(locStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
return d.findLocation(goid, frame, deferredCall, locStr, loc, includeNonExecutableLines, substitutePathRules)
|
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 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{}
|
locations := []api.Location{}
|
||||||
t := proc.ValidTargets{Group: d.target}
|
t := proc.ValidTargets{Group: d.target}
|
||||||
|
subst := ""
|
||||||
for t.Next() {
|
for t.Next() {
|
||||||
pid := t.Pid()
|
pid := t.Pid()
|
||||||
s, _ := proc.ConvertEvalScope(t.Target, goid, frame, deferredCall)
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, "", err
|
||||||
}
|
}
|
||||||
for i := range locs {
|
for i := range locs {
|
||||||
if locs[i].PC == 0 {
|
if locs[i].PC == 0 {
|
||||||
@ -1977,7 +1982,7 @@ func (d *Debugger) findLocation(goid int64, frame, deferredCall int, locStr stri
|
|||||||
}
|
}
|
||||||
locations = append(locations, locs...)
|
locations = append(locations, locs...)
|
||||||
}
|
}
|
||||||
return locations, nil
|
return locations, subst, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Disassemble code between startPC and endPC.
|
// Disassemble code between startPC and endPC.
|
||||||
|
@ -306,7 +306,7 @@ type FindLocationArgs struct {
|
|||||||
|
|
||||||
func (c *RPCServer) FindLocation(args FindLocationArgs, answer *[]api.Location) error {
|
func (c *RPCServer) FindLocation(args FindLocationArgs, answer *[]api.Location) error {
|
||||||
var err 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
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -414,10 +414,10 @@ func (c *RPCClient) AttachedToExistingProcess() bool {
|
|||||||
return out.Answer
|
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
|
var out FindLocationOut
|
||||||
err := c.call("FindLocation", FindLocationIn{scope, loc, !findInstructions, substitutePathRules}, &out)
|
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
|
// DisassembleRange disassembles code between startPC and endPC
|
||||||
|
@ -706,6 +706,7 @@ type FindLocationIn struct {
|
|||||||
|
|
||||||
type FindLocationOut 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.
|
// 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.
|
// NOTE: this function does not actually set breakpoints.
|
||||||
func (c *RPCServer) FindLocation(arg FindLocationIn, out *FindLocationOut) error {
|
func (c *RPCServer) FindLocation(arg FindLocationIn, out *FindLocationOut) error {
|
||||||
var err 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
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,7 +89,7 @@ type locationFinder1 interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type locationFinder2 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 {
|
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:
|
case locationFinder1:
|
||||||
locs, err = c.FindLocation(api.EvalScope{GoroutineID: -1}, loc)
|
locs, err = c.FindLocation(api.EvalScope{GoroutineID: -1}, loc)
|
||||||
case locationFinder2:
|
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:
|
default:
|
||||||
t.Errorf("unexpected type %T passed to findLocationHelper", c)
|
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])
|
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 := "/"
|
sep := "/"
|
||||||
if strings.Contains(locsNoSubst[0].File, "\\") {
|
if strings.Contains(locsNoSubst[0].File, "\\") {
|
||||||
sep = "\\"
|
sep = "\\"
|
||||||
}
|
}
|
||||||
substRules := [][2]string{{strings.Replace(locsNoSubst[0].File, "locationsprog.go", "", 1), strings.Replace(locsNoSubst[0].File, "_fixtures"+sep+"locationsprog.go", "nonexistent", 1)}}
|
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])
|
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 {
|
if err != nil {
|
||||||
t.Fatalf("FindLocation(locationsprog.go:35) with substitute rules: %v", err)
|
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 {
|
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 {
|
if err != nil {
|
||||||
t.Fatalf("FindLocation(%q) -> error %v", loc, err)
|
t.Fatalf("FindLocation(%q) -> error %v", loc, err)
|
||||||
}
|
}
|
||||||
@ -1360,7 +1360,7 @@ func TestIssue355(t *testing.T) {
|
|||||||
assertError(err, t, "ListGoroutines()")
|
assertError(err, t, "ListGoroutines()")
|
||||||
_, err = c.Stacktrace(gid, 10, 0, &normalLoadConfig)
|
_, err = c.Stacktrace(gid, 10, 0, &normalLoadConfig)
|
||||||
assertError(err, t, "Stacktrace()")
|
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()")
|
assertError(err, t, "FindLocation()")
|
||||||
_, err = c.DisassemblePC(api.EvalScope{GoroutineID: -1}, 0x40100, api.IntelFlavour)
|
_, err = c.DisassemblePC(api.EvalScope{GoroutineID: -1}, 0x40100, api.IntelFlavour)
|
||||||
assertError(err, t, "DisassemblePC()")
|
assertError(err, t, "DisassemblePC()")
|
||||||
@ -1380,7 +1380,7 @@ func TestDisasm(t *testing.T) {
|
|||||||
state := <-ch
|
state := <-ch
|
||||||
assertNoError(state.Err, t, "Continue()")
|
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()")
|
assertNoError(err, t, "FindLocation()")
|
||||||
if len(locs) != 1 {
|
if len(locs) != 1 {
|
||||||
t.Fatalf("wrong number of locations for main.main: %d", len(locs))
|
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) {
|
func TestIssue406(t *testing.T) {
|
||||||
protest.AllowRecording(t)
|
protest.AllowRecording(t)
|
||||||
withTestClient2("issue406", t, func(c service.Client) {
|
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()")
|
assertNoError(err, t, "FindLocation()")
|
||||||
_, err = c.CreateBreakpoint(&api.Breakpoint{Addr: locs[0].PC})
|
_, err = c.CreateBreakpoint(&api.Breakpoint{Addr: locs[0].PC})
|
||||||
assertNoError(err, t, "CreateBreakpoint()")
|
assertNoError(err, t, "CreateBreakpoint()")
|
||||||
@ -2253,7 +2253,7 @@ func TestUnknownMethodCall(t *testing.T) {
|
|||||||
func TestIssue1703(t *testing.T) {
|
func TestIssue1703(t *testing.T) {
|
||||||
// Calling Disassemble when there is no current goroutine should work.
|
// Calling Disassemble when there is no current goroutine should work.
|
||||||
withTestClient2("testnextprog", t, func(c service.Client) {
|
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")
|
assertNoError(err, t, "FindLocation")
|
||||||
t.Logf("FindLocation: %#v", locs)
|
t.Logf("FindLocation: %#v", locs)
|
||||||
text, err := c.DisassemblePC(api.EvalScope{GoroutineID: -1}, locs[0].PC, api.IntelFlavour)
|
text, err := c.DisassemblePC(api.EvalScope{GoroutineID: -1}, locs[0].PC, api.IntelFlavour)
|
||||||
|
Loading…
Reference in New Issue
Block a user