162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * KUnit function redirection (static stubbing) API. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2022, Google LLC. 662306a36Sopenharmony_ci * Author: David Gow <davidgow@google.com> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci#ifndef _KUNIT_STATIC_STUB_H 962306a36Sopenharmony_ci#define _KUNIT_STATIC_STUB_H 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#if !IS_ENABLED(CONFIG_KUNIT) 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci/* If CONFIG_KUNIT is not enabled, these stubs quietly disappear. */ 1462306a36Sopenharmony_ci#define KUNIT_STATIC_STUB_REDIRECT(real_fn_name, args...) do {} while (0) 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#else 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include <kunit/test.h> 1962306a36Sopenharmony_ci#include <kunit/test-bug.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#include <linux/compiler.h> /* for {un,}likely() */ 2262306a36Sopenharmony_ci#include <linux/sched.h> /* for task_struct */ 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci/** 2662306a36Sopenharmony_ci * KUNIT_STATIC_STUB_REDIRECT() - call a replacement 'static stub' if one exists 2762306a36Sopenharmony_ci * @real_fn_name: The name of this function (as an identifier, not a string) 2862306a36Sopenharmony_ci * @args: All of the arguments passed to this function 2962306a36Sopenharmony_ci * 3062306a36Sopenharmony_ci * This is a function prologue which is used to allow calls to the current 3162306a36Sopenharmony_ci * function to be redirected by a KUnit test. KUnit tests can call 3262306a36Sopenharmony_ci * kunit_activate_static_stub() to pass a replacement function in. The 3362306a36Sopenharmony_ci * replacement function will be called by KUNIT_STATIC_STUB_REDIRECT(), which 3462306a36Sopenharmony_ci * will then return from the function. If the caller is not in a KUnit context, 3562306a36Sopenharmony_ci * the function will continue execution as normal. 3662306a36Sopenharmony_ci * 3762306a36Sopenharmony_ci * Example: 3862306a36Sopenharmony_ci * 3962306a36Sopenharmony_ci * .. code-block:: c 4062306a36Sopenharmony_ci * 4162306a36Sopenharmony_ci * int real_func(int n) 4262306a36Sopenharmony_ci * { 4362306a36Sopenharmony_ci * KUNIT_STATIC_STUB_REDIRECT(real_func, n); 4462306a36Sopenharmony_ci * return 0; 4562306a36Sopenharmony_ci * } 4662306a36Sopenharmony_ci * 4762306a36Sopenharmony_ci * int replacement_func(int n) 4862306a36Sopenharmony_ci * { 4962306a36Sopenharmony_ci * return 42; 5062306a36Sopenharmony_ci * } 5162306a36Sopenharmony_ci * 5262306a36Sopenharmony_ci * void example_test(struct kunit *test) 5362306a36Sopenharmony_ci * { 5462306a36Sopenharmony_ci * kunit_activate_static_stub(test, real_func, replacement_func); 5562306a36Sopenharmony_ci * KUNIT_EXPECT_EQ(test, real_func(1), 42); 5662306a36Sopenharmony_ci * } 5762306a36Sopenharmony_ci * 5862306a36Sopenharmony_ci */ 5962306a36Sopenharmony_ci#define KUNIT_STATIC_STUB_REDIRECT(real_fn_name, args...) \ 6062306a36Sopenharmony_cido { \ 6162306a36Sopenharmony_ci typeof(&real_fn_name) replacement; \ 6262306a36Sopenharmony_ci struct kunit *current_test = kunit_get_current_test(); \ 6362306a36Sopenharmony_ci \ 6462306a36Sopenharmony_ci if (likely(!current_test)) \ 6562306a36Sopenharmony_ci break; \ 6662306a36Sopenharmony_ci \ 6762306a36Sopenharmony_ci replacement = kunit_hooks.get_static_stub_address(current_test, \ 6862306a36Sopenharmony_ci &real_fn_name); \ 6962306a36Sopenharmony_ci \ 7062306a36Sopenharmony_ci if (unlikely(replacement)) \ 7162306a36Sopenharmony_ci return replacement(args); \ 7262306a36Sopenharmony_ci} while (0) 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci/* Helper function for kunit_activate_static_stub(). The macro does 7562306a36Sopenharmony_ci * typechecking, so use it instead. 7662306a36Sopenharmony_ci */ 7762306a36Sopenharmony_civoid __kunit_activate_static_stub(struct kunit *test, 7862306a36Sopenharmony_ci void *real_fn_addr, 7962306a36Sopenharmony_ci void *replacement_addr); 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci/** 8262306a36Sopenharmony_ci * kunit_activate_static_stub() - replace a function using static stubs. 8362306a36Sopenharmony_ci * @test: A pointer to the 'struct kunit' test context for the current test. 8462306a36Sopenharmony_ci * @real_fn_addr: The address of the function to replace. 8562306a36Sopenharmony_ci * @replacement_addr: The address of the function to replace it with. 8662306a36Sopenharmony_ci * 8762306a36Sopenharmony_ci * When activated, calls to real_fn_addr from within this test (even if called 8862306a36Sopenharmony_ci * indirectly) will instead call replacement_addr. The function pointed to by 8962306a36Sopenharmony_ci * real_fn_addr must begin with the static stub prologue in 9062306a36Sopenharmony_ci * KUNIT_STATIC_STUB_REDIRECT() for this to work. real_fn_addr and 9162306a36Sopenharmony_ci * replacement_addr must have the same type. 9262306a36Sopenharmony_ci * 9362306a36Sopenharmony_ci * The redirection can be disabled again with kunit_deactivate_static_stub(). 9462306a36Sopenharmony_ci */ 9562306a36Sopenharmony_ci#define kunit_activate_static_stub(test, real_fn_addr, replacement_addr) do { \ 9662306a36Sopenharmony_ci typecheck_fn(typeof(&real_fn_addr), replacement_addr); \ 9762306a36Sopenharmony_ci __kunit_activate_static_stub(test, real_fn_addr, replacement_addr); \ 9862306a36Sopenharmony_ci} while (0) 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci/** 10262306a36Sopenharmony_ci * kunit_deactivate_static_stub() - disable a function redirection 10362306a36Sopenharmony_ci * @test: A pointer to the 'struct kunit' test context for the current test. 10462306a36Sopenharmony_ci * @real_fn_addr: The address of the function to no-longer redirect 10562306a36Sopenharmony_ci * 10662306a36Sopenharmony_ci * Deactivates a redirection configured with kunit_activate_static_stub(). After 10762306a36Sopenharmony_ci * this function returns, calls to real_fn_addr() will execute the original 10862306a36Sopenharmony_ci * real_fn, not any previously-configured replacement. 10962306a36Sopenharmony_ci */ 11062306a36Sopenharmony_civoid kunit_deactivate_static_stub(struct kunit *test, void *real_fn_addr); 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci#endif 11362306a36Sopenharmony_ci#endif 114