1 // SPDX-License-Identifier: GPL-2.0
3 * KUnit function redirection (static stubbing) API.
5 * Copyright (C) 2022, Google LLC.
6 * Author: David Gow <davidgow@google.com>
9 #include <kunit/test.h>
10 #include <kunit/static_stub.h>
11 #include "hooks-impl.h"
14 /* Context for a static stub. This is stored in the resource data. */
15 struct kunit_static_stub_ctx
{
17 void *replacement_addr
;
20 static void __kunit_static_stub_resource_free(struct kunit_resource
*res
)
25 /* Matching function for kunit_find_resource(). match_data is real_fn_addr. */
26 static bool __kunit_static_stub_resource_match(struct kunit
*test
,
27 struct kunit_resource
*res
,
28 void *match_real_fn_addr
)
30 /* This pointer is only valid if res is a static stub resource. */
31 struct kunit_static_stub_ctx
*ctx
= res
->data
;
33 /* Make sure the resource is a static stub resource. */
34 if (res
->free
!= &__kunit_static_stub_resource_free
)
37 return ctx
->real_fn_addr
== match_real_fn_addr
;
40 /* Hook to return the address of the replacement function. */
41 void *__kunit_get_static_stub_address_impl(struct kunit
*test
, void *real_fn_addr
)
43 struct kunit_resource
*res
;
44 struct kunit_static_stub_ctx
*ctx
;
45 void *replacement_addr
;
47 res
= kunit_find_resource(test
,
48 __kunit_static_stub_resource_match
,
55 replacement_addr
= ctx
->replacement_addr
;
56 kunit_put_resource(res
);
57 return replacement_addr
;
60 void kunit_deactivate_static_stub(struct kunit
*test
, void *real_fn_addr
)
62 struct kunit_resource
*res
;
64 KUNIT_ASSERT_PTR_NE_MSG(test
, real_fn_addr
, NULL
,
65 "Tried to deactivate a NULL stub.");
67 /* Look up the existing stub for this function. */
68 res
= kunit_find_resource(test
,
69 __kunit_static_stub_resource_match
,
72 /* Error out if the stub doesn't exist. */
73 KUNIT_ASSERT_PTR_NE_MSG(test
, res
, NULL
,
74 "Tried to deactivate a nonexistent stub.");
76 /* Free the stub. We 'put' twice, as we got a reference
77 * from kunit_find_resource()
79 kunit_remove_resource(test
, res
);
80 kunit_put_resource(res
);
82 EXPORT_SYMBOL_GPL(kunit_deactivate_static_stub
);
84 /* Helper function for kunit_activate_static_stub(). The macro does
85 * typechecking, so use it instead.
87 void __kunit_activate_static_stub(struct kunit
*test
,
89 void *replacement_addr
)
91 struct kunit_static_stub_ctx
*ctx
;
92 struct kunit_resource
*res
;
94 KUNIT_ASSERT_PTR_NE_MSG(test
, real_fn_addr
, NULL
,
95 "Tried to activate a stub for function NULL");
97 /* If the replacement address is NULL, deactivate the stub. */
98 if (!replacement_addr
) {
99 kunit_deactivate_static_stub(test
, replacement_addr
);
103 /* Look up any existing stubs for this function, and replace them. */
104 res
= kunit_find_resource(test
,
105 __kunit_static_stub_resource_match
,
109 ctx
->replacement_addr
= replacement_addr
;
111 /* We got an extra reference from find_resource(), so put it. */
112 kunit_put_resource(res
);
114 ctx
= kmalloc(sizeof(*ctx
), GFP_KERNEL
);
115 KUNIT_ASSERT_NOT_ERR_OR_NULL(test
, ctx
);
116 ctx
->real_fn_addr
= real_fn_addr
;
117 ctx
->replacement_addr
= replacement_addr
;
118 res
= kunit_alloc_resource(test
, NULL
,
119 &__kunit_static_stub_resource_free
,
123 EXPORT_SYMBOL_GPL(__kunit_activate_static_stub
);