// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "arguments.h"
#include "span_context.h"
#include "go_context.h"
#include "go_types.h"
#include "uprobe.h"

//char __license[] SEC("license") = "Dual MIT/GPL";

#define PATH_MAX_LEN 128
#define MAX_BUCKETS 8
#define METHOD_MAX_LEN 8
#define MAX_CONCURRENT 50
#define REMOTE_ADDR_MAX_LEN 256
#define HOST_MAX_LEN 256
#define PROTO_MAX_LEN 8

struct http_server_span_t {
	BASE_SPAN_PROPERTIES
	u64 status_code;
	char method[METHOD_MAX_LEN];
	char path[PATH_MAX_LEN];
	char remote_addr[REMOTE_ADDR_MAX_LEN];
	char host[HOST_MAX_LEN];
	char proto[PROTO_MAX_LEN];
};

struct uprobe_data_t {
	struct http_server_span_t span;
	// bpf2go doesn't support pointers fields
	// saving the response pointer in the entry probe
	// and using it in the return probe
	u64 resp_ptr;
};

struct {
	__uint(type, BPF_MAP_TYPE_HASH);
	__type(key, void *);
	__type(value, struct uprobe_data_t);
	__uint(max_entries, MAX_CONCURRENT);
} http_server_uprobes SEC(".maps");

struct {
	__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
	__uint(key_size, sizeof(u32));
	__uint(value_size, sizeof(struct map_bucket));
	__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 cw_header_token));
	__uint(max_entries, MAX_CONCURRENT);
} header_range SEC(".maps");

struct {
	__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
	__uint(key_size, sizeof(u32));
	__uint(value_size, sizeof(struct span_context));
	__uint(max_entries, 1);
} parent_span_context_storage_map SEC(".maps");

struct {
	__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
	__uint(key_size, sizeof(u32));
	__uint(value_size, sizeof(struct apm_span_context));
	__uint(max_entries, 1);
} cw_parent_span_context_storage_map SEC(".maps");

struct {
	__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
	__uint(key_size, sizeof(u32));
	__uint(value_size, sizeof(struct uprobe_data_t));
	__uint(max_entries, 1);
} http_server_uprobe_storage_map SEC(".maps");

struct {
	__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
} events SEC(".maps");

struct header_key {
	char str[CW_HEADER_KEY_LENGTH];
};

struct {
	__uint(type, BPF_MAP_TYPE_HASH);
	__uint(key_size, sizeof(u32));
	__uint(value_size, sizeof(struct header_key));
	__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;
// volatile const u64 headers_ptr_pos;
// volatile const u64 buckets_ptr_pos;
//for (int i = 0; i < W3C_KEY_LENGTH; i++)
//{
//if (current_header_key[i] != "traceparent"[i]){
//goto outer_loop;
//}
//if (current_header_key[i] != "Traceparent"[i]){
//goto outer_loop;
//}
//}

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);
	if (res < 0) {
		return NULL;
	}
	u64 headers_count = 0;
	res = bpf_probe_read(&headers_count, sizeof(headers_count), headers_ptr);
	if (res < 0) {
		return NULL;
	}
	if (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 0;
    }
	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;
	}
	for (u32 j = 0; j < MAX_BUCKETS; j++) {
		if (j >= bucket_count) {
			break;
		}
		res = bpf_probe_read(map_value, sizeof(struct map_bucket), header_buckets + (j * sizeof(struct map_bucket)));
		if (res < 0) {
			continue;
		}

//		for (u32 i = 0; i < 8; i++) {
		u32 i = 0;
			if (map_value->tophash[i] != 0 && map_value->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), map_value->keys[i].str);
			for (int ii = 0; ii < CW_HEADER_KEY_LENGTH; ii++) {
				if (map_value->keys[i].str[ii] != CW_HEADER_KEY_VAL[i] && map_value->keys[i].str[ii] != CW_HEADER_KEY_UFIRST_VAL[ii]) {
//					goto outer_loop;
				}
			}
//				continue;
			}
//			if (map_value->keys[i].len != CW_HEADER_KEY_LENGTH) {
//				continue;
//			}

//			char current_header_key[CW_HEADER_KEY_LENGTH];
//			bpf_probe_read(current_header_key, sizeof(current_header_key), map_value->keys[i].str);


