Fix SignalHandlerTest with ASAN
[folly.git] / folly / experimental / symbolizer / Elf.h
index f0a0bd7b874181cc29e60c474b1ca5c9b5a356c6..a4f5afd22553ca9045c2571bf5ff98b07dcdaf6e 100644 (file)
 #include <link.h> // For ElfW()
 
 #include <cstdio>
+#include <initializer_list>
 #include <stdexcept>
 #include <system_error>
 
 #include <folly/Conv.h>
 #include <folly/Likely.h>
 #include <folly/Range.h>
-#include <folly/SafeAssert.h>
+#include <folly/lang/SafeAssert.h>
 
 namespace folly {
 namespace symbolizer {
 
+using ElfAddr = ElfW(Addr);
+using ElfEhdr = ElfW(Ehdr);
+using ElfOff = ElfW(Off);
+using ElfPhdr = ElfW(Phdr);
+using ElfShdr = ElfW(Shdr);
+using ElfSym = ElfW(Sym);
+
 /**
  * ELF file parser.
  *
@@ -46,7 +54,7 @@ class ElfFile {
   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, bool readOnly = true);
 
   // Open the ELF file.
   // Returns 0 on success, kSystemError (guaranteed to be -1) (and sets errno)
@@ -59,15 +67,19 @@ class ElfFile {
     kInvalidElfFile = -2,
   };
   // Open the ELF file. Does not throw on error.
-  int openNoThrow(const char* name, bool readOnly=true,
-                  const char** msg=nullptr) noexcept;
+  int openNoThrow(
+      const char* name,
+      bool readOnly = true,
+      const char** msg = nullptr) noexcept;
 
   // Like openNoThrow, but follow .gnu_debuglink if present
-  int openAndFollow(const char* name, bool readOnly=true,
-                    const char** msg=nullptr) noexcept;
+  int openAndFollow(
+      const char* name,
+      bool readOnly = true,
+      const char** msg = nullptr) noexcept;
 
   // Open the ELF file. Throws on error.
-  void open(const char* name, bool readOnly=true);
+  void open(const char* name, bool readOnly = true);
 
   ~ElfFile();
 
@@ -75,8 +87,8 @@ class ElfFile {
   ElfFile& operator=(ElfFile&& other);
 
   /** Retrieve the ELF header */
-  const ElfW(Ehdr)& elfHeader() const {
-    return at<ElfW(Ehdr)>(0);
+  const ElfEhdr& elfHeader() const {
+    return at<ElfEhdr>(0);
   }
 
   /**
@@ -88,19 +100,19 @@ class ElfFile {
   }
 
   /** Find a section given its name */
-  const ElfW(Shdr)* getSectionByName(const char* name) const;
+  const ElfShdr* getSectionByName(const char* name) const;
 
   /** Find a section given its index in the section header table */
-  const ElfW(Shdr)* getSectionByIndex(size_t idx) const;
+  const ElfShdr* getSectionByIndex(size_t idx) const;
 
   /** Retrieve the name of a section */
-  const char* getSectionName(const ElfW(Shdr)& section) const;
+  const char* getSectionName(const ElfShdr& section) const;
 
   /** Get the actual section body */
-  folly::StringPiece getSectionBody(const ElfW(Shdr)& section) const;
+  folly::StringPiece getSectionBody(const ElfShdr& section) const;
 
   /** Retrieve a string from a string table section */
-  const char* getString(const ElfW(Shdr)& stringTable, size_t offset) const;
+  const char* getString(const ElfShdr& stringTable, size_t offset) const;
 
   /**
    * Iterate over all strings in a string table section for as long as
@@ -109,7 +121,15 @@ class ElfFile {
    * if fn returned false for all strings in the table.
    */
   template <class Fn>
-  const char* iterateStrings(const ElfW(Shdr)& stringTable, Fn fn) const;
+  const char* iterateStrings(const ElfShdr& stringTable, 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.
+   */
+  template <class Fn>
+  const ElfPhdr* iterateProgramHeaders(Fn fn) const;
 
   /**
    * Iterate over all sections for as long as fn(section) returns false.
@@ -117,14 +137,23 @@ class ElfFile {
    * true, or nullptr if fn returned false for all sections.
    */
   template <class Fn>
-  const ElfW(Shdr)* iterateSections(Fn fn) const;
+  const ElfShdr* iterateSections(Fn fn) const;
 
   /**
-   * Iterate over all sections with a given type.  Similar to
+   * Iterate over all sections with a given type. Similar to
    * iterateSections(), but filtered only for sections with the given type.
    */
   template <class Fn>
-  const ElfW(Shdr)* iterateSectionsWithType(uint32_t type, Fn fn) const;
+  const ElfShdr* iterateSectionsWithType(uint32_t type, Fn fn) const;
+
+  /**
+   * Iterate over all sections with a given types. Similar to
+   * iterateSectionWithTypes(), but filtered on multiple types.
+   */
+  template <class Fn>
+  const ElfShdr* iterateSectionsWithTypes(
+      std::initializer_list<uint32_t> types,
+      Fn fn) const;
 
   /**
    * Iterate over all symbols witin a given section.
@@ -133,10 +162,15 @@ class ElfFile {
    * or nullptr if fn returned false for all symbols.
    */
   template <class Fn>
-  const ElfW(Sym)* iterateSymbols(const ElfW(Shdr)& section, Fn fn) const;
+  const ElfSym* iterateSymbols(const ElfShdr& section, Fn fn) const;
+  template <class Fn>
+  const ElfSym*
+  iterateSymbolsWithType(const ElfShdr& section, uint32_t type, Fn fn) const;
   template <class Fn>
-  const ElfW(Sym)* iterateSymbolsWithType(const ElfW(Shdr)& section,
-                                          uint32_t type, Fn fn) const;
+  const ElfSym* iterateSymbolsWithTypes(
+      const ElfShdr& section,
+      std::initializer_list<uint32_t> types,
+      Fn fn) const;
 
   /**
    * Find symbol definition by address.
@@ -145,7 +179,7 @@ class ElfFile {
    *
    * Returns {nullptr, nullptr} if not found.
    */
-  typedef std::pair<const ElfW(Shdr)*, const ElfW(Sym)*> Symbol;
+  typedef std::pair<const ElfShdr*, const ElfSym*> Symbol;
   Symbol getDefinitionByAddress(uintptr_t address) const;
 
   /**
@@ -162,8 +196,8 @@ class ElfFile {
    * Get the value of a symbol.
    */
   template <class T>
-  const T& getSymbolValue(const ElfW(Sym)* symbol) const {
-    const ElfW(Shdr)* section = getSectionByIndex(symbol->st_shndx);
+  const T& getSymbolValue(const ElfSym* symbol) const {
+    const ElfShdr* section = getSectionByIndex(symbol->st_shndx);
     FOLLY_SAFE_CHECK(section, "Symbol's section index is invalid");
 
     return valueAt<T>(*section, symbol->st_value);
@@ -177,12 +211,12 @@ class ElfFile {
    * a char* symbol, you'd do something like this:
    *
    *  auto sym = getSymbolByName("someGlobalValue");
-   *  auto addr = getSymbolValue<ElfW(Addr)>(sym.second);
+   *  auto addr = getSymbolValue<ElfAddr>(sym.second);
    *  const char* str = &getSymbolValue<const char>(addr);
    */
   template <class T>
-  const T& getAddressValue(const ElfW(Addr) addr) const {
-    const ElfW(Shdr)* section = getSectionContainingAddress(addr);
+  const T& getAddressValue(const ElfAddr addr) const {
+    const ElfShdr* section = getSectionContainingAddress(addr);
     FOLLY_SAFE_CHECK(section, "Address does not refer to existing section");
 
     return valueAt<T>(*section, addr);
@@ -194,7 +228,7 @@ class ElfFile {
   const char* getSymbolName(Symbol symbol) const;
 
   /** Find the section containing the given address */
-  const ElfW(Shdr)* getSectionContainingAddress(ElfW(Addr) addr) const;
+  const ElfShdr* getSectionContainingAddress(ElfAddr addr) const;
 
  private:
   bool init(const char** msg);
@@ -202,19 +236,20 @@ class ElfFile {
   ElfFile(const ElfFile&) = delete;
   ElfFile& operator=(const ElfFile&) = delete;
 
-  void validateStringTable(const ElfW(Shdr)& stringTable) const;
+  void validateStringTable(const ElfShdr& stringTable) const;
 
   template <class T>
-  const typename std::enable_if<std::is_pod<T>::value, T>::type&
-  at(ElfW(Off) offset) const {
-    FOLLY_SAFE_CHECK(offset + sizeof(T) <= length_,
-                     "Offset is not contained within our mmapped file");
+  const typename std::enable_if<std::is_pod<T>::value, T>::type& at(
+      ElfOff offset) const {
+    FOLLY_SAFE_CHECK(
+        offset + sizeof(T) <= length_,
+        "Offset is not contained within our mmapped file");
 
     return *reinterpret_cast<T*>(file_ + offset);
   }
 
   template <class T>
-  const T& valueAt(const ElfW(Shdr)& section, const ElfW(Addr) addr) const {
+  const T& valueAt(const ElfShdr& section, const ElfAddr addr) const {
     // For exectuables and shared objects, st_value holds a virtual address
     // that refers to the memory owned by sections. Since we didn't map the
     // sections into the addresses that they're expecting (sh_addr), but
@@ -229,20 +264,20 @@ class ElfFile {
         "Only exectuables and shared objects are supported");
     FOLLY_SAFE_CHECK(
         addr >= section.sh_addr &&
-        (addr + sizeof(T)) <= (section.sh_addr + section.sh_size),
+            (addr + sizeof(T)) <= (section.sh_addr + section.sh_size),
         "Address is not contained within the provided segment");
 
     return at<T>(section.sh_offset + (addr - section.sh_addr));
   }
 
   int fd_;
-  char* file_;     // mmap() location
-  size_t length_;  // mmap() length
+  char* file_; // mmap() location
+  size_t length_; // mmap() length
 
   uintptr_t baseAddress_;
 };
 
-}  // namespace symbolizer
-}  // namespace folly
+} // namespace symbolizer
+} // namespace folly
 
 #include <folly/experimental/symbolizer/Elf-inl.h>