proxygen
folly::symbolizer::ElfFile Class Reference

#include <Elf.h>

Public Types

enum  { kSuccess = 0, kSystemError = -1, kInvalidElfFile = -2 }
 
typedef std::pair< const ElfShdr *, const ElfSym * > Symbol
 

Public Member Functions

 ElfFile () noexcept
 
 ElfFile (const char *name, bool readOnly=true)
 
int openNoThrow (const char *name, bool readOnly=true, const char **msg=nullptr) noexcept
 
int openAndFollow (const char *name, bool readOnly=true, const char **msg=nullptr) noexcept
 
void open (const char *name, bool readOnly=true)
 
 ~ElfFile ()
 
 ElfFile (ElfFile &&other) noexcept
 
ElfFileoperator= (ElfFile &&other)
 
const ElfEhdrelfHeader () const
 
uintptr_t getBaseAddress () const
 
const ElfShdrgetSectionByName (const char *name) const
 
const ElfShdrgetSectionByIndex (size_t idx) const
 
const char * getSectionName (const ElfShdr &section) const
 
folly::StringPiece getSectionBody (const ElfShdr &section) const
 
const char * getString (const ElfShdr &stringTable, size_t offset) const
 
template<class Fn >
const char * iterateStrings (const ElfShdr &stringTable, Fn fn) const
 
template<class Fn >
const ElfPhdriterateProgramHeaders (Fn fn) const
 
template<class Fn >
const ElfShdriterateSections (Fn fn) const
 
template<class Fn >
const ElfShdriterateSectionsWithType (uint32_t type, Fn fn) const
 
template<class Fn >
const ElfShdriterateSectionsWithTypes (std::initializer_list< uint32_t > types, Fn fn) const
 
template<class Fn >
const ElfSymiterateSymbols (const ElfShdr &section, Fn fn) const
 
template<class Fn >
const ElfSymiterateSymbolsWithType (const ElfShdr &section, uint32_t type, Fn fn) const
 
template<class Fn >
const ElfSymiterateSymbolsWithTypes (const ElfShdr &section, std::initializer_list< uint32_t > types, Fn fn) const
 
Symbol getDefinitionByAddress (uintptr_t address) const
 
Symbol getSymbolByName (const char *name) const
 
template<class T >
const TgetSymbolValue (const ElfSym *symbol) const
 
template<class T >
const TgetAddressValue (const ElfAddr addr) const
 
const char * getSymbolName (Symbol symbol) const
 
const ElfShdrgetSectionContainingAddress (ElfAddr addr) const
 

Private Member Functions

bool init (const char **msg)
 
void reset ()
 
 ElfFile (const ElfFile &)=delete
 
ElfFileoperator= (const ElfFile &)=delete
 
void validateStringTable (const ElfShdr &stringTable) const
 
template<class T >
const std::enable_if< std::is_pod< T >::value, T >::typeat (ElfOff offset) const
 
template<class T >
const TvalueAt (const ElfShdr &section, const ElfAddr addr) const
 

Private Attributes

char filepath_ [kFilepathMaxLen] = {}
 
int fd_
 
char * file_
 
size_t length_
 
uintptr_t baseAddress_
 

Static Private Attributes

static constexpr size_t kFilepathMaxLen = 512
 

Detailed Description

ELF file parser.

We handle native files only (32-bit files on a 32-bit platform, 64-bit files on a 64-bit platform), and only executables (ET_EXEC) and shared objects (ET_DYN).

Definition at line 52 of file Elf.h.

Member Typedef Documentation

typedef std::pair<const ElfShdr*, const ElfSym*> folly::symbolizer::ElfFile::Symbol

Find symbol definition by address. Note that this is the file virtual address, so you need to undo any relocation that might have happened.

Returns {nullptr, nullptr} if not found.

Definition at line 182 of file Elf.h.

Member Enumeration Documentation

anonymous enum
Enumerator
kSuccess 
kSystemError 
kInvalidElfFile 

Definition at line 64 of file Elf.h.

Constructor & Destructor Documentation

folly::symbolizer::ElfFile::ElfFile ( )
noexcept

Definition at line 39 of file Elf.cpp.

Referenced by getAddressValue().

40  : fd_(-1),
41  file_(static_cast<char*>(MAP_FAILED)),
42  length_(0),
43  baseAddress_(0) {}
uintptr_t baseAddress_
Definition: Elf.h:289
folly::symbolizer::ElfFile::ElfFile ( const char *  name,
bool  readOnly = true 
)
explicit

Definition at line 45 of file Elf.cpp.

References open().

46  : fd_(-1),
47  file_(static_cast<char*>(MAP_FAILED)),
48  length_(0),
49  baseAddress_(0) {
50  open(name, readOnly);
51 }
uintptr_t baseAddress_
Definition: Elf.h:289
const char * name
Definition: http_parser.c:437
void open(const char *name, bool readOnly=true)
Definition: Elf.cpp:53
folly::symbolizer::ElfFile::~ElfFile ( )

Definition at line 154 of file Elf.cpp.

References reset().

154  {
155  reset();
156 }
folly::symbolizer::ElfFile::ElfFile ( ElfFile &&  other)
noexcept

Definition at line 158 of file Elf.cpp.

References filepath_, and kFilepathMaxLen.