//
//			struct header_key * current_header_key = bpf_map_lookup_elem(&header_keys_map, &map_id);
//			if (current_header_key) {
//				bpf_probe_read(current_header_key->str, sizeof(current_header_key->str),  map_value->keys[i].str);
//			}
//
//			for (int i = 0; i < CW_HEADER_KEY_LENGTH; i++) {
//				if (current_header_key[i] != CW_HEADER_KEY_VAL[i] && current_header_key[i] != CW_HEADER_KEY_UFIRST_VAL[i]) {
//					goto outer_loop;
//				}
//			}
//
//			void *traceparent_header_value_ptr = map_value->values[i].array;
//			struct go_string_ot traceparent_header_value_go_str;
//			res = bpf_probe_read(&traceparent_header_value_go_str, sizeof(traceparent_header_value_go_str),
//			                     traceparent_header_value_ptr);
//			// 00-95b5ec2b81e2374a4a27ce36ab71d349-18f65a5a3ab22213-02
//			cw_bpf_debug("traceparent_header_value_go_str.str:%s", traceparent_header_value_go_str.str);
//
//			if (res < 0) {
//				return NULL;
//			}
//
//			// char traceparent_header_value[130];
//			int key = 0;
//			char *traceparent_header_value;
//			traceparent_header_value = bpf_map_lookup_elem(&go_large_array_map, &key);
//
//			res = bpf_probe_read(&traceparent_header_value, sizeof(traceparent_header_value),
//			                     traceparent_header_value_go_str.str);
//
//
//			if (res < 0) {
//				return NULL;
//			}
//			struct span_context *parent_span_context = bpf_map_lookup_elem(&parent_span_context_storage_map, &map_id);
//			if (!parent_span_context) {
//				cw_bpf_debug("no parent_span_context");
//				return NULL;
//			}
//			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) {
//				cw_bpf_debug("no cw_parent_span_context");
//				return NULL;
//			}
//
//			w3c_string_to_span_context(traceparent_header_value, parent_span_context);
//
//			cw_string_to_span_context(traceparent_header_value, cw_parent_span_context);
//
//			// 保存sc
//			cw_save_parent_tracking_span(cw_parent_span_context);
//
//			return parent_span_context;
//			outer_loop:
//			continue;
//		}
	}
	return NULL;
}

// 获取 get_map_bucket
static __always_inline struct map_bucket *get_map_bucket(void *headers_ptr_ptr) {
	void *headers_ptr;
	long res;
	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) {
		return NULL;
	}
	if (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;
	}
	__builtin_memset(map_value, 0, sizeof(struct map_bucket));

	for (u32 j = 0; j < 8; j++) {
		if (j >= bucket_count) {
			break;
		}
		res = bpf_probe_read(map_value, sizeof(struct map_bucket), header_buckets + (j * sizeof(struct map_bucket)));
		if (res == 0) {
			return map_value;
		}
	}
	return NULL;
}


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;
	long res;
	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)
	{
		return NULL;
	}
	if (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;
	void *header_buckets;
	/**/
	__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;
	}
	/**/

	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;
	MAP_BUCKET_TYPE(go_string_ot, go_slice_ot) *map_value = bpf_map_lookup_elem(&golang_mapbucket_storage_map, &map_id);
	if (!map_value)
	{
		return NULL;
	}

	for (u64 j = 0; j < MAX_BUCKETS; j++)
	{
		if (j >= bucket_count)
		{
			break;
		}
		res = bpf_probe_read(map_value, sizeof(MAP_BUCKET_TYPE(go_string_ot, go_slice_ot)), header_buckets + (j * sizeof(MAP_BUCKET_TYPE(go_string_ot, go_slice_ot))));
		if (res < 0)
		{
			continue;
		}
		for (u64 i = 0; i < 8; i++)
		{
			if (map_value->tophash[i] == 0)
			{
				continue;
			}
			if (map_value->keys[i].len != CW_HEADER_KEY_LENGTH)
			{
				continue;
			}
			char current_header_key[CW_HEADER_KEY_LENGTH];
			bpf_probe_read(current_header_key, sizeof(current_header_key), map_value->keys[i].str);
			if (!bpf_memcmp(current_header_key, CW_HEADER_KEY_VAL, CW_HEADER_KEY_LENGTH) && !bpf_memcmp(current_header_key, CW_HEADER_KEY_UFIRST_VAL, CW_HEADER_KEY_LENGTH))
			{
				continue;
			}
			void *traceparent_header_value_ptr = map_value->values[i].array;
			struct go_string_ot traceparent_header_value_go_str;
			res = bpf_probe_read(&traceparent_header_value_go_str, sizeof(traceparent_header_value_go_str), traceparent_header_value_ptr);
			if (res < 0)
			{
				return NULL;
			}
			if (traceparent_header_value_go_str.len != CW_HEADER_VAL_LENGTH)
			{
				continue;
			}
			char traceparent_header_value2[CW_HEADER_VAL_LENGTH];
			res = bpf_probe_read(&traceparent_header_value2, sizeof(traceparent_header_value2), traceparent_header_value_go_str.str);
			if (res < 0)
			{
				return NULL;
			}
//			bpf_printk("has cw header111 j=%d i=%d %s", j, i,traceparent_header_value_go_str.str);

			return traceparent_header_value_go_str.str;
//			w3c_string_to_span_context(traceparent_header_value, parent_span_context);
//			return 0;
		}
	}
	return NULL;
}

