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