grpc.client.probe.bpf.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522
  1. // Copyright The OpenTelemetry Authors
  2. // SPDX-License-Identifier: Apache-2.0
  3. #include "arguments.h"
  4. #include "span_context.h"
  5. #include "go_types.h"
  6. #include "go_context.h"
  7. #include "uprobe.h"
  8. // #define MAX_SIZE 50
  9. #define MAX_CONCURRENT 50
  10. #define MAX_ERROR_LEN 128
  11. // #define PROTOCOL_GRPC 15
  12. struct grpc_client_request_t {
  13. BASE_SPAN_PROPERTIES
  14. char err_msg[MAX_ERROR_LEN];
  15. char method[MAX_SIZE];
  16. char target[MAX_SIZE];
  17. u32 status_code;
  18. u64 method_size;
  19. u64 target_size;
  20. struct apm_span_context apm_sc;
  21. struct apm_span_context apm_psc;
  22. };
  23. // struct hpack_header_field {
  24. // struct go_string_ot name;
  25. // struct go_string_ot value;
  26. // bool sensitive;
  27. // };
  28. struct {
  29. __uint(type, BPF_MAP_TYPE_HASH);
  30. __type(key, void *);
  31. __type(value, struct grpc_client_request_t);
  32. __uint(max_entries, MAX_CONCURRENT);
  33. } grpc_client_events SEC(".maps");
  34. struct {
  35. __uint(type, BPF_MAP_TYPE_HASH);
  36. __type(key, u32);
  37. __type(value, struct apm_trace_key_t);
  38. __uint(max_entries, MAX_CONCURRENT);
  39. } streamid_to_span_contexts SEC(".maps");
  40. // 用于 ClientConn_Invoke 函数的临时存储,避免栈空间超限
  41. struct {
  42. __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
  43. __uint(key_size, sizeof(u32));
  44. __uint(value_size, sizeof(struct grpc_client_request_t));
  45. __uint(max_entries, 1);
  46. } grpc_client_storage_map SEC(".maps");
  47. // 用于 loopyWriter_headerHandler 的临时存储
  48. struct header_handler_storage {
  49. struct span_context sc;
  50. char val[CW_HEADER_VAL_LENGTH];
  51. struct hpack_header_field hf;
  52. };
  53. struct {
  54. __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
  55. __uint(key_size, sizeof(u32));
  56. __uint(value_size, sizeof(struct header_handler_storage));
  57. __uint(max_entries, 1);
  58. } header_handler_storage_map SEC(".maps");
  59. // Injected in init
  60. // volatile const u64 clientconn_target_ptr_pos;
  61. u64 clientconn_target_ptr_pos = 24; //使用固定值24即可,不再处理多版本场景。
  62. // volatile const u64 httpclient_nextid_pos;
  63. // u64 httpclient_nextid_pos = 404; //处理多版本,通过变量获取吧
  64. // volatile const u64 headerFrame_streamid_pos;
  65. u64 headerFrame_streamid_pos = 0; //使用固定值0即可,不再处理多版本场景。
  66. // volatile const u64 headerFrame_hf_pos;
  67. u64 headerFrame_hf_pos = 8; //使用固定值8即可,不再处理多版本场景。
  68. // volatile const u64 error_status_pos;
  69. u64 error_status_pos = 0; //使用固定值0即可,不再处理多版本场景。
  70. // volatile const u64 status_s_pos;
  71. // static u64 status_s_pos = 0;
  72. // volatile const u64 status_message_pos;
  73. u64 status_message_pos = 48; //使用固定值48即可,不再处理多版本场景。
  74. // volatile const u64 status_code_pos;
  75. // static u64 status_code_pos = 40;
  76. // volatile const bool write_status_supported;
  77. // This instrumentation attaches uprobe to the following function:
  78. // func (cc *ClientConn) Invoke(ctx context.Context, method string, args, reply interface{}, opts ...CallOption) error
  79. SEC("uprobe/ClientConn_Invoke")
  80. int uprobe_ClientConn_Invoke(struct pt_regs *ctx) {
  81. // cw_bpf_debug("enter the uprobe_ClientConn_Invoke \n");
  82. // positions
  83. u64 clientconn_pos = 1;
  84. u64 method_ptr_pos = 4;
  85. u64 method_len_pos = 5;
  86. // struct go_iface go_context = {0};
  87. // get_Go_context(ctx, 2, 0, true);
  88. void *context_ptr_val = get_Go_context(ctx, 2, 0, true);
  89. if (context_ptr_val == NULL)
  90. {
  91. return 0;
  92. }
  93. // Get key
  94. void *key = (void *)GOROUTINE(ctx);
  95. // cw_bpf_debug("enter the uprobe_ClientConn_Invoke key is 0x%llx\n", (u64)key);
  96. void *grpcReq_ptr = bpf_map_lookup_elem(&grpc_client_events, &key);
  97. if (grpcReq_ptr != NULL) {
  98. cw_bpf_debug("uprobe/ClientConn_Invoke already tracked with the current context");
  99. return 0;
  100. }
  101. // 使用 per-cpu array map 存储大变量,避免栈空间超限
  102. u32 zero = 0;
  103. struct grpc_client_request_t *grpcReq = bpf_map_lookup_elem(&grpc_client_storage_map, &zero);
  104. if (grpcReq == NULL) {
  105. cw_bpf_debug("grpc:client:ClientConn_Invoke: failed to get storage");
  106. return -1;
  107. }
  108. // 清零并初始化
  109. __builtin_memset(grpcReq, 0, sizeof(struct grpc_client_request_t));
  110. grpcReq->start_time = bpf_ktime_get_ns();
  111. // Read Method
  112. void *method_ptr = get_argument(ctx, method_ptr_pos);
  113. u64 method_len = (u64)get_argument(ctx, method_len_pos);
  114. u64 method_size = sizeof(grpcReq->method);
  115. method_size = method_size < method_len ? method_size : method_len;
  116. bpf_probe_read(&grpcReq->method, method_size, method_ptr);
  117. grpcReq->method_size = method_size;
  118. // Read ClientConn.Target
  119. void *clientconn_ptr = get_argument(ctx, clientconn_pos);
  120. if (!get_go_string_from_user_ptr((void *)(clientconn_ptr + clientconn_target_ptr_pos),
  121. grpcReq->target,
  122. sizeof(grpcReq->target))) {
  123. cw_bpf_debug("target write failed, aborting ebpf probe");
  124. return 0;
  125. }
  126. grpcReq->target_size = sizeof(grpcReq->target);
  127. struct apm_span_context *cw_psc = cw_get_parent_tracking_span();
  128. if(cw_psc){
  129. set_assumed_app_id_arrays(grpcReq->target, cw_psc->assumed_app_id, APM_ASSUMED_APP_ID_STRING_SIZE);
  130. cw_save_parent_tracking_span(cw_psc);
  131. }
  132. // cw_bpf_debug("grpcReq->target is %s\n", grpcReq->target);
  133. // start_span_params_t start_span_params = {
  134. // .ctx = ctx,
  135. // .go_context = &go_context,
  136. // .psc = &grpcReq->psc,
  137. // .sc = &grpcReq->sc,
  138. // .get_parent_span_context_fn = NULL,
  139. // .get_parent_span_context_arg = NULL,
  140. // };
  141. // start_span(&start_span_params);
  142. // Write event
  143. bpf_map_update_elem(&grpc_client_events, &key, grpcReq, 0);
  144. start_tracking_span(context_ptr_val, &grpcReq->sc);
  145. // cw_bpf_debug("enter the uprobe_ClientConn_Invoke start_tracking_span\n");
  146. return 0;
  147. }
  148. // This instrumentation attaches uprobe to the following function:
  149. // func (cc *ClientConn) Invoke(ctx context.Context, method string, args, reply interface{}, opts ...CallOption) error
  150. SEC("uprobe/ClientConn_Invoke")
  151. int uprobe_ClientConn_Invoke_Returns(struct pt_regs *ctx) {
  152. // cw_bpf_debug("enter the uprobe_ClientConn_Invoke_Returns \n");
  153. void *key = (void *)GOROUTINE(ctx);
  154. struct grpc_client_request_t *grpc_span = bpf_map_lookup_elem(&grpc_client_events, &key);
  155. if (grpc_span == NULL) {
  156. cw_bpf_debug("event is NULL in ret probe");
  157. return 0;
  158. }
  159. // if (!write_status_supported) {
  160. // goto done;
  161. // }
  162. // Getting the returned response (error)
  163. // The status code is embedded 3 layers deep:
  164. // Invoke() error
  165. // the `error` interface concrete type here is a gRPC `internal.Error` struct
  166. // type Error struct {
  167. // s *Status
  168. // }
  169. // The `Error` struct embeds a `Status` proto object
  170. // type Status struct {
  171. // s *Status
  172. // }
  173. // The `Status` proto object contains a `Code` int32 field, which is what we want
  174. // type Status struct {
  175. // Code int32
  176. // Message string
  177. // Details []*anypb.Any
  178. // }
  179. void *resp_ptr = get_argument(ctx, 2);
  180. if (resp_ptr == 0) {
  181. // err == nil
  182. goto done;
  183. }
  184. void *status_ptr = 0;
  185. // get `s` (Status pointer field) from Error struct
  186. bpf_probe_read_user(&status_ptr, sizeof(status_ptr), (void *)(resp_ptr + error_status_pos));
  187. // get `s` field from Status object pointer
  188. void *s_ptr = 0;
  189. bpf_probe_read_user(&s_ptr, sizeof(s_ptr), (void *)(status_ptr + status_s_pos));
  190. // Get status code from Status.s pointer
  191. bpf_probe_read_user(
  192. &grpc_span->status_code, sizeof(grpc_span->status_code), (void *)(s_ptr + status_code_pos));
  193. get_go_string_from_user_ptr(
  194. (void *)(s_ptr + status_message_pos), grpc_span->err_msg, sizeof(grpc_span->err_msg));
  195. done:
  196. // cw_bpf_debug("switch to the done position\n");
  197. grpc_span->end_time = bpf_ktime_get_ns();
  198. // output_span_event(ctx, grpc_span, sizeof(*grpc_span), &grpc_span->sc);
  199. stop_tracking_span(&grpc_span->sc, &grpc_span->psc);
  200. bpf_map_delete_elem(&grpc_client_events, &key);
  201. __u64 pid_tgid = bpf_get_current_pid_tgid();
  202. __u64 pid = pid_tgid >> 32;
  203. struct ebpf_proc_info *info = bpf_map_lookup_elem(&proc_info_map, &pid);
  204. if (!info) {
  205. return 0;
  206. }
  207. cw_bpf_debug("[Go] [uprobe/setNodeEnter]: proc_info_map::%ld, %d, %d\n", info->code_type);
  208. struct apm_trace_key_t trace_key = get_apm_trace_key(120 * NS_PER_SEC, true);
  209. struct apm_trace_info_t * trace_info = get_apm_trace_info_by_trace_key(trace_key);
  210. if (trace_info == NULL) {
  211. cw_bpf_debug("enter the trace_info is NULL\n");
  212. trace_info = get_apm_trace_info_v3(trace_key,pid_tgid, pid, pid_tgid);
  213. }
  214. u32 zero = 0;
  215. struct l7_event *e = bpf_map_lookup_elem(&l7_event_heap, &zero);
  216. if (!e) {
  217. return 0;
  218. }
  219. // e->fd = 0;
  220. // e->pid = pid;
  221. e->protocol = PROTOCOL_GRPC;
  222. e->trace_end = 0;
  223. e->trace_start = 0;
  224. // e->status = STATUS_UNKNOWN;
  225. // e->method = METHOD_GRPC;
  226. e->statement_id = 0;
  227. e->payload_size = grpc_span->method_size;
  228. if (trace_info) {
  229. // cw_bpf_debug("trace_info->trace_id is %llu\n", trace_info->trace_id);
  230. e->trace_id = trace_info->trace_id;
  231. }
  232. if(e->trace_id == 0){
  233. e->trace_id = get_apm_trace_id(pid,pid_tgid);
  234. cw_bpf_debug("e->trace_id is %llu\n", e->trace_id);
  235. }
  236. // 使用固定长度读取 target 信息,避免验证器复杂性
  237. if (grpc_span->target_size > 0) {
  238. // 使用固定的小长度来避免验证器问题
  239. u32 fixed_size = 32; // 固定32字节,足够大多数target
  240. if (grpc_span->target_size < fixed_size) {
  241. fixed_size = (u32)grpc_span->target_size;
  242. }
  243. bpf_probe_read(&e->rpc_target, fixed_size, grpc_span->target);
  244. }
  245. COPY_PAYLOAD(e->payload, grpc_span->method_size, grpc_span->method);
  246. // cw_bpf_debug("e->payload is %s\n", e->payload);
  247. // cw_bpf_debug("grpc_span->target is %s\n", grpc_span->target);
  248. // COPY_PAYLOAD(e->payload + grpc_span->method_size, grpc_span->target_size, grpc_span->target);
  249. // cw_bpf_debug("e->payload is %s\n", e->payload);
  250. // e->payload_size += grpc_span->target_size;
  251. struct apm_span_context * sc = cw_get_current_tracking_span(trace_info);
  252. if (sc) {
  253. cw_copy_byte_arrays(sc->assumed_app_id, e->assumed_app_id, APM_ASSUMED_APP_ID_SIZE);
  254. cw_copy_byte_arrays(sc->span_id, e->span_id, APM_SPAN_ID_SIZE);
  255. }
  256. e->end_at = bpf_ktime_get_ns();
  257. e->start_at = grpc_span->start_time;
  258. e->duration = e->end_at - e->start_at;
  259. // cw_bpf_debug("send_event trace_id is444 %llu\n", e->trace_id);
  260. long error = bpf_perf_event_output(ctx, &l7_events, BPF_F_CURRENT_CPU, e, sizeof(*e));
  261. if (error ==0){
  262. cw_add_event_count(e->trace_id);
  263. }
  264. // cw_bpf_debug("enter the uprobe_ClientConn_Invoke_Returns done\n");
  265. return 0;
  266. }
  267. static __always_inline void
  268. cw_append_item_to_slice(void *new_item, u32 item_size, void *slice_user_ptr) {
  269. // read the slice descriptor
  270. struct go_slice_ot slice = {0};
  271. long res = bpf_probe_read_user(&slice, sizeof(slice), slice_user_ptr);
  272. if (res != 0) {
  273. cw_bpf_debug("cw_append_item_to_slice: failed to read slice descriptor, res=%ld\n", res);
  274. return;
  275. }
  276. // cw_bpf_debug("cw_append_item_to_slice len is %d\n", slice.len);
  277. // cw_bpf_debug("cw_append_item_to_slice cap is %d\n", slice.cap);
  278. // cw_bpf_debug("cw_append_item_to_slice array is %p\n", slice.array);
  279. u64 slice_len = slice.len;
  280. u64 slice_cap = slice.cap;
  281. if (slice_len < slice_cap && slice.array != NULL) {
  282. // Room available on current array, append to the underlying array
  283. // cw_bpf_debug("enter the cw_append_item_to_slice11111\n");
  284. res = bpf_probe_write_user(slice.array + (item_size * slice_len), new_item, item_size);
  285. } else {
  286. // No room on current array - try to copy new one of size item_size * (len + 1)
  287. u32 alloc_size = item_size * slice_len;
  288. if (alloc_size >= MAX_SLICE_ARRAY_SIZE) {
  289. return;
  290. }
  291. // Get temporary buffer
  292. u32 index = 0;
  293. struct slice_array_buff *map_buff = bpf_map_lookup_elem(&slice_array_buff_map, &index);
  294. if (!map_buff) {
  295. return;
  296. }
  297. unsigned char *new_slice_array = map_buff->buff;
  298. // help the verifier
  299. alloc_size &= (MAX_SLICE_ARRAY_SIZE - 1);
  300. if (alloc_size + item_size > MAX_SLICE_ARRAY_SIZE) {
  301. // No room for new item
  302. return;
  303. }
  304. // Append to buffer
  305. if (slice.array != NULL) {
  306. bpf_probe_read_user(new_slice_array, alloc_size, slice.array);
  307. // cw_bpf_debug("append_item_to_slice: copying %d bytes to new array from address 0x%llx",
  308. // alloc_size,
  309. // slice.array);
  310. }
  311. copy_byte_arrays(new_item, new_slice_array + alloc_size, item_size);
  312. // Copy buffer to userspace
  313. u32 new_array_size = alloc_size + item_size;
  314. void *new_array = write_target_data(new_slice_array, new_array_size);
  315. if (new_array == NULL) {
  316. cw_bpf_debug("append_item_to_slice: failed to copy new array to userspace");
  317. return;
  318. }
  319. // Update array pointer of slice
  320. slice.array = new_array;
  321. slice.cap++;
  322. // cw_bpf_debug("enter the cw_append_item_to_slice222222\n");
  323. }
  324. // Update len
  325. slice.len++;
  326. // cw_bpf_debug("after cw_append_item_to_slice len is %d\n", slice.len);
  327. long success = bpf_probe_write_user(slice_user_ptr, &slice, sizeof(slice));
  328. if (success != 0) {
  329. cw_bpf_debug("append_item_to_slice: failed to update slice in userspace");
  330. return;
  331. }
  332. }
  333. SEC("uprobe/loopyWriter_headerHandler")
  334. int uprobe_LoopyWriter_HeaderHandler(struct pt_regs *ctx) {
  335. void *headerFrame_ptr = get_argument(ctx, 2);
  336. // cw_bpf_debug("enter the get header handler storage\n");
  337. __u64 pid_tgid = bpf_get_current_pid_tgid();
  338. __u32 tgid = pid_tgid >> 32;
  339. struct ebpf_proc_info *proc_info =
  340. bpf_map_lookup_elem(&proc_info_map, &tgid);
  341. if(!proc_info)
  342. {
  343. return 0;
  344. }
  345. u32 stream_id = 0;
  346. bpf_probe_read(
  347. &stream_id, sizeof(stream_id), (void *)(headerFrame_ptr + (headerFrame_streamid_pos)));
  348. struct apm_trace_key_t *sc_ptr = bpf_map_lookup_elem(&streamid_to_span_contexts, &stream_id);
  349. if (sc_ptr == NULL) {
  350. bpf_map_delete_elem(&streamid_to_span_contexts, &stream_id);
  351. return 0;
  352. }
  353. // Get storage from per-cpu map
  354. u32 zero = 0;
  355. struct header_handler_storage *storage = bpf_map_lookup_elem(&header_handler_storage_map, &zero);
  356. if (!storage) {
  357. bpf_map_delete_elem(&streamid_to_span_contexts, &stream_id);
  358. cw_bpf_debug("Failed to get header handler storage\n");
  359. return 0;
  360. }
  361. // Generate span context
  362. generate_random_bytes(storage->sc.TraceID, TRACE_ID_SIZE);
  363. generate_random_bytes(storage->sc.SpanID, SPAN_ID_SIZE);
  364. u32 map_id = 0;
  365. struct grpc_client_request_t *grpcClientReq = bpf_map_lookup_elem(&grpc_client_storage_map, &map_id);
  366. if (grpcClientReq == NULL)
  367. {
  368. bpf_map_delete_elem(&streamid_to_span_contexts, &stream_id);
  369. cw_bpf_debug("uprobe_LoopyWriter_HeaderHandler: grpcClientReq is NULL");
  370. return 0;
  371. }
  372. __builtin_memset(grpcClientReq, 0, sizeof(struct grpc_client_request_t));
  373. grpcClientReq->start_time = bpf_ktime_get_ns();
  374. // cw_bpf_debug("enter the uprobe_LoopyWriter_HeaderHandler444444\n");
  375. // struct apm_span_context *cw_psc = cw_get_parent_tracking_span();
  376. struct apm_span_context *cw_psc = cw_get_parent_tracking_span_by_trace_key(*sc_ptr);
  377. if(cw_psc){
  378. bpf_probe_read(&grpcClientReq->apm_psc, sizeof(grpcClientReq->apm_psc), cw_psc);
  379. copy_byte_arrays(grpcClientReq->apm_psc.trace_id, grpcClientReq->apm_sc.trace_id, APM_TRACE_ID_SIZE);
  380. generate_random_bytes(grpcClientReq->apm_sc.span_id, APM_SPAN_ID_SIZE);
  381. copy_byte_arrays(grpcClientReq->apm_psc.assumed_app_id, grpcClientReq->apm_sc.assumed_app_id, APM_ASSUMED_APP_ID_SIZE);
  382. }
  383. bpf_map_delete_elem(&streamid_to_span_contexts, &stream_id);
  384. u32 k0 = 0;
  385. struct trace_conf_t *trace_conf = trace_conf_map__lookup(&k0);
  386. if (trace_conf) {
  387. copy_byte_arrays(trace_conf->host_id, grpcClientReq->apm_sc.host_id, APM_HOST_ID_SIZE);
  388. }
  389. copy_byte_arrays(proc_info->instance_id, grpcClientReq->apm_sc.instance_id, APM_APP_ID_SIZE);
  390. copy_byte_arrays(proc_info->app_id, grpcClientReq->apm_sc.app_id, APM_APP_ID_SIZE);
  391. // cw_bpf_debug("grpcClientReq->apm_sc.app_id is %s\n", grpcClientReq->apm_sc.app_id);
  392. bpf_map_update_elem(&apm_current_span_context_map, sc_ptr, &grpcClientReq->apm_sc, BPF_ANY);
  393. // cw_save_current_tracking_span(&grpcClientReq->apm_sc);
  394. // Strategy: Write key and value separately using write_target_data
  395. // Both key and value can use write_target_data as it automatically manages memory allocation
  396. // First write the key
  397. char tp_key[CW_HEADER_KEY_LENGTH] = CW_HEADER_KEY_VAL;
  398. char *key_data_addr = cw_write_target_data((void *)tp_key, sizeof(tp_key), proc_info);
  399. if (key_data_addr == NULL) {
  400. cw_bpf_debug("Key data write failed\n");
  401. return 0;
  402. }
  403. // Prepare and write the value
  404. char val[CW_HEADER_VAL_LENGTH];
  405. __builtin_memset(val, 0, sizeof(val));
  406. span_context_to_cw_string(&grpcClientReq->apm_sc, val);
  407. // Write value using cw_write_target_data (it will automatically allocate next available position)
  408. char *val_data_addr = cw_write_target_data((void *)val, sizeof(val), proc_info);
  409. if (val_data_addr == NULL) {
  410. cw_bpf_debug("Val data write failed\n");
  411. return 0;
  412. }
  413. struct go_string_ot key_str = {.str = key_data_addr, .len = sizeof(tp_key)};
  414. struct go_string_ot val_str = {.str = val_data_addr, .len = sizeof(val)};
  415. // Build header field
  416. storage->hf.name = key_str;
  417. storage->hf.value = val_str;
  418. storage->hf.sensitive = false;
  419. // Append to slice
  420. void *slice_ptr = (void *)(headerFrame_ptr + headerFrame_hf_pos);
  421. cw_append_item_to_slice(&storage->hf, sizeof(storage->hf), slice_ptr);
  422. return 0;
  423. }
  424. SEC("uprobe/http2Client_NewStream")
  425. // func (t *http2Client) NewStream(ctx context.Context, callHdr *CallHdr) (*Stream, error)
  426. int uprobe_http2Client_NewStream(struct pt_regs *ctx) {
  427. // cw_bpf_debug("enter the uprobe_http2Client_NewStream \n");
  428. __u32 tgid = (__u32)(bpf_get_current_pid_tgid() >> 32);
  429. struct ebpf_proc_info *info =
  430. bpf_map_lookup_elem(&proc_info_map, &tgid);
  431. if (!info) {
  432. return -1;
  433. }
  434. // cw_bpf_debug("info->httpclient_nextid_pos is %d\n", info->httpclient_nextid_pos);
  435. struct go_iface go_context = {0};
  436. get_Go_context(ctx, 2, 0, true);
  437. void *httpclient_ptr = get_argument(ctx, 1);
  438. u32 nextid = 0;
  439. bpf_probe_read(&nextid, sizeof(nextid), (void *)(httpclient_ptr + (info->httpclient_nextid_pos)));
  440. // Get the span context from go context. The mapping is created in the Invoke probe,
  441. // the context here is derived from the Invoke context.
  442. // struct span_context *current_span_context = get_parent_span_context(&go_context);
  443. struct apm_trace_key_t trace_key = get_apm_trace_key(120 * NS_PER_SEC, true);
  444. bpf_map_update_elem(&streamid_to_span_contexts, &nextid, &trace_key, 0);
  445. return 0;
  446. }