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  */
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)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 
62 	/* address and size compensated for alignment prepad */
63 	if (addr) {
64 		*addr = (void *)((uintptr_t)ext->mem[region] + ldr->sects[region].sh_info);
65 	}
66 	if (size) {
67 		*size = ext->mem_size[region] - ldr->sects[region].sh_info;
68 	}
69 
70 	return 0;
71 }
72 
73 /**
74  * @brief Get the index of a section with the specified name.
75  *
76  * Requires the @ref llext_load_param.keep_section_info flag to be set at
77  * extension load time.
78  *
79  * @param[in] ldr Loader
80  * @param[in] ext Extension
81  * @param[in] section_name Name of the section to look for
82  *
83  * @return Section index on success, -ENOENT if the section was not found,
84  *         -ENOTSUP if section data is not available.
85  */
86 int llext_section_shndx(const struct llext_loader *ldr, const struct llext *ext,
87 			    const char *section_name);
88 
89 /**
90  * @brief Get information about a section for the specified extension.
91  *
92  * Retrieve information about an ELF sections in the extension. Any output
93  * parameter can be @c NULL if that information is not needed.
94  *
95  * Requires the @ref llext_load_param.keep_section_info flag to be set at
96  * extension load time.
97  *
98  * @param[in] ldr Loader
99  * @param[in] ext Extension
100  * @param[in] shndx Section index
101  * @param[out] hdr Variable storing the pointer to the section header
102  * @param[out] region Variable storing the region the section belongs to
103  * @param[out] offset Variable storing the offset of the section in the region
104  *
105  * @return 0 on success, -EINVAL if the section index is invalid,
106  *         -ENOTSUP if section data is not available.
107  */
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)108 static inline int llext_get_section_info(const struct llext_loader *ldr,
109 					 const struct llext *ext,
110 					 unsigned int shndx,
111 					 const elf_shdr_t **hdr,
112 					 enum llext_mem *region,
113 					 size_t *offset)
114 {
115 	if (shndx < 0 || shndx >= ext->sect_cnt) {
116 		return -EINVAL;
117 	}
118 	if (!ldr->sect_map) {
119 		return -ENOTSUP;
120 	}
121 
122 	enum llext_mem mem_idx = ldr->sect_map[shndx].mem_idx;
123 
124 	if (hdr) {
125 		*hdr = &ext->sect_hdrs[shndx];
126 	}
127 	if (region) {
128 		*region = mem_idx;
129 	}
130 
131 	/* offset compensated for alignment prepad */
132 	if (offset) {
133 		*offset = ldr->sect_map[shndx].offset - ldr->sects[mem_idx].sh_info;
134 	}
135 
136 	return 0;
137 }
138 
139 /**
140  * @}
141  */
142 
143 #ifdef __cplusplus
144 }
145 #endif
146 
147 #endif /* ZEPHYR_LLEXT_INSPECT_H */
148