159  : fd_(other.fd_),
160  file_(other.file_),
161  length_(other.length_),
162  baseAddress_(other.baseAddress_) {
163  // copy other.filepath_, leaving filepath_ zero-terminated, always.
164  strncat(filepath_, other.filepath_, kFilepathMaxLen - 1);
165  other.filepath_[0] = 0;
166  other.fd_ = -1;
167  other.file_ = static_cast<char*>(MAP_FAILED);
168  other.length_ = 0;
169  other.baseAddress_ = 0;
170 }
char filepath_[kFilepathMaxLen]
Definition: Elf.h:284
uintptr_t baseAddress_
Definition: Elf.h:289
static constexpr size_t kFilepathMaxLen
Definition: Elf.h:283
folly::symbolizer::ElfFile::ElfFile ( const ElfFile )
privatedelete

Member Function Documentation

template<class T >
const std::enable_if<std::is_pod<T>::value, T>::type& folly::symbolizer::ElfFile::at ( ElfOff  offset) const
inlineprivate

Definition at line 242 of file Elf.h.

References file_, filepath_, FOLLY_SAFE_CHECK, kFilepathMaxLen, length_, and folly::T.

243  {
244  if (offset + sizeof(T) > length_) {
245  char msg[kFilepathMaxLen + 128];
246  snprintf(
247  msg,
248  sizeof(msg),
249  "Offset (%zu + %zu) is not contained within our mmapped"
250  " file (%s) of length %zu",
251  offset,
252  sizeof(T),
253  filepath_,
254  length_);
255  FOLLY_SAFE_CHECK(offset + sizeof(T) <= length_, msg);
256  }
257 
258  return *reinterpret_cast<T*>(file_ + offset);
259  }
char filepath_[kFilepathMaxLen]
Definition: Elf.h:284
folly::std T
static constexpr size_t kFilepathMaxLen
Definition: Elf.h:283
#define FOLLY_SAFE_CHECK(expr, msg)
Definition: SafeAssert.h:35
const ElfEhdr& folly::symbolizer::ElfFile::elfHeader ( ) const
inline

Retrieve the ELF header

Definition at line 90 of file Elf.h.

Referenced by getSectionByIndex(), getSectionByName(), getSectionName(), init(), iterateProgramHeaders(), iterateSections(), and valueAt().

90  {
91  return at<ElfEhdr>(0);
92  }
template<class T >
const T& folly::symbolizer::ElfFile::getAddressValue ( const ElfAddr  addr) const
inline

Get the value of the object stored at the given address.

This is the function that you want to use in conjunction with getSymbolValue() to follow pointers. For example, to get the value of a char* symbol, you'd do something like this:

auto sym = getSymbolByName("someGlobalValue"); auto addr = getSymbolValue<ElfAddr>(sym.second); const char* str = &getSymbolValue<const char>(addr);

Definition at line 218 of file Elf.h.

References addr, ElfFile(), FOLLY_SAFE_CHECK, getSectionContainingAddress(), getSymbolName(), init(), operator=(), reset(), and validateStringTable().

Referenced by TEST_F().

218  {
219  const ElfShdr* section = getSectionContainingAddress(addr);
220  FOLLY_SAFE_CHECK(section, "Address does not refer to existing section");
221 
222  return valueAt<T>(*section, addr);
223  }
const ElfShdr * getSectionContainingAddress(ElfAddr addr) const
Definition: Elf.cpp:437
#define FOLLY_SAFE_CHECK(expr, msg)
Definition: SafeAssert.h:35
ThreadPoolListHook * addr
ElfW(Shdr) ElfShdr
Definition: Elf.h:42
uintptr_t folly::symbolizer::ElfFile::getBaseAddress ( ) const
inline

Get the base address, the address where the file should be loaded if no relocations happened.

Definition at line 98 of file Elf.h.

References baseAddress_, getSectionBody(), getSectionByIndex(), getSectionByName(), getSectionName(), getString(), iterateProgramHeaders(), iterateSections(), iterateSectionsWithType(), iterateSectionsWithTypes(), iterateStrings(), iterateSymbols(), iterateSymbolsWithType(), iterateSymbolsWithTypes(), type, and uint32_t.

98  {
99  return baseAddress_;
100  }
uintptr_t baseAddress_
Definition: Elf.h:289
ElfFile::Symbol folly::symbolizer::ElfFile::getDefinitionByAddress ( uintptr_t  address) const

Definition at line 370 of file Elf.cpp.

References iterateSectionsWithType(), iterateSymbolsWithTypes(), and STT_GNU_IFUNC.

370  {
371  Symbol foundSymbol{nullptr, nullptr};
372 
373  auto findSection = [&](const ElfShdr& section) {
374  auto findSymbols = [&](const ElfSym& sym) {
375  if (sym.st_shndx == SHN_UNDEF) {
376  return false; // not a definition
377  }
378  if (address >= sym.st_value && address < sym.st_value + sym.st_size) {
379  foundSymbol.first = &section;
380  foundSymbol.second = &sym;
381  return true;
382  }
383 
384  return false;
385  };
386 
388  section, {STT_OBJECT, STT_FUNC, STT_GNU_IFUNC}, findSymbols);
389  };
390 
391  // Try the .dynsym section first if it exists, it's smaller.
392  (iterateSectionsWithType(SHT_DYNSYM, findSection) ||
393  iterateSectionsWithType(SHT_SYMTAB, findSection));
394 
395  return foundSymbol;
396 }
const ElfShdr * iterateSectionsWithType(uint32_t type, Fn fn) const
Definition: Elf-inl.h:61
const ElfSym * iterateSymbolsWithTypes(const ElfShdr &section, std::initializer_list< uint32_t > types, Fn fn) const
Definition: Elf-inl.h:123
#define STT_GNU_IFUNC
Definition: Elf.cpp:33
ElfW(Sym) ElfSym
Definition: Elf.h:43
std::pair< const ElfShdr *, const ElfSym * > Symbol
Definition: Elf.h:182
ElfW(Shdr) ElfShdr
Definition: Elf.h:42
folly::StringPiece folly::symbolizer::ElfFile::getSectionBody ( const ElfShdr section) const

