1 /* SPDX-License-Identifier: GPL-2.0 */ 2 /* 3 * KUnit function redirection (static stubbing) API. 4 * 5 * Copyright (C) 2022, Google LLC. 6 * Author: David Gow <davidgow@google.com> 7 */ 8 #ifndef _KUNIT_STATIC_STUB_H 9 #define _KUNIT_STATIC_STUB_H 10 11 #if !IS_ENABLED(CONFIG_KUNIT) 12 13 /* If CONFIG_KUNIT is not enabled, these stubs quietly disappear. */ 14 #define KUNIT_TRIGGER_STATIC_STUB(real_fn_name, args...) do {} while (0) 15 16 #else 17 18 #include <kunit/test.h> 19 #include <kunit/test-bug.h> 20 21 #include <linux/compiler.h> /* for {un,}likely() */ 22 #include <linux/sched.h> /* for task_struct */ 23 24 25 /** 26 * KUNIT_STATIC_STUB_REDIRECT() - call a replacement 'static stub' if one exists 27 * @real_fn_name: The name of this function (as an identifier, not a string) 28 * @args: All of the arguments passed to this function 29 * 30 * This is a function prologue which is used to allow calls to the current 31 * function to be redirected by a KUnit test. KUnit tests can call 32 * kunit_activate_static_stub() to pass a replacement function in. The 33 * replacement function will be called by KUNIT_TRIGGER_STATIC_STUB(), which 34 * will then return from the function. If the caller is not in a KUnit context, 35 * the function will continue execution as normal. 36 * 37 * Example: 38 * 39 * .. code-block:: c 40 * 41 * int real_func(int n) 42 * { 43 * KUNIT_STATIC_STUB_REDIRECT(real_func, n); 44 * return 0; 45 * } 46 * 47 * int replacement_func(int n) 48 * { 49 * return 42; 50 * } 51 * 52 * void example_test(struct kunit *test) 53 * { 54 * kunit_activate_static_stub(test, real_func, replacement_func); 55 * KUNIT_EXPECT_EQ(test, real_func(1), 42); 56 * } 57 * 58 */ 59 #define KUNIT_STATIC_STUB_REDIRECT(real_fn_name, args...) \ 60 do { \ 61 typeof(&real_fn_name) replacement; \ 62 struct kunit *current_test = kunit_get_current_test(); \ 63 \ 64 if (likely(!current_test)) \ 65 break; \ 66 \ 67 replacement = kunit_hooks.get_static_stub_address(current_test, \ 68 &real_fn_name); \ 69 \ 70 if (unlikely(replacement)) \ 71 return replacement(args); \ 72 } while (0) 73 74 /* Helper function for kunit_activate_static_stub(). The macro does 75 * typechecking, so use it instead. 76 */ 77 void __kunit_activate_static_stub(struct kunit *test, 78 void *real_fn_addr, 79 void *replacement_addr); 80 81 /** 82 * kunit_activate_static_stub() - replace a function using static stubs. 83 * @test: A pointer to the 'struct kunit' test context for the current test. 84 * @real_fn_addr: The address of the function to replace. 85 * @replacement_addr: The address of the function to replace it with. 86 * 87 * When activated, calls to real_fn_addr from within this test (even if called 88 * indirectly) will instead call replacement_addr. The function pointed to by 89 * real_fn_addr must begin with the static stub prologue in 90 * KUNIT_TRIGGER_STATIC_STUB() for this to work. real_fn_addr and 91 * replacement_addr must have the same type. 92 * 93 * The redirection can be disabled again with kunit_deactivate_static_stub(). 94 */ 95 #define kunit_activate_static_stub(test, real_fn_addr, replacement_addr) do { \ 96 typecheck_fn(typeof(&real_fn_addr), replacement_addr); \ 97 __kunit_activate_static_stub(test, real_fn_addr, replacement_addr); \ 98 } while (0) 99 100 101 /** 102 * kunit_deactivate_static_stub() - disable a function redirection 103 * @test: A pointer to the 'struct kunit' test context for the current test. 104 * @real_fn_addr: The address of the function to no-longer redirect 105 * 106 * Deactivates a redirection configured with kunit_activate_static_stub(). After 107 * this function returns, calls to real_fn_addr() will execute the original 108 * real_fn, not any previously-configured replacement. 109 */ 110 void kunit_deactivate_static_stub(struct kunit *test, void *real_fn_addr); 111 112 #endif 113 #endif 114