Elf.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  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. #include <folly/experimental/symbolizer/Elf.h>
  17. #include <fcntl.h>
  18. #include <folly/portability/SysMman.h>
  19. #include <sys/stat.h>
  20. #include <sys/types.h>
  21. #include <cstring>
  22. #include <string>
  23. #include <glog/logging.h>
  24. #include <folly/Conv.h>
  25. #include <folly/Exception.h>
  26. #include <folly/ScopeGuard.h>
  27. #ifndef STT_GNU_IFUNC
  28. #define STT_GNU_IFUNC 10
  29. #endif
  30. namespace folly {
  31. namespace symbolizer {
  32. ElfFile::ElfFile() noexcept
  33. : fd_(-1),
  34. file_(static_cast<char*>(MAP_FAILED)),
  35. length_(0),
  36. baseAddress_(0) {}
  37. ElfFile::ElfFile(const char* name, bool readOnly)
  38. : fd_(-1),
  39. file_(static_cast<char*>(MAP_FAILED)),
  40. length_(0),
  41. baseAddress_(0) {
  42. open(name, readOnly);
  43. }
  44. void ElfFile::open(const char* name, bool readOnly) {
  45. const char* msg = "";
  46. int r = openNoThrow(name, readOnly, &msg);
  47. if (r == kSystemError) {
  48. throwSystemError(msg);
  49. } else {
  50. CHECK_EQ(r, kSuccess) << msg;
  51. }
  52. }
  53. int ElfFile::openNoThrow(
  54. const char* name,
  55. bool readOnly,
  56. const char** msg) noexcept {
  57. FOLLY_SAFE_CHECK(fd_ == -1, "File already open");
  58. strncat(filepath_, name, kFilepathMaxLen - 1);
  59. fd_ = ::open(name, readOnly ? O_RDONLY : O_RDWR);
  60. if (fd_ == -1) {
  61. if (msg) {
  62. *msg = "open";
  63. }
  64. return kSystemError;
  65. }
  66. // Always close fd and unmap in case of failure along the way to avoid
  67. // check failure above if we leave fd != -1 and the object is recycled
  68. // like it is inside SignalSafeElfCache
  69. auto guard = makeGuard([&] { reset(); });
  70. struct stat st;
  71. int r = fstat(fd_, &st);
  72. if (r == -1) {
  73. if (msg) {
  74. *msg = "fstat";
  75. }
  76. return kSystemError;
  77. }
  78. length_ = st.st_size;
  79. int prot = PROT_READ;
  80. if (!readOnly) {
  81. prot |= PROT_WRITE;
  82. }
  83. file_ = static_cast<char*>(mmap(nullptr, length_, prot, MAP_SHARED, fd_, 0));
  84. if (file_ == MAP_FAILED) {
  85. if (msg) {
  86. *msg = "mmap";
  87. }
  88. return kSystemError;
  89. }
  90. if (!init(msg)) {
  91. reset();
  92. errno = EINVAL;
  93. return kInvalidElfFile;
  94. }
  95. guard.dismiss();
  96. return kSuccess;
  97. }
  98. int ElfFile::openAndFollow(
  99. const char* name,
  100. bool readOnly,
  101. const char** msg) noexcept {
  102. auto result = openNoThrow(name, readOnly, msg);
  103. if (!readOnly || result != kSuccess) {
  104. return result;
  105. }
  106. /* NOTE .gnu_debuglink specifies only the name of the debugging info file
  107. * (with no directory components). GDB checks 3 different directories, but
  108. * ElfFile only supports the first version:
  109. * - dirname(name)
  110. * - dirname(name) + /.debug/
  111. * - X/dirname(name)/ - where X is set in gdb's `debug-file-directory`.
  112. */
  113. auto dirend = strrchr(name, '/');
  114. // include ending '/' if any.
  115. auto dirlen = dirend != nullptr ? dirend + 1 - name : 0;
  116. auto debuginfo = getSectionByName(".gnu_debuglink");
  117. if (!debuginfo) {
  118. return result;
  119. }
  120. // The section starts with the filename, with any leading directory
  121. // components removed, followed by a zero byte.
  122. auto debugFileName = getSectionBody(*debuginfo);
  123. auto debugFileLen = strlen(debugFileName.begin());
  124. if (dirlen + debugFileLen >= PATH_MAX) {
  125. return result;
  126. }
  127. char linkname[PATH_MAX];
  128. memcpy(linkname, name, dirlen);
  129. memcpy(linkname + dirlen, debugFileName.begin(), debugFileLen + 1);
  130. reset();
  131. result = openNoThrow(linkname, readOnly, msg);
  132. if (result == kSuccess) {
  133. return result;
  134. }
  135. return openNoThrow(name, readOnly, msg);
  136. }
  137. ElfFile::~ElfFile() {
  138. reset();
  139. }
  140. ElfFile::ElfFile(ElfFile&& other) noexcept
  141. : fd_(other.fd_),
  142. file_(other.file_),
  143. length_(other.length_),
  144. baseAddress_(other.baseAddress_) {
  145. // copy other.filepath_, leaving filepath_ zero-terminated, always.
  146. strncat(filepath_, other.filepath_, kFilepathMaxLen - 1);
  147. other.filepath_[0] = 0;
  148. other.fd_ = -1;
  149. other.file_ = static_cast<char*>(MAP_FAILED);
  150. other.length_ = 0;
  151. other.baseAddress_ = 0;
  152. }
  153. ElfFile& ElfFile::operator=(ElfFile&& other) {
  154. assert(this != &other);
  155. reset();
  156. // copy other.filepath_, leaving filepath_ zero-terminated, always.
  157. strncat(filepath_, other.filepath_, kFilepathMaxLen - 1);
  158. fd_ = other.fd_;
  159. file_ = other.file_;
  160. length_ = other.length_;
  161. baseAddress_ = other.baseAddress_;
  162. other.filepath_[0] = 0;
  163. other.fd_ = -1;
  164. other.file_ = static_cast<char*>(MAP_FAILED);
  165. other.length_ = 0;
  166. other.baseAddress_ = 0;
  167. return *this;
  168. }
  169. void ElfFile::reset() {
  170. filepath_[0] = 0;
  171. if (file_ != MAP_FAILED) {
  172. munmap(file_, length_);
  173. file_ = static_cast<char*>(MAP_FAILED);
  174. }
  175. if (fd_ != -1) {
  176. close(fd_);
  177. fd_ = -1;
  178. }
  179. }
  180. bool ElfFile::init(const char** msg) {
  181. if (length_ < 4) {
  182. if (msg) {
  183. *msg = "not an ELF file (too short)";
  184. }
  185. return false;
  186. }
  187. std::array<char, 5> elfMagBuf = {{0, 0, 0, 0, 0}};
  188. if (::lseek(fd_, 0, SEEK_SET) != 0 || ::read(fd_, elfMagBuf.data(), 4) != 4) {
  189. if (msg) {
  190. *msg = "unable to read ELF file for magic number";
  191. }
  192. return false;
  193. }
  194. if (std::strncmp(elfMagBuf.data(), ELFMAG, sizeof(ELFMAG)) != 0) {
  195. if (msg) {
  196. *msg = "invalid ELF magic";
  197. }
  198. return false;
  199. }
  200. if (::lseek(fd_, 0, SEEK_SET) != 0) {
  201. if (msg) {
  202. *msg = "unable to reset file descriptor after reading ELF magic number";
  203. }
  204. return false;
  205. }
  206. auto& elfHeader = this->elfHeader();
  207. #define EXPECTED_CLASS P1(ELFCLASS, __ELF_NATIVE_CLASS)
  208. #define P1(a, b) P2(a, b)
  209. #define P2(a, b) a##b
  210. // Validate ELF class (32/64 bits)
  211. if (elfHeader.e_ident[EI_CLASS] != EXPECTED_CLASS) {
  212. if (msg) {
  213. *msg = "invalid ELF class";
  214. }
  215. return false;
  216. }
  217. #undef P1
  218. #undef P2
  219. #undef EXPECTED_CLASS
  220. // Validate ELF data encoding (LSB/MSB)
  221. static constexpr auto kExpectedEncoding =
  222. kIsLittleEndian ? ELFDATA2LSB : ELFDATA2MSB;
  223. if (elfHeader.e_ident[EI_DATA] != kExpectedEncoding) {
  224. if (msg) {
  225. *msg = "invalid ELF encoding";
  226. }
  227. return false;
  228. }
  229. // Validate ELF version (1)
  230. if (elfHeader.e_ident[EI_VERSION] != EV_CURRENT ||
  231. elfHeader.e_version != EV_CURRENT) {
  232. if (msg) {
  233. *msg = "invalid ELF version";
  234. }
  235. return false;
  236. }
  237. // We only support executable and shared object files
  238. if (elfHeader.e_type != ET_EXEC && elfHeader.e_type != ET_DYN) {
  239. if (msg) {
  240. *msg = "invalid ELF file type";
  241. }
  242. return false;
  243. }
  244. if (elfHeader.e_phnum == 0) {
  245. if (msg) {
  246. *msg = "no program header!";
  247. }
  248. return false;
  249. }
  250. if (elfHeader.e_phentsize != sizeof(ElfPhdr)) {
  251. if (msg) {
  252. *msg = "invalid program header entry size";
  253. }
  254. return false;
  255. }
  256. if (elfHeader.e_shentsize != sizeof(ElfShdr)) {
  257. if (msg) {
  258. *msg = "invalid section header entry size";
  259. }
  260. }
  261. // Program headers are sorted by load address, so the first PT_LOAD
  262. // header gives us the base address.
  263. const ElfPhdr* programHeader =
  264. iterateProgramHeaders([](auto& h) { return h.p_type == PT_LOAD; });
  265. if (!programHeader) {
  266. if (msg) {
  267. *msg = "could not find base address";
  268. }
  269. return false;
  270. }
  271. baseAddress_ = programHeader->p_vaddr;
  272. return true;
  273. }
  274. const ElfShdr* ElfFile::getSectionByIndex(size_t idx) const {
  275. FOLLY_SAFE_CHECK(idx < elfHeader().e_shnum, "invalid section index");
  276. return &at<ElfShdr>(elfHeader().e_shoff + idx * sizeof(ElfShdr));
  277. }
  278. folly::StringPiece ElfFile::getSectionBody(const ElfShdr& section) const {
  279. return folly::StringPiece(file_ + section.sh_offset, section.sh_size);
  280. }
  281. void ElfFile::validateStringTable(const ElfShdr& stringTable) const {
  282. FOLLY_SAFE_CHECK(
  283. stringTable.sh_type == SHT_STRTAB, "invalid type for string table");
  284. const char* start = file_ + stringTable.sh_offset;
  285. // First and last bytes must be 0
  286. FOLLY_SAFE_CHECK(
  287. stringTable.sh_size == 0 ||
  288. (start[0] == '\0' && start[stringTable.sh_size - 1] == '\0'),
  289. "invalid string table");
  290. }
  291. const char* ElfFile::getString(const ElfShdr& stringTable, size_t offset)
  292. const {
  293. validateStringTable(stringTable);
  294. FOLLY_SAFE_CHECK(
  295. offset < stringTable.sh_size, "invalid offset in string table");
  296. return file_ + stringTable.sh_offset + offset;
  297. }
  298. const char* ElfFile::getSectionName(const ElfShdr& section) const {
  299. if (elfHeader().e_shstrndx == SHN_UNDEF) {
  300. return nullptr; // no section name string table
  301. }
  302. const ElfShdr& sectionNames = *getSectionByIndex(elfHeader().e_shstrndx);
  303. return getString(sectionNames, section.sh_name);
  304. }
  305. const ElfShdr* ElfFile::getSectionByName(const char* name) const {
  306. if (elfHeader().e_shstrndx == SHN_UNDEF) {
  307. return nullptr; // no section name string table
  308. }
  309. const ElfShdr& sectionNames = *getSectionByIndex(elfHeader().e_shstrndx);
  310. const char* start = file_ + sectionNames.sh_offset;
  311. // Find section with the appropriate sh_name offset
  312. const ElfShdr* foundSection = iterateSections([&](const ElfShdr& sh) {
  313. if (sh.sh_name >= sectionNames.sh_size) {
  314. return false;
  315. }
  316. return !strcmp(start + sh.sh_name, name);
  317. });
  318. return foundSection;
  319. }
  320. ElfFile::Symbol ElfFile::getDefinitionByAddress(uintptr_t address) const {
  321. Symbol foundSymbol{nullptr, nullptr};
  322. auto findSection = [&](const ElfShdr& section) {
  323. auto findSymbols = [&](const ElfSym& sym) {
  324. if (sym.st_shndx == SHN_UNDEF) {
  325. return false; // not a definition
  326. }
  327. if (address >= sym.st_value && address < sym.st_value + sym.st_size) {
  328. foundSymbol.first = &section;
  329. foundSymbol.second = &sym;
  330. return true;
  331. }
  332. return false;
  333. };
  334. return iterateSymbolsWithTypes(
  335. section, {STT_OBJECT, STT_FUNC, STT_GNU_IFUNC}, findSymbols);
  336. };
  337. // Try the .dynsym section first if it exists, it's smaller.
  338. (iterateSectionsWithType(SHT_DYNSYM, findSection) ||
  339. iterateSectionsWithType(SHT_SYMTAB, findSection));
  340. return foundSymbol;
  341. }
  342. ElfFile::Symbol ElfFile::getSymbolByName(const char* name) const {
  343. Symbol foundSymbol{nullptr, nullptr};
  344. auto findSection = [&](const ElfShdr& section) -> bool {
  345. // This section has no string table associated w/ its symbols; hence we
  346. // can't get names for them
  347. if (section.sh_link == SHN_UNDEF) {
  348. return false;
  349. }
  350. auto findSymbols = [&](const ElfSym& sym) -> bool {
  351. if (sym.st_shndx == SHN_UNDEF) {
  352. return false; // not a definition
  353. }
  354. if (sym.st_name == 0) {
  355. return false; // no name for this symbol
  356. }
  357. const char* sym_name =
  358. getString(*getSectionByIndex(section.sh_link), sym.st_name);
  359. if (strcmp(sym_name, name) == 0) {
  360. foundSymbol.first = &section;
  361. foundSymbol.second = &sym;
  362. return true;
  363. }
  364. return false;
  365. };
  366. return iterateSymbolsWithTypes(
  367. section, {STT_OBJECT, STT_FUNC, STT_GNU_IFUNC}, findSymbols);
  368. };
  369. // Try the .dynsym section first if it exists, it's smaller.
  370. iterateSectionsWithType(SHT_DYNSYM, findSection) ||
  371. iterateSectionsWithType(SHT_SYMTAB, findSection);
  372. return foundSymbol;
  373. }
  374. const ElfShdr* ElfFile::getSectionContainingAddress(ElfAddr addr) const {
  375. return iterateSections([&](const ElfShdr& sh) -> bool {
  376. return (addr >= sh.sh_addr) && (addr < (sh.sh_addr + sh.sh_size));
  377. });
  378. }
  379. const char* ElfFile::getSymbolName(Symbol symbol) const {
  380. if (!symbol.first || !symbol.second) {
  381. return nullptr;
  382. }
  383. if (symbol.second->st_name == 0) {
  384. return nullptr; // symbol has no name
  385. }
  386. if (symbol.first->sh_link == SHN_UNDEF) {
  387. return nullptr; // symbol table has no strings
  388. }
  389. return getString(
  390. *getSectionByIndex(symbol.first->sh_link), symbol.second->st_name);
  391. }
  392. } // namespace symbolizer
  393. } // namespace folly