Просмотр исходного кода

Feature #TASK_QT-18250 修改bug

rock.wu 9 месяцев назад
Родитель
Сommit
efb2d439b9

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

@@ -42,6 +42,27 @@ struct go_iface
     void *data;
 };
 
+// Go 的 bmap 结构(与运行时完全匹配)
+struct go_bmap {
+    char tophash[8];                    // 固定8个槽位
+    struct go_string_ot keys[8];        // 固定8个槽位
+    struct go_slice_ot values[8];       // 固定8个槽位
+    void *overflow;                     // 指向下一个overflow bucket
+};
+
+// 扩展的bucket结构(用于存储额外信息)
+struct map_bucket_extended {
+    struct go_bmap bmap;                // 标准的Go bmap结构
+    void *headers_ptr;
+    void *bucket_ptr;
+    char header_str[CW_HEADER_VAL_LENGTH];
+    u64 curr_keyvalue_count;
+    u8 bucket_index;
+    u8 is_overflow;                     // 标记是否为overflow bucket
+    u32 overflow_chain_length;          // overflow链长度
+};
+
+// 保持向后兼容的旧结构体
 struct map_bucket {
     char tophash[8];
     struct go_string_ot keys[8];

+ 291 - 10
ebpftracer/ebpf/utrace/go/net/server.probe.bpf.c

@@ -60,6 +60,13 @@ struct {
 	__uint(max_entries, MAX_CONCURRENT);
 } golang_mapbucket_storage_map SEC(".maps");
 
+struct {
+	__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
+	__uint(key_size, sizeof(u32));
+	__uint(value_size, sizeof(struct map_bucket_extended));
+	__uint(max_entries, MAX_CONCURRENT);
+} golang_mapbucket_extended_storage_map SEC(".maps");
+
 struct {
 	__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
 	__uint(key_size, sizeof(u32));
@@ -247,7 +254,206 @@ static __always_inline struct span_context *extract_context_from_req_headers(voi
 	return NULL;
 }
 
-// 获取 get_map_bucket
+// 在单个bucket中搜索header值
+static __always_inline char *search_header_in_bucket(
+    struct go_bmap *bmap, 
+    u32 start_idx, 
+    u32 end_idx) {
+    
+    for (u32 i = start_idx; i < end_idx && i < 8; i++) {
+        if (bmap->tophash[i] != 0 && bmap->keys[i].len == CW_HEADER_KEY_LENGTH) {
+            char current_header_key[CW_HEADER_KEY_LENGTH];
+            bpf_probe_read(current_header_key, sizeof(current_header_key), bmap->keys[i].str);
+            
+            if ((current_header_key[0] == CW_HEADER_KEY_VAL[0] || 
+                 current_header_key[0] == CW_HEADER_KEY_UFIRST_VAL[0]) &&
+                current_header_key[1] == CW_HEADER_KEY_UFIRST_VAL[1] &&
+                current_header_key[2] == CW_HEADER_KEY_UFIRST_VAL[2] &&
+                current_header_key[3] == CW_HEADER_KEY_UFIRST_VAL[3] &&
+                current_header_key[4] == CW_HEADER_KEY_UFIRST_VAL[4] &&
+                current_header_key[5] == CW_HEADER_KEY_UFIRST_VAL[5] &&
+                current_header_key[6] == CW_HEADER_KEY_UFIRST_VAL[6]) {
+                
+                void *traceparent_header_value_ptr = bmap->values[i].array;
+                struct go_string_ot traceparent_header_value_go_str;
+                long res = bpf_probe_read(&traceparent_header_value_go_str, 
+                                        sizeof(traceparent_header_value_go_str),
+                                        traceparent_header_value_ptr);
+                if (res == 0) {
+                    cw_bpf_debug("Found header in bucket at index %d", i);
+                    return traceparent_header_value_go_str.str;
+                }
+            }
+        }
+    }
+    return NULL;
+}
+
+// 搜索header值(支持overflow bucket)
+static __always_inline char *get_header_val_with_overflow(
+    struct map_bucket_extended *bucket_ext, 
+    u32 max_overflow_chain_length) {
+    
+    // 首先在主bucket中搜索
+    char *val = search_header_in_bucket(&bucket_ext->bmap, 0, 8);
+    if (val != NULL) {
+        return val;
+    }
+    
+    // 如果主bucket没找到,搜索overflow bucket
+    if (bucket_ext->bmap.overflow != NULL) {
+        void *current_overflow = bucket_ext->bmap.overflow;
+        u32 chain_length = 0;
+        
+        while (current_overflow != NULL && chain_length < max_overflow_chain_length) {
+            struct go_bmap overflow_bmap;
+            long res = bpf_probe_read(&overflow_bmap, sizeof(struct go_bmap), current_overflow);
+            if (res < 0) {
+                cw_bpf_debug("Failed to read overflow bucket at chain length %d", chain_length);
+                break;
+            }
+            
+            // 在overflow bucket中搜索
+            val = search_header_in_bucket(&overflow_bmap, 0, 8);
+            if (val != NULL) {
+                cw_bpf_debug("Found header in overflow bucket at chain length %d", chain_length);
+                return val;
+            }
+            
+            // 移动到下一个overflow bucket
+            res = bpf_probe_read(&current_overflow, sizeof(current_overflow), 
+                               current_overflow + offsetof(struct go_bmap, overflow));
+            if (res < 0) {
+                cw_bpf_debug("Failed to read next overflow bucket pointer");
+                break;
+            }
+            chain_length++;
+        }
+        
+        cw_bpf_debug("Searched %d overflow buckets, max allowed: %d", chain_length, max_overflow_chain_length);
+    }
+    
+    return NULL;
+}
+
+// 读取单个bucket(包括overflow chain)
+static __always_inline struct map_bucket_extended *read_bucket_with_overflow(
+    void *bucket_ptr, 
+    u32 max_overflow_chain_length) {
+    
+    u32 map_id = 0;
+    struct map_bucket_extended *result = bpf_map_lookup_elem(&golang_mapbucket_extended_storage_map, &map_id);
+    if (!result) {
+        cw_bpf_debug("Failed to get extended bucket storage");
+        return NULL;
+    }
+    
+    __builtin_memset(result, 0, sizeof(struct map_bucket_extended));
+    
+    // 读取主bucket
+    long res = bpf_probe_read(&result->bmap, sizeof(struct go_bmap), bucket_ptr);
+    if (res < 0) {
+        cw_bpf_debug("Failed to read main bucket");
+        return NULL;
+    }
+    
+    result->is_overflow = 0;
+    result->overflow_chain_length = 0;
+    
+    // 检查是否有overflow bucket
+    if (result->bmap.overflow != NULL) {
+        result->is_overflow = 1;
+        result->overflow_chain_length = 1;
+        
+        // 遍历overflow chain(限制最大长度避免无限循环)
+        void *current_overflow = result->bmap.overflow;
+        u32 chain_length = 1;
+        
+        while (current_overflow != NULL && chain_length < max_overflow_chain_length) {
+            void *next_overflow;
+            res = bpf_probe_read(&next_overflow, sizeof(next_overflow), 
+                               current_overflow + offsetof(struct go_bmap, overflow));
+            if (res < 0) {
+                cw_bpf_debug("Failed to read overflow chain at length %d", chain_length);
+                break;
+            }
+            current_overflow = next_overflow;
+            chain_length++;
+        }
+        
+        result->overflow_chain_length = chain_length;
+        cw_bpf_debug("Found overflow chain with length %d", chain_length);
+    }
+    
+    return result;
+}
+
+// 获取 map_bucket(支持overflow)
+static __always_inline struct map_bucket_extended *get_map_bucket_with_overflow(
+    void *headers_ptr_ptr, 
+    u32 max_overflow_chain_length) {
+    
+    void *headers_ptr;
+    long res = bpf_probe_read(&headers_ptr, sizeof(headers_ptr), headers_ptr_ptr);
+    if (res < 0) {
+        cw_bpf_debug("Failed to read headers pointer");
+        return NULL;
+    }
+    
+    u64 headers_count = 0;
+    res = bpf_probe_read(&headers_count, sizeof(headers_count), headers_ptr);
+    if (res < 0) {
+        cw_bpf_debug("Failed to read headers count");
+        return NULL;
+    }
+    if (headers_count == 0) {
+        cw_bpf_debug("Headers count is 0");
+        return NULL;
+    }
+    
+    unsigned char log_2_bucket_count;
+    res = bpf_probe_read(&log_2_bucket_count, sizeof(log_2_bucket_count), headers_ptr + 9);
+    if (res < 0) {
+        cw_bpf_debug("Failed to read log_2_bucket_count");
+        return NULL;
+    }
+    u64 bucket_count = 1 << log_2_bucket_count;
+    
+    __u64 pid_tgid = bpf_get_current_pid_tgid();
+    __u32 tgid = pid_tgid >> 32;
+    struct ebpf_proc_info *proc_info = bpf_map_lookup_elem(&proc_info_map, &tgid);
+    if (!proc_info) {
+        cw_bpf_debug("No proc info found");
+        return NULL;
+    }
+    
+    void *header_buckets;
+    res = bpf_probe_read(&header_buckets, sizeof(header_buckets), 
+                        (void *)(headers_ptr + proc_info->buckets_ptr_pos));
+    if (res < 0) {
+        cw_bpf_debug("Failed to read header buckets pointer");
+        return NULL;
+    }
+    
+    cw_bpf_debug("Searching %d buckets with max overflow chain length %d", bucket_count, max_overflow_chain_length);
+    
+    // 遍历所有buckets
+    for (u32 j = 0; j < bucket_count; j++) {
+        void *current_bucket = header_buckets + (j * sizeof(struct go_bmap));
+        struct map_bucket_extended *result = read_bucket_with_overflow(
+            current_bucket, max_overflow_chain_length);
+        
+        if (result != NULL) {
+            cw_bpf_debug("Found valid bucket at index %d", j);
+            return result;
+        }
+    }
+    
+    cw_bpf_debug("No valid bucket found");
+    return NULL;
+}
+
+// 获取 get_map_bucket(保持向后兼容)
 static __always_inline struct map_bucket *get_map_bucket(void *headers_ptr_ptr) {
 	void *headers_ptr;
 	long res;
@@ -301,6 +507,84 @@ static __always_inline struct map_bucket *get_map_bucket(void *headers_ptr_ptr)
 	return NULL;
 }
 
+// 简化的overflow bucket搜索函数
+static __always_inline char *get_header_val_with_overflow_simple(void *headers_ptr_ptr) {
+	void *headers_ptr;
+	long res = bpf_probe_read(&headers_ptr, sizeof(headers_ptr), headers_ptr_ptr);
+	if (res < 0) {
+		return NULL;
+	}
+	
+	u64 headers_count = 0;
+	res = bpf_probe_read(&headers_count, sizeof(headers_count), headers_ptr);
+	if (res < 0 || headers_count == 0) {
+		return NULL;
+	}
+	
+	unsigned char log_2_bucket_count;
+	res = bpf_probe_read(&log_2_bucket_count, sizeof(log_2_bucket_count), headers_ptr + 9);
+	if (res < 0) {
+		return NULL;
+	}
+	u64 bucket_count = 1 << log_2_bucket_count;
+	
+	__u64 pid_tgid = bpf_get_current_pid_tgid();
+	__u32 tgid = pid_tgid >> 32;
+	struct ebpf_proc_info *proc_info = bpf_map_lookup_elem(&proc_info_map, &tgid);
+	if (!proc_info) {
+		return NULL;
+	}
+	
+	void *header_buckets;
+	res = bpf_probe_read(&header_buckets, sizeof(header_buckets), 
+	                    (void *)(headers_ptr + proc_info->buckets_ptr_pos));
+	if (res < 0) {
+		return NULL;
+	}
+	
+	u32 map_id = 0;
+	struct map_bucket *map_value = bpf_map_lookup_elem(&golang_mapbucket_storage_map, &map_id);
+	if (!map_value) {
+		return NULL;
+	}
+	
+	// 遍历所有buckets
+	for (u32 j = 0; j < bucket_count; j++) {
+		__builtin_memset(map_value, 0, sizeof(struct map_bucket));
+		
+		// 读取主bucket
+		res = bpf_probe_read(map_value, sizeof(struct map_bucket), 
+		                   header_buckets + (j * sizeof(struct map_bucket)));
+		if (res < 0) {
+			continue;
+		}
+		
+		// 在主bucket中搜索
+		char *val = get_header_val(map_value, 0, 8);
+		if (val != NULL) {
+			cw_bpf_debug("Found header in main bucket %d", j);
+			return val;
+		}
+		
+		// 检查是否有overflow bucket
+		if (map_value->overflow != NULL) {
+			cw_bpf_debug("Found overflow bucket for bucket %d", j);
+			
+			// 读取overflow bucket
+			res = bpf_probe_read(map_value, sizeof(struct map_bucket), map_value->overflow);
+			if (res == 0) {
+				val = get_header_val(map_value, 0, 8);
+				if (val != NULL) {
+					cw_bpf_debug("Found header in overflow bucket for bucket %d", j);
+					return val;
+				}
+			}
+		}
+	}
+	
+	return NULL;
+}
+
 // 获取 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++) {
@@ -387,13 +671,10 @@ int uprobe_HandlerFunc_ServeHTTP(struct pt_regs *ctx) {
 
 	// Propagate context
 	void *req_ptr = get_argument(ctx, 4);
-	struct map_bucket * map_bucket_p = get_map_bucket((void *) (req_ptr + proc_info->headers_ptr_pos));
-
-	if (map_bucket_p == NULL) {
-		return 0;
-	}
-
-	char * traceparent_header_value = get_header_val_off(map_bucket_p);
+	
+	// 使用改进的搜索函数,支持overflow bucket
+	char *traceparent_header_value = get_header_val_with_overflow_simple(
+		(void *)(req_ptr + proc_info->headers_ptr_pos));
 	struct apm_span_context *cw_parent_span_context = bpf_map_lookup_elem(&cw_parent_span_context_storage_map, &map_id);
 	if (!cw_parent_span_context) {
 		return 0;
@@ -401,7 +682,7 @@ int uprobe_HandlerFunc_ServeHTTP(struct pt_regs *ctx) {
 	__builtin_memset(cw_parent_span_context, 0, sizeof(struct apm_span_context));
 
 	if (traceparent_header_value != NULL) {
-		cw_bpf_debug("traceparent_header_value != NULL");
+		bpf_printk("traceparent_header_value != NULL");
 
 		cw_string_to_span_context(traceparent_header_value, cw_parent_span_context);
 		// found parent context in http headers
@@ -412,7 +693,7 @@ int uprobe_HandlerFunc_ServeHTTP(struct pt_regs *ctx) {
 		generate_random_bytes(http_server_span->sc.SpanID, SPAN_ID_SIZE);
 		cw_save_parent_tracking_span(cw_parent_span_context);
 	} else {
-		cw_bpf_debug("traceparent_header_value == NULL");
+		bpf_printk("traceparent_header_value == NULL");
 		http_server_span->sc = generate_span_context();
 
 		struct apm_span_context *cw_parent_span_context = bpf_map_lookup_elem(&cw_parent_span_context_storage_map, &map_id);