最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

golang與非golang程序探測beyla源碼解讀

 更新時間:2023年12月18日 14:06:19   作者:a朋  
這篇文章主要為大家介紹了beyla源碼解讀之golang與非golang程序的探測實(shí)例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

beyla中g(shù)olang程序與非golang程序的ebpf探測

beyla中g(shù)olang程序與非golang程序的ebpf采用了不同的探測方式

  • golang:使用uprobe監(jiān)聽用戶庫函數(shù);
  • 非golang:使用kprobe監(jiān)聽內(nèi)核函數(shù);

程序類型的定義:

// beyla/pkg/internal/svc/svc.go
type InstrumentableType int
const (
   InstrumentableGolang = InstrumentableType(iota)
   InstrumentableJava
   InstrumentableDotnet
   InstrumentablePython
   InstrumentableRuby
   InstrumentableNodejs
   InstrumentableRust
   InstrumentableGeneric
)

一.程序的區(qū)分方法

對golang與非golang程序,其區(qū)分方法是讀elf可執(zhí)行文件,然后查找symbols是否包含golang的function,以go nethttp為例:

  • 讀elf文件的symbols,然后查找其中是否有g(shù)o http的function;
  • http的function:

    • "net/http.serverHandler.ServeHTTP"
    • "net/http.(*conn).readRequest"
    • "net/http.(*response).WriteHeader"
    • "net/http.(*Transport).roundTrip"

源碼,重點(diǎn)是inspectOffset(execElf)函數(shù):

  • 讀取elf文件,解析其中的symbols;
  • 如果探測到golang的用戶函數(shù),則認(rèn)為是Golang程序;
// beyla/pkg/internal/discover/typer.go
func (t *typer) asInstrumentable(execElf *exec.FileInfo) Instrumentable {
    ...
    // look for suitable Go application first
    offsets, ok := t.inspectOffsets(execElf)
    if ok {
        // we found go offsets, let's see if this application is not a proxy
        if !isGoProxy(offsets) {
            return Instrumentable{Type: svc.InstrumentableGolang, FileInfo: execElf, Offsets: offsets}
        }
    } 
    ...
    detectedType := exec.FindProcLanguage(execElf.Pid, execElf.ELF)
    return Instrumentable{Type: detectedType, FileInfo: execElf, ChildPids: child}
}

按照注冊監(jiān)聽時的function列表,在elf中查找symbols:

  • findGoSymbolTable(elfF)負(fù)責(zé)從elf中提取symbols;
// beyla/pkg/internal/goexec/instructions.go
func instrumentationPoints(elfF *elf.File, funcNames []string) (map[string]FuncOffsets, error) {
    ...
    symTab, err := findGoSymbolTable(elfF)
    for _, f := range symTab.Funcs {
        ...
        if _, ok := functions[fName]; ok {
            offs, ok, err := findFuncOffset(&f, elfF)
            if ok {
                allOffsets[fName] = offs
            }
        }
    }
    return allOffsets, nil
}

重點(diǎn)看一下findGoSymbolTable()函數(shù)的實(shí)現(xiàn):

  • 首先,讀取elf文件中section=.gopclntab的內(nèi)容;
  • 然后,讀取elf文件中section=.text的內(nèi)容;
  • 最后,使用上面讀取的內(nèi)容,構(gòu)造symTab;
  • golang的這種elf結(jié)構(gòu),保證了:

    • 即使elf被stripped,也能通過 debug/gosym 庫,將其中的symbols讀取出來;
    • debug/gosym 是Go標(biāo)準(zhǔn)庫中的一個包,用于解析Go程序的符號表信息;
// beyla/pkg/internal/goexec/instructions.go
func findGoSymbolTable(elfF *elf.File) (*gosym.Table, error) {
    var err error
    var pclndat []byte
    // program counter line table
    if sec := elfF.Section(".gopclntab"); sec != nil {
        if pclndat, err = sec.Data(); err != nil {
            return nil, fmt.Errorf("acquiring .gopclntab data: %w", err)
        }
    }
    txtSection := elfF.Section(".text")
    pcln := gosym.NewLineTable(pclndat, txtSection.Addr)
    symTab, err := gosym.NewTable(nil, pcln)
    ...
    return symTab, nil
}

看下elf中包含的sections:

  • 可以看出,其中包gopclntab和text這兩個section;
