diff options
-rw-r--r-- | src/libcamera/ipa_module.cpp | 68 |
1 files changed, 43 insertions, 25 deletions
diff --git a/src/libcamera/ipa_module.cpp b/src/libcamera/ipa_module.cpp index d201b4f8..d2e3c366 100644 --- a/src/libcamera/ipa_module.cpp +++ b/src/libcamera/ipa_module.cpp @@ -15,6 +15,7 @@ #include <sys/mman.h> #include <sys/stat.h> #include <sys/types.h> +#include <tuple> #include <unistd.h> #include "log.h" @@ -81,18 +82,27 @@ int elfVerifyIdent(void *map, size_t soSize) return 0; } +/** + * \brief Retrieve address and size of a symbol from an mmap'ed ELF file + * \param[in] map Address of mmap'ed ELF file + * \param[in] soSize Size of mmap'ed ELF file (in bytes) + * \param[in] symbol Symbol name + * + * \return zero or error code, address or nullptr, size of symbol or zero, + * respectively + */ template<class ElfHeader, class SecHeader, class SymHeader> -int elfLoadSymbol(void *dst, size_t size, void *map, size_t soSize, - const char *symbol) +std::tuple<void *, size_t> +elfLoadSymbol(void *map, size_t soSize, const char *symbol) { ElfHeader *eHdr = elfPointer<ElfHeader>(map, 0, soSize); if (!eHdr) - return -ENOEXEC; + return std::make_tuple(nullptr, 0); off_t offset = eHdr->e_shoff + eHdr->e_shentsize * eHdr->e_shstrndx; SecHeader *sHdr = elfPointer<SecHeader>(map, offset, soSize); if (!sHdr) - return -ENOEXEC; + return std::make_tuple(nullptr, 0); off_t shnameoff = sHdr->sh_offset; /* Locate .dynsym section header. */ @@ -101,12 +111,12 @@ int elfLoadSymbol(void *dst, size_t size, void *map, size_t soSize, offset = eHdr->e_shoff + eHdr->e_shentsize * i; sHdr = elfPointer<SecHeader>(map, offset, soSize); if (!sHdr) - return -ENOEXEC; + return std::make_tuple(nullptr, 0); offset = shnameoff + sHdr->sh_name; char *name = elfPointer<char[8]>(map, offset, soSize); if (!name) - return -ENOEXEC; + return std::make_tuple(nullptr, 0); if (sHdr->sh_type == SHT_DYNSYM && !strcmp(name, ".dynsym")) { dynsym = sHdr; @@ -116,13 +126,13 @@ int elfLoadSymbol(void *dst, size_t size, void *map, size_t soSize, if (dynsym == nullptr) { LOG(IPAModule, Error) << "ELF has no .dynsym section"; - return -ENOEXEC; + return std::make_tuple(nullptr, 0); } offset = eHdr->e_shoff + eHdr->e_shentsize * dynsym->sh_link; sHdr = elfPointer<SecHeader>(map, offset, soSize); if (!sHdr) - return -ENOEXEC; + return std::make_tuple(nullptr, 0); off_t dynsym_nameoff = sHdr->sh_offset; /* Locate symbol in the .dynsym section. */ @@ -132,16 +142,16 @@ int elfLoadSymbol(void *dst, size_t size, void *map, size_t soSize, offset = dynsym->sh_offset + dynsym->sh_entsize * i; SymHeader *sym = elfPointer<SymHeader>(map, offset, soSize); if (!sym) - return -ENOEXEC; + return std::make_tuple(nullptr, 0); offset = dynsym_nameoff + sym->st_name; char *name = elfPointer<char>(map, offset, soSize, strlen(symbol) + 1); if (!name) - return -ENOEXEC; + return std::make_tuple(nullptr, 0); if (!strcmp(name, symbol) && - sym->st_info & STB_GLOBAL && sym->st_size == size) { + sym->st_info & STB_GLOBAL) { targetSymbol = sym; break; } @@ -149,24 +159,22 @@ int elfLoadSymbol(void *dst, size_t size, void *map, size_t soSize, if (targetSymbol == nullptr) { LOG(IPAModule, Error) << "Symbol " << symbol << " not found"; - return -ENOEXEC; + return std::make_tuple(nullptr, 0); } /* Locate and return data of symbol. */ if (targetSymbol->st_shndx >= eHdr->e_shnum) - return -ENOEXEC; + return std::make_tuple(nullptr, 0); offset = eHdr->e_shoff + targetSymbol->st_shndx * eHdr->e_shentsize; sHdr = elfPointer<SecHeader>(map, offset, soSize); if (!sHdr) - return -ENOEXEC; + return std::make_tuple(nullptr, 0); offset = sHdr->sh_offset + (targetSymbol->st_value - sHdr->sh_addr); - char *data = elfPointer<char>(map, offset, soSize, size); + char *data = elfPointer<char>(map, offset, soSize, targetSymbol->st_size); if (!data) - return -ENOEXEC; - - memcpy(dst, data, size); + return std::make_tuple(nullptr, 0); - return 0; + return std::make_tuple(data, targetSymbol->st_size); } } /* namespace */ @@ -257,8 +265,10 @@ int IPAModule::loadIPAModuleInfo() return ret; } - size_t soSize; + void *data; + size_t dataSize; void *map; + size_t soSize; struct stat st; int ret = fstat(fd, &st); if (ret < 0) @@ -275,11 +285,19 @@ int IPAModule::loadIPAModuleInfo() goto unmap; if (sizeof(unsigned long) == 4) - ret = elfLoadSymbol<Elf32_Ehdr, Elf32_Shdr, Elf32_Sym> - (&info_, sizeof(info_), map, soSize, "ipaModuleInfo"); + std::tie(data, dataSize) = + elfLoadSymbol<Elf32_Ehdr, Elf32_Shdr, Elf32_Sym> + (map, soSize, "ipaModuleInfo"); else - ret = elfLoadSymbol<Elf64_Ehdr, Elf64_Shdr, Elf64_Sym> - (&info_, sizeof(info_), map, soSize, "ipaModuleInfo"); + std::tie(data, dataSize) = + elfLoadSymbol<Elf64_Ehdr, Elf64_Shdr, Elf64_Sym> + (map, soSize, "ipaModuleInfo"); + + if (data && dataSize == sizeof(info_)) + memcpy(&info_, data, dataSize); + + if (!data) + goto unmap; if (info_.moduleAPIVersion != IPA_MODULE_API_VERSION) { LOG(IPAModule, Error) << "IPA module API version mismatch"; @@ -289,7 +307,7 @@ int IPAModule::loadIPAModuleInfo() unmap: munmap(map, soSize); close: - if (ret) + if (ret || !data) LOG(IPAModule, Error) << "Error loading IPA module info for " << libPath_; |