Skip to content

Commit fe29c40

Browse files
pillo79kartben
authored andcommitted
llext: add inspection API test suite
This patch adds a test suite for the inspection API. The test checks that the symbols exported by the 'inspect_ext' extension are correctly mapped inside their corresponding regions and sections. Signed-off-by: Luca Burelli <[email protected]>
1 parent 44c7a14 commit fe29c40

File tree

3 files changed

+96
-0
lines changed

3 files changed

+96
-0
lines changed

tests/subsys/llext/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ set(ext_names
2121
relative_jump
2222
object
2323
syscalls
24+
inspect
2425
threads_kernel_objects
2526
export_dependent
2627
export_dependency
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* Copyright (c) 2025 Arduino SA
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
/* This extension exports a number of symbols to be used by the LLEXT
8+
* inspection APIs. Each symbol is exported within a different section
9+
* and only the addresses are checked in this test.
10+
*/
11+
12+
#include <zephyr/llext/symbol.h>
13+
14+
int number_in_bss;
15+
int number_in_data = 1;
16+
const int number_in_rodata = 2;
17+
const int number_in_my_rodata Z_GENERIC_SECTION(.my_rodata) = 3;
18+
19+
void function_in_text(void)
20+
{
21+
/* only used for address check */
22+
}
23+
24+
EXPORT_SYMBOL(number_in_bss);
25+
EXPORT_SYMBOL(number_in_data);
26+
EXPORT_SYMBOL(number_in_rodata);
27+
EXPORT_SYMBOL(number_in_my_rodata);
28+
EXPORT_SYMBOL(function_in_text);

tests/subsys/llext/src/test_llext.c

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#endif
1414
#include <zephyr/llext/elf.h>
1515
#include <zephyr/llext/llext.h>
16+
#include <zephyr/llext/inspect.h>
1617
#include <zephyr/llext/symbol.h>
1718
#include <zephyr/llext/buf_loader.h>
1819
#include <zephyr/llext/fs_loader.h>
@@ -316,6 +317,72 @@ LLEXT_LOAD_UNLOAD(threads_kernel_objects,
316317
.test_setup = threads_objects_test_setup,
317318
)
318319

320+
static LLEXT_CONST uint8_t inspect_ext[] ELF_ALIGN = {
321+
#include "inspect.inc"
322+
};
323+
324+
void do_inspect_checks(struct llext_loader *ldr, struct llext *ext, enum llext_mem reg_idx,
325+
const char *sect_name, const char *sym_name)
326+
{
327+
const elf_shdr_t *sect_hdr = NULL, *reg_hdr = NULL;
328+
enum llext_mem sect_region = LLEXT_MEM_COUNT;
329+
uintptr_t reg_addr = 0, sym_addr = 0;
330+
size_t reg_size = 0, sect_offset = 0;
331+
int sect_shndx, res;
332+
333+
res = llext_get_region_info(ldr, ext, reg_idx,
334+
&reg_hdr, (const void **)&reg_addr, &reg_size);
335+
zassert_ok(res, "get_region_info() should succeed");
336+
sect_shndx = llext_section_shndx(ldr, ext, sect_name);
337+
zassert_true(sect_shndx > 0, "section %s should be found", sect_name);
338+
res = llext_get_section_info(ldr, ext, sect_shndx,
339+
&sect_hdr, &sect_region, &sect_offset);
340+
zassert_ok(res, "get_section_info() should succeed");
341+
sym_addr = (uintptr_t)llext_find_sym(&ext->exp_tab, sym_name);
342+
zassert_true(sym_addr, "symbol %s must be exported", sym_name);
343+
344+
zassert_equal(reg_idx, sect_region, "region mismatch (expected %d, got %d)",
345+
reg_idx, sect_region);
346+
zassert_true(sect_hdr->sh_offset >= reg_hdr->sh_offset &&
347+
(sect_hdr->sh_offset + sect_hdr->sh_size <=
348+
reg_hdr->sh_offset + reg_hdr->sh_size),
349+
"section %s overflows its region %d", sect_name, reg_idx);
350+
zassert_true(sect_offset < reg_size, "section offset outside region");
351+
zassert_true(sym_addr >= reg_addr && sym_addr < reg_addr + reg_size,
352+
"symbol %s mapped outside region %d", sym_name, reg_idx);
353+
zassert_true(sym_addr >= reg_addr + sect_offset &&
354+
sym_addr < reg_addr + sect_offset + sect_hdr->sh_size,
355+
"symbol %s mapped outside section %s", sym_name, sect_name);
356+
}
357+
358+
ZTEST(llext, test_inspect)
359+
{
360+
int res;
361+
362+
struct llext_buf_loader buf_loader =
363+
LLEXT_BUF_LOADER(inspect_ext, sizeof(inspect_ext));
364+
struct llext_loader *ldr = &buf_loader.loader;
365+
struct llext_load_param ldr_parm = LLEXT_LOAD_PARAM_DEFAULT;
366+
struct llext *ext = NULL;
367+
size_t max_alloc_bytes;
368+
369+
ldr_parm.keep_section_info = true;
370+
res = llext_load(ldr, "inspect", &ext, &ldr_parm);
371+
zassert_ok(res, "load should succeed");
372+
373+
do_inspect_checks(ldr, ext, LLEXT_MEM_BSS, ".bss", "number_in_bss");
374+
do_inspect_checks(ldr, ext, LLEXT_MEM_DATA, ".data", "number_in_data");
375+
do_inspect_checks(ldr, ext, LLEXT_MEM_RODATA, ".rodata", "number_in_rodata");
376+
do_inspect_checks(ldr, ext, LLEXT_MEM_RODATA, ".my_rodata", "number_in_my_rodata");
377+
do_inspect_checks(ldr, ext, LLEXT_MEM_TEXT, ".text", "function_in_text");
378+
379+
max_alloc_bytes = ext->alloc_size;
380+
llext_free_inspection_data(ldr, ext);
381+
zassert_true(ext->alloc_size < max_alloc_bytes, "inspection data should be freed");
382+
383+
llext_unload(&ext);
384+
}
385+
319386
#ifndef CONFIG_LLEXT_TYPE_ELF_OBJECT
320387
static LLEXT_CONST uint8_t multi_file_ext[] ELF_ALIGN = {
321388
#include "multi_file.inc"

0 commit comments

Comments
 (0)