Skip to content

Commit 44c7a14

Browse files
pillo79kartben
authored andcommitted
llext: add ELF inspection APIs
Add APIs to inspect the contents of an ELF file loaded as an extension. This is useful for applications that need to access the contents of the extension in a more fine-grained way than the existing LLEXT APIs. Use of these APIs requires the 'keep_elf_data' option to be provided via struct llext_load_param to the 'llext_load()' call. Signed-off-by: Luca Burelli <[email protected]>
1 parent 325d6b7 commit 44c7a14

File tree

6 files changed

+175
-22
lines changed

6 files changed

+175
-22
lines changed

doc/services/llext/api.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,5 @@ API Reference
66
.. doxygengroup:: llext_symbols
77

88
.. doxygengroup:: llext_loader_apis
9+
10+
.. doxygengroup:: llext_inspect_apis

doc/services/llext/load.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@ The returned ``void *`` can then be cast to the appropriate type and used.
6060
A wrapper for calling a function with no arguments is provided in
6161
:c:func:`llext_call_fn`.
6262

63+
Advanced users that need direct access to areas of the newly loaded extension
64+
may want to refer to :c:func:`llext_get_section_info` and other LLEXT
65+
inspection APIs.
66+
6367
Cleaning up after use
6468
=====================
6569

include/zephyr/llext/inspect.h

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
/*
2+
* Copyright (c) 2025 Arduino SA
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#ifndef ZEPHYR_LLEXT_INSPECT_H
8+
#define ZEPHYR_LLEXT_INSPECT_H
9+
10+
#ifdef __cplusplus
11+
extern "C" {
12+
#endif
13+
14+
#include <stddef.h>
15+
#include <zephyr/llext/llext.h>
16+
#include <zephyr/llext/loader.h>
17+
#include <zephyr/llext/llext_internal.h>
18+
19+
/**
20+
* @file
21+
* @brief LLEXT ELF inspection routines.
22+
*
23+
* This file contains routines to inspect the contents of an ELF file. It is
24+
* intended to be used by applications that need advanced access to the ELF
25+
* file structures of a loaded extension.
26+
*
27+
* @defgroup llext_inspect_apis ELF inspection APIs
28+
* @ingroup llext_apis
29+
* @{
30+
*/
31+
32+
/**
33+
* @brief Get information about a memory region for the specified extension.
34+
*
35+
* Retrieve information about a region (merged group of similar sections) in
36+
* the extension. Any output parameter can be NULL if that information is not
37+
* needed.
38+
*
39+
* @param[in] ldr Loader
40+
* @param[in] ext Extension
41+
* @param[in] region Region to get information about
42+
* @param[out] hdr Variable storing the pointer to the region header
43+
* @param[out] addr Variable storing the region load address
44+
* @param[out] size Variable storing the region size
45+
*
46+
* @return 0 on success, -EINVAL if the region is invalid
47+
*/
48+
static inline int llext_get_region_info(const struct llext_loader *ldr,
49+
const struct llext *ext,
50+
enum llext_mem region,
51+
const elf_shdr_t **hdr,
52+
const void **addr, size_t *size)
53+
{
54+
if ((unsigned int)region >= LLEXT_MEM_COUNT) {
55+
return -EINVAL;
56+
}
57+
58+
if (hdr) {
59+
*hdr = &ldr->sects[region];
60+
}
61+
if (addr) {
62+
*addr = ext->mem[region];
63+
}
64+
if (size) {
65+
*size = ext->mem_size[region];
66+
}
67+
68+
return 0;
69+
}
70+
71+
/**
72+
* @brief Get the index of a section with the specified name.
73+
*
74+
* Requires the @ref llext_load_param.keep_section_info flag to be set at
75+
* extension load time.
76+
*
77+
* @param[in] ldr Loader
78+
* @param[in] ext Extension
79+
* @param[in] section_name Name of the section to look for
80+
*
81+
* @return Section index on success, -ENOENT if the section was not found,
82+
* -ENOTSUP if section data is not available.
83+
*/
84+
int llext_section_shndx(const struct llext_loader *ldr, const struct llext *ext,
85+
const char *section_name);
86+
87+
/**
88+
* @brief Get information about a section for the specified extension.
89+
*
90+
* Retrieve information about an ELF sections in the extension. Any output
91+
* parameter can be @c NULL if that information is not needed.
92+
*
93+
* Requires the @ref llext_load_param.keep_section_info flag to be set at
94+
* extension load time.
95+
*
96+
* @param[in] ldr Loader
97+
* @param[in] ext Extension
98+
* @param[in] shndx Section index
99+
* @param[out] hdr Variable storing the pointer to the section header
100+
* @param[out] region Variable storing the region the section belongs to
101+
* @param[out] offset Variable storing the offset of the section in the region
102+
*
103+
* @return 0 on success, -EINVAL if the section index is invalid,
104+
* -ENOTSUP if section data is not available.
105+
*/
106+
static inline int llext_get_section_info(const struct llext_loader *ldr,
107+
const struct llext *ext,
108+
unsigned int shndx,
109+
const elf_shdr_t **hdr,
110+
enum llext_mem *region,
111+
size_t *offset)
112+
{
113+
if (shndx < 0 || shndx >= ext->sect_cnt) {
114+
return -EINVAL;
115+
}
116+
if (!ldr->sect_map) {
117+
return -ENOTSUP;
118+
}
119+
120+
if (hdr) {
121+
*hdr = &ext->sect_hdrs[shndx];
122+
}
123+
if (region) {
124+
*region = ldr->sect_map[shndx].mem_idx;
125+
}
126+
if (offset) {
127+
*offset = ldr->sect_map[shndx].offset;
128+
}
129+
130+
return 0;
131+
}
132+
133+
/**
134+
* @}
135+
*/
136+
137+
#ifdef __cplusplus
138+
}
139+
#endif
140+
141+
#endif /* ZEPHYR_LLEXT_INSPECT_H */

