4187aa695c19396b196c6128831b27db093222f3
[folly.git] / folly / experimental / symbolizer / Elf.h
1 /*
2  * Copyright 2012 Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 // ELF file parser
18
19 #ifndef FOLLY_EXPERIMENTAL_SYMBOLIZER_ELF_H_
20 #define FOLLY_EXPERIMENTAL_SYMBOLIZER_ELF_H_
21
22 #include <stdio.h>
23 #include <elf.h>
24 #include <link.h>  // For ElfW()
25
26 #include <stdexcept>
27 #include <system_error>
28
29 #include "folly/Likely.h"
30 #include "folly/Range.h"
31 #include "folly/Conv.h"
32
33 namespace facebook {
34 namespace symbolizer {
35
36 /**
37  * ELF file parser.
38  *
39  * We handle native files only (32-bit files on a 32-bit platform, 64-bit files
40  * on a 64-bit platform), and only executables (ET_EXEC) and shared objects
41  * (ET_DYN).
42  */
43 class ElfFile {
44  public:
45   ElfFile();
46   explicit ElfFile(const char* name);
47   ~ElfFile();
48
49   ElfFile(ElfFile&& other);
50   ElfFile& operator=(ElfFile&& other);
51
52   /** Retrieve the ELF header */
53   const ElfW(Ehdr)& elfHeader() const {
54     return at<ElfW(Ehdr)>(0);
55   }
56
57   /**
58    * Get the base address, the address where the file should be loaded if
59    * no relocations happened.
60    */
61   uintptr_t getBaseAddress() const {
62     return baseAddress_;
63   }
64
65   /** Find a section given its name */
66   const ElfW(Shdr)* getSectionByName(const char* name) const;
67
68   /** Find a section given its index in the section header table */
69   const ElfW(Shdr)* getSectionByIndex(size_t idx) const;
70
71   /** Retrieve the name of a section */
72   const char* getSectionName(const ElfW(Shdr)& section) const;
73
74   /** Get the actual section body */
75   folly::StringPiece getSectionBody(const ElfW(Shdr)& section) const;
76
77   /** Retrieve a string from a string table section */
78   const char* getString(const ElfW(Shdr)& stringTable, size_t offset) const;
79
80   /**
81    * Iterate over all strings in a string table section for as long as
82    * fn(str) returns false.
83    * Returns the current ("found") string when fn returned true, or nullptr
84    * if fn returned false for all strings in the table.
85    */
86   template <class Fn>
87   const char* iterateStrings(const ElfW(Shdr)& stringTable, Fn fn) const;
88
89   /**
90    * Iterate over all sections for as long as fn(section) returns false.
91    * Returns a pointer to the current ("found") section when fn returned
92    * true, or nullptr if fn returned false for all sections.
93    */
94   template <class Fn>
95   const ElfW(Shdr)* iterateSections(Fn fn) const;
96
97   /**
98    * Iterate over all sections with a given type.  Similar to
99    * iterateSections(), but filtered only for sections with the given type.
100    */
101   template <class Fn>
102   const ElfW(Shdr)* iterateSectionsWithType(uint32_t type, Fn fn) const;
103
104   /**
105    * Find symbol definition by address.
106    * Note that this is the file virtual address, so you need to undo
107    * any relocation that might have happened.
108    */
109   typedef std::pair<const ElfW(Shdr)*, const ElfW(Sym)*> Symbol;
110   Symbol getDefinitionByAddress(uintptr_t address) const;
111
112   /**
113    * Retrieve symbol name.
114    */
115   const char* getSymbolName(Symbol symbol) const;
116
117  private:
118   void init();
119   void destroy();
120   ElfFile(const ElfFile&) = delete;
121   ElfFile& operator=(const ElfFile&) = delete;
122
123   void validateStringTable(const ElfW(Shdr)& stringTable) const;
124
125   template <class T>
126   const T& at(off_t offset) const {
127     return *reinterpret_cast<T*>(file_ + offset);
128   }
129
130   int fd_;
131   char* file_;     // mmap() location
132   size_t length_;  // mmap() length
133
134   uintptr_t baseAddress_;
135 };
136
137 template <class... Args>
138 void systemError(Args... args) __attribute__((noreturn));
139
140 template <class... Args>
141 void systemError(Args... args) {
142   throw std::system_error(errno, std::system_category(),
143                           folly::to<std::string>(args...));
144 }
145
146 template <class... Args>
147 inline void enforce(bool v, Args... args) {
148   if (UNLIKELY(!v)) {
149     throw std::runtime_error(folly::to<std::string>(args...));
150   }
151 }
152
153 }  // namespace symbolizer
154 }  // namespace facebook
155
156 #include "folly/experimental/symbolizer/Elf-inl.h"
157
158 #endif /* FOLLY_EXPERIMENTAL_SYMBOLIZER_ELF_H_ */
159