Skip to content

Commit

Permalink
print function calling trees with offsets
Browse files Browse the repository at this point in the history
  • Loading branch information
jschwinger233 committed Jul 18, 2022
1 parent 1921de7 commit b1b5b08
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 66 deletions.
3 changes: 1 addition & 2 deletions internal/bpf/ufuncgraph.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,9 @@ void static backtrace(__u64 bp, struct stackwalk *walk, __u8 *bt_data, __u8 bt)
}
walk->root_bp = bp;
bp = walk->stack_id;
if (bt == 1 && walk->depth < MAX_BT_LAYERS) {
if (bt == 1 && walk->depth < MAX_BT_LAYERS)
if (bpf_probe_read_user(bt_data + walk->depth*8, sizeof(__u8)*8, (void*)bp+8) < 0)
return;
}
}
walk->depth = 0xffffffffffffffff;
return;
Expand Down
Binary file modified internal/bpf/ufuncgraph_bpfel_x86.o
Binary file not shown.
45 changes: 45 additions & 0 deletions internal/symparser/functree.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package symparser

import (
"fmt"
"strings"

log "github.com/sirupsen/logrus"
)

type FuncTree struct {
Name string
FpOffset uint64
RetOffsets []uint64
Children []*FuncTree
Err error
}

func (t *FuncTree) Traverse(f func(int, *FuncTree, *FuncTree) bool) {
t.Visit(0, nil, t, f)
}

func (t *FuncTree) Visit(layer int, parent, self *FuncTree, f func(int, *FuncTree, *FuncTree) bool) {
cont := f(layer, parent, self)
if cont {
for _, tree := range t.Children {
t.Visit(layer+1, t, tree, f)
}
}
}

func (t *FuncTree) Print(indent int) {
prefix := strings.Repeat(" ", indent)
rets := []string{}
for _, ret := range t.RetOffsets {
rets = append(rets, fmt.Sprintf("%x", ret))
}
if t.Err == nil {
log.Infof("%s%s: %x %s\n", prefix, t.Name, t.FpOffset, rets)
} else {
log.Warnf("%s%s: %s\n", prefix, t.Name, t.Err)
}
for _, tree := range t.Children {
tree.Print(indent + 2)
}
}
128 changes: 64 additions & 64 deletions internal/symparser/symparser.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package symparser

import (
"fmt"

"github.com/jschwinger233/ufuncgraph/elf"
"github.com/jschwinger233/ufuncgraph/utils"
log "github.com/sirupsen/logrus"
)

type SymParser struct {
Expand All @@ -26,87 +27,86 @@ func New(bin string) (_ *SymParser, err error) {
}

func (p *SymParser) ParseUprobes(wildcards []string, depth int, backtrace bool) (uprobes []Uprobe, err error) {
var include, exclude []string
var includes, excludes []string
for _, wc := range wildcards {
if wc[0] == '!' {
exclude = append(exclude, wc[1:])
excludes = append(excludes, wc[1:])
} else {
include = append(include, wc)
includes = append(includes, wc)
}
}
funcnames, err := p.FuncnamesMatchedWildcards(include)

funcnames, err := p.FuncnamesMatchedWildcards(includes)
if err != nil {
return
}

allFuncnameSet := map[string]interface{}{}
oriFuncnameSet := map[string]interface{}{}
trees := []*FuncTree{}
for _, funcname := range funcnames {
allFuncnameSet[funcname] = nil
oriFuncnameSet[funcname] = nil
trees = append(trees, p.ParseFuncTree(funcname, depth, excludes))
}

searched := map[string]interface{}{}
toSearch := make([]string, len(oriFuncnameSet))
copy(toSearch, funcnames)
for d := 0; d < depth; d++ {
searching := make([]string, len(toSearch))
copy(searching, toSearch)
toSearch = []string{}
for _, funcname := range searching {
searched[funcname] = nil
funcnames, err := p.FuncCalledBy(funcname)
if err != nil {
continue
visited := map[string]interface{}{}
for _, tree := range trees {
tree.Print(0)
tree.Traverse(func(layer int, parent, self *FuncTree) bool {
if _, ok := visited[self.Name]; ok {
return false
}
for _, name := range funcnames {
allFuncnameSet[name] = nil
if _, ok := searched[name]; !ok {
toSearch = append(toSearch, name)
}
}
}
}
visited[self.Name] = nil

for funcname := range allFuncnameSet {
excluded := false
for _, wc := range exclude {
if utils.MatchWildcard(wc, funcname) {
excluded = true
break
if self.Err != nil {
return true
}
}
if excluded {
continue
}
fpOffset, err := p.FuncFramePointerOffset(funcname)
if err != nil {
log.Warnf("failed to get entpoint: %s", err)
continue
}
retOffsets, err := p.FuncRetOffsets(funcname)
if err != nil {
log.Warnf("failed to get retpoints: %s", err)
continue
}
_, userSpecified := oriFuncnameSet[funcname]
uprobes = append(uprobes, Uprobe{
Funcname: funcname,
Location: AtFramePointer,
Offset: fpOffset,
UserSpecified: userSpecified,
Backtrace: userSpecified && backtrace,
})
log.Infof("added uprobe %s at framepointor: %d", funcname, fpOffset)
for _, off := range retOffsets {

userSpecified := layer == 0
uprobes = append(uprobes, Uprobe{
Funcname: funcname,
Location: AtRet,
Offset: off,
Funcname: self.Name,
Location: AtFramePointer,
Offset: self.FpOffset,
UserSpecified: userSpecified,
Backtrace: userSpecified && backtrace,
})
}
log.Infof("added uprobe %s at ret: %v", funcname, retOffsets)
for _, off := range self.RetOffsets {
uprobes = append(uprobes, Uprobe{
Funcname: self.Name,
Location: AtRet,
Offset: off,
})
}
return true
})
}

return
}

func (p *SymParser) ParseFuncTree(name string, depth int, excludes []string) (tree *FuncTree) {
tree = &FuncTree{Name: name}
funcnames, err := p.FuncCalledBy(name)
if err != nil {
tree.Err = err
return
}
tree.FpOffset, tree.Err = p.FuncFramePointerOffset(name)
if tree.Err != nil {
return
}
tree.RetOffsets, tree.Err = p.FuncRetOffsets(name)
if tree.Err != nil {
return
}
for _, wc := range excludes {
if utils.MatchWildcard(wc, name) {
tree.Err = fmt.Errorf("excluded by %s", wc)
break
}
}
if depth == 0 {
return
}
for _, funcname := range funcnames {
tree.Children = append(tree.Children, p.ParseFuncTree(funcname, depth-1, excludes))
}
return
}
1 change: 1 addition & 0 deletions internal/symparser/uprobe.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ type Uprobe struct {
Location UprobeLocation
Offset uint64
UserSpecified, Backtrace bool
FetchArgs []string
}

0 comments on commit b1b5b08

Please sign in to comment.