.. | .. |
---|
13 | 13 | |
---|
14 | 14 | #include "trace_probe.h" |
---|
15 | 15 | |
---|
16 | | -const char *reserved_field_names[] = { |
---|
| 16 | +#undef C |
---|
| 17 | +#define C(a, b) b |
---|
| 18 | + |
---|
| 19 | +static const char *trace_probe_err_text[] = { ERRORS }; |
---|
| 20 | + |
---|
| 21 | +static const char *reserved_field_names[] = { |
---|
17 | 22 | "common_type", |
---|
18 | 23 | "common_flags", |
---|
19 | 24 | "common_preempt_count", |
---|
.. | .. |
---|
26 | 31 | |
---|
27 | 32 | /* Printing in basic type function template */ |
---|
28 | 33 | #define DEFINE_BASIC_PRINT_TYPE_FUNC(tname, type, fmt) \ |
---|
29 | | -int PRINT_TYPE_FUNC_NAME(tname)(struct trace_seq *s, const char *name, \ |
---|
30 | | - void *data, void *ent) \ |
---|
| 34 | +int PRINT_TYPE_FUNC_NAME(tname)(struct trace_seq *s, void *data, void *ent)\ |
---|
31 | 35 | { \ |
---|
32 | | - trace_seq_printf(s, " %s=" fmt, name, *(type *)data); \ |
---|
| 36 | + trace_seq_printf(s, fmt, *(type *)data); \ |
---|
33 | 37 | return !trace_seq_has_overflowed(s); \ |
---|
34 | 38 | } \ |
---|
35 | | -const char PRINT_TYPE_FMT_NAME(tname)[] = fmt; \ |
---|
36 | | -NOKPROBE_SYMBOL(PRINT_TYPE_FUNC_NAME(tname)); |
---|
| 39 | +const char PRINT_TYPE_FMT_NAME(tname)[] = fmt; |
---|
37 | 40 | |
---|
38 | 41 | DEFINE_BASIC_PRINT_TYPE_FUNC(u8, u8, "%u") |
---|
39 | 42 | DEFINE_BASIC_PRINT_TYPE_FUNC(u16, u16, "%u") |
---|
.. | .. |
---|
48 | 51 | DEFINE_BASIC_PRINT_TYPE_FUNC(x32, u32, "0x%x") |
---|
49 | 52 | DEFINE_BASIC_PRINT_TYPE_FUNC(x64, u64, "0x%Lx") |
---|
50 | 53 | |
---|
| 54 | +int PRINT_TYPE_FUNC_NAME(symbol)(struct trace_seq *s, void *data, void *ent) |
---|
| 55 | +{ |
---|
| 56 | + trace_seq_printf(s, "%pS", (void *)*(unsigned long *)data); |
---|
| 57 | + return !trace_seq_has_overflowed(s); |
---|
| 58 | +} |
---|
| 59 | +const char PRINT_TYPE_FMT_NAME(symbol)[] = "%pS"; |
---|
| 60 | + |
---|
51 | 61 | /* Print type function for string type */ |
---|
52 | | -int PRINT_TYPE_FUNC_NAME(string)(struct trace_seq *s, const char *name, |
---|
53 | | - void *data, void *ent) |
---|
| 62 | +int PRINT_TYPE_FUNC_NAME(string)(struct trace_seq *s, void *data, void *ent) |
---|
54 | 63 | { |
---|
55 | 64 | int len = *(u32 *)data >> 16; |
---|
56 | 65 | |
---|
57 | 66 | if (!len) |
---|
58 | | - trace_seq_printf(s, " %s=(fault)", name); |
---|
| 67 | + trace_seq_puts(s, "(fault)"); |
---|
59 | 68 | else |
---|
60 | | - trace_seq_printf(s, " %s=\"%s\"", name, |
---|
| 69 | + trace_seq_printf(s, "\"%s\"", |
---|
61 | 70 | (const char *)get_loc_data(data, ent)); |
---|
62 | 71 | return !trace_seq_has_overflowed(s); |
---|
63 | 72 | } |
---|
64 | | -NOKPROBE_SYMBOL(PRINT_TYPE_FUNC_NAME(string)); |
---|
65 | 73 | |
---|
66 | 74 | const char PRINT_TYPE_FMT_NAME(string)[] = "\\\"%s\\\""; |
---|
67 | 75 | |
---|
68 | | -#define CHECK_FETCH_FUNCS(method, fn) \ |
---|
69 | | - (((FETCH_FUNC_NAME(method, u8) == fn) || \ |
---|
70 | | - (FETCH_FUNC_NAME(method, u16) == fn) || \ |
---|
71 | | - (FETCH_FUNC_NAME(method, u32) == fn) || \ |
---|
72 | | - (FETCH_FUNC_NAME(method, u64) == fn) || \ |
---|
73 | | - (FETCH_FUNC_NAME(method, string) == fn) || \ |
---|
74 | | - (FETCH_FUNC_NAME(method, string_size) == fn)) \ |
---|
75 | | - && (fn != NULL)) |
---|
| 76 | +/* Fetch type information table */ |
---|
| 77 | +static const struct fetch_type probe_fetch_types[] = { |
---|
| 78 | + /* Special types */ |
---|
| 79 | + __ASSIGN_FETCH_TYPE("string", string, string, sizeof(u32), 1, |
---|
| 80 | + "__data_loc char[]"), |
---|
| 81 | + __ASSIGN_FETCH_TYPE("ustring", string, string, sizeof(u32), 1, |
---|
| 82 | + "__data_loc char[]"), |
---|
| 83 | + /* Basic types */ |
---|
| 84 | + ASSIGN_FETCH_TYPE(u8, u8, 0), |
---|
| 85 | + ASSIGN_FETCH_TYPE(u16, u16, 0), |
---|
| 86 | + ASSIGN_FETCH_TYPE(u32, u32, 0), |
---|
| 87 | + ASSIGN_FETCH_TYPE(u64, u64, 0), |
---|
| 88 | + ASSIGN_FETCH_TYPE(s8, u8, 1), |
---|
| 89 | + ASSIGN_FETCH_TYPE(s16, u16, 1), |
---|
| 90 | + ASSIGN_FETCH_TYPE(s32, u32, 1), |
---|
| 91 | + ASSIGN_FETCH_TYPE(s64, u64, 1), |
---|
| 92 | + ASSIGN_FETCH_TYPE_ALIAS(x8, u8, u8, 0), |
---|
| 93 | + ASSIGN_FETCH_TYPE_ALIAS(x16, u16, u16, 0), |
---|
| 94 | + ASSIGN_FETCH_TYPE_ALIAS(x32, u32, u32, 0), |
---|
| 95 | + ASSIGN_FETCH_TYPE_ALIAS(x64, u64, u64, 0), |
---|
| 96 | + ASSIGN_FETCH_TYPE_ALIAS(symbol, ADDR_FETCH_TYPE, ADDR_FETCH_TYPE, 0), |
---|
76 | 97 | |
---|
77 | | -/* Data fetch function templates */ |
---|
78 | | -#define DEFINE_FETCH_reg(type) \ |
---|
79 | | -void FETCH_FUNC_NAME(reg, type)(struct pt_regs *regs, void *offset, void *dest) \ |
---|
80 | | -{ \ |
---|
81 | | - *(type *)dest = (type)regs_get_register(regs, \ |
---|
82 | | - (unsigned int)((unsigned long)offset)); \ |
---|
83 | | -} \ |
---|
84 | | -NOKPROBE_SYMBOL(FETCH_FUNC_NAME(reg, type)); |
---|
85 | | -DEFINE_BASIC_FETCH_FUNCS(reg) |
---|
86 | | -/* No string on the register */ |
---|
87 | | -#define fetch_reg_string NULL |
---|
88 | | -#define fetch_reg_string_size NULL |
---|
89 | | - |
---|
90 | | -#define DEFINE_FETCH_retval(type) \ |
---|
91 | | -void FETCH_FUNC_NAME(retval, type)(struct pt_regs *regs, \ |
---|
92 | | - void *dummy, void *dest) \ |
---|
93 | | -{ \ |
---|
94 | | - *(type *)dest = (type)regs_return_value(regs); \ |
---|
95 | | -} \ |
---|
96 | | -NOKPROBE_SYMBOL(FETCH_FUNC_NAME(retval, type)); |
---|
97 | | -DEFINE_BASIC_FETCH_FUNCS(retval) |
---|
98 | | -/* No string on the retval */ |
---|
99 | | -#define fetch_retval_string NULL |
---|
100 | | -#define fetch_retval_string_size NULL |
---|
101 | | - |
---|
102 | | -/* Dereference memory access function */ |
---|
103 | | -struct deref_fetch_param { |
---|
104 | | - struct fetch_param orig; |
---|
105 | | - long offset; |
---|
106 | | - fetch_func_t fetch; |
---|
107 | | - fetch_func_t fetch_size; |
---|
| 98 | + ASSIGN_FETCH_TYPE_END |
---|
108 | 99 | }; |
---|
109 | 100 | |
---|
110 | | -#define DEFINE_FETCH_deref(type) \ |
---|
111 | | -void FETCH_FUNC_NAME(deref, type)(struct pt_regs *regs, \ |
---|
112 | | - void *data, void *dest) \ |
---|
113 | | -{ \ |
---|
114 | | - struct deref_fetch_param *dprm = data; \ |
---|
115 | | - unsigned long addr; \ |
---|
116 | | - call_fetch(&dprm->orig, regs, &addr); \ |
---|
117 | | - if (addr) { \ |
---|
118 | | - addr += dprm->offset; \ |
---|
119 | | - dprm->fetch(regs, (void *)addr, dest); \ |
---|
120 | | - } else \ |
---|
121 | | - *(type *)dest = 0; \ |
---|
122 | | -} \ |
---|
123 | | -NOKPROBE_SYMBOL(FETCH_FUNC_NAME(deref, type)); |
---|
124 | | -DEFINE_BASIC_FETCH_FUNCS(deref) |
---|
125 | | -DEFINE_FETCH_deref(string) |
---|
126 | | - |
---|
127 | | -void FETCH_FUNC_NAME(deref, string_size)(struct pt_regs *regs, |
---|
128 | | - void *data, void *dest) |
---|
129 | | -{ |
---|
130 | | - struct deref_fetch_param *dprm = data; |
---|
131 | | - unsigned long addr; |
---|
132 | | - |
---|
133 | | - call_fetch(&dprm->orig, regs, &addr); |
---|
134 | | - if (addr && dprm->fetch_size) { |
---|
135 | | - addr += dprm->offset; |
---|
136 | | - dprm->fetch_size(regs, (void *)addr, dest); |
---|
137 | | - } else |
---|
138 | | - *(string_size *)dest = 0; |
---|
139 | | -} |
---|
140 | | -NOKPROBE_SYMBOL(FETCH_FUNC_NAME(deref, string_size)); |
---|
141 | | - |
---|
142 | | -static void update_deref_fetch_param(struct deref_fetch_param *data) |
---|
143 | | -{ |
---|
144 | | - if (CHECK_FETCH_FUNCS(deref, data->orig.fn)) |
---|
145 | | - update_deref_fetch_param(data->orig.data); |
---|
146 | | - else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn)) |
---|
147 | | - update_symbol_cache(data->orig.data); |
---|
148 | | -} |
---|
149 | | -NOKPROBE_SYMBOL(update_deref_fetch_param); |
---|
150 | | - |
---|
151 | | -static void free_deref_fetch_param(struct deref_fetch_param *data) |
---|
152 | | -{ |
---|
153 | | - if (CHECK_FETCH_FUNCS(deref, data->orig.fn)) |
---|
154 | | - free_deref_fetch_param(data->orig.data); |
---|
155 | | - else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn)) |
---|
156 | | - free_symbol_cache(data->orig.data); |
---|
157 | | - kfree(data); |
---|
158 | | -} |
---|
159 | | -NOKPROBE_SYMBOL(free_deref_fetch_param); |
---|
160 | | - |
---|
161 | | -/* Bitfield fetch function */ |
---|
162 | | -struct bitfield_fetch_param { |
---|
163 | | - struct fetch_param orig; |
---|
164 | | - unsigned char hi_shift; |
---|
165 | | - unsigned char low_shift; |
---|
166 | | -}; |
---|
167 | | - |
---|
168 | | -#define DEFINE_FETCH_bitfield(type) \ |
---|
169 | | -void FETCH_FUNC_NAME(bitfield, type)(struct pt_regs *regs, \ |
---|
170 | | - void *data, void *dest) \ |
---|
171 | | -{ \ |
---|
172 | | - struct bitfield_fetch_param *bprm = data; \ |
---|
173 | | - type buf = 0; \ |
---|
174 | | - call_fetch(&bprm->orig, regs, &buf); \ |
---|
175 | | - if (buf) { \ |
---|
176 | | - buf <<= bprm->hi_shift; \ |
---|
177 | | - buf >>= bprm->low_shift; \ |
---|
178 | | - } \ |
---|
179 | | - *(type *)dest = buf; \ |
---|
180 | | -} \ |
---|
181 | | -NOKPROBE_SYMBOL(FETCH_FUNC_NAME(bitfield, type)); |
---|
182 | | -DEFINE_BASIC_FETCH_FUNCS(bitfield) |
---|
183 | | -#define fetch_bitfield_string NULL |
---|
184 | | -#define fetch_bitfield_string_size NULL |
---|
185 | | - |
---|
186 | | -static void |
---|
187 | | -update_bitfield_fetch_param(struct bitfield_fetch_param *data) |
---|
188 | | -{ |
---|
189 | | - /* |
---|
190 | | - * Don't check the bitfield itself, because this must be the |
---|
191 | | - * last fetch function. |
---|
192 | | - */ |
---|
193 | | - if (CHECK_FETCH_FUNCS(deref, data->orig.fn)) |
---|
194 | | - update_deref_fetch_param(data->orig.data); |
---|
195 | | - else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn)) |
---|
196 | | - update_symbol_cache(data->orig.data); |
---|
197 | | -} |
---|
198 | | - |
---|
199 | | -static void |
---|
200 | | -free_bitfield_fetch_param(struct bitfield_fetch_param *data) |
---|
201 | | -{ |
---|
202 | | - /* |
---|
203 | | - * Don't check the bitfield itself, because this must be the |
---|
204 | | - * last fetch function. |
---|
205 | | - */ |
---|
206 | | - if (CHECK_FETCH_FUNCS(deref, data->orig.fn)) |
---|
207 | | - free_deref_fetch_param(data->orig.data); |
---|
208 | | - else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn)) |
---|
209 | | - free_symbol_cache(data->orig.data); |
---|
210 | | - |
---|
211 | | - kfree(data); |
---|
212 | | -} |
---|
213 | | - |
---|
214 | | -void FETCH_FUNC_NAME(comm, string)(struct pt_regs *regs, |
---|
215 | | - void *data, void *dest) |
---|
216 | | -{ |
---|
217 | | - int maxlen = get_rloc_len(*(u32 *)dest); |
---|
218 | | - u8 *dst = get_rloc_data(dest); |
---|
219 | | - long ret; |
---|
220 | | - |
---|
221 | | - if (!maxlen) |
---|
222 | | - return; |
---|
223 | | - |
---|
224 | | - ret = strlcpy(dst, current->comm, maxlen); |
---|
225 | | - *(u32 *)dest = make_data_rloc(ret, get_rloc_offs(*(u32 *)dest)); |
---|
226 | | -} |
---|
227 | | -NOKPROBE_SYMBOL(FETCH_FUNC_NAME(comm, string)); |
---|
228 | | - |
---|
229 | | -void FETCH_FUNC_NAME(comm, string_size)(struct pt_regs *regs, |
---|
230 | | - void *data, void *dest) |
---|
231 | | -{ |
---|
232 | | - *(u32 *)dest = strlen(current->comm) + 1; |
---|
233 | | -} |
---|
234 | | -NOKPROBE_SYMBOL(FETCH_FUNC_NAME(comm, string_size)); |
---|
235 | | - |
---|
236 | | -static const struct fetch_type *find_fetch_type(const char *type, |
---|
237 | | - const struct fetch_type *ftbl) |
---|
| 101 | +static const struct fetch_type *find_fetch_type(const char *type) |
---|
238 | 102 | { |
---|
239 | 103 | int i; |
---|
240 | 104 | |
---|
.. | .. |
---|
255 | 119 | |
---|
256 | 120 | switch (bs) { |
---|
257 | 121 | case 8: |
---|
258 | | - return find_fetch_type("u8", ftbl); |
---|
| 122 | + return find_fetch_type("u8"); |
---|
259 | 123 | case 16: |
---|
260 | | - return find_fetch_type("u16", ftbl); |
---|
| 124 | + return find_fetch_type("u16"); |
---|
261 | 125 | case 32: |
---|
262 | | - return find_fetch_type("u32", ftbl); |
---|
| 126 | + return find_fetch_type("u32"); |
---|
263 | 127 | case 64: |
---|
264 | | - return find_fetch_type("u64", ftbl); |
---|
| 128 | + return find_fetch_type("u64"); |
---|
265 | 129 | default: |
---|
266 | 130 | goto fail; |
---|
267 | 131 | } |
---|
268 | 132 | } |
---|
269 | 133 | |
---|
270 | | - for (i = 0; ftbl[i].name; i++) { |
---|
271 | | - if (strcmp(type, ftbl[i].name) == 0) |
---|
272 | | - return &ftbl[i]; |
---|
| 134 | + for (i = 0; probe_fetch_types[i].name; i++) { |
---|
| 135 | + if (strcmp(type, probe_fetch_types[i].name) == 0) |
---|
| 136 | + return &probe_fetch_types[i]; |
---|
273 | 137 | } |
---|
274 | 138 | |
---|
275 | 139 | fail: |
---|
276 | 140 | return NULL; |
---|
277 | 141 | } |
---|
278 | 142 | |
---|
279 | | -/* Special function : only accept unsigned long */ |
---|
280 | | -static void fetch_kernel_stack_address(struct pt_regs *regs, void *dummy, void *dest) |
---|
| 143 | +static struct trace_probe_log trace_probe_log; |
---|
| 144 | + |
---|
| 145 | +void trace_probe_log_init(const char *subsystem, int argc, const char **argv) |
---|
281 | 146 | { |
---|
282 | | - *(unsigned long *)dest = kernel_stack_pointer(regs); |
---|
| 147 | + trace_probe_log.subsystem = subsystem; |
---|
| 148 | + trace_probe_log.argc = argc; |
---|
| 149 | + trace_probe_log.argv = argv; |
---|
| 150 | + trace_probe_log.index = 0; |
---|
283 | 151 | } |
---|
284 | | -NOKPROBE_SYMBOL(fetch_kernel_stack_address); |
---|
285 | 152 | |
---|
286 | | -static void fetch_user_stack_address(struct pt_regs *regs, void *dummy, void *dest) |
---|
| 153 | +void trace_probe_log_clear(void) |
---|
287 | 154 | { |
---|
288 | | - *(unsigned long *)dest = user_stack_pointer(regs); |
---|
| 155 | + memset(&trace_probe_log, 0, sizeof(trace_probe_log)); |
---|
289 | 156 | } |
---|
290 | | -NOKPROBE_SYMBOL(fetch_user_stack_address); |
---|
291 | 157 | |
---|
292 | | -static fetch_func_t get_fetch_size_function(const struct fetch_type *type, |
---|
293 | | - fetch_func_t orig_fn, |
---|
294 | | - const struct fetch_type *ftbl) |
---|
| 158 | +void trace_probe_log_set_index(int index) |
---|
295 | 159 | { |
---|
296 | | - int i; |
---|
| 160 | + trace_probe_log.index = index; |
---|
| 161 | +} |
---|
297 | 162 | |
---|
298 | | - if (type != &ftbl[FETCH_TYPE_STRING]) |
---|
299 | | - return NULL; /* Only string type needs size function */ |
---|
| 163 | +void __trace_probe_log_err(int offset, int err_type) |
---|
| 164 | +{ |
---|
| 165 | + char *command, *p; |
---|
| 166 | + int i, len = 0, pos = 0; |
---|
300 | 167 | |
---|
301 | | - for (i = 0; i < FETCH_MTD_END; i++) |
---|
302 | | - if (type->fetch[i] == orig_fn) |
---|
303 | | - return ftbl[FETCH_TYPE_STRSIZE].fetch[i]; |
---|
| 168 | + if (!trace_probe_log.argv) |
---|
| 169 | + return; |
---|
304 | 170 | |
---|
305 | | - WARN_ON(1); /* This should not happen */ |
---|
| 171 | + /* Recalcurate the length and allocate buffer */ |
---|
| 172 | + for (i = 0; i < trace_probe_log.argc; i++) { |
---|
| 173 | + if (i == trace_probe_log.index) |
---|
| 174 | + pos = len; |
---|
| 175 | + len += strlen(trace_probe_log.argv[i]) + 1; |
---|
| 176 | + } |
---|
| 177 | + command = kzalloc(len, GFP_KERNEL); |
---|
| 178 | + if (!command) |
---|
| 179 | + return; |
---|
306 | 180 | |
---|
307 | | - return NULL; |
---|
| 181 | + if (trace_probe_log.index >= trace_probe_log.argc) { |
---|
| 182 | + /** |
---|
| 183 | + * Set the error position is next to the last arg + space. |
---|
| 184 | + * Note that len includes the terminal null and the cursor |
---|
| 185 | + * appaers at pos + 1. |
---|
| 186 | + */ |
---|
| 187 | + pos = len; |
---|
| 188 | + offset = 0; |
---|
| 189 | + } |
---|
| 190 | + |
---|
| 191 | + /* And make a command string from argv array */ |
---|
| 192 | + p = command; |
---|
| 193 | + for (i = 0; i < trace_probe_log.argc; i++) { |
---|
| 194 | + len = strlen(trace_probe_log.argv[i]); |
---|
| 195 | + strcpy(p, trace_probe_log.argv[i]); |
---|
| 196 | + p[len] = ' '; |
---|
| 197 | + p += len + 1; |
---|
| 198 | + } |
---|
| 199 | + *(p - 1) = '\0'; |
---|
| 200 | + |
---|
| 201 | + tracing_log_err(NULL, trace_probe_log.subsystem, command, |
---|
| 202 | + trace_probe_err_text, err_type, pos + offset); |
---|
| 203 | + |
---|
| 204 | + kfree(command); |
---|
308 | 205 | } |
---|
309 | 206 | |
---|
310 | 207 | /* Split symbol and offset. */ |
---|
.. | .. |
---|
328 | 225 | return 0; |
---|
329 | 226 | } |
---|
330 | 227 | |
---|
| 228 | +/* @buf must has MAX_EVENT_NAME_LEN size */ |
---|
| 229 | +int traceprobe_parse_event_name(const char **pevent, const char **pgroup, |
---|
| 230 | + char *buf, int offset) |
---|
| 231 | +{ |
---|
| 232 | + const char *slash, *event = *pevent; |
---|
| 233 | + int len; |
---|
| 234 | + |
---|
| 235 | + slash = strchr(event, '/'); |
---|
| 236 | + if (slash) { |
---|
| 237 | + if (slash == event) { |
---|
| 238 | + trace_probe_log_err(offset, NO_GROUP_NAME); |
---|
| 239 | + return -EINVAL; |
---|
| 240 | + } |
---|
| 241 | + if (slash - event + 1 > MAX_EVENT_NAME_LEN) { |
---|
| 242 | + trace_probe_log_err(offset, GROUP_TOO_LONG); |
---|
| 243 | + return -EINVAL; |
---|
| 244 | + } |
---|
| 245 | + strlcpy(buf, event, slash - event + 1); |
---|
| 246 | + if (!is_good_name(buf)) { |
---|
| 247 | + trace_probe_log_err(offset, BAD_GROUP_NAME); |
---|
| 248 | + return -EINVAL; |
---|
| 249 | + } |
---|
| 250 | + *pgroup = buf; |
---|
| 251 | + *pevent = slash + 1; |
---|
| 252 | + offset += slash - event + 1; |
---|
| 253 | + event = *pevent; |
---|
| 254 | + } |
---|
| 255 | + len = strlen(event); |
---|
| 256 | + if (len == 0) { |
---|
| 257 | + trace_probe_log_err(offset, NO_EVENT_NAME); |
---|
| 258 | + return -EINVAL; |
---|
| 259 | + } else if (len > MAX_EVENT_NAME_LEN) { |
---|
| 260 | + trace_probe_log_err(offset, EVENT_TOO_LONG); |
---|
| 261 | + return -EINVAL; |
---|
| 262 | + } |
---|
| 263 | + if (!is_good_name(event)) { |
---|
| 264 | + trace_probe_log_err(offset, BAD_EVENT_NAME); |
---|
| 265 | + return -EINVAL; |
---|
| 266 | + } |
---|
| 267 | + return 0; |
---|
| 268 | +} |
---|
| 269 | + |
---|
331 | 270 | #define PARAM_MAX_STACK (THREAD_SIZE / sizeof(unsigned long)) |
---|
332 | 271 | |
---|
333 | 272 | static int parse_probe_vars(char *arg, const struct fetch_type *t, |
---|
334 | | - struct fetch_param *f, bool is_return, |
---|
335 | | - bool is_kprobe) |
---|
| 273 | + struct fetch_insn *code, unsigned int flags, int offs) |
---|
336 | 274 | { |
---|
337 | | - int ret = 0; |
---|
338 | 275 | unsigned long param; |
---|
| 276 | + int ret = 0; |
---|
| 277 | + int len; |
---|
339 | 278 | |
---|
340 | 279 | if (strcmp(arg, "retval") == 0) { |
---|
341 | | - if (is_return) |
---|
342 | | - f->fn = t->fetch[FETCH_MTD_retval]; |
---|
343 | | - else |
---|
| 280 | + if (flags & TPARG_FL_RETURN) { |
---|
| 281 | + code->op = FETCH_OP_RETVAL; |
---|
| 282 | + } else { |
---|
| 283 | + trace_probe_log_err(offs, RETVAL_ON_PROBE); |
---|
344 | 284 | ret = -EINVAL; |
---|
345 | | - } else if (strncmp(arg, "stack", 5) == 0) { |
---|
346 | | - if (arg[5] == '\0') { |
---|
347 | | - if (strcmp(t->name, DEFAULT_FETCH_TYPE_STR)) |
---|
348 | | - return -EINVAL; |
---|
349 | | - |
---|
350 | | - if (is_kprobe) |
---|
351 | | - f->fn = fetch_kernel_stack_address; |
---|
352 | | - else |
---|
353 | | - f->fn = fetch_user_stack_address; |
---|
354 | | - } else if (isdigit(arg[5])) { |
---|
355 | | - ret = kstrtoul(arg + 5, 10, ¶m); |
---|
356 | | - if (ret || (is_kprobe && param > PARAM_MAX_STACK)) |
---|
| 285 | + } |
---|
| 286 | + } else if ((len = str_has_prefix(arg, "stack"))) { |
---|
| 287 | + if (arg[len] == '\0') { |
---|
| 288 | + code->op = FETCH_OP_STACKP; |
---|
| 289 | + } else if (isdigit(arg[len])) { |
---|
| 290 | + ret = kstrtoul(arg + len, 10, ¶m); |
---|
| 291 | + if (ret) { |
---|
| 292 | + goto inval_var; |
---|
| 293 | + } else if ((flags & TPARG_FL_KERNEL) && |
---|
| 294 | + param > PARAM_MAX_STACK) { |
---|
| 295 | + trace_probe_log_err(offs, BAD_STACK_NUM); |
---|
357 | 296 | ret = -EINVAL; |
---|
358 | | - else { |
---|
359 | | - f->fn = t->fetch[FETCH_MTD_stack]; |
---|
360 | | - f->data = (void *)param; |
---|
| 297 | + } else { |
---|
| 298 | + code->op = FETCH_OP_STACK; |
---|
| 299 | + code->param = (unsigned int)param; |
---|
361 | 300 | } |
---|
362 | 301 | } else |
---|
363 | | - ret = -EINVAL; |
---|
364 | | - } else if (strcmp(arg, "comm") == 0) { |
---|
365 | | - if (strcmp(t->name, "string") != 0 && |
---|
366 | | - strcmp(t->name, "string_size") != 0) |
---|
| 302 | + goto inval_var; |
---|
| 303 | + } else if (strcmp(arg, "comm") == 0 || strcmp(arg, "COMM") == 0) { |
---|
| 304 | + code->op = FETCH_OP_COMM; |
---|
| 305 | +#ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API |
---|
| 306 | + } else if (((flags & TPARG_FL_MASK) == |
---|
| 307 | + (TPARG_FL_KERNEL | TPARG_FL_FENTRY)) && |
---|
| 308 | + (len = str_has_prefix(arg, "arg"))) { |
---|
| 309 | + ret = kstrtoul(arg + len, 10, ¶m); |
---|
| 310 | + if (ret) { |
---|
| 311 | + goto inval_var; |
---|
| 312 | + } else if (!param || param > PARAM_MAX_STACK) { |
---|
| 313 | + trace_probe_log_err(offs, BAD_ARG_NUM); |
---|
367 | 314 | return -EINVAL; |
---|
368 | | - f->fn = t->fetch[FETCH_MTD_comm]; |
---|
| 315 | + } |
---|
| 316 | + code->op = FETCH_OP_ARG; |
---|
| 317 | + code->param = (unsigned int)param - 1; |
---|
| 318 | +#endif |
---|
369 | 319 | } else |
---|
370 | | - ret = -EINVAL; |
---|
| 320 | + goto inval_var; |
---|
371 | 321 | |
---|
372 | 322 | return ret; |
---|
| 323 | + |
---|
| 324 | +inval_var: |
---|
| 325 | + trace_probe_log_err(offs, BAD_VAR); |
---|
| 326 | + return -EINVAL; |
---|
| 327 | +} |
---|
| 328 | + |
---|
| 329 | +static int str_to_immediate(char *str, unsigned long *imm) |
---|
| 330 | +{ |
---|
| 331 | + if (isdigit(str[0])) |
---|
| 332 | + return kstrtoul(str, 0, imm); |
---|
| 333 | + else if (str[0] == '-') |
---|
| 334 | + return kstrtol(str, 0, (long *)imm); |
---|
| 335 | + else if (str[0] == '+') |
---|
| 336 | + return kstrtol(str + 1, 0, (long *)imm); |
---|
| 337 | + return -EINVAL; |
---|
| 338 | +} |
---|
| 339 | + |
---|
| 340 | +static int __parse_imm_string(char *str, char **pbuf, int offs) |
---|
| 341 | +{ |
---|
| 342 | + size_t len = strlen(str); |
---|
| 343 | + |
---|
| 344 | + if (str[len - 1] != '"') { |
---|
| 345 | + trace_probe_log_err(offs + len, IMMSTR_NO_CLOSE); |
---|
| 346 | + return -EINVAL; |
---|
| 347 | + } |
---|
| 348 | + *pbuf = kstrndup(str, len - 1, GFP_KERNEL); |
---|
| 349 | + return 0; |
---|
373 | 350 | } |
---|
374 | 351 | |
---|
375 | 352 | /* Recursive argument parser */ |
---|
376 | | -static int parse_probe_arg(char *arg, const struct fetch_type *t, |
---|
377 | | - struct fetch_param *f, bool is_return, bool is_kprobe, |
---|
378 | | - const struct fetch_type *ftbl) |
---|
| 353 | +static int |
---|
| 354 | +parse_probe_arg(char *arg, const struct fetch_type *type, |
---|
| 355 | + struct fetch_insn **pcode, struct fetch_insn *end, |
---|
| 356 | + unsigned int flags, int offs) |
---|
379 | 357 | { |
---|
| 358 | + struct fetch_insn *code = *pcode; |
---|
380 | 359 | unsigned long param; |
---|
381 | | - long offset; |
---|
| 360 | + int deref = FETCH_OP_DEREF; |
---|
| 361 | + long offset = 0; |
---|
382 | 362 | char *tmp; |
---|
383 | 363 | int ret = 0; |
---|
384 | 364 | |
---|
385 | 365 | switch (arg[0]) { |
---|
386 | 366 | case '$': |
---|
387 | | - ret = parse_probe_vars(arg + 1, t, f, is_return, is_kprobe); |
---|
| 367 | + ret = parse_probe_vars(arg + 1, type, code, flags, offs); |
---|
388 | 368 | break; |
---|
389 | 369 | |
---|
390 | 370 | case '%': /* named register */ |
---|
391 | 371 | ret = regs_query_register_offset(arg + 1); |
---|
392 | 372 | if (ret >= 0) { |
---|
393 | | - f->fn = t->fetch[FETCH_MTD_reg]; |
---|
394 | | - f->data = (void *)(unsigned long)ret; |
---|
| 373 | + code->op = FETCH_OP_REG; |
---|
| 374 | + code->param = (unsigned int)ret; |
---|
395 | 375 | ret = 0; |
---|
396 | | - } |
---|
| 376 | + } else |
---|
| 377 | + trace_probe_log_err(offs, BAD_REG_NAME); |
---|
397 | 378 | break; |
---|
398 | 379 | |
---|
399 | 380 | case '@': /* memory, file-offset or symbol */ |
---|
400 | 381 | if (isdigit(arg[1])) { |
---|
401 | 382 | ret = kstrtoul(arg + 1, 0, ¶m); |
---|
402 | | - if (ret) |
---|
| 383 | + if (ret) { |
---|
| 384 | + trace_probe_log_err(offs, BAD_MEM_ADDR); |
---|
403 | 385 | break; |
---|
404 | | - |
---|
405 | | - f->fn = t->fetch[FETCH_MTD_memory]; |
---|
406 | | - f->data = (void *)param; |
---|
| 386 | + } |
---|
| 387 | + /* load address */ |
---|
| 388 | + code->op = FETCH_OP_IMM; |
---|
| 389 | + code->immediate = param; |
---|
407 | 390 | } else if (arg[1] == '+') { |
---|
408 | 391 | /* kprobes don't support file offsets */ |
---|
409 | | - if (is_kprobe) |
---|
| 392 | + if (flags & TPARG_FL_KERNEL) { |
---|
| 393 | + trace_probe_log_err(offs, FILE_ON_KPROBE); |
---|
410 | 394 | return -EINVAL; |
---|
411 | | - |
---|
| 395 | + } |
---|
412 | 396 | ret = kstrtol(arg + 2, 0, &offset); |
---|
413 | | - if (ret) |
---|
| 397 | + if (ret) { |
---|
| 398 | + trace_probe_log_err(offs, BAD_FILE_OFFS); |
---|
414 | 399 | break; |
---|
| 400 | + } |
---|
415 | 401 | |
---|
416 | | - f->fn = t->fetch[FETCH_MTD_file_offset]; |
---|
417 | | - f->data = (void *)offset; |
---|
| 402 | + code->op = FETCH_OP_FOFFS; |
---|
| 403 | + code->immediate = (unsigned long)offset; // imm64? |
---|
418 | 404 | } else { |
---|
419 | 405 | /* uprobes don't support symbols */ |
---|
420 | | - if (!is_kprobe) |
---|
| 406 | + if (!(flags & TPARG_FL_KERNEL)) { |
---|
| 407 | + trace_probe_log_err(offs, SYM_ON_UPROBE); |
---|
421 | 408 | return -EINVAL; |
---|
422 | | - |
---|
423 | | - ret = traceprobe_split_symbol_offset(arg + 1, &offset); |
---|
424 | | - if (ret) |
---|
425 | | - break; |
---|
426 | | - |
---|
427 | | - f->data = alloc_symbol_cache(arg + 1, offset); |
---|
428 | | - if (f->data) |
---|
429 | | - f->fn = t->fetch[FETCH_MTD_symbol]; |
---|
| 409 | + } |
---|
| 410 | + /* Preserve symbol for updating */ |
---|
| 411 | + code->op = FETCH_NOP_SYMBOL; |
---|
| 412 | + code->data = kstrdup(arg + 1, GFP_KERNEL); |
---|
| 413 | + if (!code->data) |
---|
| 414 | + return -ENOMEM; |
---|
| 415 | + if (++code == end) { |
---|
| 416 | + trace_probe_log_err(offs, TOO_MANY_OPS); |
---|
| 417 | + return -EINVAL; |
---|
| 418 | + } |
---|
| 419 | + code->op = FETCH_OP_IMM; |
---|
| 420 | + code->immediate = 0; |
---|
430 | 421 | } |
---|
| 422 | + /* These are fetching from memory */ |
---|
| 423 | + if (++code == end) { |
---|
| 424 | + trace_probe_log_err(offs, TOO_MANY_OPS); |
---|
| 425 | + return -EINVAL; |
---|
| 426 | + } |
---|
| 427 | + *pcode = code; |
---|
| 428 | + code->op = FETCH_OP_DEREF; |
---|
| 429 | + code->offset = offset; |
---|
431 | 430 | break; |
---|
432 | 431 | |
---|
433 | 432 | case '+': /* deref memory */ |
---|
434 | | - arg++; /* Skip '+', because kstrtol() rejects it. */ |
---|
435 | 433 | case '-': |
---|
| 434 | + if (arg[1] == 'u') { |
---|
| 435 | + deref = FETCH_OP_UDEREF; |
---|
| 436 | + arg[1] = arg[0]; |
---|
| 437 | + arg++; |
---|
| 438 | + } |
---|
| 439 | + if (arg[0] == '+') |
---|
| 440 | + arg++; /* Skip '+', because kstrtol() rejects it. */ |
---|
436 | 441 | tmp = strchr(arg, '('); |
---|
437 | | - if (!tmp) |
---|
438 | | - break; |
---|
439 | | - |
---|
| 442 | + if (!tmp) { |
---|
| 443 | + trace_probe_log_err(offs, DEREF_NEED_BRACE); |
---|
| 444 | + return -EINVAL; |
---|
| 445 | + } |
---|
440 | 446 | *tmp = '\0'; |
---|
441 | 447 | ret = kstrtol(arg, 0, &offset); |
---|
442 | | - |
---|
443 | | - if (ret) |
---|
| 448 | + if (ret) { |
---|
| 449 | + trace_probe_log_err(offs, BAD_DEREF_OFFS); |
---|
444 | 450 | break; |
---|
445 | | - |
---|
| 451 | + } |
---|
| 452 | + offs += (tmp + 1 - arg) + (arg[0] != '-' ? 1 : 0); |
---|
446 | 453 | arg = tmp + 1; |
---|
447 | 454 | tmp = strrchr(arg, ')'); |
---|
| 455 | + if (!tmp) { |
---|
| 456 | + trace_probe_log_err(offs + strlen(arg), |
---|
| 457 | + DEREF_OPEN_BRACE); |
---|
| 458 | + return -EINVAL; |
---|
| 459 | + } else { |
---|
| 460 | + const struct fetch_type *t2 = find_fetch_type(NULL); |
---|
448 | 461 | |
---|
449 | | - if (tmp) { |
---|
450 | | - struct deref_fetch_param *dprm; |
---|
451 | | - const struct fetch_type *t2; |
---|
452 | | - |
---|
453 | | - t2 = find_fetch_type(NULL, ftbl); |
---|
454 | 462 | *tmp = '\0'; |
---|
455 | | - dprm = kzalloc(sizeof(struct deref_fetch_param), GFP_KERNEL); |
---|
456 | | - |
---|
457 | | - if (!dprm) |
---|
458 | | - return -ENOMEM; |
---|
459 | | - |
---|
460 | | - dprm->offset = offset; |
---|
461 | | - dprm->fetch = t->fetch[FETCH_MTD_memory]; |
---|
462 | | - dprm->fetch_size = get_fetch_size_function(t, |
---|
463 | | - dprm->fetch, ftbl); |
---|
464 | | - ret = parse_probe_arg(arg, t2, &dprm->orig, is_return, |
---|
465 | | - is_kprobe, ftbl); |
---|
| 463 | + ret = parse_probe_arg(arg, t2, &code, end, flags, offs); |
---|
466 | 464 | if (ret) |
---|
467 | | - kfree(dprm); |
---|
468 | | - else { |
---|
469 | | - f->fn = t->fetch[FETCH_MTD_deref]; |
---|
470 | | - f->data = (void *)dprm; |
---|
| 465 | + break; |
---|
| 466 | + if (code->op == FETCH_OP_COMM || |
---|
| 467 | + code->op == FETCH_OP_DATA) { |
---|
| 468 | + trace_probe_log_err(offs, COMM_CANT_DEREF); |
---|
| 469 | + return -EINVAL; |
---|
471 | 470 | } |
---|
| 471 | + if (++code == end) { |
---|
| 472 | + trace_probe_log_err(offs, TOO_MANY_OPS); |
---|
| 473 | + return -EINVAL; |
---|
| 474 | + } |
---|
| 475 | + *pcode = code; |
---|
| 476 | + |
---|
| 477 | + code->op = deref; |
---|
| 478 | + code->offset = offset; |
---|
| 479 | + } |
---|
| 480 | + break; |
---|
| 481 | + case '\\': /* Immediate value */ |
---|
| 482 | + if (arg[1] == '"') { /* Immediate string */ |
---|
| 483 | + ret = __parse_imm_string(arg + 2, &tmp, offs + 2); |
---|
| 484 | + if (ret) |
---|
| 485 | + break; |
---|
| 486 | + code->op = FETCH_OP_DATA; |
---|
| 487 | + code->data = tmp; |
---|
| 488 | + } else { |
---|
| 489 | + ret = str_to_immediate(arg + 1, &code->immediate); |
---|
| 490 | + if (ret) |
---|
| 491 | + trace_probe_log_err(offs + 1, BAD_IMM); |
---|
| 492 | + else |
---|
| 493 | + code->op = FETCH_OP_IMM; |
---|
472 | 494 | } |
---|
473 | 495 | break; |
---|
474 | 496 | } |
---|
475 | | - if (!ret && !f->fn) { /* Parsed, but do not find fetch method */ |
---|
476 | | - pr_info("%s type has no corresponding fetch method.\n", t->name); |
---|
| 497 | + if (!ret && code->op == FETCH_OP_NOP) { |
---|
| 498 | + /* Parsed, but do not find fetch method */ |
---|
| 499 | + trace_probe_log_err(offs, BAD_FETCH_ARG); |
---|
477 | 500 | ret = -EINVAL; |
---|
478 | 501 | } |
---|
479 | | - |
---|
480 | 502 | return ret; |
---|
481 | 503 | } |
---|
482 | 504 | |
---|
.. | .. |
---|
485 | 507 | /* Bitfield type needs to be parsed into a fetch function */ |
---|
486 | 508 | static int __parse_bitfield_probe_arg(const char *bf, |
---|
487 | 509 | const struct fetch_type *t, |
---|
488 | | - struct fetch_param *f) |
---|
| 510 | + struct fetch_insn **pcode) |
---|
489 | 511 | { |
---|
490 | | - struct bitfield_fetch_param *bprm; |
---|
| 512 | + struct fetch_insn *code = *pcode; |
---|
491 | 513 | unsigned long bw, bo; |
---|
492 | 514 | char *tail; |
---|
493 | 515 | |
---|
494 | 516 | if (*bf != 'b') |
---|
495 | 517 | return 0; |
---|
496 | 518 | |
---|
497 | | - bprm = kzalloc(sizeof(*bprm), GFP_KERNEL); |
---|
498 | | - if (!bprm) |
---|
499 | | - return -ENOMEM; |
---|
500 | | - |
---|
501 | | - bprm->orig = *f; |
---|
502 | | - f->fn = t->fetch[FETCH_MTD_bitfield]; |
---|
503 | | - f->data = (void *)bprm; |
---|
504 | 519 | bw = simple_strtoul(bf + 1, &tail, 0); /* Use simple one */ |
---|
505 | 520 | |
---|
506 | 521 | if (bw == 0 || *tail != '@') |
---|
.. | .. |
---|
511 | 526 | |
---|
512 | 527 | if (tail == bf || *tail != '/') |
---|
513 | 528 | return -EINVAL; |
---|
| 529 | + code++; |
---|
| 530 | + if (code->op != FETCH_OP_NOP) |
---|
| 531 | + return -EINVAL; |
---|
| 532 | + *pcode = code; |
---|
514 | 533 | |
---|
515 | | - bprm->hi_shift = BYTES_TO_BITS(t->size) - (bw + bo); |
---|
516 | | - bprm->low_shift = bprm->hi_shift + bo; |
---|
| 534 | + code->op = FETCH_OP_MOD_BF; |
---|
| 535 | + code->lshift = BYTES_TO_BITS(t->size) - (bw + bo); |
---|
| 536 | + code->rshift = BYTES_TO_BITS(t->size) - bw; |
---|
| 537 | + code->basesize = t->size; |
---|
517 | 538 | |
---|
518 | 539 | return (BYTES_TO_BITS(t->size) < (bw + bo)) ? -EINVAL : 0; |
---|
519 | 540 | } |
---|
520 | 541 | |
---|
521 | 542 | /* String length checking wrapper */ |
---|
522 | | -int traceprobe_parse_probe_arg(char *arg, ssize_t *size, |
---|
523 | | - struct probe_arg *parg, bool is_return, bool is_kprobe, |
---|
524 | | - const struct fetch_type *ftbl) |
---|
| 543 | +static int traceprobe_parse_probe_arg_body(char *arg, ssize_t *size, |
---|
| 544 | + struct probe_arg *parg, unsigned int flags, int offset) |
---|
525 | 545 | { |
---|
526 | | - const char *t; |
---|
527 | | - int ret; |
---|
| 546 | + struct fetch_insn *code, *scode, *tmp = NULL; |
---|
| 547 | + char *t, *t2, *t3; |
---|
| 548 | + int ret, len; |
---|
528 | 549 | |
---|
529 | | - if (strlen(arg) > MAX_ARGSTR_LEN) { |
---|
530 | | - pr_info("Argument is too long.: %s\n", arg); |
---|
531 | | - return -ENOSPC; |
---|
| 550 | + len = strlen(arg); |
---|
| 551 | + if (len > MAX_ARGSTR_LEN) { |
---|
| 552 | + trace_probe_log_err(offset, ARG_TOO_LONG); |
---|
| 553 | + return -EINVAL; |
---|
| 554 | + } else if (len == 0) { |
---|
| 555 | + trace_probe_log_err(offset, NO_ARG_BODY); |
---|
| 556 | + return -EINVAL; |
---|
532 | 557 | } |
---|
| 558 | + |
---|
533 | 559 | parg->comm = kstrdup(arg, GFP_KERNEL); |
---|
534 | | - if (!parg->comm) { |
---|
535 | | - pr_info("Failed to allocate memory for command '%s'.\n", arg); |
---|
| 560 | + if (!parg->comm) |
---|
536 | 561 | return -ENOMEM; |
---|
537 | | - } |
---|
538 | | - t = strchr(parg->comm, ':'); |
---|
| 562 | + |
---|
| 563 | + t = strchr(arg, ':'); |
---|
539 | 564 | if (t) { |
---|
540 | | - arg[t - parg->comm] = '\0'; |
---|
541 | | - t++; |
---|
| 565 | + *t = '\0'; |
---|
| 566 | + t2 = strchr(++t, '['); |
---|
| 567 | + if (t2) { |
---|
| 568 | + *t2++ = '\0'; |
---|
| 569 | + t3 = strchr(t2, ']'); |
---|
| 570 | + if (!t3) { |
---|
| 571 | + offset += t2 + strlen(t2) - arg; |
---|
| 572 | + trace_probe_log_err(offset, |
---|
| 573 | + ARRAY_NO_CLOSE); |
---|
| 574 | + return -EINVAL; |
---|
| 575 | + } else if (t3[1] != '\0') { |
---|
| 576 | + trace_probe_log_err(offset + t3 + 1 - arg, |
---|
| 577 | + BAD_ARRAY_SUFFIX); |
---|
| 578 | + return -EINVAL; |
---|
| 579 | + } |
---|
| 580 | + *t3 = '\0'; |
---|
| 581 | + if (kstrtouint(t2, 0, &parg->count) || !parg->count) { |
---|
| 582 | + trace_probe_log_err(offset + t2 - arg, |
---|
| 583 | + BAD_ARRAY_NUM); |
---|
| 584 | + return -EINVAL; |
---|
| 585 | + } |
---|
| 586 | + if (parg->count > MAX_ARRAY_LEN) { |
---|
| 587 | + trace_probe_log_err(offset + t2 - arg, |
---|
| 588 | + ARRAY_TOO_BIG); |
---|
| 589 | + return -EINVAL; |
---|
| 590 | + } |
---|
| 591 | + } |
---|
542 | 592 | } |
---|
| 593 | + |
---|
543 | 594 | /* |
---|
544 | | - * The default type of $comm should be "string", and it can't be |
---|
545 | | - * dereferenced. |
---|
| 595 | + * Since $comm and immediate string can not be dereferred, |
---|
| 596 | + * we can find those by strcmp. |
---|
546 | 597 | */ |
---|
547 | | - if (!t && strcmp(arg, "$comm") == 0) |
---|
548 | | - t = "string"; |
---|
549 | | - parg->type = find_fetch_type(t, ftbl); |
---|
| 598 | + if (strcmp(arg, "$comm") == 0 || strcmp(arg, "$COMM") == 0 || |
---|
| 599 | + strncmp(arg, "\\\"", 2) == 0) { |
---|
| 600 | + /* The type of $comm must be "string", and not an array. */ |
---|
| 601 | + if (parg->count || (t && strcmp(t, "string"))) |
---|
| 602 | + return -EINVAL; |
---|
| 603 | + parg->type = find_fetch_type("string"); |
---|
| 604 | + } else |
---|
| 605 | + parg->type = find_fetch_type(t); |
---|
550 | 606 | if (!parg->type) { |
---|
551 | | - pr_info("Unsupported type: %s\n", t); |
---|
| 607 | + trace_probe_log_err(offset + (t ? (t - arg) : 0), BAD_TYPE); |
---|
552 | 608 | return -EINVAL; |
---|
553 | 609 | } |
---|
554 | 610 | parg->offset = *size; |
---|
555 | | - *size += parg->type->size; |
---|
556 | | - ret = parse_probe_arg(arg, parg->type, &parg->fetch, is_return, |
---|
557 | | - is_kprobe, ftbl); |
---|
| 611 | + *size += parg->type->size * (parg->count ?: 1); |
---|
558 | 612 | |
---|
559 | | - if (ret >= 0 && t != NULL) |
---|
560 | | - ret = __parse_bitfield_probe_arg(t, parg->type, &parg->fetch); |
---|
561 | | - |
---|
562 | | - if (ret >= 0) { |
---|
563 | | - parg->fetch_size.fn = get_fetch_size_function(parg->type, |
---|
564 | | - parg->fetch.fn, |
---|
565 | | - ftbl); |
---|
566 | | - parg->fetch_size.data = parg->fetch.data; |
---|
| 613 | + if (parg->count) { |
---|
| 614 | + len = strlen(parg->type->fmttype) + 6; |
---|
| 615 | + parg->fmt = kmalloc(len, GFP_KERNEL); |
---|
| 616 | + if (!parg->fmt) |
---|
| 617 | + return -ENOMEM; |
---|
| 618 | + snprintf(parg->fmt, len, "%s[%d]", parg->type->fmttype, |
---|
| 619 | + parg->count); |
---|
567 | 620 | } |
---|
| 621 | + |
---|
| 622 | + code = tmp = kcalloc(FETCH_INSN_MAX, sizeof(*code), GFP_KERNEL); |
---|
| 623 | + if (!code) |
---|
| 624 | + return -ENOMEM; |
---|
| 625 | + code[FETCH_INSN_MAX - 1].op = FETCH_OP_END; |
---|
| 626 | + |
---|
| 627 | + ret = parse_probe_arg(arg, parg->type, &code, &code[FETCH_INSN_MAX - 1], |
---|
| 628 | + flags, offset); |
---|
| 629 | + if (ret) |
---|
| 630 | + goto fail; |
---|
| 631 | + |
---|
| 632 | + /* Store operation */ |
---|
| 633 | + if (!strcmp(parg->type->name, "string") || |
---|
| 634 | + !strcmp(parg->type->name, "ustring")) { |
---|
| 635 | + if (code->op != FETCH_OP_DEREF && code->op != FETCH_OP_UDEREF && |
---|
| 636 | + code->op != FETCH_OP_IMM && code->op != FETCH_OP_COMM && |
---|
| 637 | + code->op != FETCH_OP_DATA) { |
---|
| 638 | + trace_probe_log_err(offset + (t ? (t - arg) : 0), |
---|
| 639 | + BAD_STRING); |
---|
| 640 | + ret = -EINVAL; |
---|
| 641 | + goto fail; |
---|
| 642 | + } |
---|
| 643 | + if ((code->op == FETCH_OP_IMM || code->op == FETCH_OP_COMM || |
---|
| 644 | + code->op == FETCH_OP_DATA) || parg->count) { |
---|
| 645 | + /* |
---|
| 646 | + * IMM, DATA and COMM is pointing actual address, those |
---|
| 647 | + * must be kept, and if parg->count != 0, this is an |
---|
| 648 | + * array of string pointers instead of string address |
---|
| 649 | + * itself. |
---|
| 650 | + */ |
---|
| 651 | + code++; |
---|
| 652 | + if (code->op != FETCH_OP_NOP) { |
---|
| 653 | + trace_probe_log_err(offset, TOO_MANY_OPS); |
---|
| 654 | + ret = -EINVAL; |
---|
| 655 | + goto fail; |
---|
| 656 | + } |
---|
| 657 | + } |
---|
| 658 | + /* If op == DEREF, replace it with STRING */ |
---|
| 659 | + if (!strcmp(parg->type->name, "ustring") || |
---|
| 660 | + code->op == FETCH_OP_UDEREF) |
---|
| 661 | + code->op = FETCH_OP_ST_USTRING; |
---|
| 662 | + else |
---|
| 663 | + code->op = FETCH_OP_ST_STRING; |
---|
| 664 | + code->size = parg->type->size; |
---|
| 665 | + parg->dynamic = true; |
---|
| 666 | + } else if (code->op == FETCH_OP_DEREF) { |
---|
| 667 | + code->op = FETCH_OP_ST_MEM; |
---|
| 668 | + code->size = parg->type->size; |
---|
| 669 | + } else if (code->op == FETCH_OP_UDEREF) { |
---|
| 670 | + code->op = FETCH_OP_ST_UMEM; |
---|
| 671 | + code->size = parg->type->size; |
---|
| 672 | + } else { |
---|
| 673 | + code++; |
---|
| 674 | + if (code->op != FETCH_OP_NOP) { |
---|
| 675 | + trace_probe_log_err(offset, TOO_MANY_OPS); |
---|
| 676 | + ret = -EINVAL; |
---|
| 677 | + goto fail; |
---|
| 678 | + } |
---|
| 679 | + code->op = FETCH_OP_ST_RAW; |
---|
| 680 | + code->size = parg->type->size; |
---|
| 681 | + } |
---|
| 682 | + scode = code; |
---|
| 683 | + /* Modify operation */ |
---|
| 684 | + if (t != NULL) { |
---|
| 685 | + ret = __parse_bitfield_probe_arg(t, parg->type, &code); |
---|
| 686 | + if (ret) { |
---|
| 687 | + trace_probe_log_err(offset + t - arg, BAD_BITFIELD); |
---|
| 688 | + goto fail; |
---|
| 689 | + } |
---|
| 690 | + } |
---|
| 691 | + /* Loop(Array) operation */ |
---|
| 692 | + if (parg->count) { |
---|
| 693 | + if (scode->op != FETCH_OP_ST_MEM && |
---|
| 694 | + scode->op != FETCH_OP_ST_STRING && |
---|
| 695 | + scode->op != FETCH_OP_ST_USTRING) { |
---|
| 696 | + trace_probe_log_err(offset + (t ? (t - arg) : 0), |
---|
| 697 | + BAD_STRING); |
---|
| 698 | + ret = -EINVAL; |
---|
| 699 | + goto fail; |
---|
| 700 | + } |
---|
| 701 | + code++; |
---|
| 702 | + if (code->op != FETCH_OP_NOP) { |
---|
| 703 | + trace_probe_log_err(offset, TOO_MANY_OPS); |
---|
| 704 | + ret = -EINVAL; |
---|
| 705 | + goto fail; |
---|
| 706 | + } |
---|
| 707 | + code->op = FETCH_OP_LP_ARRAY; |
---|
| 708 | + code->param = parg->count; |
---|
| 709 | + } |
---|
| 710 | + code++; |
---|
| 711 | + code->op = FETCH_OP_END; |
---|
| 712 | + |
---|
| 713 | + /* Shrink down the code buffer */ |
---|
| 714 | + parg->code = kcalloc(code - tmp + 1, sizeof(*code), GFP_KERNEL); |
---|
| 715 | + if (!parg->code) |
---|
| 716 | + ret = -ENOMEM; |
---|
| 717 | + else |
---|
| 718 | + memcpy(parg->code, tmp, sizeof(*code) * (code - tmp + 1)); |
---|
| 719 | + |
---|
| 720 | +fail: |
---|
| 721 | + if (ret) { |
---|
| 722 | + for (code = tmp; code < tmp + FETCH_INSN_MAX; code++) |
---|
| 723 | + if (code->op == FETCH_NOP_SYMBOL || |
---|
| 724 | + code->op == FETCH_OP_DATA) |
---|
| 725 | + kfree(code->data); |
---|
| 726 | + } |
---|
| 727 | + kfree(tmp); |
---|
568 | 728 | |
---|
569 | 729 | return ret; |
---|
570 | 730 | } |
---|
571 | 731 | |
---|
572 | 732 | /* Return 1 if name is reserved or already used by another argument */ |
---|
573 | | -int traceprobe_conflict_field_name(const char *name, |
---|
574 | | - struct probe_arg *args, int narg) |
---|
| 733 | +static int traceprobe_conflict_field_name(const char *name, |
---|
| 734 | + struct probe_arg *args, int narg) |
---|
575 | 735 | { |
---|
576 | 736 | int i; |
---|
577 | 737 | |
---|
.. | .. |
---|
586 | 746 | return 0; |
---|
587 | 747 | } |
---|
588 | 748 | |
---|
589 | | -void traceprobe_update_arg(struct probe_arg *arg) |
---|
| 749 | +int traceprobe_parse_probe_arg(struct trace_probe *tp, int i, char *arg, |
---|
| 750 | + unsigned int flags) |
---|
590 | 751 | { |
---|
591 | | - if (CHECK_FETCH_FUNCS(bitfield, arg->fetch.fn)) |
---|
592 | | - update_bitfield_fetch_param(arg->fetch.data); |
---|
593 | | - else if (CHECK_FETCH_FUNCS(deref, arg->fetch.fn)) |
---|
594 | | - update_deref_fetch_param(arg->fetch.data); |
---|
595 | | - else if (CHECK_FETCH_FUNCS(symbol, arg->fetch.fn)) |
---|
596 | | - update_symbol_cache(arg->fetch.data); |
---|
| 752 | + struct probe_arg *parg = &tp->args[i]; |
---|
| 753 | + char *body; |
---|
| 754 | + |
---|
| 755 | + /* Increment count for freeing args in error case */ |
---|
| 756 | + tp->nr_args++; |
---|
| 757 | + |
---|
| 758 | + body = strchr(arg, '='); |
---|
| 759 | + if (body) { |
---|
| 760 | + if (body - arg > MAX_ARG_NAME_LEN) { |
---|
| 761 | + trace_probe_log_err(0, ARG_NAME_TOO_LONG); |
---|
| 762 | + return -EINVAL; |
---|
| 763 | + } else if (body == arg) { |
---|
| 764 | + trace_probe_log_err(0, NO_ARG_NAME); |
---|
| 765 | + return -EINVAL; |
---|
| 766 | + } |
---|
| 767 | + parg->name = kmemdup_nul(arg, body - arg, GFP_KERNEL); |
---|
| 768 | + body++; |
---|
| 769 | + } else { |
---|
| 770 | + /* If argument name is omitted, set "argN" */ |
---|
| 771 | + parg->name = kasprintf(GFP_KERNEL, "arg%d", i + 1); |
---|
| 772 | + body = arg; |
---|
| 773 | + } |
---|
| 774 | + if (!parg->name) |
---|
| 775 | + return -ENOMEM; |
---|
| 776 | + |
---|
| 777 | + if (!is_good_name(parg->name)) { |
---|
| 778 | + trace_probe_log_err(0, BAD_ARG_NAME); |
---|
| 779 | + return -EINVAL; |
---|
| 780 | + } |
---|
| 781 | + if (traceprobe_conflict_field_name(parg->name, tp->args, i)) { |
---|
| 782 | + trace_probe_log_err(0, USED_ARG_NAME); |
---|
| 783 | + return -EINVAL; |
---|
| 784 | + } |
---|
| 785 | + /* Parse fetch argument */ |
---|
| 786 | + return traceprobe_parse_probe_arg_body(body, &tp->size, parg, flags, |
---|
| 787 | + body - arg); |
---|
597 | 788 | } |
---|
598 | 789 | |
---|
599 | 790 | void traceprobe_free_probe_arg(struct probe_arg *arg) |
---|
600 | 791 | { |
---|
601 | | - if (CHECK_FETCH_FUNCS(bitfield, arg->fetch.fn)) |
---|
602 | | - free_bitfield_fetch_param(arg->fetch.data); |
---|
603 | | - else if (CHECK_FETCH_FUNCS(deref, arg->fetch.fn)) |
---|
604 | | - free_deref_fetch_param(arg->fetch.data); |
---|
605 | | - else if (CHECK_FETCH_FUNCS(symbol, arg->fetch.fn)) |
---|
606 | | - free_symbol_cache(arg->fetch.data); |
---|
| 792 | + struct fetch_insn *code = arg->code; |
---|
607 | 793 | |
---|
| 794 | + while (code && code->op != FETCH_OP_END) { |
---|
| 795 | + if (code->op == FETCH_NOP_SYMBOL || |
---|
| 796 | + code->op == FETCH_OP_DATA) |
---|
| 797 | + kfree(code->data); |
---|
| 798 | + code++; |
---|
| 799 | + } |
---|
| 800 | + kfree(arg->code); |
---|
608 | 801 | kfree(arg->name); |
---|
609 | 802 | kfree(arg->comm); |
---|
| 803 | + kfree(arg->fmt); |
---|
610 | 804 | } |
---|
611 | 805 | |
---|
| 806 | +int traceprobe_update_arg(struct probe_arg *arg) |
---|
| 807 | +{ |
---|
| 808 | + struct fetch_insn *code = arg->code; |
---|
| 809 | + long offset; |
---|
| 810 | + char *tmp; |
---|
| 811 | + char c; |
---|
| 812 | + int ret = 0; |
---|
| 813 | + |
---|
| 814 | + while (code && code->op != FETCH_OP_END) { |
---|
| 815 | + if (code->op == FETCH_NOP_SYMBOL) { |
---|
| 816 | + if (code[1].op != FETCH_OP_IMM) |
---|
| 817 | + return -EINVAL; |
---|
| 818 | + |
---|
| 819 | + tmp = strpbrk(code->data, "+-"); |
---|
| 820 | + if (tmp) |
---|
| 821 | + c = *tmp; |
---|
| 822 | + ret = traceprobe_split_symbol_offset(code->data, |
---|
| 823 | + &offset); |
---|
| 824 | + if (ret) |
---|
| 825 | + return ret; |
---|
| 826 | + |
---|
| 827 | + code[1].immediate = |
---|
| 828 | + (unsigned long)kallsyms_lookup_name(code->data); |
---|
| 829 | + if (tmp) |
---|
| 830 | + *tmp = c; |
---|
| 831 | + if (!code[1].immediate) |
---|
| 832 | + return -ENOENT; |
---|
| 833 | + code[1].immediate += offset; |
---|
| 834 | + } |
---|
| 835 | + code++; |
---|
| 836 | + } |
---|
| 837 | + return 0; |
---|
| 838 | +} |
---|
| 839 | + |
---|
| 840 | +/* When len=0, we just calculate the needed length */ |
---|
| 841 | +#define LEN_OR_ZERO (len ? len - pos : 0) |
---|
612 | 842 | static int __set_print_fmt(struct trace_probe *tp, char *buf, int len, |
---|
613 | 843 | bool is_return) |
---|
614 | 844 | { |
---|
615 | | - int i; |
---|
| 845 | + struct probe_arg *parg; |
---|
| 846 | + int i, j; |
---|
616 | 847 | int pos = 0; |
---|
617 | | - |
---|
618 | 848 | const char *fmt, *arg; |
---|
619 | 849 | |
---|
620 | 850 | if (!is_return) { |
---|
.. | .. |
---|
625 | 855 | arg = "REC->" FIELD_STRING_FUNC ", REC->" FIELD_STRING_RETIP; |
---|
626 | 856 | } |
---|
627 | 857 | |
---|
628 | | - /* When len=0, we just calculate the needed length */ |
---|
629 | | -#define LEN_OR_ZERO (len ? len - pos : 0) |
---|
630 | | - |
---|
631 | 858 | pos += snprintf(buf + pos, LEN_OR_ZERO, "\"%s", fmt); |
---|
632 | 859 | |
---|
633 | 860 | for (i = 0; i < tp->nr_args; i++) { |
---|
634 | | - pos += snprintf(buf + pos, LEN_OR_ZERO, " %s=%s", |
---|
635 | | - tp->args[i].name, tp->args[i].type->fmt); |
---|
| 861 | + parg = tp->args + i; |
---|
| 862 | + pos += snprintf(buf + pos, LEN_OR_ZERO, " %s=", parg->name); |
---|
| 863 | + if (parg->count) { |
---|
| 864 | + pos += snprintf(buf + pos, LEN_OR_ZERO, "{%s", |
---|
| 865 | + parg->type->fmt); |
---|
| 866 | + for (j = 1; j < parg->count; j++) |
---|
| 867 | + pos += snprintf(buf + pos, LEN_OR_ZERO, ",%s", |
---|
| 868 | + parg->type->fmt); |
---|
| 869 | + pos += snprintf(buf + pos, LEN_OR_ZERO, "}"); |
---|
| 870 | + } else |
---|
| 871 | + pos += snprintf(buf + pos, LEN_OR_ZERO, "%s", |
---|
| 872 | + parg->type->fmt); |
---|
636 | 873 | } |
---|
637 | 874 | |
---|
638 | 875 | pos += snprintf(buf + pos, LEN_OR_ZERO, "\", %s", arg); |
---|
639 | 876 | |
---|
640 | 877 | for (i = 0; i < tp->nr_args; i++) { |
---|
641 | | - if (strcmp(tp->args[i].type->name, "string") == 0) |
---|
| 878 | + parg = tp->args + i; |
---|
| 879 | + if (parg->count) { |
---|
| 880 | + if ((strcmp(parg->type->name, "string") == 0) || |
---|
| 881 | + (strcmp(parg->type->name, "ustring") == 0)) |
---|
| 882 | + fmt = ", __get_str(%s[%d])"; |
---|
| 883 | + else |
---|
| 884 | + fmt = ", REC->%s[%d]"; |
---|
| 885 | + for (j = 0; j < parg->count; j++) |
---|
| 886 | + pos += snprintf(buf + pos, LEN_OR_ZERO, |
---|
| 887 | + fmt, parg->name, j); |
---|
| 888 | + } else { |
---|
| 889 | + if ((strcmp(parg->type->name, "string") == 0) || |
---|
| 890 | + (strcmp(parg->type->name, "ustring") == 0)) |
---|
| 891 | + fmt = ", __get_str(%s)"; |
---|
| 892 | + else |
---|
| 893 | + fmt = ", REC->%s"; |
---|
642 | 894 | pos += snprintf(buf + pos, LEN_OR_ZERO, |
---|
643 | | - ", __get_str(%s)", |
---|
644 | | - tp->args[i].name); |
---|
645 | | - else |
---|
646 | | - pos += snprintf(buf + pos, LEN_OR_ZERO, ", REC->%s", |
---|
647 | | - tp->args[i].name); |
---|
| 895 | + fmt, parg->name); |
---|
| 896 | + } |
---|
648 | 897 | } |
---|
649 | | - |
---|
650 | | -#undef LEN_OR_ZERO |
---|
651 | 898 | |
---|
652 | 899 | /* return the length of print_fmt */ |
---|
653 | 900 | return pos; |
---|
654 | 901 | } |
---|
| 902 | +#undef LEN_OR_ZERO |
---|
655 | 903 | |
---|
656 | | -int set_print_fmt(struct trace_probe *tp, bool is_return) |
---|
| 904 | +int traceprobe_set_print_fmt(struct trace_probe *tp, bool is_return) |
---|
657 | 905 | { |
---|
| 906 | + struct trace_event_call *call = trace_probe_event_call(tp); |
---|
658 | 907 | int len; |
---|
659 | 908 | char *print_fmt; |
---|
660 | 909 | |
---|
.. | .. |
---|
666 | 915 | |
---|
667 | 916 | /* Second: actually write the @print_fmt */ |
---|
668 | 917 | __set_print_fmt(tp, print_fmt, len + 1, is_return); |
---|
669 | | - tp->call.print_fmt = print_fmt; |
---|
| 918 | + call->print_fmt = print_fmt; |
---|
670 | 919 | |
---|
671 | 920 | return 0; |
---|
672 | 921 | } |
---|
| 922 | + |
---|
| 923 | +int traceprobe_define_arg_fields(struct trace_event_call *event_call, |
---|
| 924 | + size_t offset, struct trace_probe *tp) |
---|
| 925 | +{ |
---|
| 926 | + int ret, i; |
---|
| 927 | + |
---|
| 928 | + /* Set argument names as fields */ |
---|
| 929 | + for (i = 0; i < tp->nr_args; i++) { |
---|
| 930 | + struct probe_arg *parg = &tp->args[i]; |
---|
| 931 | + const char *fmt = parg->type->fmttype; |
---|
| 932 | + int size = parg->type->size; |
---|
| 933 | + |
---|
| 934 | + if (parg->fmt) |
---|
| 935 | + fmt = parg->fmt; |
---|
| 936 | + if (parg->count) |
---|
| 937 | + size *= parg->count; |
---|
| 938 | + ret = trace_define_field(event_call, fmt, parg->name, |
---|
| 939 | + offset + parg->offset, size, |
---|
| 940 | + parg->type->is_signed, |
---|
| 941 | + FILTER_OTHER); |
---|
| 942 | + if (ret) |
---|
| 943 | + return ret; |
---|
| 944 | + } |
---|
| 945 | + return 0; |
---|
| 946 | +} |
---|
| 947 | + |
---|
| 948 | +static void trace_probe_event_free(struct trace_probe_event *tpe) |
---|
| 949 | +{ |
---|
| 950 | + kfree(tpe->class.system); |
---|
| 951 | + kfree(tpe->call.name); |
---|
| 952 | + kfree(tpe->call.print_fmt); |
---|
| 953 | + kfree(tpe); |
---|
| 954 | +} |
---|
| 955 | + |
---|
| 956 | +int trace_probe_append(struct trace_probe *tp, struct trace_probe *to) |
---|
| 957 | +{ |
---|
| 958 | + if (trace_probe_has_sibling(tp)) |
---|
| 959 | + return -EBUSY; |
---|
| 960 | + |
---|
| 961 | + list_del_init(&tp->list); |
---|
| 962 | + trace_probe_event_free(tp->event); |
---|
| 963 | + |
---|
| 964 | + tp->event = to->event; |
---|
| 965 | + list_add_tail(&tp->list, trace_probe_probe_list(to)); |
---|
| 966 | + |
---|
| 967 | + return 0; |
---|
| 968 | +} |
---|
| 969 | + |
---|
| 970 | +void trace_probe_unlink(struct trace_probe *tp) |
---|
| 971 | +{ |
---|
| 972 | + list_del_init(&tp->list); |
---|
| 973 | + if (list_empty(trace_probe_probe_list(tp))) |
---|
| 974 | + trace_probe_event_free(tp->event); |
---|
| 975 | + tp->event = NULL; |
---|
| 976 | +} |
---|
| 977 | + |
---|
| 978 | +void trace_probe_cleanup(struct trace_probe *tp) |
---|
| 979 | +{ |
---|
| 980 | + int i; |
---|
| 981 | + |
---|
| 982 | + for (i = 0; i < tp->nr_args; i++) |
---|
| 983 | + traceprobe_free_probe_arg(&tp->args[i]); |
---|
| 984 | + |
---|
| 985 | + if (tp->event) |
---|
| 986 | + trace_probe_unlink(tp); |
---|
| 987 | +} |
---|
| 988 | + |
---|
| 989 | +int trace_probe_init(struct trace_probe *tp, const char *event, |
---|
| 990 | + const char *group, bool alloc_filter) |
---|
| 991 | +{ |
---|
| 992 | + struct trace_event_call *call; |
---|
| 993 | + size_t size = sizeof(struct trace_probe_event); |
---|
| 994 | + int ret = 0; |
---|
| 995 | + |
---|
| 996 | + if (!event || !group) |
---|
| 997 | + return -EINVAL; |
---|
| 998 | + |
---|
| 999 | + if (alloc_filter) |
---|
| 1000 | + size += sizeof(struct trace_uprobe_filter); |
---|
| 1001 | + |
---|
| 1002 | + tp->event = kzalloc(size, GFP_KERNEL); |
---|
| 1003 | + if (!tp->event) |
---|
| 1004 | + return -ENOMEM; |
---|
| 1005 | + |
---|
| 1006 | + INIT_LIST_HEAD(&tp->event->files); |
---|
| 1007 | + INIT_LIST_HEAD(&tp->event->class.fields); |
---|
| 1008 | + INIT_LIST_HEAD(&tp->event->probes); |
---|
| 1009 | + INIT_LIST_HEAD(&tp->list); |
---|
| 1010 | + list_add(&tp->list, &tp->event->probes); |
---|
| 1011 | + |
---|
| 1012 | + call = trace_probe_event_call(tp); |
---|
| 1013 | + call->class = &tp->event->class; |
---|
| 1014 | + call->name = kstrdup(event, GFP_KERNEL); |
---|
| 1015 | + if (!call->name) { |
---|
| 1016 | + ret = -ENOMEM; |
---|
| 1017 | + goto error; |
---|
| 1018 | + } |
---|
| 1019 | + |
---|
| 1020 | + tp->event->class.system = kstrdup(group, GFP_KERNEL); |
---|
| 1021 | + if (!tp->event->class.system) { |
---|
| 1022 | + ret = -ENOMEM; |
---|
| 1023 | + goto error; |
---|
| 1024 | + } |
---|
| 1025 | + |
---|
| 1026 | + return 0; |
---|
| 1027 | + |
---|
| 1028 | +error: |
---|
| 1029 | + trace_probe_cleanup(tp); |
---|
| 1030 | + return ret; |
---|
| 1031 | +} |
---|
| 1032 | + |
---|
| 1033 | +static struct trace_event_call * |
---|
| 1034 | +find_trace_event_call(const char *system, const char *event_name) |
---|
| 1035 | +{ |
---|
| 1036 | + struct trace_event_call *tp_event; |
---|
| 1037 | + const char *name; |
---|
| 1038 | + |
---|
| 1039 | + list_for_each_entry(tp_event, &ftrace_events, list) { |
---|
| 1040 | + if (!tp_event->class->system || |
---|
| 1041 | + strcmp(system, tp_event->class->system)) |
---|
| 1042 | + continue; |
---|
| 1043 | + name = trace_event_name(tp_event); |
---|
| 1044 | + if (!name || strcmp(event_name, name)) |
---|
| 1045 | + continue; |
---|
| 1046 | + return tp_event; |
---|
| 1047 | + } |
---|
| 1048 | + |
---|
| 1049 | + return NULL; |
---|
| 1050 | +} |
---|
| 1051 | + |
---|
| 1052 | +int trace_probe_register_event_call(struct trace_probe *tp) |
---|
| 1053 | +{ |
---|
| 1054 | + struct trace_event_call *call = trace_probe_event_call(tp); |
---|
| 1055 | + int ret; |
---|
| 1056 | + |
---|
| 1057 | + lockdep_assert_held(&event_mutex); |
---|
| 1058 | + |
---|
| 1059 | + if (find_trace_event_call(trace_probe_group_name(tp), |
---|
| 1060 | + trace_probe_name(tp))) |
---|
| 1061 | + return -EEXIST; |
---|
| 1062 | + |
---|
| 1063 | + ret = register_trace_event(&call->event); |
---|
| 1064 | + if (!ret) |
---|
| 1065 | + return -ENODEV; |
---|
| 1066 | + |
---|
| 1067 | + ret = trace_add_event_call(call); |
---|
| 1068 | + if (ret) |
---|
| 1069 | + unregister_trace_event(&call->event); |
---|
| 1070 | + |
---|
| 1071 | + return ret; |
---|
| 1072 | +} |
---|
| 1073 | + |
---|
| 1074 | +int trace_probe_add_file(struct trace_probe *tp, struct trace_event_file *file) |
---|
| 1075 | +{ |
---|
| 1076 | + struct event_file_link *link; |
---|
| 1077 | + |
---|
| 1078 | + link = kmalloc(sizeof(*link), GFP_KERNEL); |
---|
| 1079 | + if (!link) |
---|
| 1080 | + return -ENOMEM; |
---|
| 1081 | + |
---|
| 1082 | + link->file = file; |
---|
| 1083 | + INIT_LIST_HEAD(&link->list); |
---|
| 1084 | + list_add_tail_rcu(&link->list, &tp->event->files); |
---|
| 1085 | + trace_probe_set_flag(tp, TP_FLAG_TRACE); |
---|
| 1086 | + return 0; |
---|
| 1087 | +} |
---|
| 1088 | + |
---|
| 1089 | +struct event_file_link *trace_probe_get_file_link(struct trace_probe *tp, |
---|
| 1090 | + struct trace_event_file *file) |
---|
| 1091 | +{ |
---|
| 1092 | + struct event_file_link *link; |
---|
| 1093 | + |
---|
| 1094 | + trace_probe_for_each_link(link, tp) { |
---|
| 1095 | + if (link->file == file) |
---|
| 1096 | + return link; |
---|
| 1097 | + } |
---|
| 1098 | + |
---|
| 1099 | + return NULL; |
---|
| 1100 | +} |
---|
| 1101 | + |
---|
| 1102 | +int trace_probe_remove_file(struct trace_probe *tp, |
---|
| 1103 | + struct trace_event_file *file) |
---|
| 1104 | +{ |
---|
| 1105 | + struct event_file_link *link; |
---|
| 1106 | + |
---|
| 1107 | + link = trace_probe_get_file_link(tp, file); |
---|
| 1108 | + if (!link) |
---|
| 1109 | + return -ENOENT; |
---|
| 1110 | + |
---|
| 1111 | + list_del_rcu(&link->list); |
---|
| 1112 | + synchronize_rcu(); |
---|
| 1113 | + kfree(link); |
---|
| 1114 | + |
---|
| 1115 | + if (list_empty(&tp->event->files)) |
---|
| 1116 | + trace_probe_clear_flag(tp, TP_FLAG_TRACE); |
---|
| 1117 | + |
---|
| 1118 | + return 0; |
---|
| 1119 | +} |
---|
| 1120 | + |
---|
| 1121 | +/* |
---|
| 1122 | + * Return the smallest index of different type argument (start from 1). |
---|
| 1123 | + * If all argument types and name are same, return 0. |
---|
| 1124 | + */ |
---|
| 1125 | +int trace_probe_compare_arg_type(struct trace_probe *a, struct trace_probe *b) |
---|
| 1126 | +{ |
---|
| 1127 | + int i; |
---|
| 1128 | + |
---|
| 1129 | + /* In case of more arguments */ |
---|
| 1130 | + if (a->nr_args < b->nr_args) |
---|
| 1131 | + return a->nr_args + 1; |
---|
| 1132 | + if (a->nr_args > b->nr_args) |
---|
| 1133 | + return b->nr_args + 1; |
---|
| 1134 | + |
---|
| 1135 | + for (i = 0; i < a->nr_args; i++) { |
---|
| 1136 | + if ((b->nr_args <= i) || |
---|
| 1137 | + ((a->args[i].type != b->args[i].type) || |
---|
| 1138 | + (a->args[i].count != b->args[i].count) || |
---|
| 1139 | + strcmp(a->args[i].name, b->args[i].name))) |
---|
| 1140 | + return i + 1; |
---|
| 1141 | + } |
---|
| 1142 | + |
---|
| 1143 | + return 0; |
---|
| 1144 | +} |
---|
| 1145 | + |
---|
| 1146 | +bool trace_probe_match_command_args(struct trace_probe *tp, |
---|
| 1147 | + int argc, const char **argv) |
---|
| 1148 | +{ |
---|
| 1149 | + char buf[MAX_ARGSTR_LEN + 1]; |
---|
| 1150 | + int i; |
---|
| 1151 | + |
---|
| 1152 | + if (tp->nr_args < argc) |
---|
| 1153 | + return false; |
---|
| 1154 | + |
---|
| 1155 | + for (i = 0; i < argc; i++) { |
---|
| 1156 | + snprintf(buf, sizeof(buf), "%s=%s", |
---|
| 1157 | + tp->args[i].name, tp->args[i].comm); |
---|
| 1158 | + if (strcmp(buf, argv[i])) |
---|
| 1159 | + return false; |
---|
| 1160 | + } |
---|
| 1161 | + return true; |
---|
| 1162 | +} |
---|