#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 MAX_HOSTNAME_SIZE 256
#define MAX_PROTO_SIZE 8
#define MAX_PATH_SIZE 100
#define MAX_METHOD_SIZE 10
#define MAX_CONCURRENT 50

struct http_request_t {
    BASE_SPAN_PROPERTIES
    char host[MAX_HOSTNAME_SIZE];
    char proto[MAX_PROTO_SIZE];
    u64 status_code;
    char method[MAX_METHOD_SIZE];
    char path[MAX_PATH_SIZE];

	struct apm_span_context apm_sc;
    struct apm_span_context apm_psc;
};

struct {
	__uint(type, BPF_MAP_TYPE_HASH);
	__type(key, void*);
	__type(value, struct http_request_t);
	__uint(max_entries, MAX_CONCURRENT);
} http_events 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, 1);
//} golang_mapbucket_storage_map SEC(".maps");

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

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

// Injected in init
// volatile const u64 method_ptr_pos;
// volatile const u64 url_ptr_pos;
// volatile const u64 path_ptr_pos;
// volatile const u64 headers_ptr_pos;
// volatile const u64 ctx_ptr_pos;
// volatile const u64 buckets_ptr_pos;
// volatile const u64 status_code_pos;
// volatile const u64 request_host_pos;
// volatile const u64 request_proto_pos;

