21 #include <sys/types.h> 26 #include <glog/logging.h> 33 #define STT_GNU_IFUNC 10 37 namespace symbolizer {
41 file_(static_cast<
char*>(MAP_FAILED)),
47 file_(static_cast<char*>(MAP_FAILED)),
81 int r = fstat(
fd_, &st);
94 file_ =
static_cast<char*
>(mmap(
nullptr,
length_, prot, MAP_SHARED,
fd_, 0));
95 if (
file_ == MAP_FAILED) {
115 if (!readOnly || result !=
kSuccess) {
126 auto dirend = strrchr(
name,
'/');
128 auto dirlen = dirend !=
nullptr ? dirend + 1 -
name : 0;
138 auto debugFileLen = strlen(debugFileName.begin());
139 if (dirlen + debugFileLen >= PATH_MAX) {
143 char linkname[PATH_MAX];
144 memcpy(linkname,
name, dirlen);
145 memcpy(linkname + dirlen, debugFileName.begin(), debugFileLen + 1);
165 other.filepath_[0] = 0;
167 other.file_ =
static_cast<char*
>(MAP_FAILED);
169 other.baseAddress_ = 0;
173 assert(
this != &other);
183 other.filepath_[0] = 0;
185 other.file_ =
static_cast<char*
>(MAP_FAILED);
187 other.baseAddress_ = 0;
195 if (
file_ != MAP_FAILED) {
197 file_ =
static_cast<char*
>(MAP_FAILED);
209 *msg =
"not an ELF file (too short)";
214 std::array<char, 5> elfMagBuf = {{0, 0, 0, 0, 0}};
215 if (::lseek(
fd_, 0, SEEK_SET) != 0 || ::
read(
fd_, elfMagBuf.data(), 4) != 4) {
217 *msg =
"unable to read ELF file for magic number";
221 if (std::strncmp(elfMagBuf.data(), ELFMAG,
sizeof(ELFMAG)) != 0) {
223 *msg =
"invalid ELF magic";
227 if (::lseek(
fd_, 0, SEEK_SET) != 0) {
229 *msg =
"unable to reset file descriptor after reading ELF magic number";
236 #define EXPECTED_CLASS P1(ELFCLASS, __ELF_NATIVE_CLASS) 237 #define P1(a, b) P2(a, b) 238 #define P2(a, b) a##b 242 *msg =
"invalid ELF class";
248 #undef EXPECTED_CLASS 251 static constexpr
auto kExpectedEncoding =
253 if (
elfHeader.e_ident[EI_DATA] != kExpectedEncoding) {
255 *msg =
"invalid ELF encoding";
261 if (
elfHeader.e_ident[EI_VERSION] != EV_CURRENT ||
264 *msg =
"invalid ELF version";
272 *msg =
"invalid ELF file type";
279 *msg =
"no program header!";
286 *msg =
"invalid program header entry size";
293 *msg =
"invalid section header entry size";
302 if (!programHeader) {
304 *msg =
"could not find base address";
324 stringTable.sh_type == SHT_STRTAB,
"invalid type for string table");
326 const char*
start =
file_ + stringTable.sh_offset;
329 stringTable.sh_size == 0 ||
330 (start[0] ==
'\0' && start[stringTable.sh_size - 1] ==
'\0'),
331 "invalid string table");
338 offset < stringTable.sh_size,
"invalid offset in string table");
340 return file_ + stringTable.sh_offset + offset;
344 if (
elfHeader().e_shstrndx == SHN_UNDEF) {
349 return getString(sectionNames, section.sh_name);
353 if (
elfHeader().e_shstrndx == SHN_UNDEF) {
358 const char*
start =
file_ + sectionNames.sh_offset;
362 if (sh.sh_name >= sectionNames.sh_size) {
365 return !strcmp(start + sh.sh_name, name);
371 Symbol foundSymbol{
nullptr,
nullptr};
373 auto findSection = [&](
const ElfShdr& section) {
374 auto findSymbols = [&](
const ElfSym& sym) {
375 if (sym.st_shndx == SHN_UNDEF) {
378 if (address >= sym.st_value && address < sym.st_value + sym.st_size) {
379 foundSymbol.first = §ion;
380 foundSymbol.second = &sym;
388 section, {STT_OBJECT, STT_FUNC,
STT_GNU_IFUNC}, findSymbols);
399 Symbol foundSymbol{
nullptr,
nullptr};
401 auto findSection = [&](
const ElfShdr& section) ->
bool {
404 if (section.sh_link == SHN_UNDEF) {
408 auto findSymbols = [&](
const ElfSym& sym) ->
bool {
409 if (sym.st_shndx == SHN_UNDEF) {
412 if (sym.st_name == 0) {
415 const char* sym_name =
417 if (strcmp(sym_name, name) == 0) {
418 foundSymbol.first = §ion;
419 foundSymbol.second = &sym;
427 section, {STT_OBJECT, STT_FUNC,
STT_GNU_IFUNC}, findSymbols);
439 return (addr >= sh.sh_addr) && (addr < (sh.sh_addr + sh.sh_size));
444 if (!symbol.first || !symbol.second) {
448 if (symbol.second->st_name == 0) {
452 if (symbol.first->sh_link == SHN_UNDEF) {
char filepath_[kFilepathMaxLen]
Symbol getDefinitionByAddress(uintptr_t address) const
const char * getSymbolName(Symbol symbol) const
const ElfPhdr * iterateProgramHeaders(Fn fn) const
const ElfShdr * getSectionContainingAddress(ElfAddr addr) const
int openAndFollow(const char *name, bool readOnly=true, const char **msg=nullptr) noexcept
const ElfShdr * iterateSectionsWithType(uint32_t type, Fn fn) const
const ElfShdr * getSectionByIndex(size_t idx) const
constexpr auto kIsLittleEndian
folly::StringPiece getSectionBody(const ElfShdr §ion) const
—— Concurrent Priority Queue Implementation ——
requires E e noexcept(noexcept(s.error(std::move(e))))
const ElfShdr * iterateSections(Fn fn) const
const char * getString(const ElfShdr &stringTable, size_t offset) const
const ElfSym * iterateSymbolsWithTypes(const ElfShdr §ion, std::initializer_list< uint32_t > types, Fn fn) const
void validateStringTable(const ElfShdr &stringTable) const
void open(const char *name, bool readOnly=true)
size_t read(T &out, folly::io::Cursor &cursor)
int openNoThrow(const char *name, bool readOnly=true, const char **msg=nullptr) noexcept
GuardImpl guard(ErrorHandler &&handler)
const ElfEhdr & elfHeader() const
const ElfShdr * getSectionByName(const char *name) const
Symbol getSymbolByName(const char *name) const
static constexpr size_t kFilepathMaxLen
ElfFile & operator=(ElfFile &&other)
#define FOLLY_SAFE_CHECK(expr, msg)
bool init(const char **msg)
FOLLY_NODISCARD detail::ScopeGuardImplDecay< F, true > makeGuard(F &&f) noexcept(noexcept(detail::ScopeGuardImplDecay< F, true >(static_cast< F && >(f))))
void throwSystemError(Args &&...args)
Range< const char * > StringPiece
int close(NetworkSocket s)
ThreadPoolListHook * addr
std::pair< const ElfShdr *, const ElfSym * > Symbol
const char * getSectionName(const ElfShdr §ion) const