Get the actual section body

Definition at line 318 of file Elf.cpp.

References file_.

Referenced by getBaseAddress(), folly::symbolizer::Dwarf::getSection(), and openAndFollow().

318  {
319  return folly::StringPiece(file_ + section.sh_offset, section.sh_size);
320 }
Range< const char * > StringPiece
const ElfShdr * folly::symbolizer::ElfFile::getSectionByIndex ( size_t  idx) const

Find a section given its index in the section header table

Definition at line 313 of file Elf.cpp.

References elfHeader(), and FOLLY_SAFE_CHECK.

Referenced by getBaseAddress(), getSectionByName(), getSectionName(), getSymbolByName(), getSymbolName(), and getSymbolValue().

313  {
314  FOLLY_SAFE_CHECK(idx < elfHeader().e_shnum, "invalid section index");
315  return &at<ElfShdr>(elfHeader().e_shoff + idx * sizeof(ElfShdr));
316 }
const ElfEhdr & elfHeader() const
Definition: Elf.h:90
#define FOLLY_SAFE_CHECK(expr, msg)
Definition: SafeAssert.h:35
ElfW(Shdr) ElfShdr
Definition: Elf.h:42
const ElfShdr * folly::symbolizer::ElfFile::getSectionByName ( const char *  name) const

Find a section given its name

Definition at line 352 of file Elf.cpp.

References elfHeader(), file_, getSectionByIndex(), iterateSections(), and start.

Referenced by getBaseAddress(), folly::symbolizer::Dwarf::getSection(), and openAndFollow().

352  {
353  if (elfHeader().e_shstrndx == SHN_UNDEF) {
354  return nullptr; // no section name string table
355  }
356 
357  const ElfShdr& sectionNames = *getSectionByIndex(elfHeader().e_shstrndx);
358  const char* start = file_ + sectionNames.sh_offset;
359 
360  // Find section with the appropriate sh_name offset
361  const ElfShdr* foundSection = iterateSections([&](const ElfShdr& sh) {
362  if (sh.sh_name >= sectionNames.sh_size) {
363  return false;
364  }
365  return !strcmp(start + sh.sh_name, name);
366  });
367  return foundSection;
368 }
const ElfShdr * getSectionByIndex(size_t idx) const
Definition: Elf.cpp:313
const ElfShdr * iterateSections(Fn fn) const
Definition: Elf-inl.h:43
const char * name
Definition: http_parser.c:437
const ElfEhdr & elfHeader() const
Definition: Elf.h:90
auto start
ElfW(Shdr) ElfShdr
Definition: Elf.h:42
const ElfShdr * folly::symbolizer::ElfFile::getSectionContainingAddress ( ElfAddr  addr) const

Find the section containing the given address

Definition at line 437 of file Elf.cpp.

References iterateSections().

Referenced by getAddressValue().

437  {
438  return iterateSections([&](const ElfShdr& sh) -> bool {
439  return (addr >= sh.sh_addr) && (addr < (sh.sh_addr + sh.sh_size));
440  });
441 }
const ElfShdr * iterateSections(Fn fn) const
Definition: Elf-inl.h:43
ThreadPoolListHook * addr
ElfW(Shdr) ElfShdr
Definition: Elf.h:42
const char * folly::symbolizer::ElfFile::getSectionName ( const ElfShdr section) const

Retrieve the name of a section

Definition at line 343 of file Elf.cpp.

References elfHeader(), getSectionByIndex(), and getString().

Referenced by getBaseAddress().

343  {
344  if (elfHeader().e_shstrndx == SHN_UNDEF) {
345  return nullptr; // no section name string table
346  }
347 
348  const ElfShdr& sectionNames = *getSectionByIndex(elfHeader().e_shstrndx);
349  return getString(sectionNames, section.sh_name);
350 }
const ElfShdr * getSectionByIndex(size_t idx) const
Definition: Elf.cpp:313
const char * getString(const ElfShdr &stringTable, size_t offset) const
Definition: Elf.cpp:334
const ElfEhdr & elfHeader() const
Definition: Elf.h:90
ElfW(Shdr) ElfShdr
Definition: Elf.h:42
const char * folly::symbolizer::ElfFile::getString ( const ElfShdr stringTable,
size_t  offset 
) const

Retrieve a string from a string table section

Definition at line 334 of file Elf.cpp.

References file_, FOLLY_SAFE_CHECK, and validateStringTable().

Referenced by getBaseAddress(), getSectionName(), getSymbolByName(), and getSymbolName().

335  {
336  validateStringTable(stringTable);
338  offset < stringTable.sh_size, "invalid offset in string table");
339 
340  return file_ + stringTable.sh_offset + offset;
341 }
void validateStringTable(const ElfShdr &stringTable) const
Definition: Elf.cpp:322
#define FOLLY_SAFE_CHECK(expr, msg)
Definition: SafeAssert.h:35
ElfFile::Symbol folly::symbolizer::ElfFile::getSymbolByName ( const char *  name) const

