Commit 4462a7f0 authored by Yedidya Feldblum's avatar Yedidya Feldblum Committed by Facebook Github Bot

Let ElfFile open functions take Options

Summary:
[Folly] Let `ElfFile` open functions take a single builder-style composite `Options` argument v.s. taking a sequence of individual arguments one for each option.

Right now there is only one option but it is possible to add more in the future.

While here, rename and invert `readOnly` to `writable`.

Reviewed By: vitaut

Differential Revision: D18740699

fbshipit-source-id: 6fb016f731bf46a1b4ac6b2efcea739f6261818a
parent 8871fd42
......@@ -43,16 +43,16 @@ ElfFile::ElfFile() noexcept
length_(0),
baseAddress_(0) {}
ElfFile::ElfFile(const char* name, bool readOnly)
ElfFile::ElfFile(const char* name, Options const& options)
: fd_(-1),
file_(static_cast<char*>(MAP_FAILED)),
length_(0),
baseAddress_(0) {
open(name, readOnly);
open(name, options);
}
void ElfFile::open(const char* name, bool readOnly) {
auto r = openNoThrow(name, readOnly);
void ElfFile::open(const char* name, Options const& options) {
auto r = openNoThrow(name, options);
if (r == kSystemError) {
throwSystemError(r.msg);
} else {
......@@ -62,14 +62,14 @@ void ElfFile::open(const char* name, bool readOnly) {
ElfFile::OpenResult ElfFile::openNoThrow(
const char* name,
bool readOnly) noexcept {
Options const& options) noexcept {
FOLLY_SAFE_CHECK(fd_ == -1, "File already open");
// 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
auto guard = makeGuard([&] { reset(); });
strncat(filepath_, name, kFilepathMaxLen - 1);
fd_ = ::open(name, readOnly ? O_RDONLY : O_RDWR);
fd_ = ::open(name, options.writable() ? O_RDWR : O_RDONLY);
if (fd_ == -1) {
return {kSystemError, "open"};
}
......@@ -81,7 +81,7 @@ ElfFile::OpenResult ElfFile::openNoThrow(
length_ = st.st_size;
int prot = PROT_READ;
if (!readOnly) {
if (options.writable()) {
prot |= PROT_WRITE;
}
file_ = static_cast<char*>(mmap(nullptr, length_, prot, MAP_SHARED, fd_, 0));
......@@ -100,9 +100,9 @@ ElfFile::OpenResult ElfFile::openNoThrow(
ElfFile::OpenResult ElfFile::openAndFollow(
const char* name,
bool readOnly) noexcept {
auto result = openNoThrow(name, readOnly);
if (!readOnly || result != kSuccess) {
Options const& options) noexcept {
auto result = openNoThrow(name, options);
if (options.writable() || result != kSuccess) {
return result;
}
......@@ -134,11 +134,11 @@ ElfFile::OpenResult ElfFile::openAndFollow(
memcpy(linkname, name, dirlen);
memcpy(linkname + dirlen, debugFileName.begin(), debugFileLen + 1);
reset();
result = openNoThrow(linkname, readOnly);
result = openNoThrow(linkname, options);
if (result == kSuccess) {
return result;
}
return openNoThrow(name, readOnly);
return openNoThrow(name, options);
}
ElfFile::~ElfFile() {
......
......@@ -51,10 +51,27 @@ using ElfSym = ElfW(Sym);
*/
class ElfFile {
public:
class Options {
public:
constexpr Options() noexcept {}
constexpr bool writable() const noexcept {
return writable_;
}
constexpr Options& writable(bool const value) noexcept {
writable_ = value;
return *this;
}
private:
bool writable_ = false;
};
ElfFile() noexcept;
// Note: may throw, call openNoThrow() explicitly if you don't want to throw
explicit ElfFile(const char* name, bool readOnly = true);
explicit ElfFile(const char* name, Options const& options = Options());
// Open the ELF file.
// Returns 0 on success, kSystemError (guaranteed to be -1) (and sets errno)
......@@ -75,13 +92,17 @@ class ElfFile {
}
};
// Open the ELF file. Does not throw on error.
OpenResult openNoThrow(const char* name, bool readOnly = true) noexcept;
OpenResult openNoThrow(
const char* name,
Options const& options = Options()) noexcept;
// Like openNoThrow, but follow .gnu_debuglink if present
OpenResult openAndFollow(const char* name, bool readOnly = true) noexcept;
OpenResult openAndFollow(
const char* name,
Options const& options = Options()) noexcept;
// Open the ELF file. Throws on error.
void open(const char* name, bool readOnly = true);
void open(const char* name, Options const& options = Options());
~ElfFile();
......
......@@ -79,7 +79,7 @@ std::shared_ptr<ElfFile> SignalSafeElfCache::getFile(StringPiece p) {
auto& f = slots_[n];
int r = f->openAndFollow(scratchpad_.data(), true);
int r = f->openAndFollow(scratchpad_.data());
if (r != ElfFile::kSuccess) {
return nullptr;
}
......@@ -107,7 +107,7 @@ std::shared_ptr<ElfFile> ElfCache::getFile(StringPiece p) {
auto& path = entry->path;
// No negative caching
int r = entry->file.openAndFollow(path.c_str(), true);
int r = entry->file.openAndFollow(path.c_str());
if (r != ElfFile::kSuccess) {
return nullptr;
}
......
......@@ -58,7 +58,7 @@ TEST_F(ElfTest, TinyNonElfFile) {
folly::writeFull(tmpFile.fd(), contents.data(), contents.size());
ElfFile elfFile;
auto res = elfFile.openNoThrow(tmpFile.path().c_str(), true);
auto res = elfFile.openNoThrow(tmpFile.path().c_str());
EXPECT_EQ(ElfFile::kInvalidElfFile, res.code);
EXPECT_STREQ("not an ELF file (too short)", res.msg);
}
......@@ -70,7 +70,7 @@ TEST_F(ElfTest, NonElfScript) {
folly::writeFull(tmpFile.fd(), contents.data(), contents.size());
ElfFile elfFile;
auto res = elfFile.openNoThrow(tmpFile.path().c_str(), true);
auto res = elfFile.openNoThrow(tmpFile.path().c_str());
EXPECT_EQ(ElfFile::kInvalidElfFile, res.code);
EXPECT_STREQ("invalid ELF magic", res.msg);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment