/*
- * Copyright 2017-present Facebook, Inc.
+ * Copyright 2012-present Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include <sys/stat.h>
#include <sys/types.h>
+#include <cstring>
#include <string>
#include <glog/logging.h>
#include <folly/Exception.h>
#include <folly/ScopeGuard.h>
+#ifndef STT_GNU_IFUNC
+#define STT_GNU_IFUNC 10
+#endif
+
namespace folly {
namespace symbolizer {
bool readOnly,
const char** msg) noexcept {
FOLLY_SAFE_CHECK(fd_ == -1, "File already open");
+ strncat(filepath_, name, kFilepathMaxLen - 1);
fd_ = ::open(name, readOnly ? O_RDONLY : O_RDWR);
if (fd_ == -1) {
if (msg) {
// Always close fd and unmap in case of failure along the way to avoid
// check failure above if we leave fd != -1 and the object is recycled
// like it is inside SignalSafeElfCache
- ScopeGuard guard = makeGuard([&] { reset(); });
+ auto guard = makeGuard([&] { reset(); });
struct stat st;
int r = fstat(fd_, &st);
if (r == -1) {
file_(other.file_),
length_(other.length_),
baseAddress_(other.baseAddress_) {
+ // copy other.filepath_, leaving filepath_ zero-terminated, always.
+ strncat(filepath_, other.filepath_, kFilepathMaxLen - 1);
+ other.filepath_[0] = 0;
other.fd_ = -1;
other.file_ = static_cast<char*>(MAP_FAILED);
other.length_ = 0;
assert(this != &other);
reset();
+ // copy other.filepath_, leaving filepath_ zero-terminated, always.
+ strncat(filepath_, other.filepath_, kFilepathMaxLen - 1);
fd_ = other.fd_;
file_ = other.file_;
length_ = other.length_;
baseAddress_ = other.baseAddress_;
+ other.filepath_[0] = 0;
other.fd_ = -1;
other.file_ = static_cast<char*>(MAP_FAILED);
other.length_ = 0;
}
void ElfFile::reset() {
+ filepath_[0] = 0;
+
if (file_ != MAP_FAILED) {
munmap(file_, length_);
file_ = static_cast<char*>(MAP_FAILED);
}
bool ElfFile::init(const char** msg) {
- auto& elfHeader = this->elfHeader();
+ if (length_ < 4) {
+ if (msg) {
+ *msg = "not an ELF file (too short)";
+ }
+ return false;
+ }
// Validate ELF magic numbers
- if (!(elfHeader.e_ident[EI_MAG0] == ELFMAG0 &&
- elfHeader.e_ident[EI_MAG1] == ELFMAG1 &&
- elfHeader.e_ident[EI_MAG2] == ELFMAG2 &&
- elfHeader.e_ident[EI_MAG3] == ELFMAG3)) {
+ if (file_[EI_MAG0] != ELFMAG0 || file_[EI_MAG1] != ELFMAG1 ||
+ file_[EI_MAG2] != ELFMAG2 || file_[EI_MAG3] != ELFMAG3) {
if (msg) {
*msg = "invalid ELF magic";
}
return false;
}
+ auto& elfHeader = this->elfHeader();
+
#define EXPECTED_CLASS P1(ELFCLASS, __ELF_NATIVE_CLASS)
#define P1(a, b) P2(a, b)
#define P2(a, b) a##b
}
}
- const ElfPhdr* programHeader = &at<ElfPhdr>(elfHeader.e_phoff);
- bool foundBase = false;
- for (size_t i = 0; i < elfHeader.e_phnum; programHeader++, i++) {
- // Program headers are sorted by load address, so the first PT_LOAD
- // header gives us the base address.
- if (programHeader->p_type == PT_LOAD) {
- baseAddress_ = programHeader->p_vaddr;
- foundBase = true;
- break;
- }
- }
+ // Program headers are sorted by load address, so the first PT_LOAD
+ // header gives us the base address.
+ const ElfPhdr* programHeader =
+ iterateProgramHeaders([](auto& h) { return h.p_type == PT_LOAD; });
- if (!foundBase) {
+ if (!programHeader) {
if (msg) {
*msg = "could not find base address";
}
return false;
}
+ baseAddress_ = programHeader->p_vaddr;
return true;
}
return false;
};
- return iterateSymbolsWithType(section, STT_OBJECT, findSymbols) ||
- iterateSymbolsWithType(section, STT_FUNC, findSymbols);
+ return iterateSymbolsWithTypes(
+ section, {STT_OBJECT, STT_FUNC, STT_GNU_IFUNC}, findSymbols);
};
// Try the .dynsym section first if it exists, it's smaller.
return false;
};
- return iterateSymbolsWithType(section, STT_OBJECT, findSymbols) ||
- iterateSymbolsWithType(section, STT_FUNC, findSymbols);
+ return iterateSymbolsWithTypes(
+ section, {STT_OBJECT, STT_FUNC, STT_GNU_IFUNC}, findSymbols);
};
// Try the .dynsym section first if it exists, it's smaller.