| Message ID | 20260129082814.1777779-3-paul.elder@ideasonboard.com |
|---|---|
| State | New |
| Headers | show |
| Series |
|
| Related | show |
Hi Paul, Looks good to me! Quoting Paul Elder (2026-01-29 08:28:08) > In the near future we will add support for layers/shoes on top of > libcamera, which will need to validate and load symbols from ELF files > similar to how IPAModule does. To avoid code duplication, move this code > out of IPAModule into internal utils. > > Signed-off-by: Paul Elder <paul.elder@ideasonboard.com> > Reviewed-by: Stefan Klug <stefan.klug@ideasonboard.com> > --- > No change in v6 > > No change in v5 > > No change in v4 > > Changes in v3: > - add documentation for elfVerifyIdent > > No change in v2 > --- > include/libcamera/internal/utils.h | 6 ++ > src/libcamera/ipa_module.cpp | 152 +-------------------------- > src/libcamera/utils.cpp | 162 +++++++++++++++++++++++++++++ > 3 files changed, 171 insertions(+), 149 deletions(-) > > diff --git a/include/libcamera/internal/utils.h b/include/libcamera/internal/utils.h > index 5b7957b5d77e..7d69849b1c19 100644 > --- a/include/libcamera/internal/utils.h > +++ b/include/libcamera/internal/utils.h > @@ -8,9 +8,12 @@ > #pragma once > > #include <functional> > +#include <stdint.h> > #include <string> > #include <vector> > > +#include <libcamera/base/span.h> > + > namespace libcamera { > > namespace utils { > @@ -18,6 +21,9 @@ namespace utils { > unsigned int findSharedObjects(const char *libDir, unsigned int maxDepth, > std::function<int(const std::string &)> func); Reviewed-by: Isaac Scott <isaac.scott@ideasonboard.com> Best wishes, Isaac > > +int elfVerifyIdent(Span<const uint8_t> elf); > +Span<const uint8_t> elfLoadSymbol(Span<const uint8_t> elf, const char *symbol); > + > } /* namespace utils */ > > } /* namespace libcamera */ > diff --git a/src/libcamera/ipa_module.cpp b/src/libcamera/ipa_module.cpp > index e6ea61e44829..c8559ec8b74c 100644 > --- a/src/libcamera/ipa_module.cpp > +++ b/src/libcamera/ipa_module.cpp > @@ -25,6 +25,7 @@ > #include <libcamera/base/utils.h> > > #include "libcamera/internal/pipeline_handler.h" > +#include "libcamera/internal/utils.h" > > /** > * \file ipa_module.h > @@ -40,153 +41,6 @@ namespace libcamera { > > LOG_DEFINE_CATEGORY(IPAModule) > > -namespace { > - > -template<typename T> > -typename std::remove_extent_t<T> *elfPointer(Span<const uint8_t> elf, > - off_t offset, size_t objSize) > -{ > - size_t size = offset + objSize; > - if (size > elf.size() || size < objSize) > - return nullptr; > - > - return reinterpret_cast<typename std::remove_extent_t<T> *>( > - reinterpret_cast<const char *>(elf.data()) + offset); > -} > - > -template<typename T> > -typename std::remove_extent_t<T> *elfPointer(Span<const uint8_t> elf, > - off_t offset) > -{ > - return elfPointer<T>(elf, offset, sizeof(T)); > -} > - > -int elfVerifyIdent(Span<const uint8_t> elf) > -{ > - const char *e_ident = elfPointer<const char[EI_NIDENT]>(elf, 0); > - if (!e_ident) > - return -ENOEXEC; > - > - if (e_ident[EI_MAG0] != ELFMAG0 || > - e_ident[EI_MAG1] != ELFMAG1 || > - e_ident[EI_MAG2] != ELFMAG2 || > - e_ident[EI_MAG3] != ELFMAG3 || > - e_ident[EI_VERSION] != EV_CURRENT) > - return -ENOEXEC; > - > - int bitClass = sizeof(unsigned long) == 4 ? ELFCLASS32 : ELFCLASS64; > - if (e_ident[EI_CLASS] != bitClass) > - return -ENOEXEC; > - > - int a = 1; > - unsigned char endianness = *reinterpret_cast<char *>(&a) == 1 > - ? ELFDATA2LSB : ELFDATA2MSB; > - if (e_ident[EI_DATA] != endianness) > - return -ENOEXEC; > - > - return 0; > -} > - > -const ElfW(Shdr) *elfSection(Span<const uint8_t> elf, const ElfW(Ehdr) *eHdr, > - ElfW(Half) idx) > -{ > - if (idx >= eHdr->e_shnum) > - return nullptr; > - > - off_t offset = eHdr->e_shoff + idx * > - static_cast<uint32_t>(eHdr->e_shentsize); > - return elfPointer<const ElfW(Shdr)>(elf, offset); > -} > - > -/** > - * \brief Retrieve address and size of a symbol from an mmap'ed ELF file > - * \param[in] elf Address and size of mmap'ed ELF file > - * \param[in] symbol Symbol name > - * > - * \return The memory region storing the symbol on success, or an empty span > - * otherwise > - */ > -Span<const uint8_t> elfLoadSymbol(Span<const uint8_t> elf, const char *symbol) > -{ > - const ElfW(Ehdr) *eHdr = elfPointer<const ElfW(Ehdr)>(elf, 0); > - if (!eHdr) > - return {}; > - > - const ElfW(Shdr) *sHdr = elfSection(elf, eHdr, eHdr->e_shstrndx); > - if (!sHdr) > - return {}; > - off_t shnameoff = sHdr->sh_offset; > - > - /* Locate .dynsym section header. */ > - const ElfW(Shdr) *dynsym = nullptr; > - for (unsigned int i = 0; i < eHdr->e_shnum; i++) { > - sHdr = elfSection(elf, eHdr, i); > - if (!sHdr) > - return {}; > - > - off_t offset = shnameoff + sHdr->sh_name; > - const char *name = elfPointer<const char[8]>(elf, offset); > - if (!name) > - return {}; > - > - if (sHdr->sh_type == SHT_DYNSYM && !strcmp(name, ".dynsym")) { > - dynsym = sHdr; > - break; > - } > - } > - > - if (dynsym == nullptr) { > - LOG(IPAModule, Error) << "ELF has no .dynsym section"; > - return {}; > - } > - > - sHdr = elfSection(elf, eHdr, dynsym->sh_link); > - if (!sHdr) > - return {}; > - off_t dynsym_nameoff = sHdr->sh_offset; > - > - /* Locate symbol in the .dynsym section. */ > - const ElfW(Sym) *targetSymbol = nullptr; > - unsigned int dynsym_num = dynsym->sh_size / dynsym->sh_entsize; > - for (unsigned int i = 0; i < dynsym_num; i++) { > - off_t offset = dynsym->sh_offset + dynsym->sh_entsize * i; > - const ElfW(Sym) *sym = elfPointer<const ElfW(Sym)>(elf, offset); > - if (!sym) > - return {}; > - > - offset = dynsym_nameoff + sym->st_name; > - const char *name = elfPointer<const char>(elf, offset, > - strlen(symbol) + 1); > - if (!name) > - return {}; > - > - if (!strcmp(name, symbol) && > - sym->st_info & STB_GLOBAL) { > - targetSymbol = sym; > - break; > - } > - } > - > - if (targetSymbol == nullptr) { > - LOG(IPAModule, Error) << "Symbol " << symbol << " not found"; > - return {}; > - } > - > - /* Locate and return data of symbol. */ > - sHdr = elfSection(elf, eHdr, targetSymbol->st_shndx); > - if (!sHdr) > - return {}; > - off_t offset = sHdr->sh_offset + (targetSymbol->st_value - sHdr->sh_addr); > - const uint8_t *data = elfPointer<const uint8_t>(elf, offset, > - targetSymbol->st_size); > - if (!data) > - return {}; > - > - return { data, targetSymbol->st_size }; > -} > - > -} /* namespace */ > - > /** > * \def IPA_MODULE_API_VERSION > * \brief The IPA module API version > @@ -280,13 +134,13 @@ int IPAModule::loadIPAModuleInfo() > } > > Span<const uint8_t> data = file.map(); > - int ret = elfVerifyIdent(data); > + int ret = utils::elfVerifyIdent(data); > if (ret) { > LOG(IPAModule, Error) << "IPA module is not an ELF file"; > return ret; > } > > - Span<const uint8_t> info = elfLoadSymbol(data, "ipaModuleInfo"); > + Span<const uint8_t> info = utils::elfLoadSymbol(data, "ipaModuleInfo"); > if (info.size() < sizeof(info_)) { > LOG(IPAModule, Error) << "IPA module has no valid info"; > return -EINVAL; > diff --git a/src/libcamera/utils.cpp b/src/libcamera/utils.cpp > index 2ce62f236cea..6894b489b557 100644 > --- a/src/libcamera/utils.cpp > +++ b/src/libcamera/utils.cpp > @@ -10,20 +10,63 @@ > #include <algorithm> > #include <dirent.h> > #include <functional> > +#include <link.h> > +#include <stdint.h> > #include <string.h> > #include <string> > #include <sys/types.h> > #include <vector> > > +#include <libcamera/base/log.h> > + > /** > * \file internal/utils.h > * \brief Miscellaneous utility functions (internal) > */ > > +/* musl doesn't declare _DYNAMIC in link.h, declare it manually. */ > +extern ElfW(Dyn) _DYNAMIC[]; > + > namespace libcamera { > > +namespace { > + > +template<typename T> > +typename std::remove_extent_t<T> *elfPointer(Span<const uint8_t> elf, > + off_t offset, size_t objSize) > +{ > + size_t size = offset + objSize; > + if (size > elf.size() || size < objSize) > + return nullptr; > + > + return reinterpret_cast<typename std::remove_extent_t<T> *>( > + reinterpret_cast<const char *>(elf.data()) + offset); > +} > + > +template<typename T> > +typename std::remove_extent_t<T> *elfPointer(Span<const uint8_t> elf, > + off_t offset) > +{ > + return elfPointer<T>(elf, offset, sizeof(T)); > +} > + > +const ElfW(Shdr) *elfSection(Span<const uint8_t> elf, const ElfW(Ehdr) *eHdr, > + ElfW(Half) idx) > +{ > + if (idx >= eHdr->e_shnum) > + return nullptr; > + > + off_t offset = eHdr->e_shoff + idx * > + static_cast<uint32_t>(eHdr->e_shentsize); > + return elfPointer<const ElfW(Shdr)>(elf, offset); > +} > + > +} /* namespace */ > + > namespace utils { > > +LOG_DEFINE_CATEGORY(Utils) > + > /** > * \brief Identify shared library objects within a directory > * \param[in] libDir The directory to search for shared objects > @@ -102,6 +145,125 @@ unsigned int findSharedObjects(const char *libDir, unsigned int maxDepth, > return count; > } > > +/** > + * \brief Verify that a binary blob is an ELF > + * \param[in] elf The binary blob as a Span > + * > + * \return 0 for success, and -ENOEXEC otherwise > + */ > +int elfVerifyIdent(Span<const uint8_t> elf) > +{ > + const char *e_ident = elfPointer<const char[EI_NIDENT]>(elf, 0); > + if (!e_ident) > + return -ENOEXEC; > + > + if (e_ident[EI_MAG0] != ELFMAG0 || > + e_ident[EI_MAG1] != ELFMAG1 || > + e_ident[EI_MAG2] != ELFMAG2 || > + e_ident[EI_MAG3] != ELFMAG3 || > + e_ident[EI_VERSION] != EV_CURRENT) > + return -ENOEXEC; > + > + int bitClass = sizeof(unsigned long) == 4 ? ELFCLASS32 : ELFCLASS64; > + if (e_ident[EI_CLASS] != bitClass) > + return -ENOEXEC; > + > + int a = 1; > + unsigned char endianness = *reinterpret_cast<char *>(&a) == 1 > + ? ELFDATA2LSB : ELFDATA2MSB; > + if (e_ident[EI_DATA] != endianness) > + return -ENOEXEC; > + > + return 0; > +} > + > +/** > + * \brief Retrieve address and size of a symbol from an mmap'ed ELF file > + * \param[in] elf Address and size of mmap'ed ELF file > + * \param[in] symbol Symbol name > + * > + * \return The memory region storing the symbol on success, or an empty span > + * otherwise > + */ > +Span<const uint8_t> elfLoadSymbol(Span<const uint8_t> elf, const char *symbol) > +{ > + const ElfW(Ehdr) *eHdr = elfPointer<const ElfW(Ehdr)>(elf, 0); > + if (!eHdr) > + return {}; > + > + const ElfW(Shdr) *sHdr = elfSection(elf, eHdr, eHdr->e_shstrndx); > + if (!sHdr) > + return {}; > + off_t shnameoff = sHdr->sh_offset; > + > + /* Locate .dynsym section header. */ > + const ElfW(Shdr) *dynsym = nullptr; > + for (unsigned int i = 0; i < eHdr->e_shnum; i++) { > + sHdr = elfSection(elf, eHdr, i); > + if (!sHdr) > + return {}; > + > + off_t offset = shnameoff + sHdr->sh_name; > + const char *name = elfPointer<const char[8]>(elf, offset); > + if (!name) > + return {}; > + > + if (sHdr->sh_type == SHT_DYNSYM && !strcmp(name, ".dynsym")) { > + dynsym = sHdr; > + break; > + } > + } > + > + if (dynsym == nullptr) { > + LOG(Utils, Error) << "ELF has no .dynsym section"; > + return {}; > + } > + > + sHdr = elfSection(elf, eHdr, dynsym->sh_link); > + if (!sHdr) > + return {}; > + off_t dynsym_nameoff = sHdr->sh_offset; > + > + /* Locate symbol in the .dynsym section. */ > + const ElfW(Sym) *targetSymbol = nullptr; > + unsigned int dynsym_num = dynsym->sh_size / dynsym->sh_entsize; > + for (unsigned int i = 0; i < dynsym_num; i++) { > + off_t offset = dynsym->sh_offset + dynsym->sh_entsize * i; > + const ElfW(Sym) *sym = elfPointer<const ElfW(Sym)>(elf, offset); > + if (!sym) > + return {}; > + > + offset = dynsym_nameoff + sym->st_name; > + const char *name = elfPointer<const char>(elf, offset, > + strlen(symbol) + 1); > + if (!name) > + return {}; > + > + if (!strcmp(name, symbol) && > + sym->st_info & STB_GLOBAL) { > + targetSymbol = sym; > + break; > + } > + } > + > + if (targetSymbol == nullptr) { > + LOG(Utils, Error) << "Symbol " << symbol << " not found"; > + return {}; > + } > + > + /* Locate and return data of symbol. */ > + sHdr = elfSection(elf, eHdr, targetSymbol->st_shndx); > + if (!sHdr) > + return {}; > + off_t offset = sHdr->sh_offset + (targetSymbol->st_value - sHdr->sh_addr); > + const uint8_t *data = elfPointer<const uint8_t>(elf, offset, > + targetSymbol->st_size); > + if (!data) > + return {}; > + > + return { data, targetSymbol->st_size }; > +} > + > } /* namespace utils */ > > } /* namespace libcamera */ > -- > 2.47.2 >
diff --git a/include/libcamera/internal/utils.h b/include/libcamera/internal/utils.h index 5b7957b5d77e..7d69849b1c19 100644 --- a/include/libcamera/internal/utils.h +++ b/include/libcamera/internal/utils.h @@ -8,9 +8,12 @@ #pragma once #include <functional> +#include <stdint.h> #include <string> #include <vector> +#include <libcamera/base/span.h> + namespace libcamera { namespace utils { @@ -18,6 +21,9 @@ namespace utils { unsigned int findSharedObjects(const char *libDir, unsigned int maxDepth, std::function<int(const std::string &)> func); +int elfVerifyIdent(Span<const uint8_t> elf); +Span<const uint8_t> elfLoadSymbol(Span<const uint8_t> elf, const char *symbol); + } /* namespace utils */ } /* namespace libcamera */ diff --git a/src/libcamera/ipa_module.cpp b/src/libcamera/ipa_module.cpp index e6ea61e44829..c8559ec8b74c 100644 --- a/src/libcamera/ipa_module.cpp +++ b/src/libcamera/ipa_module.cpp @@ -25,6 +25,7 @@ #include <libcamera/base/utils.h> #include "libcamera/internal/pipeline_handler.h" +#include "libcamera/internal/utils.h" /** * \file ipa_module.h @@ -40,153 +41,6 @@ namespace libcamera { LOG_DEFINE_CATEGORY(IPAModule) -namespace { - -template<typename T> -typename std::remove_extent_t<T> *elfPointer(Span<const uint8_t> elf, - off_t offset, size_t objSize) -{ - size_t size = offset + objSize; - if (size > elf.size() || size < objSize) - return nullptr; - - return reinterpret_cast<typename std::remove_extent_t<T> *>( - reinterpret_cast<const char *>(elf.data()) + offset); -} - -template<typename T> -typename std::remove_extent_t<T> *elfPointer(Span<const uint8_t> elf, - off_t offset) -{ - return elfPointer<T>(elf, offset, sizeof(T)); -} - -int elfVerifyIdent(Span<const uint8_t> elf) -{ - const char *e_ident = elfPointer<const char[EI_NIDENT]>(elf, 0); - if (!e_ident) - return -ENOEXEC; - - if (e_ident[EI_MAG0] != ELFMAG0 || - e_ident[EI_MAG1] != ELFMAG1 || - e_ident[EI_MAG2] != ELFMAG2 || - e_ident[EI_MAG3] != ELFMAG3 || - e_ident[EI_VERSION] != EV_CURRENT) - return -ENOEXEC; - - int bitClass = sizeof(unsigned long) == 4 ? ELFCLASS32 : ELFCLASS64; - if (e_ident[EI_CLASS] != bitClass) - return -ENOEXEC; - - int a = 1; - unsigned char endianness = *reinterpret_cast<char *>(&a) == 1 - ? ELFDATA2LSB : ELFDATA2MSB; - if (e_ident[EI_DATA] != endianness) - return -ENOEXEC; - - return 0; -} - -const ElfW(Shdr) *elfSection(Span<const uint8_t> elf, const ElfW(Ehdr) *eHdr, - ElfW(Half) idx) -{ - if (idx >= eHdr->e_shnum) - return nullptr; - - off_t offset = eHdr->e_shoff + idx * - static_cast<uint32_t>(eHdr->e_shentsize); - return elfPointer<const ElfW(Shdr)>(elf, offset); -} - -/** - * \brief Retrieve address and size of a symbol from an mmap'ed ELF file - * \param[in] elf Address and size of mmap'ed ELF file - * \param[in] symbol Symbol name - * - * \return The memory region storing the symbol on success, or an empty span - * otherwise - */ -Span<const uint8_t> elfLoadSymbol(Span<const uint8_t> elf, const char *symbol) -{ - const ElfW(Ehdr) *eHdr = elfPointer<const ElfW(Ehdr)>(elf, 0); - if (!eHdr) - return {}; - - const ElfW(Shdr) *sHdr = elfSection(elf, eHdr, eHdr->e_shstrndx); - if (!sHdr) - return {}; - off_t shnameoff = sHdr->sh_offset; - - /* Locate .dynsym section header. */ - const ElfW(Shdr) *dynsym = nullptr; - for (unsigned int i = 0; i < eHdr->e_shnum; i++) { - sHdr = elfSection(elf, eHdr, i); - if (!sHdr) - return {}; - - off_t offset = shnameoff + sHdr->sh_name; - const char *name = elfPointer<const char[8]>(elf, offset); - if (!name) - return {}; - - if (sHdr->sh_type == SHT_DYNSYM && !strcmp(name, ".dynsym")) { - dynsym = sHdr; - break; - } - } - - if (dynsym == nullptr) { - LOG(IPAModule, Error) << "ELF has no .dynsym section"; - return {}; - } - - sHdr = elfSection(elf, eHdr, dynsym->sh_link); - if (!sHdr) - return {}; - off_t dynsym_nameoff = sHdr->sh_offset; - - /* Locate symbol in the .dynsym section. */ - const ElfW(Sym) *targetSymbol = nullptr; - unsigned int dynsym_num = dynsym->sh_size / dynsym->sh_entsize; - for (unsigned int i = 0; i < dynsym_num; i++) { - off_t offset = dynsym->sh_offset + dynsym->sh_entsize * i; - const ElfW(Sym) *sym = elfPointer<const ElfW(Sym)>(elf, offset); - if (!sym) - return {}; - - offset = dynsym_nameoff + sym->st_name; - const char *name = elfPointer<const char>(elf, offset, - strlen(symbol) + 1); - if (!name) - return {}; - - if (!strcmp(name, symbol) && - sym->st_info & STB_GLOBAL) { - targetSymbol = sym; - break; - } - } - - if (targetSymbol == nullptr) { - LOG(IPAModule, Error) << "Symbol " << symbol << " not found"; - return {}; - } - - /* Locate and return data of symbol. */ - sHdr = elfSection(elf, eHdr, targetSymbol->st_shndx); - if (!sHdr) - return {}; - off_t offset = sHdr->sh_offset + (targetSymbol->st_value - sHdr->sh_addr); - const uint8_t *data = elfPointer<const uint8_t>(elf, offset, - targetSymbol->st_size); - if (!data) - return {}; - - return { data, targetSymbol->st_size }; -} - -} /* namespace */ - /** * \def IPA_MODULE_API_VERSION * \brief The IPA module API version @@ -280,13 +134,13 @@ int IPAModule::loadIPAModuleInfo() } Span<const uint8_t> data = file.map(); - int ret = elfVerifyIdent(data); + int ret = utils::elfVerifyIdent(data); if (ret) { LOG(IPAModule, Error) << "IPA module is not an ELF file"; return ret; } - Span<const uint8_t> info = elfLoadSymbol(data, "ipaModuleInfo"); + Span<const uint8_t> info = utils::elfLoadSymbol(data, "ipaModuleInfo"); if (info.size() < sizeof(info_)) { LOG(IPAModule, Error) << "IPA module has no valid info"; return -EINVAL; diff --git a/src/libcamera/utils.cpp b/src/libcamera/utils.cpp index 2ce62f236cea..6894b489b557 100644 --- a/src/libcamera/utils.cpp +++ b/src/libcamera/utils.cpp @@ -10,20 +10,63 @@ #include <algorithm> #include <dirent.h> #include <functional> +#include <link.h> +#include <stdint.h> #include <string.h> #include <string> #include <sys/types.h> #include <vector> +#include <libcamera/base/log.h> + /** * \file internal/utils.h * \brief Miscellaneous utility functions (internal) */ +/* musl doesn't declare _DYNAMIC in link.h, declare it manually. */ +extern ElfW(Dyn) _DYNAMIC[]; + namespace libcamera { +namespace { + +template<typename T> +typename std::remove_extent_t<T> *elfPointer(Span<const uint8_t> elf, + off_t offset, size_t objSize) +{ + size_t size = offset + objSize; + if (size > elf.size() || size < objSize) + return nullptr; + + return reinterpret_cast<typename std::remove_extent_t<T> *>( + reinterpret_cast<const char *>(elf.data()) + offset); +} + +template<typename T> +typename std::remove_extent_t<T> *elfPointer(Span<const uint8_t> elf, + off_t offset) +{ + return elfPointer<T>(elf, offset, sizeof(T)); +} + +const ElfW(Shdr) *elfSection(Span<const uint8_t> elf, const ElfW(Ehdr) *eHdr, + ElfW(Half) idx) +{ + if (idx >= eHdr->e_shnum) + return nullptr; + + off_t offset = eHdr->e_shoff + idx * + static_cast<uint32_t>(eHdr->e_shentsize); + return elfPointer<const ElfW(Shdr)>(elf, offset); +} + +} /* namespace */ + namespace utils { +LOG_DEFINE_CATEGORY(Utils) + /** * \brief Identify shared library objects within a directory * \param[in] libDir The directory to search for shared objects @@ -102,6 +145,125 @@ unsigned int findSharedObjects(const char *libDir, unsigned int maxDepth, return count; } +/** + * \brief Verify that a binary blob is an ELF + * \param[in] elf The binary blob as a Span + * + * \return 0 for success, and -ENOEXEC otherwise + */ +int elfVerifyIdent(Span<const uint8_t> elf) +{ + const char *e_ident = elfPointer<const char[EI_NIDENT]>(elf, 0); + if (!e_ident) + return -ENOEXEC; + + if (e_ident[EI_MAG0] != ELFMAG0 || + e_ident[EI_MAG1] != ELFMAG1 || + e_ident[EI_MAG2] != ELFMAG2 || + e_ident[EI_MAG3] != ELFMAG3 || + e_ident[EI_VERSION] != EV_CURRENT) + return -ENOEXEC; + + int bitClass = sizeof(unsigned long) == 4 ? ELFCLASS32 : ELFCLASS64; + if (e_ident[EI_CLASS] != bitClass) + return -ENOEXEC; + + int a = 1; + unsigned char endianness = *reinterpret_cast<char *>(&a) == 1 + ? ELFDATA2LSB : ELFDATA2MSB; + if (e_ident[EI_DATA] != endianness) + return -ENOEXEC; + + return 0; +} + +/** + * \brief Retrieve address and size of a symbol from an mmap'ed ELF file + * \param[in] elf Address and size of mmap'ed ELF file + * \param[in] symbol Symbol name + * + * \return The memory region storing the symbol on success, or an empty span + * otherwise + */ +Span<const uint8_t> elfLoadSymbol(Span<const uint8_t> elf, const char *symbol) +{ + const ElfW(Ehdr) *eHdr = elfPointer<const ElfW(Ehdr)>(elf, 0); + if (!eHdr) + return {}; + + const ElfW(Shdr) *sHdr = elfSection(elf, eHdr, eHdr->e_shstrndx); + if (!sHdr) + return {}; + off_t shnameoff = sHdr->sh_offset; + + /* Locate .dynsym section header. */ + const ElfW(Shdr) *dynsym = nullptr; + for (unsigned int i = 0; i < eHdr->e_shnum; i++) { + sHdr = elfSection(elf, eHdr, i); + if (!sHdr) + return {}; + + off_t offset = shnameoff + sHdr->sh_name; + const char *name = elfPointer<const char[8]>(elf, offset); + if (!name) + return {}; + + if (sHdr->sh_type == SHT_DYNSYM && !strcmp(name, ".dynsym")) { + dynsym = sHdr; + break; + } + } + + if (dynsym == nullptr) { + LOG(Utils, Error) << "ELF has no .dynsym section"; + return {}; + } + + sHdr = elfSection(elf, eHdr, dynsym->sh_link); + if (!sHdr) + return {}; + off_t dynsym_nameoff = sHdr->sh_offset; + + /* Locate symbol in the .dynsym section. */ + const ElfW(Sym) *targetSymbol = nullptr; + unsigned int dynsym_num = dynsym->sh_size / dynsym->sh_entsize; + for (unsigned int i = 0; i < dynsym_num; i++) { + off_t offset = dynsym->sh_offset + dynsym->sh_entsize * i; + const ElfW(Sym) *sym = elfPointer<const ElfW(Sym)>(elf, offset); + if (!sym) + return {}; + + offset = dynsym_nameoff + sym->st_name; + const char *name = elfPointer<const char>(elf, offset, + strlen(symbol) + 1); + if (!name) + return {}; + + if (!strcmp(name, symbol) && + sym->st_info & STB_GLOBAL) { + targetSymbol = sym; + break; + } + } + + if (targetSymbol == nullptr) { + LOG(Utils, Error) << "Symbol " << symbol << " not found"; + return {}; + } + + /* Locate and return data of symbol. */ + sHdr = elfSection(elf, eHdr, targetSymbol->st_shndx); + if (!sHdr) + return {}; + off_t offset = sHdr->sh_offset + (targetSymbol->st_value - sHdr->sh_addr); + const uint8_t *data = elfPointer<const uint8_t>(elf, offset, + targetSymbol->st_size); + if (!data) + return {}; + + return { data, targetSymbol->st_size }; +} + } /* namespace utils */ } /* namespace libcamera */