static __always_inline long inject_header(void* headers_ptr, struct span_context* propagated_ctx) {
    // Read the key-value count - this field must be the first one in the hmap struct as documented in src/runtime/map.go
    u64 curr_keyvalue_count = 0;
    long res = bpf_probe_read_user(&curr_keyvalue_count, sizeof(curr_keyvalue_count), headers_ptr);

    if (res < 0) {
        cw_bpf_debug("Couldn't read map key-value count from user");
        return -1;
    }

    if (curr_keyvalue_count >= 8) {
        cw_bpf_debug("Map size is bigger than 8, skipping context propagation");
        return -1;
    }

    // Get pointer to temp bucket struct we store in a map (avoiding large local variable on the stack)
    // Performing read-modify-write on the bucket
    u32 map_id = 0;
    struct map_bucket *bucket_map_value = bpf_map_lookup_elem(&golang_mapbucket_storage_map, &map_id);
    if (!bucket_map_value) {
        return -1;
    }
    __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 -1;
    }

    void *buckets_ptr_ptr = (void*) (headers_ptr + proc_info->buckets_ptr_pos);
    void *bucket_ptr = 0; // The actual pointer to the buckets

    if (curr_keyvalue_count == 0) {
        // No key-value pairs in the Go map, need to "allocate" memory for the user
        bucket_ptr = write_target_data(bucket_map_value, sizeof(struct map_bucket));
        if (bucket_ptr == NULL) {
            cw_bpf_debug("inject_header: Failed to write bucket to user");
            return -1;
        }
        // Update the buckets pointer in the hmap struct to point to newly allocated bucket
        res = bpf_probe_write_user(buckets_ptr_ptr, &bucket_ptr, sizeof(bucket_ptr));
        if (res < 0) {
            cw_bpf_debug("Failed to update the map bucket pointer for the user");
            return -1;
        }
    } else {
        // There is at least 1 key-value pair, hence the bucket pointer from the user is valid
        // Read the bucket pointer
        res = bpf_probe_read_user(&bucket_ptr, sizeof(bucket_ptr), buckets_ptr_ptr);
        // Read the user's bucket to the eBPF map entry
        bpf_probe_read_user(bucket_map_value, sizeof(struct map_bucket), bucket_ptr);
    }

    u8 bucket_index = curr_keyvalue_count & 0x7;

    char traceparent_tophash = 0xee;
    bucket_map_value->tophash[bucket_index] = traceparent_tophash;

    // Prepare the key string for the user
    char key[W3C_KEY_LENGTH] = "traceparent";
    void *ptr = write_target_data(key, W3C_KEY_LENGTH);
    if (ptr == NULL) {
        cw_bpf_debug("inject_header: Failed to write key to user");
        return -1;
    }
    bucket_map_value->keys[bucket_index] = (struct go_string_ot) {.len = W3C_KEY_LENGTH, .str = ptr};

    // Prepare the value string slice
    // First the value string which constains the span context
    char val[W3C_VAL_LENGTH];
    span_context_to_w3c_string(propagated_ctx, val);
    ptr = write_target_data(val, sizeof(val));
    if(ptr == NULL) {
        cw_bpf_debug("inject_header: Failed to write value to user");
        return -1;
    }

    // The go string pointing to the above val
    struct go_string_ot header_value = {.len = W3C_VAL_LENGTH, .str = ptr};
    ptr = write_target_data((void*)&header_value, sizeof(header_value));
    if(ptr == NULL) {
        cw_bpf_debug("inject_header: Failed to write go_string to user");
        return -1;
    }

    // Last, go_slice pointing to the above go_string
    bucket_map_value->values[bucket_index] = (struct go_slice_ot) {.array = ptr, .cap = 1, .len = 1};

    // Update the map header count field
    curr_keyvalue_count += 1;
    res = bpf_probe_write_user(headers_ptr, &curr_keyvalue_count, sizeof(curr_keyvalue_count));
    if (res < 0) {
        cw_bpf_debug("Failed to update key-value count in map header");
        return -1;
    }

    // Update the bucket
    res = bpf_probe_write_user(bucket_ptr, bucket_map_value, sizeof(struct map_bucket));
    if (res < 0) {
        cw_bpf_debug("Failed to update bucket content");
        return -1;
    }

    bpf_memset((unsigned char *)bucket_map_value, sizeof(struct map_bucket), 0);
    return 0;
}
// 00:00:1015481350055581:5450531005555981:5610250100539899:304775019cd3218a304775019cd3218a:1001025098564810:140acc88cde8773f
static __always_inline long cw_inject_header(void* headers_ptr, struct apm_span_context* propagated_ctx) {
    // Read the key-value count - this field must be the first one in the hmap struct as documented in src/runtime/map.go
    u64 curr_keyvalue_count = 0;
    long res = bpf_probe_read_user(&curr_keyvalue_count, sizeof(curr_keyvalue_count), headers_ptr);

    if (res < 0) {
        cw_bpf_debug("Couldn't read map key-value count from user");
        return -1;
    }

    if (curr_keyvalue_count >= 8) {
        cw_bpf_debug("Map size is bigger than 8, skipping context propagation");
        return -1;
    }

    // Get pointer to temp bucket struct we store in a map (avoiding large local variable on the stack)
    // Performing read-modify-write on the bucket
    u32 map_id = 0;
    struct map_bucket *bucket_map_value = bpf_map_lookup_elem(&golang_mapbucket_storage_map, &map_id);
    if (!bucket_map_value) {
        return -1;
    }

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

    void *buckets_ptr_ptr = (void*) (headers_ptr + proc_info->buckets_ptr_pos);
    void *bucket_ptr = 0; // The actual pointer to the buckets

    if (curr_keyvalue_count == 0) {
        // No key-value pairs in the Go map, need to "allocate" memory for the user
        bucket_ptr = write_target_data(bucket_map_value, sizeof(struct map_bucket));
        if (bucket_ptr == NULL) {
            cw_bpf_debug("inject_header: Failed to write bucket to user");
            return -1;
        }
        // Update the buckets pointer in the hmap struct to point to newly allocated bucket
        res = bpf_probe_write_user(buckets_ptr_ptr, &bucket_ptr, sizeof(bucket_ptr));
        if (res < 0) {
            cw_bpf_debug("Failed to update the map bucket pointer for the user");
            return -1;
        }
    } else {
        // There is at least 1 key-value pair, hence the bucket pointer from the user is valid
        // Read the bucket pointer
        res = bpf_probe_read_user(&bucket_ptr, sizeof(bucket_ptr), buckets_ptr_ptr);
        // Read the user's bucket to the eBPF map entry
        bpf_probe_read_user(bucket_map_value, sizeof(struct map_bucket), bucket_ptr);
    }

    u8 bucket_index = curr_keyvalue_count & 0x7;

    char traceparent_tophash = 0xee;
    bucket_map_value->tophash[bucket_index] = traceparent_tophash;

    // Prepare the key string for the user
    char key[W3C_KEY_LENGTH] = "traceparent";
    void *ptr = write_target_data(key, W3C_KEY_LENGTH);
    if (ptr == NULL) {
        cw_bpf_debug("inject_header: Failed to write key to user");
        return -1;
    }
    bucket_map_value->keys[bucket_index] = (struct go_string_ot) {.len = W3C_KEY_LENGTH, .str = ptr};

    // Prepare the value string slice
    // First the value string which constains the span context
    char val[CW_HEADER_LENGTH];
	span_context_to_cw_string(propagated_ctx, val);
    ptr = write_target_data(val, sizeof(val));
    if(ptr == NULL) {
        cw_bpf_debug("inject_header: Failed to write value to user");
        return -1;
    }

    // The go string pointing to the above val
    struct go_string_ot header_value = {.len = CW_HEADER_LENGTH, .str = ptr};
    ptr = write_target_data((void*)&header_value, sizeof(header_value));
    if(ptr == NULL) {
        cw_bpf_debug("inject_header: Failed to write go_string to user");
        return -1;
    }

    // Last, go_slice pointing to the above go_string
    bucket_map_value->values[bucket_index] = (struct go_slice_ot) {.array = ptr, .cap = 1, .len = 1};

    // Update the map header count field
    curr_keyvalue_count += 1;
    res = bpf_probe_write_user(headers_ptr, &curr_keyvalue_count, sizeof(curr_keyvalue_count));
    if (res < 0) {
        cw_bpf_debug("Failed to update key-value count in map header");
        return -1;
    }

    // Update the bucket
    res = bpf_probe_write_user(bucket_ptr, bucket_map_value, sizeof(struct map_bucket));
    if (res < 0) {
        cw_bpf_debug("Failed to update bucket content");
        return -1;
    }

    bpf_memset((unsigned char *)bucket_map_value, sizeof(struct map_bucket), 0);
    return 0;
}

