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_STATIC_STUB_REDIRECT(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_STATIC_STUB_REDIRECT(), 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...) \
60do { \
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 */
77void __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_STATIC_STUB_REDIRECT() 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(&replacement_addr), real_fn_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 */
110void kunit_deactivate_static_stub(struct kunit *test, void *real_fn_addr);
111
112#endif
113#endif
114

source code of linux/include/kunit/static_stub.h