summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Elder <paul.elder@ideasonboard.com>2019-06-06 15:01:20 -0400
committerPaul Elder <paul.elder@ideasonboard.com>2019-07-04 11:51:29 +0900
commit851bf31df898b1569571244ce2094b59a9efcb7f (patch)
tree7cff8527876e64907dbb05f0acd563652abf4c02
parentd68a29771f47bccd45fae72eef86ee6586deaf63 (diff)
libcamera: ipa_module: elfLoadSymbol find symbol regardless of size
Make elfLoadSymbol more generic by making the symbol size an output rather than an input. Also move the memcpy out of elfLoadSymbol. If the size of struct IPAModuleInfo changes between versions, we still want to be able to load it and perhaps do conversions for backwards compatibility. In this case the size should not be a restriction when searching for the symbol. Signed-off-by: Paul Elder <paul.elder@ideasonboard.com> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
-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_;