File indexing completed on 2025-01-18 09:30:43
0001
0002
0003
0004
0005
0006
0007
0008 #ifndef BOOST_DLL_DETAIL_POSIX_ELF_INFO_HPP
0009 #define BOOST_DLL_DETAIL_POSIX_ELF_INFO_HPP
0010
0011 #include <boost/dll/config.hpp>
0012
0013 #ifdef BOOST_HAS_PRAGMA_ONCE
0014 # pragma once
0015 #endif
0016
0017 #include <cstring>
0018 #include <fstream>
0019 #include <limits>
0020 #include <vector>
0021
0022 #include <boost/cstdint.hpp>
0023 #include <boost/throw_exception.hpp>
0024
0025 namespace boost { namespace dll { namespace detail {
0026
0027 template <class AddressOffsetT>
0028 struct Elf_Ehdr_template {
0029 unsigned char e_ident[16];
0030 boost::uint16_t e_type;
0031 boost::uint16_t e_machine;
0032 boost::uint32_t e_version;
0033 AddressOffsetT e_entry;
0034 AddressOffsetT e_phoff;
0035 AddressOffsetT e_shoff;
0036 boost::uint32_t e_flags;
0037 boost::uint16_t e_ehsize;
0038 boost::uint16_t e_phentsize;
0039 boost::uint16_t e_phnum;
0040 boost::uint16_t e_shentsize;
0041 boost::uint16_t e_shnum;
0042 boost::uint16_t e_shstrndx;
0043 };
0044
0045 typedef Elf_Ehdr_template<boost::uint32_t> Elf32_Ehdr_;
0046 typedef Elf_Ehdr_template<boost::uint64_t> Elf64_Ehdr_;
0047
0048 template <class AddressOffsetT>
0049 struct Elf_Shdr_template {
0050 boost::uint32_t sh_name;
0051 boost::uint32_t sh_type;
0052 AddressOffsetT sh_flags;
0053 AddressOffsetT sh_addr;
0054 AddressOffsetT sh_offset;
0055 AddressOffsetT sh_size;
0056 boost::uint32_t sh_link;
0057 boost::uint32_t sh_info;
0058 AddressOffsetT sh_addralign;
0059 AddressOffsetT sh_entsize;
0060 };
0061
0062 typedef Elf_Shdr_template<boost::uint32_t> Elf32_Shdr_;
0063 typedef Elf_Shdr_template<boost::uint64_t> Elf64_Shdr_;
0064
0065 template <class AddressOffsetT>
0066 struct Elf_Sym_template;
0067
0068 template <>
0069 struct Elf_Sym_template<boost::uint32_t> {
0070 typedef boost::uint32_t AddressOffsetT;
0071
0072 boost::uint32_t st_name;
0073 AddressOffsetT st_value;
0074 AddressOffsetT st_size;
0075 unsigned char st_info;
0076 unsigned char st_other;
0077 boost::uint16_t st_shndx;
0078 };
0079
0080 template <>
0081 struct Elf_Sym_template<boost::uint64_t> {
0082 typedef boost::uint64_t AddressOffsetT;
0083
0084 boost::uint32_t st_name;
0085 unsigned char st_info;
0086 unsigned char st_other;
0087 boost::uint16_t st_shndx;
0088 AddressOffsetT st_value;
0089 AddressOffsetT st_size;
0090 };
0091
0092
0093 typedef Elf_Sym_template<boost::uint32_t> Elf32_Sym_;
0094 typedef Elf_Sym_template<boost::uint64_t> Elf64_Sym_;
0095
0096 template <class AddressOffsetT>
0097 class elf_info {
0098 typedef boost::dll::detail::Elf_Ehdr_template<AddressOffsetT> header_t;
0099 typedef boost::dll::detail::Elf_Shdr_template<AddressOffsetT> section_t;
0100 typedef boost::dll::detail::Elf_Sym_template<AddressOffsetT> symbol_t;
0101
0102 BOOST_STATIC_CONSTANT(boost::uint32_t, SHT_SYMTAB_ = 2);
0103 BOOST_STATIC_CONSTANT(boost::uint32_t, SHT_STRTAB_ = 3);
0104 BOOST_STATIC_CONSTANT(boost::uint32_t, SHT_DYNSYM_ = 11);
0105
0106 BOOST_STATIC_CONSTANT(unsigned char, STB_LOCAL_ = 0);
0107 BOOST_STATIC_CONSTANT(unsigned char, STB_GLOBAL_ = 1);
0108 BOOST_STATIC_CONSTANT(unsigned char, STB_WEAK_ = 2);
0109
0110
0111 BOOST_STATIC_CONSTANT(unsigned char, STV_DEFAULT_ = 0);
0112 BOOST_STATIC_CONSTANT(unsigned char, STV_INTERNAL_ = 1);
0113 BOOST_STATIC_CONSTANT(unsigned char, STV_HIDDEN_ = 2);
0114 BOOST_STATIC_CONSTANT(unsigned char, STV_PROTECTED_ = 3);
0115
0116 public:
0117 static bool parsing_supported(std::ifstream& fs) {
0118 const unsigned char magic_bytes[5] = {
0119 0x7f, 'E', 'L', 'F', sizeof(boost::uint32_t) == sizeof(AddressOffsetT) ? 1 : 2
0120 };
0121
0122 unsigned char ch;
0123 fs.seekg(0);
0124 for (std::size_t i = 0; i < sizeof(magic_bytes); ++i) {
0125 fs >> ch;
0126 if (ch != magic_bytes[i]) {
0127 return false;
0128 }
0129 }
0130
0131 return true;
0132 }
0133
0134 static std::vector<std::string> sections(std::ifstream& fs) {
0135 std::vector<std::string> ret;
0136 std::vector<char> names;
0137 sections_names_raw(fs, names);
0138
0139 const char* name_begin = &names[0];
0140 const char* const name_end = name_begin + names.size();
0141 ret.reserve(header(fs).e_shnum);
0142 do {
0143 if (*name_begin) {
0144 ret.push_back(name_begin);
0145 name_begin += ret.back().size() + 1;
0146 } else {
0147 ++name_begin;
0148 }
0149 } while (name_begin != name_end);
0150
0151 return ret;
0152 }
0153
0154 private:
0155 template <class Integer>
0156 static void checked_seekg(std::ifstream& fs, Integer pos) {
0157
0158
0159
0160
0161
0162
0163
0164
0165 fs.seekg(static_cast<std::streamoff>(pos));
0166 }
0167
0168 template <class T>
0169 static void read_raw(std::ifstream& fs, T& value, std::size_t size = sizeof(T)) {
0170 fs.read(reinterpret_cast<char*>(&value), size);
0171 }
0172
0173 static header_t header(std::ifstream& fs) {
0174 header_t elf;
0175
0176 fs.seekg(0);
0177 read_raw(fs, elf);
0178
0179 return elf;
0180 }
0181
0182 static void sections_names_raw(std::ifstream& fs, std::vector<char>& sections) {
0183 const header_t elf = header(fs);
0184
0185 section_t section_names_section;
0186 checked_seekg(fs, elf.e_shoff + elf.e_shstrndx * sizeof(section_t));
0187 read_raw(fs, section_names_section);
0188
0189 sections.resize(static_cast<std::size_t>(section_names_section.sh_size) + 1, '\0');
0190 checked_seekg(fs, section_names_section.sh_offset);
0191 read_raw(fs, sections[0], static_cast<std::size_t>(section_names_section.sh_size));
0192 }
0193
0194 static void symbols_text(std::ifstream& fs, std::vector<symbol_t>& symbols, std::vector<char>& text) {
0195 std::vector<char> names;
0196 sections_names_raw(fs, names);
0197 symbols_text(fs, symbols, text, names);
0198 }
0199
0200 static void symbols_text(std::ifstream& fs, std::vector<symbol_t>& symbols, std::vector<char>& text, const std::vector<char>& names) {
0201 const header_t elf = header(fs);
0202 checked_seekg(fs, elf.e_shoff);
0203
0204
0205
0206 AddressOffsetT symtab_size = 0;
0207 AddressOffsetT symtab_offset = 0;
0208 AddressOffsetT strtab_size = 0;
0209 AddressOffsetT strtab_offset = 0;
0210
0211 AddressOffsetT dynsym_size = 0;
0212 AddressOffsetT dynsym_offset = 0;
0213 AddressOffsetT dynstr_size = 0;
0214 AddressOffsetT dynstr_offset = 0;
0215
0216 for (std::size_t i = 0; i < elf.e_shnum; ++i) {
0217 section_t section;
0218 read_raw(fs, section);
0219 if (section.sh_name >= names.size()) {
0220 continue;
0221 }
0222 const char* name = &names[section.sh_name];
0223
0224 if (section.sh_type == SHT_SYMTAB_ && !std::strcmp(name, ".symtab")) {
0225 symtab_size = section.sh_size;
0226 symtab_offset = section.sh_offset;
0227 } else if (section.sh_type == SHT_STRTAB_) {
0228 if (!std::strcmp(name, ".dynstr")) {
0229 dynstr_size = section.sh_size;
0230 dynstr_offset = section.sh_offset;
0231 } else if (!std::strcmp(name, ".strtab")) {
0232 strtab_size = section.sh_size;
0233 strtab_offset = section.sh_offset;
0234 }
0235 } else if (section.sh_type == SHT_DYNSYM_ && !std::strcmp(name, ".dynsym")) {
0236 dynsym_size = section.sh_size;
0237 dynsym_offset = section.sh_offset;
0238 }
0239 }
0240
0241 if (!symtab_size || !strtab_size) {
0242
0243 symtab_size = dynsym_size;
0244 symtab_offset = dynsym_offset;
0245 strtab_size = dynstr_size;
0246 strtab_offset = dynstr_offset;
0247 }
0248
0249 if (!symtab_size || !strtab_size) {
0250 return;
0251 }
0252
0253 text.resize(static_cast<std::size_t>(strtab_size) + 1, '\0');
0254 checked_seekg(fs, strtab_offset);
0255 read_raw(fs, text[0], static_cast<std::size_t>(strtab_size));
0256
0257 symbols.resize(static_cast<std::size_t>(symtab_size / sizeof(symbol_t)));
0258 checked_seekg(fs, symtab_offset);
0259 read_raw(fs, symbols[0], static_cast<std::size_t>(symtab_size - (symtab_size % sizeof(symbol_t))) );
0260 }
0261
0262 static bool is_visible(const symbol_t& sym) BOOST_NOEXCEPT {
0263 const unsigned char visibility = (sym.st_other & 0x03);
0264
0265
0266 return (visibility == STV_DEFAULT_ || visibility == STV_PROTECTED_)
0267 && (sym.st_info >> 4) != STB_LOCAL_ && !!sym.st_size;
0268 }
0269
0270 public:
0271 static std::vector<std::string> symbols(std::ifstream& fs) {
0272 std::vector<std::string> ret;
0273
0274 std::vector<symbol_t> symbols;
0275 std::vector<char> text;
0276 symbols_text(fs, symbols, text);
0277
0278 ret.reserve(symbols.size());
0279 for (std::size_t i = 0; i < symbols.size(); ++i) {
0280 if (is_visible(symbols[i]) && symbols[i].st_name < text.size()) {
0281 ret.push_back(&text[symbols[i].st_name]);
0282 if (ret.back().empty()) {
0283 ret.pop_back();
0284 }
0285 }
0286 }
0287
0288 return ret;
0289 }
0290
0291 static std::vector<std::string> symbols(std::ifstream& fs, const char* section_name) {
0292 std::vector<std::string> ret;
0293
0294 std::size_t index = 0;
0295 std::size_t ptrs_in_section_count = 0;
0296
0297 std::vector<char> names;
0298 sections_names_raw(fs, names);
0299
0300 const header_t elf = header(fs);
0301
0302 for (; index < elf.e_shnum; ++index) {
0303 section_t section;
0304 checked_seekg(fs, elf.e_shoff + index * sizeof(section_t));
0305 read_raw(fs, section);
0306
0307 if (!std::strcmp(&names.at(section.sh_name), section_name)) {
0308 if (!section.sh_entsize) {
0309 section.sh_entsize = 1;
0310 }
0311 ptrs_in_section_count = static_cast<std::size_t>(section.sh_size / section.sh_entsize);
0312 break;
0313 }
0314 }
0315
0316 std::vector<symbol_t> symbols;
0317 std::vector<char> text;
0318 symbols_text(fs, symbols, text, names);
0319
0320 if (ptrs_in_section_count < symbols.size()) {
0321 ret.reserve(ptrs_in_section_count);
0322 } else {
0323 ret.reserve(symbols.size());
0324 }
0325
0326 for (std::size_t i = 0; i < symbols.size(); ++i) {
0327 if (symbols[i].st_shndx == index && is_visible(symbols[i]) && symbols[i].st_name < text.size()) {
0328 ret.push_back(&text[symbols[i].st_name]);
0329 if (ret.back().empty()) {
0330 ret.pop_back();
0331 }
0332 }
0333 }
0334
0335 return ret;
0336 }
0337 };
0338
0339 typedef elf_info<boost::uint32_t> elf_info32;
0340 typedef elf_info<boost::uint64_t> elf_info64;
0341
0342 }}}
0343
0344 #endif