// 00:00:1015481350055581:5450531005555981:5610250100539899:304775019cd3218a304775019cd3218a:1001025098564810:140acc88cde8773f
static __always_inline long cw_inject_header2(void* headers_ptr, struct apm_span_context* propagated_ctx) {
    // Read the key-value count - this field must be the first one in the hmap struct as documented in src/runtime/map.go
    u64 curr_keyvalue_count = 0;
    long res = bpf_probe_read_user(&curr_keyvalue_count, sizeof(curr_keyvalue_count), headers_ptr);

    if (res < 0) {
        cw_bpf_debug("Couldn't read map key-value count from user");
        return -1;
    }

    if (curr_keyvalue_count >= 8) {
        cw_bpf_debug("Map size is bigger than 8, skipping context propagation");
        return -1;
    }

    // Get pointer to temp bucket struct we store in a map (avoiding large local variable on the stack)
    // Performing read-modify-write on the bucket
    u32 map_id = 0;
    struct map_bucket *bucket_map_value = bpf_map_lookup_elem(&golang_mapbucket_storage_map, &map_id);
    if (!bucket_map_value) {
        return -1;
    }
    __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 -1;
    }

    void *buckets_ptr_ptr = (void*) (headers_ptr + proc_info->buckets_ptr_pos);
    void *bucket_ptr = 0; // The actual pointer to the buckets

    if (curr_keyvalue_count == 0) {
        // No key-value pairs in the Go map, need to "allocate" memory for the user
        bucket_ptr = write_target_data(bucket_map_value, sizeof(struct map_bucket));
        if (bucket_ptr == NULL) {
            cw_bpf_debug("inject_header: Failed to write bucket to user");
            return -1;
        }
        // Update the buckets pointer in the hmap struct to point to newly allocated bucket
        res = bpf_probe_write_user(buckets_ptr_ptr, &bucket_ptr, sizeof(bucket_ptr));
        if (res < 0) {
            cw_bpf_debug("Failed to update the map bucket pointer for the user");
            return -1;
        }
    } else {
        // There is at least 1 key-value pair, hence the bucket pointer from the user is valid
        // Read the bucket pointer
        res = bpf_probe_read_user(&bucket_ptr, sizeof(bucket_ptr), buckets_ptr_ptr);
        // Read the user's bucket to the eBPF map entry
        bpf_probe_read_user(bucket_map_value, sizeof(struct map_bucket), bucket_ptr);
    }

    u8 bucket_index = curr_keyvalue_count & 0x7;