static __always_inline char *
extract_context_from_req_headers(void *key, void *headers_ptr_ptr) {
	return extract_context_from_req_headers_pre_parsed(key);
//	if (use_swiss == 1) {
//	}
//	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++) {
		if (map_value->tophash[i] != 0 && map_value->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), map_value->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 = map_value->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("get_header_val %d-%d %s",off,count,traceparent_header_value_go_str.str);
					return traceparent_header_value_go_str.str;
				}
			}
		}
	}
	return NULL;
}

// 分段获取 header_val
static __always_inline char *get_header_val_off(struct map_bucket *map_value) {
	char *val = get_header_val(map_value, 0, 2);
	if (val == NULL) {
		val = get_header_val(map_value, 2, 4);
	}
	if (val == NULL) {
		val = get_header_val(map_value, 4, 6);
	}
	if (val == NULL) {
		val = get_header_val(map_value, 6, 8);
	}
	return val;
}


// This instrumentation attaches uprobe to the following function:
// func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request)
SEC("uprobe/HandlerFunc_ServeHTTP")
int uprobe_HandlerFunc_ServeHTTP(struct pt_regs *ctx) {
	cw_bpf_debug("[uprobe_HandlerFunc_ServeHTTP]");
	__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("[uprobe_HandlerFunc_ServeHTTP] no proc info");
        return 0;
    }

	void *req_ctx_ptr = get_Go_context(ctx, 4, proc_info->ctx_ptr_pos, false);
	void *key = get_consistent_key(ctx, req_ctx_ptr);
	void *httpReq_ptr = bpf_map_lookup_elem(&http_server_uprobes, &key);
	if (httpReq_ptr != NULL) {
		cw_bpf_debug("uprobe/HandlerFunc_ServeHTTP already tracked with the current request");
		return 0;
	}
	
	u32 map_id = 0;
	struct uprobe_data_t *uprobe_data = bpf_map_lookup_elem(&http_server_uprobe_storage_map, &map_id);
	if (uprobe_data == NULL) {
		cw_bpf_debug("uprobe/HandlerFunc_ServeHTTP: http_server_span is NULL");
		return 0;
	}

	__builtin_memset(uprobe_data, 0, sizeof(struct uprobe_data_t));

	// Save response writer
	void *resp_impl = get_argument(ctx, 3);
	uprobe_data->resp_ptr = (u64) resp_impl;

	struct http_server_span_t *http_server_span = &uprobe_data->span;
	http_server_span->start_time = bpf_ktime_get_ns();
//	return 1;

	// 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));

	char *traceparent_header_value = extract_context_from_req_headers(key,
	                                                                  (void *) (req_ptr + proc_info->headers_ptr_pos));

//	bpf_printk("111 %s",traceparent_header_value);