include/zephyr/llext/llext_internal.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ extern "C" {
2121
struct llext_loader;
2222
struct llext;
2323

24+
struct llext_elf_sect_map {
25+
enum llext_mem mem_idx;
26+
size_t offset;
27+
};
28+
2429
const void *llext_loaded_sect_ptr(struct llext_loader *ldr, struct llext *ext, unsigned int sh_ndx);
2530

2631
/** @endcond */

subsys/llext/llext.c

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -23,32 +23,37 @@ static sys_slist_t _llext_list = SYS_SLIST_STATIC_INIT(&_llext_list);
2323

2424
static struct k_mutex llext_lock = Z_MUTEX_INITIALIZER(llext_lock);
2525

26-
int llext_get_section_header(struct llext_loader *ldr, struct llext *ext, const char *search_name,
27-
elf_shdr_t *shdr)
26+
int llext_section_shndx(const struct llext_loader *ldr, const struct llext *ext,
27+
const char *sect_name)
2828
{
29-
const elf_shdr_t *tmp;
3029
unsigned int i;
3130

32-
for (i = 0, tmp = ext->sect_hdrs;
33-
i < ext->sect_cnt;
34-
i++, tmp++) {
35-
const char *name = llext_peek(ldr,
36-
ldr->sects[LLEXT_MEM_SHSTRTAB].sh_offset +
37-
tmp->sh_name);
38-
39-
if (!name) {
40-
return -ENOTSUP;
41-
}
31+
for (i = 1; i < ext->sect_cnt; i++) {
32+
const char *name = llext_string(ldr, ext, LLEXT_MEM_SHSTRTAB,
33+
ext->sect_hdrs[i].sh_name);
4234

43-
if (!strcmp(name, search_name)) {
44-
*shdr = *tmp;
45-
return 0;
35+
if (!strcmp(name, sect_name)) {
36+
return i;
4637
}
4738
}
4839

4940
return -ENOENT;
5041
}
5142

43+
int llext_get_section_header(struct llext_loader *ldr, struct llext *ext, const char *search_name,
44+
elf_shdr_t *shdr)
45+
{
46+
int ret;
47+
48+
ret = llext_section_shndx(ldr, ext, search_name);
49+
if (ret < 0) {
50+
return ret;
51+
}
52+
53+
*shdr = ext->sect_hdrs[ret];
54+
return 0;
55+
}
56+
5257
ssize_t llext_find_section(struct llext_loader *ldr, const char *search_name)
5358
{
5459
elf_shdr_t *shdr;

subsys/llext/llext_priv.h

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,7 @@
99

1010
#include <zephyr/kernel.h>
1111
#include <zephyr/llext/llext.h>
12-
13-
struct llext_elf_sect_map {
14-
enum llext_mem mem_idx;
15-
size_t offset;
16-
};
12+
#include <zephyr/llext/llext_internal.h>
1713

1814
/*
1915
* Memory management (llext_mem.c)
@@ -53,7 +49,7 @@ static inline void llext_free(void *ptr)
5349
int do_llext_load(struct llext_loader *ldr, struct llext *ext,
5450
const struct llext_load_param *ldr_parm);
5551

56-
static inline const char *llext_string(struct llext_loader *ldr, struct llext *ext,
52+
static inline const char *llext_string(const struct llext_loader *ldr, const struct llext *ext,
5753
enum llext_mem mem_idx, unsigned int idx)
5854
{
5955
return (char *)ext->mem[mem_idx] + idx;

0 commit comments

Comments
 (0)