# objdump -h example-http
example-http     文件格式 elf64-x86-64
節(jié):
Idx Name          Size      VMA               LMA               File off  Algn
  0 .text         0020e3e6  0000000000401000  0000000000401000  00001000  2**5
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .plt          00000260  000000000060f400  000000000060f400  0020f400  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  2 .rodata       000e2060  0000000000610000  0000000000610000  00210000  2**5
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  3 .dynsym       000003f0  00000000006f2940  00000000006f2940  002f2940  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
...
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 12 .gosymtab     00000000  00000000006f4a90  00000000006f4a90  002f4a90  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 13 .gopclntab    001440b0  00000000006f4aa0  00000000006f4aa0  002f4aa0  2**5
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 14 .go.buildinfo 00000140  0000000000839000  0000000000839000  00439000  2**4
                  CONTENTS, ALLOC, LOAD, DATA
...
 24 .note.go.buildid 00000064  0000000000400f80  0000000000400f80  00000f80  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA

二.golang與非golang程序的監(jiān)聽探針

golang與非golang程序使用了不同的ebpf監(jiān)聽方法。

  • golang程序:使用newGoTracerGroup()注冊tracer的方法;
  • 非golang程序:使用newNonGoTracersGroup()注冊tracer的方法;
// beyla/pkg/internal/discover/attacher.go
func (ta *TraceAttacher) getTracer(ie *Instrumentable) (*ebpf.ProcessTracer, bool) {
    ...
    var programs []ebpf.Tracer
    switch ie.Type {
    case svc.InstrumentableGolang:
        ...
        tracerType = ebpf.Go
        programs = filterNotFoundPrograms(newGoTracersGroup(ta.Cfg, ta.Metrics), ie.Offsets)
    case svc.InstrumentableJava, svc.InstrumentableNodejs, svc.InstrumentableRuby, svc.InstrumentablePython, svc.InstrumentableDotnet, svc.InstrumentableGeneric, svc.InstrumentableRust:
        ...
        programs = newNonGoTracersGroup(ta.Cfg, ta.Metrics)
    }
    ...
}

1.golang程序的tracer:

// beyla/pkg/internal/discover/finder.go
func newGoTracersGroup(cfg *pipe.Config, metrics imetrics.Reporter) []ebpf.Tracer {
    // Each program is an eBPF source: net/http, grpc...
    return []ebpf.Tracer{
        nethttp.New(&cfg.EBPF, metrics),
        &nethttp.GinTracer{Tracer: *nethttp.New(&cfg.EBPF, metrics)},
        grpc.New(&cfg.EBPF, metrics),
        goruntime.New(&cfg.EBPF, metrics),
        gosql.New(&cfg.EBPF, metrics),
    }
}

以nethttp為例,ebpf監(jiān)聽的用戶庫函數(shù):

// beyla/pkg/internal/ebpf/nethttp/nethttp.go
func (p *Tracer) GoProbes() map[string]ebpfcommon.FunctionPrograms {
   return map[string]ebpfcommon.FunctionPrograms{
      "net/http.serverHandler.ServeHTTP": {
         Start: p.bpfObjects.UprobeServeHTTP,
      },
      "net/http.(*conn).readRequest": {
         End: p.bpfObjects.UprobeReadRequestReturns,
      },
      "net/http.(*response).WriteHeader": {
         Start: p.bpfObjects.UprobeWriteHeader,
      },
      "net/http.(*Transport).roundTrip": { // HTTP client, works with Client.Do as well as using the RoundTripper directly
         Start: p.bpfObjects.UprobeRoundTrip,
         End:   p.bpfObjects.UprobeRoundTripReturn,
      },
   }
}

2.非golang程序的tracer:

// beyla/pkg/internal/discover/finder.go
func newNonGoTracersGroup(cfg *pipe.Config, metrics imetrics.Reporter) []ebpf.Tracer {
    return []ebpf.Tracer{httpfltr.New(cfg, metrics), httpssl.New(cfg, metrics)}
}

進(jìn)入到httpfltr查看監(jiān)聽的kprobe函數(shù):

// beyla/pkg/internal/ebpf/httpfltr/httpfltr.go
func (p *Tracer) KProbes() map[string]ebpfcommon.FunctionPrograms {
   return map[string]ebpfcommon.FunctionPrograms{
      // Both sys accept probes use the same kretprobe.
      // We could tap into __sys_accept4, but we might be more prone to
      // issues with the internal kernel code changing.
      "sys_accept": {
         Required: true,
         End:      p.bpfObjects.KretprobeSysAccept4,
      },
      "sys_accept4": {
         Required: true,
         End:      p.bpfObjects.KretprobeSysAccept4,
      },
      "sock_alloc": {
         Required: true,
         End:      p.bpfObjects.KretprobeSockAlloc,
      },
      "tcp_rcv_established": {
         Required: true,
         Start:    p.bpfObjects.KprobeTcpRcvEstablished,
      },
      // Tracking of HTTP client calls, by tapping into connect
      "sys_connect": {
         Required: true,
         End:      p.bpfObjects.KretprobeSysConnect,
      },
      "tcp_connect": {
         Required: true,
         Start:    p.bpfObjects.KprobeTcpConnect,
      },
      "tcp_sendmsg": {
         Required: true,
         Start:    p.bpfObjects.KprobeTcpSendmsg,
      },
      // Reading more than 160 bytes
      "tcp_recvmsg": {
         Required: true,
         Start:    p.bpfObjects.KprobeTcpRecvmsg,
         End:      p.bpfObjects.KretprobeTcpRecvmsg,
      },
   }
}

