|
|
@@ -12,6 +12,7 @@ import (
|
|
|
"strconv"
|
|
|
"strings"
|
|
|
|
|
|
+ "github.com/cilium/ebpf"
|
|
|
"github.com/cilium/ebpf/link"
|
|
|
"github.com/coroot/coroot-node-agent/ebpftracer/tracer"
|
|
|
"github.com/coroot/coroot-node-agent/proc"
|
|
|
@@ -29,6 +30,7 @@ const (
|
|
|
goExecute = "runtime.execute"
|
|
|
goNewproc1 = "runtime.newproc1"
|
|
|
goRunqget = "runtime.runqget"
|
|
|
+ goGoready = "runtime.goready"
|
|
|
goServeHTTP = "net/http.serverHandler.ServeHTTP"
|
|
|
goTransport = "net/http.(*Transport).roundTrip"
|
|
|
goHeaderWriteSubset = "net/http.Header.writeSubset"
|
|
|
@@ -38,6 +40,9 @@ const (
|
|
|
goGrpcClientConnInvoke = "google.golang.org/grpc.(*ClientConn).Invoke"
|
|
|
goGrpcClientLoopyHeaderHandler = "google.golang.org/grpc/internal/transport.(*loopyWriter).headerHandler"
|
|
|
goGrpcHttp2ClientNewStream = "google.golang.org/grpc/internal/transport.(*http2Client).NewStream"
|
|
|
+ goReadContinuedLineSlice = "net/textproto.(*Reader).readContinuedLineSlice"
|
|
|
+ goGocqlSessionExecuteQuery = "github.com/gocql/gocql.(*Session).executeQuery"
|
|
|
+ goGocqlSessionExecuteQueryV2 = "github.com/apache/cassandra-gocql-driver/v2.(*Session).executeQuery"
|
|
|
)
|
|
|
|
|
|
var (
|
|
|
@@ -141,6 +146,8 @@ func (t *Tracer) AttachGoTlsUprobes(pid uint32, appInfo *AppInfo, codeType uint1
|
|
|
appID := appInfo.AppIdHash.HashtVal
|
|
|
var err error
|
|
|
var name, version string
|
|
|
+ var major, minor, revision int
|
|
|
+
|
|
|
log := func(msg string, err error) {
|
|
|
if err != nil {
|
|
|
for _, s := range []string{"not a Go executable", "no such file or directory", "no such process", "permission denied"} {
|
|
|
@@ -182,7 +189,7 @@ func (t *Tracer) AttachGoTlsUprobes(pid uint32, appInfo *AppInfo, codeType uint1
|
|
|
symbols, err := ef.Symbols()
|
|
|
if err != nil {
|
|
|
if errors.Is(err, elf.ErrNoSymbols) {
|
|
|
- log("no symbol section", nil)
|
|
|
+ log("no symbol section", err)
|
|
|
return nil, err
|
|
|
}
|
|
|
log("failed to read symbols", err)
|
|
|
@@ -191,7 +198,7 @@ func (t *Tracer) AttachGoTlsUprobes(pid uint32, appInfo *AppInfo, codeType uint1
|
|
|
|
|
|
textSection := ef.Section(".text")
|
|
|
if textSection == nil {
|
|
|
- log("no text section", nil)
|
|
|
+ log("no text section", err)
|
|
|
return nil, err
|
|
|
}
|
|
|
textSectionData, err := textSection.Data()
|
|
|
@@ -248,12 +255,130 @@ func (t *Tracer) AttachGoTlsUprobes(pid uint32, appInfo *AppInfo, codeType uint1
|
|
|
}
|
|
|
|
|
|
offset, ok := tracer.GetOffset(tracer.NewID("std", "runtime", "g", "goid"), path)
|
|
|
+ if ok {
|
|
|
+ klog.Infof("[AttachGoTlsUprobes] STEP 11.1: Successfully got goid offset=%d", offset)
|
|
|
+ } else {
|
|
|
+ klog.Errorf("[AttachGoTlsUprobes] STEP 11.2: Failed to get goid offset, pid=%d, version=%s", pid, bi.GoVersion)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取 runtime.p.goidcache 偏移量
|
|
|
+ klog.Infof("[AttachGoTlsUprobes] STEP 11.3: Getting offset for runtime.p.goidcache")
|
|
|
+ goidcacheOffset, okGoidcache := tracer.GetOffset(tracer.NewID("std", "runtime", "p", "goidcache"), path)
|
|
|
+ if okGoidcache {
|
|
|
+ klog.Infof("[AttachGoTlsUprobes] STEP 11.4: Successfully got goidcache offset=%d", goidcacheOffset)
|
|
|
+ } else {
|
|
|
+ klog.Warnf("[AttachGoTlsUprobes] STEP 11.5: Failed to get goidcache offset, pid=%d, version=%s, using fallback", pid, bi.GoVersion)
|
|
|
+ goidcacheOffset = 384 // fallback value
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取 runtime.p.runnext 偏移量
|
|
|
+ klog.Infof("[AttachGoTlsUprobes] STEP 11.6: Getting offset for runtime.p.runnext")
|
|
|
+ runnextOffset, okRunnext := tracer.GetOffset(tracer.NewID("std", "runtime", "p", "runnext"), path)
|
|
|
+ if okRunnext {
|
|
|
+ klog.Infof("[AttachGoTlsUprobes] STEP 11.7: Successfully got runnext offset=%d", runnextOffset)
|
|
|
+ } else {
|
|
|
+ klog.Warnf("[AttachGoTlsUprobes] STEP 11.8: Failed to get runnext offset, pid=%d, version=%s, using fallback", pid, bi.GoVersion)
|
|
|
+ runnextOffset = 2456 // fallback value
|
|
|
+ }
|
|
|
+
|
|
|
+ klog.Infof("[AttachGoTlsUprobes] STEP 12: Getting offset for runtime.hmap.buckets")
|
|
|
bucketsOff, ok2 := tracer.GetOffset(tracer.NewID("std", "runtime", "hmap", "buckets"), path)
|
|
|
|
|
|
- if ok && ok2 {
|
|
|
+ // Go 1.24+ 使用新的 map 实现(Swiss Tables),使用 internal/runtime/maps.Map 而不是 runtime.hmap
|
|
|
+ if !ok2 {
|
|
|
+ klog.Errorf("[AttachGoTlsUprobes] STEP 12.2: Failed to get buckets offset, pid=%d, version=%s", pid, bi.GoVersion)
|
|
|
+ klog.Infof("[AttachGoTlsUprobes] STEP 12.3: Trying Swiss Tables maps.Map.dirPtr for Go 1.24+")
|
|
|
+
|
|
|
+ // Go 1.24+ Swiss Tables 使用 internal/runtime/maps.Map 结构体
|
|
|
+ // 结构体字段:used uint64, seed uintptr, dirPtr unsafe.Pointer (相当于旧的 buckets)
|
|
|
+ // 尝试获取 maps.Map.dirPtr 的偏移量
|
|
|
+ // 注意:DWARF 中的包路径可能是 "internal/runtime/maps" 或 "internal/runtime/maps.Map"
|
|
|
+ swissFields := []struct {
|
|
|
+ pkg string
|
|
|
+ structName string
|
|
|
+ field string
|
|
|
+ }{
|
|
|
+ {"internal/runtime/maps", "Map", "dirPtr"},
|
|
|
+ {"internal.runtime.maps", "Map", "dirPtr"},
|
|
|
+ {"maps", "Map", "dirPtr"},
|
|
|
+ }
|
|
|
+
|
|
|
+ for _, sf := range swissFields {
|
|
|
+ // 尝试不同的包路径格式
|
|
|
+ swissOff, swissOk := tracer.GetOffset(tracer.NewID("std", sf.pkg, sf.structName, sf.field), path)
|
|
|
+ if swissOk {
|
|
|
+ klog.Infof("[AttachGoTlsUprobes] STEP 12.4: Found Swiss Tables field '%s.%s.%s' with offset=%d", sf.pkg, sf.structName, sf.field, swissOff)
|
|
|
+ bucketsOff = swissOff
|
|
|
+ ok2 = true
|
|
|
+ break
|
|
|
+ } else {
|
|
|
+ klog.Debugf("[AttachGoTlsUprobes] STEP 12.4: Trying Swiss Tables field '%s.%s.%s' not found", sf.pkg, sf.structName, sf.field)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果还是找不到,尝试旧的 hmap 字段作为备选
|
|
|
+ if !ok2 {
|
|
|
+ klog.Infof("[AttachGoTlsUprobes] STEP 12.5: Trying alternative hmap field names")
|
|
|
+ alternativeFields := []string{"table", "swiss", "swissTable", "buckets1", "oldbuckets", "bmap", "extra"}
|
|
|
+ for _, fieldName := range alternativeFields {
|
|
|
+ altOff, altOk := tracer.GetOffset(tracer.NewID("std", "runtime", "hmap", fieldName), path)
|
|
|
+ if altOk {
|
|
|
+ klog.Infof("[AttachGoTlsUprobes] STEP 12.6: Found alternative field '%s' with offset=%d", fieldName, altOff)
|
|
|
+ bucketsOff = altOff
|
|
|
+ ok2 = true
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if !ok2 {
|
|
|
+ klog.Errorf("[AttachGoTlsUprobes] STEP 12.7: All attempts failed, Go 1.24+ Swiss Tables map structure not found")
|
|
|
+ // 根据源码分析,maps.Map 结构体布局(64-bit):
|
|
|
+ // - used uint64 (8 bytes, offset 0)
|
|
|
+ // - seed uintptr (8 bytes, offset 8)
|
|
|
+ // - dirPtr unsafe.Pointer (8 bytes, offset 16) <- 相当于旧的 buckets
|
|
|
+ // 如果 DWARF 查找失败,使用硬编码的偏移量作为 fallback
|
|
|
+ // 注意:这需要确认目标系统是 64-bit,且结构体对齐正确
|
|
|
+ klog.Warnf("[AttachGoTlsUprobes] STEP 12.8: Using hardcoded offset for maps.Map.dirPtr (offset=16 on 64-bit)")
|
|
|
+ klog.Warnf("[AttachGoTlsUprobes] STEP 12.9: This assumes: used(uint64@0) + seed(uintptr@8) + dirPtr(unsafe.Pointer@16)")
|
|
|
+
|
|
|
+ // 检查 Go 版本是否 >= 1.24
|
|
|
+ realVersion := strings.Replace(bi.GoVersion, "go", "", 1)
|
|
|
+ parts := strings.Split(realVersion, ".")
|
|
|
+ if len(parts) >= 2 {
|
|
|
+ major, _ = strconv.Atoi(parts[0])
|
|
|
+ minor, _ = strconv.Atoi(parts[1])
|
|
|
+ if major > 1 || (major == 1 && minor >= 24) {
|
|
|
+ // Go 1.24+ 使用 Swiss Tables,maps.Map.dirPtr 在 offset 16 (64-bit)
|
|
|
+ // 假设是 64-bit 系统(大多数生产环境)
|
|
|
+ bucketsOff = 16
|
|
|
+ ok2 = true
|
|
|
+ klog.Infof("[AttachGoTlsUprobes] STEP 12.10: Using hardcoded offset=%d for Go %s (Swiss Tables)", bucketsOff, bi.GoVersion)
|
|
|
+ } else {
|
|
|
+ klog.Errorf("[AttachGoTlsUprobes] STEP 12.11: Go version < 1.24 but buckets not found, this is unexpected")
|
|
|
+ bucketsOff = 0
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ klog.Errorf("[AttachGoTlsUprobes] STEP 12.12: Failed to parse Go version: %s", bi.GoVersion)
|
|
|
+ bucketsOff = 0
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ klog.Infof("[AttachGoTlsUprobes] STEP 12.1: Successfully got buckets offset=%d", bucketsOff)
|
|
|
+ }
|
|
|
+
|
|
|
+ klog.Infof("[AttachGoTlsUprobes] STEP 13: Checking if both offsets are valid, goid_ok=%v, buckets_ok=%v", ok, ok2)
|
|
|
+ // Go 1.24+ 兼容:如果 goid 成功但 buckets 失败,仍然继续(但记录警告)
|
|
|
+ if ok {
|
|
|
+ if !ok2 {
|
|
|
+ klog.Warnf("[AttachGoTlsUprobes] STEP 13.0: buckets offset missing for Go 1.24+, but continuing with goid only")
|
|
|
+ // 对于 Go 1.24,可能需要调整后续逻辑,暂时允许继续
|
|
|
+ }
|
|
|
+ klog.Infof("[AttachGoTlsUprobes] STEP 13.1: Both offsets valid, proceeding with version encoding")
|
|
|
+ klog.Infof("[AttachGoTlsUprobes] STEP 14: Parsing Go version string")
|
|
|
realVersion := strings.Replace(bi.GoVersion, "go", "", 1)
|
|
|
+ klog.Infof("[AttachGoTlsUprobes] STEP 14.1: Real version string=%s", realVersion)
|
|
|
parts := strings.Split(realVersion, ".")
|
|
|
- var major, minor, revision int
|
|
|
if len(parts) >= 2 {
|
|
|
major, err = strconv.Atoi(parts[0])
|
|
|
if err != nil {
|
|
|
@@ -272,24 +397,40 @@ func (t *Tracer) AttachGoTlsUprobes(pid uint32, appInfo *AppInfo, codeType uint1
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ klog.Infof("[AttachGoTlsUprobes] Parsed version, major=%d, minor=%d, revision=%d", major, minor, revision)
|
|
|
goVersion := ((major & 0xFF) << 16) + ((minor & 0xFF) << 8) + min(revision, 255)
|
|
|
|
|
|
+ klog.Infof("[AttachGoTlsUprobes] Initializing EbpfProcInfo structure")
|
|
|
info := EbpfProcInfo{}
|
|
|
info.Version = uint32(goVersion)
|
|
|
info.Offsets[OFFSET_IDX_GOID_RUNTIME_G] = uint16(offset)
|
|
|
+ info.Offsets[OFFSET_IDX_P_GOIDCACHE] = uint16(goidcacheOffset)
|
|
|
+ info.Offsets[OFFSET_IDX_P_RUNNEXT] = uint16(runnextOffset)
|
|
|
info.NetTCPConnItab = uint64(0)
|
|
|
info.CryptoTLSConnItab = uint64(0)
|
|
|
info.CredentialsSyscallConnItab = uint64(0)
|
|
|
info.InstanceId = instanceID
|
|
|
info.AppId = appID
|
|
|
info.CodeType = codeType
|
|
|
+ if major == 1 && minor >= 24 {
|
|
|
+ info.UseSwissMap = uint64(1)
|
|
|
+ }
|
|
|
if grpcMajorVersion >= 1 && grpcMinorVersion >= 60 {
|
|
|
info.IsNewFramePos = 1
|
|
|
+ klog.Infof("[AttachGoTlsUprobes] Using new frame position for gRPC >= 1.60")
|
|
|
} else {
|
|
|
info.IsNewFramePos = 0
|
|
|
+ klog.Infof("[AttachGoTlsUprobes] Using old frame position for gRPC < 1.60")
|
|
|
}
|
|
|
// go
|
|
|
info.BucketsPtrPos = bucketsOff
|
|
|
+ if bucketsOff == 0 {
|
|
|
+ klog.Warnf("[AttachGoTlsUprobes] STEP 15.3: BucketsPtrPos=0 (Go 1.24+ may not use buckets field)")
|
|
|
+ } else {
|
|
|
+ klog.Infof("[AttachGoTlsUprobes] STEP 15.3: Basic info initialized, BucketsPtrPos=%d", bucketsOff)
|
|
|
+ }
|
|
|
+
|
|
|
+ klog.Infof("[AttachGoTlsUprobes] STEP 16: Getting offsets for HTTP and gRPC fields")
|
|
|
fields := map[*uint64]tracer.ID{
|
|
|
&info.MethodPtrPos: tracer.NewID("std", "net/http", "Request", "Method"),
|
|
|
&info.UrlPtrPos: tracer.NewID("std", "net/http", "Request", "URL"),
|
|
|
@@ -306,26 +447,37 @@ func (t *Tracer) AttachGoTlsUprobes(pid uint32, appInfo *AppInfo, codeType uint1
|
|
|
&info.IoWriterNPos: tracer.NewID("std", "bufio", "Writer", "n"),
|
|
|
}
|
|
|
|
|
|
+ successCount := 0
|
|
|
+ failCount := 0
|
|
|
for field, id := range fields {
|
|
|
off, ok := tracer.GetOffset(id, path)
|
|
|
if !ok {
|
|
|
- klog.Warnf("failed to get offset for ID: %v", id)
|
|
|
+ klog.Warnf("[AttachGoTlsUprobes] STEP 16.1: Failed to get offset for ID: %v (PkgPath=%s, Struct=%s, Field=%s)", id, id.PkgPath, id.Struct, id.Field)
|
|
|
+ failCount++
|
|
|
+ } else {
|
|
|
+ successCount++
|
|
|
+ klog.Debugf("[AttachGoTlsUprobes] STEP 16.2: Got offset for %s.%s.%s = %d", id.PkgPath, id.Struct, id.Field, off)
|
|
|
}
|
|
|
*field = off
|
|
|
}
|
|
|
+ klog.Infof("[AttachGoTlsUprobes] Field offset collection completed, success=%d, failed=%d", successCount, failCount)
|
|
|
|
|
|
// 获取内存地址
|
|
|
if appInfo.GoProcCache.StartAddr == 0 && appInfo.GoProcCache.EndAddr == 0 {
|
|
|
+ klog.Infof("[AttachGoTlsUprobes] Cache empty, calling Allocate")
|
|
|
allocDetails, allocErr := tracer.Allocate(int(pid))
|
|
|
if allocErr != nil {
|
|
|
return nil, allocErr
|
|
|
}
|
|
|
if allocDetails != nil {
|
|
|
- //info.StartAddr = allocDetails.StartAddr
|
|
|
- //info.EndAddr = allocDetails.EndAddr
|
|
|
appInfo.GoProcCache.StartAddr = allocDetails.StartAddr
|
|
|
appInfo.GoProcCache.EndAddr = allocDetails.EndAddr
|
|
|
+ klog.Infof("[AttachGoTlsUprobes] Allocate succeeded, StartAddr=0x%x, EndAddr=0x%x", allocDetails.StartAddr, allocDetails.EndAddr)
|
|
|
+ } else {
|
|
|
+ klog.Warnf("[AttachGoTlsUprobes] Allocate returned nil")
|
|
|
}
|
|
|
+ } else {
|
|
|
+ klog.Infof("[AttachGoTlsUprobes] Using cached addresses, StartAddr=0x%x, EndAddr=0x%x", appInfo.GoProcCache.StartAddr, appInfo.GoProcCache.EndAddr)
|
|
|
}
|
|
|
info.StartAddr = appInfo.GoProcCache.StartAddr
|
|
|
info.EndAddr = appInfo.GoProcCache.EndAddr
|
|
|
@@ -335,26 +487,69 @@ func (t *Tracer) AttachGoTlsUprobes(pid uint32, appInfo *AppInfo, codeType uint1
|
|
|
klog.Debugln("goVersion", goVersion)
|
|
|
klog.WithField("pid", pid).Debugln("info.StartAddr", info.StartAddr)
|
|
|
klog.WithField("pid", pid).Debugln("info.EndAddr", info.EndAddr)
|
|
|
+
|
|
|
+ klog.Infof("[AttachGoTlsUprobes] Updating proc_info map")
|
|
|
_, err = tracer.UpdateProcInfoToMap(t.collection, pid, info)
|
|
|
if err != nil {
|
|
|
klog.Error("failed to update program info", err)
|
|
|
return nil, err
|
|
|
}
|
|
|
+ klog.Infof("[AttachGoTlsUprobes] Proc_info map updated successfully")
|
|
|
appInfo.EBPFProcInfo = &info
|
|
|
+ } else {
|
|
|
+ klog.Errorf("[AttachGoTlsUprobes] Skipping proc_info initialization due to missing offsets, goid_ok=%v, buckets_ok=%v", ok, ok2)
|
|
|
+ if !ok {
|
|
|
+ klog.Errorf("[AttachGoTlsUprobes] runtime.g.goid offset missing - this is critical!")
|
|
|
+ }
|
|
|
+ if !ok2 {
|
|
|
+ klog.Errorf("[AttachGoTlsUprobes] runtime.hmap.buckets offset missing - Go 1.24+ may use new map implementation")
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ klog.Infof("[AttachGoTlsUprobes] Starting symbol matching and uprobe attachment, total symbols=%d", len(symbols))
|
|
|
var links []link.Link
|
|
|
- for _, s := range symbols {
|
|
|
+ matchedSymbols := 0
|
|
|
+ for i, s := range symbols {
|
|
|
if elf.ST_TYPE(s.Info) != elf.STT_FUNC || s.Size == 0 {
|
|
|
continue
|
|
|
}
|
|
|
switch s.Name {
|
|
|
case goTlsWriteSymbol, goTlsReadSymbol:
|
|
|
- case goExecute, goNewproc1, goRunqget, goServeHTTP, goTransport, goHeaderWriteSubset, goGrpcHttp2OperateHeader, goGrpcServerHandleStream, goGrpcServerWritestatus, goGrpcClientConnInvoke, goGrpcClientLoopyHeaderHandler, goGrpcHttp2ClientNewStream:
|
|
|
+ matchedSymbols++
|
|
|
+ klog.Infof("[AttachGoTlsUprobes] STEP 19.1: Matched TLS symbol: %s (index=%d)", s.Name, i)
|
|
|
+ case goExecute:
|
|
|
+ matchedSymbols++
|
|
|
+ klog.Infof("[AttachGoTlsUprobes] STEP 19.2: Matched runtime.execute symbol (index=%d)", i)
|
|
|
+ case goNewproc1:
|
|
|
+ matchedSymbols++
|
|
|
+ klog.Infof("[AttachGoTlsUprobes] STEP 19.3: Matched runtime.newproc1 symbol (index=%d)", i)
|
|
|
+ case goRunqget:
|
|
|
+ matchedSymbols++
|
|
|
+ klog.Infof("[AttachGoTlsUprobes] STEP 19.4: Matched runtime.runqget symbol (index=%d)", i)
|
|
|
+ case goServeHTTP:
|
|
|
+ matchedSymbols++
|
|
|
+ klog.Infof("[AttachGoTlsUprobes] STEP 19.6: Matched net/http.serverHandler.ServeHTTP symbol (index=%d)", i)
|
|
|
+ case goTransport, goHeaderWriteSubset:
|
|
|
+ matchedSymbols++
|
|
|
+ klog.Infof("[AttachGoTlsUprobes] STEP 19.7: Matched net/http.Transport.roundTrip writeSubset symbol (index=%d)", i)
|
|
|
+ case goGrpcClientConnInvoke:
|
|
|
+ matchedSymbols++
|
|
|
+ klog.Infof("[AttachGoTlsUprobes] STEP 19.8: Matched gRPC ClientConn.Invoke symbol (index=%d)", i)
|
|
|
+ case goGrpcHttp2OperateHeader, goGrpcServerHandleStream, goGrpcServerWritestatus, goGrpcClientLoopyHeaderHandler, goGrpcHttp2ClientNewStream:
|
|
|
+ matchedSymbols++
|
|
|
+ klog.Infof("[AttachGoTlsUprobes] STEP 19.9: Matched gRPC symbol: %s (index=%d)", s.Name, i)
|
|
|
+ case goGocqlSessionExecuteQuery:
|
|
|
+ matchedSymbols++
|
|
|
+ klog.Infof("[AttachGoTlsUprobes] STEP 19.10: Matched gocql Session.executeQuery symbol (index=%d)", i)
|
|
|
+ case goGocqlSessionExecuteQueryV2:
|
|
|
+ matchedSymbols++
|
|
|
+ klog.Infof("[AttachGoTlsUprobes] STEP 19.11: Matched cassandra Session.executeQuery symbol (index=%d)", i)
|
|
|
+ case goReadContinuedLineSlice:
|
|
|
default:
|
|
|
continue
|
|
|
}
|
|
|
+ klog.Debugf("[AttachGoTlsUprobes] Processing symbol %s, Value=0x%x, Size=%d", s.Name, s.Value, s.Size)
|
|
|
address := s.Value
|
|
|
for _, p := range ef.Progs {
|
|
|
if p.Type != elf.PT_LOAD || (p.Flags&elf.PF_X) == 0 {
|
|
|
@@ -370,125 +565,71 @@ func (t *Tracer) AttachGoTlsUprobes(pid uint32, appInfo *AppInfo, codeType uint1
|
|
|
|
|
|
switch s.Name {
|
|
|
case goExecute:
|
|
|
- l, err := exe.Uprobe(s.Name, t.uprobes["runtime_execute"], &link.UprobeOptions{Address: address})
|
|
|
+ klog.Infof("[AttachGoTlsUprobes] STEP 20: Attaching uprobe for runtime.execute, address=0x%x", address)
|
|
|
+ l, err := attachUprobe(exe, s.Name, "runtime_execute", t.uprobes, address, "failed to attach write_enter uprobe", true)
|
|
|
if err != nil {
|
|
|
- log("failed to attach write_enter uprobe", err)
|
|
|
klog.Infoln("runtime.execute no")
|
|
|
return nil, err
|
|
|
- } else {
|
|
|
- klog.Infoln("runtime.execute ok")
|
|
|
}
|
|
|
+ klog.Infof("[AttachGoTlsUprobes] STEP 20.2: Successfully attached runtime.execute uprobe")
|
|
|
+ klog.Infoln("runtime.execute ok")
|
|
|
links = append(links, l)
|
|
|
|
|
|
case goNewproc1:
|
|
|
- l, err := exe.Uprobe(s.Name, t.uprobes["enter_runtime_newproc1"], &link.UprobeOptions{Address: address})
|
|
|
+ klog.Infof("[AttachGoTlsUprobes] STEP 21: Attaching uprobe for runtime.newproc1, address=0x%x", address)
|
|
|
+ retLinks, err := attachUprobeWithReturns(exe, s.Name, "enter_runtime_newproc1", "exit_runtime_newproc1", t.uprobes, address, s, textSection, textSectionLen, textSectionData, ef.Machine, "failed to attach newproc1 uprobe", true)
|
|
|
if err != nil {
|
|
|
log("failed to attach newproc1 uprobe", err)
|
|
|
return nil, err
|
|
|
}
|
|
|
- links = append(links, l)
|
|
|
- sStart := s.Value - textSection.Addr
|
|
|
- sEnd := sStart + s.Size
|
|
|
- if sEnd > textSectionLen {
|
|
|
- continue
|
|
|
- }
|
|
|
- sBytes := textSectionData[sStart:sEnd]
|
|
|
- returnOffsets := getReturnOffsets(ef.Machine, sBytes)
|
|
|
- if len(returnOffsets) == 0 {
|
|
|
- log("failed to attach enter_runtime_newproc1 uprobe", fmt.Errorf("no return offsets found"))
|
|
|
- return nil, err
|
|
|
- }
|
|
|
- for _, offset := range returnOffsets {
|
|
|
- l, err := exe.Uprobe(s.Name, t.uprobes["exit_runtime_newproc1"], &link.UprobeOptions{Address: address, Offset: uint64(offset)})
|
|
|
- if err != nil {
|
|
|
- log("failed to attach exit_runtime_newproc1 uprobe", err)
|
|
|
- return nil, err
|
|
|
- }
|
|
|
- links = append(links, l)
|
|
|
- }
|
|
|
+ links = append(links, retLinks...)
|
|
|
+ klog.Infof("[AttachGoTlsUprobes] STEP 21.2: Successfully attached enter_runtime_newproc1 uprobe")
|
|
|
|
|
|
case goRunqget:
|
|
|
- l, err := exe.Uprobe(s.Name, t.uprobes["enter_runtime_runqget"], &link.UprobeOptions{Address: address})
|
|
|
+ l, err := attachUprobe(exe, s.Name, "enter_runtime_runqget", t.uprobes, address, "failed to attach goRunqget uprobe", true)
|
|
|
if err != nil {
|
|
|
log("failed to attach goRunqget uprobe", err)
|
|
|
return nil, err
|
|
|
}
|
|
|
links = append(links, l)
|
|
|
- //sStart := s.Value - textSection.Addr
|
|
|
- //sEnd := sStart + s.Size
|
|
|
- //if sEnd > textSectionLen {
|
|
|
- // continue
|
|
|
- //}
|
|
|
- //sBytes := textSectionData[sStart:sEnd]
|
|
|
- //returnOffsets := getReturnOffsets(ef.Machine, sBytes)
|
|
|
- //if len(returnOffsets) == 0 {
|
|
|
- // log("failed to attach enter_runtime_newproc1 uprobe", fmt.Errorf("no return offsets found"))
|
|
|
- // return nil
|
|
|
- //}
|
|
|
- //for _, offset := range returnOffsets {
|
|
|
- // l, err := exe.Uprobe(s.Name, t.uprobes["exit_runtime_newproc1"], &link.UprobeOptions{Address: address, Offset: uint64(offset)})
|
|
|
- // if err != nil {
|
|
|
- // log("failed to attach exit_runtime_newproc1 uprobe", err)
|
|
|
- // return nil
|
|
|
- // }
|
|
|
- // links = append(links, l)
|
|
|
- //}
|
|
|
+
|
|
|
+ //case goGoready:
|
|
|
+ //klog.Infof("[AttachGoTlsUprobes] STEP 22: Attaching uprobe for runtime.goready, address=0x%x", address)
|
|
|
+ //l, err := attachUprobe(exe, s.Name, "runtime_goready", t.uprobes, address, "failed to attach runtime.goready uprobe", true)
|
|
|
+ //if err != nil {
|
|
|
+ // klog.Infoln("runtime.goready no")
|
|
|
+ // return nil, err
|
|
|
+ //}
|
|
|
+ //klog.Infof("[AttachGoTlsUprobes] STEP 22.2: Successfully attached runtime.goready uprobe")
|
|
|
+ //klog.Infoln("runtime.goready ok")
|
|
|
+ //links = append(links, l)
|
|
|
case goGrpcClientConnInvoke:
|
|
|
- // 根据 gRPC 版本选择相应的探针
|
|
|
- l, err := exe.Uprobe(s.Name, t.uprobes["uprobe_ClientConn_Invoke"], &link.UprobeOptions{Address: address})
|
|
|
+ retLinks, err := attachUprobeWithReturns(exe, s.Name, "uprobe_ClientConn_Invoke", "uprobe_ClientConn_Invoke_Returns", t.uprobes, address, s, textSection, textSectionLen, textSectionData, ef.Machine, "failed to attach uprobe_ClientConn_Invoke uprobe", true)
|
|
|
if err != nil {
|
|
|
- klog.WithError(err).Errorf("failed to attach uprobe_ClientConn_Invoke uprobe")
|
|
|
- continue
|
|
|
- }
|
|
|
- klog.Infoln("uprobe_ClientConn_Invoke ok")
|
|
|
- links = append(links, l)
|
|
|
- sStart := s.Value - textSection.Addr
|
|
|
- sEnd := sStart + s.Size
|
|
|
- if sEnd > textSectionLen {
|
|
|
- continue
|
|
|
- }
|
|
|
- sBytes := textSectionData[sStart:sEnd]
|
|
|
- returnOffsets := getReturnOffsets(ef.Machine, sBytes)
|
|
|
- if len(returnOffsets) == 0 {
|
|
|
- err = fmt.Errorf("failed to attach uprobe_ClientConn_Invoke no return offsets found")
|
|
|
- klog.Errorln(err)
|
|
|
return nil, err
|
|
|
}
|
|
|
- for _, offset := range returnOffsets {
|
|
|
- l, err := exe.Uprobe(s.Name, t.uprobes["uprobe_ClientConn_Invoke_Returns"], &link.UprobeOptions{Address: address, Offset: uint64(offset)})
|
|
|
- if err != nil {
|
|
|
- klog.WithError(err).Errorln(fmt.Errorf("failed to attach uprobe_ClientConn_Invoke_Returns uprobe"))
|
|
|
- return nil, err
|
|
|
- }
|
|
|
- links = append(links, l)
|
|
|
+ if retLinks != nil {
|
|
|
+ klog.Infoln("uprobe_ClientConn_Invoke ok")
|
|
|
+ links = append(links, retLinks...)
|
|
|
}
|
|
|
case goGrpcClientLoopyHeaderHandler:
|
|
|
- // 根据 gRPC 版本选择相应的探针
|
|
|
- l, err := exe.Uprobe(s.Name, t.uprobes["uprobe_LoopyWriter_HeaderHandler"], &link.UprobeOptions{Address: address})
|
|
|
- if err != nil {
|
|
|
- klog.WithError(err).Errorf("failed to attach uprobe_LoopyWriter_HeaderHandler uprobe")
|
|
|
- continue
|
|
|
+ l, err := attachUprobe(exe, s.Name, "uprobe_LoopyWriter_HeaderHandler", t.uprobes, address, "failed to attach uprobe_LoopyWriter_HeaderHandler uprobe", false)
|
|
|
+ if err == nil && l != nil {
|
|
|
+ klog.Infoln("uprobe_LoopyWriter_HeaderHandler ok")
|
|
|
+ links = append(links, l)
|
|
|
}
|
|
|
- klog.Infoln("uprobe_LoopyWriter_HeaderHandler ok")
|
|
|
- links = append(links, l)
|
|
|
case goGrpcHttp2ClientNewStream:
|
|
|
- // 根据 gRPC 版本选择相应的探针
|
|
|
- l, err := exe.Uprobe(s.Name, t.uprobes["uprobe_http2Client_NewStream"], &link.UprobeOptions{Address: address})
|
|
|
- if err != nil {
|
|
|
- klog.WithError(err).Errorf("failed to attach uprobe_http2Client_NewStream uprobe")
|
|
|
- continue
|
|
|
+ l, err := attachUprobe(exe, s.Name, "uprobe_http2Client_NewStream", t.uprobes, address, "failed to attach uprobe_http2Client_NewStream uprobe", false)
|
|
|
+ if err == nil && l != nil {
|
|
|
+ klog.Infoln("uprobe_http2Client_NewStream ok")
|
|
|
+ links = append(links, l)
|
|
|
}
|
|
|
- klog.Infoln("uprobe_http2Client_NewStream ok")
|
|
|
- links = append(links, l)
|
|
|
case goGrpcHttp2OperateHeader:
|
|
|
- // 根据 gRPC 版本选择相应的探针
|
|
|
- l, err := exe.Uprobe(s.Name, t.uprobes["uprobe_http2Server_operateHeader"], &link.UprobeOptions{Address: address})
|
|
|
- if err != nil {
|
|
|
- klog.WithError(err).Errorf("failed to attach uprobe_http2Server_operateHeader uprobe")
|
|
|
- continue
|
|
|
+ l, err := attachUprobe(exe, s.Name, "uprobe_http2Server_operateHeader", t.uprobes, address, "failed to attach uprobe_http2Server_operateHeader uprobe", false)
|
|
|
+ if err == nil && l != nil {
|
|
|
+ klog.Infoln("uprobe_http2Server_operateHeader ok")
|
|
|
+ links = append(links, l)
|
|
|
}
|
|
|
- klog.Infoln("uprobe_http2Server_operateHeader ok")
|
|
|
- links = append(links, l)
|
|
|
// case goGrpcServerWritestatus:
|
|
|
// // 根据 gRPC 版本选择相应的 WriteStatus 探针
|
|
|
// l, err := exe.Uprobe(s.Name, t.uprobes["uprobe_http2Server_WriteStatus"], &link.UprobeOptions{Address: address})
|
|
|
@@ -500,114 +641,53 @@ func (t *Tracer) AttachGoTlsUprobes(pid uint32, appInfo *AppInfo, codeType uint1
|
|
|
case goGrpcServerHandleStream:
|
|
|
// 根据 gRPC 版本选择相应的探针
|
|
|
probeName := t.selectGRPCServerProbe(grpcMajorVersion, grpcMinorVersion)
|
|
|
- l, err := exe.Uprobe(s.Name, t.uprobes[probeName], &link.UprobeOptions{Address: address})
|
|
|
+ retLinks, err := attachUprobeWithReturns(exe, s.Name, probeName, "uprobe_server_handleStream_Returns", t.uprobes, address, s, textSection, textSectionLen, textSectionData, ef.Machine, fmt.Sprintf("failed to attach %s uprobe", probeName), true)
|
|
|
if err != nil {
|
|
|
- klog.WithError(err).Errorf("failed to attach %s uprobe", probeName)
|
|
|
- continue
|
|
|
- }
|
|
|
- klog.Infof("%s ok (gRPC v%d.%d)", probeName, grpcMajorVersion, grpcMinorVersion)
|
|
|
- links = append(links, l)
|
|
|
- sStart := s.Value - textSection.Addr
|
|
|
- sEnd := sStart + s.Size
|
|
|
- klog.Infoln("google.golang.org/grpc.(*Server).handleStream ok----111111")
|
|
|
- if sEnd > textSectionLen {
|
|
|
- continue
|
|
|
- }
|
|
|
- klog.Infoln("google.golang.org/grpc.(*Server).handleStream ok----2222")
|
|
|
- sBytes := textSectionData[sStart:sEnd]
|
|
|
- returnOffsets := getReturnOffsets(ef.Machine, sBytes)
|
|
|
- if len(returnOffsets) == 0 {
|
|
|
- err = fmt.Errorf("failed to attach uprobe_server_handleStream2 no return offsets found")
|
|
|
- klog.Errorln(err)
|
|
|
return nil, err
|
|
|
}
|
|
|
- for _, offset := range returnOffsets {
|
|
|
- l, err := exe.Uprobe(s.Name, t.uprobes["uprobe_server_handleStream_Returns"], &link.UprobeOptions{Address: address, Offset: uint64(offset)})
|
|
|
- if err != nil {
|
|
|
- klog.WithError(err).Errorln(fmt.Errorf("failed to attach exit_runtime_newproc1 uprobe"))
|
|
|
- return nil, err
|
|
|
- }
|
|
|
+ if retLinks != nil {
|
|
|
+ klog.Infof("%s ok (gRPC v%d.%d)", probeName, grpcMajorVersion, grpcMinorVersion)
|
|
|
klog.Infoln("google.golang.org/grpc.(*Server).handleStream ok----")
|
|
|
- links = append(links, l)
|
|
|
+ links = append(links, retLinks...)
|
|
|
}
|
|
|
case goServeHTTP:
|
|
|
- l, err := exe.Uprobe(s.Name, t.uprobes["uprobe_HandlerFunc_ServeHTTP"], &link.UprobeOptions{Address: address})
|
|
|
+ retLinks, err := attachUprobeWithReturns(exe, s.Name, "uprobe_HandlerFunc_ServeHTTP", "uprobe_HandlerFunc_ServeHTTP_Returns", t.uprobes, address, s, textSection, textSectionLen, textSectionData, ef.Machine, "failed to attach uprobe_HandlerFunc_ServeHTTP uprobe", true)
|
|
|
if err != nil {
|
|
|
- klog.WithError(err).Errorln("failed to attach uprobe_HandlerFunc_ServeHTTP uprobe")
|
|
|
- continue
|
|
|
- }
|
|
|
- klog.Infoln("net/http.serverHandler.ServeHTTP ok")
|
|
|
- links = append(links, l)
|
|
|
- sStart := s.Value - textSection.Addr
|
|
|
- sEnd := sStart + s.Size
|
|
|
- if sEnd > textSectionLen {
|
|
|
- continue
|
|
|
- }
|
|
|
- sBytes := textSectionData[sStart:sEnd]
|
|
|
- returnOffsets := getReturnOffsets(ef.Machine, sBytes)
|
|
|
- if len(returnOffsets) == 0 {
|
|
|
- err = fmt.Errorf("failed to attach uprobe_HandlerFunc_ServeHTTP no return offsets found")
|
|
|
- klog.Errorln(err)
|
|
|
return nil, err
|
|
|
}
|
|
|
- for _, offset := range returnOffsets {
|
|
|
- l, err := exe.Uprobe(s.Name, t.uprobes["uprobe_HandlerFunc_ServeHTTP_Returns"], &link.UprobeOptions{Address: address, Offset: uint64(offset)})
|
|
|
- if err != nil {
|
|
|
- klog.WithError(err).Errorln(fmt.Errorf("failed to attach exit_runtime_newproc1 uprobe"))
|
|
|
- return nil, err
|
|
|
- }
|
|
|
- links = append(links, l)
|
|
|
+ if retLinks != nil {
|
|
|
+ klog.Infoln("net/http.serverHandler.ServeHTTP ok")
|
|
|
+ links = append(links, retLinks...)
|
|
|
}
|
|
|
|
|
|
case goTransport:
|
|
|
if t.DisableE2ETracing() {
|
|
|
continue
|
|
|
}
|
|
|
- l, err := exe.Uprobe(s.Name, t.uprobes["uprobe_Transport_roundTrip"], &link.UprobeOptions{Address: address})
|
|
|
+ retLinks, err := attachUprobeWithReturns(exe, s.Name, "uprobe_Transport_roundTrip", "uprobe_Transport_roundTrip_Returns", t.uprobes, address, s, textSection, textSectionLen, textSectionData, ef.Machine, "failed to attach write_enter uprobe", true)
|
|
|
if err != nil {
|
|
|
- klog.WithError(err).Errorln(fmt.Errorf("failed to attach write_enter uprobe"))
|
|
|
- continue
|
|
|
- } else {
|
|
|
- }
|
|
|
- klog.Infoln("net/http.uprobe_Transport_roundTrip ok")
|
|
|
-
|
|
|
- links = append(links, l)
|
|
|
- sStart := s.Value - textSection.Addr
|
|
|
- sEnd := sStart + s.Size
|
|
|
- if sEnd > textSectionLen {
|
|
|
- continue
|
|
|
- }
|
|
|
- sBytes := textSectionData[sStart:sEnd]
|
|
|
- returnOffsets := getReturnOffsets(ef.Machine, sBytes)
|
|
|
- if len(returnOffsets) == 0 {
|
|
|
- err = fmt.Errorf("failed to attach uprobe_Transport_roundTrip uprobe no return offsets found")
|
|
|
- klog.Errorln(err)
|
|
|
return nil, err
|
|
|
}
|
|
|
- for _, offset := range returnOffsets {
|
|
|
- l, err := exe.Uprobe(s.Name, t.uprobes["uprobe_Transport_roundTrip_Returns"], &link.UprobeOptions{Address: address, Offset: uint64(offset)})
|
|
|
- if err != nil {
|
|
|
- klog.WithError(err).Errorln("failed to attach exit_runtime_newproc1 uprobe")
|
|
|
- return nil, err
|
|
|
- }
|
|
|
- links = append(links, l)
|
|
|
+ if retLinks != nil {
|
|
|
+ klog.Infoln("net/http.uprobe_Transport_roundTrip ok")
|
|
|
+ links = append(links, retLinks...)
|
|
|
}
|
|
|
|
|
|
case goHeaderWriteSubset:
|
|
|
if t.DisableE2ETracing() {
|
|
|
continue
|
|
|
}
|
|
|
- l, err := exe.Uprobe(s.Name, t.uprobes["uprobe_writeSubset"], &link.UprobeOptions{Address: address})
|
|
|
+ l, err := attachUprobe(exe, s.Name, "uprobe_writeSubset", t.uprobes, address, "failed to attach write_enter uprobe", true)
|
|
|
if err != nil {
|
|
|
- klog.WithError(err).Errorln("failed to attach uprobe_writeSubset uprobe")
|
|
|
- continue
|
|
|
+ klog.WithError(err).Errorln("failed to attach uprobe_writeSubset")
|
|
|
+ return nil, err
|
|
|
}
|
|
|
klog.Infoln("net/http.Header.writeSubset ok")
|
|
|
links = append(links, l)
|
|
|
|
|
|
case goTlsWriteSymbol:
|
|
|
klog.Infoln("fucktls goTlsWriteSymbol crypto/tls uprobes attached")
|
|
|
- l, err := exe.Uprobe(s.Name, t.uprobes["go_crypto_tls_write_enter"], &link.UprobeOptions{Address: address})
|
|
|
+ l, err := attachUprobe(exe, s.Name, "go_crypto_tls_write_enter", t.uprobes, address, "failed to attach write_enter uprobe", true)
|
|
|
if err != nil {
|
|
|
klog.WithError(err).Errorln("failed to attach write_enter uprobe")
|
|
|
return nil, err
|
|
|
@@ -616,37 +696,50 @@ func (t *Tracer) AttachGoTlsUprobes(pid uint32, appInfo *AppInfo, codeType uint1
|
|
|
|
|
|
case goTlsReadSymbol:
|
|
|
klog.Infoln("fucktls goTlsReadSymbol crypto/tls uprobes attached")
|
|
|
- l, err := exe.Uprobe(s.Name, t.uprobes["go_crypto_tls_read_enter"], &link.UprobeOptions{Address: address})
|
|
|
+ retLinks, err := attachUprobeWithReturns(exe, s.Name, "go_crypto_tls_read_enter", "go_crypto_tls_read_exit", t.uprobes, address, s, textSection, textSectionLen, textSectionData, ef.Machine, "failed to attach read_enter uprobe", true)
|
|
|
if err != nil {
|
|
|
klog.WithError(err).Errorln("failed to attach read_enter uprobe")
|
|
|
return nil, err
|
|
|
}
|
|
|
- links = append(links, l)
|
|
|
- sStart := s.Value - textSection.Addr
|
|
|
- sEnd := sStart + s.Size
|
|
|
- if sEnd > textSectionLen {
|
|
|
- continue
|
|
|
+ if retLinks != nil {
|
|
|
+ links = append(links, retLinks...)
|
|
|
}
|
|
|
- sBytes := textSectionData[sStart:sEnd]
|
|
|
- returnOffsets := getReturnOffsets(ef.Machine, sBytes)
|
|
|
- if len(returnOffsets) == 0 {
|
|
|
- err = fmt.Errorf("failed to attach read_exit uprobe no return offsets found")
|
|
|
- klog.Errorln(err)
|
|
|
- return nil, err
|
|
|
- }
|
|
|
- for _, offset := range returnOffsets {
|
|
|
- l, err := exe.Uprobe(s.Name, t.uprobes["go_crypto_tls_read_exit"], &link.UprobeOptions{Address: address, Offset: uint64(offset)})
|
|
|
+ case goReadContinuedLineSlice:
|
|
|
+ if major == 1 && minor >= 24 {
|
|
|
+ retLinks, err := attachUprobeWithReturns(exe, s.Name, "", "uprobe_textproto_Reader_readContinuedLineSlice_Returns", t.uprobes, address, s, textSection, textSectionLen, textSectionData, ef.Machine, "failed to attach read_exit uprobe", true)
|
|
|
if err != nil {
|
|
|
- klog.WithError(err).Errorln("failed to attach read_exit uprobe")
|
|
|
return nil, err
|
|
|
}
|
|
|
- links = append(links, l)
|
|
|
+ if retLinks != nil {
|
|
|
+ links = append(links, retLinks...)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ case goGocqlSessionExecuteQuery:
|
|
|
+ retLinks, err := attachUprobeWithReturns(exe, s.Name, "uprobe_Session_executeQuery", "uprobe_Session_executeQuery_Returns", t.uprobes, address, s, textSection, textSectionLen, textSectionData, ef.Machine, "failed to attach uprobe_Session_executeQuery uprobe", true)
|
|
|
+ if err != nil {
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+ if retLinks != nil {
|
|
|
+ klog.Infoln("uprobe_Session_executeQuery ok")
|
|
|
+ links = append(links, retLinks...)
|
|
|
+ }
|
|
|
+ case goGocqlSessionExecuteQueryV2:
|
|
|
+ retLinks, err := attachUprobeWithReturns(exe, s.Name, "uprobe_Session_executeQuery_cassandra", "uprobe_Session_executeQuery_cassandra_Returns", t.uprobes, address, s, textSection, textSectionLen, textSectionData, ef.Machine, "failed to attach uprobe_Session_executeQuery_cassandra uprobe", true)
|
|
|
+ if err != nil {
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+ if retLinks != nil {
|
|
|
+ klog.Infoln("uprobe_Session_executeQuery_cassandra ok")
|
|
|
+ links = append(links, retLinks...)
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+ klog.Infof("[AttachGoTlsUprobes] Symbol processing completed, matched symbols=%d, total links=%d", matchedSymbols, len(links))
|
|
|
if len(links) == 0 {
|
|
|
+ klog.Errorf("[AttachGoTlsUprobes] No uprobes attached, returning error")
|
|
|
return nil, err
|
|
|
}
|
|
|
+ klog.Infof("[AttachGoTlsUprobes] Function completed successfully, attached %d uprobes", len(links))
|
|
|
klog.Infoln("crypto/tls uprobes attached")
|
|
|
return links, nil
|
|
|
}
|
|
|
@@ -731,6 +824,73 @@ func (t *Tracer) selectGRPCServerProbe(major, minor int) string {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+// attachUprobe 附加单个 uprobe,处理错误
|
|
|
+func attachUprobe(exe *link.Executable, symbolName string, probeName string, uprobes map[string]*ebpf.Program, address uint64, onError string, returnOnError bool) (link.Link, error) {
|
|
|
+ l, err := exe.Uprobe(symbolName, uprobes[probeName], &link.UprobeOptions{Address: address})
|
|
|
+ if err != nil {
|
|
|
+ if returnOnError {
|
|
|
+ klog.WithError(err).Errorf("failed to attach %s uprobe: %s", probeName, onError)
|
|
|
+ return nil, err
|
|
|
+ } else {
|
|
|
+ klog.WithError(err).Errorf("failed to attach %s uprobe: %s", probeName, onError)
|
|
|
+ return nil, nil
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return l, nil
|
|
|
+}
|
|
|
+
|
|
|
+// attachUprobeWithReturns 附加 uprobe 并附加返回探针
|
|
|
+// enterProbeName 为空字符串时,只附加返回探针
|
|
|
+func attachUprobeWithReturns(exe *link.Executable, symbolName string, enterProbeName, returnProbeName string, uprobes map[string]*ebpf.Program, address uint64, s elf.Symbol, textSection *elf.Section, textSectionLen uint64, textSectionData []byte, machine elf.Machine, onError string, returnOnError bool) ([]link.Link, error) {
|
|
|
+ var links []link.Link
|
|
|
+
|
|
|
+ // 附加入口探针(如果提供了入口探针名称)
|
|
|
+ if enterProbeName != "" {
|
|
|
+ l, err := attachUprobe(exe, symbolName, enterProbeName, uprobes, address, onError, returnOnError)
|
|
|
+ if err != nil {
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+ if l == nil {
|
|
|
+ return nil, nil
|
|
|
+ }
|
|
|
+ links = append(links, l)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 计算符号在 text section 中的位置
|
|
|
+ sStart := s.Value - textSection.Addr
|
|
|
+ sEnd := sStart + s.Size
|
|
|
+ if sEnd > textSectionLen {
|
|
|
+ return links, nil
|
|
|
+ }
|
|
|
+
|
|
|
+ // 读取符号字节码
|
|
|
+ sBytes := textSectionData[sStart:sEnd]
|
|
|
+ returnOffsets := getReturnOffsets(machine, sBytes)
|
|
|
+ if len(returnOffsets) == 0 {
|
|
|
+ if returnOnError {
|
|
|
+ err := fmt.Errorf("failed to attach %s: no return offsets found", returnProbeName)
|
|
|
+ klog.Errorln(err)
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+ return links, nil
|
|
|
+ }
|
|
|
+
|
|
|
+ // 为每个返回点附加探针
|
|
|
+ for _, offset := range returnOffsets {
|
|
|
+ l, err := exe.Uprobe(symbolName, uprobes[returnProbeName], &link.UprobeOptions{Address: address, Offset: uint64(offset)})
|
|
|
+ if err != nil {
|
|
|
+ if returnOnError {
|
|
|
+ klog.WithError(err).Errorf("failed to attach %s uprobe", returnProbeName)
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ links = append(links, l)
|
|
|
+ }
|
|
|
+
|
|
|
+ return links, nil
|
|
|
+}
|
|
|
+
|
|
|
func getReturnOffsets(machine elf.Machine, instructions []byte) []int {
|
|
|
var res []int
|
|
|
switch machine {
|