Find symbol definition by name.

If a symbol with this name cannot be found, a <nullptr, nullptr> Symbol will be returned. This is O(N) in the number of symbols in the file.

Returns {nullptr, nullptr} if not found.

Definition at line 398 of file Elf.cpp.

References getSectionByIndex(), getString(), iterateSectionsWithType(), iterateSymbolsWithTypes(), and STT_GNU_IFUNC.

Referenced by TEST_F().

398  {
399  Symbol foundSymbol{nullptr, nullptr};
400 
401  auto findSection = [&](const ElfShdr& section) -> bool {
402  // This section has no string table associated w/ its symbols; hence we
403  // can't get names for them
404  if (section.sh_link == SHN_UNDEF) {
405  return false;
406  }
407 
408  auto findSymbols = [&](const ElfSym& sym) -> bool {
409  if (sym.st_shndx == SHN_UNDEF) {
410  return false; // not a definition
411  }
412  if (sym.st_name == 0) {
413  return false; // no name for this symbol
414  }
415  const char* sym_name =
416  getString(*getSectionByIndex(section.sh_link), sym.st_name);
417  if (strcmp(sym_name, name) == 0) {
418  foundSymbol.first = &section;
419  foundSymbol.second = &sym;
420  return true;
421  }
422 
423  return false;
424  };
425 
427  section, {STT_OBJECT, STT_FUNC, STT_GNU_IFUNC}, findSymbols);
428  };
429 
430  // Try the .dynsym section first if it exists, it's smaller.
431  iterateSectionsWithType(SHT_DYNSYM, findSection) ||
432  iterateSectionsWithType(SHT_SYMTAB, findSection);
433 
434  return foundSymbol;
435 }
const ElfShdr * iterateSectionsWithType(uint32_t type, Fn fn) const
Definition: Elf-inl.h:61
const ElfShdr * getSectionByIndex(size_t idx) const
Definition: Elf.cpp:313
const char * getString(const ElfShdr &stringTable, size_t offset) const
Definition: Elf.cpp:334
const ElfSym * iterateSymbolsWithTypes(const ElfShdr &section, std::initializer_list< uint32_t > types, Fn fn) const
Definition: Elf-inl.h:123
const char * name
Definition: http_parser.c:437
#define STT_GNU_IFUNC
Definition: Elf.cpp:33
ElfW(Sym) ElfSym
Definition: Elf.h:43
std::pair< const ElfShdr *, const ElfSym * > Symbol
Definition: Elf.h:182
ElfW(Shdr) ElfShdr
Definition: Elf.h:42
const char * folly::symbolizer::ElfFile::getSymbolName ( Symbol  symbol) const

Retrieve symbol name.

Definition at line 443 of file Elf.cpp.

References getSectionByIndex(), and getString().

Referenced by getAddressValue().

443  {
444  if (!symbol.first || !symbol.second) {
445  return nullptr;
446  }
447 
448  if (symbol.second->st_name == 0) {
449  return nullptr; // symbol has no name
450  }
451 
452  if (symbol.first->sh_link == SHN_UNDEF) {
453  return nullptr; // symbol table has no strings
454  }
455 
456  return getString(
457  *getSectionByIndex(symbol.first->sh_link), symbol.second->st_name);
458 }
const ElfShdr * getSectionByIndex(size_t idx) const
Definition: Elf.cpp:313
const char * getString(const ElfShdr &stringTable, size_t offset) const
Definition: Elf.cpp:334
template<class T >
const T& folly::symbolizer::ElfFile::getSymbolValue ( const ElfSym symbol) const
inline

Get the value of a symbol.

Definition at line 199 of file Elf.h.

References FOLLY_SAFE_CHECK, and getSectionByIndex().

Referenced by TEST_F().

199  {
200  const ElfShdr* section = getSectionByIndex(symbol->st_shndx);
201  FOLLY_SAFE_CHECK(section, "Symbol's section index is invalid");
202 
203  return valueAt<T>(*section, symbol->st_value);
204  }
const ElfShdr * getSectionByIndex(size_t idx) const
Definition: Elf.cpp:313
#define FOLLY_SAFE_CHECK(expr, msg)
Definition: SafeAssert.h:35
ElfW(Shdr) ElfShdr
Definition: Elf.h:42
bool folly::symbolizer::ElfFile::init ( const char **  msg)
private

Definition at line 206 of file Elf.cpp.

References baseAddress_, elfHeader(), EXPECTED_CLASS, fd_, h, iterateProgramHeaders(), folly::kIsLittleEndian, length_, and fizz::detail::read().

Referenced by getAddressValue(), and openNoThrow().

