Masami Hiramatsu | 5330592 | 2018-04-25 21:18:03 +0900 | [diff] [blame] | 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 | |
Masami Hiramatsu | 9178412 | 2018-04-25 21:19:01 +0900 | [diff] [blame] | 51 | /* |
Masami Hiramatsu | 9b960a3 | 2018-04-25 21:19:59 +0900 | [diff] [blame] | 52 | * These functions must be defined for each callsite. |
Masami Hiramatsu | 9178412 | 2018-04-25 21:19:01 +0900 | [diff] [blame] | 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 | */ |
Masami Hiramatsu | 5330592 | 2018-04-25 21:18:03 +0900 | [diff] [blame] | 56 | static int |
Steven Rostedt (VMware) | 8565a45 | 2021-08-19 00:13:28 -0400 | [diff] [blame] | 57 | process_fetch_insn(struct fetch_insn *code, void *rec, |
Masami Hiramatsu | 9178412 | 2018-04-25 21:19:01 +0900 | [diff] [blame] | 58 | void *dest, void *base); |
Masami Hiramatsu | 9b960a3 | 2018-04-25 21:19:59 +0900 | [diff] [blame] | 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); |
Masami Hiramatsu | 88903c4 | 2019-05-15 14:38:30 +0900 | [diff] [blame] | 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); |
Masami Hiramatsu | 9b960a3 | 2018-04-25 21:19:59 +0900 | [diff] [blame] | 65 | static nokprobe_inline int |
| 66 | probe_mem_read(void *dest, void *src, size_t size); |
Masami Hiramatsu | e65f7ae | 2019-05-15 14:38:42 +0900 | [diff] [blame] | 67 | static nokprobe_inline int |
| 68 | probe_mem_read_user(void *dest, void *src, size_t size); |
Masami Hiramatsu | 9b960a3 | 2018-04-25 21:19:59 +0900 | [diff] [blame] | 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 | { |
Masami Hiramatsu | 40b53b7 | 2018-04-25 21:21:55 +0900 | [diff] [blame] | 75 | struct fetch_insn *s3 = NULL; |
| 76 | int total = 0, ret = 0, i = 0; |
| 77 | u32 loc = 0; |
| 78 | unsigned long lval = val; |
Masami Hiramatsu | 9b960a3 | 2018-04-25 21:19:59 +0900 | [diff] [blame] | 79 | |
Masami Hiramatsu | 40b53b7 | 2018-04-25 21:21:55 +0900 | [diff] [blame] | 80 | stage2: |
Masami Hiramatsu | 9b960a3 | 2018-04-25 21:19:59 +0900 | [diff] [blame] | 81 | /* 2nd stage: dereference memory if needed */ |
Masami Hiramatsu | e65f7ae | 2019-05-15 14:38:42 +0900 | [diff] [blame] | 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; |
Masami Hiramatsu | 9b960a3 | 2018-04-25 21:19:59 +0900 | [diff] [blame] | 93 | if (ret) |
| 94 | return ret; |
| 95 | code++; |
Masami Hiramatsu | e65f7ae | 2019-05-15 14:38:42 +0900 | [diff] [blame] | 96 | } while (1); |
Masami Hiramatsu | 9b960a3 | 2018-04-25 21:19:59 +0900 | [diff] [blame] | 97 | |
Masami Hiramatsu | 40b53b7 | 2018-04-25 21:21:55 +0900 | [diff] [blame] | 98 | s3 = code; |
| 99 | stage3: |
Masami Hiramatsu | 9b960a3 | 2018-04-25 21:19:59 +0900 | [diff] [blame] | 100 | /* 3rd stage: store value to buffer */ |
| 101 | if (unlikely(!dest)) { |
Masami Hiramatsu | 40b53b7 | 2018-04-25 21:21:55 +0900 | [diff] [blame] | 102 | if (code->op == FETCH_OP_ST_STRING) { |
Masami Hiramatsu | 489fe00 | 2019-05-07 22:55:52 +0900 | [diff] [blame] | 103 | ret = fetch_store_strlen(val + code->offset); |
Masami Hiramatsu | 40b53b7 | 2018-04-25 21:21:55 +0900 | [diff] [blame] | 104 | code++; |
| 105 | goto array; |
Masami Hiramatsu | 88903c4 | 2019-05-15 14:38:30 +0900 | [diff] [blame] | 106 | } else if (code->op == FETCH_OP_ST_USTRING) { |
| 107 | ret += fetch_store_strlen_user(val + code->offset); |
| 108 | code++; |
| 109 | goto array; |
Masami Hiramatsu | 40b53b7 | 2018-04-25 21:21:55 +0900 | [diff] [blame] | 110 | } else |
Masami Hiramatsu | 9b960a3 | 2018-04-25 21:19:59 +0900 | [diff] [blame] | 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; |
Masami Hiramatsu | e65f7ae | 2019-05-15 14:38:42 +0900 | [diff] [blame] | 121 | case FETCH_OP_ST_UMEM: |
| 122 | probe_mem_read_user(dest, (void *)val + code->offset, code->size); |
| 123 | break; |
Masami Hiramatsu | 9b960a3 | 2018-04-25 21:19:59 +0900 | [diff] [blame] | 124 | case FETCH_OP_ST_STRING: |
Masami Hiramatsu | 40b53b7 | 2018-04-25 21:21:55 +0900 | [diff] [blame] | 125 | loc = *(u32 *)dest; |
Masami Hiramatsu | 9b960a3 | 2018-04-25 21:19:59 +0900 | [diff] [blame] | 126 | ret = fetch_store_string(val + code->offset, dest, base); |
| 127 | break; |
Masami Hiramatsu | 88903c4 | 2019-05-15 14:38:30 +0900 | [diff] [blame] | 128 | case FETCH_OP_ST_USTRING: |
| 129 | loc = *(u32 *)dest; |
| 130 | ret = fetch_store_string_user(val + code->offset, dest, base); |
| 131 | break; |
Masami Hiramatsu | 9b960a3 | 2018-04-25 21:19:59 +0900 | [diff] [blame] | 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 | |
Masami Hiramatsu | 40b53b7 | 2018-04-25 21:21:55 +0900 | [diff] [blame] | 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; |
Masami Hiramatsu | 88903c4 | 2019-05-15 14:38:30 +0900 | [diff] [blame] | 149 | if (s3->op != FETCH_OP_ST_STRING && |
| 150 | s3->op != FETCH_OP_ST_USTRING) { |
Masami Hiramatsu | 40b53b7 | 2018-04-25 21:21:55 +0900 | [diff] [blame] | 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 | |
Masami Hiramatsu | 9b960a3 | 2018-04-25 21:19:59 +0900 | [diff] [blame] | 167 | return code->op == FETCH_OP_END ? ret : -EILSEQ; |
| 168 | } |
Masami Hiramatsu | 5330592 | 2018-04-25 21:18:03 +0900 | [diff] [blame] | 169 | |
Ingo Molnar | f2cc020 | 2021-03-23 18:49:35 +0100 | [diff] [blame] | 170 | /* Sum up total data length for dynamic arrays (strings) */ |
Masami Hiramatsu | 5330592 | 2018-04-25 21:18:03 +0900 | [diff] [blame] | 171 | static nokprobe_inline int |
| 172 | __get_data_size(struct trace_probe *tp, struct pt_regs *regs) |
| 173 | { |
| 174 | struct probe_arg *arg; |
Masami Hiramatsu | 9178412 | 2018-04-25 21:19:01 +0900 | [diff] [blame] | 175 | int i, len, ret = 0; |
Masami Hiramatsu | 5330592 | 2018-04-25 21:18:03 +0900 | [diff] [blame] | 176 | |
| 177 | for (i = 0; i < tp->nr_args; i++) { |
| 178 | arg = tp->args + i; |
| 179 | if (unlikely(arg->dynamic)) { |
Masami Hiramatsu | 9178412 | 2018-04-25 21:19:01 +0900 | [diff] [blame] | 180 | len = process_fetch_insn(arg->code, regs, NULL, NULL); |
| 181 | if (len > 0) |
| 182 | ret += len; |
Masami Hiramatsu | 5330592 | 2018-04-25 21:18:03 +0900 | [diff] [blame] | 183 | } |
| 184 | } |
| 185 | |
| 186 | return ret; |
| 187 | } |
| 188 | |
| 189 | /* Store the value of each argument */ |
| 190 | static nokprobe_inline void |
Steven Rostedt (VMware) | 8565a45 | 2021-08-19 00:13:28 -0400 | [diff] [blame] | 191 | store_trace_args(void *data, struct trace_probe *tp, void *rec, |
Masami Hiramatsu | 9178412 | 2018-04-25 21:19:01 +0900 | [diff] [blame] | 192 | int header_size, int maxlen) |
Masami Hiramatsu | 5330592 | 2018-04-25 21:18:03 +0900 | [diff] [blame] | 193 | { |
| 194 | struct probe_arg *arg; |
Masami Hiramatsu | 9178412 | 2018-04-25 21:19:01 +0900 | [diff] [blame] | 195 | void *base = data - header_size; |
| 196 | void *dyndata = data + tp->size; |
| 197 | u32 *dl; /* Data location */ |
| 198 | int ret, i; |
Masami Hiramatsu | 5330592 | 2018-04-25 21:18:03 +0900 | [diff] [blame] | 199 | |
| 200 | for (i = 0; i < tp->nr_args; i++) { |
| 201 | arg = tp->args + i; |
Masami Hiramatsu | 9178412 | 2018-04-25 21:19:01 +0900 | [diff] [blame] | 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); |
Steven Rostedt (VMware) | 8565a45 | 2021-08-19 00:13:28 -0400 | [diff] [blame] | 206 | ret = process_fetch_insn(arg->code, rec, dl, base); |
Andreas Ziegler | f667587 | 2019-02-06 20:00:13 +0100 | [diff] [blame] | 207 | if (unlikely(ret < 0 && arg->dynamic)) { |
Masami Hiramatsu | 9178412 | 2018-04-25 21:19:01 +0900 | [diff] [blame] | 208 | *dl = make_data_loc(0, dyndata - base); |
Andreas Ziegler | f667587 | 2019-02-06 20:00:13 +0100 | [diff] [blame] | 209 | } else { |
Masami Hiramatsu | 9178412 | 2018-04-25 21:19:01 +0900 | [diff] [blame] | 210 | dyndata += ret; |
Andreas Ziegler | f667587 | 2019-02-06 20:00:13 +0100 | [diff] [blame] | 211 | maxlen -= ret; |
| 212 | } |
Masami Hiramatsu | 5330592 | 2018-04-25 21:18:03 +0900 | [diff] [blame] | 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 | { |
Masami Hiramatsu | 40b53b7 | 2018-04-25 21:21:55 +0900 | [diff] [blame] | 220 | void *p; |
| 221 | int i, j; |
Masami Hiramatsu | 5330592 | 2018-04-25 21:18:03 +0900 | [diff] [blame] | 222 | |
| 223 | for (i = 0; i < nr_args; i++) { |
Masami Hiramatsu | 40b53b7 | 2018-04-25 21:21:55 +0900 | [diff] [blame] | 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 | } |
Masami Hiramatsu | 5330592 | 2018-04-25 21:18:03 +0900 | [diff] [blame] | 240 | } |
| 241 | return 0; |
| 242 | } |