|
13 | 13 | #endif |
14 | 14 | #include <zephyr/llext/elf.h> |
15 | 15 | #include <zephyr/llext/llext.h> |
| 16 | +#include <zephyr/llext/inspect.h> |
16 | 17 | #include <zephyr/llext/symbol.h> |
17 | 18 | #include <zephyr/llext/buf_loader.h> |
18 | 19 | #include <zephyr/llext/fs_loader.h> |
@@ -316,6 +317,72 @@ LLEXT_LOAD_UNLOAD(threads_kernel_objects, |
316 | 317 | .test_setup = threads_objects_test_setup, |
317 | 318 | ) |
318 | 319 |
|
| 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 | + ®_hdr, (const void **)®_addr, ®_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 | + §_hdr, §_region, §_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 | + |
319 | 386 | #ifndef CONFIG_LLEXT_TYPE_ELF_OBJECT |
320 | 387 | static LLEXT_CONST uint8_t multi_file_ext[] ELF_ALIGN = { |
321 | 388 | #include "multi_file.inc" |
|
0 commit comments