diff options
| -rw-r--r-- | kernel/trace/trace.h | 2 | ||||
| -rw-r--r-- | kernel/trace/trace_selftest.c | 114 |
2 files changed, 115 insertions, 1 deletions
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 55e1f7f0db12..593debefc4e9 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h | |||
| @@ -472,11 +472,11 @@ extern void trace_find_cmdline(int pid, char comm[]); | |||
| 472 | 472 | ||
| 473 | #ifdef CONFIG_DYNAMIC_FTRACE | 473 | #ifdef CONFIG_DYNAMIC_FTRACE |
| 474 | extern unsigned long ftrace_update_tot_cnt; | 474 | extern unsigned long ftrace_update_tot_cnt; |
| 475 | #endif | ||
| 475 | #define DYN_FTRACE_TEST_NAME trace_selftest_dynamic_test_func | 476 | #define DYN_FTRACE_TEST_NAME trace_selftest_dynamic_test_func |
| 476 | extern int DYN_FTRACE_TEST_NAME(void); | 477 | extern int DYN_FTRACE_TEST_NAME(void); |
| 477 | #define DYN_FTRACE_TEST_NAME2 trace_selftest_dynamic_test_func2 | 478 | #define DYN_FTRACE_TEST_NAME2 trace_selftest_dynamic_test_func2 |
| 478 | extern int DYN_FTRACE_TEST_NAME2(void); | 479 | extern int DYN_FTRACE_TEST_NAME2(void); |
| 479 | #endif | ||
| 480 | 480 | ||
| 481 | extern int ring_buffer_expanded; | 481 | extern int ring_buffer_expanded; |
| 482 | extern bool tracing_selftest_disabled; | 482 | extern bool tracing_selftest_disabled; |
diff --git a/kernel/trace/trace_selftest.c b/kernel/trace/trace_selftest.c index 86422f91dbe1..1003a4d5eb25 100644 --- a/kernel/trace/trace_selftest.c +++ b/kernel/trace/trace_selftest.c | |||
| @@ -543,6 +543,116 @@ out: | |||
| 543 | # define trace_selftest_function_recursion() ({ 0; }) | 543 | # define trace_selftest_function_recursion() ({ 0; }) |
| 544 | #endif /* CONFIG_DYNAMIC_FTRACE */ | 544 | #endif /* CONFIG_DYNAMIC_FTRACE */ |
| 545 | 545 | ||
| 546 | static enum { | ||
| 547 | TRACE_SELFTEST_REGS_START, | ||
| 548 | TRACE_SELFTEST_REGS_FOUND, | ||
| 549 | TRACE_SELFTEST_REGS_NOT_FOUND, | ||
| 550 | } trace_selftest_regs_stat; | ||
| 551 | |||
| 552 | static void trace_selftest_test_regs_func(unsigned long ip, | ||
| 553 | unsigned long pip, | ||
| 554 | struct ftrace_ops *op, | ||
| 555 | struct pt_regs *pt_regs) | ||
| 556 | { | ||
| 557 | if (pt_regs) | ||
| 558 | trace_selftest_regs_stat = TRACE_SELFTEST_REGS_FOUND; | ||
| 559 | else | ||
| 560 | trace_selftest_regs_stat = TRACE_SELFTEST_REGS_NOT_FOUND; | ||
| 561 | } | ||
| 562 | |||
| 563 | static struct ftrace_ops test_regs_probe = { | ||
| 564 | .func = trace_selftest_test_regs_func, | ||
| 565 | .flags = FTRACE_OPS_FL_RECURSION_SAFE | FTRACE_OPS_FL_SAVE_REGS, | ||
| 566 | }; | ||
| 567 | |||
| 568 | static int | ||
| 569 | trace_selftest_function_regs(void) | ||
| 570 | { | ||
| 571 | int save_ftrace_enabled = ftrace_enabled; | ||
| 572 | int save_tracer_enabled = tracer_enabled; | ||
| 573 | char *func_name; | ||
| 574 | int len; | ||
| 575 | int ret; | ||
| 576 | int supported = 0; | ||
| 577 | |||
| 578 | #ifdef ARCH_SUPPORTS_FTRACE_SAVE_REGS | ||
| 579 | supported = 1; | ||
| 580 | #endif | ||
| 581 | |||
| 582 | /* The previous test PASSED */ | ||
| 583 | pr_cont("PASSED\n"); | ||
| 584 | pr_info("Testing ftrace regs%s: ", | ||
| 585 | !supported ? "(no arch support)" : ""); | ||
| 586 | |||
| 587 | /* enable tracing, and record the filter function */ | ||
| 588 | ftrace_enabled = 1; | ||
| 589 | tracer_enabled = 1; | ||
| 590 | |||
| 591 | /* Handle PPC64 '.' name */ | ||
| 592 | func_name = "*" __stringify(DYN_FTRACE_TEST_NAME); | ||
| 593 | len = strlen(func_name); | ||
| 594 | |||
| 595 | ret = ftrace_set_filter(&test_regs_probe, func_name, len, 1); | ||
| 596 | /* | ||
| 597 | * If DYNAMIC_FTRACE is not set, then we just trace all functions. | ||
| 598 | * This test really doesn't care. | ||
| 599 | */ | ||
| 600 | if (ret && ret != -ENODEV) { | ||
| 601 | pr_cont("*Could not set filter* "); | ||
| 602 | goto out; | ||
| 603 | } | ||
| 604 | |||
| 605 | ret = register_ftrace_function(&test_regs_probe); | ||
| 606 | /* | ||
| 607 | * Now if the arch does not support passing regs, then this should | ||
| 608 | * have failed. | ||
| 609 | */ | ||
| 610 | if (!supported) { | ||
| 611 | if (!ret) { | ||
| 612 | pr_cont("*registered save-regs without arch support* "); | ||
| 613 | goto out; | ||
| 614 | } | ||
| 615 | test_regs_probe.flags |= FTRACE_OPS_FL_SAVE_REGS_IF_SUPPORTED; | ||
| 616 | ret = register_ftrace_function(&test_regs_probe); | ||
| 617 | } | ||
| 618 | if (ret) { | ||
| 619 | pr_cont("*could not register callback* "); | ||
| 620 | goto out; | ||
| 621 | } | ||
| 622 | |||
| 623 | |||
| 624 | DYN_FTRACE_TEST_NAME(); | ||
| 625 | |||
| 626 | unregister_ftrace_function(&test_regs_probe); | ||
| 627 | |||
| 628 | ret = -1; | ||
| 629 | |||
| 630 | switch (trace_selftest_regs_stat) { | ||
| 631 | case TRACE_SELFTEST_REGS_START: | ||
| 632 | pr_cont("*callback never called* "); | ||
| 633 | goto out; | ||
| 634 | |||
| 635 | case TRACE_SELFTEST_REGS_FOUND: | ||
| 636 | if (supported) | ||
| 637 | break; | ||
| 638 | pr_cont("*callback received regs without arch support* "); | ||
| 639 | goto out; | ||
| 640 | |||
| 641 | case TRACE_SELFTEST_REGS_NOT_FOUND: | ||
| 642 | if (!supported) | ||
| 643 | break; | ||
| 644 | pr_cont("*callback received NULL regs* "); | ||
| 645 | goto out; | ||
| 646 | } | ||
| 647 | |||
| 648 | ret = 0; | ||
| 649 | out: | ||
| 650 | ftrace_enabled = save_ftrace_enabled; | ||
| 651 | tracer_enabled = save_tracer_enabled; | ||
| 652 | |||
| 653 | return ret; | ||
| 654 | } | ||
| 655 | |||
| 546 | /* | 656 | /* |
| 547 | * Simple verification test of ftrace function tracer. | 657 | * Simple verification test of ftrace function tracer. |
| 548 | * Enable ftrace, sleep 1/10 second, and then read the trace | 658 | * Enable ftrace, sleep 1/10 second, and then read the trace |
| @@ -592,6 +702,10 @@ trace_selftest_startup_function(struct tracer *trace, struct trace_array *tr) | |||
| 592 | goto out; | 702 | goto out; |
| 593 | 703 | ||
| 594 | ret = trace_selftest_function_recursion(); | 704 | ret = trace_selftest_function_recursion(); |
| 705 | if (ret) | ||
| 706 | goto out; | ||
| 707 | |||
| 708 | ret = trace_selftest_function_regs(); | ||
| 595 | out: | 709 | out: |
| 596 | ftrace_enabled = save_ftrace_enabled; | 710 | ftrace_enabled = save_ftrace_enabled; |
| 597 | tracer_enabled = save_tracer_enabled; | 711 | tracer_enabled = save_tracer_enabled; |