//    char traceparent_tophash = 0xee;
//    bucket_map_value->tophash[bucket_index] = traceparent_tophash;

    // Prepare the key string for the user
    char key[CW_HEADER_KEY_LENGTH] = CW_HEADER_KEY_VAL;
    void *ptr = write_target_data(key, CW_HEADER_KEY_LENGTH);
    if (ptr == NULL) {
        cw_bpf_debug("inject_header: Failed to write key to user");
        return -1;
    }
    bucket_map_value->keys[bucket_index] = (struct go_string_ot) {.len = CW_HEADER_KEY_LENGTH, .str = ptr};

	char traceparent_tophash = 0xee;
	bucket_map_value->tophash[bucket_index] = traceparent_tophash;
	bucket_map_value->keys[bucket_index] = (struct go_string_ot) {.len = CW_HEADER_KEY_LENGTH, .str = ptr};


    // Prepare the value string slice
    // First the value string which constains the span context
    char val[CW_HEADER_VAL_LENGTH];
	span_context_to_cw_string(propagated_ctx, val);
    ptr = write_target_data(val, sizeof(val));
    if(ptr == NULL) {
        cw_bpf_debug("inject_header: Failed to write value to user");
        return -1;
    }

    // The go string pointing to the above val
    struct go_string_ot header_value = {.len = CW_HEADER_VAL_LENGTH, .str = ptr};
    ptr = write_target_data((void*)&header_value, sizeof(header_value));
    if(ptr == NULL) {
        cw_bpf_debug("inject_header: Failed to write go_string to user");
        return -1;
    }

    // Last, go_slice pointing to the above go_string
    bucket_map_value->values[bucket_index] = (struct go_slice_ot) {.array = ptr, .cap = 1, .len = 1};

    // Update the map header count field
    curr_keyvalue_count += 1;
    res = bpf_probe_write_user(headers_ptr, &curr_keyvalue_count, sizeof(curr_keyvalue_count));
    if (res < 0) {
        cw_bpf_debug("Failed to update key-value count in map header");
        return -1;
    }

    // Update the bucket
    res = bpf_probe_write_user(bucket_ptr, bucket_map_value, sizeof(struct map_bucket));
    if (res < 0) {
        cw_bpf_debug("Failed to update bucket content");
        return -1;
    }

    bpf_memset((unsigned char *)bucket_map_value, sizeof(struct map_bucket), 0);
    return 0;
}