206  {
207  if (length_ < 4) {
208  if (msg) {
209  *msg = "not an ELF file (too short)";
210  }
211  return false;
212  }
213 
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) {
216  if (msg) {
217  *msg = "unable to read ELF file for magic number";
218  }
219  return false;
220  }
221  if (std::strncmp(elfMagBuf.data(), ELFMAG, sizeof(ELFMAG)) != 0) {
222  if (msg) {
223  *msg = "invalid ELF magic";
224  }
225  return false;
226  }
227  if (::lseek(fd_, 0, SEEK_SET) != 0) {
228  if (msg) {
229  *msg = "unable to reset file descriptor after reading ELF magic number";
230  }
231  return false;
232  }
233 
234  auto& elfHeader = this->elfHeader();
235 
236 #define EXPECTED_CLASS P1(ELFCLASS, __ELF_NATIVE_CLASS)
237 #define P1(a, b) P2(a, b)
238 #define P2(a, b) a##b
239  // Validate ELF class (32/64 bits)
240  if (elfHeader.e_ident[EI_CLASS] != EXPECTED_CLASS) {
241  if (msg) {
242  *msg = "invalid ELF class";
243  }
244  return false;
245  }
246 #undef P1
247 #undef P2
248 #undef EXPECTED_CLASS
249 
250  // Validate ELF data encoding (LSB/MSB)
251  static constexpr auto kExpectedEncoding =
252  kIsLittleEndian ? ELFDATA2LSB : ELFDATA2MSB;
253  if (elfHeader.e_ident[EI_DATA] != kExpectedEncoding) {
254  if (msg) {
255  *msg = "invalid ELF encoding";
256  }
257  return false;
258  }
259 
260  // Validate ELF version (1)
261  if (elfHeader.e_ident[EI_VERSION] != EV_CURRENT ||
262  elfHeader.e_version != EV_CURRENT) {
263  if (msg) {
264  *msg = "invalid ELF version";
265  }
266  return false;
267  }
268 
269  // We only support executable and shared object files
270  if (elfHeader.e_type != ET_EXEC && elfHeader.e_type != ET_DYN) {
271  if (msg) {
272  *msg = "invalid ELF file type";
273  }
274  return false;
275  }
276 
277  if (elfHeader.e_phnum == 0) {
278  if (msg) {
279  *msg = "no program header!";
280  }
281  return false;
282  }
283 
284  if (elfHeader.e_phentsize != sizeof(ElfPhdr)) {
285  if (msg) {
286  *msg = "invalid program header entry size";
287  }
288  return false;
289  }
290 
291  if (elfHeader.e_shentsize != sizeof(ElfShdr)) {
292  if (msg) {
293  *msg = "invalid section header entry size";
294  }
295  }
296 
297  // Program headers are sorted by load address, so the first PT_LOAD
298  // header gives us the base address.
299  const ElfPhdr* programHeader =
300  iterateProgramHeaders([](auto& h) { return h.p_type == PT_LOAD; });
301 
302  if (!programHeader) {
303  if (msg) {
304  *msg = "could not find base address";
305  }
306  return false;
307  }
308  baseAddress_ = programHeader->p_vaddr;
309 
310  return true;
311 }
*than *hazptr_holder h
Definition: Hazptr.h:116
uintptr_t baseAddress_
Definition: Elf.h:289
const ElfPhdr * iterateProgramHeaders(Fn fn) const
Definition: Elf-inl.h:25
ElfW(Phdr) ElfPhdr
Definition: Elf.h:41
constexpr auto kIsLittleEndian
Definition: Portability.h:278
#define EXPECTED_CLASS
size_t read(T &out, folly::io::Cursor &cursor)
Definition: Types-inl.h:258
const ElfEhdr & elfHeader() const
Definition: Elf.h:90
ElfW(Shdr) ElfShdr
Definition: Elf.h:42
template<class Fn >
const ElfPhdr * folly::symbolizer::ElfFile::iterateProgramHeaders ( Fn  fn) const

Iterate over program headers as long as fn(section) returns false. Returns a pointer to the current ("found") section when fn returned true, or nullptr if fn returned false for all sections.

Definition at line 25 of file Elf-inl.h.

References elfHeader(), i, length_, and ptr.

Referenced by getBaseAddress(), init(), and TEST_F().

25  {
26  // there exist ELF binaries which execute correctly, but have invalid internal
27  // offset(s) to program/section headers; most probably due to invalid
28  // stripping of symbols
29  if (elfHeader().e_phoff + sizeof(ElfPhdr) >= length_) {
30  return nullptr;
31  }
32 
33  const ElfPhdr* ptr = &at<ElfPhdr>(elfHeader().e_phoff);
34  for (size_t i = 0; i < elfHeader().e_phnum; i++, ptr++) {
35  if (fn(*ptr)) {
36  return ptr;
37  }
38  }
39  return nullptr;
40 }
void * ptr
ElfW(Phdr) ElfPhdr
Definition: Elf.h:41
const ElfEhdr & elfHeader() const
Definition: Elf.h:90
template<class Fn >
const ElfShdr * folly::symbolizer::ElfFile::iterateSections ( Fn  fn) const

Iterate over all sections for as long as fn(section) returns false. Returns a pointer to the current ("found") section when fn returned true, or nullptr if fn returned false for all sections.

Definition at line 43 of file Elf-inl.h.

References elfHeader(), i, length_, and ptr.

Referenced by getBaseAddress(), getSectionByName(), getSectionContainingAddress(), iterateSectionsWithType(), and iterateSectionsWithTypes().

43  {
44  // there exist ELF binaries which execute correctly, but have invalid internal
45  // offset(s) to program/section headers; most probably due to invalid
46  // stripping of symbols
47  if (elfHeader().e_shoff + sizeof(ElfShdr) >= length_) {
48  return nullptr;
49  }
50 
51  const ElfShdr* ptr = &at<ElfShdr>(elfHeader().e_shoff);
52  for (size_t i = 0; i < elfHeader().e_shnum; i++, ptr++) {
53  if (fn(*ptr)) {
54  return ptr;
55  }
56  }
57  return nullptr;
58 }
void * ptr
const ElfEhdr & elfHeader() const
Definition: Elf.h:90
ElfW(Shdr) ElfShdr
Definition: Elf.h:42
template<class Fn >
const ElfShdr * folly::symbolizer::ElfFile::iterateSectionsWithType ( uint32_t  type,
Fn  fn 
) const

