summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/libcamera/ipa_module.cpp68
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_;