diff --git a/tests/subsys/llext/CMakeLists.txt b/tests/subsys/llext/CMakeLists.txt index 0c121b2852d6..31730e2a2c7e 100644 --- a/tests/subsys/llext/CMakeLists.txt +++ b/tests/subsys/llext/CMakeLists.txt @@ -21,6 +21,7 @@ set(ext_names relative_jump object syscalls + inspect threads_kernel_objects export_dependent export_dependency diff --git a/tests/subsys/llext/src/inspect_ext.c b/tests/subsys/llext/src/inspect_ext.c new file mode 100644 index 000000000000..97d09f99932b --- /dev/null +++ b/tests/subsys/llext/src/inspect_ext.c @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2025 Arduino SA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* This extension exports a number of symbols to be used by the LLEXT + * inspection APIs. Each symbol is exported within a different section + * and only the addresses are checked in this test. + */ + +#include + +int number_in_bss; +int number_in_data = 1; +const int number_in_rodata = 2; +const int number_in_my_rodata Z_GENERIC_SECTION(.my_rodata) = 3; + +void function_in_text(void) +{ + /* only used for address check */ +} + +EXPORT_SYMBOL(number_in_bss); +EXPORT_SYMBOL(number_in_data); +EXPORT_SYMBOL(number_in_rodata); +EXPORT_SYMBOL(number_in_my_rodata); +EXPORT_SYMBOL(function_in_text); diff --git a/tests/subsys/llext/src/test_llext.c b/tests/subsys/llext/src/test_llext.c index 9ac695311f03..b60d6e211e23 100644 --- a/tests/subsys/llext/src/test_llext.c +++ b/tests/subsys/llext/src/test_llext.c @@ -13,6 +13,7 @@ #endif #include #include +#include #include #include #include @@ -316,6 +317,64 @@ LLEXT_LOAD_UNLOAD(threads_kernel_objects, .test_setup = threads_objects_test_setup, ) +static LLEXT_CONST uint8_t inspect_ext[] ELF_ALIGN = { + #include "inspect.inc" +}; + +void do_inspect_checks(struct llext_loader *ldr, struct llext *ext, enum llext_mem reg_idx, + const char *sect_name, const char *sym_name) +{ + const elf_shdr_t *sect_hdr = NULL, *reg_hdr = NULL; + enum llext_mem sect_region = LLEXT_MEM_COUNT; + uintptr_t reg_addr = 0, sym_addr = 0; + size_t reg_size = 0, sect_offset = 0; + int sect_shndx, res; + + res = llext_get_region_info(ldr, ext, reg_idx, ®_hdr, (const void **)®_addr, ®_size); + zassert_ok(res, "get_region_info() should succeed"); + sect_shndx = llext_section_shndx(ldr, ext, sect_name); + zassert_true(sect_shndx > 0, "section %s should be found", sect_name); + res = llext_get_section_info(ldr, ext, sect_shndx, §_hdr, §_region, §_offset); + zassert_ok(res, "get_section_info() should succeed"); + sym_addr = (uintptr_t)llext_find_sym(&ext->exp_tab, sym_name); + zassert_true(sym_addr, "symbol %s must be exported", sym_name); + + zassert_equal(reg_idx, sect_region, "region mismatch (expected %d, got %d)", + reg_idx, sect_region); + zassert_true(sect_hdr->sh_offset >= reg_hdr->sh_offset && + sect_hdr->sh_offset + sect_hdr->sh_size <= reg_hdr->sh_offset + reg_hdr->sh_size, + "section %s overflowing region %d", sect_name, reg_idx); + zassert_true(sect_offset < reg_size, "section offset outside region"); + zassert_true(sym_addr >= reg_addr && sym_addr < reg_addr + reg_size, + "symbol %s mapped outside region %d", sym_name, reg_idx); + zassert_true(sym_addr >= reg_addr + sect_offset && + sym_addr < reg_addr + sect_offset + sect_hdr->sh_size, + "symbol %s mapped outside section %s", sym_name, sect_name); +} + +ZTEST(llext, test_inspect) +{ + int res; + + struct llext_buf_loader buf_loader = + LLEXT_BUF_LOADER(inspect_ext, sizeof(inspect_ext)); + struct llext_loader *ldr = &buf_loader.loader; + struct llext_load_param ldr_parm = LLEXT_LOAD_PARAM_DEFAULT; + struct llext *ext = NULL; + + ldr_parm.keep_section_info = true; + res = llext_load(ldr, "inspect", &ext, &ldr_parm); + zassert_ok(res, "load should succeed"); + + do_inspect_checks(ldr, ext, LLEXT_MEM_BSS, ".bss", "number_in_bss"); + do_inspect_checks(ldr, ext, LLEXT_MEM_DATA, ".data", "number_in_data"); + do_inspect_checks(ldr, ext, LLEXT_MEM_RODATA, ".rodata", "number_in_rodata"); + do_inspect_checks(ldr, ext, LLEXT_MEM_RODATA, ".my_rodata", "number_in_my_rodata"); + do_inspect_checks(ldr, ext, LLEXT_MEM_TEXT, ".text", "function_in_text"); + + llext_unload(&ext); +} + #ifndef CONFIG_LLEXT_TYPE_ELF_OBJECT static LLEXT_CONST uint8_t multi_file_ext[] ELF_ALIGN = { #include "multi_file.inc"