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