參考:http://m.fzitv.net/article/264383.htm

以上就是golang與非golang程序探測beyla源碼解讀的詳細(xì)內(nèi)容,更多關(guān)于golang beyla程序探測的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 深入解析如何基于go-retry構(gòu)建靈活安全和高效的重試邏輯

    深入解析如何基于go-retry構(gòu)建靈活安全和高效的重試邏輯

    本文將深入解析 sethvargo/go-retry 這個輕量且強(qiáng)大的 Go 重試庫,帶大家從原理到實(shí)踐,構(gòu)建靈活、安全、高效的重試邏輯,感興趣的小伙伴可以了解下
    2025-11-11
  • 快速上手GO的net/http包

    快速上手GO的net/http包

    本文主要介紹了快速上手GO的net/http包,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2025-05-05
  • Golang調(diào)度器GMP原理小結(jié)

    Golang調(diào)度器GMP原理小結(jié)

    本文主要介紹了Golang調(diào)度器GMP原理小結(jié),詳細(xì)描述了Goroutine的創(chuàng)建、執(zhí)行、阻塞、喚醒等場景下的調(diào)度過程,下面就來一起了解一下
    2026-04-04
  • Go 實(shí)現(xiàn)一次性打包各個平臺的可執(zhí)行程序

    Go 實(shí)現(xiàn)一次性打包各個平臺的可執(zhí)行程序

    這篇文章主要介紹了Go 實(shí)現(xiàn)一次性打包各個平臺的可執(zhí)行程序,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • Go實(shí)現(xiàn)跨平臺的藍(lán)牙聊天室示例詳解

    Go實(shí)現(xiàn)跨平臺的藍(lán)牙聊天室示例詳解

    這篇文章主要為大家介紹了Go實(shí)現(xiàn)跨平臺的藍(lán)牙聊天室示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-12-12
  • GoLang分布式鎖與snowflake雪花算法

    GoLang分布式鎖與snowflake雪花算法

    這篇文章主要介紹了GoLang分布式鎖與snowflake雪花算法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2022-12-12
  • Go語言算法之尋找數(shù)組第二大元素的方法

    Go語言算法之尋找數(shù)組第二大元素的方法

    這篇文章主要介紹了Go語言算法之尋找數(shù)組第二大元素的方法,以實(shí)例形式分析了不排序、只循環(huán)一次來實(shí)現(xiàn)尋找數(shù)組第二大元素的技巧,是比較典型的算法,需要的朋友可以參考下
    2015-02-02
  • 基于Go Int轉(zhuǎn)string幾種方式性能測試

    基于Go Int轉(zhuǎn)string幾種方式性能測試

    這篇文章主要介紹了Go Int轉(zhuǎn)string幾種方式測試,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-04-04
  • Golang開發(fā)之接口的具體使用詳解

    Golang開發(fā)之接口的具體使用詳解

    在 Golang 中,接口是一種類型,它是由一組方法簽名組成的抽象集合。這篇文章主要為大家介紹了Golang接口的具體使用,希望對大家有所幫助
    2023-04-04
  • 深入理解golang的基本類型排序與slice排序

    深入理解golang的基本類型排序與slice排序

    大家都知道排序有內(nèi)部排序和外部排序,內(nèi)部排序是數(shù)據(jù)記錄在內(nèi)存中進(jìn)行排序,而外部排序是因排序的數(shù)據(jù)很大,一次不能容納全部的排序記錄,在排序過程中需要訪問外存。下面就來詳細(xì)介紹golang的基本類型排序與slice排序,有需要的朋友們可以參考借鑒。
    2016-09-09

最新評論

高安市| 景谷| 铜梁县| 丰镇市| 当阳市| 纳雍县| 长子县| 六枝特区| 台北市| 大悟县| 青海省| 吉隆县| 浦北县| 广东省| 牟定县| 武川县| 兴文县| 鄂托克旗| 桐乡市| 岳阳县| 达孜县| 安宁市| 马关县| 呈贡县| 丹寨县| 冀州市| 南溪县| 卫辉市| 阜新| 盱眙县| 康平县| 濮阳市| 恩平市| 勃利县| 云安县| 海伦市| 陇西县| 兴化市| 怀集县| 昌乐县| 双鸭山市|