Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0 */
0002 /*
0003  * Traceprobe fetch helper inlines
0004  */
0005 
0006 static nokprobe_inline void
0007 fetch_store_raw(unsigned long val, struct fetch_insn *code, void *buf)
0008 {
0009     switch (code->size) {
0010     case 1:
0011         *(u8 *)buf = (u8)val;
0012         break;
0013     case 2:
0014         *(u16 *)buf = (u16)val;
0015         break;
0016     case 4:
0017         *(u32 *)buf = (u32)val;
0018         break;
0019     case 8:
0020         //TBD: 32bit signed
0021         *(u64 *)buf = (u64)val;
0022         break;
0023     default:
0024         *(unsigned long *)buf = val;
0025     }
0026 }
0027 
0028 static nokprobe_inline void
0029 fetch_apply_bitfield(struct fetch_insn *code, void *buf)
0030 {
0031     switch (code->basesize) {
0032     case 1:
0033         *(u8 *)buf <<= code->lshift;
0034         *(u8 *)buf >>= code->rshift;
0035         break;
0036     case 2:
0037         *(u16 *)buf <<= code->lshift;
0038         *(u16 *)buf >>= code->rshift;
0039         break;
0040     case 4:
0041         *(u32 *)buf <<= code->lshift;
0042         *(u32 *)buf >>= code->rshift;
0043         break;
0044     case 8:
0045         *(u64 *)buf <<= code->lshift;
0046         *(u64 *)buf >>= code->rshift;
0047         break;
0048     }
0049 }
0050 
0051 /*
0052  * These functions must be defined for each callsite.
0053  * Return consumed dynamic data size (>= 0), or error (< 0).
0054  * If dest is NULL, don't store result and return required dynamic data size.
0055  */
0056 static int
0057 process_fetch_insn(struct fetch_insn *code, void *rec,
0058            void *dest, void *base);
0059 static nokprobe_inline int fetch_store_strlen(unsigned long addr);
0060 static nokprobe_inline int
0061 fetch_store_string(unsigned long addr, void *dest, void *base);
0062 static nokprobe_inline int fetch_store_strlen_user(unsigned long addr);
0063 static nokprobe_inline int
0064 fetch_store_string_user(unsigned long addr, void *dest, void *base);
0065 static nokprobe_inline int
0066 probe_mem_read(void *dest, void *src, size_t size);
0067 static nokprobe_inline int
0068 probe_mem_read_user(void *dest, void *src, size_t size);
0069 
0070 /* From the 2nd stage, routine is same */
0071 static nokprobe_inline int
0072 process_fetch_insn_bottom(struct fetch_insn *code, unsigned long val,
0073                void *dest, void *base)
0074 {
0075     struct fetch_insn *s3 = NULL;
0076     int total = 0, ret = 0, i = 0;
0077     u32 loc = 0;
0078     unsigned long lval = val;
0079 
0080 stage2:
0081     /* 2nd stage: dereference memory if needed */
0082     do {
0083         if (code->op == FETCH_OP_DEREF) {
0084             lval = val;
0085             ret = probe_mem_read(&val, (void *)val + code->offset,
0086                          sizeof(val));
0087         } else if (code->op == FETCH_OP_UDEREF) {
0088             lval = val;
0089             ret = probe_mem_read_user(&val,
0090                  (void *)val + code->offset, sizeof(val));
0091         } else
0092             break;
0093         if (ret)
0094             return ret;
0095         code++;
0096     } while (1);
0097 
0098     s3 = code;
0099 stage3:
0100     /* 3rd stage: store value to buffer */
0101     if (unlikely(!dest)) {
0102         if (code->op == FETCH_OP_ST_STRING) {
0103             ret = fetch_store_strlen(val + code->offset);
0104             code++;
0105             goto array;
0106         } else if (code->op == FETCH_OP_ST_USTRING) {
0107             ret += fetch_store_strlen_user(val + code->offset);
0108             code++;
0109             goto array;
0110         } else
0111             return -EILSEQ;
0112     }
0113 
0114     switch (code->op) {
0115     case FETCH_OP_ST_RAW:
0116         fetch_store_raw(val, code, dest);
0117         break;
0118     case FETCH_OP_ST_MEM:
0119         probe_mem_read(dest, (void *)val + code->offset, code->size);
0120         break;
0121     case FETCH_OP_ST_UMEM:
0122         probe_mem_read_user(dest, (void *)val + code->offset, code->size);
0123         break;
0124     case FETCH_OP_ST_STRING:
0125         loc = *(u32 *)dest;
0126         ret = fetch_store_string(val + code->offset, dest, base);
0127         break;
0128     case FETCH_OP_ST_USTRING:
0129         loc = *(u32 *)dest;
0130         ret = fetch_store_string_user(val + code->offset, dest, base);
0131         break;
0132     default:
0133         return -EILSEQ;
0134     }
0135     code++;
0136 
0137     /* 4th stage: modify stored value if needed */
0138     if (code->op == FETCH_OP_MOD_BF) {
0139         fetch_apply_bitfield(code, dest);
0140         code++;
0141     }
0142 
0143 array:
0144     /* the last stage: Loop on array */
0145     if (code->op == FETCH_OP_LP_ARRAY) {
0146         total += ret;
0147         if (++i < code->param) {
0148             code = s3;
0149             if (s3->op != FETCH_OP_ST_STRING &&
0150                 s3->op != FETCH_OP_ST_USTRING) {
0151                 dest += s3->size;
0152                 val += s3->size;
0153                 goto stage3;
0154             }
0155             code--;
0156             val = lval + sizeof(char *);
0157             if (dest) {
0158                 dest += sizeof(u32);
0159                 *(u32 *)dest = update_data_loc(loc, ret);
0160             }
0161             goto stage2;
0162         }
0163         code++;
0164         ret = total;
0165     }
0166 
0167     return code->op == FETCH_OP_END ? ret : -EILSEQ;
0168 }
0169 
0170 /* Sum up total data length for dynamic arrays (strings) */
0171 static nokprobe_inline int
0172 __get_data_size(struct trace_probe *tp, struct pt_regs *regs)
0173 {
0174     struct probe_arg *arg;
0175     int i, len, ret = 0;
0176 
0177     for (i = 0; i < tp->nr_args; i++) {
0178         arg = tp->args + i;
0179         if (unlikely(arg->dynamic)) {
0180             len = process_fetch_insn(arg->code, regs, NULL, NULL);
0181             if (len > 0)
0182                 ret += len;
0183         }
0184     }
0185 
0186     return ret;
0187 }
0188 
0189 /* Store the value of each argument */
0190 static nokprobe_inline void
0191 store_trace_args(void *data, struct trace_probe *tp, void *rec,
0192          int header_size, int maxlen)
0193 {
0194     struct probe_arg *arg;
0195     void *base = data - header_size;
0196     void *dyndata = data + tp->size;
0197     u32 *dl;    /* Data location */
0198     int ret, i;
0199 
0200     for (i = 0; i < tp->nr_args; i++) {
0201         arg = tp->args + i;
0202         dl = data + arg->offset;
0203         /* Point the dynamic data area if needed */
0204         if (unlikely(arg->dynamic))
0205             *dl = make_data_loc(maxlen, dyndata - base);
0206         ret = process_fetch_insn(arg->code, rec, dl, base);
0207         if (unlikely(ret < 0 && arg->dynamic)) {
0208             *dl = make_data_loc(0, dyndata - base);
0209         } else {
0210             dyndata += ret;
0211             maxlen -= ret;
0212         }
0213     }
0214 }
0215 
0216 static inline int
0217 print_probe_args(struct trace_seq *s, struct probe_arg *args, int nr_args,
0218          u8 *data, void *field)
0219 {
0220     void *p;
0221     int i, j;
0222 
0223     for (i = 0; i < nr_args; i++) {
0224         struct probe_arg *a = args + i;
0225 
0226         trace_seq_printf(s, " %s=", a->name);
0227         if (likely(!a->count)) {
0228             if (!a->type->print(s, data + a->offset, field))
0229                 return -ENOMEM;
0230             continue;
0231         }
0232         trace_seq_putc(s, '{');
0233         p = data + a->offset;
0234         for (j = 0; j < a->count; j++) {
0235             if (!a->type->print(s, p, field))
0236                 return -ENOMEM;
0237             trace_seq_putc(s, j == a->count - 1 ? '}' : ',');
0238             p += a->type->size;
0239         }
0240     }
0241     return 0;
0242 }