diff options
Diffstat (limited to 'kernel/trace')
-rw-r--r-- | kernel/trace/ftrace.c | 81 |
1 files changed, 44 insertions, 37 deletions
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 3160254f6c7e..d5bd21f39524 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
@@ -348,6 +348,47 @@ ftrace_record_ip(unsigned long ip) | |||
348 | return rec; | 348 | return rec; |
349 | } | 349 | } |
350 | 350 | ||
351 | static void print_ip_ins(const char *fmt, unsigned char *p) | ||
352 | { | ||
353 | int i; | ||
354 | |||
355 | printk(KERN_CONT "%s", fmt); | ||
356 | |||
357 | for (i = 0; i < MCOUNT_INSN_SIZE; i++) | ||
358 | printk(KERN_CONT "%s%02x", i ? ":" : "", p[i]); | ||
359 | } | ||
360 | |||
361 | static void ftrace_bug(int failed, unsigned long ip, | ||
362 | unsigned char *expected, | ||
363 | unsigned char *replace) | ||
364 | { | ||
365 | switch (failed) { | ||
366 | case -EFAULT: | ||
367 | FTRACE_WARN_ON_ONCE(1); | ||
368 | pr_info("ftrace faulted on modifying "); | ||
369 | print_ip_sym(ip); | ||
370 | break; | ||
371 | case -EINVAL: | ||
372 | FTRACE_WARN_ON_ONCE(1); | ||
373 | pr_info("ftrace failed to modify "); | ||
374 | print_ip_sym(ip); | ||
375 | print_ip_ins(" expected: ", expected); | ||
376 | print_ip_ins(" actual: ", (unsigned char *)ip); | ||
377 | print_ip_ins(" replace: ", replace); | ||
378 | printk(KERN_CONT "\n"); | ||
379 | break; | ||
380 | case -EPERM: | ||
381 | FTRACE_WARN_ON_ONCE(1); | ||
382 | pr_info("ftrace faulted on writing "); | ||
383 | print_ip_sym(ip); | ||
384 | break; | ||
385 | default: | ||
386 | FTRACE_WARN_ON_ONCE(1); | ||
387 | pr_info("ftrace faulted on unknown error "); | ||
388 | print_ip_sym(ip); | ||
389 | } | ||
390 | } | ||
391 | |||
351 | #define FTRACE_ADDR ((long)(ftrace_caller)) | 392 | #define FTRACE_ADDR ((long)(ftrace_caller)) |
352 | 393 | ||
353 | static int | 394 | static int |
@@ -465,22 +506,13 @@ static void ftrace_replace_code(int enable) | |||
465 | if ((system_state == SYSTEM_BOOTING) || | 506 | if ((system_state == SYSTEM_BOOTING) || |
466 | !core_kernel_text(rec->ip)) { | 507 | !core_kernel_text(rec->ip)) { |
467 | ftrace_free_rec(rec); | 508 | ftrace_free_rec(rec); |
468 | } | 509 | } else |
510 | ftrace_bug(failed, rec->ip, old, new); | ||
469 | } | 511 | } |
470 | } | 512 | } |
471 | } | 513 | } |
472 | } | 514 | } |
473 | 515 | ||
474 | static void print_ip_ins(const char *fmt, unsigned char *p) | ||
475 | { | ||
476 | int i; | ||
477 | |||
478 | printk(KERN_CONT "%s", fmt); | ||
479 | |||
480 | for (i = 0; i < MCOUNT_INSN_SIZE; i++) | ||
481 | printk(KERN_CONT "%s%02x", i ? ":" : "", p[i]); | ||
482 | } | ||
483 | |||
484 | static int | 516 | static int |
485 | ftrace_code_disable(struct dyn_ftrace *rec) | 517 | ftrace_code_disable(struct dyn_ftrace *rec) |
486 | { | 518 | { |
@@ -495,32 +527,7 @@ ftrace_code_disable(struct dyn_ftrace *rec) | |||
495 | 527 | ||
496 | ret = ftrace_modify_code(ip, call, nop); | 528 | ret = ftrace_modify_code(ip, call, nop); |
497 | if (ret) { | 529 | if (ret) { |
498 | switch (ret) { | 530 | ftrace_bug(ret, ip, call, nop); |
499 | case -EFAULT: | ||
500 | FTRACE_WARN_ON_ONCE(1); | ||
501 | pr_info("ftrace faulted on modifying "); | ||
502 | print_ip_sym(ip); | ||
503 | break; | ||
504 | case -EINVAL: | ||
505 | FTRACE_WARN_ON_ONCE(1); | ||
506 | pr_info("ftrace failed to modify "); | ||
507 | print_ip_sym(ip); | ||
508 | print_ip_ins(" expected: ", call); | ||
509 | print_ip_ins(" actual: ", (unsigned char *)ip); | ||
510 | print_ip_ins(" replace: ", nop); | ||
511 | printk(KERN_CONT "\n"); | ||
512 | break; | ||
513 | case -EPERM: | ||
514 | FTRACE_WARN_ON_ONCE(1); | ||
515 | pr_info("ftrace faulted on writing "); | ||
516 | print_ip_sym(ip); | ||
517 | break; | ||
518 | default: | ||
519 | FTRACE_WARN_ON_ONCE(1); | ||
520 | pr_info("ftrace faulted on unknown error "); | ||
521 | print_ip_sym(ip); | ||
522 | } | ||
523 | |||
524 | rec->flags |= FTRACE_FL_FAILED; | 531 | rec->flags |= FTRACE_FL_FAILED; |
525 | return 0; | 532 | return 0; |
526 | } | 533 | } |