// 00:00:1015481350055581:5450531005555981:5610250100539899:304775019cd3218a304775019cd3218a:1001025098564810:140acc88cde8773f
static __always_inline long cw_inject_header_half(void* headers_ptr, char * header_str,struct ebpf_proc_info* proc_info) {
    // Read the key-value count - this field must be the first one in the hmap struct as documented in src/runtime/map.go
    u64 curr_keyvalue_count = 0;
    long res = bpf_probe_read_user(&curr_keyvalue_count, sizeof(curr_keyvalue_count), headers_ptr);

    if (res < 0) {
        cw_bpf_debug("Couldn't read map key-value count from user");
        return -1;
    }

    if (curr_keyvalue_count >= 8) {
        cw_bpf_debug("Map size is bigger than 8, skipping context propagation");
        return -1;
    }

    // Get pointer to temp bucket struct we store in a map (avoiding large local variable on the stack)
    // Performing read-modify-write on the bucket
    u32 map_id = 0;
    struct map_bucket *bucket_map_value = bpf_map_lookup_elem(&golang_mapbucket_storage_map, &map_id);
    if (!bucket_map_value) {
        return -1;
    }
//    __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 -1;
//    }

    void *buckets_ptr_ptr = (void*) (headers_ptr + proc_info->buckets_ptr_pos);
    void *bucket_ptr = 0; // The actual pointer to the buckets

    if (curr_keyvalue_count == 0) {
        // No key-value pairs in the Go map, need to "allocate" memory for the user
        bucket_ptr = cw_write_target_data(bucket_map_value, sizeof(struct map_bucket),proc_info);
        if (bucket_ptr == NULL) {
            cw_bpf_debug("inject_header: Failed to write bucket to user");
            return -1;
        }
        // Update the buckets pointer in the hmap struct to point to newly allocated bucket
        res = bpf_probe_write_user(buckets_ptr_ptr, &bucket_ptr, sizeof(bucket_ptr));
        if (res < 0) {
            cw_bpf_debug("Failed to update the map bucket pointer for the user");
            return -1;
        }
    } else {
        // There is at least 1 key-value pair, hence the bucket pointer from the user is valid
        // Read the bucket pointer
        bpf_probe_read_user(&bucket_ptr, sizeof(bucket_ptr), buckets_ptr_ptr);
        // Read the user's bucket to the eBPF map entry
        bpf_probe_read_user(bucket_map_value, sizeof(struct map_bucket), bucket_ptr);
    }

    u8 bucket_index = curr_keyvalue_count & 0x7;

//	bucket_map_value->header_value_str_p = ptr;

	bucket_map_value->headers_ptr = headers_ptr;
	bucket_map_value->bucket_ptr = bucket_ptr;

	bucket_map_value->curr_keyvalue_count = curr_keyvalue_count;
	bucket_map_value->bucket_index = bucket_index;
	bpf_probe_read(bucket_map_value->header_str, sizeof(bucket_map_value->header_str),header_str);
	cw_bpf_debug("bucket_map_value->header_str %s",bucket_map_value->header_str);
//	bucket_map_value->header_str = header_str;

//	void * header_str_ptr = cw_write_target_data(header_str, CW_HEADER_VAL_LENGTH,proc_info);
//	if(header_str_ptr == NULL) {
//		cw_bpf_debug("inject_header: Failed to write value to user");
//		return -1;
//	}
//	bucket_map_value->header_str_p = header_str;

	return 0;

//    char traceparent_tophash = 0xee;
//    bucket_map_value->tophash[bucket_index] = traceparent_tophash;

    // Prepare the key string for the user
    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) {
        cw_bpf_debug("inject_header: Failed to write key to user");
        return -1;
    }
//    bucket_map_value->keys[bucket_index] = (struct go_string_ot) {.len = CW_HEADER_KEY_LENGTH, .str = ptr};

	char traceparent_tophash = 0xee;
	bucket_map_value->tophash[bucket_index] = traceparent_tophash;
	bucket_map_value->keys[bucket_index] = (struct go_string_ot) {.len = CW_HEADER_KEY_LENGTH, .str = ptr};

//	u32 k0;
//	struct tail_client_ctx_t *tail_calls_context = bpf_map_lookup_elem(&tail_client_ctx_heap, &k0);
//	if (!tail_calls_context){
//		return -1;
//	}

    // Prepare the value string slice
    // First the value string which constains the span context
//    char val[CW_HEADER_VAL_LENGTH];
//	span_context_to_cw_string(propagated_ctx, val);
// 往前提
    ptr = cw_write_target_data(header_str, CW_HEADER_VAL_LENGTH,proc_info);
    if(ptr == NULL) {
        cw_bpf_debug("inject_header: Failed to write value to user");
        return -1;
    }

//	return 0;
    // The go string pointing to the above val
    struct go_string_ot header_value = {.len = CW_HEADER_VAL_LENGTH, .str = ptr};
    ptr = cw_write_target_data((void*)&header_value, sizeof(header_value),proc_info);
    if(ptr == NULL) {
        cw_bpf_debug("inject_header: Failed to write go_string to user");
        return -1;
    }

    // Last, go_slice pointing to the above go_string
    bucket_map_value->values[bucket_index] = (struct go_slice_ot) {.array = ptr, .cap = 1, .len = 1};

    // Update the map header count field
    curr_keyvalue_count += 1;
    res = bpf_probe_write_user(headers_ptr, &curr_keyvalue_count, sizeof(curr_keyvalue_count));
    if (res < 0) {
        cw_bpf_debug("Failed to update key-value count in map header");
        return -1;
    }

    // Update the bucket
    res = bpf_probe_write_user(bucket_ptr, bucket_map_value, sizeof(struct map_bucket));
    if (res < 0) {
        cw_bpf_debug("Failed to update bucket content");
        return -1;
    }

    bpf_memset((unsigned char *)bucket_map_value, sizeof(struct map_bucket), 0);
    return 0;
}

