x/debug: change source file disambiguation heuristic.
First prefer files that match a longer suffix of the requested file.
Then break ties by choosing files that are under the directory from
which the program was compiled.
Then break ties by choosing a file with the shortest name.
Change-Id: I50b87fe4bf1fa70075e6d48032c6633c5c71f8da
Reviewed-on: https://go-review.googlesource.com/16260
Reviewed-by: Dave Day <djd@golang.org>
diff --git a/dwarf/line.go b/dwarf/line.go
index ca30b79..f035ef9 100644
--- a/dwarf/line.go
+++ b/dwarf/line.go
@@ -96,20 +96,35 @@
return nil, err
}
+ compDir := d.compilationDirectory()
+
// Find the closest match in the executable for the specified file.
// We choose the file with the largest number of path components matching
- // at the end of the name, and break ties by choosing the shortest filename.
+ // at the end of the name. If there is a tie, we prefer files that are
+ // under the compilation directory. If there is still a tie, we choose
+ // the file with the shortest name.
var bestFile struct {
fileNum uint64 // Index of the file in the DWARF data.
components int // Number of matching path components.
length int // Length of the filename.
+ underComp bool // File is under the compilation directory.
}
for num, f := range m.header.file {
c := matchingPathComponentSuffixSize(f.name, file)
- if c > bestFile.components || (c == bestFile.components && len(f.name) < bestFile.length) {
+ underComp := strings.HasPrefix(f.name, compDir)
+ better := false
+ if c != bestFile.components {
+ better = c > bestFile.components
+ } else if underComp != bestFile.underComp {
+ better = underComp
+ } else {
+ better = len(f.name) < bestFile.length
+ }
+ if better {
bestFile.fileNum = uint64(num)
bestFile.components = c
bestFile.length = len(f.name)
+ bestFile.underComp = underComp
}
}
if bestFile.components == 0 {
@@ -132,6 +147,23 @@
return pcs, nil
}
+// compilationDirectory finds the first compilation unit entry in d and returns
+// the compilation directory contained in it.
+// If it fails, it returns the empty string.
+func (d *Data) compilationDirectory() string {
+ r := d.Reader()
+ for {
+ entry, err := r.Next()
+ if entry == nil || err != nil {
+ return ""
+ }
+ if entry.Tag == TagCompileUnit {
+ name, _ := entry.Val(AttrCompDir).(string)
+ return name
+ }
+ }
+}
+
// matchingPathComponentSuffixSize returns the largest n such that the last n
// components of the paths p1 and p2 are equal.
// e.g. matchingPathComponentSuffixSize("a/b/x/y.go", "b/a/x/y.go") returns 2.