فهرست منبع

Fixed #TASK_GK-2944 横向串联

Carl 2 سال پیش
والد
کامیت
0f121277a6

+ 79 - 28
ebpftracer/ebpf/l7/apm_trace.c

@@ -16,12 +16,44 @@ struct fd_trace_key_t {
 };
 
 
+//#define APM_TRACE_ID_SIZE 16
+//#define APM_SPAN_ID_SIZE 8
+#define APM_REMOTE_ADDR_MAX_LEN 256
+
+#define APM_TYPE_FROM_STRING_SIZE 2
+#define APM_SAMPLE_STRING_SIZE 2
+#define APM_HOST_ID_STRING_SIZE 16
+#define APM_APP_ID_STRING_SIZE 16
+#define APM_INSTANCE_ID_STRING_SIZE 16
+#define APM_TRACE_ID_STRING_SIZE 32
+#define APM_ASSUMED_APP_ID_STRING_SIZE 16
+#define APM_SPAN_ID_STRING_SIZE 16
+
+#define APM_TYPE_FROM_SIZE 1
+#define APM_SAMPLE_SIZE 1
+#define APM_HOST_ID_SIZE 8
+#define APM_APP_ID_SIZE 8
+#define APM_INSTANCE_ID_SIZE 8
 #define APM_TRACE_ID_SIZE 16
+#define APM_ASSUMED_APP_ID_SIZE 8
 #define APM_SPAN_ID_SIZE 8
 
