Pārlūkot izejas kodu

Feature #TASK_QT-31492 go1.24-server调整

Carl 6 mēneši atpakaļ
vecāks
revīzija
43a9b56472

+ 1 - 0
ebpftracer/ebpf/include/socket_trace_common.h

@@ -203,6 +203,7 @@ struct ebpf_proc_info {
 	__u64 ctx_ptr_pos;
 	__u64 headers_ptr_pos;
 	__u64 buckets_ptr_pos;
+	__u64 use_swiss_map;
 	//gRPC
 	__u64 httpclient_nextid_pos;
 	__u64 stream_method_ptr_pos;

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

@@ -79,10 +79,10 @@ struct
 // cw_inject_header_half: 准备 header 注入数据,保存到 bucket_map_value,由后续的 go_update_header 完成实际注入
 // 支持 Go 1.24+ Swiss Tables 和旧版本的 hmap
 static __always_inline long cw_inject_header_half(void* headers_ptr, char * header_str,struct ebpf_proc_info* proc_info) {
-    bpf_printk("cw_inject_header_half: START");
+    cw_bpf_debug("cw_inject_header_half: START");
     
     if (!proc_info) {
-        bpf_printk("cw_inject_header_half: proc_info is NULL");
+        cw_bpf_debug("cw_inject_header_half: proc_info is NULL");
         return -1;
     }
 
@@ -90,26 +90,26 @@ static __always_inline long cw_inject_header_half(void* headers_ptr, char * head
     u32 map_id = CLIENT_MAP_KEY;
     struct map_bucket *bucket_map_value = bpf_map_lookup_elem(&golang_mapbucket_storage_map, &map_id);
     if (!bucket_map_value) {
-        bpf_printk("cw_inject_header_half: Failed to get bucket_map_value");
+        cw_bpf_debug("cw_inject_header_half: Failed to get bucket_map_value");
         return -1;
     }
     __builtin_memset(bucket_map_value, 0, sizeof(struct map_bucket));
 
     // Check if Go version >= 1.24 (Swiss Tables)
     if (proc_info->version >= GO_VERSION(1, 24, 0)) {
-        bpf_printk("cw_inject_header_half: Go 1.24+ Swiss Tables detected");
+        cw_bpf_debug("cw_inject_header_half: Go 1.24+ Swiss Tables detected");
         
         // Read used count (first field in maps.Map)
         u64 used = 0;
         long res = bpf_probe_read_user(&used, sizeof(used), headers_ptr);
         if (res < 0) {
-            bpf_printk("cw_inject_header_half: Failed to read used count, res=%ld", res);
+            cw_bpf_debug("cw_inject_header_half: Failed to read used count, res=%ld", res);
             return -1;
         }
-        bpf_printk("cw_inject_header_half: used=%llu", used);
+        cw_bpf_debug("cw_inject_header_half: used=%llu", used);
 
         if (used >= 8) {
-            bpf_printk("cw_inject_header_half: Map is full (used=%llu)", used);
+            cw_bpf_debug("cw_inject_header_half: Map is full (used=%llu)", used);
             return -1;
         }
 
@@ -117,10 +117,10 @@ static __always_inline long cw_inject_header_half(void* headers_ptr, char * head
         s32 dirLen = 0;
         res = bpf_probe_read_user(&dirLen, sizeof(dirLen), (void*)(headers_ptr + 24));
         if (res < 0) {
-            bpf_printk("cw_inject_header_half: Failed to read dirLen, res=%ld", res);
+            cw_bpf_debug("cw_inject_header_half: Failed to read dirLen, res=%ld", res);
             return -1;
         }
-        bpf_printk("cw_inject_header_half: dirLen=%d", dirLen);
+        cw_bpf_debug("cw_inject_header_half: dirLen=%d", dirLen);
 
         void *group_ptr = NULL;
         
@@ -129,7 +129,7 @@ static __always_inline long cw_inject_header_half(void* headers_ptr, char * head
             void *dirPtr_ptr = (void*)(headers_ptr + proc_info->buckets_ptr_pos);
             res = bpf_probe_read_user(&group_ptr, sizeof(group_ptr), dirPtr_ptr);
             if (res < 0) {
-                bpf_printk("cw_inject_header_half: Failed to read dirPtr, res=%ld", res);
+                cw_bpf_debug("cw_inject_header_half: Failed to read dirPtr, res=%ld", res);
                 return -1;
             }
             
@@ -142,7 +142,7 @@ static __always_inline long cw_inject_header_half(void* headers_ptr, char * head
                 u64 empty_ctrls = 0x8080808080808080ULL;
                 group_ptr = cw_write_target_data(&empty_ctrls, sizeof(empty_ctrls), proc_info);
                 if (group_ptr == NULL) {
-                    bpf_printk("cw_inject_header_half: Failed to allocate group");
+                    cw_bpf_debug("cw_inject_header_half: Failed to allocate group");
                     return -1;
                 }
                 
@@ -153,25 +153,25 @@ static __always_inline long cw_inject_header_half(void* headers_ptr, char * head
                     void *chunk_ptr = (void*)((u64)group_ptr + (i * 8));
                     res = bpf_probe_write_user(chunk_ptr, &zero, sizeof(zero));
                     if (res < 0) {
-                        bpf_printk("cw_inject_header_half: Failed to init chunk %d, res=%ld", i, res);
+                        cw_bpf_debug("cw_inject_header_half: Failed to init chunk %d, res=%ld", i, res);
                         return -1;
                     }
                 }
                 
-                bpf_printk("cw_inject_header_half: Allocated new group at %p", group_ptr);
+                cw_bpf_debug("cw_inject_header_half: Allocated new group at %p", group_ptr);
                 
                 // Update dirPtr in the map to point to the new group
                 res = bpf_probe_write_user(dirPtr_ptr, &group_ptr, sizeof(group_ptr));
                 if (res < 0) {
-                    bpf_printk("cw_inject_header_half: Failed to update dirPtr, res=%ld", res);
+                    cw_bpf_debug("cw_inject_header_half: Failed to update dirPtr, res=%ld", res);
                     return -1;
                 }
-                bpf_printk("cw_inject_header_half: Updated dirPtr");
+                cw_bpf_debug("cw_inject_header_half: Updated dirPtr");
             } else {
-                bpf_printk("cw_inject_header_half: group_ptr=%p (existing)", group_ptr);
+                cw_bpf_debug("cw_inject_header_half: group_ptr=%p (existing)", group_ptr);
             }
         } else {
-            bpf_printk("cw_inject_header_half: Large map (dirLen=%d) not supported yet", dirLen);
+            cw_bpf_debug("cw_inject_header_half: Large map (dirLen=%d) not supported yet", dirLen);
             return -1;
         }
 
@@ -179,10 +179,10 @@ static __always_inline long cw_inject_header_half(void* headers_ptr, char * head
         u64 ctrls = 0;
         res = bpf_probe_read_user(&ctrls, sizeof(ctrls), group_ptr);
         if (res < 0) {
-            bpf_printk("cw_inject_header_half: Failed to read control word, res=%ld", res);
+            cw_bpf_debug("cw_inject_header_half: Failed to read control word, res=%ld", res);
             return -1;
         }
-        bpf_printk("cw_inject_header_half: ctrls=0x%llx", ctrls);
+        cw_bpf_debug("cw_inject_header_half: ctrls=0x%llx", ctrls);
 
         // Find first empty slot (ctrl byte = 0x80)
         u8 empty_ctrl = 0x80;
@@ -194,13 +194,13 @@ static __always_inline long cw_inject_header_half(void* headers_ptr, char * head
             if (ctrl_byte == empty_ctrl) {
                 slot_idx = i;
                 found_empty = true;
-                bpf_printk("cw_inject_header_half: Found empty slot at index %d", i);
+                cw_bpf_debug("cw_inject_header_half: Found empty slot at index %d", i);
                 break;
             }
         }
 
         if (!found_empty) {
-            bpf_printk("cw_inject_header_half: No empty slot found (ctrls=0x%llx)", ctrls);
+            cw_bpf_debug("cw_inject_header_half: No empty slot found (ctrls=0x%llx)", ctrls);
             return -1;
         }
 
@@ -217,7 +217,7 @@ static __always_inline long cw_inject_header_half(void* headers_ptr, char * head
         __builtin_memcpy(bucket_map_value->header_str, header_str, CW_HEADER_VAL_LENGTH);
         
         // Quick verification: check first 3 bytes
-        bpf_printk("cw_inject_header_half: copied[0-2]=0x%02x 0x%02x 0x%02x", 
+        cw_bpf_debug("cw_inject_header_half: copied[0-2]=0x%02x 0x%02x 0x%02x", 
                    (u8)bucket_map_value->header_str[0], 
                    (u8)bucket_map_value->header_str[1], 
                    (u8)bucket_map_value->header_str[2]);
@@ -226,23 +226,23 @@ static __always_inline long cw_inject_header_half(void* headers_ptr, char * head
         // Actually, we can use a different approach - store dirLen in bucket_index
         // For now, we'll use bucket_index as slot_idx (0-7), and check version in go_update_header
         
-        bpf_printk("cw_inject_header_half: SUCCESS - saved info for Swiss Tables, slot_idx=%d", slot_idx);
+        cw_bpf_debug("cw_inject_header_half: SUCCESS - saved info for Swiss Tables, slot_idx=%d", slot_idx);
         return 0;
     }
 
     // Old implementation for Go < 1.24
-    bpf_printk("cw_inject_header_half: Using old hmap implementation");
+    cw_bpf_debug("cw_inject_header_half: Using old hmap implementation");
     
     // Read the key-value count - this field must be the first one in the hmap struct
     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("cw_inject_header_half: Couldn't read map key-value count, res=%ld", res);
+        cw_bpf_debug("cw_inject_header_half: Couldn't read map key-value count, res=%ld", res);
         return -1;
     }
 
     if (curr_keyvalue_count >= 8) {
-        bpf_printk("cw_inject_header_half: Map size is bigger than 8, skipping");
+        cw_bpf_debug("cw_inject_header_half: Map size is bigger than 8, skipping");
         return -1;
     }
 
@@ -253,13 +253,13 @@ static __always_inline long cw_inject_header_half(void* headers_ptr, char * head
         // No key-value pairs in the Go map, need to "allocate" memory for the user
         bucket_ptr = cw_write_target_data(bucket_map_value, sizeof(struct map_bucket), proc_info);
         if (bucket_ptr == NULL) {
-            bpf_printk("cw_inject_header_half: Failed to write bucket to user");
+            cw_bpf_debug("cw_inject_header_half: 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("cw_inject_header_half: Failed to update bucket pointer, res=%ld", res);
+            cw_bpf_debug("cw_inject_header_half: Failed to update bucket pointer, res=%ld", res);
             return -1;
         }
     } else {
@@ -278,7 +278,7 @@ static __always_inline long cw_inject_header_half(void* headers_ptr, char * head
     bucket_map_value->bucket_index = bucket_index;
     bpf_probe_read(bucket_map_value->header_str, sizeof(bucket_map_value->header_str), header_str);
     
-    bpf_printk("cw_inject_header_half: SUCCESS - saved info for old hmap, bucket_index=%d", bucket_index);
+    cw_bpf_debug("cw_inject_header_half: SUCCESS - saved info for old hmap, bucket_index=%d", bucket_index);
     return 0;
 }
 
@@ -286,7 +286,7 @@ static __always_inline long cw_inject_header_half(void* headers_ptr, char * head
 // func net/http/transport.roundTrip(req *Request) (*Response, error)
 SEC("uprobe/Transport_roundTrip")
 int uprobe_Transport_roundTrip(struct pt_regs *ctx) {
-	bpf_printk("--------[Uprobe HTTP Client] start %llu",get_current_goroutine());
+	cw_bpf_debug("--------[Uprobe HTTP Client] start %llu",get_current_goroutine());
 
     u64 request_pos = 2;
     void *req_ptr = get_argument(ctx, request_pos);
@@ -428,14 +428,14 @@ int uprobe_Transport_roundTrip(struct pt_regs *ctx) {
 	span_context_to_cw_string(&httpReq->apm_sc, val);
 	
 	// Verify val content after generation - check first few bytes as hex
-	bpf_printk("uprobe_Transport_roundTrip: val[0]=0x%02x, val[1]=0x%02x, val[2]=0x%02x", 
+	cw_bpf_debug("uprobe_Transport_roundTrip: val[0]=0x%02x, val[1]=0x%02x, val[2]=0x%02x", 
 	           (u8)val[0], (u8)val[1], (u8)val[2]);
-	bpf_printk("uprobe_Transport_roundTrip: val[3]=0x%02x, val[4]=0x%02x, val[5]=0x%02x", 
+	cw_bpf_debug("uprobe_Transport_roundTrip: val[3]=0x%02x, val[4]=0x%02x, val[5]=0x%02x", 
 	           (u8)val[3], (u8)val[4], (u8)val[5]);
 	
 	// Also verify as characters if printable
 	if (val[0] >= 32 && val[0] < 127) {
-		bpf_printk("uprobe_Transport_roundTrip: val[0-2] as chars: %c%c%c", val[0], val[1], val[2]);
+		cw_bpf_debug("uprobe_Transport_roundTrip: val[0-2] as chars: %c%c%c", val[0], val[1], val[2]);
 	}
 
 	long res2 = cw_inject_header_half(headers_ptr, val,proc_info);
@@ -459,7 +459,7 @@ int uprobe_Transport_roundTrip(struct pt_regs *ctx) {
 // bpf_prog_up__go_update_header: 完成实际的 header 注入
 // 从 bucket_map_value 读取信息,写入到 Go map 中
 PROGUP(go_update_header)(struct pt_regs *ctx) {
-	bpf_printk("go_update_header: START");
+	cw_bpf_debug("go_update_header: START");
 	
 	__u64 pid_tgid = bpf_get_current_pid_tgid();
 	__u32 tgid = pid_tgid >> 32;
@@ -467,27 +467,27 @@ PROGUP(go_update_header)(struct pt_regs *ctx) {
 			bpf_map_lookup_elem(&proc_info_map, &tgid);
 	if(!proc_info)
 	{
-		bpf_printk("go_update_header: proc_info is NULL");
+		cw_bpf_debug("go_update_header: proc_info is NULL");
 		return 0;
 	}
 
 	u32 map_id = CLIENT_MAP_KEY;
 	struct map_bucket *bucket_map_value = bpf_map_lookup_elem(&golang_mapbucket_storage_map, &map_id);
 	if (!bucket_map_value) {
-		bpf_printk("go_update_header: bucket_map_value is NULL");
+		cw_bpf_debug("go_update_header: bucket_map_value is NULL");
 		return -1;
 	}
 	
 	if (!bucket_map_value->headers_ptr){
-		bpf_printk("go_update_header: headers_ptr is NULL");
+		cw_bpf_debug("go_update_header: headers_ptr is NULL");
 		return -1;
 	}
 	if (!bucket_map_value->bucket_ptr){
-		bpf_printk("go_update_header: bucket_ptr is NULL");
+		cw_bpf_debug("go_update_header: bucket_ptr is NULL");
 		return -1;
 	}
 	if (bucket_map_value->bucket_index >= 8) {
-		bpf_printk("go_update_header: bucket_index >= 8");
+		cw_bpf_debug("go_update_header: bucket_index >= 8");
 		return -1;
 	}
 
@@ -497,19 +497,19 @@ PROGUP(go_update_header)(struct pt_regs *ctx) {
 	char * header_str = bucket_map_value->header_str;
 	u8 bucket_index = bucket_map_value->bucket_index;  // For old hmap: bucket_index, For Swiss Tables: slot_idx
 
-	bpf_printk("go_update_header: headers_ptr=%p", headers_ptr);
-	bpf_printk("go_update_header: bucket_ptr=%p, count=%llu", bucket_ptr, curr_keyvalue_count);
-	bpf_printk("go_update_header: bucket_index=%d", bucket_index);
+	cw_bpf_debug("go_update_header: headers_ptr=%p", headers_ptr);
+	cw_bpf_debug("go_update_header: bucket_ptr=%p, count=%llu", bucket_ptr, curr_keyvalue_count);
+	cw_bpf_debug("go_update_header: bucket_index=%d", bucket_index);
 	
 	// Verify header_str content before using it - check first 6 bytes
-	bpf_printk("go_update_header: header_str[0-2]=0x%02x 0x%02x 0x%02x", 
+	cw_bpf_debug("go_update_header: header_str[0-2]=0x%02x 0x%02x 0x%02x", 
 	           (u8)header_str[0], (u8)header_str[1], (u8)header_str[2]);
-	bpf_printk("go_update_header: header_str[3-5]=0x%02x 0x%02x 0x%02x", 
+	cw_bpf_debug("go_update_header: header_str[3-5]=0x%02x 0x%02x 0x%02x", 
 	           (u8)header_str[3], (u8)header_str[4], (u8)header_str[5]);
 
 	// Check if Go version >= 1.24 (Swiss Tables)
 	if (proc_info->version >= GO_VERSION(1, 24, 0)) {
-		bpf_printk("go_update_header: Go 1.24+ Swiss Tables - injecting into group");
+		cw_bpf_debug("go_update_header: Go 1.24+ Swiss Tables - injecting into group");
 		
 		// For Swiss Tables, bucket_ptr is actually group_ptr, bucket_index is slot_idx
 		void *group_ptr = bucket_ptr;
@@ -520,10 +520,10 @@ PROGUP(go_update_header)(struct pt_regs *ctx) {
 		char key[8] = "cwtrace";  // 7 chars + null terminator for C string
 		void *key_str_ptr = cw_write_target_data(key, CW_HEADER_KEY_LENGTH, proc_info);
 		if (key_str_ptr == NULL) {
-			bpf_printk("go_update_header: Failed to write key");
+			cw_bpf_debug("go_update_header: Failed to write key");
 			return -1;
 		}
-		bpf_printk("go_update_header: key_str_ptr=%p", key_str_ptr);
+		cw_bpf_debug("go_update_header: key_str_ptr=%p", key_str_ptr);
 		
 		// Save key_str_ptr to a volatile variable to prevent compiler optimization
 		// Use multiple steps to force compiler to use correct value
@@ -531,12 +531,12 @@ PROGUP(go_update_header)(struct pt_regs *ctx) {
 		volatile void *key_str_ptr_volatile = key_str_ptr_copy;
 		u64 saved_key_str_ptr_early = (u64)(void*)key_str_ptr_volatile;
 		
-		bpf_printk("go_update_header: saved_key_str_ptr_early=0x%llx", saved_key_str_ptr_early);
+		cw_bpf_debug("go_update_header: saved_key_str_ptr_early=0x%llx", saved_key_str_ptr_early);
 		
 		// Verify the saved value is not NULL and not equal to any future slot_ptr_u64 value
 		// We can't check against slot_ptr_u64 yet, but we can check it's not zero
 		if (saved_key_str_ptr_early == 0) {
-			bpf_printk("go_update_header: ERROR: saved_key_str_ptr_early is NULL!");
+			cw_bpf_debug("go_update_header: ERROR: saved_key_str_ptr_early is NULL!");
 			return -1;
 		}
 		
@@ -544,21 +544,21 @@ PROGUP(go_update_header)(struct pt_regs *ctx) {
 		void *key_str_ptr_verify = key_str_ptr;
 		u64 saved_verify = (u64)key_str_ptr_verify;
 		if (saved_key_str_ptr_early != saved_verify) {
-			bpf_printk("go_update_header: ERROR: saved_key_str_ptr_early mismatch!");
-			bpf_printk("go_update_header: saved=0x%llx, verify=0x%llx", saved_key_str_ptr_early, saved_verify);
+			cw_bpf_debug("go_update_header: ERROR: saved_key_str_ptr_early mismatch!");
+			cw_bpf_debug("go_update_header: saved=0x%llx, verify=0x%llx", saved_key_str_ptr_early, saved_verify);
 			return -1;
 		}
 
 		// Prepare value string
 		// Verify header_str content before writing
-		bpf_printk("go_update_header: Before write, header_str[0-2]=0x%02x 0x%02x 0x%02x", 
+		cw_bpf_debug("go_update_header: Before write, header_str[0-2]=0x%02x 0x%02x 0x%02x", 
 		           (u8)header_str[0], (u8)header_str[1], (u8)header_str[2]);
-		bpf_printk("go_update_header: Before write, header_str[3-5]=0x%02x 0x%02x 0x%02x", 
+		cw_bpf_debug("go_update_header: Before write, header_str[3-5]=0x%02x 0x%02x 0x%02x", 
 		           (u8)header_str[3], (u8)header_str[4], (u8)header_str[5]);
 		
 		void *header_str_ptr = cw_write_target_data(header_str, CW_HEADER_VAL_LENGTH, proc_info);
 		if(header_str_ptr == NULL) {
-			bpf_printk("go_update_header: Failed to write header_str");
+			cw_bpf_debug("go_update_header: Failed to write header_str");
 			return -1;
 		}
 		// Save header_str_ptr to u64 immediately and verify it's correct
@@ -570,26 +570,26 @@ PROGUP(go_update_header)(struct pt_regs *ctx) {
 		// Verify immediately
 		u64 verify_immediate = (u64)header_str_ptr;
 		if (saved_header_str_ptr_u64 != verify_immediate) {
-			bpf_printk("go_update_header: ERROR: saved_header_str_ptr_u64 mismatch at save!");
-			bpf_printk("go_update_header: saved=0x%llx, verify=0x%llx", saved_header_str_ptr_u64, verify_immediate);
+			cw_bpf_debug("go_update_header: ERROR: saved_header_str_ptr_u64 mismatch at save!");
+			cw_bpf_debug("go_update_header: saved=0x%llx, verify=0x%llx", saved_header_str_ptr_u64, verify_immediate);
 			return -1;
 		}
 		
-		bpf_printk("go_update_header: header_str_ptr=%p", header_str_ptr);
-		bpf_printk("go_update_header: saved_header_str_ptr_u64=0x%llx", saved_header_str_ptr_u64);
+		cw_bpf_debug("go_update_header: header_str_ptr=%p", header_str_ptr);
+		cw_bpf_debug("go_update_header: saved_header_str_ptr_u64=0x%llx", saved_header_str_ptr_u64);
 		
 		// Verify what was written to userspace using both pointers
 		char verify_header_str_saved[8] = {0};
 		long verify_res_saved = bpf_probe_read_user(verify_header_str_saved, sizeof(verify_header_str_saved), (void*)saved_header_str_ptr_u64);
 		if (verify_res_saved == 0) {
-			bpf_printk("go_update_header: From saved_ptr, [0-2]=0x%02x 0x%02x 0x%02x", 
+			cw_bpf_debug("go_update_header: From saved_ptr, [0-2]=0x%02x 0x%02x 0x%02x", 
 			           (u8)verify_header_str_saved[0], (u8)verify_header_str_saved[1], (u8)verify_header_str_saved[2]);
 		}
 		
 		char verify_header_str_orig[8] = {0};
 		long verify_res_orig = bpf_probe_read_user(verify_header_str_orig, sizeof(verify_header_str_orig), header_str_ptr);
 		if (verify_res_orig == 0) {
-			bpf_printk("go_update_header: From orig_ptr, [0-2]=0x%02x 0x%02x 0x%02x", 
+			cw_bpf_debug("go_update_header: From orig_ptr, [0-2]=0x%02x 0x%02x 0x%02x", 
 			           (u8)verify_header_str_orig[0], (u8)verify_header_str_orig[1], (u8)verify_header_str_orig[2]);
 		}
 
@@ -597,10 +597,10 @@ PROGUP(go_update_header)(struct pt_regs *ctx) {
 		struct go_string_ot val_str = {.str = (void*)saved_header_str_ptr_u64, .len = CW_HEADER_VAL_LENGTH};
 		void *val_str_struct_ptr = cw_write_target_data((void*)&val_str, sizeof(val_str), proc_info);
 		if(val_str_struct_ptr == NULL) {
-			bpf_printk("go_update_header: Failed to write val_str struct");
+			cw_bpf_debug("go_update_header: Failed to write val_str struct");
 			return -1;
 		}
-		bpf_printk("go_update_header: val_str_struct_ptr=%p", val_str_struct_ptr);
+		cw_bpf_debug("go_update_header: val_str_struct_ptr=%p", val_str_struct_ptr);
 
 		// Calculate slot offset
 		// Group layout: ctrlGroup (8 bytes) + slots[8]
@@ -613,30 +613,30 @@ PROGUP(go_update_header)(struct pt_regs *ctx) {
 		u64 slot_size = 40;  // string (16) + []string (24)
 		u64 slot_offset = group_slots_offset + (slot_idx * slot_size);
 		
-		bpf_printk("go_update_header: slot_idx=%d", slot_idx);
-		bpf_printk("go_update_header: group_slots_offset=%llu", group_slots_offset);
-		bpf_printk("go_update_header: slot_size=%llu", slot_size);
-		bpf_printk("go_update_header: slot_offset=%llu", slot_offset);
-		bpf_printk("go_update_header: group_ptr=%p", group_ptr);
+		cw_bpf_debug("go_update_header: slot_idx=%d", slot_idx);
+		cw_bpf_debug("go_update_header: group_slots_offset=%llu", group_slots_offset);
+		cw_bpf_debug("go_update_header: slot_size=%llu", slot_size);
+		cw_bpf_debug("go_update_header: slot_offset=%llu", slot_offset);
+		cw_bpf_debug("go_update_header: group_ptr=%p", group_ptr);
 		
 		// Calculate slot_ptr carefully to avoid any issues
 		u64 group_ptr_u64 = (u64)group_ptr;
 		u64 slot_ptr_u64 = group_ptr_u64 + slot_offset;
 		
-		bpf_printk("go_update_header: group_ptr_u64=0x%llx", group_ptr_u64);
-		bpf_printk("go_update_header: slot_ptr_u64=0x%llx", slot_ptr_u64);
+		cw_bpf_debug("go_update_header: group_ptr_u64=0x%llx", group_ptr_u64);
+		cw_bpf_debug("go_update_header: slot_ptr_u64=0x%llx", slot_ptr_u64);
 		
 		// Verify slot_ptr is within reasonable bounds (should be >= group_ptr + 8 and < group_ptr + 328)
 		if (slot_ptr_u64 < group_ptr_u64 + 8 || slot_ptr_u64 >= group_ptr_u64 + 328) {
-			bpf_printk("go_update_header: slot_ptr out of bounds!");
-			bpf_printk("go_update_header: group_ptr_u64=0x%llx, slot_ptr_u64=0x%llx", group_ptr_u64, slot_ptr_u64);
+			cw_bpf_debug("go_update_header: slot_ptr out of bounds!");
+			cw_bpf_debug("go_update_header: group_ptr_u64=0x%llx, slot_ptr_u64=0x%llx", group_ptr_u64, slot_ptr_u64);
 			return -1;
 		}
 
 		// Write key (go_string_ot at slot offset 0)
 		// Verify key_str_ptr is valid
 		if (key_str_ptr == NULL) {
-			bpf_printk("go_update_header: key_str_ptr is NULL!");
+			cw_bpf_debug("go_update_header: key_str_ptr is NULL!");
 			return -1;
 		}
 		
@@ -644,20 +644,20 @@ PROGUP(go_update_header)(struct pt_regs *ctx) {
 		char key_check[8] = {0};
 		long res = bpf_probe_read_user(key_check, sizeof(key_check), key_str_ptr);
 		if (res < 0) {
-			bpf_printk("go_update_header: Failed to verify key string data, res=%ld", res);
+			cw_bpf_debug("go_update_header: Failed to verify key string data, res=%ld", res);
 			return -1;
 		}
-		bpf_printk("go_update_header: key_str_ptr=%p", key_str_ptr);
-		bpf_printk("go_update_header: key_check[0]=0x%x", (u8)key_check[0]);
+		cw_bpf_debug("go_update_header: key_str_ptr=%p", key_str_ptr);
+		cw_bpf_debug("go_update_header: key_check[0]=0x%x", (u8)key_check[0]);
 		
 		// Create key_str struct and verify it's correct before writing
 		struct go_string_ot key_str = {.str = key_str_ptr, .len = CW_HEADER_KEY_LENGTH};
-		bpf_printk("go_update_header: Writing key: str=%p, len=%d", key_str.str, key_str.len);
+		cw_bpf_debug("go_update_header: Writing key: str=%p, len=%d", key_str.str, key_str.len);
 		
 		// Verify key_str is still correct right before writing
 		if (key_str.str != key_str_ptr || key_str.len != CW_HEADER_KEY_LENGTH) {
-			bpf_printk("go_update_header: ERROR: key_str corrupted before write!");
-			bpf_printk("go_update_header: key_str.str=%p, expected=%p", key_str.str, key_str_ptr);
+			cw_bpf_debug("go_update_header: ERROR: key_str corrupted before write!");
+			cw_bpf_debug("go_update_header: key_str.str=%p, expected=%p", key_str.str, key_str_ptr);
 			return -1;
 		}
 		
@@ -666,8 +666,8 @@ PROGUP(go_update_header)(struct pt_regs *ctx) {
 		struct go_string_ot slot_before = {0};
 		res = bpf_probe_read_user(&slot_before, sizeof(slot_before), (void*)slot_ptr_u64);
 		if (res == 0) {
-			bpf_printk("go_update_header: Slot before write: str=%p", slot_before.str);
-			bpf_printk("go_update_header: Slot before write: len=%lld", slot_before.len);
+			cw_bpf_debug("go_update_header: Slot before write: str=%p", slot_before.str);
+			cw_bpf_debug("go_update_header: Slot before write: len=%lld", slot_before.len);
 		}
 		
 		// Write key directly using slot_ptr_u64 - write pointer and length separately to avoid corruption
@@ -676,21 +676,21 @@ PROGUP(go_update_header)(struct pt_regs *ctx) {
 		char key_recreate[8] = "cwtrace";
 		void *key_str_ptr_fresh = cw_write_target_data(key_recreate, CW_HEADER_KEY_LENGTH, proc_info);
 		if (key_str_ptr_fresh == NULL) {
-			bpf_printk("go_update_header: Failed to recreate key string");
+			cw_bpf_debug("go_update_header: Failed to recreate key string");
 			return -1;
 		}
 		u64 key_str_ptr_u64 = (u64)key_str_ptr_fresh;
 		
 		u64 saved_key_str_len = (u64)CW_HEADER_KEY_LENGTH;
 		
-		bpf_printk("go_update_header: key_str_ptr_fresh=%p, u64=0x%llx", key_str_ptr_fresh, key_str_ptr_u64);
-		bpf_printk("go_update_header: saved_key_str_len=%llu", saved_key_str_len);
-		bpf_printk("go_update_header: Writing key pointer: 0x%llx to slot at 0x%llx", key_str_ptr_u64, slot_ptr_u64);
+		cw_bpf_debug("go_update_header: key_str_ptr_fresh=%p, u64=0x%llx", key_str_ptr_fresh, key_str_ptr_u64);
+		cw_bpf_debug("go_update_header: saved_key_str_len=%llu", saved_key_str_len);
+		cw_bpf_debug("go_update_header: Writing key pointer: 0x%llx to slot at 0x%llx", key_str_ptr_u64, slot_ptr_u64);
 		
 		// Write pointer first (first 8 bytes of go_string_ot) - use fresh value
 		res = bpf_probe_write_user((void*)slot_ptr_u64, &key_str_ptr_u64, sizeof(key_str_ptr_u64));
 		if (res < 0) {
-			bpf_printk("go_update_header: Failed to write key pointer, res=%ld", res);
+			cw_bpf_debug("go_update_header: Failed to write key pointer, res=%ld", res);
 			return -1;
 		}
 		
@@ -698,34 +698,34 @@ PROGUP(go_update_header)(struct pt_regs *ctx) {
 		u64 verify_ptr = 0;
 		res = bpf_probe_read_user(&verify_ptr, sizeof(verify_ptr), (void*)slot_ptr_u64);
 		if (res == 0) {
-			bpf_printk("go_update_header: Verified pointer after write: 0x%llx", verify_ptr);
+			cw_bpf_debug("go_update_header: Verified pointer after write: 0x%llx", verify_ptr);
 			if (verify_ptr != key_str_ptr_u64) {
-				bpf_printk("go_update_header: ERROR: Pointer mismatch!");
-				bpf_printk("go_update_header: Expected 0x%llx, got 0x%llx", key_str_ptr_u64, verify_ptr);
+				cw_bpf_debug("go_update_header: ERROR: Pointer mismatch!");
+				cw_bpf_debug("go_update_header: Expected 0x%llx, got 0x%llx", key_str_ptr_u64, verify_ptr);
 			}
 		}
 		
 		// Write length second (next 8 bytes of go_string_ot)
 		u64 slot_len_ptr = slot_ptr_u64 + 8;
-		bpf_printk("go_update_header: Writing key length: %llu to slot at 0x%llx", saved_key_str_len, slot_len_ptr);
+		cw_bpf_debug("go_update_header: Writing key length: %llu to slot at 0x%llx", saved_key_str_len, slot_len_ptr);
 		res = bpf_probe_write_user((void*)slot_len_ptr, &saved_key_str_len, sizeof(saved_key_str_len));
 		if (res < 0) {
-			bpf_printk("go_update_header: Failed to write key length, res=%ld", res);
+			cw_bpf_debug("go_update_header: Failed to write key length, res=%ld", res);
 			return -1;
 		}
-		bpf_printk("go_update_header: Key written to slot");
+		cw_bpf_debug("go_update_header: Key written to slot");
 		
 		// Verify what we wrote - use slot_ptr_u64 directly
 		u64 slot_ptr_for_verify = slot_ptr_u64;
 		struct go_string_ot verify_key = {0};
 		res = bpf_probe_read_user(&verify_key, sizeof(verify_key), (void*)slot_ptr_for_verify);
 		if (res == 0) {
-			bpf_printk("go_update_header: Verified key: str=%p, len=%lld", verify_key.str, verify_key.len);
-			bpf_printk("go_update_header: Verify read from 0x%llx", slot_ptr_for_verify);
+			cw_bpf_debug("go_update_header: Verified key: str=%p, len=%lld", verify_key.str, verify_key.len);
+			cw_bpf_debug("go_update_header: Verify read from 0x%llx", slot_ptr_for_verify);
 			if (verify_key.str != key_str_ptr_fresh || verify_key.len != CW_HEADER_KEY_LENGTH) {
-				bpf_printk("go_update_header: Key verification failed!");
-				bpf_printk("go_update_header: Expected str=%p, len=%d", key_str_ptr_fresh, CW_HEADER_KEY_LENGTH);
-				bpf_printk("go_update_header: Got str=%p, len=%lld", verify_key.str, verify_key.len);
+				cw_bpf_debug("go_update_header: Key verification failed!");
+				cw_bpf_debug("go_update_header: Expected str=%p, len=%d", key_str_ptr_fresh, CW_HEADER_KEY_LENGTH);
+				cw_bpf_debug("go_update_header: Got str=%p, len=%lld", verify_key.str, verify_key.len);
 				return -1;
 			}
 			
@@ -733,57 +733,57 @@ PROGUP(go_update_header)(struct pt_regs *ctx) {
 			char key_content[8] = {0};
 			res = bpf_probe_read_user(key_content, sizeof(key_content), verify_key.str);
 			if (res == 0) {
-				bpf_printk("go_update_header: Key content[0-2]: %c%c%c", key_content[0], key_content[1], key_content[2]);
-				bpf_printk("go_update_header: Key content[3-4]: %c%c", key_content[3], key_content[4]);
-				bpf_printk("go_update_header: Key content[5-6]: %c%c", key_content[5], key_content[6]);
+				cw_bpf_debug("go_update_header: Key content[0-2]: %c%c%c", key_content[0], key_content[1], key_content[2]);
+				cw_bpf_debug("go_update_header: Key content[3-4]: %c%c", key_content[3], key_content[4]);
+				cw_bpf_debug("go_update_header: Key content[5-6]: %c%c", key_content[5], key_content[6]);
 			}
 			
 			// Read the entire slot to see what Go runtime will see
 			// Read as go_string_ot first, then verify the bytes
 			u64 slot_ptr_for_read = slot_ptr_u64;
-			bpf_printk("go_update_header: Reading slot at 0x%llx", slot_ptr_for_read);
+			cw_bpf_debug("go_update_header: Reading slot at 0x%llx", slot_ptr_for_read);
 			struct go_string_ot slot_key_verify = {0};
 			res = bpf_probe_read_user(&slot_key_verify, sizeof(slot_key_verify), (void*)slot_ptr_for_read);
 			if (res == 0) {
-				bpf_printk("go_update_header: Slot key as struct: str=%p, len=%lld", slot_key_verify.str, slot_key_verify.len);
-				bpf_printk("go_update_header: Expected: str=%p, len=%d", key_str_ptr_fresh, CW_HEADER_KEY_LENGTH);
+				cw_bpf_debug("go_update_header: Slot key as struct: str=%p, len=%lld", slot_key_verify.str, slot_key_verify.len);
+				cw_bpf_debug("go_update_header: Expected: str=%p, len=%d", key_str_ptr_fresh, CW_HEADER_KEY_LENGTH);
 				if (slot_key_verify.str != key_str_ptr_fresh || slot_key_verify.len != CW_HEADER_KEY_LENGTH) {
-					bpf_printk("go_update_header: WARNING: Slot content mismatch!");
+					cw_bpf_debug("go_update_header: WARNING: Slot content mismatch!");
 				}
 			} else {
-				bpf_printk("go_update_header: Failed to read slot_key_verify, res=%ld", res);
+				cw_bpf_debug("go_update_header: Failed to read slot_key_verify, res=%ld", res);
 			}
 			
 			// Also read raw bytes for debugging - use slot_key_verify we already read
-			bpf_printk("go_update_header: Slot raw pointer from struct: 0x%llx", (u64)slot_key_verify.str);
-			bpf_printk("go_update_header: Slot raw length from struct: 0x%llx", (u64)slot_key_verify.len);
+			cw_bpf_debug("go_update_header: Slot raw pointer from struct: 0x%llx", (u64)slot_key_verify.str);
+			cw_bpf_debug("go_update_header: Slot raw length from struct: 0x%llx", (u64)slot_key_verify.len);
 			
 			// Read raw bytes to see what's actually in memory
 			char slot_raw[16] = {0};  // Only read first 16 bytes (go_string_ot)
 			res = bpf_probe_read_user(slot_raw, sizeof(slot_raw), (void*)slot_ptr_for_read);
 			if (res == 0) {
-				bpf_printk("go_update_header: Slot raw bytes (first 16 bytes):");
+				cw_bpf_debug("go_update_header: Slot raw bytes (first 16 bytes):");
 				for (int i = 0; i < 16; i++) {
-					bpf_printk("go_update_header: slot[%d]=0x%02x", i, (u8)slot_raw[i]);
+					cw_bpf_debug("go_update_header: slot[%d]=0x%02x", i, (u8)slot_raw[i]);
 				}
 				// Verify first 8 bytes match the pointer we wrote
 				u64 *raw_ptr = (u64*)slot_raw;
-				bpf_printk("go_update_header: First 8 bytes as u64: 0x%llx", raw_ptr[0]);
-				bpf_printk("go_update_header: Expected pointer: 0x%llx", key_str_ptr_u64);
+				cw_bpf_debug("go_update_header: First 8 bytes as u64: 0x%llx", raw_ptr[0]);
+				cw_bpf_debug("go_update_header: Expected pointer: 0x%llx", key_str_ptr_u64);
 			}
 		} else {
-			bpf_printk("go_update_header: Failed to verify key, res=%ld", res);
+			cw_bpf_debug("go_update_header: Failed to verify key, res=%ld", res);
 		}
 
 		// Write value (go_slice_ot at slot offset 16, after key)
 		// Verify elem_ptr is within bounds
 		u64 elem_ptr_u64 = slot_ptr_u64 + 16;  // After key (16 bytes)
 		if (elem_ptr_u64 < group_ptr_u64 + 8 || elem_ptr_u64 >= group_ptr_u64 + 328) {
-			bpf_printk("go_update_header: elem_ptr out of bounds!");
-			bpf_printk("go_update_header: elem_ptr_u64=0x%llx", elem_ptr_u64);
+			cw_bpf_debug("go_update_header: elem_ptr out of bounds!");
+			cw_bpf_debug("go_update_header: elem_ptr_u64=0x%llx", elem_ptr_u64);
 			return -1;
 		}
-		bpf_printk("go_update_header: elem_ptr_u64=0x%llx", elem_ptr_u64);
+		cw_bpf_debug("go_update_header: elem_ptr_u64=0x%llx", elem_ptr_u64);
 		
 		// Re-create value string struct to avoid register corruption (similar to key fix)
 		// Re-read header_str from map to get the correct pointer value
@@ -795,40 +795,40 @@ PROGUP(go_update_header)(struct pt_regs *ctx) {
 		// Re-write header_str to get a fresh pointer (similar to key fix)
 		void *header_str_ptr_fresh = cw_write_target_data(header_str, CW_HEADER_VAL_LENGTH, proc_info);
 		if (header_str_ptr_fresh == NULL) {
-			bpf_printk("go_update_header: Failed to recreate header_str");
+			cw_bpf_debug("go_update_header: Failed to recreate header_str");
 			return -1;
 		}
 		u64 header_str_ptr_fresh_u64 = (u64)header_str_ptr_fresh;
-		bpf_printk("go_update_header: header_str_ptr_fresh=%p, u64=0x%llx", header_str_ptr_fresh, header_str_ptr_fresh_u64);
+		cw_bpf_debug("go_update_header: header_str_ptr_fresh=%p, u64=0x%llx", header_str_ptr_fresh, header_str_ptr_fresh_u64);
 		
 		// Use fresh pointer to create val_str struct
 		struct go_string_ot val_str_fresh = {.str = (void*)header_str_ptr_fresh_u64, .len = CW_HEADER_VAL_LENGTH};
 		void *val_str_struct_ptr_fresh = cw_write_target_data((void*)&val_str_fresh, sizeof(val_str_fresh), proc_info);
 		if (val_str_struct_ptr_fresh == NULL) {
-			bpf_printk("go_update_header: Failed to recreate val_str struct");
+			cw_bpf_debug("go_update_header: Failed to recreate val_str struct");
 			return -1;
 		}
 		u64 val_str_struct_ptr_u64 = (u64)val_str_struct_ptr_fresh;
-		bpf_printk("go_update_header: val_str_struct_ptr_fresh=%p, u64=0x%llx", val_str_struct_ptr_fresh, val_str_struct_ptr_u64);
+		cw_bpf_debug("go_update_header: val_str_struct_ptr_fresh=%p, u64=0x%llx", val_str_struct_ptr_fresh, val_str_struct_ptr_u64);
 		
 		struct go_slice_ot val_slice = {.array = (void*)val_str_struct_ptr_u64, .len = 1, .cap = 1};
-		bpf_printk("go_update_header: Writing value slice: array=%p, len=%d, cap=%d", val_slice.array, val_slice.len, val_slice.cap);
+		cw_bpf_debug("go_update_header: Writing value slice: array=%p, len=%d, cap=%d", val_slice.array, val_slice.len, val_slice.cap);
 		// Use elem_ptr_u64 directly to avoid variable corruption
 		res = bpf_probe_write_user((void*)elem_ptr_u64, &val_slice, sizeof(val_slice));
 		if (res < 0) {
-			bpf_printk("go_update_header: Failed to write value slice, res=%ld", res);
+			cw_bpf_debug("go_update_header: Failed to write value slice, res=%ld", res);
 			return -1;
 		}
-		bpf_printk("go_update_header: Value written to slot");
+		cw_bpf_debug("go_update_header: Value written to slot");
 		
 		// Verify value was written correctly
 		struct go_slice_ot verify_val = {0};
 		res = bpf_probe_read_user(&verify_val, sizeof(verify_val), (void*)elem_ptr_u64);
 		if (res == 0) {
-			bpf_printk("go_update_header: Verified value: array=%p, len=%lld, cap=%lld", verify_val.array, verify_val.len, verify_val.cap);
+			cw_bpf_debug("go_update_header: Verified value: array=%p, len=%lld, cap=%lld", verify_val.array, verify_val.len, verify_val.cap);
 			if (verify_val.array != (void*)val_str_struct_ptr_u64 || verify_val.len != 1 || verify_val.cap != 1) {
-				bpf_printk("go_update_header: Value verification failed!");
-				bpf_printk("go_update_header: Expected array=%p, got array=%p", (void*)val_str_struct_ptr_u64, verify_val.array);
+				cw_bpf_debug("go_update_header: Value verification failed!");
+				cw_bpf_debug("go_update_header: Expected array=%p, got array=%p", (void*)val_str_struct_ptr_u64, verify_val.array);
 				return -1;
 			}
 			
@@ -836,16 +836,16 @@ PROGUP(go_update_header)(struct pt_regs *ctx) {
 			struct go_string_ot verify_val_str = {0};
 			res = bpf_probe_read_user(&verify_val_str, sizeof(verify_val_str), verify_val.array);
 			if (res == 0) {
-				bpf_printk("go_update_header: Value string: str=%p, len=%lld", verify_val_str.str, verify_val_str.len);
+				cw_bpf_debug("go_update_header: Value string: str=%p, len=%lld", verify_val_str.str, verify_val_str.len);
 				if (verify_val_str.str != (void*)header_str_ptr_fresh_u64) {
-					bpf_printk("go_update_header: WARNING: Value string pointer mismatch!");
-					bpf_printk("go_update_header: Expected str=%p, got str=%p", (void*)header_str_ptr_fresh_u64, verify_val_str.str);
+					cw_bpf_debug("go_update_header: WARNING: Value string pointer mismatch!");
+					cw_bpf_debug("go_update_header: Expected str=%p, got str=%p", (void*)header_str_ptr_fresh_u64, verify_val_str.str);
 				} else {
 					// Verify the actual string content
 					char verify_str_content[8] = {0};
 					res = bpf_probe_read_user(verify_str_content, sizeof(verify_str_content), verify_val_str.str);
 					if (res == 0) {
-						bpf_printk("go_update_header: Value string content[0-2]=0x%02x 0x%02x 0x%02x", 
+						cw_bpf_debug("go_update_header: Value string content[0-2]=0x%02x 0x%02x 0x%02x", 
 						           (u8)verify_str_content[0], (u8)verify_str_content[1], (u8)verify_str_content[2]);
 					}
 				}
@@ -860,7 +860,7 @@ PROGUP(go_update_header)(struct pt_regs *ctx) {
 		u64 ctrls = 0;
 		res = bpf_probe_read_user(&ctrls, sizeof(ctrls), group_ptr);
 		if (res < 0) {
-			bpf_printk("go_update_header: Failed to read control word, res=%ld", res);
+			cw_bpf_debug("go_update_header: Failed to read control word, res=%ld", res);
 			return -1;
 		}
 		
@@ -868,42 +868,42 @@ PROGUP(go_update_header)(struct pt_regs *ctx) {
 		u64 ctrl_mask = 0xFFULL << (slot_idx * 8);
 		u64 new_ctrl_value = ((u64)new_ctrl) << (slot_idx * 8);
 		ctrls = (ctrls & ~ctrl_mask) | new_ctrl_value;
-		bpf_printk("go_update_header: Updating ctrl, slot_idx=%d, new_ctrl=0x%x", slot_idx, new_ctrl);
+		cw_bpf_debug("go_update_header: Updating ctrl, slot_idx=%d, new_ctrl=0x%x", slot_idx, new_ctrl);
 		
 		res = bpf_probe_write_user(group_ptr, &ctrls, sizeof(ctrls));
 		if (res < 0) {
-			bpf_printk("go_update_header: Failed to update control word, res=%ld", res);
+			cw_bpf_debug("go_update_header: Failed to update control word, res=%ld", res);
 			return -1;
 		}
-		bpf_printk("go_update_header: Control word updated");
+		cw_bpf_debug("go_update_header: Control word updated");
 
 		// Update used count
 		u64 used = curr_keyvalue_count + 1;
 		res = bpf_probe_write_user(headers_ptr, &used, sizeof(used));
 		if (res < 0) {
-			bpf_printk("go_update_header: Failed to update used count, res=%ld", res);
+			cw_bpf_debug("go_update_header: Failed to update used count, res=%ld", res);
 			return -1;
 		}
-		bpf_printk("go_update_header: Used count updated to %llu", used);
+		cw_bpf_debug("go_update_header: Used count updated to %llu", used);
 
 		bpf_memset((unsigned char *)bucket_map_value, sizeof(struct map_bucket), 0);
-		bpf_printk("go_update_header: SUCCESS - Swiss Tables injection completed");
+		cw_bpf_debug("go_update_header: SUCCESS - Swiss Tables injection completed");
 		return 0;
 	}
 
 	// Old implementation for Go < 1.24
-	bpf_printk("go_update_header: Using old hmap implementation");
+	cw_bpf_debug("go_update_header: Using old hmap implementation");
 	
 	char key[CW_HEADER_KEY_LENGTH] = CW_HEADER_KEY_VAL;
 	void *ptr = cw_write_target_data(key, CW_HEADER_KEY_LENGTH, proc_info);
 	if (ptr == NULL) {
-		bpf_printk("go_update_header: Failed to write key");
+		cw_bpf_debug("go_update_header: Failed to write key");
 		return -1;
 	}
 
 	void * header_str_ptr = cw_write_target_data(header_str, CW_HEADER_VAL_LENGTH, proc_info);
 	if(header_str_ptr == NULL) {
-		bpf_printk("go_update_header: Failed to write header_str");
+		cw_bpf_debug("go_update_header: Failed to write header_str");
 		return -1;
 	}
 
@@ -911,7 +911,7 @@ PROGUP(go_update_header)(struct pt_regs *ctx) {
 	struct go_string_ot header_value = {.len = CW_HEADER_VAL_LENGTH, .str = header_str_ptr};
 	void * header_value_ptr = cw_write_target_data((void*)&header_value, sizeof(header_value), proc_info);
 	if(header_value_ptr == NULL) {
-		bpf_printk("go_update_header: Failed to write go_string");
+		cw_bpf_debug("go_update_header: Failed to write go_string");
 		return -1;
 	}
 
@@ -925,19 +925,19 @@ PROGUP(go_update_header)(struct pt_regs *ctx) {
 	curr_keyvalue_count = curr_keyvalue_count + 1;
 	long res = bpf_probe_write_user(headers_ptr, &curr_keyvalue_count, sizeof(curr_keyvalue_count));
 	if (res < 0) {
-		bpf_printk("go_update_header: Failed to update count, res=%ld", res);
+		cw_bpf_debug("go_update_header: Failed to update count, res=%ld", res);
 		return -1;
 	}
 
 	// Update the bucket
 	res = bpf_probe_write_user(bucket_ptr, bucket_map_value, sizeof(struct map_bucket));
 	if (res < 0) {
-		bpf_printk("go_update_header: Failed to update bucket, res=%ld", res);
+		cw_bpf_debug("go_update_header: Failed to update bucket, res=%ld", res);
 		return -1;
 	}
 
 	bpf_memset((unsigned char *)bucket_map_value, sizeof(struct map_bucket), 0);
-	bpf_printk("go_update_header: SUCCESS - old hmap injection completed");
+	cw_bpf_debug("go_update_header: SUCCESS - old hmap injection completed");
 	return 0;
 }
 

+ 36 - 36
ebpftracer/ebpf/utrace/go/net/grpc.client.probe.bpf.c

@@ -94,7 +94,7 @@ u64 status_message_pos = 48;        //使用固定值48即可,不再处理多
 // func (cc *ClientConn) Invoke(ctx context.Context, method string, args, reply interface{}, opts ...CallOption) error
 SEC("uprobe/ClientConn_Invoke")
 int uprobe_ClientConn_Invoke(struct pt_regs *ctx) {
-    // bpf_printk("enter the uprobe_ClientConn_Invoke \n");
+    // cw_bpf_debug("enter the uprobe_ClientConn_Invoke \n");
     // positions
     u64 clientconn_pos = 1;
     u64 method_ptr_pos = 4;
@@ -110,10 +110,10 @@ int uprobe_ClientConn_Invoke(struct pt_regs *ctx) {
 
     // Get key
     void *key = (void *)GOROUTINE(ctx);
-    // bpf_printk("enter the uprobe_ClientConn_Invoke key is 0x%llx\n", (u64)key);
+    // cw_bpf_debug("enter the uprobe_ClientConn_Invoke key is 0x%llx\n", (u64)key);
     void *grpcReq_ptr = bpf_map_lookup_elem(&grpc_client_events, &key);
     if (grpcReq_ptr != NULL) {
-        bpf_printk("uprobe/ClientConn_Invoke already tracked with the current context");
+        cw_bpf_debug("uprobe/ClientConn_Invoke already tracked with the current context");
         return 0;
     }
 
@@ -121,7 +121,7 @@ int uprobe_ClientConn_Invoke(struct pt_regs *ctx) {
     u32 zero = 0;
     struct grpc_client_request_t *grpcReq = bpf_map_lookup_elem(&grpc_client_storage_map, &zero);
     if (grpcReq == NULL) {
-        bpf_printk("grpc:client:ClientConn_Invoke: failed to get storage");
+        cw_bpf_debug("grpc:client:ClientConn_Invoke: failed to get storage");
         return -1;
     }
     
@@ -142,7 +142,7 @@ int uprobe_ClientConn_Invoke(struct pt_regs *ctx) {
     if (!get_go_string_from_user_ptr((void *)(clientconn_ptr + clientconn_target_ptr_pos),
                                      grpcReq->target,
                                      sizeof(grpcReq->target))) {
-        bpf_printk("target write failed, aborting ebpf probe");
+        cw_bpf_debug("target write failed, aborting ebpf probe");
         return 0;
     }
 
@@ -155,7 +155,7 @@ int uprobe_ClientConn_Invoke(struct pt_regs *ctx) {
         cw_save_parent_tracking_span(cw_psc);
 	}
 
-    // bpf_printk("grpcReq->target is %s\n", grpcReq->target);
+    // cw_bpf_debug("grpcReq->target is %s\n", grpcReq->target);
 
     // start_span_params_t start_span_params = {
     //     .ctx = ctx,
@@ -170,7 +170,7 @@ int uprobe_ClientConn_Invoke(struct pt_regs *ctx) {
     // Write event
     bpf_map_update_elem(&grpc_client_events, &key, grpcReq, 0);
     start_tracking_span(context_ptr_val, &grpcReq->sc);
-    // bpf_printk("enter the uprobe_ClientConn_Invoke start_tracking_span\n");
+    // cw_bpf_debug("enter the uprobe_ClientConn_Invoke start_tracking_span\n");
     return 0;
 }
 
@@ -178,11 +178,11 @@ int uprobe_ClientConn_Invoke(struct pt_regs *ctx) {
 // func (cc *ClientConn) Invoke(ctx context.Context, method string, args, reply interface{}, opts ...CallOption) error
 SEC("uprobe/ClientConn_Invoke")
 int uprobe_ClientConn_Invoke_Returns(struct pt_regs *ctx) {
-    // bpf_printk("enter the uprobe_ClientConn_Invoke_Returns \n");
+    // cw_bpf_debug("enter the uprobe_ClientConn_Invoke_Returns \n");
     void *key = (void *)GOROUTINE(ctx);
     struct grpc_client_request_t *grpc_span = bpf_map_lookup_elem(&grpc_client_events, &key);
     if (grpc_span == NULL) {
-        bpf_printk("event is NULL in ret probe");
+        cw_bpf_debug("event is NULL in ret probe");
         return 0;
     }
 
@@ -224,7 +224,7 @@ int uprobe_ClientConn_Invoke_Returns(struct pt_regs *ctx) {
         (void *)(s_ptr + status_message_pos), grpc_span->err_msg, sizeof(grpc_span->err_msg));
 
 done:
-    // bpf_printk("switch to the done position\n");
+    // cw_bpf_debug("switch to the done position\n");
     grpc_span->end_time = bpf_ktime_get_ns();
     // output_span_event(ctx, grpc_span, sizeof(*grpc_span), &grpc_span->sc);
     stop_tracking_span(&grpc_span->sc, &grpc_span->psc);
@@ -245,7 +245,7 @@ done:
     struct apm_trace_info_t * trace_info = get_apm_trace_info_by_trace_key(trace_key);
 
     if (trace_info == NULL) {
-        bpf_printk("enter the trace_info is NULL\n");
+        cw_bpf_debug("enter the trace_info is NULL\n");
         trace_info = get_apm_trace_info_v3(trace_key,pid_tgid, pid, pid_tgid);
     }
     
@@ -265,12 +265,12 @@ done:
     e->statement_id = 0;
     e->payload_size = grpc_span->method_size;
     if (trace_info) {
-        // bpf_printk("trace_info->trace_id is %llu\n", trace_info->trace_id);
+        // cw_bpf_debug("trace_info->trace_id is %llu\n", trace_info->trace_id);
         e->trace_id = trace_info->trace_id;
     }
     if(e->trace_id == 0){
         e->trace_id = get_apm_trace_id(pid,pid_tgid);
-        bpf_printk("e->trace_id is %llu\n", e->trace_id);
+        cw_bpf_debug("e->trace_id is %llu\n", e->trace_id);
     }
     // 使用固定长度读取 target 信息,避免验证器复杂性
     if (grpc_span->target_size > 0) {
@@ -283,10 +283,10 @@ done:
     }
     COPY_PAYLOAD(e->payload, grpc_span->method_size, grpc_span->method);
 
-    // bpf_printk("e->payload is %s\n", e->payload);
-    // bpf_printk("grpc_span->target is %s\n", grpc_span->target);
+    // cw_bpf_debug("e->payload is %s\n", e->payload);
+    // cw_bpf_debug("grpc_span->target is %s\n", grpc_span->target);
     // COPY_PAYLOAD(e->payload + grpc_span->method_size, grpc_span->target_size, grpc_span->target);
-    // bpf_printk("e->payload is %s\n", e->payload);
+    // cw_bpf_debug("e->payload is %s\n", e->payload);
     // e->payload_size += grpc_span->target_size;
     
     struct  apm_span_context * sc = cw_get_current_tracking_span(trace_info);
@@ -298,14 +298,14 @@ done:
     e->end_at = bpf_ktime_get_ns();
     e->start_at = grpc_span->start_time;
     e->duration = e->end_at - e->start_at;
-    // bpf_printk("send_event trace_id is444 %llu\n", e->trace_id);
+    // cw_bpf_debug("send_event trace_id is444 %llu\n", e->trace_id);
     long error = bpf_perf_event_output(ctx, &l7_events, BPF_F_CURRENT_CPU, e, sizeof(*e));
 	if (error ==0){
 	    cw_add_event_count(e->trace_id);
 	}
 
 
-    // bpf_printk("enter the uprobe_ClientConn_Invoke_Returns done\n");
+    // cw_bpf_debug("enter the uprobe_ClientConn_Invoke_Returns done\n");
     return 0;
 }
 
@@ -316,19 +316,19 @@ cw_append_item_to_slice(void *new_item, u32 item_size, void *slice_user_ptr) {
     struct go_slice_ot slice = {0};
     long res = bpf_probe_read_user(&slice, sizeof(slice), slice_user_ptr);
     if (res != 0) {
-        bpf_printk("cw_append_item_to_slice: failed to read slice descriptor, res=%ld\n", res);
+        cw_bpf_debug("cw_append_item_to_slice: failed to read slice descriptor, res=%ld\n", res);
         return;
     }
 
-    // bpf_printk("cw_append_item_to_slice len is %d\n", slice.len);
-    // bpf_printk("cw_append_item_to_slice cap is %d\n", slice.cap);
-    // bpf_printk("cw_append_item_to_slice array is %p\n", slice.array);
+    // cw_bpf_debug("cw_append_item_to_slice len is %d\n", slice.len);
+    // cw_bpf_debug("cw_append_item_to_slice cap is %d\n", slice.cap);
+    // cw_bpf_debug("cw_append_item_to_slice array is %p\n", slice.array);
 
     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
-        // bpf_printk("enter the cw_append_item_to_slice11111\n");
+        // cw_bpf_debug("enter the cw_append_item_to_slice11111\n");
         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)
@@ -354,7 +354,7 @@ cw_append_item_to_slice(void *new_item, u32 item_size, void *slice_user_ptr) {
         // 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",
+            // cw_bpf_debug("append_item_to_slice: copying %d bytes to new array from address 0x%llx",
                     //    alloc_size,
                     //    slice.array);
         }
@@ -365,7 +365,7 @@ cw_append_item_to_slice(void *new_item, u32 item_size, void *slice_user_ptr) {
 
         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");
+            cw_bpf_debug("append_item_to_slice: failed to copy new array to userspace");
             return;
         }
 
@@ -373,15 +373,15 @@ cw_append_item_to_slice(void *new_item, u32 item_size, void *slice_user_ptr) {
         slice.array = new_array;
         slice.cap++;
 
-        // bpf_printk("enter the cw_append_item_to_slice222222\n");
+        // cw_bpf_debug("enter the cw_append_item_to_slice222222\n");
     }
 
     // Update len
     slice.len++;
-    // bpf_printk("after cw_append_item_to_slice len is %d\n", slice.len);
+    // cw_bpf_debug("after cw_append_item_to_slice len is %d\n", 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");
+        cw_bpf_debug("append_item_to_slice: failed to update slice in userspace");
         return;
     }
 }
@@ -389,7 +389,7 @@ cw_append_item_to_slice(void *new_item, u32 item_size, void *slice_user_ptr) {
 SEC("uprobe/loopyWriter_headerHandler")
 int uprobe_LoopyWriter_HeaderHandler(struct pt_regs *ctx) {
     void *headerFrame_ptr = get_argument(ctx, 2);
-    // bpf_printk("enter the get header handler storage\n");
+    // cw_bpf_debug("enter the get header handler storage\n");
 
     __u64 pid_tgid = bpf_get_current_pid_tgid();
 	__u32 tgid = pid_tgid >> 32;
@@ -414,7 +414,7 @@ int uprobe_LoopyWriter_HeaderHandler(struct pt_regs *ctx) {
     struct header_handler_storage *storage = bpf_map_lookup_elem(&header_handler_storage_map, &zero);
     if (!storage) {
         bpf_map_delete_elem(&streamid_to_span_contexts, &stream_id);
-        bpf_printk("Failed to get header handler storage\n");
+        cw_bpf_debug("Failed to get header handler storage\n");
         return 0;
     }
     
@@ -435,7 +435,7 @@ int uprobe_LoopyWriter_HeaderHandler(struct pt_regs *ctx) {
     __builtin_memset(grpcClientReq, 0, sizeof(struct grpc_client_request_t));
     grpcClientReq->start_time = bpf_ktime_get_ns();
 
-    // bpf_printk("enter the uprobe_LoopyWriter_HeaderHandler444444\n");
+    // cw_bpf_debug("enter the uprobe_LoopyWriter_HeaderHandler444444\n");
 	// struct apm_span_context *cw_psc = cw_get_parent_tracking_span();
     struct apm_span_context *cw_psc = cw_get_parent_tracking_span_by_trace_key(*sc_ptr);
 	if(cw_psc){
@@ -453,7 +453,7 @@ int uprobe_LoopyWriter_HeaderHandler(struct pt_regs *ctx) {
 
     copy_byte_arrays(proc_info->instance_id, grpcClientReq->apm_sc.instance_id, APM_APP_ID_SIZE);
 	copy_byte_arrays(proc_info->app_id, grpcClientReq->apm_sc.app_id, APM_APP_ID_SIZE);
-    // bpf_printk("grpcClientReq->apm_sc.app_id is %s\n", grpcClientReq->apm_sc.app_id);
+    // cw_bpf_debug("grpcClientReq->apm_sc.app_id is %s\n", grpcClientReq->apm_sc.app_id);
 
     bpf_map_update_elem(&apm_current_span_context_map, sc_ptr, &grpcClientReq->apm_sc, BPF_ANY);
 	// cw_save_current_tracking_span(&grpcClientReq->apm_sc);
@@ -464,7 +464,7 @@ int uprobe_LoopyWriter_HeaderHandler(struct pt_regs *ctx) {
     char tp_key[CW_HEADER_KEY_LENGTH] = CW_HEADER_KEY_VAL;
     char *key_data_addr = cw_write_target_data((void *)tp_key, sizeof(tp_key), proc_info);
     if (key_data_addr == NULL) {
-        bpf_printk("Key data write failed\n");
+        cw_bpf_debug("Key data write failed\n");
         return 0;
     }
     
@@ -476,7 +476,7 @@ int uprobe_LoopyWriter_HeaderHandler(struct pt_regs *ctx) {
     // Write value using cw_write_target_data (it will automatically allocate next available position)
     char *val_data_addr = cw_write_target_data((void *)val, sizeof(val), proc_info);
     if (val_data_addr == NULL) {
-        bpf_printk("Val data write failed\n");
+        cw_bpf_debug("Val data write failed\n");
         return 0;
     }
     
@@ -498,14 +498,14 @@ int uprobe_LoopyWriter_HeaderHandler(struct pt_regs *ctx) {
 SEC("uprobe/http2Client_NewStream")
 // func (t *http2Client) NewStream(ctx context.Context, callHdr *CallHdr) (*Stream, error)
 int uprobe_http2Client_NewStream(struct pt_regs *ctx) {
-    // bpf_printk("enter the uprobe_http2Client_NewStream \n");
+    // cw_bpf_debug("enter the uprobe_http2Client_NewStream \n");
     __u32 tgid = (__u32)(bpf_get_current_pid_tgid() >> 32);
 	struct ebpf_proc_info *info =
 		bpf_map_lookup_elem(&proc_info_map, &tgid);
 	if (!info) {
 		return -1;
 	}
-    // bpf_printk("info->httpclient_nextid_pos is %d\n", info->httpclient_nextid_pos);
+    // cw_bpf_debug("info->httpclient_nextid_pos is %d\n", info->httpclient_nextid_pos);
 
     struct go_iface go_context = {0};
     get_Go_context(ctx, 2, 0, true);

+ 49 - 49
ebpftracer/ebpf/utrace/go/net/grpc.server.probe.bpf.c

@@ -103,19 +103,19 @@ handleStream(struct pt_regs *ctx, void *stream_ptr, struct go_iface *go_context)
 		return -1;
 	}
     if (go_context == NULL) {
-        bpf_printk("grpc:server:handleStream: NULL go_context");
+        cw_bpf_debug("grpc:server:handleStream: NULL go_context");
         return -1;
     }
-    // bpf_printk("info->stream_method_ptr_pos is %d\n", info->stream_method_ptr_pos);
+    // cw_bpf_debug("info->stream_method_ptr_pos is %d\n", info->stream_method_ptr_pos);
     if (stream_ptr == NULL) {
-        bpf_printk("grpc:server:handleStream: NULL stream_ptr");
+        cw_bpf_debug("grpc:server:handleStream: NULL stream_ptr");
         return -1;
     }
 
     void *key = (void *)GOROUTINE(ctx);
     void *grpcReq_event_ptr = bpf_map_lookup_elem(&grpc_events, &key);
     if (grpcReq_event_ptr != NULL) {
-        bpf_printk("grpc:server:handleStream: event already tracked");
+        cw_bpf_debug("grpc:server:handleStream: event already tracked");
         return 0;
     }
 
@@ -125,7 +125,7 @@ handleStream(struct pt_regs *ctx, void *stream_ptr, struct go_iface *go_context)
     long rc =
         bpf_probe_read_user(&stream_id, sizeof(stream_id), (void *)(stream_ptr + stream_id_pos));
     if (rc != 0) {
-        bpf_printk("grpc:server:handleStream: failed to read stream ID");
+        cw_bpf_debug("grpc:server:handleStream: failed to read stream ID");
         return -2;
     }
 
@@ -135,7 +135,7 @@ handleStream(struct pt_regs *ctx, void *stream_ptr, struct go_iface *go_context)
         u32 zero = 0;
         grpcReq = bpf_map_lookup_elem(&grpc_storage_map, &zero);
         if (grpcReq == NULL) {
-            bpf_printk("grpc:server:handleStream: failed to get grpcReq");
+            cw_bpf_debug("grpc:server:handleStream: failed to get grpcReq");
             return 0;
         }
     }
@@ -159,12 +159,12 @@ handleStream(struct pt_regs *ctx, void *stream_ptr, struct go_iface *go_context)
     bool parsed_method =
         get_go_string_from_user_ptr(method_ptr, grpcReq->method, sizeof(grpcReq->method));
     if (!parsed_method) {
-        bpf_printk("grpc:server:handleStream: failed to read gRPC method from stream");
+        cw_bpf_debug("grpc:server:handleStream: failed to read gRPC method from stream");
         bpf_map_delete_elem(&streamid_to_grpc_events, &stream_id);
         return -3;
     }
 
-    // bpf_printk("grpc:server:handleStream: get the method is %s\n", grpcReq->method);
+    // cw_bpf_debug("grpc:server:handleStream: get the method is %s\n", grpcReq->method);
 
     // if (server_addr_supported) {
     //     void *http2server = get_argument(ctx, 3);
@@ -175,14 +175,14 @@ handleStream(struct pt_regs *ctx, void *stream_ptr, struct go_iface *go_context)
     //             &local_addr_ptr, sizeof(local_addr_ptr), get_go_interface_instance(local_addr_pos));
     //         get_tcp_net_addr_from_tcp_addr(ctx, &grpcReq->local_addr, (void *)(local_addr_ptr));
     //     } else {
-    //         bpf_printk("grpc:server:handleStream: failed to get http2server arg");
+    //         cw_bpf_debug("grpc:server:handleStream: failed to get http2server arg");
     //     }
     // }
 
     // Write event
     rc = bpf_map_update_elem(&grpc_events, &key, grpcReq, 0);
     if (rc != 0) {
-        bpf_printk("grpc:server:handleStream: failed to update event");
+        cw_bpf_debug("grpc:server:handleStream: failed to update event");
         return -4;
     }
     start_tracking_span(go_context->data, &grpcReq->sc);
@@ -197,7 +197,7 @@ handleStream(struct pt_regs *ctx, void *stream_ptr, struct go_iface *go_context)
         return 0;
     }
 
-    // bpf_printk("start get apm data\n");
+    // cw_bpf_debug("start get apm data\n");
 
 
     // struct apm_span_context *cw_parent_span_context = bpf_map_lookup_elem(&apm_span_context_heap3, &zero);
@@ -227,7 +227,7 @@ handleStream(struct pt_regs *ctx, void *stream_ptr, struct go_iface *go_context)
     
     // 拷贝 grpcReq->method 到 payload 并设置 payload_size
     // 手动计算字符串长度(在 eBPF 中不能使用 strlen)
-    u32 method_len = 0;
+    u64 method_len = 0;
     for (int i = 0; i < MAX_SIZE; i++) {
         if (grpcReq->method[i] == '\0') {
             method_len = i;
@@ -243,7 +243,7 @@ handleStream(struct pt_regs *ctx, void *stream_ptr, struct go_iface *go_context)
     e->payload_size = method_len;
     COPY_PAYLOAD(e->payload, method_len, grpcReq->method);
 
-    // bpf_printk("grpc:server:handleStream: get the payload size is %d\n", e->payload_size);
+    // cw_bpf_debug("grpc:server:handleStream: get the payload size is %d\n", e->payload_size);
 
     struct apm_trace_info_t trace_info = cw_save_trace_info(id,pid, k.fd);
     
@@ -269,7 +269,7 @@ handleStream(struct pt_regs *ctx, void *stream_ptr, struct go_iface *go_context)
 // Returns 0 on success, otherwise a negative error value in case of failure.
 // static __always_inline int writeStatus(struct pt_regs *ctx, void *status_ptr) {
 //     if (status_ptr == NULL) {
-//         bpf_printk("grpc:server:writeStatus: NULL status_ptr");
+//         cw_bpf_debug("grpc:server:writeStatus: NULL status_ptr");
 //         return -1;
 //     }
 
@@ -277,14 +277,14 @@ handleStream(struct pt_regs *ctx, void *stream_ptr, struct go_iface *go_context)
 
 //     struct grpc_request_t *req_ptr = bpf_map_lookup_elem(&grpc_events, &key);
 //     if (req_ptr == NULL) {
-//         bpf_printk("grpc:server:handleStream: failed to lookup grpc request");
+//         cw_bpf_debug("grpc:server:handleStream: failed to lookup grpc request");
 //         return -2;
 //     }
 
 //     void *s_ptr = 0;
 //     long rc = bpf_probe_read_user(&s_ptr, sizeof(s_ptr), (void *)(status_ptr + status_s_pos));
 //     if (rc != 0) {
-//         bpf_printk("grpc:server:handleStream: failed to read Status.s");
+//         cw_bpf_debug("grpc:server:handleStream: failed to read Status.s");
 //         return -3;
 //     }
 
@@ -292,7 +292,7 @@ handleStream(struct pt_regs *ctx, void *stream_ptr, struct go_iface *go_context)
 //     rc = bpf_probe_read_user(
 //         &req_ptr->status_code, sizeof(req_ptr->status_code), (void *)(s_ptr + status_code_pos));
 //     if (rc != 0) {
-//         bpf_printk("grpc:server:handleStream: failed to read status code");
+//         cw_bpf_debug("grpc:server:handleStream: failed to read status code");
 //         return -4;
 //     }
 //     req_ptr->has_status = true;
@@ -306,10 +306,10 @@ handleStream(struct pt_regs *ctx, void *stream_ptr, struct go_iface *go_context)
 // This is only compatible with versions < 1.69.0 of the Server.
 SEC("uprobe/server_handleStream")
 int uprobe_server_handleStream(struct pt_regs *ctx) {
-    // bpf_printk("enter the uprobe_server_handleStream");
+    // cw_bpf_debug("enter the uprobe_server_handleStream");
     u64 stream_pos = 4;
     void *stream_ptr = get_argument(ctx, stream_pos);
-    // bpf_printk("enter uprobe_server_handleStream\n");
+    // cw_bpf_debug("enter uprobe_server_handleStream\n");
     // Get key
     __u64 pid_tgid = bpf_get_current_pid_tgid();
 	__u32 tgid = pid_tgid >> 32;
@@ -317,7 +317,7 @@ int uprobe_server_handleStream(struct pt_regs *ctx) {
 			bpf_map_lookup_elem(&proc_info_map, &tgid);
     if(!proc_info)
     {
-	    bpf_printk("[uprobe_HandlerFunc_ServeHTTP] no proc info");
+	    cw_bpf_debug("[uprobe_HandlerFunc_ServeHTTP] no proc info");
         return 0;
     }
     struct go_iface go_context = {0};
@@ -329,7 +329,7 @@ int uprobe_server_handleStream(struct pt_regs *ctx) {
 // UPROBE_RETURN(server_handleStream, struct grpc_request_t, grpc_events) 
 SEC("uprobe/server_handleStream")
 int uprobe_server_handleStream_Returns(struct pt_regs *ctx) {  
-    // bpf_printk("enter the uprobe_server_handleStream return");     
+    // cw_bpf_debug("enter the uprobe_server_handleStream return");     
     void *key = (void *)GOROUTINE(ctx);
     __u64 id = bpf_get_current_pid_tgid();
 	__u32 zero = 0;
@@ -339,7 +339,7 @@ int uprobe_server_handleStream_Returns(struct pt_regs *ctx) {
 
 	pid = id >> 32;
 	tid =  (__u32)id;
-    // bpf_printk("enter uprobe_server_handleStream_Returns\n");
+    // cw_bpf_debug("enter uprobe_server_handleStream_Returns\n");
 
     struct l7_request_key k = {};
     k.pid = pid;
@@ -348,7 +348,7 @@ int uprobe_server_handleStream_Returns(struct pt_regs *ctx) {
     k.stream_id = -1;    
     struct grpc_request_t *event = bpf_map_lookup_elem(&grpc_events, &key);
     if (event == NULL) {
-        bpf_printk("grpc:server:uprobe/server_handleStream2Return: event is NULL");
+        cw_bpf_debug("grpc:server:uprobe/server_handleStream2Return: event is NULL");
         return -5;
     }
     event->end_time = bpf_ktime_get_ns();
@@ -429,7 +429,7 @@ int uprobe_server_handleStream_Returns(struct pt_regs *ctx) {
     //不发送payload
     bpf_perf_event_output(ctx, &l7_events, BPF_F_CURRENT_CPU, e, sizeof(*e));
 
-    // bpf_printk("stop get apm data\n");
+    // cw_bpf_debug("stop get apm data\n");
     return 0;                                                                                  
 }
 
@@ -447,12 +447,12 @@ int uprobe_server_handleStream2(struct pt_regs *ctx) {
 	if (!info) {
 		return -1;
 	}
-    bpf_printk("info->stream_ctx_pos is %d\n", info->stream_ctx_pos);
+    cw_bpf_debug("info->stream_ctx_pos is %d\n", info->stream_ctx_pos);
     u64 server_stream_pos = 4;
-    // bpf_printk("enter uprobe_server_handleStream2\n");
+    // cw_bpf_debug("enter uprobe_server_handleStream2\n");
     void *server_stream_ptr = get_argument(ctx, server_stream_pos);
     if (server_stream_ptr == NULL) {
-        bpf_printk("grpc:server:uprobe/server_handleStream2: failed to get ServerStream arg");
+        cw_bpf_debug("grpc:server:uprobe/server_handleStream2: failed to get ServerStream arg");
         return -1;
     }
 
@@ -460,7 +460,7 @@ int uprobe_server_handleStream2(struct pt_regs *ctx) {
     long rc = bpf_probe_read_user(
         &stream_ptr, sizeof(stream_ptr), (void *)(server_stream_ptr + server_stream_stream_pos));
     if (rc != 0) {
-        bpf_printk("grpc:server:uprobe/server_handleStream2: failed to read stream_ptr");
+        cw_bpf_debug("grpc:server:uprobe/server_handleStream2: failed to read stream_ptr");
         return -2;
     }
 
@@ -468,7 +468,7 @@ int uprobe_server_handleStream2(struct pt_regs *ctx) {
     rc = bpf_probe_read_user(
         &go_context.type, sizeof(go_context.type), (void *)(stream_ptr + info->stream_ctx_pos));
     if (rc != 0) {
-        bpf_printk("grpc:server:uprobe/server_handleStream2: failed to read context type");
+        cw_bpf_debug("grpc:server:uprobe/server_handleStream2: failed to read context type");
         return -3;
     }
 
@@ -476,7 +476,7 @@ int uprobe_server_handleStream2(struct pt_regs *ctx) {
                              sizeof(go_context.data),
                              get_go_interface_instance(stream_ptr + info->stream_ctx_pos));
     if (rc != 0) {
-        bpf_printk("grpc:server:uprobe/server_handleStream2: failed to read context data");
+        cw_bpf_debug("grpc:server:uprobe/server_handleStream2: failed to read context data");
         return -4;
     }
 
@@ -503,7 +503,7 @@ int uprobe_server_handleStream2_Returns(struct pt_regs *ctx) {
     long rc = bpf_probe_read_user(
         &stream_ptr, sizeof(stream_ptr), (void *)(server_stream_ptr + server_stream_stream_pos));
     if (rc != 0) {
-        bpf_printk("grpc:server:uprobe/server_handleStream2Return: failed to read stream_ptr");
+        cw_bpf_debug("grpc:server:uprobe/server_handleStream2Return: failed to read stream_ptr");
         return -2;
     }
 
@@ -511,7 +511,7 @@ lookup:
     key = (void *)GOROUTINE(ctx);
     struct grpc_request_t *event = bpf_map_lookup_elem(&grpc_events, &key);
     if (event == NULL) {
-        bpf_printk("grpc:server:uprobe/server_handleStream2Return: event is NULL");
+        cw_bpf_debug("grpc:server:uprobe/server_handleStream2Return: event is NULL");
         return -5;
     }
     event->end_time = bpf_ktime_get_ns();
@@ -527,7 +527,7 @@ lookup:
 
 	pid = id >> 32;
 	tid =  (__u32)id;
-    // bpf_printk("enter uprobe_server_handleStream_Returns\n");
+    // cw_bpf_debug("enter uprobe_server_handleStream_Returns\n");
 
     struct l7_request_key k = {};
     k.pid = pid;
@@ -608,7 +608,7 @@ lookup:
     //不发送payload
     bpf_perf_event_output(ctx, &l7_events, BPF_F_CURRENT_CPU, e, sizeof(*e));
 
-    // bpf_printk("stop get apm data\n");
+    // cw_bpf_debug("stop get apm data\n");
     return 0;
 }
 
@@ -617,7 +617,7 @@ lookup:
 // func (t *http2Server) operateHeaders(ctx context.Context, frame *http2.MetaHeadersFrame, handle func(*Stream)) error
 SEC("uprobe/http2Server_operateHeader")
 int uprobe_http2Server_operateHeader(struct pt_regs *ctx) {
-    // bpf_printk("enter the uprobe_http2Server_operateHeader");
+    // cw_bpf_debug("enter the uprobe_http2Server_operateHeader");
     __u32 tgid = (__u32)(bpf_get_current_pid_tgid() >> 32);
 	struct ebpf_proc_info *info =
 		bpf_map_lookup_elem(&proc_info_map, &tgid);
@@ -633,7 +633,7 @@ int uprobe_http2Server_operateHeader(struct pt_regs *ctx) {
     char key[CW_HEADER_KEY_LENGTH + 1] = "cwtrace";
     // 确保字符串以 null 结尾
     key[CW_HEADER_KEY_LENGTH] = '\0';
-    // bpf_printk("enter the uprobe_http2Server_operateHeader\n");
+    // cw_bpf_debug("enter the uprobe_http2Server_operateHeader\n");
     
     __u32 zero = 0;
     struct apm_span_context *cw_parent_span_context = bpf_map_lookup_elem(&apm_span_context_heap3, &zero);
@@ -654,35 +654,35 @@ int uprobe_http2Server_operateHeader(struct pt_regs *ctx) {
         if (hf.name.len != CW_HEADER_KEY_LENGTH || hf.value.len != CW_HEADER_VAL_LENGTH) {
             continue;
         }
-        // bpf_printk("found traceparent header name is %s", hf.name.str);
-        // bpf_printk("found traceparent header value is %s", hf.value.str);
+        // cw_bpf_debug("found traceparent header name is %s", hf.name.str);
+        // cw_bpf_debug("found traceparent header value is %s", hf.value.str);
         
         char current_key[CW_HEADER_KEY_LENGTH + 1];
         if (bpf_probe_read(current_key, sizeof(current_key), hf.name.str) != 0) {
             continue;
         }
-        // bpf_printk("---found traceparent header name is %s", hf.name.str);
-        // bpf_printk("+++found traceparent header value is %s", hf.value.str);
+        // cw_bpf_debug("---found traceparent header name is %s", hf.name.str);
+        // cw_bpf_debug("+++found traceparent header value is %s", hf.value.str);
 
         current_key[CW_HEADER_KEY_LENGTH] = '\0';
 
-        // bpf_printk("---11111found cwtrace key is %s", key);
-        // bpf_printk("+++11111found cwtrace current_key is %s", current_key);
+        // cw_bpf_debug("---11111found cwtrace key is %s", key);
+        // cw_bpf_debug("+++11111found cwtrace current_key is %s", current_key);
         // 简化字符串比较
         // if (bpf_memcmp(key, current_key, 6) == 0) {
         if (current_key[0] == 'c' && current_key[1] == 'w' && current_key[2] == 't' && current_key[3] == 'r' && current_key[4] == 'a' && current_key[5] == 'c' && current_key[6] == 'e') {
             find_w3c = 1;
-            // bpf_printk("found traceparent header");
+            // cw_bpf_debug("found traceparent header");
             // 执行字符串到span context的转换
             cw_string_to_span_context(hf.value.str, cw_parent_span_context);
-            // bpf_printk("11111found traceparent header value is %s", hf.value.str);
+            // cw_bpf_debug("11111found traceparent header value is %s", hf.value.str);
             break; // 找到后立即退出
         }
     }
     if (find_w3c == 0)
     {
         generate_random_bytes(cw_parent_span_context->trace_id, TRACE_ID_SIZE);
-        bpf_printk("enter uprobe_http2Server_operateHeader, generate the traceid\n");
+        cw_bpf_debug("enter uprobe_http2Server_operateHeader, generate the traceid\n");
     }
     cw_save_parent_tracking_span(cw_parent_span_context);
     return 0;
@@ -694,7 +694,7 @@ int uprobe_http2Server_operateHeader(struct pt_regs *ctx) {
 // This is only compatible with versions > 1.40 and < 1.69.0 of the Server.
 // SEC("uprobe/http2Server_WriteStatus")
 // int uprobe_http2Server_WriteStatus(struct pt_regs *ctx) {
-//     // bpf_printk("enter uprobe_http2Server_WriteStatus\n");
+//     // cw_bpf_debug("enter uprobe_http2Server_WriteStatus\n");
 //     void *status_ptr = get_argument(ctx, 3);
 //     return writeStatus(ctx, status_ptr);
 // }
@@ -705,11 +705,11 @@ int uprobe_http2Server_operateHeader(struct pt_regs *ctx) {
 // // This is only compatible with versions > 1.69.0 of the Server.
 // SEC("uprobe/http2Server_WriteStatus2")
 // int uprobe_http2Server_WriteStatus2(struct pt_regs *ctx) {
-//     // bpf_printk("enter uprobe_http2Server_WriteStatus2\n");
+//     // cw_bpf_debug("enter uprobe_http2Server_WriteStatus2\n");
 //     u64 server_stream_pos = 2;
 //     void *server_stream_ptr = get_argument(ctx, server_stream_pos);
 //     if (server_stream_ptr == NULL) {
-//         bpf_printk("grpc:server:uprobe/http2Server_WriteStatus2: failed to get ServerStream arg");
+//         cw_bpf_debug("grpc:server:uprobe/http2Server_WriteStatus2: failed to get ServerStream arg");
 //         return -1;
 //     }
 
@@ -717,7 +717,7 @@ int uprobe_http2Server_operateHeader(struct pt_regs *ctx) {
 //     long rc = bpf_probe_read_user(
 //         &stream_ptr, sizeof(stream_ptr), (void *)(server_stream_ptr + server_stream_stream_pos));
 //     if (rc != 0) {
-//         bpf_printk("grpc:server:uprobe/http2Server_WriteStatus2: failed to read stream_ptr");
+//         cw_bpf_debug("grpc:server:uprobe/http2Server_WriteStatus2: failed to read stream_ptr");
 //         return -2;
 //     }
 

+ 55 - 5
ebpftracer/ebpf/utrace/go/net/server.probe.bpf.c

@@ -103,6 +103,12 @@ struct {
 	__uint(max_entries, 8);
 } header_keys_map SEC(".maps");
 
+struct {
+	__uint(type, BPF_MAP_TYPE_LRU_HASH);
+	__uint(key_size, sizeof(u64));
+	__uint(value_size, sizeof(char [CW_HEADER_VAL_LENGTH]));
+	__uint(max_entries, MAX_CONCURRENT);
+} http_server_context_headers SEC(".maps");
 
 // Injected in init
 // volatile const u64 ctx_ptr_pos;
@@ -118,7 +124,7 @@ struct {
 //}
 //}
 
-static __always_inline struct span_context *extract_context_from_req_headers(void *headers_ptr_ptr) {
+static __always_inline struct span_context *extract_context_from_req_headers_del(void *headers_ptr_ptr) {
 	void *headers_ptr;
 	long res;
 	res = bpf_probe_read(&headers_ptr, sizeof(headers_ptr), headers_ptr_ptr);
@@ -312,6 +318,17 @@ static __always_inline struct map_bucket *get_map_bucket(void *headers_ptr_ptr)
 
 MAP_BUCKET_DEFINITION(go_string_ot,  go_slice_ot)
 
+static __always_inline char *
+extract_context_from_req_headers_pre_parsed(void *key) {
+	char *header_val =
+			bpf_map_lookup_elem(&http_server_context_headers, &key);
+	if (!header_val) {
+		return NULL;
+	}
+
+	return header_val;
+}
+
 static __always_inline char *extract_context_from_req_headers_go_map(void *headers_ptr_ptr)
 {
 	void *headers_ptr;
@@ -415,6 +432,15 @@ static __always_inline char *extract_context_from_req_headers_go_map(void *heade
 	}
 	return NULL;
 }
+
+static __always_inline char *
+extract_context_from_req_headers(void *key, void *headers_ptr_ptr, __u64 use_swiss) {
+	if (use_swiss == 1) {
+		return extract_context_from_req_headers_pre_parsed(key);
+	}
+	return extract_context_from_req_headers_go_map(headers_ptr_ptr);
+}
+
 // 获取 header_val
 static __always_inline char *get_header_val(struct map_bucket *map_value,u32 off,u32 count) {
 	for (u32 i = off; i < count; i++) {
@@ -503,8 +529,10 @@ int uprobe_HandlerFunc_ServeHTTP(struct pt_regs *ctx) {
 	void *req_ptr = get_argument(ctx, 4);
 //	struct map_bucket * map_bucket_p = get_map_bucket((void *) (req_ptr + proc_info->headers_ptr_pos));
 
-	char *traceparent_header_value = extract_context_from_req_headers_go_map(
-			(void *) (req_ptr + proc_info->headers_ptr_pos));
+	char *traceparent_header_value = extract_context_from_req_headers(key,
+	                                                                  (void *) (req_ptr + proc_info->headers_ptr_pos),
+	                                                                  proc_info->use_swiss_map);
+
 //	bpf_printk("111 %s",traceparent_header_value);
 
 //	char * traceparent_header_value = get_header_val_off(map_bucket_p);
@@ -589,10 +617,11 @@ int uprobe_HandlerFunc_ServeHTTP_Returns(struct pt_regs *ctx) {
 	struct uprobe_data_t *uprobe_data = bpf_map_lookup_elem(&http_server_uprobes, &key);
 	if (uprobe_data == NULL) {
 		cw_bpf_debug("uprobe/HandlerFunc_ServeHTTP_Returns: entry_state is NULL");
+		bpf_map_delete_elem(&http_server_context_headers, &key);
 		return 0;
 	}
 	bpf_map_delete_elem(&http_server_uprobes, &key);
-
+	bpf_map_delete_elem(&http_server_context_headers, &key);
 	struct http_server_span_t *http_server_span = &uprobe_data->span;
 //	void *resp_ptr = (void *) uprobe_data->resp_ptr;
 //	void *req_ptr = NULL;
@@ -624,4 +653,25 @@ int uprobe_HandlerFunc_ServeHTTP_Returns(struct pt_regs *ctx) {
 	clear_parent_span_context();
 	cw_bpf_debug("HTTP_END");
 	return 0;
-}
+}
+
+// This instrumentation attaches uprobe to the following function:
+// func (r *Reader) readContinuedLineSlice(lim int64, validateFirstLine func([]byte) error) ([]byte, error) {
+SEC("uprobe/textproto_Reader_readContinuedLineSlice")
+int uprobe_textproto_Reader_readContinuedLineSlice_Returns(struct pt_regs *ctx) {
+	void *key = (void *) GOROUTINE(ctx);
+	u64 len = (u64) GO_PARAM2(ctx);
+	u8 *buf = (u8 *) GO_PARAM1(ctx);
+	if (len == (CW_HEADER_KEY_LENGTH + CW_HEADER_VAL_LENGTH + 2)) {
+		long cw_header_native = 0x3A65636172747763LL; // 小端序下的 "cwtrace:"
+		__u64 key64 = 0;
+		bpf_probe_read_user(&key64, sizeof(key64), buf);
+		if (key64 == cw_header_native) {
+			char header_val[CW_HEADER_VAL_LENGTH] = {};
+			bpf_probe_read_user(header_val, sizeof(header_val), buf + CW_HEADER_KEY_LENGTH + 2);
+			cw_bpf_debug("Swiss Map:%s", header_val);
+			bpf_map_update_elem(&http_server_context_headers, &key, &header_val, BPF_ANY);
+		}
+	}
+	return 0;
+}

+ 160 - 212
ebpftracer/tls.go

@@ -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"
@@ -23,20 +24,21 @@ import (
 )
 
 const (
-	minSupportedGoVersion = "v1.15.0"
-	goTlsWriteSymbol      = "crypto/tls.(*Conn).Write"
-	goTlsReadSymbol       = "crypto/tls.(*Conn).Read"
-	goExecute             = "runtime.execute"
-	goNewproc1            = "runtime.newproc1"
-	goRunqget             = "runtime.runqget"
-	goServeHTTP           = "net/http.serverHandler.ServeHTTP"
-	goTransport           = "net/http.(*Transport).roundTrip"
-	goGrpcServerHandleStream = "google.golang.org/grpc.(*Server).handleStream"
-	goGrpcHttp2OperateHeader = "google.golang.org/grpc/internal/transport.(*http2Server).operateHeaders"
-	goGrpcServerWritestatus = "google.golang.org/grpc/internal/transport.(*http2Server).WriteStatus"
-	goGrpcClientConnInvoke = "google.golang.org/grpc.(*ClientConn).Invoke"
+	minSupportedGoVersion          = "v1.15.0"
+	goTlsWriteSymbol               = "crypto/tls.(*Conn).Write"
+	goTlsReadSymbol                = "crypto/tls.(*Conn).Read"
+	goExecute                      = "runtime.execute"
+	goNewproc1                     = "runtime.newproc1"
+	goRunqget                      = "runtime.runqget"
+	goServeHTTP                    = "net/http.serverHandler.ServeHTTP"
+	goTransport                    = "net/http.(*Transport).roundTrip"
+	goGrpcServerHandleStream       = "google.golang.org/grpc.(*Server).handleStream"
+	goGrpcHttp2OperateHeader       = "google.golang.org/grpc/internal/transport.(*http2Server).operateHeaders"
+	goGrpcServerWritestatus        = "google.golang.org/grpc/internal/transport.(*http2Server).WriteStatus"
+	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"
+	goGrpcHttp2ClientNewStream     = "google.golang.org/grpc/internal/transport.(*http2Client).NewStream"
+	goReadContinuedLineSlice       = "net/textproto.(*Reader).readContinuedLineSlice"
 )
 
 var (
@@ -143,6 +145,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"} {
@@ -174,7 +178,7 @@ func (t *Tracer) AttachGoTlsUprobes(pid uint32, appInfo *AppInfo, codeType uint1
 		return nil, err
 	}
 	klog.Infof("[AttachGoTlsUprobes] STEP 4.2: Executable name=%s", name)
-	
+
 	version = strings.Replace(bi.GoVersion, "go", "v", 1)
 	klog.Infof("[AttachGoTlsUprobes] STEP 5: Checking version compatibility, version=%s, minSupported=%s", version, minSupportedGoVersion)
 	if semver.Compare(version, minSupportedGoVersion) < 0 {
@@ -239,27 +243,27 @@ func (t *Tracer) AttachGoTlsUprobes(pid uint32, appInfo *AppInfo, codeType uint1
 	for _, dep := range bi.Deps {
 		if strings.Contains(dep.Path, "grpc") {
 			klog.Infoln("Found gRPC dependency:", dep.Path, "version:", dep.Version)
-			
+
 			// 解析版本号
 			version := dep.Version
 			if version != "" {
 				// 移除可能的 "v" 前缀
 				version = strings.TrimPrefix(version, "v")
 				parts := strings.Split(version, ".")
-				
+
 				if len(parts) >= 2 {
 					major, err := strconv.Atoi(parts[0])
 					if err != nil {
 						klog.WithError(err).Warnf("Error parsing major version from %s", parts[0])
 						continue
 					}
-					
+
 					minor, err := strconv.Atoi(parts[1])
 					if err != nil {
 						klog.WithError(err).Warnf("Error parsing minor version from %s", parts[1])
 						continue
 					}
-					
+
 					klog.Infof("Detected gRPC version: %d.%d for PID %d", major, minor, pid)
 					grpcMajorVersion = major
 					grpcMinorVersion = minor
@@ -285,26 +289,26 @@ func (t *Tracer) AttachGoTlsUprobes(pid uint32, appInfo *AppInfo, codeType uint1
 
 	klog.Infof("[AttachGoTlsUprobes] STEP 12: Getting offset for runtime.hmap.buckets")
 	bucketsOff, ok2 := tracer.GetOffset(tracer.NewID("std", "runtime", "hmap", "buckets"), path)
-	
+
 	// 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
+			pkg        string
 			structName string
-			field  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)
@@ -317,7 +321,7 @@ func (t *Tracer) AttachGoTlsUprobes(pid uint32, appInfo *AppInfo, codeType uint1
 				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")
@@ -332,7 +336,7 @@ func (t *Tracer) AttachGoTlsUprobes(pid uint32, appInfo *AppInfo, codeType uint1
 				}
 			}
 		}
-		
+
 		if !ok2 {
 			klog.Errorf("[AttachGoTlsUprobes] STEP 12.7: All attempts failed, Go 1.24+ Swiss Tables map structure not found")
 			// 根据源码分析,maps.Map 结构体布局(64-bit):
@@ -343,13 +347,13 @@ func (t *Tracer) AttachGoTlsUprobes(pid uint32, appInfo *AppInfo, codeType uint1
 			// 注意:这需要确认目标系统是 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])
+				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 系统(大多数生产环境)
@@ -381,7 +385,6 @@ func (t *Tracer) AttachGoTlsUprobes(pid uint32, appInfo *AppInfo, codeType uint1
 		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 {
@@ -417,6 +420,9 @@ func (t *Tracer) AttachGoTlsUprobes(pid uint32, appInfo *AppInfo, codeType uint1
 			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] STEP 15.1: Using new frame position for gRPC >= 1.60")
@@ -431,20 +437,20 @@ func (t *Tracer) AttachGoTlsUprobes(pid uint32, appInfo *AppInfo, codeType uint1
 			} 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"),
-				&info.PathPtrPos:     tracer.NewID("std", "net/url", "URL", "Path"),
-				&info.StatusCodePos:  tracer.NewID("std", "net/http", "response", "status"),
-				&info.RequestHostPos: tracer.NewID("std", "net/http", "Request", "Host"),
-				&info.ProtoPos:       tracer.NewID("std", "net/http", "Request", "Proto"),
-				&info.CtxPtrPos:      tracer.NewID("std", "net/http", "Request", "ctx"),
-				&info.HeadersPtrPos:  tracer.NewID("std", "net/http", "Request", "Header"),
-				&info.HttpClientNextidPos: tracer.NewID("google.golang.org/grpc","google.golang.org/grpc/internal/transport","http2Client","nextID"),
-				&info.StreamMethodPtrPos: tracer.NewID("google.golang.org/grpc","google.golang.org/grpc/internal/transport","Stream","method"),
-				&info.StreamCtxPos: tracer.NewID("google.golang.org/grpc","google.golang.org/grpc/internal/transport","Stream","ctx"),
+				&info.MethodPtrPos:        tracer.NewID("std", "net/http", "Request", "Method"),
+				&info.UrlPtrPos:           tracer.NewID("std", "net/http", "Request", "URL"),
+				&info.PathPtrPos:          tracer.NewID("std", "net/url", "URL", "Path"),
+				&info.StatusCodePos:       tracer.NewID("std", "net/http", "response", "status"),
+				&info.RequestHostPos:      tracer.NewID("std", "net/http", "Request", "Host"),
+				&info.ProtoPos:            tracer.NewID("std", "net/http", "Request", "Proto"),
+				&info.CtxPtrPos:           tracer.NewID("std", "net/http", "Request", "ctx"),
+				&info.HeadersPtrPos:       tracer.NewID("std", "net/http", "Request", "Header"),
+				&info.HttpClientNextidPos: tracer.NewID("google.golang.org/grpc", "google.golang.org/grpc/internal/transport", "http2Client", "nextID"),
+				&info.StreamMethodPtrPos:  tracer.NewID("google.golang.org/grpc", "google.golang.org/grpc/internal/transport", "Stream", "method"),
+				&info.StreamCtxPos:        tracer.NewID("google.golang.org/grpc", "google.golang.org/grpc/internal/transport", "Stream", "ctx"),
 			}
 
 			successCount := 0
@@ -489,7 +495,7 @@ 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] STEP 18: Updating proc_info map")
 			_, err = tracer.UpdateProcInfoToMap(t.collection, pid, info)
 			if err != nil {
@@ -542,6 +548,7 @@ func (t *Tracer) AttachGoTlsUprobes(pid uint32, appInfo *AppInfo, codeType uint1
 		case goGrpcHttp2OperateHeader, goGrpcServerHandleStream, goGrpcServerWritestatus, goGrpcClientLoopyHeaderHandler, goGrpcHttp2ClientNewStream:
 			matchedSymbols++
 			klog.Infof("[AttachGoTlsUprobes] STEP 19.8: Matched gRPC symbol: %s (index=%d)", s.Name, i)
+		case goReadContinuedLineSlice:
 		default:
 			continue
 		}
@@ -562,52 +569,27 @@ func (t *Tracer) AttachGoTlsUprobes(pid uint32, appInfo *AppInfo, codeType uint1
 		switch s.Name {
 		case goExecute:
 			klog.Infof("[AttachGoTlsUprobes] STEP 20: Attaching uprobe for runtime.execute, address=0x%x", address)
-			l, err := exe.Uprobe(s.Name, t.uprobes["runtime_execute"], &link.UprobeOptions{Address: address})
+			l, err := attachUprobe(exe, s.Name, "runtime_execute", t.uprobes, address, "failed to attach write_enter uprobe", true)
 			if err != nil {
-				klog.Errorf("[AttachGoTlsUprobes] STEP 20.1: Failed to attach runtime.execute uprobe, error=%v", err)
-				log("failed to attach write_enter uprobe", err)
 				klog.Infoln("runtime.execute no")
 				return nil, err
-			} else {
-				klog.Infof("[AttachGoTlsUprobes] STEP 20.2: Successfully attached runtime.execute uprobe")
-				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:
 			klog.Infof("[AttachGoTlsUprobes] STEP 21: Attaching uprobe for runtime.newproc1, address=0x%x", address)
-			l, err := exe.Uprobe(s.Name, t.uprobes["enter_runtime_newproc1"], &link.UprobeOptions{Address: 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 {
-				klog.Errorf("[AttachGoTlsUprobes] STEP 21.1: Failed to attach enter_runtime_newproc1 uprobe, error=%v", err)
-				log("failed to attach newproc1 uprobe", err)
 				return nil, err
 			}
+			links = append(links, retLinks...)
 			klog.Infof("[AttachGoTlsUprobes] STEP 21.2: Successfully attached enter_runtime_newproc1 uprobe")
-			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)
-			}
 
 		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)
@@ -631,61 +613,32 @@ func (t *Tracer) AttachGoTlsUprobes(pid uint32, appInfo *AppInfo, codeType uint1
 			//	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})
@@ -695,137 +648,65 @@ func (t *Tracer) AttachGoTlsUprobes(pid uint32, appInfo *AppInfo, codeType uint1
 		// 	}
 		// 	links = append(links, l)
 		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 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
 			}
 			links = append(links, l)
 
 		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
-			}
-			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
+			if retLinks != nil {
+				links = append(links, retLinks...)
 			}
-			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...)
+				}
 			}
 		}
 	}
@@ -919,6 +800,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 {

+ 3 - 1
utils/modelse/bpf_struct.go

@@ -176,6 +176,8 @@ type EbpfTraceConf struct {
 		__u64 ctx_ptr_pos;
 		__u64 headers_ptr_pos;
 		__u64 buckets_ptr_pos;
+		__u64 use_swiss_map;
+		//gRPC
 		__u64 httpclient_nextid_pos;
 		__u64 stream_method_ptr_pos;
 		__u64 stream_ctx_pos;
@@ -203,7 +205,7 @@ type EbpfProcInfo struct {
 	CtxPtrPos      uint64
 	HeadersPtrPos  uint64
 	BucketsPtrPos  uint64
-
+	UseSwissMap    uint64
 	// gRPC
 	HttpClientNextidPos uint64
 	StreamMethodPtrPos  uint64