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