@@ -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 */
@@ -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,126 @@ 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 */