Iterate over all sections with a given type. Similar to iterateSections(), but filtered only for sections with the given type.

Definition at line 61 of file Elf-inl.h.

References iterateSections().

Referenced by getBaseAddress(), getDefinitionByAddress(), and getSymbolByName().

61  {
62  return iterateSections(
63  [&](const ElfShdr& sh) { return sh.sh_type == type && fn(sh); });
64 }
PskType type
const ElfShdr * iterateSections(Fn fn) const
Definition: Elf-inl.h:43
ElfW(Shdr) ElfShdr
Definition: Elf.h:42
template<class Fn >
const ElfShdr * folly::symbolizer::ElfFile::iterateSectionsWithTypes ( std::initializer_list< uint32_t types,
Fn  fn 
) const

Iterate over all sections with a given types. Similar to iterateSectionWithTypes(), but filtered on multiple types.

Definition at line 67 of file Elf-inl.h.

References iterateSections().

Referenced by getBaseAddress().

69  {
70  return iterateSections([&](const ElfShdr& sh) {
71  auto const it = std::find(types.begin(), types.end(), sh.sh_type);
72  return it != types.end() && fn(sh);
73  });
74 }
const ElfShdr * iterateSections(Fn fn) const
Definition: Elf-inl.h:43
ElfW(Shdr) ElfShdr
Definition: Elf.h:42
template<class Fn >
const char * folly::symbolizer::ElfFile::iterateStrings ( const ElfShdr stringTable,
Fn  fn 
) const

Iterate over all strings in a string table section for as long as fn(str) returns false. Returns the current ("found") string when fn returned true, or nullptr if fn returned false for all strings in the table.

Definition at line 77 of file Elf-inl.h.

References folly::test::end(), file_, ptr, start, and validateStringTable().

Referenced by getBaseAddress().

77  {
78  validateStringTable(stringTable);
79 
80  const char* start = file_ + stringTable.sh_offset;
81  const char* end = start + stringTable.sh_size;
82 
83  const char* ptr = start;
84  while (ptr != end && !fn(ptr)) {
85  ptr += strlen(ptr) + 1;
86  }
87 
88  return ptr != end ? ptr : nullptr;
89 }
void * ptr
void validateStringTable(const ElfShdr &stringTable) const
Definition: Elf.cpp:322
auto end(TestAdlIterable &instance)
Definition: ForeachTest.cpp:62
auto start
template<class Fn >
const ElfSym * folly::symbolizer::ElfFile::iterateSymbols ( const ElfShdr section,
Fn  fn 
) const

Iterate over all symbols witin a given section.

Returns a pointer to the current ("found") symbol when fn returned true, or nullptr if fn returned false for all symbols.

Definition at line 92 of file Elf-inl.h.

References folly::test::end(), and FOLLY_SAFE_CHECK.

Referenced by getBaseAddress(), iterateSymbolsWithType(), and iterateSymbolsWithTypes().

92  {
94  section.sh_entsize == sizeof(ElfSym),
95  "invalid entry size in symbol table");
96 
97  const ElfSym* sym = &at<ElfSym>(section.sh_offset);
98  const ElfSym* end = sym + (section.sh_size / section.sh_entsize);
99 
100  while (sym < end) {
101  if (fn(*sym)) {
102  return sym;
103  }
104 
105  ++sym;
106  }
107 
108  return nullptr;
109 }
auto end(TestAdlIterable &instance)
Definition: ForeachTest.cpp:62
#define FOLLY_SAFE_CHECK(expr, msg)
Definition: SafeAssert.h:35
ElfW(Sym) ElfSym
Definition: Elf.h:43
template<class Fn >
const ElfSym * folly::symbolizer::ElfFile::iterateSymbolsWithType ( const ElfShdr section,
uint32_t  type,
Fn  fn 
) const

Definition at line 112 of file Elf-inl.h.

References iterateSymbols().

Referenced by getBaseAddress().

115  {
116  // N.B. st_info has the same representation on 32- and 64-bit platforms
117  return iterateSymbols(section, [&](const ElfSym& sym) -> bool {
118  return ELF32_ST_TYPE(sym.st_info) == type && fn(sym);
119  });
120 }
PskType type
const ElfSym * iterateSymbols(const ElfShdr &section, Fn fn) const
Definition: Elf-inl.h:92
ElfW(Sym) ElfSym
Definition: Elf.h:43
template<class Fn >
const ElfSym * folly::symbolizer::ElfFile::iterateSymbolsWithTypes ( const ElfShdr section,
std::initializer_list< uint32_t types,
Fn  fn 
) const

Definition at line 123 of file Elf-inl.h.

References iterateSymbols().

Referenced by getBaseAddress(), getDefinitionByAddress(), and getSymbolByName().

126  {
127  // N.B. st_info has the same representation on 32- and 64-bit platforms
128  return iterateSymbols(section, [&](const ElfSym& sym) -> bool {
129  auto const elfType = ELF32_ST_TYPE(sym.st_info);
130  auto const it = std::find(types.begin(), types.end(), elfType);
131  return it != types.end() && fn(sym);
132  });
133 }
const ElfSym * iterateSymbols(const ElfShdr &section, Fn fn) const
Definition: Elf-inl.h:92
ElfW(Sym) ElfSym
Definition: Elf.h:43
void folly::symbolizer::ElfFile::open ( const char *  name,
bool  readOnly = true 
)

