github.com/cnboonhan/delve@v0.0.0-20230908061759-363f2388c2fb/pkg/proc/internal/ebpf/bpf/trace.bpf.c (about) 1 #include "include/trace.bpf.h" 2 3 #define STRING_KIND 24 4 5 // parse_string_param will parse a string parameter. The parsed value of the string 6 // will be put into param->deref_val. This function expects the string struct 7 // which contains a pointer to the string and the length of the string to have 8 // already been read from memory and passed in as param->val. 9 __always_inline 10 int parse_string_param(struct pt_regs *ctx, function_parameter_t *param) { 11 u64 str_len; 12 size_t str_addr; 13 14 __builtin_memcpy(&str_addr, param->val, sizeof(str_addr)); 15 __builtin_memcpy(&str_len, param->val + sizeof(str_addr), sizeof(str_len)); 16 param->daddr = str_addr; 17 18 if (str_addr != 0) { 19 if (str_len > 0x30) { 20 str_len = 0x30; 21 } 22 int ret = bpf_probe_read_user(¶m->deref_val, str_len, (void *)(str_addr)); 23 if (ret < 0) { 24 return 1; 25 } 26 } 27 return 0; 28 } 29 30 __always_inline 31 int parse_param_stack(struct pt_regs *ctx, function_parameter_t *param) { 32 long ret; 33 size_t addr = ctx->sp + param->offset; 34 ret = bpf_probe_read_user(¶m->val, param->size, (void *)(addr)); 35 if (ret < 0) { 36 return 1; 37 } 38 return 0; 39 } 40 41 __always_inline 42 void get_value_from_register(struct pt_regs *ctx, void *dest, int reg_num) { 43 switch (reg_num) { 44 case 0: // RAX 45 __builtin_memcpy(dest, &ctx->ax, sizeof(ctx->ax)); 46 break; 47 case 1: // RDX 48 __builtin_memcpy(dest, &ctx->dx, sizeof(ctx->dx)); 49 break; 50 case 2: // RCX 51 __builtin_memcpy(dest, &ctx->cx, sizeof(ctx->cx)); 52 break; 53 case 3: // RBX 54 __builtin_memcpy(dest, &ctx->bx, sizeof(ctx->bx)); 55 break; 56 case 4: // RSI 57 __builtin_memcpy(dest, &ctx->si, sizeof(ctx->si)); 58 break; 59 case 5: // RDI 60 __builtin_memcpy(dest, &ctx->di, sizeof(ctx->di)); 61 break; 62 case 6: // RBP 63 __builtin_memcpy(dest, &ctx->bp, sizeof(ctx->bp)); 64 break; 65 case 7: // RSP 66 __builtin_memcpy(dest, &ctx->sp, sizeof(ctx->sp)); 67 break; 68 case 8: // R8 69 __builtin_memcpy(dest, &ctx->r8, sizeof(ctx->r8)); 70 break; 71 case 9: // R9 72 __builtin_memcpy(dest, &ctx->r9, sizeof(ctx->r9)); 73 break; 74 case 10: // R10 75 __builtin_memcpy(dest, &ctx->r10, sizeof(ctx->r10)); 76 break; 77 case 11: // R11 78 __builtin_memcpy(dest, &ctx->r11, sizeof(ctx->r11)); 79 break; 80 case 12: // R12 81 __builtin_memcpy(dest, &ctx->r12, sizeof(ctx->r12)); 82 break; 83 case 13: // R13 84 __builtin_memcpy(dest, &ctx->r13, sizeof(ctx->r13)); 85 break; 86 case 14: // R14 87 __builtin_memcpy(dest, &ctx->r14, sizeof(ctx->r14)); 88 break; 89 case 15: // R15 90 __builtin_memcpy(dest, &ctx->r15, sizeof(ctx->r15)); 91 break; 92 } 93 } 94 95 __always_inline 96 int parse_param_registers(struct pt_regs *ctx, function_parameter_t *param) { 97 switch (param->n_pieces) { 98 case 6: 99 get_value_from_register(ctx, param->val+40, param->reg_nums[5]); 100 case 5: 101 get_value_from_register(ctx, param->val+32, param->reg_nums[4]); 102 case 4: 103 get_value_from_register(ctx, param->val+24, param->reg_nums[3]); 104 case 3: 105 get_value_from_register(ctx, param->val+16, param->reg_nums[2]); 106 case 2: 107 get_value_from_register(ctx, param->val+8, param->reg_nums[1]); 108 case 1: 109 get_value_from_register(ctx, param->val, param->reg_nums[0]); 110 } 111 return 0; 112 } 113 114 __always_inline 115 int parse_param(struct pt_regs *ctx, function_parameter_t *param) { 116 if (param->size > 0x30) { 117 return 0; 118 } 119 120 // Parse the initial value of the parameter. 121 // If the parameter is a basic type, we will be finished here. 122 // If the parameter is a more complex type such as a string or 123 // a slice we will need some further processing below. 124 int ret = 0; 125 if (param->in_reg) { 126 ret = parse_param_registers(ctx, param); 127 } else { 128 ret = parse_param_stack(ctx, param); 129 } 130 if (ret != 0) { 131 return ret; 132 } 133 134 switch (param->kind) { 135 case STRING_KIND: 136 return parse_string_param(ctx, param); 137 } 138 139 return 0; 140 } 141 142 __always_inline 143 int get_goroutine_id(function_parameter_list_t *parsed_args) { 144 struct task_struct *task; 145 size_t g_addr; 146 __u64 goid; 147 148 // Get the current task. 149 task = (struct task_struct *)bpf_get_current_task(); 150 // Get the Goroutine ID which is stored in thread local storage. 151 bpf_probe_read_user(&g_addr, sizeof(void *), (void*)(BPF_CORE_READ(task, thread.fsbase)+parsed_args->g_addr_offset)); 152 bpf_probe_read_user(&goid, sizeof(void *), (void*)(g_addr+parsed_args->goid_offset)); 153 parsed_args->goroutine_id = goid; 154 155 return 1; 156 } 157 158 __always_inline 159 void parse_params(struct pt_regs *ctx, unsigned int n_params, function_parameter_t params[6]) { 160 // Since we cannot loop in eBPF programs let's take adavantage of the 161 // fact that in C switch cases will pass through automatically. 162 switch (n_params) { 163 case 6: 164 parse_param(ctx, ¶ms[5]); 165 case 5: 166 parse_param(ctx, ¶ms[4]); 167 case 4: 168 parse_param(ctx, ¶ms[3]); 169 case 3: 170 parse_param(ctx, ¶ms[2]); 171 case 2: 172 parse_param(ctx, ¶ms[1]); 173 case 1: 174 parse_param(ctx, ¶ms[0]); 175 } 176 } 177 178 SEC("uprobe/dlv_trace") 179 int uprobe__dlv_trace(struct pt_regs *ctx) { 180 function_parameter_list_t *args; 181 function_parameter_list_t *parsed_args; 182 uint64_t key = ctx->ip; 183 184 args = bpf_map_lookup_elem(&arg_map, &key); 185 if (!args) { 186 return 1; 187 } 188 189 parsed_args = bpf_ringbuf_reserve(&events, sizeof(function_parameter_list_t), 0); 190 if (!parsed_args) { 191 return 1; 192 } 193 194 // Initialize the parsed_args struct. 195 parsed_args->goid_offset = args->goid_offset; 196 parsed_args->g_addr_offset = args->g_addr_offset; 197 parsed_args->goroutine_id = args->goroutine_id; 198 parsed_args->fn_addr = args->fn_addr; 199 parsed_args->n_parameters = args->n_parameters; 200 parsed_args->n_ret_parameters = args->n_ret_parameters; 201 parsed_args->is_ret = args->is_ret; 202 __builtin_memcpy(parsed_args->params, args->params, sizeof(args->params)); 203 __builtin_memcpy(parsed_args->ret_params, args->ret_params, sizeof(args->ret_params)); 204 205 if (!get_goroutine_id(parsed_args)) { 206 bpf_ringbuf_discard(parsed_args, 0); 207 return 1; 208 } 209 210 if (!args->is_ret) { 211 // In uprobe at function entry. 212 213 // Parse input parameters. 214 parse_params(ctx, args->n_parameters, parsed_args->params); 215 } else { 216 // We are now stopped at the RET instruction for this function. 217 218 // Parse output parameters. 219 parse_params(ctx, args->n_ret_parameters, parsed_args->ret_params); 220 } 221 222 bpf_ringbuf_submit(parsed_args, BPF_RB_FORCE_WAKEUP); 223 224 return 0; 225 } 226 227 char _license[] SEC("license") = "Dual MIT/GPL";