| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210 |
- package ebpftracer
- import (
- "context"
- "debug/elf"
- debugelf "debug/elf"
- "fmt"
- "io"
- "log"
- "os"
- "regexp"
- "sort"
- "strconv"
- "github.com/cilium/ebpf"
- "github.com/cilium/ebpf/link"
- "github.com/coroot/coroot-node-agent/ebpftracer/tracer"
- "github.com/coroot/coroot-node-agent/proc"
- "golang.org/x/sync/semaphore"
- )
- func (t *Tracer) stack() error {
- // uprobes := []tracer.Uprobe{}
- if t.disableL7Tracing {
- return nil
- }
- ENV_PID := os.Getenv("FILTER_PID")
- WHITE_LIST := os.Getenv("WHITE_LIST")
- if ENV_PID == "" {
- return nil
- }
- MatchString := ".*HandleFunc|.*main.*|testfun.*|.*serverHandler.*|.*ServeHTTP.*"
- if WHITE_LIST != "" {
- MatchString = WHITE_LIST
- }
- fmt.Println("UprobesMatchString::: init", MatchString)
- pid, _ := strconv.ParseInt(ENV_PID, 10, 32)
- path := proc.Path(uint32(pid), "exe")
- t.Uprobes, _ = t.getUprobes(path, MatchString)
- t.UprobesMap = map[string]tracer.Uprobe{}
- fmt.Println("UprobesMap::: init")
- for _, up := range t.Uprobes {
- fmt.Println("UprobesMap:::", up.Funcname)
- t.UprobesMap[fmt.Sprintf("%s", up.Funcname)] = up
- }
- links := t.attachUprobes(path, t.Uprobes)
- t.links = append(t.links, links...)
- // defer t.detachUprobes(links)
- return nil
- }
- func (t *Tracer) getUprobes(path string, MatchString string) ([]tracer.Uprobe, error) {
- uprobes := []tracer.Uprobe{}
- binFile, err := os.Open(path)
- if err != nil {
- return nil, err
- }
- // cache := map[string]interface{}{}
- // 解析 elf 文件
- elfFile, _ := debugelf.NewFile(binFile)
- // 获取所有符号表
- symbols, _ := elfFile.Symbols()
- sort.Slice(symbols, func(i, j int) bool { return symbols[i].Value < symbols[j].Value })
- t.Symbols = symbols
- // 符号表组装成键值 map,方便使用
- symnames := map[string]debugelf.Symbol{}
- for _, symbol := range symbols {
- fmt.Println(symbol.Name, symbol)
- symnames[symbol.Name] = symbol
- }
- textSection := elfFile.Section(".text")
- if textSection == nil {
- fmt.Println("no text section", nil)
- return nil, nil
- }
- textSectionData, err := textSection.Data()
- if err != nil {
- fmt.Println("failed to read text section", err)
- return nil, nil
- }
- textSectionLen := uint64(len(textSectionData) - 1)
- // 遍历符号表
- for _, symbol := range symbols {
- if debugelf.ST_TYPE(symbol.Info) != debugelf.STT_FUNC {
- continue
- }
- // fmt.Println("Hello FunName: ", symbol.Name)
- // 使用正则表达式匹配函数白名单列表
- found, err := regexp.MatchString(MatchString, symbol.Name)
- // found, err := regexp.MatchString("main.*", symbol.Name)
- if err != nil {
- log.Fatal(err)
- }
- if found {
- // 匹配到了加入 attachFuncs 列表
- fmt.Println("Fuck This: ", symbol.Name)
- // attachFuncs = append(attachFuncs, symbol.Name)
- // 根据函数名拿到当前函数的符号结构体
- sym := symnames[symbol.Name]
- if err != nil {
- fmt.Printf("symnames[symbol.Name]", symbol.Name, err)
- return nil, err
- }
- address := sym.Value
- for _, p := range elfFile.Progs {
- if p.Type != elf.PT_LOAD || (p.Flags&elf.PF_X) == 0 {
- continue
- }
- if p.Vaddr <= sym.Value && sym.Value < (p.Vaddr+p.Memsz) {
- address = sym.Value - p.Vaddr + p.Off
- break
- }
- }
- // 函数入口加入待 attach 列表
- uprobes = append(uprobes, tracer.Uprobe{
- Funcname: symbol.Name, // 函数名
- Location: tracer.AtEntry, // 入口
- Address: address, // 函数地址
- AbsOffset: 0, // 函数相对 ELF 偏移
- RelOffset: 0, // 函数真实偏移
- Wanted: true,
- })
- sStart := sym.Value - textSection.Addr
- sEnd := sStart + sym.Size
- if sEnd > textSectionLen {
- continue
- }
- sBytes := textSectionData[sStart:sEnd]
- returnOffsets := getReturnOffsets(elfFile.Machine, sBytes)
- for _, offset := range returnOffsets {
- uprobes = append(uprobes, tracer.Uprobe{
- Funcname: symbol.Name,
- Location: tracer.AtRet,
- Address: address,
- AbsOffset: uint64(offset),
- RelOffset: 0,
- })
- }
- }
- }
- return uprobes, nil
- }
- func (t *Tracer) attachUprobes(path string, uprobes []tracer.Uprobe) []link.Link {
- var links []link.Link
- ex, err := link.OpenExecutable(path)
- if err != nil {
- return nil
- }
- fmt.Println("AttachAttachAttach", path)
- for i, up := range t.uprobes {
- fmt.Println("attachingERROR---", i, up)
- }
- for i, up := range uprobes {
- fmt.Printf("attaching %d -> %d -> %s -> 0x%x -> 0x%x\n", i, len(uprobes), up.Funcname, up.AbsOffset, up.Address)
- var prog *ebpf.Program
- switch up.Location {
- case tracer.AtEntry:
- prog = t.uprobes["ent"]
- case tracer.AtRet:
- prog = t.uprobes["ret"]
- }
- fmt.Println("progprogprogprogprogprog---", prog)
- up, err := ex.Uprobe(up.Funcname, prog, &link.UprobeOptions{Address: up.Address, Offset: up.AbsOffset})
- if err != nil {
- fmt.Println("attachingERROR", err)
- // return nil
- } else {
- links = append(links, up)
- }
- }
- return links
- }
- func (t *Tracer) detachUprobes(links []link.Link) {
- sem := semaphore.NewWeighted(10)
- for i, closer := range links {
- fmt.Printf("detaching %d/%d\r", i+1, len(links))
- sem.Acquire(context.Background(), 1)
- go func(closer io.Closer) {
- defer sem.Release(1)
- closer.Close()
- }(closer)
- }
- fmt.Println()
- }
|