114 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			114 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* SPDX-License-Identifier: GPL-2.0 */
 | |
| /*
 | |
|  * KUnit function redirection (static stubbing) API.
 | |
|  *
 | |
|  * Copyright (C) 2022, Google LLC.
 | |
|  * Author: David Gow <davidgow@google.com>
 | |
|  */
 | |
| #ifndef _KUNIT_STATIC_STUB_H
 | |
| #define _KUNIT_STATIC_STUB_H
 | |
| 
 | |
| #if !IS_ENABLED(CONFIG_KUNIT)
 | |
| 
 | |
| /* If CONFIG_KUNIT is not enabled, these stubs quietly disappear. */
 | |
| #define KUNIT_STATIC_STUB_REDIRECT(real_fn_name, args...) do {} while (0)
 | |
| 
 | |
| #else
 | |
| 
 | |
| #include <kunit/test.h>
 | |
| #include <kunit/test-bug.h>
 | |
| 
 | |
| #include <linux/compiler.h> /* for {un,}likely() */
 | |
| #include <linux/sched.h> /* for task_struct */
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * KUNIT_STATIC_STUB_REDIRECT() - call a replacement 'static stub' if one exists
 | |
|  * @real_fn_name: The name of this function (as an identifier, not a string)
 | |
|  * @args: All of the arguments passed to this function
 | |
|  *
 | |
|  * This is a function prologue which is used to allow calls to the current
 | |
|  * function to be redirected by a KUnit test. KUnit tests can call
 | |
|  * kunit_activate_static_stub() to pass a replacement function in. The
 | |
|  * replacement function will be called by KUNIT_STATIC_STUB_REDIRECT(), which
 | |
|  * will then return from the function. If the caller is not in a KUnit context,
 | |
|  * the function will continue execution as normal.
 | |
|  *
 | |
|  * Example:
 | |
|  *
 | |
|  * .. code-block:: c
 | |
|  *
 | |
|  *	int real_func(int n)
 | |
|  *	{
 | |
|  *		KUNIT_STATIC_STUB_REDIRECT(real_func, n);
 | |
|  *		return 0;
 | |
|  *	}
 | |
|  *
 | |
|  *	int replacement_func(int n)
 | |
|  *	{
 | |
|  *		return 42;
 | |
|  *	}
 | |
|  *
 | |
|  *	void example_test(struct kunit *test)
 | |
|  *	{
 | |
|  *		kunit_activate_static_stub(test, real_func, replacement_func);
 | |
|  *		KUNIT_EXPECT_EQ(test, real_func(1), 42);
 | |
|  *	}
 | |
|  *
 | |
|  */
 | |
| #define KUNIT_STATIC_STUB_REDIRECT(real_fn_name, args...)		\
 | |
| do {									\
 | |
| 	typeof(&real_fn_name) replacement;				\
 | |
| 	struct kunit *current_test = kunit_get_current_test();		\
 | |
| 									\
 | |
| 	if (likely(!current_test))					\
 | |
| 		break;							\
 | |
| 									\
 | |
| 	replacement = kunit_hooks.get_static_stub_address(current_test,	\
 | |
| 							&real_fn_name);	\
 | |
| 									\
 | |
| 	if (unlikely(replacement))					\
 | |
| 		return replacement(args);				\
 | |
| } while (0)
 | |
| 
 | |
| /* Helper function for kunit_activate_static_stub(). The macro does
 | |
|  * typechecking, so use it instead.
 | |
|  */
 | |
| void __kunit_activate_static_stub(struct kunit *test,
 | |
| 				  void *real_fn_addr,
 | |
| 				  void *replacement_addr);
 | |
| 
 | |
| /**
 | |
|  * kunit_activate_static_stub() - replace a function using static stubs.
 | |
|  * @test: A pointer to the 'struct kunit' test context for the current test.
 | |
|  * @real_fn_addr: The address of the function to replace.
 | |
|  * @replacement_addr: The address of the function to replace it with.
 | |
|  *
 | |
|  * When activated, calls to real_fn_addr from within this test (even if called
 | |
|  * indirectly) will instead call replacement_addr. The function pointed to by
 | |
|  * real_fn_addr must begin with the static stub prologue in
 | |
|  * KUNIT_STATIC_STUB_REDIRECT() for this to work. real_fn_addr and
 | |
|  * replacement_addr must have the same type.
 | |
|  *
 | |
|  * The redirection can be disabled again with kunit_deactivate_static_stub().
 | |
|  */
 | |
| #define kunit_activate_static_stub(test, real_fn_addr, replacement_addr) do {	\
 | |
| 	typecheck_fn(typeof(&replacement_addr), real_fn_addr);			\
 | |
| 	__kunit_activate_static_stub(test, real_fn_addr, replacement_addr);	\
 | |
| } while (0)
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * kunit_deactivate_static_stub() - disable a function redirection
 | |
|  * @test: A pointer to the 'struct kunit' test context for the current test.
 | |
|  * @real_fn_addr: The address of the function to no-longer redirect
 | |
|  *
 | |
|  * Deactivates a redirection configured with kunit_activate_static_stub(). After
 | |
|  * this function returns, calls to real_fn_addr() will execute the original
 | |
|  * real_fn, not any previously-configured replacement.
 | |
|  */
 | |
| void kunit_deactivate_static_stub(struct kunit *test, void *real_fn_addr);
 | |
| 
 | |
| #endif
 | |
| #endif
 |