elf_info.hpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. // Copyright 2014 Renato Tegon Forti, Antony Polukhin.
  2. // Copyright 2015-2019 Antony Polukhin.
  3. //
  4. // Distributed under the Boost Software License, Version 1.0.
  5. // (See accompanying file LICENSE_1_0.txt
  6. // or copy at http://www.boost.org/LICENSE_1_0.txt)
  7. #ifndef BOOST_DLL_DETAIL_POSIX_ELF_INFO_HPP
  8. #define BOOST_DLL_DETAIL_POSIX_ELF_INFO_HPP
  9. #include <boost/dll/config.hpp>
  10. #ifdef BOOST_HAS_PRAGMA_ONCE
  11. # pragma once
  12. #endif
  13. #include <cstring>
  14. #include <fstream>
  15. #include <boost/cstdint.hpp>
  16. #include <boost/dll/detail/x_info_interface.hpp>
  17. namespace boost { namespace dll { namespace detail {
  18. template <class AddressOffsetT>
  19. struct Elf_Ehdr_template {
  20. unsigned char e_ident[16]; /* Magic number and other info */
  21. boost::uint16_t e_type; /* Object file type */
  22. boost::uint16_t e_machine; /* Architecture */
  23. boost::uint32_t e_version; /* Object file version */
  24. AddressOffsetT e_entry; /* Entry point virtual address */
  25. AddressOffsetT e_phoff; /* Program header table file offset */
  26. AddressOffsetT e_shoff; /* Section header table file offset */
  27. boost::uint32_t e_flags; /* Processor-specific flags */
  28. boost::uint16_t e_ehsize; /* ELF header size in bytes */
  29. boost::uint16_t e_phentsize; /* Program header table entry size */
  30. boost::uint16_t e_phnum; /* Program header table entry count */
  31. boost::uint16_t e_shentsize; /* Section header table entry size */
  32. boost::uint16_t e_shnum; /* Section header table entry count */
  33. boost::uint16_t e_shstrndx; /* Section header string table index */
  34. };
  35. typedef Elf_Ehdr_template<boost::uint32_t> Elf32_Ehdr_;
  36. typedef Elf_Ehdr_template<boost::uint64_t> Elf64_Ehdr_;
  37. template <class AddressOffsetT>
  38. struct Elf_Shdr_template {
  39. boost::uint32_t sh_name; /* Section name (string tbl index) */
  40. boost::uint32_t sh_type; /* Section type */
  41. AddressOffsetT sh_flags; /* Section flags */
  42. AddressOffsetT sh_addr; /* Section virtual addr at execution */
  43. AddressOffsetT sh_offset; /* Section file offset */
  44. AddressOffsetT sh_size; /* Section size in bytes */
  45. boost::uint32_t sh_link; /* Link to another section */
  46. boost::uint32_t sh_info; /* Additional section information */
  47. AddressOffsetT sh_addralign; /* Section alignment */
  48. AddressOffsetT sh_entsize; /* Entry size if section holds table */
  49. };
  50. typedef Elf_Shdr_template<boost::uint32_t> Elf32_Shdr_;
  51. typedef Elf_Shdr_template<boost::uint64_t> Elf64_Shdr_;
  52. template <class AddressOffsetT>
  53. struct Elf_Sym_template;
  54. template <>
  55. struct Elf_Sym_template<boost::uint32_t> {
  56. typedef boost::uint32_t AddressOffsetT;
  57. boost::uint32_t st_name; /* Symbol name (string tbl index) */
  58. AddressOffsetT st_value; /* Symbol value */
  59. AddressOffsetT st_size; /* Symbol size */
  60. unsigned char st_info; /* Symbol type and binding */
  61. unsigned char st_other; /* Symbol visibility */
  62. boost::uint16_t st_shndx; /* Section index */
  63. };
  64. template <>
  65. struct Elf_Sym_template<boost::uint64_t> {
  66. typedef boost::uint64_t AddressOffsetT;
  67. boost::uint32_t st_name; /* Symbol name (string tbl index) */
  68. unsigned char st_info; /* Symbol type and binding */
  69. unsigned char st_other; /* Symbol visibility */
  70. boost::uint16_t st_shndx; /* Section index */
  71. AddressOffsetT st_value; /* Symbol value */
  72. AddressOffsetT st_size; /* Symbol size */
  73. };
  74. typedef Elf_Sym_template<boost::uint32_t> Elf32_Sym_;
  75. typedef Elf_Sym_template<boost::uint64_t> Elf64_Sym_;
  76. template <class AddressOffsetT>
  77. class elf_info: public x_info_interface {
  78. std::ifstream& f_;
  79. typedef boost::dll::detail::Elf_Ehdr_template<AddressOffsetT> header_t;
  80. typedef boost::dll::detail::Elf_Shdr_template<AddressOffsetT> section_t;
  81. typedef boost::dll::detail::Elf_Sym_template<AddressOffsetT> symbol_t;
  82. BOOST_STATIC_CONSTANT(boost::uint32_t, SHT_SYMTAB_ = 2);
  83. BOOST_STATIC_CONSTANT(boost::uint32_t, SHT_STRTAB_ = 3);
  84. BOOST_STATIC_CONSTANT(unsigned char, STB_LOCAL_ = 0); /* Local symbol */
  85. BOOST_STATIC_CONSTANT(unsigned char, STB_GLOBAL_ = 1); /* Global symbol */
  86. BOOST_STATIC_CONSTANT(unsigned char, STB_WEAK_ = 2); /* Weak symbol */
  87. /* Symbol visibility specification encoded in the st_other field. */
  88. BOOST_STATIC_CONSTANT(unsigned char, STV_DEFAULT_ = 0); /* Default symbol visibility rules */
  89. BOOST_STATIC_CONSTANT(unsigned char, STV_INTERNAL_ = 1); /* Processor specific hidden class */
  90. BOOST_STATIC_CONSTANT(unsigned char, STV_HIDDEN_ = 2); /* Sym unavailable in other modules */
  91. BOOST_STATIC_CONSTANT(unsigned char, STV_PROTECTED_ = 3); /* Not preemptible, not exported */
  92. public:
  93. static bool parsing_supported(std::ifstream& f) {
  94. const unsigned char magic_bytes[5] = {
  95. 0x7f, 'E', 'L', 'F', sizeof(boost::uint32_t) == sizeof(AddressOffsetT) ? 1 : 2
  96. };
  97. unsigned char ch;
  98. f.seekg(0);
  99. for (std::size_t i = 0; i < sizeof(magic_bytes); ++i) {
  100. f >> ch;
  101. if (ch != magic_bytes[i]) {
  102. return false;
  103. }
  104. }
  105. return true;
  106. }
  107. explicit elf_info(std::ifstream& f) BOOST_NOEXCEPT
  108. : f_(f)
  109. {}
  110. std::vector<std::string> sections() {
  111. std::vector<std::string> ret;
  112. std::vector<char> names;
  113. sections_names_raw(names);
  114. const char* name_begin = &names[0];
  115. const char* const name_end = name_begin + names.size();
  116. ret.reserve(header().e_shnum);
  117. do {
  118. ret.push_back(name_begin);
  119. name_begin += ret.back().size() + 1;
  120. } while (name_begin != name_end);
  121. return ret;
  122. }
  123. private:
  124. template <class T>
  125. inline void read_raw(T& value, std::size_t size = sizeof(T)) const {
  126. f_.read(reinterpret_cast<char*>(&value), size);
  127. }
  128. inline header_t header() {
  129. header_t elf;
  130. f_.seekg(0);
  131. read_raw(elf);
  132. return elf;
  133. }
  134. void sections_names_raw(std::vector<char>& sections) {
  135. const header_t elf = header();
  136. section_t section_names_section;
  137. f_.seekg(elf.e_shoff + elf.e_shstrndx * sizeof(section_t));
  138. read_raw(section_names_section);
  139. sections.resize(static_cast<std::size_t>(section_names_section.sh_size));
  140. f_.seekg(section_names_section.sh_offset);
  141. read_raw(sections[0], static_cast<std::size_t>(section_names_section.sh_size));
  142. }
  143. void symbols_text(std::vector<symbol_t>& symbols, std::vector<char>& text) {
  144. const header_t elf = header();
  145. f_.seekg(elf.e_shoff);
  146. for (std::size_t i = 0; i < elf.e_shnum; ++i) {
  147. section_t section;
  148. read_raw(section);
  149. if (section.sh_type == SHT_SYMTAB_) {
  150. symbols.resize(static_cast<std::size_t>(section.sh_size / sizeof(symbol_t)));
  151. const std::ifstream::pos_type pos = f_.tellg();
  152. f_.seekg(section.sh_offset);
  153. read_raw(symbols[0], static_cast<std::size_t>(section.sh_size - (section.sh_size % sizeof(symbol_t))) );
  154. f_.seekg(pos);
  155. } else if (section.sh_type == SHT_STRTAB_) {
  156. text.resize(static_cast<std::size_t>(section.sh_size));
  157. const std::ifstream::pos_type pos = f_.tellg();
  158. f_.seekg(section.sh_offset);
  159. read_raw(text[0], static_cast<std::size_t>(section.sh_size));
  160. f_.seekg(pos);
  161. }
  162. }
  163. }
  164. static bool is_visible(const symbol_t& sym) BOOST_NOEXCEPT {
  165. // `(sym.st_info >> 4) != STB_LOCAL_ && !!sym.st_size` check also workarounds the
  166. // GCC's issue https://sourceware.org/bugzilla/show_bug.cgi?id=13621
  167. return (sym.st_other & 0x03) == STV_DEFAULT_ && (sym.st_info >> 4) != STB_LOCAL_ && !!sym.st_size;
  168. }
  169. public:
  170. std::vector<std::string> symbols() {
  171. std::vector<std::string> ret;
  172. std::vector<symbol_t> symbols;
  173. std::vector<char> text;
  174. symbols_text(symbols, text);
  175. ret.reserve(symbols.size());
  176. for (std::size_t i = 0; i < symbols.size(); ++i) {
  177. if (is_visible(symbols[i])) {
  178. ret.push_back(&text[0] + symbols[i].st_name);
  179. if (ret.back().empty()) {
  180. ret.pop_back(); // Do not show empty names
  181. }
  182. }
  183. }
  184. return ret;
  185. }
  186. std::vector<std::string> symbols(const char* section_name) {
  187. std::vector<std::string> ret;
  188. std::size_t index = 0;
  189. std::size_t ptrs_in_section_count = 0;
  190. {
  191. std::vector<char> names;
  192. sections_names_raw(names);
  193. const header_t elf = header();
  194. for (; index < elf.e_shnum; ++index) {
  195. section_t section;
  196. f_.seekg(elf.e_shoff + index * sizeof(section_t));
  197. read_raw(section);
  198. if (!std::strcmp(&names[0] + section.sh_name, section_name)) {
  199. if (!section.sh_entsize) {
  200. section.sh_entsize = 1;
  201. }
  202. ptrs_in_section_count = static_cast<std::size_t>(section.sh_size / section.sh_entsize);
  203. break;
  204. }
  205. }
  206. }
  207. std::vector<symbol_t> symbols;
  208. std::vector<char> text;
  209. symbols_text(symbols, text);
  210. if (ptrs_in_section_count < symbols.size()) {
  211. ret.reserve(ptrs_in_section_count);
  212. } else {
  213. ret.reserve(symbols.size());
  214. }
  215. for (std::size_t i = 0; i < symbols.size(); ++i) {
  216. if (symbols[i].st_shndx == index && is_visible(symbols[i])) {
  217. ret.push_back(&text[0] + symbols[i].st_name);
  218. if (ret.back().empty()) {
  219. ret.pop_back(); // Do not show empty names
  220. }
  221. }
  222. }
  223. return ret;
  224. }
  225. };
  226. typedef elf_info<boost::uint32_t> elf_info32;
  227. typedef elf_info<boost::uint64_t> elf_info64;
  228. }}} // namespace boost::dll::detail
  229. #endif // BOOST_DLL_DETAIL_POSIX_ELF_INFO_HPP