Definition at line 53 of file Elf.cpp.

References kSuccess, kSystemError, openNoThrow(), and folly::throwSystemError().

Referenced by ElfFile(), and openNoThrow().

53  {
54  const char* msg = "";
55  int r = openNoThrow(name, readOnly, &msg);
56  if (r == kSystemError) {
57  throwSystemError(msg);
58  } else {
59  CHECK_EQ(r, kSuccess) << msg;
60  }
61 }
const char * name
Definition: http_parser.c:437
int openNoThrow(const char *name, bool readOnly=true, const char **msg=nullptr) noexcept
Definition: Elf.cpp:63
void throwSystemError(Args &&...args)
Definition: Exception.h:76
int folly::symbolizer::ElfFile::openAndFollow ( const char *  name,
bool  readOnly = true,
const char **  msg = nullptr 
)
noexcept

Definition at line 110 of file Elf.cpp.

References getSectionBody(), getSectionByName(), kSuccess, name, openNoThrow(), and reset().

113  {
114  auto result = openNoThrow(name, readOnly, msg);
115  if (!readOnly || result != kSuccess) {
116  return result;
117  }
118 
119  /* NOTE .gnu_debuglink specifies only the name of the debugging info file
120  * (with no directory components). GDB checks 3 different directories, but
121  * ElfFile only supports the first version:
122  * - dirname(name)
123  * - dirname(name) + /.debug/
124  * - X/dirname(name)/ - where X is set in gdb's `debug-file-directory`.
125  */
126  auto dirend = strrchr(name, '/');
127  // include ending '/' if any.
128  auto dirlen = dirend != nullptr ? dirend + 1 - name : 0;
129 
130  auto debuginfo = getSectionByName(".gnu_debuglink");
131  if (!debuginfo) {
132  return result;
133  }
134 
135  // The section starts with the filename, with any leading directory
136  // components removed, followed by a zero byte.
137  auto debugFileName = getSectionBody(*debuginfo);
138  auto debugFileLen = strlen(debugFileName.begin());
139  if (dirlen + debugFileLen >= PATH_MAX) {
140  return result;
141  }
142 
143  char linkname[PATH_MAX];
144  memcpy(linkname, name, dirlen);
145  memcpy(linkname + dirlen, debugFileName.begin(), debugFileLen + 1);
146  reset();
147  result = openNoThrow(linkname, readOnly, msg);
148  if (result == kSuccess) {
149  return result;
150  }
151  return openNoThrow(name, readOnly, msg);
152 }
folly::StringPiece getSectionBody(const ElfShdr &section) const
Definition: Elf.cpp:318
const char * name
Definition: http_parser.c:437
int openNoThrow(const char *name, bool readOnly=true, const char **msg=nullptr) noexcept
Definition: Elf.cpp:63
const ElfShdr * getSectionByName(const char *name) const
Definition: Elf.cpp:352
int folly::symbolizer::ElfFile::openNoThrow ( const char *  name,
bool  readOnly = true,
const char **  msg = nullptr 
)
noexcept

Definition at line 63 of file Elf.cpp.

References fd_, file_, filepath_, FOLLY_SAFE_CHECK, folly::gen::guard(), init(), kFilepathMaxLen, kInvalidElfFile, kSuccess, kSystemError, length_, folly::makeGuard(), name, open(), and reset().

Referenced by open(), openAndFollow(), and TEST_F().

66  {
67  FOLLY_SAFE_CHECK(fd_ == -1, "File already open");
68  strncat(filepath_, name, kFilepathMaxLen - 1);
69  fd_ = ::open(name, readOnly ? O_RDONLY : O_RDWR);
70  if (fd_ == -1) {
71  if (msg) {
72  *msg = "open";
73  }
74  return kSystemError;
75  }
76  // Always close fd and unmap in case of failure along the way to avoid
77  // check failure above if we leave fd != -1 and the object is recycled
78  // like it is inside SignalSafeElfCache
79  auto guard = makeGuard([&] { reset(); });
80  struct stat st;
81  int r = fstat(fd_, &st);
82  if (r == -1) {
83  if (msg) {
84  *msg = "fstat";
85  }
86  return kSystemError;
87  }
88 
89  length_ = st.st_size;
90  int prot = PROT_READ;
91  if (!readOnly) {
92  prot |= PROT_WRITE;
93  }
94  file_ = static_cast<char*>(mmap(nullptr, length_, prot, MAP_SHARED, fd_, 0));
95  if (file_ == MAP_FAILED) {
96  if (msg) {
97  *msg = "mmap";
98  }
99  return kSystemError;
100  }
101  if (!init(msg)) {
102  reset();
103  errno = EINVAL;
104  return kInvalidElfFile;
105  }
106  guard.dismiss();
107  return kSuccess;
108 }
char filepath_[kFilepathMaxLen]
Definition: Elf.h:284
const char * name
Definition: http_parser.c:437
void open(const char *name, bool readOnly=true)
Definition: Elf.cpp:53
GuardImpl guard(ErrorHandler &&handler)
Definition: Base.h:840
static constexpr size_t kFilepathMaxLen
Definition: Elf.h:283
#define FOLLY_SAFE_CHECK(expr, msg)
Definition: SafeAssert.h:35
bool init(const char **msg)
Definition: Elf.cpp:206
FOLLY_NODISCARD detail::ScopeGuardImplDecay< F, true > makeGuard(F &&f) noexcept(noexcept(detail::ScopeGuardImplDecay< F, true >(static_cast< F && >(f))))
Definition: ScopeGuard.h:184
ElfFile & folly::symbolizer::ElfFile::operator= ( ElfFile &&  other)

