Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove inlined function PC resolution for stack traces, remove DWARF caching #32166

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions pkg/dynamicinstrumentation/di.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,7 @@ func RunDynamicInstrumentation(opts *DIOptions) (*GoDI, error) {
if err != nil {
return nil, err
}
stopFunctions := []func(){
diagnostics.StopGlobalDiagnostics,
}
stopFunctions := []func(){}
if opts.ReaderWriterOptions.CustomReaderWriters {
cm, err := diconfig.NewReaderConfigManager()
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion pkg/dynamicinstrumentation/diconfig/config_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ func (cm *RCConfigManager) installConfigProbe(procInfo *ditypes.ProcessInfo) err
svcConfigProbe := *configProbe
svcConfigProbe.ServiceName = procInfo.ServiceName
procInfo.ProbesByID[configProbe.ID] = &svcConfigProbe

log.Infof("Installing config probe for service: %s.", svcConfigProbe.ServiceName)
err = AnalyzeBinary(procInfo)
if err != nil {
return fmt.Errorf("could not analyze binary for config probe: %w", err)
Expand Down
37 changes: 8 additions & 29 deletions pkg/dynamicinstrumentation/diconfig/dwarf.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@ func getTypeMap(dwarfData *dwarf.Data, targetFunctions map[string]bool) (*ditype
return loadFunctionDefinitions(dwarfData, targetFunctions)
}

var dwarfMap = make(map[string]*dwarf.Data)

type seenTypeCounter struct {
parameter *ditypes.Parameter
count uint8
Expand All @@ -42,12 +40,12 @@ func loadFunctionDefinitions(dwarfData *dwarf.Data, targetFunctions map[string]b
var funcName string

var result = ditypes.TypeMap{
Functions: make(map[string][]ditypes.Parameter),
InlinedFunctions: make(map[uint64][]*dwarf.Entry),
Functions: make(map[string][]ditypes.Parameter),
}

var (
name string
isReturn bool
typeFields *ditypes.Parameter
)

Expand Down Expand Up @@ -83,25 +81,6 @@ entryLoop:
}
}

if entry.Tag == dwarf.TagInlinedSubroutine {
// This is a inlined function
for i := range entry.Field {
// Find it's high program counter (where it exits in the parent routine)
if entry.Field[i].Attr == dwarf.AttrHighpc {

// The field for HighPC can be a constant or address, which are int64 and uint64 respectively
if entry.Field[i].Class == dwarf.ClassConstant {
result.InlinedFunctions[uint64(entry.Field[i].Val.(int64))] =
append([]*dwarf.Entry{entry}, result.InlinedFunctions[uint64(entry.Field[i].Val.(int64))]...)
} else if entry.Field[i].Class == dwarf.ClassAddress {
result.InlinedFunctions[entry.Field[i].Val.(uint64)] =
append([]*dwarf.Entry{entry}, result.InlinedFunctions[entry.Field[i].Val.(uint64)]...)
}
}
}
continue entryLoop
}

if entry.Tag == dwarf.TagSubprogram {

for _, field := range entry.Field {
Expand Down Expand Up @@ -144,6 +123,10 @@ entryLoop:
name = entry.Field[i].Val.(string)
}

if entry.Field[i].Attr == dwarf.AttrVarParam {
isReturn = entry.Field[i].Val.(bool)
}

// Collect information about the type of this ditypes.Parameter
if entry.Field[i].Attr == dwarf.AttrType {

Expand All @@ -161,7 +144,7 @@ entryLoop:
}
}

if typeFields != nil {
if typeFields != nil && !isReturn /* we ignore return values for now */ {
// We've collected information about this ditypes.Parameter, append it to the slice of ditypes.Parameters for this function
typeFields.Name = name
result.Functions[funcName] = append(result.Functions[funcName], *typeFields)
Expand All @@ -181,19 +164,15 @@ entryLoop:
}

func loadDWARF(binaryPath string) (*dwarf.Data, error) {
if dwarfData, ok := dwarfMap[binaryPath]; ok {
return dwarfData, nil
}
elfFile, err := safeelf.Open(binaryPath)
grantseltzer marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return nil, fmt.Errorf("couldn't open elf binary: %w", err)
}

defer elfFile.Close()
dwarfData, err := elfFile.DWARF()
if err != nil {
return nil, fmt.Errorf("couldn't retrieve debug info from elf: %w", err)
}
dwarfMap[binaryPath] = dwarfData
return dwarfData, nil
}

Expand Down
7 changes: 1 addition & 6 deletions pkg/dynamicinstrumentation/ditypes/analysis.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,11 @@ import (
"fmt"
)

// TypeMap contains all the information about functions and their parameters including
// functions that have been inlined in the binary
// TypeMap contains all the information about functions and their parameters
type TypeMap struct {
// Functions maps fully-qualified function names to a slice of its parameters
Functions map[string][]Parameter

// InlinedFunctions maps program counters to a slice of dwarf entries used
// when resolving stack traces that include inlined functions
InlinedFunctions map[uint64][]*dwarf.Entry

// FunctionsByPC places DWARF subprogram (function) entries in order by
// its low program counter which is necessary for resolving stack traces
FunctionsByPC []*LowPCEntry
Expand Down
3 changes: 2 additions & 1 deletion pkg/dynamicinstrumentation/module/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ func NewModule(config *Config) (*Module, error) { //nolint:revive // TODO
ProbesFilePath: coreconfig.SystemProbe().GetString("dynamic_instrumentation.probes_file_path"),
SnapshotOutput: coreconfig.SystemProbe().GetString("dynamic_instrumentation.snapshot_output_file_path"),
DiagnosticOutput: coreconfig.SystemProbe().GetString("dynamic_instrumentation.diagnostics_output_file_path"),
}})
},
})
if err != nil {
return nil, err
}
Expand Down
44 changes: 0 additions & 44 deletions pkg/dynamicinstrumentation/uploader/stack_trace.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,23 +30,6 @@ func parseStackTrace(procInfo *ditypes.ProcessInfo, rawProgramCounters []uint64)
break
}

