Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:30:43

0001 // Copyright 2014 Renato Tegon Forti, Antony Polukhin.
0002 // Copyright Antony Polukhin, 2015-2023.
0003 //
0004 // Distributed under the Boost Software License, Version 1.0.
0005 // (See accompanying file LICENSE_1_0.txt
0006 // or copy at http://www.boost.org/LICENSE_1_0.txt)
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];    /* Magic number and other info */
0030   boost::uint16_t   e_type;         /* Object file type */
0031   boost::uint16_t   e_machine;      /* Architecture */
0032   boost::uint32_t   e_version;      /* Object file version */
0033   AddressOffsetT    e_entry;        /* Entry point virtual address */
0034   AddressOffsetT    e_phoff;        /* Program header table file offset */
0035   AddressOffsetT    e_shoff;        /* Section header table file offset */
0036   boost::uint32_t   e_flags;        /* Processor-specific flags */
0037   boost::uint16_t   e_ehsize;       /* ELF header size in bytes */
0038   boost::uint16_t   e_phentsize;    /* Program header table entry size */
0039   boost::uint16_t   e_phnum;        /* Program header table entry count */
0040   boost::uint16_t   e_shentsize;    /* Section header table entry size */
0041   boost::uint16_t   e_shnum;        /* Section header table entry count */
0042   boost::uint16_t   e_shstrndx;     /* Section header string table index */
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;        /* Section name (string tbl index) */
0051   boost::uint32_t   sh_type;        /* Section type */
0052   AddressOffsetT    sh_flags;       /* Section flags */
0053   AddressOffsetT    sh_addr;        /* Section virtual addr at execution */
0054   AddressOffsetT    sh_offset;      /* Section file offset */
0055   AddressOffsetT    sh_size;        /* Section size in bytes */
0056   boost::uint32_t   sh_link;        /* Link to another section */
0057   boost::uint32_t   sh_info;        /* Additional section information */
0058   AddressOffsetT    sh_addralign;   /* Section alignment */
0059   AddressOffsetT    sh_entsize;     /* Entry size if section holds table */
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;    /* Symbol name (string tbl index) */
0073   AddressOffsetT    st_value;   /* Symbol value */
0074   AddressOffsetT    st_size;    /* Symbol size */
0075   unsigned char     st_info;    /* Symbol type and binding */
0076   unsigned char     st_other;   /* Symbol visibility */
0077   boost::uint16_t   st_shndx;   /* Section index */
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;    /* Symbol name (string tbl index) */
0085   unsigned char     st_info;    /* Symbol type and binding */
0086   unsigned char     st_other;   /* Symbol visibility */
0087   boost::uint16_t   st_shndx;   /* Section index */
0088   AddressOffsetT    st_value;   /* Symbol value */
0089   AddressOffsetT    st_size;    /* Symbol 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);   /* Local symbol */
0107     BOOST_STATIC_CONSTANT(unsigned char, STB_GLOBAL_ = 1);  /* Global symbol */
0108     BOOST_STATIC_CONSTANT(unsigned char, STB_WEAK_ = 2);    /* Weak symbol */
0109 
0110     /* Symbol visibility specification encoded in the st_other field.  */
0111     BOOST_STATIC_CONSTANT(unsigned char, STV_DEFAULT_ = 0);      /* Default symbol visibility rules */
0112     BOOST_STATIC_CONSTANT(unsigned char, STV_INTERNAL_ = 1);     /* Processor specific hidden class */
0113     BOOST_STATIC_CONSTANT(unsigned char, STV_HIDDEN_ = 2);       /* Sym unavailable in other modules */
0114     BOOST_STATIC_CONSTANT(unsigned char, STV_PROTECTED_ = 3);    /* Not preemptible, not exported */
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         /* TODO: use cmp_less, cmp_greater
0158         if ((std::numeric_limits<std::streamoff>::max)() < pos) {
0159             boost::throw_exception(std::runtime_error("Integral overflow while getting info from ELF file"));
0160         }
0161         if ((std::numeric_limits<std::streamoff>::min)() > pos){
0162             boost::throw_exception(std::runtime_error("Integral underflow while getting info from ELF file"));
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         // ".dynsym" section may not have info on symbols that could be used while self loading an executable,
0205         // so we prefer ".symtab" section.
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             // ".symtab" stripped from the binary and we have to fallback to ".dynsym"
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         // `(sym.st_info >> 4) != STB_LOCAL_ && !!sym.st_size` check also workarounds the
0265         // GCC's issue https://sourceware.org/bugzilla/show_bug.cgi?id=13621
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(); // Do not show empty names
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(); // Do not show empty names
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 }}} // namespace boost::dll::detail
0343 
0344 #endif // BOOST_DLL_DETAIL_POSIX_ELF_INFO_HPP