@@ -8,9 +8,12 @@
#pragma once
#include <functional>
+#include <stdint.h>
#include <string>
#include <vector>
+#include <libcamera/base/span.h>
+
namespace libcamera {
namespace utils {
@@ -21,6 +24,9 @@ void parseDir(const char *libDir, unsigned int maxDepth,
unsigned int addDir(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 */
@@ -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;
@@ -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,120 @@ unsigned int addDir(const char *libDir, unsigned int maxDepth,
return count;
}
+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 */
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> --- include/libcamera/internal/utils.h | 6 ++ src/libcamera/ipa_module.cpp | 152 +--------------------------- src/libcamera/utils.cpp | 157 +++++++++++++++++++++++++++++ 3 files changed, 166 insertions(+), 149 deletions(-)