service/debugger: improve NomalLocationSpec.Find's heuristics (#923)

When location spec is given and the base can be interpreted either in
source file name or function name, NomalLocationSpec searches both
the source file list and the function symbol list, and selects matching
candidates. Previously, all the matching candidates were added to one
single list regardless whether the candidate was from the source file
list or not. Then, later, Find tries to guess whether the candiate
was a function or a file based on a heuristic, i.e, whether the
candidate is an absolute file path. The heuristic is fragile - since
there is no guarantee that the included source file name is an absolute
path.

Instead, this CL preserves where the candidate was found; file list or
function symbol list. Then, use that info to determine whether the
candidate is a source file name or not.
This commit is contained in:
Hyang-Ah Hana Kim 2017-07-20 15:02:59 -04:00 committed by Derek Parker
parent 0cea7ccc23
commit 809bdca191

@ -327,63 +327,66 @@ func (ale AmbiguousLocationError) Error() string {
}
func (loc *NormalLocationSpec) Find(d *Debugger, scope *proc.EvalScope, locStr string) ([]api.Location, error) {
funcs := d.target.BinInfo().Funcs()
files := d.target.BinInfo().Sources()
candidates := []string{}
for file := range files {
limit := maxFindLocationCandidates
var candidateFiles []string
for file := range d.target.BinInfo().Sources() {
if loc.FileMatch(file) {
candidates = append(candidates, file)
if len(candidates) >= maxFindLocationCandidates {
candidateFiles = append(candidateFiles, file)
if len(candidateFiles) >= limit {
break
}
}
}
limit -= len(candidateFiles)
var candidateFuncs []string
if loc.FuncBase != nil {
for _, f := range funcs {
for _, f := range d.target.BinInfo().Funcs() {
if f.Sym == nil {
continue
}
if loc.FuncBase.Match(f.Sym) {
if loc.Base == f.Name {
// if an exact match for the function name is found use it
candidates = []string{f.Name}
break
}
if len(candidates) < maxFindLocationCandidates {
candidates = append(candidates, f.Name)
}
if !loc.FuncBase.Match(f.Sym) {
continue
}
if loc.Base == f.Name {
// if an exact match for the function name is found use it
candidateFuncs = []string{f.Name}
break
}
candidateFuncs = append(candidateFuncs, f.Name)
if len(candidateFuncs) >= limit {
break
}
}
}
switch len(candidates) {
case 1:
var addr uint64
var err error
if filepath.IsAbs(candidates[0]) {
if loc.LineOffset < 0 {
return nil, fmt.Errorf("Malformed breakpoint location, no line offset specified")
}
addr, err = proc.FindFileLocation(d.target, candidates[0], loc.LineOffset)
if matching := len(candidateFiles) + len(candidateFuncs); matching == 0 {
return nil, fmt.Errorf("Location %q not found", locStr)
} else if matching > 1 {
return nil, AmbiguousLocationError{Location: locStr, CandidatesString: append(candidateFiles, candidateFuncs...)}
}
// len(candidateFiles) + len(candidateFuncs) == 1
var addr uint64
var err error
if len(candidateFiles) == 1 {
if loc.LineOffset < 0 {
return nil, fmt.Errorf("Malformed breakpoint location, no line offset specified")
}
addr, err = proc.FindFileLocation(d.target, candidateFiles[0], loc.LineOffset)
} else { // len(candidateFUncs) == 1
if loc.LineOffset < 0 {
addr, err = proc.FindFunctionLocation(d.target, candidateFuncs[0], true, 0)
} else {
if loc.LineOffset < 0 {
addr, err = proc.FindFunctionLocation(d.target, candidates[0], true, 0)
} else {
addr, err = proc.FindFunctionLocation(d.target, candidates[0], false, loc.LineOffset)
}
addr, err = proc.FindFunctionLocation(d.target, candidateFuncs[0], false, loc.LineOffset)
}
if err != nil {
return nil, err
}
return []api.Location{{PC: addr}}, nil
case 0:
return nil, fmt.Errorf("Location \"%s\" not found", locStr)
default:
return nil, AmbiguousLocationError{Location: locStr, CandidatesString: candidates}
}
if err != nil {
return nil, err
}
return []api.Location{{PC: addr}}, nil
}
func (loc *OffsetLocationSpec) Find(d *Debugger, scope *proc.EvalScope, locStr string) ([]api.Location, error) {