| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * KUnit function redirection (static stubbing) API.
- *
- * Copyright (C) 2022, Google LLC.
- * Author: David Gow <davidgow@google.com>
- */
- #include <kunit/test.h>
- #include <kunit/static_stub.h>
- #include "hooks-impl.h"
- /* Context for a static stub. This is stored in the resource data. */
- struct kunit_static_stub_ctx {
- void *real_fn_addr;
- void *replacement_addr;
- };
- static void __kunit_static_stub_resource_free(struct kunit_resource *res)
- {
- kfree(res->data);
- }
- /* Matching function for kunit_find_resource(). match_data is real_fn_addr. */
- static bool __kunit_static_stub_resource_match(struct kunit *test,
- struct kunit_resource *res,
- void *match_real_fn_addr)
- {
- /* This pointer is only valid if res is a static stub resource. */
- struct kunit_static_stub_ctx *ctx = res->data;
- /* Make sure the resource is a static stub resource. */
- if (res->free != &__kunit_static_stub_resource_free)
- return false;
- return ctx->real_fn_addr == match_real_fn_addr;
- }
- /* Hook to return the address of the replacement function. */
- void *__kunit_get_static_stub_address_impl(struct kunit *test, void *real_fn_addr)
- {
- struct kunit_resource *res;
- struct kunit_static_stub_ctx *ctx;
- void *replacement_addr;
- res = kunit_find_resource(test,
- __kunit_static_stub_resource_match,
- real_fn_addr);
- if (!res)
- return NULL;
- ctx = res->data;
- replacement_addr = ctx->replacement_addr;
- kunit_put_resource(res);
- return replacement_addr;
- }
- void kunit_deactivate_static_stub(struct kunit *test, void *real_fn_addr)
- {
- struct kunit_resource *res;
- KUNIT_ASSERT_PTR_NE_MSG(test, real_fn_addr, NULL,
- "Tried to deactivate a NULL stub.");
- /* Look up the existing stub for this function. */
- res = kunit_find_resource(test,
- __kunit_static_stub_resource_match,
- real_fn_addr);
- /* Error out if the stub doesn't exist. */
- KUNIT_ASSERT_PTR_NE_MSG(test, res, NULL,
- "Tried to deactivate a nonexistent stub.");
- /* Free the stub. We 'put' twice, as we got a reference
- * from kunit_find_resource()
- */
- kunit_remove_resource(test, res);
- kunit_put_resource(res);
- }
- EXPORT_SYMBOL_GPL(kunit_deactivate_static_stub);
- /* 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)
- {
- struct kunit_static_stub_ctx *ctx;
- struct kunit_resource *res;
- KUNIT_ASSERT_PTR_NE_MSG(test, real_fn_addr, NULL,
- "Tried to activate a stub for function NULL");
- /* If the replacement address is NULL, deactivate the stub. */
- if (!replacement_addr) {
- kunit_deactivate_static_stub(test, real_fn_addr);
- return;
- }
- /* Look up any existing stubs for this function, and replace them. */
- res = kunit_find_resource(test,
- __kunit_static_stub_resource_match,
- real_fn_addr);
- if (res) {
- ctx = res->data;
- ctx->replacement_addr = replacement_addr;
- /* We got an extra reference from find_resource(), so put it. */
- kunit_put_resource(res);
- } else {
- ctx = kmalloc_obj(*ctx);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
- ctx->real_fn_addr = real_fn_addr;
- ctx->replacement_addr = replacement_addr;
- res = kunit_alloc_resource(test, NULL,
- &__kunit_static_stub_resource_free,
- GFP_KERNEL, ctx);
- }
- }
- EXPORT_SYMBOL_GPL(__kunit_activate_static_stub);
|