diff options
Diffstat (limited to 'kernel/trace/trace_probe.c')
| -rw-r--r-- | kernel/trace/trace_probe.c | 291 |
1 files changed, 205 insertions, 86 deletions
diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c index 8f8411e7835f..a347faced959 100644 --- a/kernel/trace/trace_probe.c +++ b/kernel/trace/trace_probe.c | |||
| @@ -13,6 +13,11 @@ | |||
| 13 | 13 | ||
| 14 | #include "trace_probe.h" | 14 | #include "trace_probe.h" |
| 15 | 15 | ||
| 16 | #undef C | ||
| 17 | #define C(a, b) b | ||
| 18 | |||
| 19 | static const char *trace_probe_err_text[] = { ERRORS }; | ||
| 20 | |||
| 16 | static const char *reserved_field_names[] = { | 21 | static const char *reserved_field_names[] = { |
| 17 | "common_type", | 22 | "common_type", |
| 18 | "common_flags", | 23 | "common_flags", |
| @@ -133,6 +138,60 @@ fail: | |||
| 133 | return NULL; | 138 | return NULL; |
| 134 | } | 139 | } |
| 135 | 140 | ||
| 141 | static struct trace_probe_log trace_probe_log; | ||
| 142 | |||
| 143 | void trace_probe_log_init(const char *subsystem, int argc, const char **argv) | ||
| 144 | { | ||
| 145 | trace_probe_log.subsystem = subsystem; | ||
| 146 | trace_probe_log.argc = argc; | ||
| 147 | trace_probe_log.argv = argv; | ||
| 148 | trace_probe_log.index = 0; | ||
| 149 | } | ||
| 150 | |||
| 151 | void trace_probe_log_clear(void) | ||
| 152 | { | ||
| 153 | memset(&trace_probe_log, 0, sizeof(trace_probe_log)); | ||
| 154 | } | ||
| 155 | |||
| 156 | void trace_probe_log_set_index(int index) | ||
| 157 | { | ||
| 158 | trace_probe_log.index = index; | ||
| 159 | } | ||
| 160 | |||
| 161 | void __trace_probe_log_err(int offset, int err_type) | ||
| 162 | { | ||
| 163 | char *command, *p; | ||
| 164 | int i, len = 0, pos = 0; | ||
| 165 | |||
| 166 | if (!trace_probe_log.argv) | ||
| 167 | return; | ||
| 168 | |||
| 169 | /* Recalcurate the length and allocate buffer */ | ||
| 170 | for (i = 0; i < trace_probe_log.argc; i++) { | ||
| 171 | if (i == trace_probe_log.index) | ||
| 172 | pos = len; | ||
| 173 | len += strlen(trace_probe_log.argv[i]) + 1; | ||
| 174 | } | ||
| 175 | command = kzalloc(len, GFP_KERNEL); | ||
| 176 | if (!command) | ||
| 177 | return; | ||
| 178 | |||
| 179 | /* And make a command string from argv array */ | ||
| 180 | p = command; | ||
| 181 | for (i = 0; i < trace_probe_log.argc; i++) { | ||
| 182 | len = strlen(trace_probe_log.argv[i]); | ||
| 183 | strcpy(p, trace_probe_log.argv[i]); | ||
| 184 | p[len] = ' '; | ||
| 185 | p += len + 1; | ||
| 186 | } | ||
| 187 | *(p - 1) = '\0'; | ||
| 188 | |||
| 189 | tracing_log_err(NULL, trace_probe_log.subsystem, command, | ||
| 190 | trace_probe_err_text, err_type, pos + offset); | ||
| 191 | |||
| 192 | kfree(command); | ||
| 193 | } | ||
| 194 | |||
| 136 | /* Split symbol and offset. */ | 195 | /* Split symbol and offset. */ |
| 137 | int traceprobe_split_symbol_offset(char *symbol, long *offset) | 196 | int traceprobe_split_symbol_offset(char *symbol, long *offset) |
| 138 | { | 197 | { |
| @@ -156,7 +215,7 @@ int traceprobe_split_symbol_offset(char *symbol, long *offset) | |||
| 156 | 215 | ||
| 157 | /* @buf must has MAX_EVENT_NAME_LEN size */ | 216 | /* @buf must has MAX_EVENT_NAME_LEN size */ |
| 158 | int traceprobe_parse_event_name(const char **pevent, const char **pgroup, | 217 | int traceprobe_parse_event_name(const char **pevent, const char **pgroup, |
| 159 | char *buf) | 218 | char *buf, int offset) |
| 160 | { | 219 | { |
| 161 | const char *slash, *event = *pevent; | 220 | const char *slash, *event = *pevent; |
| 162 | int len; | 221 | int len; |
| @@ -164,32 +223,33 @@ int traceprobe_parse_event_name(const char **pevent, const char **pgroup, | |||
| 164 | slash = strchr(event, '/'); | 223 | slash = strchr(event, '/'); |
| 165 | if (slash) { | 224 | if (slash) { |
| 166 | if (slash == event) { | 225 | if (slash == event) { |
| 167 | pr_info("Group name is not specified\n"); | 226 | trace_probe_log_err(offset, NO_GROUP_NAME); |
| 168 | return -EINVAL; | 227 | return -EINVAL; |
| 169 | } | 228 | } |
| 170 | if (slash - event + 1 > MAX_EVENT_NAME_LEN) { | 229 | if (slash - event + 1 > MAX_EVENT_NAME_LEN) { |
| 171 | pr_info("Group name is too long\n"); | 230 | trace_probe_log_err(offset, GROUP_TOO_LONG); |
| 172 | return -E2BIG; | 231 | return -EINVAL; |
| 173 | } | 232 | } |
| 174 | strlcpy(buf, event, slash - event + 1); | 233 | strlcpy(buf, event, slash - event + 1); |
| 175 | if (!is_good_name(buf)) { | 234 | if (!is_good_name(buf)) { |
| 176 | pr_info("Group name must follow the same rules as C identifiers\n"); | 235 | trace_probe_log_err(offset, BAD_GROUP_NAME); |
| 177 | return -EINVAL; | 236 | return -EINVAL; |
| 178 | } | 237 | } |
| 179 | *pgroup = buf; | 238 | *pgroup = buf; |
| 180 | *pevent = slash + 1; | 239 | *pevent = slash + 1; |
| 240 | offset += slash - event + 1; | ||
| 181 | event = *pevent; | 241 | event = *pevent; |
| 182 | } | 242 | } |
| 183 | len = strlen(event); | 243 | len = strlen(event); |
| 184 | if (len == 0) { | 244 | if (len == 0) { |
| 185 | pr_info("Event name is not specified\n"); | 245 | trace_probe_log_err(offset, NO_EVENT_NAME); |
| 186 | return -EINVAL; | 246 | return -EINVAL; |
| 187 | } else if (len > MAX_EVENT_NAME_LEN) { | 247 | } else if (len > MAX_EVENT_NAME_LEN) { |
| 188 | pr_info("Event name is too long\n"); | 248 | trace_probe_log_err(offset, EVENT_TOO_LONG); |
| 189 | return -E2BIG; | 249 | return -EINVAL; |
| 190 | } | 250 | } |
| 191 | if (!is_good_name(event)) { | 251 | if (!is_good_name(event)) { |
| 192 | pr_info("Event name must follow the same rules as C identifiers\n"); | 252 | trace_probe_log_err(offset, BAD_EVENT_NAME); |
| 193 | return -EINVAL; | 253 | return -EINVAL; |
| 194 | } | 254 | } |
| 195 | return 0; | 255 | return 0; |
| @@ -198,56 +258,67 @@ int traceprobe_parse_event_name(const char **pevent, const char **pgroup, | |||
| 198 | #define PARAM_MAX_STACK (THREAD_SIZE / sizeof(unsigned long)) | 258 | #define PARAM_MAX_STACK (THREAD_SIZE / sizeof(unsigned long)) |
| 199 | 259 | ||
| 200 | static int parse_probe_vars(char *arg, const struct fetch_type *t, | 260 | static int parse_probe_vars(char *arg, const struct fetch_type *t, |
| 201 | struct fetch_insn *code, unsigned int flags) | 261 | struct fetch_insn *code, unsigned int flags, int offs) |
| 202 | { | 262 | { |
| 203 | unsigned long param; | 263 | unsigned long param; |
| 204 | int ret = 0; | 264 | int ret = 0; |
| 205 | int len; | 265 | int len; |
| 206 | 266 | ||
| 207 | if (strcmp(arg, "retval") == 0) { | 267 | if (strcmp(arg, "retval") == 0) { |
| 208 | if (flags & TPARG_FL_RETURN) | 268 | if (flags & TPARG_FL_RETURN) { |
| 209 | code->op = FETCH_OP_RETVAL; | 269 | code->op = FETCH_OP_RETVAL; |
| 210 | else | 270 | } else { |
| 271 | trace_probe_log_err(offs, RETVAL_ON_PROBE); | ||
| 211 | ret = -EINVAL; | 272 | ret = -EINVAL; |
| 273 | } | ||
| 212 | } else if ((len = str_has_prefix(arg, "stack"))) { | 274 | } else if ((len = str_has_prefix(arg, "stack"))) { |
| 213 | if (arg[len] == '\0') { | 275 | if (arg[len] == '\0') { |
| 214 | code->op = FETCH_OP_STACKP; | 276 | code->op = FETCH_OP_STACKP; |
| 215 | } else if (isdigit(arg[len])) { | 277 | } else if (isdigit(arg[len])) { |
| 216 | ret = kstrtoul(arg + len, 10, ¶m); | 278 | ret = kstrtoul(arg + len, 10, ¶m); |
| 217 | if (ret || ((flags & TPARG_FL_KERNEL) && | 279 | if (ret) { |
| 218 | param > PARAM_MAX_STACK)) | 280 | goto inval_var; |
| 281 | } else if ((flags & TPARG_FL_KERNEL) && | ||
| 282 | param > PARAM_MAX_STACK) { | ||
| 283 | trace_probe_log_err(offs, BAD_STACK_NUM); | ||
| 219 | ret = -EINVAL; | 284 | ret = -EINVAL; |
| 220 | else { | 285 | } else { |
| 221 | code->op = FETCH_OP_STACK; | 286 | code->op = FETCH_OP_STACK; |
| 222 | code->param = (unsigned int)param; | 287 | code->param = (unsigned int)param; |
| 223 | } | 288 | } |
| 224 | } else | 289 | } else |
| 225 | ret = -EINVAL; | 290 | goto inval_var; |
| 226 | } else if (strcmp(arg, "comm") == 0) { | 291 | } else if (strcmp(arg, "comm") == 0) { |
| 227 | code->op = FETCH_OP_COMM; | 292 | code->op = FETCH_OP_COMM; |
| 228 | #ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API | 293 | #ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API |
| 229 | } else if (((flags & TPARG_FL_MASK) == | 294 | } else if (((flags & TPARG_FL_MASK) == |
| 230 | (TPARG_FL_KERNEL | TPARG_FL_FENTRY)) && | 295 | (TPARG_FL_KERNEL | TPARG_FL_FENTRY)) && |
| 231 | (len = str_has_prefix(arg, "arg"))) { | 296 | (len = str_has_prefix(arg, "arg"))) { |
| 232 | if (!isdigit(arg[len])) | ||
| 233 | return -EINVAL; | ||
| 234 | ret = kstrtoul(arg + len, 10, ¶m); | 297 | ret = kstrtoul(arg + len, 10, ¶m); |
| 235 | if (ret || !param || param > PARAM_MAX_STACK) | 298 | if (ret) { |
| 299 | goto inval_var; | ||
| 300 | } else if (!param || param > PARAM_MAX_STACK) { | ||
| 301 | trace_probe_log_err(offs, BAD_ARG_NUM); | ||
| 236 | return -EINVAL; | 302 | return -EINVAL; |
| 303 | } | ||
| 237 | code->op = FETCH_OP_ARG; | 304 | code->op = FETCH_OP_ARG; |
| 238 | code->param = (unsigned int)param - 1; | 305 | code->param = (unsigned int)param - 1; |
| 239 | #endif | 306 | #endif |
| 240 | } else | 307 | } else |
| 241 | ret = -EINVAL; | 308 | goto inval_var; |
| 242 | 309 | ||
| 243 | return ret; | 310 | return ret; |
| 311 | |||
| 312 | inval_var: | ||
| 313 | trace_probe_log_err(offs, BAD_VAR); | ||
| 314 | return -EINVAL; | ||
| 244 | } | 315 | } |
| 245 | 316 | ||
| 246 | /* Recursive argument parser */ | 317 | /* Recursive argument parser */ |
| 247 | static int | 318 | static int |
| 248 | parse_probe_arg(char *arg, const struct fetch_type *type, | 319 | parse_probe_arg(char *arg, const struct fetch_type *type, |
| 249 | struct fetch_insn **pcode, struct fetch_insn *end, | 320 | struct fetch_insn **pcode, struct fetch_insn *end, |
| 250 | unsigned int flags) | 321 | unsigned int flags, int offs) |
| 251 | { | 322 | { |
| 252 | struct fetch_insn *code = *pcode; | 323 | struct fetch_insn *code = *pcode; |
| 253 | unsigned long param; | 324 | unsigned long param; |
| @@ -257,7 +328,7 @@ parse_probe_arg(char *arg, const struct fetch_type *type, | |||
| 257 | 328 | ||
| 258 | switch (arg[0]) { | 329 | switch (arg[0]) { |
| 259 | case '$': | 330 | case '$': |
| 260 | ret = parse_probe_vars(arg + 1, type, code, flags); | 331 | ret = parse_probe_vars(arg + 1, type, code, flags, offs); |
| 261 | break; | 332 | break; |
| 262 | 333 | ||
| 263 | case '%': /* named register */ | 334 | case '%': /* named register */ |
| @@ -266,47 +337,57 @@ parse_probe_arg(char *arg, const struct fetch_type *type, | |||
| 266 | code->op = FETCH_OP_REG; | 337 | code->op = FETCH_OP_REG; |
| 267 | code->param = (unsigned int)ret; | 338 | code->param = (unsigned int)ret; |
| 268 | ret = 0; | 339 | ret = 0; |
| 269 | } | 340 | } else |
| 341 | trace_probe_log_err(offs, BAD_REG_NAME); | ||
| 270 | break; | 342 | break; |
| 271 | 343 | ||
| 272 | case '@': /* memory, file-offset or symbol */ | 344 | case '@': /* memory, file-offset or symbol */ |
| 273 | if (isdigit(arg[1])) { | 345 | if (isdigit(arg[1])) { |
| 274 | ret = kstrtoul(arg + 1, 0, ¶m); | 346 | ret = kstrtoul(arg + 1, 0, ¶m); |
| 275 | if (ret) | 347 | if (ret) { |
| 348 | trace_probe_log_err(offs, BAD_MEM_ADDR); | ||
| 276 | break; | 349 | break; |
| 350 | } | ||
| 277 | /* load address */ | 351 | /* load address */ |
| 278 | code->op = FETCH_OP_IMM; | 352 | code->op = FETCH_OP_IMM; |
| 279 | code->immediate = param; | 353 | code->immediate = param; |
| 280 | } else if (arg[1] == '+') { | 354 | } else if (arg[1] == '+') { |
| 281 | /* kprobes don't support file offsets */ | 355 | /* kprobes don't support file offsets */ |
| 282 | if (flags & TPARG_FL_KERNEL) | 356 | if (flags & TPARG_FL_KERNEL) { |
| 357 | trace_probe_log_err(offs, FILE_ON_KPROBE); | ||
| 283 | return -EINVAL; | 358 | return -EINVAL; |
| 284 | 359 | } | |
| 285 | ret = kstrtol(arg + 2, 0, &offset); | 360 | ret = kstrtol(arg + 2, 0, &offset); |
| 286 | if (ret) | 361 | if (ret) { |
| 362 | trace_probe_log_err(offs, BAD_FILE_OFFS); | ||
| 287 | break; | 363 | break; |
| 364 | } | ||
| 288 | 365 | ||
| 289 | code->op = FETCH_OP_FOFFS; | 366 | code->op = FETCH_OP_FOFFS; |
| 290 | code->immediate = (unsigned long)offset; // imm64? | 367 | code->immediate = (unsigned long)offset; // imm64? |
| 291 | } else { | 368 | } else { |
| 292 | /* uprobes don't support symbols */ | 369 | /* uprobes don't support symbols */ |
| 293 | if (!(flags & TPARG_FL_KERNEL)) | 370 | if (!(flags & TPARG_FL_KERNEL)) { |
| 371 | trace_probe_log_err(offs, SYM_ON_UPROBE); | ||
| 294 | return -EINVAL; | 372 | return -EINVAL; |
| 295 | 373 | } | |
| 296 | /* Preserve symbol for updating */ | 374 | /* Preserve symbol for updating */ |
| 297 | code->op = FETCH_NOP_SYMBOL; | 375 | code->op = FETCH_NOP_SYMBOL; |
| 298 | code->data = kstrdup(arg + 1, GFP_KERNEL); | 376 | code->data = kstrdup(arg + 1, GFP_KERNEL); |
| 299 | if (!code->data) | 377 | if (!code->data) |
| 300 | return -ENOMEM; | 378 | return -ENOMEM; |
| 301 | if (++code == end) | 379 | if (++code == end) { |
| 302 | return -E2BIG; | 380 | trace_probe_log_err(offs, TOO_MANY_OPS); |
| 303 | 381 | return -EINVAL; | |
| 382 | } | ||
| 304 | code->op = FETCH_OP_IMM; | 383 | code->op = FETCH_OP_IMM; |
| 305 | code->immediate = 0; | 384 | code->immediate = 0; |
| 306 | } | 385 | } |
| 307 | /* These are fetching from memory */ | 386 | /* These are fetching from memory */ |
| 308 | if (++code == end) | 387 | if (++code == end) { |
| 309 | return -E2BIG; | 388 | trace_probe_log_err(offs, TOO_MANY_OPS); |
| 389 | return -EINVAL; | ||
| 390 | } | ||
| 310 | *pcode = code; | 391 | *pcode = code; |
| 311 | code->op = FETCH_OP_DEREF; | 392 | code->op = FETCH_OP_DEREF; |
| 312 | code->offset = offset; | 393 | code->offset = offset; |
| @@ -317,28 +398,38 @@ parse_probe_arg(char *arg, const struct fetch_type *type, | |||
| 317 | /* fall through */ | 398 | /* fall through */ |
| 318 | case '-': | 399 | case '-': |
| 319 | tmp = strchr(arg, '('); | 400 | tmp = strchr(arg, '('); |
| 320 | if (!tmp) | 401 | if (!tmp) { |
| 402 | trace_probe_log_err(offs, DEREF_NEED_BRACE); | ||
| 321 | return -EINVAL; | 403 | return -EINVAL; |
| 322 | 404 | } | |
| 323 | *tmp = '\0'; | 405 | *tmp = '\0'; |
| 324 | ret = kstrtol(arg, 0, &offset); | 406 | ret = kstrtol(arg, 0, &offset); |
| 325 | if (ret) | 407 | if (ret) { |
| 408 | trace_probe_log_err(offs, BAD_DEREF_OFFS); | ||
| 326 | break; | 409 | break; |
| 327 | 410 | } | |
| 411 | offs += (tmp + 1 - arg) + (arg[0] != '-' ? 1 : 0); | ||
| 328 | arg = tmp + 1; | 412 | arg = tmp + 1; |
| 329 | tmp = strrchr(arg, ')'); | 413 | tmp = strrchr(arg, ')'); |
| 330 | 414 | if (!tmp) { | |
| 331 | if (tmp) { | 415 | trace_probe_log_err(offs + strlen(arg), |
| 416 | DEREF_OPEN_BRACE); | ||
| 417 | return -EINVAL; | ||
| 418 | } else { | ||
| 332 | const struct fetch_type *t2 = find_fetch_type(NULL); | 419 | const struct fetch_type *t2 = find_fetch_type(NULL); |
| 333 | 420 | ||
| 334 | *tmp = '\0'; | 421 | *tmp = '\0'; |
| 335 | ret = parse_probe_arg(arg, t2, &code, end, flags); | 422 | ret = parse_probe_arg(arg, t2, &code, end, flags, offs); |
| 336 | if (ret) | 423 | if (ret) |
| 337 | break; | 424 | break; |
| 338 | if (code->op == FETCH_OP_COMM) | 425 | if (code->op == FETCH_OP_COMM) { |
| 426 | trace_probe_log_err(offs, COMM_CANT_DEREF); | ||
| 339 | return -EINVAL; | 427 | return -EINVAL; |
| 340 | if (++code == end) | 428 | } |
| 341 | return -E2BIG; | 429 | if (++code == end) { |
| 430 | trace_probe_log_err(offs, TOO_MANY_OPS); | ||
| 431 | return -EINVAL; | ||
| 432 | } | ||
| 342 | *pcode = code; | 433 | *pcode = code; |
| 343 | 434 | ||
| 344 | code->op = FETCH_OP_DEREF; | 435 | code->op = FETCH_OP_DEREF; |
| @@ -348,6 +439,7 @@ parse_probe_arg(char *arg, const struct fetch_type *type, | |||
| 348 | } | 439 | } |
| 349 | if (!ret && code->op == FETCH_OP_NOP) { | 440 | if (!ret && code->op == FETCH_OP_NOP) { |
| 350 | /* Parsed, but do not find fetch method */ | 441 | /* Parsed, but do not find fetch method */ |
| 442 | trace_probe_log_err(offs, BAD_FETCH_ARG); | ||
| 351 | ret = -EINVAL; | 443 | ret = -EINVAL; |
| 352 | } | 444 | } |
| 353 | return ret; | 445 | return ret; |
| @@ -379,7 +471,7 @@ static int __parse_bitfield_probe_arg(const char *bf, | |||
| 379 | return -EINVAL; | 471 | return -EINVAL; |
| 380 | code++; | 472 | code++; |
| 381 | if (code->op != FETCH_OP_NOP) | 473 | if (code->op != FETCH_OP_NOP) |
| 382 | return -E2BIG; | 474 | return -EINVAL; |
| 383 | *pcode = code; | 475 | *pcode = code; |
| 384 | 476 | ||
| 385 | code->op = FETCH_OP_MOD_BF; | 477 | code->op = FETCH_OP_MOD_BF; |
| @@ -392,44 +484,66 @@ static int __parse_bitfield_probe_arg(const char *bf, | |||
| 392 | 484 | ||
| 393 | /* String length checking wrapper */ | 485 | /* String length checking wrapper */ |
| 394 | static int traceprobe_parse_probe_arg_body(char *arg, ssize_t *size, | 486 | static int traceprobe_parse_probe_arg_body(char *arg, ssize_t *size, |
| 395 | struct probe_arg *parg, unsigned int flags) | 487 | struct probe_arg *parg, unsigned int flags, int offset) |
| 396 | { | 488 | { |
| 397 | struct fetch_insn *code, *scode, *tmp = NULL; | 489 | struct fetch_insn *code, *scode, *tmp = NULL; |
| 398 | char *t, *t2; | 490 | char *t, *t2, *t3; |
| 399 | int ret, len; | 491 | int ret, len; |
| 400 | 492 | ||
| 401 | if (strlen(arg) > MAX_ARGSTR_LEN) { | 493 | len = strlen(arg); |
| 402 | pr_info("Argument is too long.: %s\n", arg); | 494 | if (len > MAX_ARGSTR_LEN) { |
| 403 | return -ENOSPC; | 495 | trace_probe_log_err(offset, ARG_TOO_LONG); |
| 496 | return -EINVAL; | ||
| 497 | } else if (len == 0) { | ||
| 498 | trace_probe_log_err(offset, NO_ARG_BODY); | ||
| 499 | return -EINVAL; | ||
| 404 | } | 500 | } |
| 501 | |||
| 405 | parg->comm = kstrdup(arg, GFP_KERNEL); | 502 | parg->comm = kstrdup(arg, GFP_KERNEL); |
| 406 | if (!parg->comm) { | 503 | if (!parg->comm) |
| 407 | pr_info("Failed to allocate memory for command '%s'.\n", arg); | ||
| 408 | return -ENOMEM; | 504 | return -ENOMEM; |
| 409 | } | 505 | |
| 410 | t = strchr(arg, ':'); | 506 | t = strchr(arg, ':'); |
| 411 | if (t) { | 507 | if (t) { |
| 412 | *t = '\0'; | 508 | *t = '\0'; |
| 413 | t2 = strchr(++t, '['); | 509 | t2 = strchr(++t, '['); |
| 414 | if (t2) { | 510 | if (t2) { |
| 415 | *t2 = '\0'; | 511 | *t2++ = '\0'; |
| 416 | parg->count = simple_strtoul(t2 + 1, &t2, 0); | 512 | t3 = strchr(t2, ']'); |
| 417 | if (strcmp(t2, "]") || parg->count == 0) | 513 | if (!t3) { |
| 514 | offset += t2 + strlen(t2) - arg; | ||
| 515 | trace_probe_log_err(offset, | ||
| 516 | ARRAY_NO_CLOSE); | ||
| 517 | return -EINVAL; | ||
| 518 | } else if (t3[1] != '\0') { | ||
| 519 | trace_probe_log_err(offset + t3 + 1 - arg, | ||
| 520 | BAD_ARRAY_SUFFIX); | ||
| 418 | return -EINVAL; | 521 | return -EINVAL; |
| 419 | if (parg->count > MAX_ARRAY_LEN) | 522 | } |
| 420 | return -E2BIG; | 523 | *t3 = '\0'; |
| 524 | if (kstrtouint(t2, 0, &parg->count) || !parg->count) { | ||
| 525 | trace_probe_log_err(offset + t2 - arg, | ||
| 526 | BAD_ARRAY_NUM); | ||
| 527 | return -EINVAL; | ||
| 528 | } | ||
| 529 | if (parg->count > MAX_ARRAY_LEN) { | ||
| 530 | trace_probe_log_err(offset + t2 - arg, | ||
| 531 | ARRAY_TOO_BIG); | ||
| 532 | return -EINVAL; | ||
| 533 | } | ||
| 421 | } | 534 | } |
| 422 | } | 535 | } |
| 423 | /* | 536 | |
| 424 | * The default type of $comm should be "string", and it can't be | 537 | /* Since $comm can not be dereferred, we can find $comm by strcmp */ |
| 425 | * dereferenced. | 538 | if (strcmp(arg, "$comm") == 0) { |
| 426 | */ | 539 | /* The type of $comm must be "string", and not an array. */ |
| 427 | if (!t && strcmp(arg, "$comm") == 0) | 540 | if (parg->count || (t && strcmp(t, "string"))) |
| 541 | return -EINVAL; | ||
| 428 | parg->type = find_fetch_type("string"); | 542 | parg->type = find_fetch_type("string"); |
| 429 | else | 543 | } else |
| 430 | parg->type = find_fetch_type(t); | 544 | parg->type = find_fetch_type(t); |
| 431 | if (!parg->type) { | 545 | if (!parg->type) { |
| 432 | pr_info("Unsupported type: %s\n", t); | 546 | trace_probe_log_err(offset + (t ? (t - arg) : 0), BAD_TYPE); |
| 433 | return -EINVAL; | 547 | return -EINVAL; |
| 434 | } | 548 | } |
| 435 | parg->offset = *size; | 549 | parg->offset = *size; |
| @@ -444,13 +558,13 @@ static int traceprobe_parse_probe_arg_body(char *arg, ssize_t *size, | |||
| 444 | parg->count); | 558 | parg->count); |
| 445 | } | 559 | } |
| 446 | 560 | ||
| 447 | code = tmp = kzalloc(sizeof(*code) * FETCH_INSN_MAX, GFP_KERNEL); | 561 | code = tmp = kcalloc(FETCH_INSN_MAX, sizeof(*code), GFP_KERNEL); |
| 448 | if (!code) | 562 | if (!code) |
| 449 | return -ENOMEM; | 563 | return -ENOMEM; |
| 450 | code[FETCH_INSN_MAX - 1].op = FETCH_OP_END; | 564 | code[FETCH_INSN_MAX - 1].op = FETCH_OP_END; |
| 451 | 565 | ||
| 452 | ret = parse_probe_arg(arg, parg->type, &code, &code[FETCH_INSN_MAX - 1], | 566 | ret = parse_probe_arg(arg, parg->type, &code, &code[FETCH_INSN_MAX - 1], |
| 453 | flags); | 567 | flags, offset); |
| 454 | if (ret) | 568 | if (ret) |
| 455 | goto fail; | 569 | goto fail; |
| 456 | 570 | ||
| @@ -458,7 +572,8 @@ static int traceprobe_parse_probe_arg_body(char *arg, ssize_t *size, | |||
| 458 | if (!strcmp(parg->type->name, "string")) { | 572 | if (!strcmp(parg->type->name, "string")) { |
| 459 | if (code->op != FETCH_OP_DEREF && code->op != FETCH_OP_IMM && | 573 | if (code->op != FETCH_OP_DEREF && code->op != FETCH_OP_IMM && |
| 460 | code->op != FETCH_OP_COMM) { | 574 | code->op != FETCH_OP_COMM) { |
| 461 | pr_info("string only accepts memory or address.\n"); | 575 | trace_probe_log_err(offset + (t ? (t - arg) : 0), |
| 576 | BAD_STRING); | ||
| 462 | ret = -EINVAL; | 577 | ret = -EINVAL; |
| 463 | goto fail; | 578 | goto fail; |
| 464 | } | 579 | } |
| @@ -470,7 +585,8 @@ static int traceprobe_parse_probe_arg_body(char *arg, ssize_t *size, | |||
| 470 | */ | 585 | */ |
| 471 | code++; | 586 | code++; |
| 472 | if (code->op != FETCH_OP_NOP) { | 587 | if (code->op != FETCH_OP_NOP) { |
| 473 | ret = -E2BIG; | 588 | trace_probe_log_err(offset, TOO_MANY_OPS); |
| 589 | ret = -EINVAL; | ||
| 474 | goto fail; | 590 | goto fail; |
| 475 | } | 591 | } |
| 476 | } | 592 | } |
| @@ -483,7 +599,8 @@ static int traceprobe_parse_probe_arg_body(char *arg, ssize_t *size, | |||
| 483 | } else { | 599 | } else { |
| 484 | code++; | 600 | code++; |
| 485 | if (code->op != FETCH_OP_NOP) { | 601 | if (code->op != FETCH_OP_NOP) { |
| 486 | ret = -E2BIG; | 602 | trace_probe_log_err(offset, TOO_MANY_OPS); |
| 603 | ret = -EINVAL; | ||
| 487 | goto fail; | 604 | goto fail; |
| 488 | } | 605 | } |
| 489 | code->op = FETCH_OP_ST_RAW; | 606 | code->op = FETCH_OP_ST_RAW; |
| @@ -493,20 +610,24 @@ static int traceprobe_parse_probe_arg_body(char *arg, ssize_t *size, | |||
| 493 | /* Modify operation */ | 610 | /* Modify operation */ |
| 494 | if (t != NULL) { | 611 | if (t != NULL) { |
| 495 | ret = __parse_bitfield_probe_arg(t, parg->type, &code); | 612 | ret = __parse_bitfield_probe_arg(t, parg->type, &code); |
| 496 | if (ret) | 613 | if (ret) { |
| 614 | trace_probe_log_err(offset + t - arg, BAD_BITFIELD); | ||
| 497 | goto fail; | 615 | goto fail; |
| 616 | } | ||
| 498 | } | 617 | } |
| 499 | /* Loop(Array) operation */ | 618 | /* Loop(Array) operation */ |
| 500 | if (parg->count) { | 619 | if (parg->count) { |
| 501 | if (scode->op != FETCH_OP_ST_MEM && | 620 | if (scode->op != FETCH_OP_ST_MEM && |
| 502 | scode->op != FETCH_OP_ST_STRING) { | 621 | scode->op != FETCH_OP_ST_STRING) { |
| 503 | pr_info("array only accepts memory or address\n"); | 622 | trace_probe_log_err(offset + (t ? (t - arg) : 0), |
| 623 | BAD_STRING); | ||
| 504 | ret = -EINVAL; | 624 | ret = -EINVAL; |
| 505 | goto fail; | 625 | goto fail; |
| 506 | } | 626 | } |
| 507 | code++; | 627 | code++; |
| 508 | if (code->op != FETCH_OP_NOP) { | 628 | if (code->op != FETCH_OP_NOP) { |
| 509 | ret = -E2BIG; | 629 | trace_probe_log_err(offset, TOO_MANY_OPS); |
| 630 | ret = -EINVAL; | ||
| 510 | goto fail; | 631 | goto fail; |
| 511 | } | 632 | } |
| 512 | code->op = FETCH_OP_LP_ARRAY; | 633 | code->op = FETCH_OP_LP_ARRAY; |
| @@ -516,7 +637,7 @@ static int traceprobe_parse_probe_arg_body(char *arg, ssize_t *size, | |||
| 516 | code->op = FETCH_OP_END; | 637 | code->op = FETCH_OP_END; |
| 517 | 638 | ||
| 518 | /* Shrink down the code buffer */ | 639 | /* Shrink down the code buffer */ |
| 519 | parg->code = kzalloc(sizeof(*code) * (code - tmp + 1), GFP_KERNEL); | 640 | parg->code = kcalloc(code - tmp + 1, sizeof(*code), GFP_KERNEL); |
| 520 | if (!parg->code) | 641 | if (!parg->code) |
| 521 | ret = -ENOMEM; | 642 | ret = -ENOMEM; |
| 522 | else | 643 | else |
| @@ -555,15 +676,19 @@ int traceprobe_parse_probe_arg(struct trace_probe *tp, int i, char *arg, | |||
| 555 | { | 676 | { |
| 556 | struct probe_arg *parg = &tp->args[i]; | 677 | struct probe_arg *parg = &tp->args[i]; |
| 557 | char *body; | 678 | char *body; |
| 558 | int ret; | ||
| 559 | 679 | ||
| 560 | /* Increment count for freeing args in error case */ | 680 | /* Increment count for freeing args in error case */ |
| 561 | tp->nr_args++; | 681 | tp->nr_args++; |
| 562 | 682 | ||
| 563 | body = strchr(arg, '='); | 683 | body = strchr(arg, '='); |
| 564 | if (body) { | 684 | if (body) { |
| 565 | if (body - arg > MAX_ARG_NAME_LEN || body == arg) | 685 | if (body - arg > MAX_ARG_NAME_LEN) { |
| 686 | trace_probe_log_err(0, ARG_NAME_TOO_LONG); | ||
| 687 | return -EINVAL; | ||
| 688 | } else if (body == arg) { | ||
| 689 | trace_probe_log_err(0, NO_ARG_NAME); | ||
| 566 | return -EINVAL; | 690 | return -EINVAL; |
| 691 | } | ||
| 567 | parg->name = kmemdup_nul(arg, body - arg, GFP_KERNEL); | 692 | parg->name = kmemdup_nul(arg, body - arg, GFP_KERNEL); |
| 568 | body++; | 693 | body++; |
| 569 | } else { | 694 | } else { |
| @@ -575,22 +700,16 @@ int traceprobe_parse_probe_arg(struct trace_probe *tp, int i, char *arg, | |||
| 575 | return -ENOMEM; | 700 | return -ENOMEM; |
| 576 | 701 | ||
| 577 | if (!is_good_name(parg->name)) { | 702 | if (!is_good_name(parg->name)) { |
| 578 | pr_info("Invalid argument[%d] name: %s\n", | 703 | trace_probe_log_err(0, BAD_ARG_NAME); |
| 579 | i, parg->name); | ||
| 580 | return -EINVAL; | 704 | return -EINVAL; |
| 581 | } | 705 | } |
| 582 | |||
| 583 | if (traceprobe_conflict_field_name(parg->name, tp->args, i)) { | 706 | if (traceprobe_conflict_field_name(parg->name, tp->args, i)) { |
| 584 | pr_info("Argument[%d]: '%s' conflicts with another field.\n", | 707 | trace_probe_log_err(0, USED_ARG_NAME); |
| 585 | i, parg->name); | ||
| 586 | return -EINVAL; | 708 | return -EINVAL; |
| 587 | } | 709 | } |
| 588 | |||
| 589 | /* Parse fetch argument */ | 710 | /* Parse fetch argument */ |
| 590 | ret = traceprobe_parse_probe_arg_body(body, &tp->size, parg, flags); | 711 | return traceprobe_parse_probe_arg_body(body, &tp->size, parg, flags, |
| 591 | if (ret) | 712 | body - arg); |
| 592 | pr_info("Parse error at argument[%d]. (%d)\n", i, ret); | ||
| 593 | return ret; | ||
| 594 | } | 713 | } |
| 595 | 714 | ||
| 596 | void traceprobe_free_probe_arg(struct probe_arg *arg) | 715 | void traceprobe_free_probe_arg(struct probe_arg *arg) |
