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 <l.burelli@arduino.cc>
This commit is contained in:
committed by
Benjamin Cabé
parent
325d6b7d7f
commit
44c7a1401e
@@ -6,3 +6,5 @@ API Reference
|
||||
.. doxygengroup:: llext_symbols
|
||||
|
||||
.. doxygengroup:: llext_loader_apis
|
||||
|
||||
.. doxygengroup:: llext_inspect_apis
|
||||
|
||||
@@ -60,6 +60,10 @@ The returned ``void *`` can then be cast to the appropriate type and used.
|
||||
A wrapper for calling a function with no arguments is provided in
|
||||
:c:func:`llext_call_fn`.
|
||||
|
||||
Advanced users that need direct access to areas of the newly loaded extension
|
||||
may want to refer to :c:func:`llext_get_section_info` and other LLEXT
|
||||
inspection APIs.
|
||||
|
||||
Cleaning up after use
|
||||
=====================
|
||||
|
||||
|
||||
141
include/zephyr/llext/inspect.h
Normal file
141
include/zephyr/llext/inspect.h
Normal file
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Arduino SA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_LLEXT_INSPECT_H
|
||||
#define ZEPHYR_LLEXT_INSPECT_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
#include <zephyr/llext/llext.h>
|
||||
#include <zephyr/llext/loader.h>
|
||||
#include <zephyr/llext/llext_internal.h>
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief LLEXT ELF inspection routines.
|
||||
*
|
||||
* This file contains routines to inspect the contents of an ELF file. It is
|
||||
* intended to be used by applications that need advanced access to the ELF
|
||||
* file structures of a loaded extension.
|
||||
*
|
||||
* @defgroup llext_inspect_apis ELF inspection APIs
|
||||
* @ingroup llext_apis
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Get information about a memory region for the specified extension.
|
||||
*
|
||||
* Retrieve information about a region (merged group of similar sections) in
|
||||
* the extension. Any output parameter can be NULL if that information is not
|
||||
* needed.
|
||||
*
|
||||
* @param[in] ldr Loader
|
||||
* @param[in] ext Extension
|
||||
* @param[in] region Region to get information about
|
||||
* @param[out] hdr Variable storing the pointer to the region header
|
||||
* @param[out] addr Variable storing the region load address
|
||||
* @param[out] size Variable storing the region size
|
||||
*
|
||||
* @return 0 on success, -EINVAL if the region is invalid
|
||||
*/
|
||||
static inline int llext_get_region_info(const struct llext_loader *ldr,
|
||||
const struct llext *ext,
|
||||
enum llext_mem region,
|
||||
const elf_shdr_t **hdr,
|
||||
const void **addr, size_t *size)
|
||||
{
|
||||
if ((unsigned int)region >= LLEXT_MEM_COUNT) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (hdr) {
|
||||
*hdr = &ldr->sects[region];
|
||||
}
|
||||
if (addr) {
|
||||
*addr = ext->mem[region];
|
||||
}
|
||||
if (size) {
|
||||
*size = ext->mem_size[region];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the index of a section with the specified name.
|
||||
*
|
||||
* Requires the @ref llext_load_param.keep_section_info flag to be set at
|
||||
* extension load time.
|
||||
*
|
||||
* @param[in] ldr Loader
|
||||
* @param[in] ext Extension
|
||||
* @param[in] section_name Name of the section to look for
|
||||
*
|
||||
* @return Section index on success, -ENOENT if the section was not found,
|
||||
* -ENOTSUP if section data is not available.
|
||||
*/
|
||||
int llext_section_shndx(const struct llext_loader *ldr, const struct llext *ext,
|
||||
const char *section_name);
|
||||
|
||||
/**
|
||||
* @brief Get information about a section for the specified extension.
|
||||
*
|
||||
* Retrieve information about an ELF sections in the extension. Any output
|
||||
* parameter can be @c NULL if that information is not needed.
|
||||
*
|
||||
* Requires the @ref llext_load_param.keep_section_info flag to be set at
|
||||
* extension load time.
|
||||
*
|
||||
* @param[in] ldr Loader
|
||||
* @param[in] ext Extension
|
||||
* @param[in] shndx Section index
|
||||
* @param[out] hdr Variable storing the pointer to the section header
|
||||
* @param[out] region Variable storing the region the section belongs to
|
||||
* @param[out] offset Variable storing the offset of the section in the region
|
||||
*
|
||||
* @return 0 on success, -EINVAL if the section index is invalid,
|
||||
* -ENOTSUP if section data is not available.
|
||||
*/
|
||||
static inline int llext_get_section_info(const struct llext_loader *ldr,
|
||||
const struct llext *ext,
|
||||
unsigned int shndx,
|
||||
const elf_shdr_t **hdr,
|
||||
enum llext_mem *region,
|
||||
size_t *offset)
|
||||
{
|
||||
if (shndx < 0 || shndx >= ext->sect_cnt) {
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!ldr->sect_map) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (hdr) {
|
||||
*hdr = &ext->sect_hdrs[shndx];
|
||||
}
|
||||
if (region) {
|
||||
*region = ldr->sect_map[shndx].mem_idx;
|
||||
}
|
||||
if (offset) {
|
||||
*offset = ldr->sect_map[shndx].offset;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZEPHYR_LLEXT_INSPECT_H */
|
||||
@@ -21,6 +21,11 @@ extern "C" {
|
||||
struct llext_loader;
|
||||
struct llext;
|
||||
|
||||
struct llext_elf_sect_map {
|
||||
enum llext_mem mem_idx;
|
||||
size_t offset;
|
||||
};
|
||||
|
||||
const void *llext_loaded_sect_ptr(struct llext_loader *ldr, struct llext *ext, unsigned int sh_ndx);
|
||||
|
||||
/** @endcond */
|
||||
|
||||
@@ -23,32 +23,37 @@ static sys_slist_t _llext_list = SYS_SLIST_STATIC_INIT(&_llext_list);
|
||||
|
||||
static struct k_mutex llext_lock = Z_MUTEX_INITIALIZER(llext_lock);
|
||||
|
||||
int llext_get_section_header(struct llext_loader *ldr, struct llext *ext, const char *search_name,
|
||||
elf_shdr_t *shdr)
|
||||
int llext_section_shndx(const struct llext_loader *ldr, const struct llext *ext,
|
||||
const char *sect_name)
|
||||
{
|
||||
const elf_shdr_t *tmp;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0, tmp = ext->sect_hdrs;
|
||||
i < ext->sect_cnt;
|
||||
i++, tmp++) {
|
||||
const char *name = llext_peek(ldr,
|
||||
ldr->sects[LLEXT_MEM_SHSTRTAB].sh_offset +
|
||||
tmp->sh_name);
|
||||
for (i = 1; i < ext->sect_cnt; i++) {
|
||||
const char *name = llext_string(ldr, ext, LLEXT_MEM_SHSTRTAB,
|
||||
ext->sect_hdrs[i].sh_name);
|
||||
|
||||
if (!name) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (!strcmp(name, search_name)) {
|
||||
*shdr = *tmp;
|
||||
return 0;
|
||||
if (!strcmp(name, sect_name)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
int llext_get_section_header(struct llext_loader *ldr, struct llext *ext, const char *search_name,
|
||||
elf_shdr_t *shdr)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = llext_section_shndx(ldr, ext, search_name);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
*shdr = ext->sect_hdrs[ret];
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t llext_find_section(struct llext_loader *ldr, const char *search_name)
|
||||
{
|
||||
elf_shdr_t *shdr;
|
||||
|
||||
@@ -9,11 +9,7 @@
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/llext/llext.h>
|
||||
|
||||
struct llext_elf_sect_map {
|
||||
enum llext_mem mem_idx;
|
||||
size_t offset;
|
||||
};
|
||||
#include <zephyr/llext/llext_internal.h>
|
||||
|
||||
/*
|
||||
* Memory management (llext_mem.c)
|
||||
@@ -53,7 +49,7 @@ static inline void llext_free(void *ptr)
|
||||
int do_llext_load(struct llext_loader *ldr, struct llext *ext,
|
||||
const struct llext_load_param *ldr_parm);
|
||||
|
||||
static inline const char *llext_string(struct llext_loader *ldr, struct llext *ext,
|
||||
static inline const char *llext_string(const struct llext_loader *ldr, const struct llext *ext,
|
||||
enum llext_mem mem_idx, unsigned int idx)
|
||||
{
|
||||
return (char *)ext->mem[mem_idx] + idx;
|
||||
|
||||
Reference in New Issue
Block a user