Skip to content

Commit

Permalink
Remove inlined function PC resolution for stack traces, remove DWARF …
Browse files Browse the repository at this point in the history
…caching (DataDog#32166)

Signed-off-by: grantseltzer <[email protected]>
  • Loading branch information
grantseltzer authored Dec 24, 2024
1 parent 407d013 commit 272716f
Show file tree
Hide file tree
Showing 6 changed files with 13 additions and 84 deletions.
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)
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
}

0 comments on commit 272716f

Please sign in to comment.