Ver código fonte

Fixed #TASK_QT-9810 1、支持实现动态获取nio.so;2、支持判断多语言场景语言类型。

rock 1 ano atrás
pai
commit
99df7b4ef2
5 arquivos alterados com 139 adições e 9 exclusões
  1. 2 2
      Makefile2
  2. 10 0
      containers/container.go
  3. 4 1
      containers/registry.go
  4. 82 0
      containers/util.go
  5. 41 6
      ebpftracer/jvm.go

+ 2 - 2
Makefile2

@@ -17,12 +17,12 @@ build:
 	CGO_ENABLED=1 go build -buildvcs=false -o euspace
 c:
 	#docker exec -it 9d928d96d4d0 sh -c 'cd /opt/github/euspace/ebpftracer && sh build.sh${PARAMS}'
-	docker exec -it 67b590ec7772 sh -c 'cd /opt/github/euspace/ebpftracer && sh build_linux.sh${PARAMS}'
+	docker exec -it 0cc230e1ba05 sh -c 'cd /opt/github/euspace/ebpftracer && sh build_linux.sh${PARAMS}'
 c-build: c
 
 go-build:
 	#ssh [email protected] 'export https_proxy=http://10.0.22.50:4780 && source ~/.g/env && cd /opt/github/euspace && make -f Makefile2 build'
-	docker exec -it 67b590ec7772 bash -c 'cd /opt/github/euspace && source ~/.g/env && make -f Makefile2 build'
+	docker exec -it 0cc230e1ba05 bash -c 'cd /opt/github/euspace && source ~/.g/env && make -f Makefile2 build'
 go: go-build run
 
 run:

+ 10 - 0
containers/container.go

@@ -1084,6 +1084,16 @@ func (c *Container) revalidateListens(now time.Time, actualListens map[netaddr.I
 	}
 }
 
