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