proxygen
Elf.h
Go to the documentation of this file.
1 /*
2  * Copyright 2012-present 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 #pragma once
20 #define FOLLY_EXPERIMENTAL_SYMBOLIZER_ELF_H_
21 
22 #include <elf.h>
23 #include <link.h> // For ElfW()
24 
25 #include <cstdio>
26 #include <initializer_list>
27 #include <stdexcept>
28 #include <system_error>
29 
30 #include <folly/Conv.h>
31 #include <folly/Likely.h>
32 #include <folly/Range.h>
33 #include <folly/lang/SafeAssert.h>
34 
35 namespace folly {
36 namespace symbolizer {
37 
38 using ElfAddr = ElfW(Addr);
39 using ElfEhdr = ElfW(Ehdr);
40 using ElfOff = ElfW(Off);
41 using ElfPhdr = ElfW(Phdr);
42 using ElfShdr = ElfW(Shdr);
43 using ElfSym = ElfW(Sym);
44 
52 class ElfFile {
53  public:
54  ElfFile() noexcept;
55 
56  // Note: may throw, call openNoThrow() explicitly if you don't want to throw
57  explicit ElfFile(const char* name, bool readOnly = true);
58 
59  // Open the ELF file.
60  // Returns 0 on success, kSystemError (guaranteed to be -1) (and sets errno)
61  // on IO error, kInvalidElfFile (and sets errno to EINVAL) for an invalid
62  // Elf file. On error, if msg is not nullptr, sets *msg to a static string
63  // indicating what failed.
64  enum {
65  kSuccess = 0,
68  };
69  // Open the ELF file. Does not throw on error.
70  int openNoThrow(
71  const char* name,
72  bool readOnly = true,
73  const char** msg = nullptr) noexcept;
74 
75  // Like openNoThrow, but follow .gnu_debuglink if present
76  int openAndFollow(
77  const char* name,
78  bool readOnly = true,
79  const char** msg = nullptr) noexcept;
80 
81  // Open the ELF file. Throws on error.
82  void open(const char* name, bool readOnly = true);
83 
84  ~ElfFile();
85 
86  ElfFile(ElfFile&& other) noexcept;
87  ElfFile& operator=(ElfFile&& other);
88 
90  const ElfEhdr& elfHeader() const {
91  return at<ElfEhdr>(0);
92  }
93 
98  uintptr_t getBaseAddress() const {
99  return baseAddress_;
100  }
101 
103  const ElfShdr* getSectionByName(const char* name) const;
104 
106  const ElfShdr* getSectionByIndex(size_t idx) const;
107 
109  const char* getSectionName(const ElfShdr& section) const;
110 
112  folly::StringPiece getSectionBody(const ElfShdr& section) const;
113 
115  const char* getString(const ElfShdr& stringTable, size_t offset) const;
116 
123  template <class Fn>
124  const char* iterateStrings(const ElfShdr& stringTable, Fn fn) const;
125 
131  template <class Fn>
132  const ElfPhdr* iterateProgramHeaders(Fn fn) const;
133 
139  template <class Fn>
140  const ElfShdr* iterateSections(Fn fn) const;
141 
146  template <class Fn>
147  const ElfShdr* iterateSectionsWithType(uint32_t type, Fn fn) const;
148 
153  template <class Fn>
155  std::initializer_list<uint32_t> types,
156  Fn fn) const;
157 
164  template <class Fn>
165  const ElfSym* iterateSymbols(const ElfShdr& section, Fn fn) const;
166  template <class Fn>
167  const ElfSym*
168  iterateSymbolsWithType(const ElfShdr& section, uint32_t type, Fn fn) const;
169  template <class Fn>
171  const ElfShdr& section,
172  std::initializer_list<uint32_t> types,
173  Fn fn) const;
174 
182  typedef std::pair<const ElfShdr*, const ElfSym*> Symbol;
183  Symbol getDefinitionByAddress(uintptr_t address) const;
184 
193  Symbol getSymbolByName(const char* name) const;
194 
198  template <class T>
199  const T& getSymbolValue(const ElfSym* symbol) const {
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  }
205 
217  template <class T>
218  const T& getAddressValue(const ElfAddr addr) const {
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  }
224 
228  const char* getSymbolName(Symbol symbol) const;
229 
232 
233  private:
234  bool init(const char** msg);
235  void reset();
236  ElfFile(const ElfFile&) = delete;
237  ElfFile& operator=(const ElfFile&) = delete;
238 
239  void validateStringTable(const ElfShdr& stringTable) const;
240 
241  template <class T>
243  ElfOff offset) const {
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  }
260 
261  template <class T>
262  const T& valueAt(const ElfShdr& section, const ElfAddr addr) const {
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  }
282 
283  static constexpr size_t kFilepathMaxLen = 512;
285  int fd_;
286  char* file_; // mmap() location
287  size_t length_; // mmap() length
288 
289  uintptr_t baseAddress_;
290 };
291 
292 } // namespace symbolizer
293 } // namespace folly
294 
const ElfShdr * iterateSectionsWithTypes(std::initializer_list< uint32_t > types, Fn fn) const
Definition: Elf-inl.h:67
char filepath_[kFilepathMaxLen]
Definition: Elf.h:284
Symbol getDefinitionByAddress(uintptr_t address) const
Definition: Elf.cpp:370
const char * getSymbolName(Symbol symbol) const
Definition: Elf.cpp:443
ElfW(Addr) ElfAddr
Definition: Elf.h:38
uintptr_t baseAddress_
Definition: Elf.h:289
const T & getAddressValue(const ElfAddr addr) const
Definition: Elf.h:218
const ElfPhdr * iterateProgramHeaders(Fn fn) const
Definition: Elf-inl.h:25
PskType type
const ElfShdr * getSectionContainingAddress(ElfAddr addr) const
Definition: Elf.cpp:437
const T & getSymbolValue(const ElfSym *symbol) const
Definition: Elf.h:199
int openAndFollow(const char *name, bool readOnly=true, const char **msg=nullptr) noexcept
Definition: Elf.cpp:110
ElfW(Off) ElfOff
Definition: Elf.h:40
ElfFile() noexcept
Definition: Elf.cpp:39
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
ElfW(Phdr) ElfPhdr
Definition: Elf.h:41
folly::std T
folly::StringPiece getSectionBody(const ElfShdr &section) const
Definition: Elf.cpp:318
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
requires E e noexcept(noexcept(s.error(std::move(e))))
const ElfShdr * iterateSections(Fn fn) const
Definition: Elf-inl.h:43
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
void validateStringTable(const ElfShdr &stringTable) const
Definition: Elf.cpp:322
void open(const char *name, bool readOnly=true)
Definition: Elf.cpp:53
int openNoThrow(const char *name, bool readOnly=true, const char **msg=nullptr) noexcept
Definition: Elf.cpp:63
const ElfEhdr & elfHeader() const
Definition: Elf.h:90
const ElfShdr * getSectionByName(const char *name) const
Definition: Elf.cpp:352
Symbol getSymbolByName(const char *name) const
Definition: Elf.cpp:398
ElfW(Ehdr) ElfEhdr
Definition: Elf.h:39
static constexpr size_t kFilepathMaxLen
Definition: Elf.h:283
ElfFile & operator=(ElfFile &&other)
Definition: Elf.cpp:172
static const char *const value
Definition: Conv.cpp:50
#define FOLLY_SAFE_CHECK(expr, msg)
Definition: SafeAssert.h:35
bool init(const char **msg)
Definition: Elf.cpp:206
const ElfSym * iterateSymbols(const ElfShdr &section, Fn fn) const
Definition: Elf-inl.h:92
const std::enable_if< std::is_pod< T >::value, T >::type & at(ElfOff offset) const
Definition: Elf.h:242
const T & valueAt(const ElfShdr &section, const ElfAddr addr) const
Definition: Elf.h:262
const
Definition: upload.py:398
ElfW(Sym) ElfSym
Definition: Elf.h:43
const ElfSym * iterateSymbolsWithType(const ElfShdr &section, uint32_t type, Fn fn) const
Definition: Elf-inl.h:112
ThreadPoolListHook * addr
std::pair< const ElfShdr *, const ElfSym * > Symbol
Definition: Elf.h:182
const char * iterateStrings(const ElfShdr &stringTable, Fn fn) const
Definition: Elf-inl.h:77
uintptr_t getBaseAddress() const
Definition: Elf.h:98
ElfW(Shdr) ElfShdr
Definition: Elf.h:42
const char * getSectionName(const ElfShdr &section) const
Definition: Elf.cpp:343