// This instrumentation attaches uprobe to the following function:
// func net/http/transport.roundTrip(req *Request) (*Response, error)
SEC("uprobe/Transport_roundTrip")
int uprobe_Transport_roundTrip(struct pt_regs *ctx) {
	cw_bpf_debug("--------[Uprobe HTTP Client] start");

    u64 request_pos = 2;
    void *req_ptr = get_argument(ctx, request_pos);

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

    // Get parent if exists
    void *context_ptr_val = get_Go_context(ctx, 2, proc_info->ctx_ptr_pos, false);
    if (context_ptr_val == NULL)
    {
        return 0;
    }
    void *key = get_consistent_key(ctx, context_ptr_val);
    void *httpReq_ptr = bpf_map_lookup_elem(&http_events, &key);
    if (httpReq_ptr != NULL)
    {
        cw_bpf_debug("uprobe/Transport_RoundTrip already tracked with the current context");
        return 0;
    }
    // return 0;
    u32 map_id = 0;
    struct http_request_t *httpReq = bpf_map_lookup_elem(&http_client_uprobe_storage_map, &map_id);
    if (httpReq == NULL)
    {
        cw_bpf_debug("uprobe/Transport_roundTrip: httpReq is NULL");
        return 0;
    }

    __builtin_memset(httpReq, 0, sizeof(struct http_request_t));
    httpReq->start_time = bpf_ktime_get_ns();
//    struct span_context *parent_span_ctx = get_parent_span_context(context_ptr_val);
//    if (parent_span_ctx != NULL) {
//        cw_bpf_debug("[Client] parent_span_ctx != NULL");

//        bpf_probe_read(&httpReq->psc, sizeof(httpReq->psc), parent_span_ctx);
//        copy_byte_arrays(httpReq->psc.TraceID, httpReq->sc.TraceID, TRACE_ID_SIZE);
//        generate_random_bytes(httpReq->sc.SpanID, SPAN_ID_SIZE);
//    } else {
//        cw_bpf_debug("[Client] parent_span_ctx == NULL");
//	    struct apm_span_context *apm_sc = get_tracking_span();
//	    if (apm_sc) {
//		    httpReq->sc = *(struct span_context *) apm_sc;
//	    } else {
//		    httpReq->sc = generate_span_context();
//	    }

	    struct apm_span_context *cw_psc = cw_get_parent_tracking_span();
		if(cw_psc){
//			httpReq->apm_sc = *cw_sc;
			bpf_probe_read(&httpReq->apm_psc, sizeof(httpReq->apm_psc), cw_psc);
			// copy trace_id
//			copy_byte_arrays(httpReq->apm_psc.instance_id, httpReq->apm_sc.instance_id, APM_INSTANCE_ID_SIZE);
			copy_byte_arrays(httpReq->apm_psc.trace_id, httpReq->apm_sc.trace_id, APM_TRACE_ID_SIZE);
			// new spanid
			generate_random_bytes(httpReq->apm_sc.span_id, APM_SPAN_ID_SIZE);

			// copy TraceID
//			copy_byte_arrays(httpReq->apm_psc.trace_id, httpReq->sc.TraceID, TRACE_ID_SIZE);
//			copy_byte_arrays(httpReq->psc.TraceID, httpReq->sc.TraceID, TRACE_ID_SIZE);
//			generate_random_bytes(httpReq->sc.SpanID, SPAN_ID_SIZE);
		}
//    }
//    if (!get_go_string_from_user_ptr((void *)(req_ptr+proc_info->method_ptr_pos), httpReq->method, sizeof(httpReq->method))) {
//        cw_bpf_debug("uprobe_Transport_roundTrip: Failed to get method from request");
//        return 0;
//    }

    // get path from Request.URL
//    void *url_ptr = 0;
//    bpf_probe_read(&url_ptr, sizeof(url_ptr), (void *)(req_ptr+proc_info->url_ptr_pos));
//    if (!get_go_string_from_user_ptr((void *)(url_ptr+proc_info->path_ptr_pos), httpReq->path, sizeof(httpReq->path))) {
//        cw_bpf_debug("uprobe_Transport_roundTrip: Failed to get path from Request.URL");
//        return 0;
//    }

    // get host from Request
    if (!get_go_string_from_user_ptr((void *)(req_ptr+proc_info->request_host_pos), httpReq->host, sizeof(httpReq->host))) {
        cw_bpf_debug("uprobe_Transport_roundTrip: Failed to get host from Request");
    }
	// TODO set request_host_pos
	cw_bpf_debug("[Client] httpReq->host:%llu",proc_info->request_host_pos);
//	for (int i = 0; i < MAX_HOSTNAME_SIZE; ++i) {
//		if (httpReq->host[i] == '\0') {
//			break;
//		}
////		httpReq->apm_sc.assumed_app_id[i] = httpReq->host[i];
//		cw_bpf_debug("[Client] httpReq->host:%c",httpReq->host[i]);
//	}
//	unsigned char hash[APM_ASSUMED_APP_ID_STRING_SIZE];

	// set host_id/appid
	u32 k0 = 0;
	struct trace_conf_t *trace_conf = trace_conf_map__lookup(&k0);
	if (trace_conf) {
//		for (int i = 0; i < 8; ++i) {
////			cw_bpf_debug("[Client] host_id:%02x", trace_conf->host_id[i]);
//		}
		copy_byte_arrays(trace_conf->host_id, httpReq->apm_sc.host_id, APM_HOST_ID_SIZE);
		copy_byte_arrays(trace_conf->app_id, httpReq->apm_sc.app_id, APM_APP_ID_SIZE);
	}

	// __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) {
//		for (int i = 0; i < 8; ++i) {
////			cw_bpf_debug("[Client] instance_id:%02x", proc_info->instance_id[i]);
//		}
//	}
	copy_byte_arrays(proc_info->instance_id, httpReq->apm_sc.instance_id, APM_APP_ID_SIZE);

	// set assumed_app_id
	set_assumed_app_id_arrays(httpReq->host, httpReq->apm_sc.assumed_app_id, APM_ASSUMED_APP_ID_STRING_SIZE);
	cw_save_current_tracking_span(&httpReq->apm_sc);
	// get proto from Request
//    if (!get_go_string_from_user_ptr((void *)(req_ptr+proc_info->request_proto_pos), httpReq->proto, sizeof(httpReq->proto))) {
//        cw_bpf_debug("uprobe_Transport_roundTrip: Failed to get proto from Request");
//    }

    // get headers from Request
    void *headers_ptr = 0;
    bpf_probe_read(&headers_ptr, sizeof(headers_ptr), (void *)(req_ptr+proc_info->headers_ptr_pos));
//    long res = inject_header(headers_ptr, &httpReq->sc);
//    long res = cw_inject_header(headers_ptr, &httpReq->apm_sc);
//    if (res < 0) {
//        cw_bpf_debug("uprobe_Transport_roundTrip: Failed to inject header");
//    }
	char val[CW_HEADER_VAL_LENGTH];
	span_context_to_cw_string(&httpReq->apm_sc, val);

	long res2 = cw_inject_header_half(headers_ptr, val,proc_info);
	if (res2 < 0) {
		cw_bpf_debug("uprobe_Transport_roundTrip: Failed to inject header");
		return -1;
	}

	bpf_tail_call(ctx, &NAME(progs_jmp_up_map), PROG_DATA_GO_UPDATE_HEADER_UP_IDX);

//	bpf_tail_call(ctx, &jmp_table2, 0);

    // Write event
//    bpf_map_update_elem(&http_events, &key, httpReq, 0);
//    start_tracking_span(context_ptr_val, &httpReq->sc);

    return 0;
}

