mirror of
				https://github.com/go-delve/delve.git
				synced 2025-10-31 18:57:18 +08:00 
			
		
		
		
	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:
		 David Chase
					David Chase
				
			
				
					committed by
					
						 Derek Parker
						Derek Parker
					
				
			
			
				
	
			
			
			 Derek Parker
						Derek Parker
					
				
			
						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) | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user