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 ...@@ -43,16 +43,16 @@ ElfFile::ElfFile() noexcept
length_(0), length_(0),
baseAddress_(0) {} baseAddress_(0) {}
ElfFile::ElfFile(const char* name, bool readOnly) ElfFile::ElfFile(const char* name, Options const& options)
: fd_(-1), : fd_(-1),
file_(static_cast<char*>(MAP_FAILED)), file_(static_cast<char*>(MAP_FAILED)),
length_(0), length_(0),
baseAddress_(0) { baseAddress_(0) {
open(name, readOnly); open(name, options);
} }
void ElfFile::open(const char* name, bool readOnly) { void ElfFile::open(const char* name, Options const& options) {
auto r = openNoThrow(name, readOnly); auto r = openNoThrow(name, options);
if (r == kSystemError) { if (r == kSystemError) {
throwSystemError(r.msg); throwSystemError(r.msg);
} else { } else {
...@@ -62,14 +62,14 @@ void ElfFile::open(const char* name, bool readOnly) { ...@@ -62,14 +62,14 @@ void ElfFile::open(const char* name, bool readOnly) {
ElfFile::OpenResult ElfFile::openNoThrow( ElfFile::OpenResult ElfFile::openNoThrow(
const char* name, const char* name,
bool readOnly) noexcept { Options const& options) noexcept {
FOLLY_SAFE_CHECK(fd_ == -1, "File already open"); FOLLY_SAFE_CHECK(fd_ == -1, "File already open");
// Always close fd and unmap in case of failure along the way to avoid // 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 // check failure above if we leave fd != -1 and the object is recycled
// like it is inside SignalSafeElfCache // like it is inside SignalSafeElfCache
auto guard = makeGuard([&] { reset(); }); auto guard = makeGuard([&] { reset(); });
strncat(filepath_, name, kFilepathMaxLen - 1); 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) { if (fd_ == -1) {
return {kSystemError, "open"}; return {kSystemError, "open"};
} }
...@@ -81,7 +81,7 @@ ElfFile::OpenResult ElfFile::openNoThrow( ...@@ -81,7 +81,7 @@ ElfFile::OpenResult ElfFile::openNoThrow(
length_ = st.st_size; length_ = st.st_size;
int prot = PROT_READ; int prot = PROT_READ;
if (!readOnly) { if (options.writable()) {
prot |= PROT_WRITE; prot |= PROT_WRITE;
} }
file_ = static_cast<char*>(mmap(nullptr, length_, prot, MAP_SHARED, fd_, 0)); file_ = static_cast<char*>(mmap(nullptr, length_, prot, MAP_SHARED, fd_, 0));
...@@ -100,9 +100,9 @@ ElfFile::OpenResult ElfFile::openNoThrow( ...@@ -100,9 +100,9 @@ ElfFile::OpenResult ElfFile::openNoThrow(
ElfFile::OpenResult ElfFile::openAndFollow( ElfFile::OpenResult ElfFile::openAndFollow(
const char* name, const char* name,
bool readOnly) noexcept { Options const& options) noexcept {
auto result = openNoThrow(name, readOnly); auto result = openNoThrow(name, options);
if (!readOnly || result != kSuccess) { if (options.writable() || result != kSuccess) {
return result; return result;
} }
...@@ -134,11 +134,11 @@ ElfFile::OpenResult ElfFile::openAndFollow( ...@@ -134,11 +134,11 @@ ElfFile::OpenResult ElfFile::openAndFollow(
memcpy(linkname, name, dirlen); memcpy(linkname, name, dirlen);
memcpy(linkname + dirlen, debugFileName.begin(), debugFileLen + 1); memcpy(linkname + dirlen, debugFileName.begin(), debugFileLen + 1);
reset(); reset();
result = openNoThrow(linkname, readOnly); result = openNoThrow(linkname, options);
if (result == kSuccess) { if (result == kSuccess) {
return result; return result;
} }
return openNoThrow(name, readOnly); return openNoThrow(name, options);
} }
ElfFile::~ElfFile() { ElfFile::~ElfFile() {
......
...@@ -51,10 +51,27 @@ using ElfSym = ElfW(Sym); ...@@ -51,10 +51,27 @@ using ElfSym = ElfW(Sym);
*/ */
class ElfFile { class ElfFile {
public: 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; ElfFile() noexcept;
// Note: may throw, call openNoThrow() explicitly if you don't want to throw // 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. // Open the ELF file.
// Returns 0 on success, kSystemError (guaranteed to be -1) (and sets errno) // Returns 0 on success, kSystemError (guaranteed to be -1) (and sets errno)
...@@ -75,13 +92,17 @@ class ElfFile { ...@@ -75,13 +92,17 @@ class ElfFile {
} }
}; };
// Open the ELF file. Does not throw on error. // 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 // 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. // 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(); ~ElfFile();
......
...@@ -79,7 +79,7 @@ std::shared_ptr<ElfFile> SignalSafeElfCache::getFile(StringPiece p) { ...@@ -79,7 +79,7 @@ std::shared_ptr<ElfFile> SignalSafeElfCache::getFile(StringPiece p) {
auto& f = slots_[n]; auto& f = slots_[n];
int r = f->openAndFollow(scratchpad_.data(), true); int r = f->openAndFollow(scratchpad_.data());
if (r != ElfFile::kSuccess) { if (r != ElfFile::kSuccess) {
return nullptr; return nullptr;
} }
...@@ -107,7 +107,7 @@ std::shared_ptr<ElfFile> ElfCache::getFile(StringPiece p) { ...@@ -107,7 +107,7 @@ std::shared_ptr<ElfFile> ElfCache::getFile(StringPiece p) {
auto& path = entry->path; auto& path = entry->path;
// No negative caching // No negative caching
int r = entry->file.openAndFollow(path.c_str(), true); int r = entry->file.openAndFollow(path.c_str());
if (r != ElfFile::kSuccess) { if (r != ElfFile::kSuccess) {
return nullptr; return nullptr;
} }
......
...@@ -58,7 +58,7 @@ TEST_F(ElfTest, TinyNonElfFile) { ...@@ -58,7 +58,7 @@ TEST_F(ElfTest, TinyNonElfFile) {
folly::writeFull(tmpFile.fd(), contents.data(), contents.size()); folly::writeFull(tmpFile.fd(), contents.data(), contents.size());
ElfFile elfFile; 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_EQ(ElfFile::kInvalidElfFile, res.code);
EXPECT_STREQ("not an ELF file (too short)", res.msg); EXPECT_STREQ("not an ELF file (too short)", res.msg);
} }
...@@ -70,7 +70,7 @@ TEST_F(ElfTest, NonElfScript) { ...@@ -70,7 +70,7 @@ TEST_F(ElfTest, NonElfScript) {
folly::writeFull(tmpFile.fd(), contents.data(), contents.size()); folly::writeFull(tmpFile.fd(), contents.data(), contents.size());
ElfFile elfFile; 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_EQ(ElfFile::kInvalidElfFile, res.code);
EXPECT_STREQ("invalid ELF magic", res.msg); 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