// bpf_prog_up__go_update_header
PROGUP(go_update_header)(struct pt_regs *ctx) {
	__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;
	}
//	__u32 k0;
//	struct tail_client_ctx_t *tail_calls_context =
//			bpf_map_lookup_elem(&tail_client_ctx_heap, &k0);
//	if (!tail_calls_context){
//		return -1;
//	}
	u32 map_id = 0;

	struct map_bucket *bucket_map_value = bpf_map_lookup_elem(&golang_mapbucket_storage_map, &map_id);
	if (!bucket_map_value) {
		return -1;
	}
//	if (!bucket_map_value->header_value_str_p){
//		return -1;
//	}
	if (!bucket_map_value->headers_ptr){
		return -1;
	}
	if (!bucket_map_value->bucket_ptr){
		return -1;
	}
//	if (!bucket_map_value->header_str){
//		return -1;
//	}
//	if (!bucket_map_value->header_str_p){
//		return -1;
//	}
	if (bucket_map_value->bucket_index >=8) {
		return -1;
	}

	void *headers_ptr = bucket_map_value->headers_ptr;
	void *bucket_ptr = bucket_map_value->bucket_ptr;

//	u8 bucket_index = 0;
//	bucket_index = bucket_map_value->bucket_index;

	u64 curr_keyvalue_count = bucket_map_value->curr_keyvalue_count;
	char * header_str = bucket_map_value->header_str;