+#define CW_HEADER_LENGTH 123
+
+//struct apm_span_context {
+//	unsigned char TraceID[APM_TRACE_ID_SIZE];
+//	unsigned char SpanID[APM_SPAN_ID_SIZE];
+//};
+
 struct apm_span_context {
-	unsigned char TraceID[APM_TRACE_ID_SIZE];
-	unsigned char SpanID[APM_SPAN_ID_SIZE];
+	unsigned char type_from[APM_TYPE_FROM_SIZE];
+	unsigned char sample[APM_SAMPLE_SIZE];
+	unsigned char host_id[APM_HOST_ID_SIZE];
+	unsigned char app_id[APM_APP_ID_SIZE];
+	unsigned char instance_id[APM_INSTANCE_ID_SIZE];
+	unsigned char trace_id[APM_TRACE_ID_SIZE];
+	unsigned char assumed_app_id[APM_ASSUMED_APP_ID_SIZE];
+	unsigned char span_id[APM_SPAN_ID_SIZE];
 };
 
 struct apm_trace_info_t {
@@ -35,7 +67,7 @@ struct apm_trace_info_t {
 	//	__u64 thread_trace_id; // 线程追踪ID
 	//	__u64 socket_id; // Records the socket associated when tracing was created (记录创建追踪时关联的socket)
 	__u64 trace_id;
-	struct apm_span_context sc;
+	struct apm_span_context psc;
 };
 
 struct {
@@ -118,17 +150,7 @@ __u64 get_fd_trace_id(__u32 pid, __u32 fd) {
 }
 
 static __inline __attribute__((__always_inline__))
-__u64 clear_trace(__u32 pid, __u32 tid, __u32 fd) {
-	struct apm_trace_key_t trace_key = get_apm_trace_key(120 * NS_PER_SEC, true);
-	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;
-}
-
-static __inline __attribute__((__always_inline__))
-void save_tracking_span(struct apm_span_context *sc) {
+void cw_save_parent_tracking_span(struct apm_span_context *sc) {
 	struct apm_trace_key_t trace_key = get_apm_trace_key(120 * NS_PER_SEC, true);
 	long err = 0;
 	err = bpf_map_update_elem(&apm_span_context_map, &trace_key, sc, BPF_ANY);
@@ -136,31 +158,60 @@ void save_tracking_span(struct apm_span_context *sc) {
 		bpf_printk("Failed to update tracked_spans map: %ld", err);
 		return;
 	}
-	struct apm_span_context *span_contexts = bpf_map_lookup_elem(&apm_span_context_map, &trace_key);
-	if (span_contexts) {
-		for (int i = 0; i < APM_TRACE_ID_SIZE; i++) {
-			bpf_printk("---%02x", span_contexts->TraceID[i]);
-		}
-
-		for (int i = 0; i < APM_SPAN_ID_SIZE; i++) {
-			bpf_printk("===%02x", span_contexts->SpanID[i]);
-		}
-	}
 }
 
 static __inline __attribute__((__always_inline__))
-struct apm_span_context * get_tracking_span() {
-	struct apm_span_context *apm_sc = {0};
+struct apm_span_context *cw_get_parent_tracking_span() {
 	struct apm_trace_key_t trace_key = get_apm_trace_key(120 * NS_PER_SEC, true);
+	struct apm_span_context *apm_sc = {0};
 	struct apm_span_context *span_contexts = bpf_map_lookup_elem(&apm_span_context_map, &trace_key);
+	bpf_printk("-------");
+
 	if (span_contexts) {
+		for (int i = 0; i < APM_TYPE_FROM_SIZE; i++) {
+			bpf_printk("type_from[%d] = %02x", i, span_contexts->type_from[i]);
+		}
+		for (int i = 0; i < APM_SAMPLE_SIZE; i++) {
+			bpf_printk("sample[%d] = %02x", i, span_contexts->sample[i]);
+		}
+		for (int i = 0; i < APM_HOST_ID_SIZE; i++) {
+			bpf_printk("host_id[%d] = %02x", i, span_contexts->host_id[i]);
+		}
+		for (int i = 0; i < APM_APP_ID_SIZE; i++) {
+			bpf_printk("app_id[%d] = %02x", i, span_contexts->app_id[i]);
+		}
+		for (int i = 0; i < APM_INSTANCE_ID_SIZE; i++) {
+			bpf_printk("instance_id[%d] = %02x", i, span_contexts->instance_id[i]);
+		}
 		for (int i = 0; i < APM_TRACE_ID_SIZE; i++) {
-			bpf_printk("get---%02x", span_contexts->TraceID[i]);
+			bpf_printk("trace_id[%d] = %02x", i, span_contexts->trace_id[i]);
+		}
+		for (int i = 0; i < APM_ASSUMED_APP_ID_SIZE; i++) {
+			bpf_printk("assumed_app_id[%d] = %02x", i, span_contexts->assumed_app_id[i]);
 		}
 		for (int i = 0; i < APM_SPAN_ID_SIZE; i++) {
-			bpf_printk("get===%02x", span_contexts->SpanID[i]);
+			bpf_printk("span_id[%d] = %02x", i, span_contexts->span_id[i]);
 		}
 		apm_sc = span_contexts;
 	}
+	bpf_printk("-------end");
+
 	return apm_sc;
+}
+
+static __inline __attribute__((__always_inline__))
+__u64 clear_span_context() {
+	struct apm_trace_key_t trace_key = get_apm_trace_key(120 * NS_PER_SEC, true);
+	bpf_map_delete_elem(&apm_span_context_map, &trace_key);
+	return 0;
+}
+
+static __inline __attribute__((__always_inline__))
+__u64 clear_trace(__u32 pid, __u32 tid, __u32 fd) {
+	struct apm_trace_key_t trace_key = get_apm_trace_key(120 * NS_PER_SEC, true);
+	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;
 }

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

@@ -330,7 +330,7 @@ int trace_enter_write(void *ctx, __u64 fd, __u16 is_tls, char *buf, __u64 size,
     }
 
     if (is_http_request(payload)) {
-        cw_bpf_debug("[Enter] [HTTP]:TGID:%d|FD:%d",k.pid,k.fd);
+        cw_bpf_debug("[Kernel Enter] [HTTP]:TGID:%d|FD:%d",k.pid,k.fd);
         req->protocol = PROTOCOL_HTTP;
 //        struct apm_trace_key_t trace_key = {0};
 //        trace_key = get_apm_trace_key(120 * NS_PER_SEC, true);
@@ -618,8 +618,8 @@ int trace_exit_read(void *ctx, __u64 id, __u32 pid, __u16 is_tls, long int ret)
     if (e->protocol == PROTOCOL_HTTP) {
         __u64 trace_id = get_apm_trace_id(pid, tid);
         e->trace_id = trace_id;
-        cw_bpf_debug("[Response][HTTP] [Trace ID] trace_id:%llu", e->trace_id);
-        cw_bpf_debug("[Response][HTTP]:TGID:%d|type:%s|FD:%d\n",k.pid,"",k.fd);
+        cw_bpf_debug("[Kernel Response][HTTP] [Trace ID] trace_id:%llu", e->trace_id);
+        cw_bpf_debug("[Kernel Response][HTTP]:TGID:%d|type:%s|FD:%d\n",k.pid,"",k.fd);
 
 //        cw_bpf_debug("[Response][HTTP222]:thread_id:%d|type:%s|FD:%d\n",k.pid,"",k.fd);
 //        cw_bpf_debug("[Response][HTTP222] trace_id:%llu", trace_id);

+ 140 - 0
ebpftracer/ebpf/utrace/go/include/alloc.h

@@ -0,0 +1,140 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef _ALLOC_H_
+#define _ALLOC_H_
+
+//#include "bpf_helpers.h"
+
+#define MAX_ENTRIES 50
+#define MAX_BUFFER_SIZE 1024
+#define MIN_BUFFER_SIZE 1
+
+// Injected in init
+volatile const u64 total_cpus;
+volatile const u64 start_addr;
+volatile const u64 end_addr;
+
+struct
+{
+    __uint(type, BPF_MAP_TYPE_PERCPU_HASH);
+    __type(key, s32);
+    __type(value, u64);
+    __uint(max_entries, MAX_ENTRIES);
+//    __uint(pinning, LIBBPF_PIN_BY_NAME);
+} alloc_map SEC(".maps");
+
+static __always_inline u64 get_area_start()
+{
+    s64 partition_size = (end_addr - start_addr) / total_cpus;
+    u32 current_cpu = bpf_get_smp_processor_id();
+    s32 start_index = 0;
+    u64 *start = (u64 *)bpf_map_lookup_elem(&alloc_map, &start_index);
+    if (start == NULL || *start == 0)
+    {
+        u64 current_start_addr = start_addr + (partition_size * current_cpu);
+        bpf_map_update_elem(&alloc_map, &start_index, &current_start_addr, BPF_ANY);
+        return current_start_addr;
+    }
+    else
+    {
+        return *start;
+    }
+}
+
+static __always_inline u64 get_area_end(u64 start)
+{
+    s64 partition_size = (end_addr - start_addr) / total_cpus;
+    s32 end_index = 1;
+    u64 *end = (u64 *)bpf_map_lookup_elem(&alloc_map, &end_index);
+    if (end == NULL || *end == 0)
+    {
+        u64 current_end_addr = start + partition_size;
+        bpf_map_update_elem(&alloc_map, &end_index, &current_end_addr, BPF_ANY);
+        return current_end_addr;
+    }
+    else
+    {
+        return *end;
+    }
+}
+
+static __always_inline s32 bound_number(s32 num, s32 min, s32 max)
+{
+    if (num < min)
+    {
+        return min;
+    }
+    else if (num > max)
+    {
+        return max;
+    }
+    return num;
+}
+
+static __always_inline void *write_target_data(void *data, s32 size)
+{
+    if (!data || data == NULL)
+    {
+        return NULL;
+    }
+
+    u64 start = get_area_start();
+    u64 end = get_area_end(start);
+    if (end - start < size)
+    {
+        bpf_printk("reached end of CPU memory block, going to the start again");
+        s32 start_index = 0;
+        bpf_map_delete_elem(&alloc_map, &start_index);
+        start = get_area_start();
+    }
+
+    void *target = (void *)start;
+    size = bound_number(size, MIN_BUFFER_SIZE, MAX_BUFFER_SIZE);
+    u64 page_offset = (u64)target & 0xFFF;
+    u64 dist_to_next_page = 4096 - page_offset;
+    if (dist_to_next_page < size)
+    {
+        target += dist_to_next_page;
+    }
+    u64 target_u = (u64)target;
+    if (target_u > end_addr || target_u < start_addr) {
+        bpf_printk("TARGET ADDRESS IS OUT OF BOUNDS: 0x%llx", target);
+        return NULL;
+    }
+
+    long success = bpf_probe_write_user(target, data, size);
+    if (success == 0)
+    {
+        s32 start_index = 0;
+        // Update the start position of this chunk, taking into account possible adjustments
+        // we made to be page aligned
+        u64 updated_start = target_u + size;
+
+        // align updated_start to 8 bytes
+        if (updated_start % 8 != 0) {
+            updated_start += 8 - (updated_start % 8);
+        }
+
+        bpf_map_update_elem(&alloc_map, &start_index, &updated_start, BPF_ANY);
+        return target;
+    }
+    else
+    {
+        bpf_printk("failed to write to userspace, error code: %d, addr: %lx, size: %d", success, target, size);
+        return NULL;
+    }
+}
+
+#endif

+ 91 - 0
ebpftracer/ebpf/utrace/go/include/arguments.h

@@ -0,0 +1,91 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef _ARGUMENTS_H_
+#define _ARGUMENTS_H_
+
+#include "go_common.h"
+//#include "bpf_tracing.h"
+//#include "bpf_helpers.h"
+#include <stdbool.h>
+
+// Injected in init
+volatile const bool is_registers_abi;
+
+static __always_inline void *get_argument_by_reg(struct pt_regs *ctx, int index)
+{
+    switch (index)
+    {
+    case 1:
+        return (void *)PT_GO_REGS_PARM1(ctx);
+    case 2:
+        return (void *)PT_GO_REGS_PARM2(ctx);
+    case 3:
+        return (void *)PT_GO_REGS_PARM3(ctx);
+    case 4:
+        return (void *)PT_GO_REGS_PARM4(ctx);
+    case 5:
+        return (void *)PT_GO_REGS_PARM5(ctx);
+    case 6:
+        return (void *)PT_GO_REGS_PARM6(ctx);
+    case 7:
+        return (void *)PT_GO_REGS_PARM7(ctx);
+    case 8:
+        return (void *)PT_GO_REGS_PARM8(ctx);
+    case 9:
+        return (void *)PT_GO_REGS_PARM9(ctx);
+    default:
+        return NULL;
+    }
+}
+
+static __always_inline void *get_argument_by_stack(struct pt_regs *ctx, int index)
+{
+    void *ptr = 0;
+    bpf_probe_read(&ptr, sizeof(ptr), (void *)(PT_REGS_SP(ctx) + (index * 8)));
+    return ptr;
+}
+
+static __always_inline void *get_argument(struct pt_regs *ctx, int index)
+{
+    if (is_registers_abi)
+    {
+        return get_argument_by_reg(ctx, index);
+    }
+
+    return get_argument_by_stack(ctx, index);
+}
+
+// Every span created by the auto instrumentation should contain end timestamp.
+// This end timestamp is recorded at the end of probed function by editing the struct that was created at the beginning.
+// Usually probes create an eBPF map to store the span struct and retrieve it at the end of the function.
+// Consistent key is used as a key for that map.
+// For Go < 1.17: consistent key is the address of context.Context.
+// For Go >= 1.17: consistent key is the goroutine address.
+static __always_inline void *get_consistent_key(struct pt_regs *ctx, void *contextContext)
+{
+    if (is_registers_abi)
+    {
+	    return (void *)GOROUTINE(ctx);
+    }
+
+    return contextContext;
+}
+
+static __always_inline bool is_register_abi()
+{
+    return is_registers_abi;
+}
+
+#endif

+ 151 - 0
ebpftracer/ebpf/utrace/go/include/go_common.h

@@ -0,0 +1,151 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#define MAX_OS_THREADS 20
+
+//#ifndef __VMLINUX_H__
+//#define __VMLINUX_H__
+#pragma once
+typedef unsigned char __u8;
+typedef short int __s16;
+typedef short unsigned int __u16;
+typedef int __s32;
+typedef unsigned int __u32;
+typedef long long int __s64;
+typedef long long unsigned int __u64;
+typedef __u8 u8;
+typedef __s16 s16;
+typedef __u16 u16;
+typedef __s32 s32;
+typedef __u32 u32;
+typedef __s64 s64;
+typedef __u64 u64;
+typedef __u16 __le16;
+typedef __u16 __be16;
+typedef __u32 __be32;
+typedef __u64 __be64;
+typedef __u32 __wsum;
+//
+//enum bpf_map_type
+//{
+//	BPF_MAP_TYPE_UNSPEC = 0,
+//	BPF_MAP_TYPE_HASH = 1,
+//	BPF_MAP_TYPE_ARRAY = 2,
+//	BPF_MAP_TYPE_PROG_ARRAY = 3,
+//	BPF_MAP_TYPE_PERF_EVENT_ARRAY = 4,
+//	BPF_MAP_TYPE_PERCPU_HASH = 5,
+//	BPF_MAP_TYPE_PERCPU_ARRAY = 6,
+//	BPF_MAP_TYPE_STACK_TRACE = 7,
+//	BPF_MAP_TYPE_CGROUP_ARRAY = 8,
+//	BPF_MAP_TYPE_LRU_HASH = 9,
+//	BPF_MAP_TYPE_LRU_PERCPU_HASH = 10,
+//	BPF_MAP_TYPE_LPM_TRIE = 11,
+//	BPF_MAP_TYPE_ARRAY_OF_MAPS = 12,
+//	BPF_MAP_TYPE_HASH_OF_MAPS = 13,
+//	BPF_MAP_TYPE_DEVMAP = 14,
+//	BPF_MAP_TYPE_SOCKMAP = 15,
+//	BPF_MAP_TYPE_CPUMAP = 16,
+//	BPF_MAP_TYPE_XSKMAP = 17,
+//	BPF_MAP_TYPE_SOCKHASH = 18,
+//	BPF_MAP_TYPE_CGROUP_STORAGE = 19,
+//	BPF_MAP_TYPE_REUSEPORT_SOCKARRAY = 20,
+//	BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE = 21,
+//	BPF_MAP_TYPE_QUEUE = 22,
+//	BPF_MAP_TYPE_STACK = 23,
+//	BPF_MAP_TYPE_SK_STORAGE = 24,
+//	BPF_MAP_TYPE_DEVMAP_HASH = 25,
+//	BPF_MAP_TYPE_STRUCT_OPS = 26,
+//	BPF_MAP_TYPE_RINGBUF = 27,
+//	BPF_MAP_TYPE_INODE_STORAGE = 28,
+//};
+//
+//enum
+//{
+//	BPF_ANY = 0,
+//	BPF_NOEXIST = 1,
+//	BPF_EXIST = 2,
+//	BPF_F_LOCK = 4,
+//};
+//
+///* BPF_FUNC_perf_event_output, BPF_FUNC_perf_event_read and
+// * BPF_FUNC_perf_event_read_value flags.
+// */
+//#define BPF_F_INDEX_MASK 0xffffffffULL
+//#define BPF_F_CURRENT_CPU BPF_F_INDEX_MASK
+//
+//#if defined(__TARGET_ARCH_x86)
+//struct pt_regs {
+//	/*
+//	 * C ABI says these regs are callee-preserved. They aren't saved on kernel entry
+//	 * unless syscall needs a complete, fully filled "struct pt_regs".
+//	 */
+//	long unsigned int r15;
+//	long unsigned int r14;
+//	long unsigned int r13;
+//	long unsigned int r12;
+//	long unsigned int bp;
+//	long unsigned int bx;
+//	/* These regs are callee-clobbered. Always saved on kernel entry. */
+//	long unsigned int r11;
+//	long unsigned int r10;
+//	long unsigned int r9;
+//	long unsigned int r8;
+//	long unsigned int ax;
+//	long unsigned int cx;
+//	long unsigned int dx;
+//	long unsigned int si;
+//	long unsigned int di;
+//	/*
+//	 * On syscall entry, this is syscall#. On CPU exception, this is error code.
+//	 * On hw interrupt, it's IRQ number:
+//	 */
+//	long unsigned int orig_ax;
+//	/* Return frame for iretq */
+//	long unsigned int ip;
+//	long unsigned int cs;
+//	long unsigned int flags;
+//	long unsigned int sp;
+//	long unsigned int ss;
+//	/* top of stack page */
+//};
+//#elif defined(__TARGET_ARCH_arm64)
+//struct user_pt_regs {
+//	__u64 regs[31];
+//	__u64 sp;
+//	__u64 pc;
+//	__u64 pstate;
+//};
+//
+//struct pt_regs {
+//	union {
+//		struct user_pt_regs user_regs;
+//		struct {
+//			u64 regs[31];
+//			u64 sp;
+//			u64 pc;
+//			u64 pstate;
+//		};
+//	};
+//	u64 orig_x0;
+//	s32 syscallno;
+//	u32 unused2;
+//	u64 orig_addr_limit;
+//	u64 pmr_save;
+//	u64 stackframe[2];
+//	u64 lockdep_hardirqs;
+//	u64 exit_rcu;
+//};
+//#endif
+//
+//#endif /* __VMLINUX_H__ */

+ 191 - 0
ebpftracer/ebpf/utrace/go/include/go_types.h

@@ -0,0 +1,191 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef _GO_TYPES_H
+#define _GO_TYPES_H
+
+#include "utils.h"
+#include "alloc.h"
+//#include "bpf_helpers.h"
+
+/* Max size of slice array in bytes 
+ Keep a power of 2 to help with masks */
+#define MAX_SLICE_ARRAY_SIZE 1024
+
+struct go_string_ot
+{
+    char *str;
+    s64 len;
+};
+
+struct go_slice_ot
+{
+    void *array;
+    s64 len;
+    s64 cap;
+};
+
+struct go_iface
+{
+    void *tab;
+    void *data;
+};
+
+struct map_bucket {
+    char tophash[8];
+    struct go_string_ot keys[8];
+    struct go_slice_ot values[8];
+    void *overflow;
+};
+
+struct slice_array_buff
+{
+    unsigned char buff[MAX_SLICE_ARRAY_SIZE];
+};
+
+struct
+{
+    __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
+    __type(key, u32);
+    __type(value, struct slice_array_buff);
+    __uint(max_entries, 1);
+} slice_array_buff_map SEC(".maps");
+
+// In Go, interfaces are represented as a pair of pointers: a pointer to the
+// interface data, and a pointer to the interface table.
+// See: runtime.iface in https://golang.org/src/runtime/runtime2.go
+static __always_inline void* get_go_interface_instance(void *iface)
+{
+    return (void*)(iface + 8);
+}
+
+static __always_inline struct go_string_ot write_user_go_string(char *str, u32 len)
+{
+    // Copy chars to userspace
+    struct go_string_ot new_string = {.str = NULL, .len = 0};
+    char *addr = write_target_data((void *)str, len);
+    if (addr == NULL) {
+        bpf_printk("write_user_go_string: failed to copy string to userspace");
+        return new_string;
+    }
+
+    // Build string struct in kernel space
+    new_string.str = addr;
+    new_string.len = len;
+
+    // Copy new string struct to userspace
+    void *res = write_target_data((void *)&new_string, sizeof(new_string));
+    if (res == NULL) {
+        new_string.len = 0;
+    }
+
+    return new_string;
+}
+
+static __always_inline void append_item_to_slice(void *new_item, u32 item_size, void *slice_user_ptr)
+{
+    // read the slice descriptor
+    struct go_slice_ot slice = {0};
+    bpf_probe_read(&slice, sizeof(slice), slice_user_ptr);
+    long res = 0;
+
+    u64 slice_len = slice.len;
+    u64 slice_cap = slice.cap;
+    if (slice_len < slice_cap && slice.array != NULL)
+    {
+        // Room available on current array, append to the underlying array
+        res = bpf_probe_write_user(slice.array + (item_size * slice_len), new_item, item_size);
+    }
+    else
+    { 
+        // No room on current array - try to copy new one of size item_size * (len + 1)
+        u32 alloc_size = item_size * slice_len;
+        if (alloc_size >= MAX_SLICE_ARRAY_SIZE)
+        {
+            return;
+        }
+    
+        // Get temporary buffer
+        u32 index = 0;
+        struct slice_array_buff *map_buff = bpf_map_lookup_elem(&slice_array_buff_map, &index);
+        if (!map_buff)
+        {
+            return;
+        }
+    
+        unsigned char *new_slice_array = map_buff->buff;
+        // help the verifier
+        alloc_size &= (MAX_SLICE_ARRAY_SIZE - 1);
+        if (alloc_size + item_size > MAX_SLICE_ARRAY_SIZE)
+        {
+            // No room for new item
+            return;
+        }
+        // Append to buffer
+        if (slice.array != NULL) {
+            bpf_probe_read_user(new_slice_array, alloc_size, slice.array);
+            bpf_printk("append_item_to_slice: copying %d bytes to new array from address 0x%llx", alloc_size, slice.array);
+        }
+        copy_byte_arrays(new_item, new_slice_array + alloc_size, item_size);
+
+        // Copy buffer to userspace
+        u32 new_array_size = alloc_size + item_size;
+
+        void *new_array = write_target_data(new_slice_array, new_array_size);
+        if (new_array == NULL)
+        {
+            bpf_printk("append_item_to_slice: failed to copy new array to userspace");
+            return;
+        }
+
+        // Update array pointer of slice
+        slice.array = new_array;
+        slice.cap++;
+    }
+
+    // Update len
+    slice.len++;
+    long success = bpf_probe_write_user(slice_user_ptr, &slice, sizeof(slice));
+    if (success != 0)
+    {
+        bpf_printk("append_item_to_slice: failed to update slice in userspace");
+        return;
+    }
+}
+
+static __always_inline bool get_go_string_from_user_ptr(void *user_str_ptr, char *dst, u64 max_len)
+{
+    if (user_str_ptr == NULL)
+    {
+        return false;
+    }
+
+    struct go_string_ot user_str = {0};
+    long success = 0;
+    success = bpf_probe_read(&user_str, sizeof(struct go_string_ot), user_str_ptr);
+    if (success != 0 || user_str.len < 1)
+    {
+        return false;
+    }
+
+    u64 size_to_read = user_str.len > max_len ? max_len : user_str.len;
+    success = bpf_probe_read(dst, size_to_read, user_str.str);
+    if (success != 0)
+    {
+        return false;
+    }
+
+    return true;
+}
+#endif

+ 157 - 0
ebpftracer/ebpf/utrace/go/include/otel_types.h

@@ -0,0 +1,157 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef _OTEL_TYPES_H
+#define _OTEL_TYPES_H
+
+#include "go_types.h"
+#include "go_common.h"
+
+// Injected in init
+volatile const u64 attr_type_invalid;
+
+volatile const u64 attr_type_bool;
+volatile const u64 attr_type_int64;
+volatile const u64 attr_type_float64;
+volatile const u64 attr_type_string;
+
+volatile const u64 attr_type_boolslice;
+volatile const u64 attr_type_int64slice;
+volatile const u64 attr_type_float64slice;
+volatile const u64 attr_type_stringslice;
+
+/* Defintions should mimic structs defined in go.opentelemetry.io/otel/attribute */
+
+typedef struct go_otel_attr_value {
+	u64              vtype;
+	u64              numeric;
+	struct go_string_ot string;
+	struct go_iface	 slice;
+} go_otel_attr_value_t;
+
+typedef struct go_otel_key_value {
+	struct go_string_ot     key;
+	go_otel_attr_value_t value;
+} go_otel_key_value_t;
+
+#define OTEL_ATTRIBUTE_KEY_MAX_LEN      (32)
+#define OTEL_ATTRIBUTE_VALUE_MAX_LEN    (128)
+#define OTEL_ATTRUBUTE_MAX_COUNT        (16)
+
+typedef struct otel_attirbute {
+	u16 val_length;
+	u8 vtype;
+	u8 reserved;
+	char key[OTEL_ATTRIBUTE_KEY_MAX_LEN];
+	char value[OTEL_ATTRIBUTE_VALUE_MAX_LEN];
+} otel_attirbute_t;
+
+typedef struct otel_attributes {
+	otel_attirbute_t attrs[OTEL_ATTRUBUTE_MAX_COUNT];
+	u8 valid_attrs;
+}__attribute__((packed)) otel_attributes_t;
+
+static __always_inline bool set_attr_value(otel_attirbute_t *attr, go_otel_attr_value_t *go_attr_value)
+{
+	u64 vtype = go_attr_value->vtype;
+
+	if (vtype == attr_type_invalid) {
+		bpf_printk("Invalid attribute value type\n");
+		return false;
+	}
+
+	// Constant size values
+	if (vtype == attr_type_bool ||
+		vtype == attr_type_int64 ||
+		vtype == attr_type_float64) {
+		bpf_probe_read(attr->value, sizeof(s64), &go_attr_value->numeric);
+		return true;
+	}
+
+	// String values
+	if (vtype == attr_type_string) {
+		if (go_attr_value->string.len >= OTEL_ATTRIBUTE_VALUE_MAX_LEN) {
+			bpf_printk("Aattribute string value is too long\n");
+			return false;
+		}
+		return get_go_string_from_user_ptr(&go_attr_value->string, attr->value, OTEL_ATTRIBUTE_VALUE_MAX_LEN);
+	}
+
+	// TODO (#525): handle slices
+	return false;
+}
+
+static __always_inline void convert_go_otel_attributes(void *attrs_buf, u64 slice_len, otel_attributes_t *enc_attrs)
+{
+	if (attrs_buf == NULL || enc_attrs == NULL){
+		return;
+	}
+
+	if (slice_len < 1) {
+		return;
+	}
+
+	u8 num_attrs = slice_len < OTEL_ATTRUBUTE_MAX_COUNT ? slice_len : OTEL_ATTRUBUTE_MAX_COUNT;
+	go_otel_key_value_t *go_attr = (go_otel_key_value_t*)attrs_buf;
+	go_otel_attr_value_t go_attr_value = {0};
+	struct go_string_ot go_str = {0};
+	u8 valid_attrs = enc_attrs->valid_attrs;
+	if (valid_attrs >= OTEL_ATTRUBUTE_MAX_COUNT) {
+		return;
+	}
+
+	for (u8 go_attr_index = 0; go_attr_index < num_attrs; go_attr_index++) {
+		__builtin_memset(&go_attr_value, 0, sizeof(go_otel_attr_value_t));
+		// Read the value struct
+		bpf_probe_read(&go_attr_value, sizeof(go_otel_attr_value_t), &go_attr[go_attr_index].value);
+
+		if (go_attr_value.vtype == attr_type_invalid) {
+			continue;
+		}
+
+		// Read the key string
+		bpf_probe_read(&go_str, sizeof(struct go_string_ot), &go_attr[go_attr_index].key);
+		if (go_str.len >= OTEL_ATTRIBUTE_KEY_MAX_LEN) {
+			// key string is too large
+			bpf_printk("Attribute key string is too long\n");
+			continue;
+		}
+
+		// Need to check valid_attrs otherwise the ebpf verifier thinks it's possible to exceed
+		// the max register value for a downstream call, even though it's not possible with
+		// this same check at the end of the loop.
+		if (valid_attrs >= OTEL_ATTRUBUTE_MAX_COUNT) {
+			break;
+		}
+
+		if (!get_go_string_from_user_ptr(&go_str, enc_attrs->attrs[valid_attrs].key, OTEL_ATTRIBUTE_KEY_MAX_LEN)) {
+			continue;
+		}
+
+		if (!set_attr_value(&enc_attrs->attrs[valid_attrs], &go_attr_value)) {
+			continue;
+		}
+
+		enc_attrs->attrs[valid_attrs].vtype = go_attr_value.vtype;
+		valid_attrs++;
+		if (valid_attrs >= OTEL_ATTRUBUTE_MAX_COUNT) {
+			// No more space for attributes
+			break;
+		}
+	}
+
+	enc_attrs->valid_attrs = valid_attrs;
+}
+
+#endif

+ 99 - 37
ebpftracer/ebpf/utrace/go/include/span_context.h

@@ -26,6 +26,7 @@ struct span_context {
 	unsigned char SpanID[SPAN_ID_SIZE];
 };
 
+
 static __always_inline struct span_context generate_span_context() {
 	struct span_context context = {};
 	generate_random_bytes(context.TraceID, TRACE_ID_SIZE);
@@ -57,6 +58,75 @@ static __always_inline void span_context_to_w3c_string(struct span_context *ctx,
 	*out = '1';
 }
 
+static __always_inline void span_context_to_cw_string(struct apm_span_context *ctx, char *buff) {
+	// W3C format: version (2 chars) - trace id (32 chars) - span id (16 chars) - sampled (2 chars)
+	//	[type_from]:[sample]:[host_id]:[app_id]:[instance_id]:[trace_id]:[assumed_app_i d]:[span_id]
+	//	2           2         16        16      16            32         16                16
+	char *out = buff;
+
+	// Write type_from
+	*out++ = '0';
+	*out++ = '0';
+	*out++ = ':';
+
+	// Write sample
+	*out++ = '0';
+	*out++ = '0';
+	*out++ = ':';
+
+	// Write host_id
+	bytes_to_hex_string(ctx->host_id, APM_HOST_ID_SIZE, out);
+	out += APM_HOST_ID_STRING_SIZE;
+	*out++ = ':';
+
+	// Write app_id
+	bytes_to_hex_string(ctx->app_id, APM_APP_ID_SIZE, out);
+	out += APM_APP_ID_STRING_SIZE;
+	*out++ = ':';
+
+
+	// Write instance_id
+	bytes_to_hex_string(ctx->instance_id, APM_INSTANCE_ID_SIZE, out);
+	out += APM_INSTANCE_ID_STRING_SIZE;
+	*out++ = ':';
+
+	// Write trace_id
+	bytes_to_hex_string(ctx->trace_id, APM_TRACE_ID_SIZE, out);
+	out += APM_TRACE_ID_STRING_SIZE;
+	*out++ = ':';
+	// Write assumed_app_id
+	bytes_to_hex_string(ctx->assumed_app_id, APM_ASSUMED_APP_ID_SIZE, out);
+	out += APM_ASSUMED_APP_ID_STRING_SIZE;
+	*out++ = ':';
+
+	// Write span_id
+	bytes_to_hex_string(ctx->span_id, APM_SPAN_ID_SIZE, out);
+	out += APM_SPAN_ID_STRING_SIZE;
+//	*out++ = ':';
+
+//	// Write trace id
+//	bytes_to_hex_string(ctx->TraceID, TRACE_ID_SIZE, out);
+//	out += TRACE_ID_STRING_SIZE;
+//	*out++ = '-';
+//	// Write trace id
+//	bytes_to_hex_string(ctx->TraceID, TRACE_ID_SIZE, out);
+//	out += TRACE_ID_STRING_SIZE;
+//	*out++ = '-';
+//	// Write trace id
+//	bytes_to_hex_string(ctx->TraceID, TRACE_ID_SIZE, out);
+//	out += TRACE_ID_STRING_SIZE;
+//	*out++ = '-';
+//
+//	// Write span id
+//	bytes_to_hex_string(ctx->SpanID, SPAN_ID_SIZE, out);
+//	out += SPAN_ID_STRING_SIZE;
+//	*out++ = '-';
+
+	// Write sampled
+//	*out++ = '0';
+//	*out = '1';
+}
+
 #define MAX_SIZE 120
 #define MAX_TOKENS 8
 
@@ -73,49 +143,41 @@ struct cw_header_token {
 static __always_inline void w3c_string_to_span_context(char *str, struct span_context *ctx) {
 //	GO:0:10154813500555812:5450531005555981:5610250100539899:304775019cd3218a:1001025098564810:140acc88cde8773f:110
 //	00-95b5ec2b81e2374a4a27ce36ab71d349-18f65a5a3ab22213-02
+//	JAVA:0:10675555109846866:10675555109846867:10675555109846868:1541924974244&c69a3a5f4f9c46eb9c85d164b702ee68:10675555109846869:10675555109846861
 	u32 trace_id_start_pos = 3;
 	u32 span_id_start_pod = 36;
-//
-//	u32 idx = 0;
-//	u32 strLen = 0;
-//	struct cw_header_token range = {0};
-//	for (u32 k = 0; k < MAX_SIZE; ++k) {
-//		if (str[k] == '\0') {
-//			break;
-//		}
-////		bpf_printk("k---%d", k);
-//		if (str[k] == ':') {
-//			strLen = 0;
-//			range.start[idx] = k + 1;
-//			bpf_printk("range.start:%d", range.start[idx]);
-//			idx++;
-//		}
-////		bpf_printk("range.len token[%d]:[%d]", token, strLen);
-//	}
-//
-//	for (u32 i = 0; i < idx; ++i) {
-//		bpf_printk("Token %u: start = %u, len = %u\n", i, range.start[i], range.len[i]);
-//	}
-
-//	struct Range range2;
-////
-//	bpf_probe_read(&range2, sizeof(range2), &range);
-//	bpf_printk("traceparent_header_value_go_str.str:%s", range2.len);
-
-//	if (ret != 0) {
-//		bpf_printk("Failed to read Range struct: %d\n", ret);
-//	} else {
-//
-//		for (int i = 1; i < 9; ++i) {
-//			if (i > 1) {
-//				range2.len[i] = range2.start[i - 1];
-//			}
-//		}
-//	}
 
 
 	hex_string_to_bytes(str + trace_id_start_pos, TRACE_ID_STRING_SIZE, ctx->TraceID);
 	hex_string_to_bytes(str + span_id_start_pod, SPAN_ID_STRING_SIZE, ctx->SpanID);
+
+
 }
 
+//	00000000GO:00:1015481350055581:5450531005555981:5610250100539899:304775019cd3218a304775019cd3218a:1001025098564810:140acc88cde8773f
+//	00:00:1015481350055581:5450531005555981:5610250100539899:304775019cd3218a304775019cd3218a:1001025098564810:140acc88cde8773f
+//	[type_from]:[sample]:[host_id]:[app_id]:[instance_id]:[trace_id]:[assumed_app_i d]:[span_id]
+//	10          2         16        16      16            32         16                16
+static __always_inline void cw_string_to_span_context(char *str, struct apm_span_context *ctx) {
+
+	u32 type_from_start_pos = 0;
+	u32 sample_start_pos = type_from_start_pos + APM_TYPE_FROM_STRING_SIZE + 1;
+	u32 host_id_start_pos = sample_start_pos + APM_SAMPLE_STRING_SIZE + 1;
+	u32 app_id_start_pos = host_id_start_pos + APM_HOST_ID_STRING_SIZE + 1;
+	u32 instance_id_start_pos = app_id_start_pos + APM_APP_ID_STRING_SIZE + 1;
+	u32 trace_id_start_pos = instance_id_start_pos + APM_INSTANCE_ID_STRING_SIZE + 1;
+	u32 assumed_app_id_start_pos = trace_id_start_pos + APM_TRACE_ID_STRING_SIZE + 1;
+	u32 span_id_start_pos = assumed_app_id_start_pos + APM_ASSUMED_APP_ID_STRING_SIZE + 1;
+
+	hex_string_to_bytes(str + type_from_start_pos, APM_TYPE_FROM_STRING_SIZE, ctx->type_from);
+	hex_string_to_bytes(str + sample_start_pos, APM_SAMPLE_STRING_SIZE, ctx->sample);
+	hex_string_to_bytes(str + host_id_start_pos, APM_HOST_ID_STRING_SIZE, ctx->host_id);
+	hex_string_to_bytes(str + app_id_start_pos, APM_APP_ID_STRING_SIZE, ctx->app_id);
+	hex_string_to_bytes(str + instance_id_start_pos, APM_INSTANCE_ID_STRING_SIZE, ctx->instance_id);
+	hex_string_to_bytes(str + trace_id_start_pos, APM_TRACE_ID_STRING_SIZE, ctx->trace_id);
+	hex_string_to_bytes(str + assumed_app_id_start_pos, APM_ASSUMED_APP_ID_STRING_SIZE, ctx->assumed_app_id);
+	hex_string_to_bytes(str + span_id_start_pos, APM_SPAN_ID_STRING_SIZE, ctx->span_id);
+}
+
+
 #endif

+ 54 - 0
ebpftracer/ebpf/utrace/go/include/uprobe.h

@@ -0,0 +1,54 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef _UPROBE_H_
+#define _UPROBE_H_
+
+#include "go_common.h"
+#include "span_context.h"
+#include "go_context.h"
+#include "go_types.h"
+
+#define BASE_SPAN_PROPERTIES \
+    u64 start_time;          \
+    u64 end_time;            \
+    struct span_context sc;  \
+    struct span_context psc;
+
+// Common flow for uprobe return:
+// 1. Find consistend key for the current uprobe context
+// 2. Use the key to lookup for the uprobe context in the uprobe_context_map
+// 3. Update the end time of the found span
+// 4. Submit the constructed event to the agent code using perf buffer events_map
+// 5. Delete the span from the uprobe_context_map
+// 6. Delete the span from the global active spans map
+#define UPROBE_RETURN(name, event_type, uprobe_context_map, events_map, context_pos, context_offset, passed_as_arg) \
+SEC("uprobe/##name##")                                                                                              \
+int uprobe_##name##_Returns(struct pt_regs *ctx) {                                                                  \
+    void *ctx_address = get_Go_context(ctx, context_pos, context_offset, passed_as_arg);                            \
+    void *key = get_consistent_key(ctx, ctx_address);                                                               \
+    void *req_ptr_map = bpf_map_lookup_elem(&uprobe_context_map, &key);                                             \
+    if (req_ptr_map == NULL) {                                                                                      \
+        return 0;                                                                                                   \
+    }                                                                                                               \
+    event_type tmpReq = {0};                                                                                        \
+    bpf_probe_read(&tmpReq, sizeof(tmpReq), req_ptr_map);                                                           \
+    tmpReq.end_time = bpf_ktime_get_ns();                                                                           \
+    bpf_perf_event_output(ctx, &events_map, BPF_F_CURRENT_CPU, &tmpReq, sizeof(tmpReq));                            \
+    bpf_map_delete_elem(&uprobe_context_map, &key);                                                                 \
+    stop_tracking_span(&tmpReq.sc, &tmpReq.psc);                                                                    \
+    return 0;                                                                                                       \
+} 
+
+#endif

+ 124 - 0
ebpftracer/ebpf/utrace/go/include/utils.h

@@ -0,0 +1,124 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef _EBPF_UTILS_H
+#define _EBPF_UTILS_H
+
+//#include "bpf_helpers.h"
+
+#define TRACE_ID_SIZE 16
+#define TRACE_ID_STRING_SIZE 32
+#define SPAN_ID_SIZE 8
+#define SPAN_ID_STRING_SIZE 16
+
+static __always_inline int bpf_memcmp(char *s1, char *s2, s32 size)
+{
+    for (int i = 0; i < size; i++)
+    {
+        if (s1[i] != s2[i])  return 0;
+    }
+
+    return 1;
+}
+
+static __always_inline void generate_random_bytes(unsigned char *buff, u32 size)
+{
+    for (int i = 0; i < (size / 4); i++)
+    {
+        u32 random = bpf_get_prandom_u32();
+        buff[(4 * i)] = (random >> 24) & 0xFF;
+        buff[(4 * i) + 1] = (random >> 16) & 0xFF;
+        buff[(4 * i) + 2] = (random >> 8) & 0xFF;
+        buff[(4 * i) + 3] = random & 0xFF;
+    }
+}
+
+char hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+static __always_inline void bytes_to_hex_string(unsigned char *pin, u32 size, char *out)
+{
+    char *pout = out;
+//    int out_index = 0;
+    for (u32 i = 0; i < size; i++)
+    {
+        *pout++ = hex[(*pin >> 4) & 0xF];
+        *pout++ = hex[(*pin++) & 0xF];
+    }
+}
+
+static __always_inline void hex_string_to_bytes(char *str, u32 size, unsigned char *out)
+{
+    for (int i = 0; i < (size / 2); i++)
+    {
+        char ch0 = str[2 * i];
+        char ch1 = str[2 * i + 1];
+        u8 nib0 = (ch0 & 0xF) + (ch0 >> 6) | ((ch0 >> 3) & 0x8);
+        u8 nib1 = (ch1 & 0xF) + (ch1 >> 6) | ((ch1 >> 3) & 0x8);
+        out[i] = (nib0 << 4) | nib1;
+    }
+}
+
+static __always_inline void copy_byte_arrays(unsigned char *src, unsigned char *dst, u32 size)
+{
+    for (int i = 0; i < size; i++)
+    {
+        dst[i] = src[i];
+    }
+}
+
+static __always_inline void custom_hash(char *str, unsigned char *hash,u32 size) {
+	u64 int_hash = 0;
+#pragma unroll
+	for (int i = 0; i < APM_REMOTE_ADDR_MAX_LEN; i++) { // Assuming maximum string length is 256
+		if (str[i] == '\0') break;
+		int_hash = (int_hash * 31) + str[i];
+	}
+
+	// Convert int_hash to 16 bytes
+	for (int i = 0; i < size; i++) {
+		hash[i] = int_hash % 10;
+		int_hash /= 10;
+	}
+}
+
+static __always_inline void set_assumed_app_id_arrays(char *host, unsigned char *dist, u32 size) {
+	unsigned char hash[APM_ASSUMED_APP_ID_STRING_SIZE];
+	custom_hash(host, hash, APM_ASSUMED_APP_ID_STRING_SIZE);
+	for (int i = 0; i < APM_ASSUMED_APP_ID_STRING_SIZE; i++) {
+		bpf_printk("%u", hash[i]);
+	}
+	hex_string_to_bytes((char *) hash, APM_ASSUMED_APP_ID_STRING_SIZE, dist);
+}
+
+static __always_inline void bpf_memset(unsigned char *dst, u32 size, unsigned char value)
+{
+    for (int i = 0; i < size; i++)
+    {
+        dst[i] = value;
+    }
+}
+
+static __always_inline bool bpf_is_zero(unsigned char *buff, u32 size)
+{
+    for (int i = 0; i < size; i++)
+    {
+        if (buff[i] != 0)
+        {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+#endif

+ 153 - 17
ebpftracer/ebpf/utrace/go/net/client.probe.bpf.c

@@ -19,6 +19,9 @@ struct http_request_t {
     u64 status_code;
     char method[MAX_METHOD_SIZE];
     char path[MAX_PATH_SIZE];
+
+	struct apm_span_context apm_sc;
+    struct apm_span_context apm_psc;
 };
 
 struct {
@@ -158,12 +161,114 @@ static __always_inline long inject_header(void* headers_ptr, struct span_context
     bpf_memset((unsigned char *)bucket_map_value, sizeof(struct map_bucket), 0);
     return 0;
 }
+// 00:00:1015481350055581:5450531005555981:5610250100539899:304775019cd3218a304775019cd3218a:1001025098564810:140acc88cde8773f
+static __always_inline long cw_inject_header(void* headers_ptr, struct apm_span_context* propagated_ctx) {
+    // Read the key-value count - this field must be the first one in the hmap struct as documented in src/runtime/map.go
+    u64 curr_keyvalue_count = 0;
+    long res = bpf_probe_read_user(&curr_keyvalue_count, sizeof(curr_keyvalue_count), headers_ptr);
+
+    if (res < 0) {
+        bpf_printk("Couldn't read map key-value count from user");
+        return -1;
+    }
+
+    if (curr_keyvalue_count >= 8) {
+        bpf_printk("Map size is bigger than 8, skipping context propagation");
+        return -1;
+    }
+
+    // Get pointer to temp bucket struct we store in a map (avoiding large local variable on the stack)
+    // Performing read-modify-write on the bucket
+    u32 map_id = 0;
+    struct map_bucket *bucket_map_value = bpf_map_lookup_elem(&golang_mapbucket_storage_map, &map_id);
+    if (!bucket_map_value) {
+        return -1;
+    }
+
+    void *buckets_ptr_ptr = (void*) (headers_ptr + buckets_ptr_pos);
+    void *bucket_ptr = 0; // The actual pointer to the buckets
+
+    if (curr_keyvalue_count == 0) {
+        // No key-value pairs in the Go map, need to "allocate" memory for the user
+        bucket_ptr = write_target_data(bucket_map_value, sizeof(struct map_bucket));
+        if (bucket_ptr == NULL) {
+            bpf_printk("inject_header: Failed to write bucket to user");
+            return -1;
+        }
+        // Update the buckets pointer in the hmap struct to point to newly allocated bucket
+        res = bpf_probe_write_user(buckets_ptr_ptr, &bucket_ptr, sizeof(bucket_ptr));
+        if (res < 0) {
+            bpf_printk("Failed to update the map bucket pointer for the user");
+            return -1;
+        }
+    } else {
+        // There is at least 1 key-value pair, hence the bucket pointer from the user is valid
+        // Read the bucket pointer
+        res = bpf_probe_read_user(&bucket_ptr, sizeof(bucket_ptr), buckets_ptr_ptr);
+        // Read the user's bucket to the eBPF map entry
+        bpf_probe_read_user(bucket_map_value, sizeof(struct map_bucket), bucket_ptr);
+    }
+
+    u8 bucket_index = curr_keyvalue_count & 0x7;
+
+    char traceparent_tophash = 0xee;
+    bucket_map_value->tophash[bucket_index] = traceparent_tophash;
+
+    // Prepare the key string for the user
+    char key[W3C_KEY_LENGTH] = "traceparent";
+    void *ptr = write_target_data(key, W3C_KEY_LENGTH);
+    if (ptr == NULL) {
+        bpf_printk("inject_header: Failed to write key to user");
+        return -1;
+    }
+    bucket_map_value->keys[bucket_index] = (struct go_string_ot) {.len = W3C_KEY_LENGTH, .str = ptr};
+
+    // Prepare the value string slice
+    // First the value string which constains the span context
+    char val[CW_HEADER_LENGTH];
+	span_context_to_cw_string(propagated_ctx, val);
+    ptr = write_target_data(val, sizeof(val));
+    if(ptr == NULL) {
+        bpf_printk("inject_header: Failed to write value to user");
+        return -1;
+    }
+
+    // The go string pointing to the above val
+    struct go_string_ot header_value = {.len = CW_HEADER_LENGTH, .str = ptr};
+    ptr = write_target_data((void*)&header_value, sizeof(header_value));
+    if(ptr == NULL) {
+        bpf_printk("inject_header: Failed to write go_string to user");
+        return -1;
+    }
+
+    // Last, go_slice pointing to the above go_string
+    bucket_map_value->values[bucket_index] = (struct go_slice_ot) {.array = ptr, .cap = 1, .len = 1};
+
+    // Update the map header count field
+    curr_keyvalue_count += 1;
+    res = bpf_probe_write_user(headers_ptr, &curr_keyvalue_count, sizeof(curr_keyvalue_count));
+    if (res < 0) {
+        bpf_printk("Failed to update key-value count in map header");
+        return -1;
+    }
+
+    // Update the bucket
+    res = bpf_probe_write_user(bucket_ptr, bucket_map_value, sizeof(struct map_bucket));
+    if (res < 0) {
+        bpf_printk("Failed to update bucket content");
+        return -1;
+    }
+
+    bpf_memset((unsigned char *)bucket_map_value, sizeof(struct map_bucket), 0);
+    return 0;
+}
 
 // This instrumentation attaches uprobe to the following function:
 // func net/http/transport.roundTrip(req *Request) (*Response, error)
 SEC("uprobe/Transport_roundTrip")
 int uprobe_Transport_roundTrip(struct pt_regs *ctx) {
-    bpf_printk("[HTTP Client] start");
+	bpf_printk("[Uprobe HTTP Client] start");
+
     u64 request_pos = 2;
     void *req_ptr = get_argument(ctx, request_pos);
 
@@ -196,17 +301,35 @@ int uprobe_Transport_roundTrip(struct pt_regs *ctx) {
     if (parent_span_ctx != NULL) {
         bpf_printk("[Client] parent_span_ctx != NULL");
 
-        bpf_probe_read(&httpReq->psc, sizeof(httpReq->psc), parent_span_ctx);
-        copy_byte_arrays(httpReq->psc.TraceID, httpReq->sc.TraceID, TRACE_ID_SIZE);
-        generate_random_bytes(httpReq->sc.SpanID, SPAN_ID_SIZE);
+//        bpf_probe_read(&httpReq->psc, sizeof(httpReq->psc), parent_span_ctx);
+//        copy_byte_arrays(httpReq->psc.TraceID, httpReq->sc.TraceID, TRACE_ID_SIZE);
+//        generate_random_bytes(httpReq->sc.SpanID, SPAN_ID_SIZE);
     } else {
-        bpf_printk("[Client] parent_span_ctx == NULL");
-	    struct apm_span_context *apm_sc = get_tracking_span();
-	    if (!apm_sc) {
-		    httpReq->sc = generate_span_context();
-		} else {
-		    httpReq->sc = *(struct span_context *) apm_sc;
-	    }
+//        bpf_printk("[Client] parent_span_ctx == NULL");
+//	    struct apm_span_context *apm_sc = get_tracking_span();
+//	    if (apm_sc) {
+//		    httpReq->sc = *(struct span_context *) apm_sc;
+//	    } else {
+//		    httpReq->sc = generate_span_context();
+//	    }
+
+
+	    struct apm_span_context *cw_sc = cw_get_parent_tracking_span();
+		if(cw_sc){
+//			httpReq->apm_sc = *cw_sc;
+			bpf_probe_read(&httpReq->apm_psc, sizeof(httpReq->apm_psc), cw_sc);
+			// copy trace_id
+//			copy_byte_arrays(httpReq->apm_psc.instance_id, httpReq->apm_sc.instance_id, APM_INSTANCE_ID_SIZE);
+			copy_byte_arrays(httpReq->apm_psc.trace_id, httpReq->apm_sc.trace_id, APM_TRACE_ID_SIZE);
+			// new spanid
+			generate_random_bytes(httpReq->apm_sc.span_id, APM_SPAN_ID_SIZE);
+
+
+			// copy TraceID
+//			copy_byte_arrays(httpReq->apm_psc.trace_id, httpReq->sc.TraceID, TRACE_ID_SIZE);
+//			copy_byte_arrays(httpReq->psc.TraceID, httpReq->sc.TraceID, TRACE_ID_SIZE);
+//			generate_random_bytes(httpReq->sc.SpanID, SPAN_ID_SIZE);
+		}
     }
 
     if (!get_go_string_from_user_ptr((void *)(req_ptr+method_ptr_pos), httpReq->method, sizeof(httpReq->method))) {
@@ -226,8 +349,20 @@ int uprobe_Transport_roundTrip(struct pt_regs *ctx) {
     if (!get_go_string_from_user_ptr((void *)(req_ptr+request_host_pos), httpReq->host, sizeof(httpReq->host))) {
         bpf_printk("uprobe_Transport_roundTrip: Failed to get host from Request");
     }
-
-    // get proto from Request
+	// TODO set request_host_pos
+	bpf_printk("[Client] httpReq->host:%llu",request_host_pos);
+//	for (int i = 0; i < MAX_HOSTNAME_SIZE; ++i) {
+//		if (httpReq->host[i] == '\0') {
+//			break;
+//		}
+////		httpReq->apm_sc.assumed_app_id[i] = httpReq->host[i];
+//		bpf_printk("[Client] httpReq->host:%c",httpReq->host[i]);
+//	}
+//	unsigned char hash[APM_ASSUMED_APP_ID_STRING_SIZE];
+
+	set_assumed_app_id_arrays(httpReq->host, httpReq->apm_sc.assumed_app_id, APM_ASSUMED_APP_ID_STRING_SIZE);
+
+	// get proto from Request
     if (!get_go_string_from_user_ptr((void *)(req_ptr+request_proto_pos), httpReq->proto, sizeof(httpReq->proto))) {
         bpf_printk("uprobe_Transport_roundTrip: Failed to get proto from Request");
     }
@@ -235,14 +370,15 @@ int uprobe_Transport_roundTrip(struct pt_regs *ctx) {
     // get headers from Request
     void *headers_ptr = 0;
     bpf_probe_read(&headers_ptr, sizeof(headers_ptr), (void *)(req_ptr+headers_ptr_pos));
-    long res = inject_header(headers_ptr, &httpReq->sc);
+//    long res = inject_header(headers_ptr, &httpReq->sc);
+    long res = cw_inject_header(headers_ptr, &httpReq->apm_sc);
     if (res < 0) {
         bpf_printk("uprobe_Transport_roundTrip: Failed to inject header");
     }
 
     // Write event
-    bpf_map_update_elem(&http_events, &key, httpReq, 0);
-    start_tracking_span(context_ptr_val, &httpReq->sc);
+//    bpf_map_update_elem(&http_events, &key, httpReq, 0);
+//    start_tracking_span(context_ptr_val, &httpReq->sc);
     return 0;
 }
 
@@ -250,7 +386,7 @@ int uprobe_Transport_roundTrip(struct pt_regs *ctx) {
 // func net/http/transport.roundTrip(req *Request) (*Response, error)
 SEC("uprobe/Transport_roundTrip")
 int uprobe_Transport_roundTrip_Returns(struct pt_regs *ctx) {
-    bpf_printk("[HTTP Client] Return start");
+    bpf_printk("[Uprobe HTTP Client] Return start");
 
     u64 end_time = bpf_ktime_get_ns();
     void *req_ctx_ptr = get_Go_context(ctx, 2, ctx_ptr_pos, false);

+ 47 - 97
ebpftracer/ebpf/utrace/go/net/server.probe.bpf.c

@@ -64,7 +64,7 @@ struct {
 	__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
 	__uint(key_size, sizeof(u32));
 	__uint(value_size, sizeof(struct cw_header_token));
-	__uint(max_entries, 1);
+	__uint(max_entries, MAX_CONCURRENT);
 } header_range SEC(".maps");
 
 struct {
@@ -74,6 +74,13 @@ struct {
 	__uint(max_entries, 1);
 } parent_span_context_storage_map SEC(".maps");
 
+struct {
+	__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
+	__uint(key_size, sizeof(u32));
+	__uint(value_size, sizeof(struct apm_span_context));
+	__uint(max_entries, 1);
+} cw_parent_span_context_storage_map SEC(".maps");
+
 struct {
 	__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
 	__uint(key_size, sizeof(u32));
@@ -179,7 +186,7 @@ static __always_inline struct span_context *extract_context_from_req_headers(voi
 			res = bpf_probe_read(&traceparent_header_value_go_str, sizeof(traceparent_header_value_go_str),
 			                     traceparent_header_value_ptr);
 			// 00-95b5ec2b81e2374a4a27ce36ab71d349-18f65a5a3ab22213-02
-//			bpf_printk("traceparent_header_value_go_str.str:%s", traceparent_header_value_go_str.str);
+			bpf_printk("traceparent_header_value_go_str.str:%s", traceparent_header_value_go_str.str);
 
 			if (res < 0) {
 				return NULL;
@@ -187,7 +194,7 @@ static __always_inline struct span_context *extract_context_from_req_headers(voi
 //			if (traceparent_header_value_go_str.len != W3C_VAL_LENGTH) {
 //				continue;
 //			}
-			char traceparent_header_value[120];
+			char traceparent_header_value[130];
 			res = bpf_probe_read(&traceparent_header_value, sizeof(traceparent_header_value),
 			                     traceparent_header_value_go_str.str);
 			// 00-95b5ec2b81e2374a4a27ce36ab71d349-18f65a5a3ab22213-02��c�����c����@c;
@@ -202,108 +209,52 @@ static __always_inline struct span_context *extract_context_from_req_headers(voi
 
 			struct span_context *parent_span_context = bpf_map_lookup_elem(&parent_span_context_storage_map, &map_id);
 			if (!parent_span_context) {
-//				bpf_printk("no parent_span_context");
+				bpf_printk("no parent_span_context");
 				return NULL;
 			}
-//			bpf_printk("parent_span_context-TraceID1:%s", parent_span_context->TraceID);
-//			bpf_printk("parent_span_context-SpanID1:%s", parent_span_context->SpanID);
-//			struct cw_header_token *header_range_data = bpf_map_lookup_elem(&header_range, &map_id);
-//			if (!header_range_data) {
-//				return NULL;
-//			}
-//			u32 idx = 0;
-//			u32 str_len = 0;
-//			struct cw_header_token tmp = *header_range_data;
-//			tmp.a = 4;
-////			struct Token t = {.start=1,.len=2};
-//			for (int k = 0; k < MAX_TOKENS; ++k) {
-////				header_range_data->token[k] = t ;
-//				header_range_data->start[k] = 1 ;
-//
-////				tmp.token[k] = t ;
-//			}
-//			for (int k = 0; k < MAX_TOKENS; ++k) {
-////					struct Token t = {.start=1, .len=2};
-////					header_range_data->token[k] = t;
-//				bpf_printk("header_range_data->token---%d", header_range_data->token[k].len);
-//
-//			}
-//
-////			header_range_data->token[0].len = 1;
-//
-//			bpf_printk("header_range_data->token---%d", header_range_data->token[0].len);
-//
-//			for (u32 k = 0; k < MAX_SIZE; ++k) {
-//				if (traceparent_header_value[k] == '\0') {
-////					bpf_map_update_elem(&header_range, &map_id, &tmp, BPF_ANY);
-//					break;
-//				}
-//				bpf_printk("k---%d", k);
-//				if (traceparent_header_value[k] == ':') {
-//					str_len = 0;
-//					tmp.token[idx].start = k + 1;
-//					header_range_data->start[idx] = k + 1;
-//					bpf_printk("range.start:%d", tmp.token[idx].start);
-//					idx++;
-//				}
-////				else {
-////					str_len++;
-////				}
-////				tmp.token[idx].len = str_len;
-//				bpf_printk("range.len token[%d]:[%d]", idx, str_len);
+			struct apm_span_context *cw_parent_span_context = bpf_map_lookup_elem(&cw_parent_span_context_storage_map, &map_id);
+			if (!cw_parent_span_context) {
+				bpf_printk("no cw_parent_span_context");
+				return NULL;
+			}
+
+			w3c_string_to_span_context(traceparent_header_value, parent_span_context);
+
+			cw_string_to_span_context(traceparent_header_value, cw_parent_span_context);
+
+			// 保存sc
+			cw_save_parent_tracking_span(cw_parent_span_context);
+
+
+//            for (int i = 0; i < TRACE_ID_SIZE; i++) {
+//                bpf_printk("%02x", parent_span_context->TraceID[i]);
+//            }
+//			char val[10];
+//			char *out = val;
+//			// Write trace id
+//			bytes_to_hex_string(cw_parent_span_context->type_from, 5, out);
+//			for (int i = 0; i < 10; ++i) {
+//				bpf_printk("traceid--%c",val[i]);
 //			}
 
 
-//			for (int k = 0; k < MAX_TOKENS; ++k) {
+
 //
-////					struct Token tt[8] = tmp.token;
-////					header_range_data->token[k] = t;
-//				bpf_printk("header_range_data->token---%d", header_range_data->token[k].len);
-////				bpf_printk("header_range_data->token---%d", tmp.token[k].len);
+//			for (int i = 0; i < 1; i++) {
+//				bpf_printk("type_from------%02x", cw_parent_span_context->type_from[i]);
 //			}
-//			for (int k = 0; k < MAX_TOKENS; ++k) {
 //
-////					struct Token tt[8] = tmp.token;
-////					header_range_data->token[k] = t;
-//				bpf_printk("header_range_data->token---%d", header_range_data->token[k].len);
-////				bpf_printk("header_range_data->token---%d", tmp.token[k].len);
-//			}
-
-//			if (idx == MAX_TOKENS) {
-//				for (int k = 0; k < idx; ++k) {
-////					struct Token t = {.start=1, .len=2};
-////					header_range_data->token[k] = t;
-//					bpf_printk("header_range_data->token---%d", header_range_data->token[k].len);
+//			char val[2];
+//			char *out = val;
+////			// Write trace id
+//			bytes_to_hex_string(cw_parent_span_context->type_from, 1, out);
 //
-//				}
-//			}
-//			for (int k = 0; k < idx ; ++k) {
-//				struct Token t = {.start=1,.len=2};
-//				header_range_data->token[k]= t;
-//			}
-//			header_range_data = &tmp;
+//			bpf_printk("type_from1--%s", out);
 
-
-//			bpf_printk("header_range_data---%d", header_range_data->a);
-//			bpf_printk("header_range_data->token---%d", header_range_data->token[0].len);
-//			__builtin_memcpy(&header_range_data->token, &tmp.token, sizeof(header_range_data->token));
-//			struct cw_header_token *header_range_data2 = bpf_map_lookup_elem(&header_range, &map_id);
-//			if (!header_range_data2) {
-//				return NULL;
+//			for (int i = 0; i < 10; ++i) {
+//				bpf_printk("traceid--%c",val[i]);
 //			}
-//			bpf_printk("header_range_data2---%d", header_range_data2->a);
 
-//			for (int kl = 0; kl < idx; ++kl) {
-//				u32 start = tmp.token[kl].start;
-//				u32 len = tmp.token[kl].len;
-//				bpf_printk("Token [%d][%d]", kl,start);
-//			}
-			w3c_string_to_span_context(traceparent_header_value, parent_span_context);
-//			bpf_printk("traceparent_header_value2:%s", traceparent_header_value);
-//            bpf_printk("parent_span_context-TraceID: ");
-//            for (int i = 0; i < TRACE_ID_SIZE; i++) {
-//                bpf_printk("%02x", parent_span_context->TraceID[i]);
-//            }
 //			bpf_printk("parent_span_context-TraceID2:%s", parent_span_context->TraceID);
 //			bpf_printk("parent_span_context-SpanID2:%s", parent_span_context->SpanID);
 			return parent_span_context;
@@ -349,7 +300,9 @@ int uprobe_HandlerFunc_ServeHTTP(struct pt_regs *ctx) {
 	if (parent_ctx != NULL) {
 		// found parent context in http headers
 		http_server_span->psc = *parent_ctx;
+		// copy traceID
 		copy_byte_arrays(http_server_span->psc.TraceID, http_server_span->sc.TraceID, TRACE_ID_SIZE);
+		// 生成随机SpanID
 		generate_random_bytes(http_server_span->sc.SpanID, SPAN_ID_SIZE);
 	} else {
 		http_server_span->sc = generate_span_context();
@@ -377,8 +330,6 @@ int uprobe_HandlerFunc_ServeHTTP(struct pt_regs *ctx) {
 //	start_tracking_span(req_ctx_ptr, &http_server_span->sc);
 
 //	void save_tracking_span(struct apm_span_context *sc)
-	struct apm_span_context apm_sc = *(struct apm_span_context *) &http_server_span->sc;
-	save_tracking_span(&apm_sc);
 
 	return 0;
 }
@@ -434,9 +385,8 @@ int uprobe_HandlerFunc_ServeHTTP_Returns(struct pt_regs *ctx) {
 	bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, http_server_span, sizeof(*http_server_span));
 	stop_tracking_span(&http_server_span->sc, &http_server_span->psc);
 
-	struct apm_trace_key_t trace_key = get_apm_trace_key(120 * NS_PER_SEC, true);
-	bpf_map_delete_elem(&apm_span_context_map, &trace_key);
 
+	clear_span_context();
 	bpf_printk("HTTP_END");
 	return 0;
 }

+ 3 - 2
ebpftracer/tracer/socket.go

@@ -317,6 +317,7 @@ func SetConstants(collectionSpec *ebpf.CollectionSpec) {
 		"ctx_ptr_pos":      int64(232),
 		"headers_ptr_pos":  int64(56),
 		"host_pos":         int64(128),
+		"request_host_pos": int64(128),
 		"is_registers_abi": true,
 		"method_ptr_pos":   int64(0),
 		"path_ptr_pos":     int64(56),
@@ -327,8 +328,8 @@ func SetConstants(collectionSpec *ebpf.CollectionSpec) {
 		"url_ptr_pos":      int64(16),
 		// todo in process
 		"total_cpus": int64(2),
-		"start_addr": int64(140143583477760),
-		"end_addr":   int64(140143583543296),
+		"start_addr": int64(139867793264640),
+		"end_addr":   int64(139867793330176),
 	}
 	err := collectionSpec.RewriteConstants(consts)
 	fmt.Println("err----------------", err)