Skip to content

Commit

Permalink
Handle one file at a time in local symbolization. (#848)
Browse files Browse the repository at this point in the history
This allows only keeping a single objfile open.
  • Loading branch information
aalexand authored Apr 22, 2024
1 parent 26353dc commit 6d00f21
Showing 1 changed file with 71 additions and 106 deletions.
177 changes: 71 additions & 106 deletions internal/symbolizer/symbolizer.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,22 +133,80 @@ func doLocalSymbolize(prof *profile.Profile, fast, force bool, obj plugin.ObjToo
}
}

mt, err := newMapping(prof, obj, ui, force)
if err != nil {
return err
functions := map[profile.Function]*profile.Function{}
addFunction := func(f *profile.Function) *profile.Function {
if fp := functions[*f]; fp != nil {
return fp
}
functions[*f] = f
f.ID = uint64(len(prof.Function)) + 1
prof.Function = append(prof.Function, f)
return f
}

missingBinaries := false
mappingLocs := map[*profile.Mapping][]*profile.Location{}
for _, l := range prof.Location {
mappingLocs[l.Mapping] = append(mappingLocs[l.Mapping], l)
}
defer mt.close()
for midx, m := range prof.Mapping {
locs := mappingLocs[m]
if len(locs) == 0 {
// The mapping is dangling and has no locations pointing to it.
continue
}
// Do not attempt to re-symbolize a mapping that has already been symbolized.
if !force && (m.HasFunctions || m.HasFilenames || m.HasLineNumbers) {
continue
}
if m.File == "" {
if midx == 0 {
ui.PrintErr("Main binary filename not available.")
continue
}
missingBinaries = true
continue
}
if m.Unsymbolizable() {
// Skip well-known system mappings
continue
}
if m.BuildID == "" {
if u, err := url.Parse(m.File); err == nil && u.IsAbs() && strings.Contains(strings.ToLower(u.Scheme), "http") {
// Skip mappings pointing to a source URL
continue
}
}

functions := make(map[profile.Function]*profile.Function)
for _, l := range mt.prof.Location {
m := l.Mapping
segment := mt.segments[m]
if segment == nil {
// Nothing to do.
name := filepath.Base(m.File)
if m.BuildID != "" {
name += fmt.Sprintf(" (build ID %s)", m.BuildID)
}
f, err := obj.Open(m.File, m.Start, m.Limit, m.Offset, m.KernelRelocationSymbol)
if err != nil {
ui.PrintErr("Local symbolization failed for ", name, ": ", err)
missingBinaries = true
continue
}
if fid := f.BuildID(); m.BuildID != "" && fid != "" && fid != m.BuildID {
ui.PrintErr("Local symbolization failed for ", name, ": build ID mismatch")
f.Close()
continue
}
symbolizeOneMapping(m, locs, f, addFunction)
f.Close()
}

stack, err := segment.SourceLine(l.Address)
if missingBinaries {
ui.PrintErr("Some binary filenames not available. Symbolization may be incomplete.\n" +
"Try setting PPROF_BINARY_PATH to the search path for local binaries.")
}
return nil
}

func symbolizeOneMapping(m *profile.Mapping, locs []*profile.Location, obj plugin.ObjFile, addFunction func(*profile.Function) *profile.Function) {
for _, l := range locs {
stack, err := obj.SourceLine(l.Address)
if err != nil || len(stack) == 0 {
// No answers from addr2line.
continue
Expand All @@ -166,18 +224,11 @@ func doLocalSymbolize(prof *profile.Profile, fast, force bool, obj plugin.ObjToo
if frame.Line != 0 {
m.HasLineNumbers = true
}
f := &profile.Function{
f := addFunction(&profile.Function{
Name: frame.Func,
SystemName: frame.Func,
Filename: frame.File,
}
if fp := functions[*f]; fp != nil {
f = fp
} else {
functions[*f] = f
f.ID = uint64(len(mt.prof.Function)) + 1
mt.prof.Function = append(mt.prof.Function, f)
}
})
l.Line[i] = profile.Line{
Function: f,
Line: int64(frame.Line),
Expand All @@ -189,8 +240,6 @@ func doLocalSymbolize(prof *profile.Profile, fast, force bool, obj plugin.ObjToo
m.HasInlineFrames = true
}
}

return nil
}

// Demangle updates the function names in a profile with demangled C++
Expand Down Expand Up @@ -294,87 +343,3 @@ func removeMatching(name string, start, end byte) string {
}
return name
}

// newMapping creates a mappingTable for a profile.
func newMapping(prof *profile.Profile, obj plugin.ObjTool, ui plugin.UI, force bool) (*mappingTable, error) {
mt := &mappingTable{
prof: prof,
segments: make(map[*profile.Mapping]plugin.ObjFile),
}

// Identify used mappings
mappings := make(map[*profile.Mapping]bool)
for _, l := range prof.Location {
mappings[l.Mapping] = true
}

missingBinaries := false
for midx, m := range prof.Mapping {
if !mappings[m] {
continue
}

// Do not attempt to re-symbolize a mapping that has already been symbolized.
if !force && (m.HasFunctions || m.HasFilenames || m.HasLineNumbers) {
continue
}

if m.File == "" {
if midx == 0 {
ui.PrintErr("Main binary filename not available.")
continue
}
missingBinaries = true
continue
}

// Skip well-known system mappings
if m.Unsymbolizable() {
continue
}

// Skip mappings pointing to a source URL
if m.BuildID == "" {
if u, err := url.Parse(m.File); err == nil && u.IsAbs() && strings.Contains(strings.ToLower(u.Scheme), "http") {
continue
}
}

name := filepath.Base(m.File)
if m.BuildID != "" {
name += fmt.Sprintf(" (build ID %s)", m.BuildID)
}
f, err := obj.Open(m.File, m.Start, m.Limit, m.Offset, m.KernelRelocationSymbol)
if err != nil {
ui.PrintErr("Local symbolization failed for ", name, ": ", err)
missingBinaries = true
continue
}
if fid := f.BuildID(); m.BuildID != "" && fid != "" && fid != m.BuildID {
ui.PrintErr("Local symbolization failed for ", name, ": build ID mismatch")
f.Close()
continue
}

mt.segments[m] = f
}
if missingBinaries {
ui.PrintErr("Some binary filenames not available. Symbolization may be incomplete.\n" +
"Try setting PPROF_BINARY_PATH to the search path for local binaries.")
}
return mt, nil
}

// mappingTable contains the mechanisms for symbolization of a
// profile.
type mappingTable struct {
prof *profile.Profile
segments map[*profile.Mapping]plugin.ObjFile
}

// close releases any external processes being used for the mapping.
func (mt *mappingTable) close() {
for _, segment := range mt.segments {
segment.Close()
}
}

0 comments on commit 6d00f21

Please sign in to comment.