//	char * traceparent_header_value = get_header_val_off(map_bucket_p);
	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;
	}
	__builtin_memset(cw_parent_span_context, 0, sizeof(struct apm_span_context));

	if (traceparent_header_value != NULL) {
		cw_bpf_debug("traceparent_header_value != NULL");

		cw_string_to_span_context(traceparent_header_value, cw_parent_span_context);
		// found parent context in http headers
//		http_server_span->psc = *parent_ctx;
		// copy traceID
		copy_byte_arrays(http_server_span->psc.TraceID, http_server_span->sc.TraceID, TRACE_ID_SIZE);
		// 生成随机SpanID
		generate_random_bytes(http_server_span->sc.SpanID, SPAN_ID_SIZE);
		cw_save_parent_tracking_span(cw_parent_span_context);
	} else {
		cw_bpf_debug("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);
		if (!cw_parent_span_context) {
			return 0;
		}

		// struct apm_span_context context = {};
		generate_random_bytes(cw_parent_span_context->trace_id, TRACE_ID_SIZE);
		// generate_random_bytes(context.span_id, SPAN_ID_SIZE);
		// 保存 trace_id 到psc
		cw_save_parent_tracking_span(cw_parent_span_context);
	}

	if (req_ctx_ptr == NULL) {
//		cw_bpf_debug("uprobe/HandlerFunc_ServeHTTP: req_ctx_ptr is NULL");
		return 0;
	}
//	cw_bpf_debug("found parent context in http headers");

//	cw_bpf_debug("parent_span_context-TraceID---");


//    for (int i = 0; i < TRACE_ID_SIZE; i++) {
//        cw_bpf_debug("%02x", uprobe_data->span.sc.TraceID[i]);
//    }

//    cw_bpf_debug("parent_span_context-SpanID---");
//    for (int i = 0; i < SPAN_ID_SIZE; i++) {
//        cw_bpf_debug("%02x", uprobe_data->span.sc.SpanID[i]);
//    }

//	bpf_map_update_elem(&http_server_uprobes, &key, uprobe_data, 0);
//	start_tracking_span(req_ctx_ptr, &http_server_span->sc);

//	void save_tracking_span(struct apm_span_context *sc)

	return 0;
}

// This instrumentation attaches uprobe to the following function:
// func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request)
SEC("uprobe/HandlerFunc_ServeHTTP")
int uprobe_HandlerFunc_ServeHTTP_Returns(struct pt_regs *ctx) {
//	return 1;
	cw_bpf_debug("[uprobe_HandlerFunc_ServeHTTP_Returns]");
//	u64 end_time = bpf_ktime_get_ns();
	__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 0;
    }

	void *req_ctx_ptr = get_Go_context(ctx, 4, proc_info->ctx_ptr_pos, false);
	void *key = get_consistent_key(ctx, req_ctx_ptr);

	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;
//	bpf_probe_read(&req_ptr, sizeof(req_ptr), (void *) (resp_ptr + req_ptr_pos));

//	http_server_span->end_time = end_time;
//
//	void *url_ptr = 0;
//	bpf_probe_read(&url_ptr, sizeof(url_ptr), (void *) (req_ptr + url_ptr_pos));
//	// Collect fields from response
//	read_go_string(req_ptr, method_ptr_pos, http_server_span->method, sizeof(http_server_span->method),
//	               "method from request");
//	read_go_string(url_ptr, path_ptr_pos, http_server_span->path, sizeof(http_server_span->path),
//	               "path from Request.URL");
//	read_go_string(req_ptr, remote_addr_pos, http_server_span->remote_addr, sizeof(http_server_span->remote_addr),
//	               "remote addr from Request.RemoteAddr");
//	read_go_string(req_ptr, host_pos, http_server_span->host, sizeof(http_server_span->host), "host from Request.Host");
//	read_go_string(req_ptr, proto_pos, http_server_span->proto, sizeof(http_server_span->proto),
//	               "proto from Request.Proto");
//
//	// status code
//	bpf_probe_read(&http_server_span->status_code, sizeof(http_server_span->status_code),
//	               (void *) (resp_ptr + status_code_pos));
//
//	bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, http_server_span, sizeof(*http_server_span));
	stop_tracking_span(&http_server_span->sc, &http_server_span->psc);


	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;
}
