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(&param->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(&param->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, &params[5]);
   165      case 5:
   166          parse_param(ctx, &params[4]);
   167      case 4:
   168          parse_param(ctx, &params[3]);
   169      case 3:
   170          parse_param(ctx, &params[2]);
   171      case 2:
   172          parse_param(ctx, &params[1]);
   173      case 1:
   174          parse_param(ctx, &params[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";