//	cw_bpf_debug("header_str %s",bucket_map_value->header_str);


	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) {
//		cw_bpf_debug("inject_header: Failed to write key to user");
		return -1;
	}
//    bucket_map_value->keys[bucket_index] = (struct go_string_ot) {.len = CW_HEADER_KEY_LENGTH, .str = ptr};

	// 往前提
//	char val[CW_HEADER_VAL_LENGTH];
//	bpf_probe_read(val, sizeof(val),&header_str);
	void * header_str_ptr = cw_write_target_data(header_str, CW_HEADER_VAL_LENGTH,proc_info);
	if(header_str_ptr == NULL) {
//		cw_bpf_debug("inject_header: Failed to write value to user");
		return -1;
	}

//	if (bucket_index < 0 || bucket_index >= 8){
//		return -1;
//	}


	// The go string pointing to the above val
	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) {
		cw_bpf_debug("inject_header: Failed to write go_string to user");
		return -1;
	}

	char traceparent_tophash = 0xee;
	u8 bucket_index = curr_keyvalue_count & 0x7;
	bucket_map_value->tophash[bucket_index] = traceparent_tophash;
	bucket_map_value->keys[bucket_index] = (struct go_string_ot) {.len = CW_HEADER_KEY_LENGTH, .str = ptr};
	bucket_map_value->values[bucket_index] = (struct go_slice_ot) {.array = header_value_ptr, .cap = 1, .len = 1};

	// Last, go_slice pointing to the above go_string
//	return 1;
//	bucket_map_value->values[bucket_index] = (struct go_slice_ot) {.array = ptr, .cap = 1, .len = 1};

	// Update the map header count field
	curr_keyvalue_count = curr_keyvalue_count + 1;
	long res = bpf_probe_write_user(headers_ptr, &curr_keyvalue_count, sizeof(curr_keyvalue_count));
	if (res < 0) {
		cw_bpf_debug("Failed to update key-value count in map header");
		return -1;
	}

	// Update the bucket
	res = bpf_probe_write_user(bucket_ptr, bucket_map_value, sizeof(struct map_bucket));
	if (res < 0) {
		cw_bpf_debug("Failed to update bucket content");
		return -1;
	}

	bpf_memset((unsigned char *)bucket_map_value, sizeof(struct map_bucket), 0);
	return 0;
}

// This instrumentation attaches uretprobe to the following function:
// func net/http/transport.roundTrip(req *Request) (*Response, error)
SEC("uprobe/Transport_roundTrip")
int uprobe_Transport_roundTrip_Returns(struct pt_regs *ctx) {
	cw_bpf_debug("[Uprobe HTTP Client] start Return----------");
	clear_current_span_context();
    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, 2, proc_info->ctx_ptr_pos, false);
    void *key = get_consistent_key(ctx, req_ctx_ptr);

    struct http_request_t *http_req_span = bpf_map_lookup_elem(&http_events, &key);
    if (http_req_span == NULL) {
        cw_bpf_debug("probe_Transport_roundTrip_Returns: entry_state is NULL");
        return 0;
    }

    if (is_register_abi()) {
        // Getting the returned response
        void *resp_ptr = get_argument(ctx, 1);
        // Get status code from response
        bpf_probe_read(&http_req_span->status_code, sizeof(http_req_span->status_code), (void *)(resp_ptr + proc_info->status_code_pos));
    }

    http_req_span->end_time = end_time;

//    bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, http_req_span, sizeof(*http_req_span));
    stop_tracking_span(&http_req_span->sc, &http_req_span->psc);

    bpf_map_delete_elem(&http_events, &key);
    return 0;
}