proc: added *BinaryInfo.AllPCsForFileLine for faster bulk queries (#1592)
Support for bulk queries makes the DWARF quality checker (github.com/dr2chase/dwarf-goodness/cmd/dwarf-goodness) run much more efficiently (replace quadratic cost with linear).
This commit is contained in:
parent
7afda8dbe0
commit
a25d2a2b24
@ -136,6 +136,36 @@ func (lineInfo *DebugLineInfo) AllPCsForFileLine(f string, l int) (pcs []uint64)
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AllPCsForFileLines Adds all PCs for a given file and set (domain of map) of lines
|
||||||
|
// to the map value corresponding to each line.
|
||||||
|
func (lineInfo *DebugLineInfo) AllPCsForFileLines(f string, m map[int][]uint64) {
|
||||||
|
if lineInfo == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
lastAddr uint64
|
||||||
|
sm = newStateMachine(lineInfo, lineInfo.Instructions)
|
||||||
|
)
|
||||||
|
|
||||||
|
for {
|
||||||
|
if err := sm.next(); err != nil {
|
||||||
|
if lineInfo.Logf != nil {
|
||||||
|
lineInfo.Logf("AllPCsForFileLine error: %v", err)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if sm.address != lastAddr && sm.isStmt && sm.valid && sm.file == f {
|
||||||
|
if pcs, ok := m[sm.line]; ok {
|
||||||
|
pcs = append(pcs, sm.address)
|
||||||
|
m[sm.line] = pcs
|
||||||
|
lastAddr = sm.address
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
var NoSourceError = errors.New("no source available")
|
var NoSourceError = errors.New("no source available")
|
||||||
|
|
||||||
// AllPCsBetween returns all PC addresses between begin and end (including both begin and end) that have the is_stmt flag set and do not belong to excludeFile:excludeLine
|
// AllPCsBetween returns all PC addresses between begin and end (including both begin and end) that have the is_stmt flag set and do not belong to excludeFile:excludeLine
|
||||||
|
@ -406,6 +406,20 @@ func (bi *BinaryInfo) AllPCsForFileLine(filename string, lineno int) []uint64 {
|
|||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AllPCsForFileLines returns a map providing all PC addresses for filename and each line in linenos
|
||||||
|
func (bi *BinaryInfo) AllPCsForFileLines(filename string, linenos []int) map[int][]uint64 {
|
||||||
|
r := make(map[int][]uint64)
|
||||||
|
for _, line := range linenos {
|
||||||
|
r[line] = make([]uint64, 0, 1)
|
||||||
|
}
|
||||||
|
for _, cu := range bi.compileUnits {
|
||||||
|
if cu.lineInfo.Lookup[filename] != nil {
|
||||||
|
cu.lineInfo.AllPCsForFileLines(filename, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
// PCToFunc returns the function containing the given PC address
|
// PCToFunc returns the function containing the given PC address
|
||||||
func (bi *BinaryInfo) PCToFunc(pc uint64) *Function {
|
func (bi *BinaryInfo) PCToFunc(pc uint64) *Function {
|
||||||
i := sort.Search(len(bi.Functions), func(i int) bool {
|
i := sort.Search(len(bi.Functions), func(i int) bool {
|
||||||
|
@ -3629,6 +3629,27 @@ func checkFrame(frame proc.Stackframe, fnname, file string, line int, inlined bo
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAllPCsForFileLines(t *testing.T) {
|
||||||
|
if ver, _ := goversion.Parse(runtime.Version()); ver.Major >= 0 && !ver.AfterOrEqual(goversion.GoVersion{1, 10, -1, 0, 0, ""}) {
|
||||||
|
// Versions of go before 1.10 do not have DWARF information for inlined calls
|
||||||
|
t.Skip("inlining not supported")
|
||||||
|
}
|
||||||
|
withTestProcessArgs("testinline", t, ".", []string{}, protest.EnableInlining, func(p proc.Process, fixture protest.Fixture) {
|
||||||
|
l2pcs := p.BinInfo().AllPCsForFileLines(fixture.Source, []int{7, 20})
|
||||||
|
if len(l2pcs) != 2 {
|
||||||
|
t.Fatalf("expected two map entries for %s:{%d,%d} (got %d: %v)", fixture.Source, 7, 20, len(l2pcs), l2pcs)
|
||||||
|
}
|
||||||
|
pcs := l2pcs[20]
|
||||||
|
if len(pcs) < 1 {
|
||||||
|
t.Fatalf("expected at least one location for %s:%d (got %d: %#x)", fixture.Source, 20, len(pcs), pcs)
|
||||||
|
}
|
||||||
|
pcs = l2pcs[7]
|
||||||
|
if len(pcs) < 2 {
|
||||||
|
t.Fatalf("expected at least two locations for %s:%d (got %d: %#x)", fixture.Source, 7, len(pcs), pcs)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestInlinedStacktraceAndVariables(t *testing.T) {
|
func TestInlinedStacktraceAndVariables(t *testing.T) {
|
||||||
if ver, _ := goversion.Parse(runtime.Version()); ver.Major >= 0 && !ver.AfterOrEqual(goversion.GoVersion{1, 10, -1, 0, 0, ""}) {
|
if ver, _ := goversion.Parse(runtime.Version()); ver.Major >= 0 && !ver.AfterOrEqual(goversion.GoVersion{1, 10, -1, 0, 0, ""}) {
|
||||||
// Versions of go before 1.10 do not have DWARF information for inlined calls
|
// Versions of go before 1.10 do not have DWARF information for inlined calls
|
||||||
@ -3680,7 +3701,7 @@ func TestInlinedStacktraceAndVariables(t *testing.T) {
|
|||||||
withTestProcessArgs("testinline", t, ".", []string{}, protest.EnableInlining, func(p proc.Process, fixture protest.Fixture) {
|
withTestProcessArgs("testinline", t, ".", []string{}, protest.EnableInlining, func(p proc.Process, fixture protest.Fixture) {
|
||||||
pcs := p.BinInfo().AllPCsForFileLine(fixture.Source, 7)
|
pcs := p.BinInfo().AllPCsForFileLine(fixture.Source, 7)
|
||||||
if len(pcs) < 2 {
|
if len(pcs) < 2 {
|
||||||
t.Fatalf("expected at least two locations for %s:%d (got %d: %#x)", fixture.Source, 6, len(pcs), pcs)
|
t.Fatalf("expected at least two locations for %s:%d (got %d: %#x)", fixture.Source, 7, len(pcs), pcs)
|
||||||
}
|
}
|
||||||
for _, pc := range pcs {
|
for _, pc := range pcs {
|
||||||
t.Logf("setting breakpoint at %#x\n", pc)
|
t.Logf("setting breakpoint at %#x\n", pc)
|
||||||
|
Loading…
Reference in New Issue
Block a user