Sfoglia il codice sorgente

Fixed #TASK_GK-2944 uprobe

Carl 2 anni fa
parent
commit
12c072e64a

+ 1 - 0
ebpftracer/ebpf/ebpf.c

@@ -42,6 +42,7 @@
 #include "file.c"
 #include "tcp/state.c"
 #include "tcp/retransmit.c"
+#include "l7/uprobe_base_bpf.c"
 #include "l7/l7.c"
 #include "l7/gotls.c"
 #include "l7/openssl.c"

+ 49 - 3
ebpftracer/ebpf/l7/apm_trace.c

@@ -9,6 +9,12 @@ struct trace_key_t {
     __u32 pid;
 };
 
+struct fd_trace_key_t {
+    __u32 tgid;
+    __u32 fd;
+};
+
+
 struct trace_info_t {
     /*
      * Whether traceID is zero ?
@@ -29,9 +35,16 @@ struct {
     __uint(max_entries, 32768);
 } trace_info_heap SEC(".maps");
 
+struct {
+    __uint(type, BPF_MAP_TYPE_LRU_HASH);
+    __uint(key_size, sizeof(struct fd_trace_key_t));
+    __uint(value_size, sizeof(struct trace_info_t));
+    __uint(max_entries, 32768);
+} fd_trace_info_heap SEC(".maps");
+
 
 static inline __attribute__((__always_inline__))
-struct trace_key_t get_trace_key(__u32 pid,__u32 tid){
+struct trace_key_t get_trace_key(__u32 pid, __u32 tid) {
     struct trace_key_t trace_key = {};
     trace_key.tgid = pid;
     trace_key.pid = tid;
@@ -39,12 +52,45 @@ struct trace_key_t get_trace_key(__u32 pid,__u32 tid){
 }
 
 static inline __attribute__((__always_inline__))
-__u64 get_trace_id(__u32 pid, __u32 tid){
+__u64 get_trace_id(__u32 pid, __u32 tid) {
     struct trace_key_t trace_key = get_trace_key(pid, tid);
     struct trace_info_t *trace_info = bpf_map_lookup_elem(&trace_info_heap, &trace_key);
     if (trace_info) {
-        bpf_printk("trace_id:%llu",trace_info->trace_id);
+        bpf_printk("trace_id:%llu", trace_info->trace_id);
+        return trace_info->trace_id;
+    }
+    return 0;
+}
+
+static __inline __attribute__((__always_inline__))
+struct fd_trace_key_t get_fd_trace_key(__u32 pid, __u32 fd) {
+    struct fd_trace_key_t trace_key = {};
+    trace_key.tgid = pid;
+    trace_key.fd = fd;
+    return trace_key;
+}
+
+static inline __attribute__((__always_inline__))
+__u64 get_fd_trace_id(__u32 pid, __u32 fd) {
+    struct fd_trace_key_t trace_key = get_fd_trace_key(pid, fd);
+    struct trace_info_t *trace_info = bpf_map_lookup_elem(&fd_trace_info_heap, &trace_key);
+    if (trace_info) {
+        bpf_printk("fd_trace_id:%llu", trace_info->trace_id);
         return trace_info->trace_id;
     }
     return 0;
 }
+
+
+static inline __attribute__((__always_inline__))
+__u64 clear_trace(__u32 pid, __u32 tid, __u32 fd) {
+    struct trace_key_t trace_key = get_trace_key(pid, tid);
+    struct fd_trace_key_t fd_trace_key = get_fd_trace_key(pid, fd);
+    // 清除trace信息
+    bpf_map_delete_elem(&trace_info_heap, &trace_key);
+    bpf_map_delete_elem(&fd_trace_info_heap, &fd_trace_key);
+    return 0;
+}
+
+
+#pragma clang diagnostic pop

+ 3 - 0
ebpftracer/ebpf/l7/gotls.c

@@ -4,6 +4,9 @@
 #define GO_PARAM2(x) ((x)->bx)
 #define GO_PARAM3(x) ((x)->cx)
 #define GOROUTINE(x) ((x)->r14)
+#define PT_GO_REGS_PARM1(x) ((x)->rax)
+#define PT_GO_REGS_PARM2(x) ((x)->rbx)
+
 #elif defined(__TARGET_ARCH_arm64)
 #define GO_PARAM1(x) (((PT_REGS_ARM64 *)(x))->regs[0])
 #define GO_PARAM2(x) (((PT_REGS_ARM64 *)(x))->regs[1])

+ 34 - 20
ebpftracer/ebpf/l7/l7.c

@@ -37,6 +37,7 @@
         return 0;                           \
     }                                       \
 })
+#define NS_PER_SEC		1000000000ULL
 
 #define IOVEC_BUF_SIZE MAX_PAYLOAD_SIZE * 2  // must be double of MAX_PAYLOAD_SIZE
 #define MAX_IOVEC_SIZE 32
@@ -55,7 +56,7 @@
 #include "dubbo2.c"
 #include "apm_trace.c"
 
-__u32 filterPid = 88028;
+__u32 filterPid = 8153;
 
 struct l7_event {
     __u64 fd;
@@ -254,17 +255,19 @@ int trace_enter_write(void *ctx, __u64 fd, __u16 is_tls, char *buf, __u64 size,
     k.is_tls = is_tls;
     k.stream_id = -1;
 
-    bpf_printk("enter-payload:%s|type:%s|FD:%d\n",payload,"type",k.fd);
+//    bpf_printk("enter-payload:%s|type:%s|FD:%d\n",payload,"type",k.fd);
 
     if (is_http_response(payload, &http_status))
     {
-        bpf_printk("[Response][HTTP]:TGID:%d|type:%s|FD:%d\n", k.pid, "type", k.fd);
-        struct trace_key_t trace_key = get_trace_key(pid, tid);
-        __u64 trace_id = get_trace_id(pid, tid);
-        bpf_printk("trace_id:%llu", trace_id);
+//        __u64 goid = get_rw_goid(120 * NS_PER_SEC, 1);
+//        bpf_printk("[Response][HTTP]:thread_id:%d|goid:%d|FD:%d\n", tid, goid, k.fd);
+//        struct trace_key_t trace_key = get_trace_key(pid, tid);
+//        struct fd_trace_key_t fd_trace_key = get_fd_trace_key(pid, fd);
+        __u64 trace_id = get_fd_trace_id(pid, fd);
+//        bpf_printk("trace_id:%llu", trace_id);
+        bpf_printk("[Response][HTTP] pid:%d,fd:%d,traceid:%llu", pid, fd, trace_id);
         // 清除trace信息
-        bpf_map_delete_elem(&trace_info_heap, &trace_key);
-
+        clear_trace(pid, tid, fd);
         // 发送事件到用户空间 start
         struct l7_event *e = bpf_map_lookup_elem(&l7_event_heap, &zero);
         if (!e) {
@@ -273,15 +276,14 @@ int trace_enter_write(void *ctx, __u64 fd, __u16 is_tls, char *buf, __u64 size,
         struct l7_request *req = bpf_map_lookup_elem(&active_l7_requests, &k);
         if (!req)
         {
-            bpf_printk("[Response][HTTP]:no req-----------");
-            bpf_printk("[Response][HTTP]:pid:%d|tid:%d",k.pid,k.fd);
-            bpf_printk("[Response][HTTP]:is_tls:%d|tid:%d",k.is_tls,k.stream_id);
+//            bpf_printk("[Response][HTTP]:no req-----------");
+//            bpf_printk("[Response][HTTP]:pid:%d|tid:%d",k.pid,k.fd);
+//            bpf_printk("[Response][HTTP]:is_tls:%d|tid:%d",k.is_tls,k.stream_id);
             return 0;
         }
-        bpf_printk("[Response][HTTP]:req->ns:%d\n",req->ns);
 
         e->duration = bpf_ktime_get_ns() - req->ns;
-        bpf_printk("[Response][HTTP]:duration->ns:%d\n",e->duration);
+//        bpf_printk("[Response][HTTP]:duration->ns:%d\n",e->duration);
         e->protocol = PROTOCOL_TRACE;
         e->status = http_status;
         e->pid = k.pid;
@@ -290,7 +292,6 @@ int trace_enter_write(void *ctx, __u64 fd, __u16 is_tls, char *buf, __u64 size,
         e->trace_start = 0;
         e->trace_end = 1;
         e->trace_id = trace_id;
-        bpf_printk("[Response][HTTP]:status:%d",e->status);
         e->payload_size = size;
         COPY_PAYLOAD(e->payload, size, payload);
         bpf_map_delete_elem(&active_l7_requests, &k);
@@ -323,7 +324,7 @@ int trace_enter_write(void *ctx, __u64 fd, __u16 is_tls, char *buf, __u64 size,
     } else if (is_memcached_query(payload, size)) {
         req->protocol = PROTOCOL_MEMCACHED;
     } else if (is_mysql_query(payload, size, &req->request_type)) {
-        bpf_printk("[Enter][Mysql]:TGID:%d|type:%s|FD:%d\n",k.pid,"type",k.fd);
+        bpf_printk("[Enter][Mysql]:thread_id:%d\n",tid);
         if (req->request_type == MYSQL_COM_STMT_CLOSE) {
             struct l7_event *e = bpf_map_lookup_elem(&l7_event_heap, &zero);
             if (!e) {
@@ -480,8 +481,13 @@ int trace_exit_read(void *ctx, __u64 id, __u32 pid, __u16 is_tls, long int ret)
             bpf_map_update_elem(&active_l7_requests, &k, req, BPF_NOEXIST);
         }
 
-        bpf_printk("[Receive][HTTP]:TGID:%d|type:%s|FD:%d\n",k.pid,"type",k.fd);
-        bpf_printk("[Receive][HTTP] payload1:%s|type:%s\n",payload,"type");
+        bpf_printk("[Receive][HTTP]:thread_id:%d\n",tid);
+//        bpf_printk("[Receive][HTTP] payload1:%s|type:%s\n",payload,"type");
+//        __u64 goid = 0;
+//        goid = get_rw_goid(120 * NS_PER_SEC, 1);
+//        bpf_printk("[Receive][HTTP] goid:%llu\n",goid);
+//        __u64 goid = get_rw_goid(120 * NS_PER_SEC, 1);
+//        bpf_printk("[Receive][HTTP]:thread_id:%d|goid:%d|FD:%d\n", tid, goid, k.fd);
 
         struct trace_key_t trace_key = {};
         struct trace_info_t trace_info = {};
@@ -496,6 +502,14 @@ int trace_exit_read(void *ctx, __u64 id, __u32 pid, __u16 is_tls, long int ret)
         e->payload_size = ret;
         COPY_PAYLOAD(e->payload, ret, payload);
 
+        // http trace
+        struct fd_trace_key_t fd_trace_key = {};
+        fd_trace_key.tgid = pid;
+        fd_trace_key.fd = k.fd;
+        bpf_map_update_elem(&fd_trace_info_heap, &fd_trace_key, &trace_info, BPF_NOEXIST);
+        bpf_printk("[Receive][HTTP] pid:%d,fd:%d,traceid:%llu", fd_trace_key.tgid, fd_trace_key.fd,
+                   trace_info.trace_id);
+
         // 入口方法缓存  bpf_map_update_elem(map, key, value, options)
         bpf_map_update_elem(&trace_info_heap, &trace_key, &trace_info, BPF_NOEXIST);
         bpf_perf_event_output(ctx, &l7_events, BPF_F_CURRENT_CPU, e, sizeof(*e));
@@ -544,7 +558,7 @@ int trace_exit_read(void *ctx, __u64 id, __u32 pid, __u16 is_tls, long int ret)
 
     bpf_map_delete_elem(&active_l7_requests, &k);
     if (e->protocol == PROTOCOL_HTTP) {
-        bpf_printk("[Response][HTTP]:TGID:%d|type:%s|FD:%d\n",k.pid,"type",k.fd);
+        bpf_printk("[Response][HTTP]:thread_id:%d\n",tid);
         response = is_http_response(payload, &e->status);
     } else if (e->protocol == PROTOCOL_POSTGRES) {
         response = is_postgres_response(payload, ret, &e->status);
@@ -560,9 +574,9 @@ int trace_exit_read(void *ctx, __u64 id, __u32 pid, __u16 is_tls, long int ret)
     } else if (e->protocol == PROTOCOL_MEMCACHED) {
         response = is_memcached_response(payload, ret, &e->status);
     } else if (e->protocol == PROTOCOL_MYSQL) {
-        bpf_printk("[Response][Mysql]:TGID:%d|type:%s|FD:%d\n",k.pid,"type",k.fd);
+        bpf_printk("[Response][Mysql]:thread_id:%d\n",tid);
         __u64 trace_id = get_trace_id(pid, tid);
-        bpf_printk("[Mysql] trace_id:%llu", trace_id);
+//        bpf_printk("[Mysql] trace_id:%llu", trace_id);
         e->trace_id = trace_id;
         response = is_mysql_response(payload, ret, req->request_type, &e->statement_id, &e->status);
         if (req->request_type == MYSQL_COM_STMT_PREPARE) {

+ 269 - 0
ebpftracer/ebpf/l7/uprobe_base_bpf.c

@@ -0,0 +1,269 @@
+#define GOROUTINE(x) ((x)->r14)
+#define MAX_SYSTEM_THREADS 4096
+#define HASH_ENTRIES_MAX 40960
+
+struct go_key {
+    __u32 tgid;
+    __u64 goid;
+} __attribute__((packed));
+
+struct bpf_map_def SEC("maps") go_ancerstor_map = {
+        .type = BPF_MAP_TYPE_LRU_HASH,
+        .key_size = sizeof(struct go_key),
+        .value_size = sizeof(__u64),
+        .max_entries = HASH_ENTRIES_MAX,
+};
+
+struct bpf_map_def SEC("maps") go_rw_ts_map = {
+        .type = BPF_MAP_TYPE_LRU_HASH,
+        .key_size = sizeof(struct go_key),
+        .value_size = sizeof(__u64),
+        .max_entries = HASH_ENTRIES_MAX,
+};
+
+struct bpf_map_def SEC("maps") goroutines_map = {
+        .type = BPF_MAP_TYPE_HASH,
+        .key_size = sizeof(__u64),
+        .value_size = sizeof(__u64),
+        .max_entries = MAX_SYSTEM_THREADS,
+};
+
+// Pass data between coroutine entry and exit functions
+struct go_newproc_caller {
+    __u64 goid;
+    void *sp; // stack pointer
+} __attribute__((packed));
+
+struct bpf_map_def SEC("maps") pid_tgid_callerid_map = {
+        .type = BPF_MAP_TYPE_HASH,
+        .key_size = sizeof(__u64),
+        .value_size = sizeof(struct go_newproc_caller),
+        .max_entries = MAX_SYSTEM_THREADS,
+};
+
+
+static __inline __u64 get_current_goroutine(void)
+{
+    __u64 current_thread = bpf_get_current_pid_tgid();
+    __u64 *goid_ptr = bpf_map_lookup_elem(&goroutines_map, &current_thread);
+    if (goid_ptr) {
+        return *goid_ptr;
+    }
+
+    return 0;
+}
+
+static __inline int is_final_ancestor(__u32 tgid, __u64 goid, __u64 now,
+                                      __u64 timeout)
+{
+    struct go_key key = { .tgid = tgid, .goid = goid };
+
+    __u64 *ts = bpf_map_lookup_elem(&go_rw_ts_map, &key);
+    if (!ts) {
+        return 0;
+    }
+
+    return now < *ts + timeout;
+}
+
+
+static __inline __u64 get_rw_goid(__u64 timeout, int is_socket_io)
+{
+    __u32 tgid = (__u32)(bpf_get_current_pid_tgid() >> 32);
+    __u64 ts = bpf_ktime_get_ns();
+    __u64 goid = get_current_goroutine();
+    if (goid == 0) {
+        return 0;
+    }
+
+    __u64 ancestor = goid;
+
+    int idx = 0;
+#pragma unroll
+    for (idx = 0; idx < 6; ++idx) {
+        if (is_final_ancestor(tgid, ancestor, ts, timeout)) {
+            return ancestor;
+        }
+        struct go_key key = { .tgid = tgid, .goid = ancestor };
+        __u64 *newancestor =
+                bpf_map_lookup_elem(&go_ancerstor_map, &key);
+        if (!newancestor) {
+            break;
+        }
+        ancestor = *newancestor;
+    }
+
+//    if (!is_socket_io) {
+//        return 0;
+//    }
+
+    struct go_key key = { .tgid = tgid, .goid = goid };
+    bpf_map_update_elem(&go_rw_ts_map, &key, &ts, BPF_ANY);
+    return goid;
+}
+
+
+
+SEC("uprobe/runtime.execute")
+int runtime_execute(struct pt_regs *ctx)// ok
+{
+    __u64 pid_tgid = bpf_get_current_pid_tgid();
+    __u32 tgid = pid_tgid >> 32;
+    __u32 tid = (__u32) pid_tgid;
+
+//    struct ebpf_proc_info *info = bpf_map_lookup_elem(&proc_info_map, &tgid);
+//    if (!info) {
+//        return 0;
+//    }
+//    int offset_g_goid = info->offsets[OFFSET_IDX_GOID_RUNTIME_G];
+//    if (offset_g_goid < 0) {
+//        return 0;
+//    }
+
+//    void *g_ptr;
+
+//    g_ptr = (void *) PT_GO_REGS_PARM1(ctx);
+
+    int offset_g_goid = 152;
+
+//    __s64 goid = 0;
+//    bpf_probe_read(&goid, sizeof(goid), g_ptr + offset_g_goid);
+
+    __s64 goroutine_id = GOROUTINE(ctx);
+
+    bpf_map_update_elem(&goroutines_map, &pid_tgid, &goroutine_id, BPF_ANY);
+    bpf_printk("[GO] [runtime.execute] thread_id:%d|goid:%d", tid, goroutine_id);
+
+    return 0;
+}
+
+SEC("uprobe/enter_runtime.newproc1")
+int enter_runtime_newproc1(struct pt_regs *ctx)
+{
+    __s64 goroutine_id = GOROUTINE(ctx);
+//    __u64 goroutine_id2 = GOROUTINE(ctx);
+
+
+    __u64 pid_tgid = bpf_get_current_pid_tgid();
+    bpf_printk("[GO] [runtime.newproc1] [enter] pid_tgid:%llu | goid:%d", pid_tgid, goroutine_id);
+//    bpf_printk("[GO] [runtime.newproc1] [enter] pid_tgid:%llu | goid:%d", pid_tgid, goroutine_id2);
+    __u32 tgid = pid_tgid >> 32;
+
+//    struct ebpf_proc_info *info =
+//            bpf_map_lookup_elem(&proc_info_map, &tgid);
+//    if (!info) {
+//        return 0;
+//    }
+
+    // go less than 1.15 cannot get parent-child coroutine relationship
+    // ~ go1.14: func newproc1(fn *funcval, argp unsafe.Pointer, narg int32, callergp *g, callerpc uintptr)
+//    if (info->version < GO_VERSION(1, 15, 0)) {
+//        return 0;
+//    }
+
+    int offset_g_goid = 152;
+//    if (offset_g_goid < 0)
+//    {
+//        return 0;
+//    }
+
+//    void *g_ptr = (void *) PT_GO_REGS_PARM2(ctx);;
+//    if (is_register_based_call(info)) {
+//        // https://github.com/golang/go/commit/8e5304f7298a0eef48e4796017c51b4d9aeb52b5
+//        if (info->version >= GO_VERSION(1, 18, 0)) {
+//            g_ptr = (void *)PT_GO_REGS_PARM2(ctx);
+//        } else {
+//            g_ptr = (void *)PT_GO_REGS_PARM4(ctx);
+//        }
+//    } else {
+//        if (info->version >= GO_VERSION(1, 18, 0)) {
+//            bpf_probe_read(&g_ptr, sizeof(g_ptr),
+//                           (void *)(PT_REGS_SP(ctx) + 16));
+//        } else {
+//            bpf_probe_read(&g_ptr, sizeof(g_ptr),
+//                           (void *)(PT_REGS_SP(ctx) + 32));
+//        }
+//    }
+
+//    __s64 goid = 0;
+//    bpf_probe_read(&goid, sizeof(goid), g_ptr + offset_g_goid);
+//    bpf_printk("[GO] [runtime.newproc1] [enter] pid_tgid:%llu | goid:%llu", pid_tgid, goid);
+
+//    if (!goid)
+//    {
+//        bpf_printk("[GO] [runtime.newproc1] [enter] pid_tgid:%llu | goid:%llu", pid_tgid, goid);
+//        return 0;
+//    }
+
+    struct go_newproc_caller caller = {
+            .goid = goroutine_id,
+//            .sp = (void *) PT_REGS_SP(ctx),
+    };
+//    if (!caller.sp) {
+    bpf_map_update_elem(&pid_tgid_callerid_map, &pid_tgid, &caller, BPF_ANY);
+//    }
+//    bpf_printk("[GO] [runtime.newproc1] [enter] pid_tgid:%llu | goid:%llu", pid_tgid);
+    return 0;
+}
+
+//
+SEC("uprobe/exit_runtime.newproc1")
+int exit_runtime_newproc1(struct pt_regs *ctx)
+{
+    __u64 pid_tgid = bpf_get_current_pid_tgid();
+    __u32 tgid = pid_tgid >> 32;
+    __u32 tid = (__u32) pid_tgid;
+
+//    struct ebpf_proc_info *info =
+//            bpf_map_lookup_elem(&proc_info_map, &tgid);
+//    if (!info) {
+//        return 0;
+//    }
+//
+//    if(info->version < GO_VERSION(1, 15, 0)){
+//        return 0;
+//    }
+
+//    int offset_g_goid = 152;
+//    if (offset_g_goid < 0)
+//    {
+//        return 0;
+//    }
+
+    struct go_newproc_caller *caller =
+            bpf_map_lookup_elem(&pid_tgid_callerid_map, &pid_tgid);
+    if (!caller)
+    {
+        bpf_printk("[GO] [runtime.newproc1] [exit] has no caller thread_id:%d", tid);
+
+        return 0;
+    }
+
+//    void *g_ptr;
+//    g_ptr = (void *) PT_GO_REGS_PARM1(ctx);
+//    if (is_register_based_call(info)) {
+//    } else {
+//        if (info->version >= GO_VERSION(1, 18, 0)) {
+//            bpf_probe_read(&g_ptr, sizeof(g_ptr), caller->sp + 32);
+//        } else {
+//            bpf_probe_read(&g_ptr, sizeof(g_ptr), caller->sp + 48);
+//        }
+//    }
+
+    __s64 goid = GOROUTINE(ctx);
+//    bpf_probe_read(&goid, sizeof(goid), g_ptr + offset_g_goid);
+//    if (!goid)
+//    {
+//        bpf_map_delete_elem(&pid_tgid_callerid_map, &pid_tgid);
+//        return 0;
+//    }
+
+    struct go_key key = {.tgid = tgid, .goid = goid};
+    __u64 callergoid = caller->goid;
+    bpf_map_update_elem(&go_ancerstor_map, &key, &callergoid, BPF_ANY);
+
+    bpf_map_delete_elem(&pid_tgid_callerid_map, &pid_tgid);
+    bpf_printk("[GO] [runtime.newproc1] [exit] thread_id:%d|current_goid:%d|caller_goid:%d\n", tid, goid, callergoid);
+
+    return 0;
+}

+ 2 - 0
ebpftracer/ebpf/vmlinux.h

@@ -9,6 +9,8 @@ struct pt_regs {
 	long unsigned int r12;
 	long unsigned int bp;
 	long unsigned int bx;
+    long unsigned  rax;
+    long unsigned  rbx;
 	long unsigned int r11;
 	long unsigned int r10;
 	long unsigned int r9;