static void trace_selftest_test_recursion_func(unsigned long ip, unsigned long pip, struct ftrace_ops *op, struct pt_regs *pt_regs) { /* * This function is registered without the recursion safe flag. * The ftrace infrastructure should provide the recursion * protection. If not, this will crash the kernel! */ trace_selftest_recursion_cnt++; DYN_FTRACE_TEST_NAME(); }
static void trace_selftest_test_recursion_safe_func(unsigned long ip, unsigned long pip, struct ftrace_ops *op, struct pt_regs *pt_regs) { /* * We said we would provide our own recursion. By calling * this function again, we should recurse back into this function * and count again. But this only happens if the arch supports * all of ftrace features and nothing else is using the function * tracing utility. */ if (trace_selftest_recursion_cnt++) return; DYN_FTRACE_TEST_NAME(); }
static int trace_selftest_function_regs(void) { int save_ftrace_enabled = ftrace_enabled; char *func_name; int len; int ret; int supported = 0; #ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS supported = 1; #endif /* The previous test PASSED */ pr_cont("PASSED\n"); pr_info("Testing ftrace regs%s: ", !supported ? "(no arch support)" : ""); /* enable tracing, and record the filter function */ ftrace_enabled = 1; /* Handle PPC64 '.' name */ func_name = "*" __stringify(DYN_FTRACE_TEST_NAME); len = strlen(func_name); ret = ftrace_set_filter(&test_regs_probe, func_name, len, 1); /* * If DYNAMIC_FTRACE is not set, then we just trace all functions. * This test really doesn't care. */ if (ret && ret != -ENODEV) { pr_cont("*Could not set filter* "); goto out; } ret = register_ftrace_function(&test_regs_probe); /* * Now if the arch does not support passing regs, then this should * have failed. */ if (!supported) { if (!ret) { pr_cont("*registered save-regs without arch support* "); goto out; } test_regs_probe.flags |= FTRACE_OPS_FL_SAVE_REGS_IF_SUPPORTED; ret = register_ftrace_function(&test_regs_probe); } if (ret) { pr_cont("*could not register callback* "); goto out; } DYN_FTRACE_TEST_NAME(); unregister_ftrace_function(&test_regs_probe); ret = -1; switch (trace_selftest_regs_stat) { case TRACE_SELFTEST_REGS_START: pr_cont("*callback never called* "); goto out; case TRACE_SELFTEST_REGS_FOUND: if (supported) break; pr_cont("*callback received regs without arch support* "); goto out; case TRACE_SELFTEST_REGS_NOT_FOUND: if (!supported) break; pr_cont("*callback received NULL regs* "); goto out; } ret = 0; out: ftrace_enabled = save_ftrace_enabled; return ret; }
static int trace_selftest_function_recursion(void) { int save_ftrace_enabled = ftrace_enabled; char *func_name; int len; int ret; /* The previous test PASSED */ pr_cont("PASSED\n"); pr_info("Testing ftrace recursion: "); /* enable tracing, and record the filter function */ ftrace_enabled = 1; /* Handle PPC64 '.' name */ func_name = "*" __stringify(DYN_FTRACE_TEST_NAME); len = strlen(func_name); ret = ftrace_set_filter(&test_rec_probe, func_name, len, 1); if (ret) { pr_cont("*Could not set filter* "); goto out; } ret = register_ftrace_function(&test_rec_probe); if (ret) { pr_cont("*could not register callback* "); goto out; } DYN_FTRACE_TEST_NAME(); unregister_ftrace_function(&test_rec_probe); ret = -1; if (trace_selftest_recursion_cnt != 1) { pr_cont("*callback not called once (%d)* ", trace_selftest_recursion_cnt); goto out; } trace_selftest_recursion_cnt = 1; pr_cont("PASSED\n"); pr_info("Testing ftrace recursion safe: "); ret = ftrace_set_filter(&test_recsafe_probe, func_name, len, 1); if (ret) { pr_cont("*Could not set filter* "); goto out; } ret = register_ftrace_function(&test_recsafe_probe); if (ret) { pr_cont("*could not register callback* "); goto out; } DYN_FTRACE_TEST_NAME(); unregister_ftrace_function(&test_recsafe_probe); ret = -1; if (trace_selftest_recursion_cnt != 2) { pr_cont("*callback not called expected 2 times (%d)* ", trace_selftest_recursion_cnt); goto out; } ret = 0; out: ftrace_enabled = save_ftrace_enabled; return ret; }
static int trace_selftest_ops(struct trace_array *tr, int cnt) { int save_ftrace_enabled = ftrace_enabled; struct ftrace_ops *dyn_ops; char *func1_name; char *func2_name; int len1; int len2; int ret = -1; printk(KERN_CONT "PASSED\n"); pr_info("Testing dynamic ftrace ops #%d: ", cnt); ftrace_enabled = 1; reset_counts(); /* Handle PPC64 '.' name */ func1_name = "*" __stringify(DYN_FTRACE_TEST_NAME); func2_name = "*" __stringify(DYN_FTRACE_TEST_NAME2); len1 = strlen(func1_name); len2 = strlen(func2_name); /* * Probe 1 will trace function 1. * Probe 2 will trace function 2. * Probe 3 will trace functions 1 and 2. */ ftrace_set_filter(&test_probe1, func1_name, len1, 1); ftrace_set_filter(&test_probe2, func2_name, len2, 1); ftrace_set_filter(&test_probe3, func1_name, len1, 1); ftrace_set_filter(&test_probe3, func2_name, len2, 0); register_ftrace_function(&test_probe1); register_ftrace_function(&test_probe2); register_ftrace_function(&test_probe3); /* First time we are running with main function */ if (cnt > 1) { ftrace_init_array_ops(tr, trace_selftest_test_global_func); register_ftrace_function(tr->ops); } DYN_FTRACE_TEST_NAME(); print_counts(); if (trace_selftest_test_probe1_cnt != 1) goto out; if (trace_selftest_test_probe2_cnt != 0) goto out; if (trace_selftest_test_probe3_cnt != 1) goto out; if (cnt > 1) { if (trace_selftest_test_global_cnt == 0) goto out; } DYN_FTRACE_TEST_NAME2(); print_counts(); if (trace_selftest_test_probe1_cnt != 1) goto out; if (trace_selftest_test_probe2_cnt != 1) goto out; if (trace_selftest_test_probe3_cnt != 2) goto out; /* Add a dynamic probe */ dyn_ops = kzalloc(sizeof(*dyn_ops), GFP_KERNEL); if (!dyn_ops) { printk("MEMORY ERROR "); goto out; } dyn_ops->func = trace_selftest_test_dyn_func; register_ftrace_function(dyn_ops); trace_selftest_test_global_cnt = 0; DYN_FTRACE_TEST_NAME(); print_counts(); if (trace_selftest_test_probe1_cnt != 2) goto out_free; if (trace_selftest_test_probe2_cnt != 1) goto out_free; if (trace_selftest_test_probe3_cnt != 3) goto out_free; if (cnt > 1) { if (trace_selftest_test_global_cnt == 0) goto out_free; } if (trace_selftest_test_dyn_cnt == 0) goto out_free; DYN_FTRACE_TEST_NAME2(); print_counts(); if (trace_selftest_test_probe1_cnt != 2) goto out_free; if (trace_selftest_test_probe2_cnt != 2) goto out_free; if (trace_selftest_test_probe3_cnt != 4) goto out_free; ret = 0; out_free: unregister_ftrace_function(dyn_ops); kfree(dyn_ops); out: /* Purposely unregister in the same order */ unregister_ftrace_function(&test_probe1); unregister_ftrace_function(&test_probe2); unregister_ftrace_function(&test_probe3); if (cnt > 1) unregister_ftrace_function(tr->ops); ftrace_reset_array_ops(tr); /* Make sure everything is off */ reset_counts(); DYN_FTRACE_TEST_NAME(); DYN_FTRACE_TEST_NAME(); if (trace_selftest_test_probe1_cnt || trace_selftest_test_probe2_cnt || trace_selftest_test_probe3_cnt || trace_selftest_test_global_cnt || trace_selftest_test_dyn_cnt) ret = -1; ftrace_enabled = save_ftrace_enabled; return ret; }
static int trace_selftest_function_recursion(void) { int save_ftrace_enabled = ftrace_enabled; char *func_name; int len; int ret; int cnt; /* The previous test PASSED */ pr_cont("PASSED\n"); pr_info("Testing ftrace recursion: "); /* enable tracing, and record the filter function */ ftrace_enabled = 1; /* Handle PPC64 '.' name */ func_name = "*" __stringify(DYN_FTRACE_TEST_NAME); len = strlen(func_name); ret = ftrace_set_filter(&test_rec_probe, func_name, len, 1); if (ret) { pr_cont("*Could not set filter* "); goto out; } ret = register_ftrace_function(&test_rec_probe); if (ret) { pr_cont("*could not register callback* "); goto out; } DYN_FTRACE_TEST_NAME(); unregister_ftrace_function(&test_rec_probe); ret = -1; if (trace_selftest_recursion_cnt != 1) { pr_cont("*callback not called once (%d)* ", trace_selftest_recursion_cnt); goto out; } trace_selftest_recursion_cnt = 1; pr_cont("PASSED\n"); pr_info("Testing ftrace recursion safe: "); ret = ftrace_set_filter(&test_recsafe_probe, func_name, len, 1); if (ret) { pr_cont("*Could not set filter* "); goto out; } ret = register_ftrace_function(&test_recsafe_probe); if (ret) { pr_cont("*could not register callback* "); goto out; } DYN_FTRACE_TEST_NAME(); unregister_ftrace_function(&test_recsafe_probe); /* * If arch supports all ftrace features, and no other task * was on the list, we should be fine. */ if (!ftrace_nr_registered_ops() && !FTRACE_FORCE_LIST_FUNC) cnt = 2; /* Should have recursed */ else cnt = 1; ret = -1; if (trace_selftest_recursion_cnt != cnt) { pr_cont("*callback not called expected %d times (%d)* ", cnt, trace_selftest_recursion_cnt); goto out; } ret = 0; out: ftrace_enabled = save_ftrace_enabled; return ret; }
static int trace_selftest_ops(int cnt) { int save_ftrace_enabled = ftrace_enabled; struct ftrace_ops *dyn_ops; char *func1_name; char *func2_name; int len1; int len2; int ret = -1; printk(KERN_CONT "PASSED\n"); pr_info("Testing dynamic ftrace ops #%d: ", cnt); ftrace_enabled = 1; reset_counts(); /* */ func1_name = "*" __stringify(DYN_FTRACE_TEST_NAME); func2_name = "*" __stringify(DYN_FTRACE_TEST_NAME2); len1 = strlen(func1_name); len2 = strlen(func2_name); /* */ ftrace_set_filter(&test_probe1, func1_name, len1, 1); ftrace_set_filter(&test_probe2, func2_name, len2, 1); ftrace_set_filter(&test_probe3, func1_name, len1, 1); ftrace_set_filter(&test_probe3, func2_name, len2, 0); register_ftrace_function(&test_probe1); register_ftrace_function(&test_probe2); register_ftrace_function(&test_probe3); register_ftrace_function(&test_global); DYN_FTRACE_TEST_NAME(); print_counts(); if (trace_selftest_test_probe1_cnt != 1) goto out; if (trace_selftest_test_probe2_cnt != 0) goto out; if (trace_selftest_test_probe3_cnt != 1) goto out; if (trace_selftest_test_global_cnt == 0) goto out; DYN_FTRACE_TEST_NAME2(); print_counts(); if (trace_selftest_test_probe1_cnt != 1) goto out; if (trace_selftest_test_probe2_cnt != 1) goto out; if (trace_selftest_test_probe3_cnt != 2) goto out; /* */ dyn_ops = kzalloc(sizeof(*dyn_ops), GFP_KERNEL); if (!dyn_ops) { printk("MEMORY ERROR "); goto out; } dyn_ops->func = trace_selftest_test_dyn_func; register_ftrace_function(dyn_ops); trace_selftest_test_global_cnt = 0; DYN_FTRACE_TEST_NAME(); print_counts(); if (trace_selftest_test_probe1_cnt != 2) goto out_free; if (trace_selftest_test_probe2_cnt != 1) goto out_free; if (trace_selftest_test_probe3_cnt != 3) goto out_free; if (trace_selftest_test_global_cnt == 0) goto out; if (trace_selftest_test_dyn_cnt == 0) goto out_free; DYN_FTRACE_TEST_NAME2(); print_counts(); if (trace_selftest_test_probe1_cnt != 2) goto out_free; if (trace_selftest_test_probe2_cnt != 2) goto out_free; if (trace_selftest_test_probe3_cnt != 4) goto out_free; ret = 0; out_free: unregister_ftrace_function(dyn_ops); kfree(dyn_ops); out: /* */ unregister_ftrace_function(&test_probe1); unregister_ftrace_function(&test_probe2); unregister_ftrace_function(&test_probe3); unregister_ftrace_function(&test_global); /* */ reset_counts(); DYN_FTRACE_TEST_NAME(); DYN_FTRACE_TEST_NAME(); if (trace_selftest_test_probe1_cnt || trace_selftest_test_probe2_cnt || trace_selftest_test_probe3_cnt || trace_selftest_test_global_cnt || trace_selftest_test_dyn_cnt) ret = -1; ftrace_enabled = save_ftrace_enabled; return ret; }