root/kernel/trace/trace_probe_tmpl.h

/* [<][>][^][v][top][bottom][index][help] */

INCLUDED FROM


DEFINITIONS

This source file includes following definitions.
  1. fetch_store_raw
  2. fetch_apply_bitfield
  3. process_fetch_insn_bottom
  4. __get_data_size
  5. store_trace_args
  6. print_probe_args

   1 /* SPDX-License-Identifier: GPL-2.0 */
   2 /*
   3  * Traceprobe fetch helper inlines
   4  */
   5 
   6 static nokprobe_inline void
   7 fetch_store_raw(unsigned long val, struct fetch_insn *code, void *buf)
   8 {
   9         switch (code->size) {
  10         case 1:
  11                 *(u8 *)buf = (u8)val;
  12                 break;
  13         case 2:
  14                 *(u16 *)buf = (u16)val;
  15                 break;
  16         case 4:
  17                 *(u32 *)buf = (u32)val;
  18                 break;
  19         case 8:
  20                 //TBD: 32bit signed
  21                 *(u64 *)buf = (u64)val;
  22                 break;
  23         default:
  24                 *(unsigned long *)buf = val;
  25         }
  26 }
  27 
  28 static nokprobe_inline void
  29 fetch_apply_bitfield(struct fetch_insn *code, void *buf)
  30 {
  31         switch (code->basesize) {
  32         case 1:
  33                 *(u8 *)buf <<= code->lshift;
  34                 *(u8 *)buf >>= code->rshift;
  35                 break;
  36         case 2:
  37                 *(u16 *)buf <<= code->lshift;
  38                 *(u16 *)buf >>= code->rshift;
  39                 break;
  40         case 4:
  41                 *(u32 *)buf <<= code->lshift;
  42                 *(u32 *)buf >>= code->rshift;
  43                 break;
  44         case 8:
  45                 *(u64 *)buf <<= code->lshift;
  46                 *(u64 *)buf >>= code->rshift;
  47                 break;
  48         }
  49 }
  50 
  51 /*
  52  * These functions must be defined for each callsite.
  53  * Return consumed dynamic data size (>= 0), or error (< 0).
  54  * If dest is NULL, don't store result and return required dynamic data size.
  55  */
  56 static int
  57 process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs,
  58                    void *dest, void *base);
  59 static nokprobe_inline int fetch_store_strlen(unsigned long addr);
  60 static nokprobe_inline int
  61 fetch_store_string(unsigned long addr, void *dest, void *base);
  62 static nokprobe_inline int fetch_store_strlen_user(unsigned long addr);
  63 static nokprobe_inline int
  64 fetch_store_string_user(unsigned long addr, void *dest, void *base);
  65 static nokprobe_inline int
  66 probe_mem_read(void *dest, void *src, size_t size);
  67 static nokprobe_inline int
  68 probe_mem_read_user(void *dest, void *src, size_t size);
  69 
  70 /* From the 2nd stage, routine is same */
  71 static nokprobe_inline int
  72 process_fetch_insn_bottom(struct fetch_insn *code, unsigned long val,
  73                            void *dest, void *base)
  74 {
  75         struct fetch_insn *s3 = NULL;
  76         int total = 0, ret = 0, i = 0;
  77         u32 loc = 0;
  78         unsigned long lval = val;
  79 
  80 stage2:
  81         /* 2nd stage: dereference memory if needed */
  82         do {
  83                 if (code->op == FETCH_OP_DEREF) {
  84                         lval = val;
  85                         ret = probe_mem_read(&val, (void *)val + code->offset,
  86                                              sizeof(val));
  87                 } else if (code->op == FETCH_OP_UDEREF) {
  88                         lval = val;
  89                         ret = probe_mem_read_user(&val,
  90                                  (void *)val + code->offset, sizeof(val));
  91                 } else
  92                         break;
  93                 if (ret)
  94                         return ret;
  95                 code++;
  96         } while (1);
  97 
  98         s3 = code;
  99 stage3:
 100         /* 3rd stage: store value to buffer */
 101         if (unlikely(!dest)) {
 102                 if (code->op == FETCH_OP_ST_STRING) {
 103                         ret = fetch_store_strlen(val + code->offset);
 104                         code++;
 105                         goto array;
 106                 } else if (code->op == FETCH_OP_ST_USTRING) {
 107                         ret += fetch_store_strlen_user(val + code->offset);
 108                         code++;
 109                         goto array;
 110                 } else
 111                         return -EILSEQ;
 112         }
 113 
 114         switch (code->op) {
 115         case FETCH_OP_ST_RAW:
 116                 fetch_store_raw(val, code, dest);
 117                 break;
 118         case FETCH_OP_ST_MEM:
 119                 probe_mem_read(dest, (void *)val + code->offset, code->size);
 120                 break;
 121         case FETCH_OP_ST_UMEM:
 122                 probe_mem_read_user(dest, (void *)val + code->offset, code->size);
 123                 break;
 124         case FETCH_OP_ST_STRING:
 125                 loc = *(u32 *)dest;
 126                 ret = fetch_store_string(val + code->offset, dest, base);
 127                 break;
 128         case FETCH_OP_ST_USTRING:
 129                 loc = *(u32 *)dest;
 130                 ret = fetch_store_string_user(val + code->offset, dest, base);
 131                 break;
 132         default:
 133                 return -EILSEQ;
 134         }
 135         code++;
 136 
 137         /* 4th stage: modify stored value if needed */
 138         if (code->op == FETCH_OP_MOD_BF) {
 139                 fetch_apply_bitfield(code, dest);
 140                 code++;
 141         }
 142 
 143 array:
 144         /* the last stage: Loop on array */
 145         if (code->op == FETCH_OP_LP_ARRAY) {
 146                 total += ret;
 147                 if (++i < code->param) {
 148                         code = s3;
 149                         if (s3->op != FETCH_OP_ST_STRING &&
 150                             s3->op != FETCH_OP_ST_USTRING) {
 151                                 dest += s3->size;
 152                                 val += s3->size;
 153                                 goto stage3;
 154                         }
 155                         code--;
 156                         val = lval + sizeof(char *);
 157                         if (dest) {
 158                                 dest += sizeof(u32);
 159                                 *(u32 *)dest = update_data_loc(loc, ret);
 160                         }
 161                         goto stage2;
 162                 }
 163                 code++;
 164                 ret = total;
 165         }
 166 
 167         return code->op == FETCH_OP_END ? ret : -EILSEQ;
 168 }
 169 
 170 /* Sum up total data length for dynamic arraies (strings) */
 171 static nokprobe_inline int
 172 __get_data_size(struct trace_probe *tp, struct pt_regs *regs)
 173 {
 174         struct probe_arg *arg;
 175         int i, len, ret = 0;
 176 
 177         for (i = 0; i < tp->nr_args; i++) {
 178                 arg = tp->args + i;
 179                 if (unlikely(arg->dynamic)) {
 180                         len = process_fetch_insn(arg->code, regs, NULL, NULL);
 181                         if (len > 0)
 182                                 ret += len;
 183                 }
 184         }
 185 
 186         return ret;
 187 }
 188 
 189 /* Store the value of each argument */
 190 static nokprobe_inline void
 191 store_trace_args(void *data, struct trace_probe *tp, struct pt_regs *regs,
 192                  int header_size, int maxlen)
 193 {
 194         struct probe_arg *arg;
 195         void *base = data - header_size;
 196         void *dyndata = data + tp->size;
 197         u32 *dl;        /* Data location */
 198         int ret, i;
 199 
 200         for (i = 0; i < tp->nr_args; i++) {
 201                 arg = tp->args + i;
 202                 dl = data + arg->offset;
 203                 /* Point the dynamic data area if needed */
 204                 if (unlikely(arg->dynamic))
 205                         *dl = make_data_loc(maxlen, dyndata - base);
 206                 ret = process_fetch_insn(arg->code, regs, dl, base);
 207                 if (unlikely(ret < 0 && arg->dynamic)) {
 208                         *dl = make_data_loc(0, dyndata - base);
 209                 } else {
 210                         dyndata += ret;
 211                         maxlen -= ret;
 212                 }
 213         }
 214 }
 215 
 216 static inline int
 217 print_probe_args(struct trace_seq *s, struct probe_arg *args, int nr_args,
 218                  u8 *data, void *field)
 219 {
 220         void *p;
 221         int i, j;
 222 
 223         for (i = 0; i < nr_args; i++) {
 224                 struct probe_arg *a = args + i;
 225 
 226                 trace_seq_printf(s, " %s=", a->name);
 227                 if (likely(!a->count)) {
 228                         if (!a->type->print(s, data + a->offset, field))
 229                                 return -ENOMEM;
 230                         continue;
 231                 }
 232                 trace_seq_putc(s, '{');
 233                 p = data + a->offset;
 234                 for (j = 0; j < a->count; j++) {
 235                         if (!a->type->print(s, p, field))
 236                                 return -ENOMEM;
 237                         trace_seq_putc(s, j == a->count - 1 ? '}' : ',');
 238                         p += a->type->size;
 239                 }
 240         }
 241         return 0;
 242 }

/* [<][>][^][v][top][bottom][index][help] */