111 lines
2.8 KiB
C++
111 lines
2.8 KiB
C++
/*
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include <folly/experimental/symbolizer/ElfCache.h>
|
|
|
|
#include <signal.h>
|
|
|
|
#include <folly/ScopeGuard.h>
|
|
#include <folly/portability/Config.h>
|
|
#include <folly/portability/SysMman.h>
|
|
|
|
#if FOLLY_HAVE_ELF
|
|
|
|
namespace folly {
|
|
namespace symbolizer {
|
|
|
|
SignalSafeElfCache::Path::Path(
|
|
char const* const data,
|
|
std::size_t const size,
|
|
reentrant_allocator<char> const& alloc) noexcept
|
|
: data_{alloc} {
|
|
data_.reserve(size + 1);
|
|
data_.insert(data_.end(), data, data + size);
|
|
data_.insert(data_.end(), '\0');
|
|
}
|
|
|
|
std::shared_ptr<ElfFile> SignalSafeElfCache::getFile(StringPiece p) {
|
|
struct cmp {
|
|
bool operator()(Entry const& a, StringPiece b) const noexcept {
|
|
return a.path < b;
|
|
}
|
|
bool operator()(StringPiece a, Entry const& b) const noexcept {
|
|
return a < b.path;
|
|
}
|
|
};
|
|
|
|
sigset_t newsigs;
|
|
sigfillset(&newsigs);
|
|
sigset_t oldsigs;
|
|
sigemptyset(&oldsigs);
|
|
sigprocmask(SIG_SETMASK, &newsigs, &oldsigs);
|
|
SCOPE_EXIT { sigprocmask(SIG_SETMASK, &oldsigs, nullptr); };
|
|
|
|
if (!state_) {
|
|
state_.emplace();
|
|
}
|
|
|
|
auto pos = state_->map.find(p, cmp{});
|
|
if (pos == state_->map.end()) {
|
|
state_->list.emplace_front(p, state_->alloc);
|
|
pos = state_->map.insert(state_->list.front()).first;
|
|
}
|
|
|
|
if (!pos->init) {
|
|
int r = pos->file->openAndFollow(pos->path.c_str());
|
|
pos->init = r == ElfFile::kSuccess;
|
|
}
|
|
if (!pos->init) {
|
|
return nullptr;
|
|
}
|
|
|
|
return pos->file;
|
|
}
|
|
|
|
std::shared_ptr<ElfFile> ElfCache::getFile(StringPiece p) {
|
|
std::lock_guard<std::mutex> lock(mutex_);
|
|
|
|
auto pos = files_.find(p);
|
|
if (pos != files_.end()) {
|
|
// Found
|
|
auto& entry = pos->second;
|
|
return filePtr(entry);
|
|
}
|
|
|
|
auto entry = std::make_shared<Entry>();
|
|
entry->path = p.str();
|
|
auto& path = entry->path;
|
|
|
|
// No negative caching
|
|
int r = entry->file.openAndFollow(path.c_str());
|
|
if (r != ElfFile::kSuccess) {
|
|
return nullptr;
|
|
}
|
|
|
|
pos = files_.emplace(path, std::move(entry)).first;
|
|
|
|
return filePtr(pos->second);
|
|
}
|
|
|
|
std::shared_ptr<ElfFile> ElfCache::filePtr(const std::shared_ptr<Entry>& e) {
|
|
// share ownership
|
|
return std::shared_ptr<ElfFile>(e, &e->file);
|
|
}
|
|
} // namespace symbolizer
|
|
} // namespace folly
|
|
|
|
#endif // FOLLY_HAVE_ELF
|