+func (c *Container) attachUprobes(tracer *ebpftracer.Tracer, pid uint32){
+	codeType := GetExeType(pid)
+	switch codeType{
+	case "java":
+		c.attachJVMUprobes(tracer,pid)
+	case "go":
+		c.attachTlsUprobes(tracer,pid)
+	}
+}
+
 func (c *Container) attachTlsUprobes(tracer *ebpftracer.Tracer, pid uint32) {
 	p := c.processes[pid]
 	if p == nil {

+ 4 - 1
containers/registry.go

@@ -235,6 +235,8 @@ func (r *Registry) handleEvents(ch <-chan ebpftracer.Event) {
 					c.onListenOpen(e.Pid, e.SrcAddr, false)
 					c.buildInstanceID()
 					// c.attachTlsUprobes(r.tracer, e.Pid)
+					// c.attachJVMUprobes(r.tracer, e.Pid)
+					c.attachUprobes(r.tracer, e.Pid)
 				} else {
 					klog.Infoln("TCP listen open from unknown container", e)
 				}
@@ -248,7 +250,8 @@ func (r *Registry) handleEvents(ch <-chan ebpftracer.Event) {
 				if c := r.getOrCreateContainer(e.Pid); c != nil {
 					c.onConnectionOpen(e.Pid, e.Fd, e.SrcAddr, e.DstAddr, e.Timestamp, false)
 					// c.attachTlsUprobes(r.tracer, e.Pid)
-					c.attachJVMUprobes(r.tracer, e.Pid)
+					// c.attachJVMUprobes(r.tracer, e.Pid)
+					c.attachUprobes(r.tracer, e.Pid)
 				} else {
 					klog.Infoln("TCP connection from unknown container", e)
 				}

+ 82 - 0
containers/util.go

@@ -0,0 +1,82 @@
+package containers
+
+import (
+	"fmt"
+	"io/ioutil"
+	"log"
+	"regexp"
+	"debug/elf"
+	"os"
+    "os/exec"
+    "runtime"
+)
+
+var libjvmRegex = regexp.MustCompile(`.*/libjvm\.so`)
+
+func GetExeType(pid uint32) string{
+	mapsFilePath := fmt.Sprintf("/proc/%d/maps", pid)
+
+	data, err := ioutil.ReadFile(mapsFilePath)
+	if err != nil {
+		log.Fatalf("Failed to read %s: %s", mapsFilePath, err)
+	}
+
+	content := string(data)
+
+	if libjvmRegex.MatchString(content) {
+		fmt.Println("is java process")
+		return string("java")
+	}else if isGoProcess(pid){
+		return string("go")
+		fmt.Println("is go process")
+	}
+	return ""
+}
+
+func isGoProcess(pid uint32) bool{
+	path, err := getProcessPath(pid)
+	if err != nil {
+		fmt.Printf("无法获取进程路径:%s\n", err)
+		return false
+	}
+	ef, err := elf.Open(path)
+	if err != nil {
+		fmt.Println("failed to open as elf binary", err)
+		return false
+	}
+	defer ef.Close()
+
+	gopclntabSection := ef.Section(".gopclntab")
+    if gopclntabSection != nil {
+            fmt.Println("is a go process")
+            return true
+    } 
+	return false
+}
+
+func getProcessPath(pid uint32) (string, error) {
+	switch runtime.GOOS {
+	case "linux":
+		return getLinuxProcessPath(pid)
+	default:
+		return "", fmt.Errorf("不支持的操作系统:%s", runtime.GOOS)
+	}
+}
+
+func getLinuxProcessPath(pid uint32) (string, error) {
+	procPath := fmt.Sprintf("/proc/%d/exe", pid)
+	path, err := os.Readlink(procPath)
+	if err != nil {
+		return "", err
+	}
+	return path, nil
+}
+
+func executeCommand(name string, args ...string) (string, error) {
+	cmd := exec.Command(name, args...)
+	out, err := cmd.Output()
+	if err != nil {
+		return "", err
+	}
+	return string(out), nil
+}

+ 41 - 6
ebpftracer/jvm.go

@@ -2,10 +2,12 @@ package ebpftracer
 
 import (
 	"errors"
-
+	"io/ioutil"
+	"strings"
 
 	"fmt"
 	"debug/elf"
+	"path/filepath"
 
 	"github.com/coroot/coroot-node-agent/utils"
 
@@ -15,7 +17,7 @@ import (
 
 const (
 	// goServeHTTP           = "net/http.serverHandler.ServeHTTP"
-	binPath           = "/root/code/jdk8u/build/linux-x86_64-normal-server-release/jdk/lib/amd64/libnio.so"
+	// binPath           = "/root/code/jdk8u/build/linux-x86_64-normal-server-release/jdk/lib/amd64/libnio.so"
 	symbolsocketRead0 = "Java_sun_nio_ch_FileDispatcherImpl_read0"
 )
 
@@ -24,12 +26,17 @@ func (t *Tracer) AttachJavaNioReadUprobes(pid uint32, insID utils.ID) []link.Lin
 		return nil
 	}
 	var links []link.Link
-	ex, err := link.OpenExecutable(binPath)
+	bpath := getSoPath(pid, "nio.so")
+	if bpath == ""{
+		fmt.Println("can,t find the nio.so")
+		return nil
+	}
+	fmt.Println("find the nio.so path is ", bpath)
+	ex, err := link.OpenExecutable(bpath)
 	if err != nil {
 		return nil
 	}
-
-	ef, err := elf.Open(binPath)
+	ef, err := elf.Open(bpath)
 	if err != nil {
 		return nil
 	}
@@ -108,7 +115,7 @@ func (t *Tracer) AttachJavaNioReadUprobes(pid uint32, insID utils.ID) []link.Lin
 	if len(links) == 0 {
 		return nil
 	}
-	fmt.Println("jvm uprobes attached")
+	fmt.Println("jvm uprobes attached, pid is ", pid)
 	return links
 }
 
@@ -133,3 +140,31 @@ func getCallNextMoveOffsets(machine elf.Machine, instructions []byte) []int {
 	}
 	return res
 }
+
+func getSoPath(pid uint32, soname string) string{
+	// 获取进程的maps文件路径
+	mapsPath := fmt.Sprintf("/proc/%d/maps", pid)
+
+	// 读取maps文件内容
+	mapsData, err := ioutil.ReadFile(mapsPath)
+	if err != nil {
+		fmt.Println("无法读取maps文件")
+		return ""
+	}
+
+	lines := strings.Split(string(mapsData), "\n")
+	for _, line := range lines {
+		fields := strings.Fields(line)
+		if len(fields) >= 6 {
+			perms := fields[1]
+			path := fields[len(fields)-1]
+
+			if strings.Contains(perms, "x") && filepath.Ext(path) == ".so" {
+				if strings.Contains(path, soname){
+					return path
+				}
+			}
+		}
+	}
+	return ""
+}