entries, ok := procInfo.TypeMap.InlinedFunctions[rawProgramCounters[i]]
if ok {
for n := range entries {
inlinedFuncInfo, err := pcToLine(procInfo, rawProgramCounters[i])
if err != nil {
return stackTrace, fmt.Errorf("could not resolve pc to inlined function info: %w", err)
}

symName, lineNumber, err := parseInlinedEntry(procInfo.DwarfData.Reader(), entries[n])
if err != nil {
return stackTrace, fmt.Errorf("could not get inlined entries: %w", err)
}
stackFrame := ditypes.StackFrame{Function: fmt.Sprintf("%s [inlined in %s]", symName, inlinedFuncInfo.fn), FileName: inlinedFuncInfo.file, Line: int(lineNumber)}
stackTrace = append(stackTrace, stackFrame)
}
}

funcInfo, err := pcToLine(procInfo, rawProgramCounters[i])
if err != nil {
return stackTrace, fmt.Errorf("could not resolve pc to function info: %w", err)
Expand Down Expand Up @@ -122,30 +105,3 @@ func pcToLine(procInfo *ditypes.ProcessInfo, pc uint64) (*funcInfo, error) {
fn: fn,
}, nil
}

func parseInlinedEntry(reader *dwarf.Reader, e *dwarf.Entry) (name string, line int64, err error) {

var offset dwarf.Offset

for i := range e.Field {
if e.Field[i].Attr == dwarf.AttrAbstractOrigin {
offset = e.Field[i].Val.(dwarf.Offset)
reader.Seek(offset)
entry, err := reader.Next()
if err != nil {
return "", -1, fmt.Errorf("could not read inlined function origin: %w", err)
}
for j := range entry.Field {
if entry.Field[j].Attr == dwarf.AttrName {
name = entry.Field[j].Val.(string)
}
}
}

if e.Field[i].Attr == dwarf.AttrCallLine {
line = e.Field[i].Val.(int64)
}
}

return name, line, nil
}
Loading