Definition at line 172 of file Elf.cpp.

References baseAddress_, fd_, file_, filepath_, kFilepathMaxLen, length_, and reset().

Referenced by getAddressValue().

172  {
173  assert(this != &other);
174  reset();
175 
176  // copy other.filepath_, leaving filepath_ zero-terminated, always.
177  strncat(filepath_, other.filepath_, kFilepathMaxLen - 1);
178  fd_ = other.fd_;
179  file_ = other.file_;
180  length_ = other.length_;
181  baseAddress_ = other.baseAddress_;
182 
183  other.filepath_[0] = 0;
184  other.fd_ = -1;
185  other.file_ = static_cast<char*>(MAP_FAILED);
186  other.length_ = 0;
187  other.baseAddress_ = 0;
188 
189  return *this;
190 }
char filepath_[kFilepathMaxLen]
Definition: Elf.h:284
uintptr_t baseAddress_
Definition: Elf.h:289
static constexpr size_t kFilepathMaxLen
Definition: Elf.h:283
ElfFile& folly::symbolizer::ElfFile::operator= ( const ElfFile )
privatedelete
void folly::symbolizer::ElfFile::reset ( )
private

Definition at line 192 of file Elf.cpp.

References folly::netops::close(), fd_, file_, filepath_, and length_.

Referenced by getAddressValue(), openAndFollow(), openNoThrow(), operator=(), and ~ElfFile().

192  {
193  filepath_[0] = 0;
194 
195  if (file_ != MAP_FAILED) {
196  munmap(file_, length_);
197  file_ = static_cast<char*>(MAP_FAILED);
198  }
199 
200  if (fd_ != -1) {
201  close(fd_);
202  fd_ = -1;
203  }
204 }
char filepath_[kFilepathMaxLen]
Definition: Elf.h:284
int close(NetworkSocket s)
Definition: NetOps.cpp:90
void folly::symbolizer::ElfFile::validateStringTable ( const ElfShdr stringTable) const
private

Definition at line 322 of file Elf.cpp.

References file_, FOLLY_SAFE_CHECK, and start.

Referenced by getAddressValue(), getString(), and iterateStrings().

322  {
324  stringTable.sh_type == SHT_STRTAB, "invalid type for string table");
325 
326  const char* start = file_ + stringTable.sh_offset;
327  // First and last bytes must be 0
329  stringTable.sh_size == 0 ||
330  (start[0] == '\0' && start[stringTable.sh_size - 1] == '\0'),
331  "invalid string table");
332 }
#define FOLLY_SAFE_CHECK(expr, msg)
Definition: SafeAssert.h:35
auto start
template<class T >
const T& folly::symbolizer::ElfFile::valueAt ( const ElfShdr section,
const ElfAddr  addr 
) const
inlineprivate

Definition at line 262 of file Elf.h.

References elfHeader(), FOLLY_SAFE_CHECK, and folly::T.

262  {
263  // For exectuables and shared objects, st_value holds a virtual address
264  // that refers to the memory owned by sections. Since we didn't map the
265  // sections into the addresses that they're expecting (sh_addr), but
266  // instead just mmapped the entire file directly, we need to translate
267  // between addresses and offsets into the file.
268  //
269  // TODO: For other file types, st_value holds a file offset directly. Since
270  // I don't have a use-case for that right now, just assert that
271  // nobody wants this. We can always add it later.
273  elfHeader().e_type == ET_EXEC || elfHeader().e_type == ET_DYN,
274  "Only exectuables and shared objects are supported");
276  addr >= section.sh_addr &&
277  (addr + sizeof(T)) <= (section.sh_addr + section.sh_size),
278  "Address is not contained within the provided segment");
279 
280  return at<T>(section.sh_offset + (addr - section.sh_addr));
281  }
folly::std T
const ElfEhdr & elfHeader() const
Definition: Elf.h:90
#define FOLLY_SAFE_CHECK(expr, msg)
Definition: SafeAssert.h:35
ThreadPoolListHook * addr

Member Data Documentation

uintptr_t folly::symbolizer::ElfFile::baseAddress_
private

Definition at line 289 of file Elf.h.

Referenced by getBaseAddress(), init(), and operator=().

int folly::symbolizer::ElfFile::fd_
private

Definition at line 285 of file Elf.h.

Referenced by init(), openNoThrow(), operator=(), and reset().

char* folly::symbolizer::ElfFile::file_
private
char folly::symbolizer::ElfFile::filepath_[kFilepathMaxLen] = {}
private

Definition at line 284 of file Elf.h.

Referenced by at(), ElfFile(), openNoThrow(), operator=(), and reset().

constexpr size_t folly::symbolizer::ElfFile::kFilepathMaxLen = 512
staticprivate

Definition at line 283 of file Elf.h.

Referenced by at(), ElfFile(), openNoThrow(), and operator=().

size_t folly::symbolizer::ElfFile::length_
private

Definition at line 287 of file Elf.h.

Referenced by at(), init(), iterateProgramHeaders(), iterateSections(), openNoThrow(), operator=(), and reset().


The documentation for this class was generated from the following files: