Branch data Line data Source code
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 : 0 : switch (code->size) { 10 : : case 1: 11 : 0 : *(u8 *)buf = (u8)val; 12 : : break; 13 : : case 2: 14 : 0 : *(u16 *)buf = (u16)val; 15 : : break; 16 : : case 4: 17 : 0 : *(u32 *)buf = (u32)val; 18 : : break; 19 : : case 8: 20 : : //TBD: 32bit signed 21 : 0 : *(u64 *)buf = (u64)val; 22 : : break; 23 : : default: 24 : 0 : *(unsigned long *)buf = val; 25 : : } 26 : : } 27 : : 28 : : static nokprobe_inline void 29 : : fetch_apply_bitfield(struct fetch_insn *code, void *buf) 30 : : { 31 : 0 : switch (code->basesize) { 32 : : case 1: 33 : 0 : *(u8 *)buf <<= code->lshift; 34 : 0 : *(u8 *)buf >>= code->rshift; 35 : : break; 36 : : case 2: 37 : 0 : *(u16 *)buf <<= code->lshift; 38 : 0 : *(u16 *)buf >>= code->rshift; 39 : : break; 40 : : case 4: 41 : 0 : *(u32 *)buf <<= code->lshift; 42 : 0 : *(u32 *)buf >>= code->rshift; 43 : : break; 44 : : case 8: 45 : 0 : *(u64 *)buf <<= code->lshift; 46 : 0 : *(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 : 0 : if (code->op == FETCH_OP_DEREF) { 84 : 0 : lval = val; 85 : 0 : ret = probe_mem_read(&val, (void *)val + code->offset, 86 : : sizeof(val)); 87 : 0 : } else if (code->op == FETCH_OP_UDEREF) { 88 : 0 : lval = val; 89 : 0 : ret = probe_mem_read_user(&val, 90 : 0 : (void *)val + code->offset, sizeof(val)); 91 : : } else 92 : : break; 93 : 0 : if (ret) 94 : 0 : return ret; 95 : 0 : code++; 96 : : } while (1); 97 : : 98 : : s3 = code; 99 : : stage3: 100 : : /* 3rd stage: store value to buffer */ 101 : 0 : if (unlikely(!dest)) { 102 : 0 : if (code->op == FETCH_OP_ST_STRING) { 103 : 0 : ret = fetch_store_strlen(val + code->offset); 104 : 0 : code++; 105 : : goto array; 106 : 0 : } else if (code->op == FETCH_OP_ST_USTRING) { 107 : 0 : ret += fetch_store_strlen_user(val + code->offset); 108 : 0 : code++; 109 : : goto array; 110 : : } else 111 : : return -EILSEQ; 112 : : } 113 : : 114 : 0 : switch (code->op) { 115 : : case FETCH_OP_ST_RAW: 116 : 0 : fetch_store_raw(val, code, dest); 117 : : break; 118 : : case FETCH_OP_ST_MEM: 119 : 0 : probe_mem_read(dest, (void *)val + code->offset, code->size); 120 : : break; 121 : : case FETCH_OP_ST_UMEM: 122 : 0 : probe_mem_read_user(dest, (void *)val + code->offset, code->size); 123 : : break; 124 : : case FETCH_OP_ST_STRING: 125 : 0 : loc = *(u32 *)dest; 126 : 0 : ret = fetch_store_string(val + code->offset, dest, base); 127 : : break; 128 : : case FETCH_OP_ST_USTRING: 129 : 0 : loc = *(u32 *)dest; 130 : 0 : ret = fetch_store_string_user(val + code->offset, dest, base); 131 : : break; 132 : : default: 133 : : return -EILSEQ; 134 : : } 135 : 0 : code++; 136 : : 137 : : /* 4th stage: modify stored value if needed */ 138 : 0 : if (code->op == FETCH_OP_MOD_BF) { 139 : : fetch_apply_bitfield(code, dest); 140 : 0 : code++; 141 : : } 142 : : 143 : : array: 144 : : /* the last stage: Loop on array */ 145 : 0 : if (code->op == FETCH_OP_LP_ARRAY) { 146 : 0 : total += ret; 147 : 0 : if (++i < code->param) { 148 : : code = s3; 149 : 0 : if (s3->op != FETCH_OP_ST_STRING && 150 : : s3->op != FETCH_OP_ST_USTRING) { 151 : 0 : dest += s3->size; 152 : 0 : val += s3->size; 153 : : goto stage3; 154 : : } 155 : 0 : code--; 156 : 0 : val = lval + sizeof(char *); 157 : 0 : if (dest) { 158 : 0 : dest += sizeof(u32); 159 : 0 : *(u32 *)dest = update_data_loc(loc, ret); 160 : : } 161 : : goto stage2; 162 : : } 163 : 0 : code++; 164 : 0 : ret = total; 165 : : } 166 : : 167 : 0 : 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 : 0 : for (i = 0; i < tp->nr_args; i++) { 178 : : arg = tp->args + i; 179 : 0 : if (unlikely(arg->dynamic)) { 180 : 0 : len = process_fetch_insn(arg->code, regs, NULL, NULL); 181 : 0 : if (len > 0) 182 : 0 : ret += len; 183 : : } 184 : : } 185 : : 186 : 0 : 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 : 0 : void *dyndata = data + tp->size; 197 : : u32 *dl; /* Data location */ 198 : : int ret, i; 199 : : 200 : 0 : for (i = 0; i < tp->nr_args; i++) { 201 : : arg = tp->args + i; 202 : 0 : dl = data + arg->offset; 203 : : /* Point the dynamic data area if needed */ 204 : 0 : if (unlikely(arg->dynamic)) 205 : 0 : *dl = make_data_loc(maxlen, dyndata - base); 206 : 0 : ret = process_fetch_insn(arg->code, regs, dl, base); 207 : 0 : if (unlikely(ret < 0 && arg->dynamic)) { 208 : 0 : *dl = make_data_loc(0, dyndata - base); 209 : : } else { 210 : 0 : dyndata += ret; 211 : 0 : maxlen -= ret; 212 : : } 213 : : } 214 : : } 215 : : 216 : : static inline int 217 : 0 : 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 : 0 : for (i = 0; i < nr_args; i++) { 224 : 0 : struct probe_arg *a = args + i; 225 : : 226 : 0 : trace_seq_printf(s, " %s=", a->name); 227 : 0 : if (likely(!a->count)) { 228 : 0 : if (!a->type->print(s, data + a->offset, field)) 229 : : return -ENOMEM; 230 : 0 : continue; 231 : : } 232 : 0 : trace_seq_putc(s, '{'); 233 : 0 : p = data + a->offset; 234 : 0 : for (j = 0; j < a->count; j++) { 235 : 0 : if (!a->type->print(s, p, field)) 236 : : return -ENOMEM; 237 : 0 : trace_seq_putc(s, j == a->count - 1 ? '}' : ','); 238 : 0 : p += a->type->size; 239 : : } 240 : : } 241 : : return 0; 242 : : }