Back to home page

EIC code displayed by LXR

 
 

    


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

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_MACHO_INFO_HPP
0009 #define BOOST_DLL_DETAIL_MACHO_INFO_HPP
0010 
0011 #include <boost/dll/config.hpp>
0012 
0013 #ifdef BOOST_HAS_PRAGMA_ONCE
0014 # pragma once
0015 #endif
0016 
0017 #include <algorithm>
0018 #include <fstream>
0019 #include <string> // for std::getline
0020 #include <vector>
0021 
0022 #include <boost/cstdint.hpp>
0023 
0024 namespace boost { namespace dll { namespace detail {
0025 
0026 typedef int integer_t;
0027 typedef int vm_prot_t;
0028 typedef integer_t cpu_type_t;
0029 typedef integer_t cpu_subtype_t;
0030 
0031 template <class AddressOffsetT>
0032 struct mach_header_template {
0033     boost::uint32_t     magic;
0034     cpu_type_t          cputype;
0035     cpu_subtype_t       cpusubtype;
0036     boost::uint32_t     filetype;
0037     boost::uint32_t     ncmds;
0038     boost::uint32_t     sizeofcmds;
0039     boost::uint32_t     flags[sizeof(AddressOffsetT) / sizeof(uint32_t)]; // Flags and reserved
0040 };
0041 
0042 typedef mach_header_template<boost::uint32_t> mach_header_32_;
0043 typedef mach_header_template<boost::uint64_t> mach_header_64_;
0044 
0045 struct load_command_ {
0046     boost::uint32_t        cmd;        /* type of command */
0047     boost::uint32_t        cmdsize;
0048 };
0049 
0050 struct load_command_types {
0051     BOOST_STATIC_CONSTANT(boost::uint32_t, LC_SEGMENT_          = 0x1);   /* segment of this file to be mapped */
0052     BOOST_STATIC_CONSTANT(boost::uint32_t, LC_SYMTAB_           = 0x2);   /* link-edit stab symbol table info */
0053     BOOST_STATIC_CONSTANT(boost::uint32_t, LC_SYMSEG_           = 0x3);   /* link-edit gdb symbol table info (obsolete) */
0054     BOOST_STATIC_CONSTANT(boost::uint32_t, LC_THREAD_           = 0x4);   /* thread */
0055     BOOST_STATIC_CONSTANT(boost::uint32_t, LC_UNIXTHREAD_       = 0x5);   /* unix thread (includes a stack) */
0056     BOOST_STATIC_CONSTANT(boost::uint32_t, LC_LOADFVMLIB_       = 0x6);   /* load a specified fixed VM shared library */
0057     BOOST_STATIC_CONSTANT(boost::uint32_t, LC_IDFVMLIB_         = 0x7);   /* fixed VM shared library identification */
0058     BOOST_STATIC_CONSTANT(boost::uint32_t, LC_IDENT_            = 0x8);   /* object identification info (obsolete) */
0059     BOOST_STATIC_CONSTANT(boost::uint32_t, LC_FVMFILE_          = 0x9);   /* fixed VM file inclusion (internal use) */
0060     BOOST_STATIC_CONSTANT(boost::uint32_t, LC_PREPAGE_          = 0xa);   /* prepage command (internal use) */
0061     BOOST_STATIC_CONSTANT(boost::uint32_t, LC_DYSYMTAB_         = 0xb);   /* dynamic link-edit symbol table info */
0062     BOOST_STATIC_CONSTANT(boost::uint32_t, LC_LOAD_DYLIB_       = 0xc);   /* load a dynamically linked shared library */
0063     BOOST_STATIC_CONSTANT(boost::uint32_t, LC_ID_DYLIB_         = 0xd);   /* dynamically linked shared lib ident */
0064     BOOST_STATIC_CONSTANT(boost::uint32_t, LC_LOAD_DYLINKER_    = 0xe);   /* load a dynamic linker */
0065     BOOST_STATIC_CONSTANT(boost::uint32_t, LC_ID_DYLINKER_      = 0xf);   /* dynamic linker identification */
0066     BOOST_STATIC_CONSTANT(boost::uint32_t, LC_PREBOUND_DYLIB_   = 0x10);  /* modules prebound for a dynamically linked shared library */
0067     BOOST_STATIC_CONSTANT(boost::uint32_t, LC_ROUTINES_         = 0x11);  /* image routines */
0068     BOOST_STATIC_CONSTANT(boost::uint32_t, LC_SUB_FRAMEWORK_    = 0x12);  /* sub framework */
0069     BOOST_STATIC_CONSTANT(boost::uint32_t, LC_SUB_UMBRELLA_     = 0x13);  /* sub umbrella */
0070     BOOST_STATIC_CONSTANT(boost::uint32_t, LC_SUB_CLIENT_       = 0x14);  /* sub client */
0071     BOOST_STATIC_CONSTANT(boost::uint32_t, LC_SUB_LIBRARY_      = 0x15);  /* sub library */
0072     BOOST_STATIC_CONSTANT(boost::uint32_t, LC_TWOLEVEL_HINTS_   = 0x16);  /* two-level namespace lookup hints */
0073     BOOST_STATIC_CONSTANT(boost::uint32_t, LC_PREBIND_CKSUM_    = 0x17);  /* prebind checksum */
0074 /*
0075  * After MacOS X 10.1 when a new load command is added that is required to be
0076  * understood by the dynamic linker for the image to execute properly the
0077  * LC_REQ_DYLD bit will be or'ed into the load command constant.  If the dynamic
0078  * linker sees such a load command it it does not understand will issue a
0079  * "unknown load command required for execution" error and refuse to use the
0080  * image.  Other load commands without this bit that are not understood will
0081  * simply be ignored.
0082  */
0083     BOOST_STATIC_CONSTANT(boost::uint32_t, LC_REQ_DYLD_         = 0x80000000);
0084 
0085 /*
0086  * load a dynamically linked shared library that is allowed to be missing
0087  * (all symbols are weak imported).
0088  */
0089     BOOST_STATIC_CONSTANT(boost::uint32_t, LC_LOAD_WEAK_DYLIB_  = (0x18 | LC_REQ_DYLD_));
0090 
0091     BOOST_STATIC_CONSTANT(boost::uint32_t, LC_SEGMENT_64_       = 0x19);                    /* 64-bit segment of this file to be mapped */
0092     BOOST_STATIC_CONSTANT(boost::uint32_t, LC_ROUTINES_64_      = 0x1a);                    /* 64-bit image routines */
0093     BOOST_STATIC_CONSTANT(boost::uint32_t, LC_UUID_             = 0x1b);                    /* the uuid */
0094     BOOST_STATIC_CONSTANT(boost::uint32_t, LC_RPATH_            = (0x1c | LC_REQ_DYLD_));   /* runpath additions */
0095     BOOST_STATIC_CONSTANT(boost::uint32_t, LC_CODE_SIGNATURE_   = 0x1d);                    /* local of code signature */
0096     BOOST_STATIC_CONSTANT(boost::uint32_t, LC_SEGMENT_SPLIT_INFO_= 0x1e);                   /* local of info to split segments */
0097     BOOST_STATIC_CONSTANT(boost::uint32_t, LC_REEXPORT_DYLIB_   = (0x1f | LC_REQ_DYLD_));   /* load and re-export dylib */
0098     BOOST_STATIC_CONSTANT(boost::uint32_t, LC_LAZY_LOAD_DYLIB_  = 0x20);                    /* delay load of dylib until first use */
0099     BOOST_STATIC_CONSTANT(boost::uint32_t, LC_ENCRYPTION_INFO_  = 0x21);                    /* encrypted segment information */
0100     BOOST_STATIC_CONSTANT(boost::uint32_t, LC_DYLD_INFO_        = 0x22);                    /* compressed dyld information */
0101     BOOST_STATIC_CONSTANT(boost::uint32_t, LC_DYLD_INFO_ONLY_   = (0x22|LC_REQ_DYLD_));     /* compressed dyld information only */
0102 };
0103 
0104 template <class AddressOffsetT>
0105 struct segment_command_template {
0106     boost::uint32_t     cmd;            /* LC_SEGMENT_ */
0107     boost::uint32_t     cmdsize;        /* includes sizeof section structs */
0108     char                segname[16];    /* segment name */
0109     AddressOffsetT      vmaddr;         /* memory address of this segment */
0110     AddressOffsetT      vmsize;         /* memory size of this segment */
0111     AddressOffsetT      fileoff;        /* file offset of this segment */
0112     AddressOffsetT      filesize;       /* amount to map from the file */
0113     vm_prot_t           maxprot;        /* maximum VM protection */
0114     vm_prot_t           initprot;       /* initial VM protection */
0115     boost::uint32_t     nsects;         /* number of sections in segment */
0116     boost::uint32_t     flags;          /* flags */
0117 };
0118 
0119 typedef segment_command_template<boost::uint32_t> segment_command_32_;
0120 typedef segment_command_template<boost::uint64_t> segment_command_64_;
0121 
0122 template <class AddressOffsetT>
0123 struct section_template {
0124     char                sectname[16];   /* name of this section */
0125     char                segname[16];    /* segment this section goes in */
0126     AddressOffsetT      addr;           /* memory address of this section */
0127     AddressOffsetT      size;           /* size in bytes of this section */
0128     boost::uint32_t     offset;         /* file offset of this section */
0129     boost::uint32_t     align;          /* section alignment (power of 2) */
0130     boost::uint32_t     reloff;         /* file offset of relocation entries */
0131     boost::uint32_t     nreloc;         /* number of relocation entries */
0132     boost::uint32_t     flags;          /* flags (section type and attributes)*/
0133     boost::uint32_t     reserved[1 + sizeof(AddressOffsetT) / sizeof(uint32_t)];
0134 };
0135 
0136 typedef section_template<boost::uint32_t> section_32_;
0137 typedef section_template<boost::uint64_t> section_64_;
0138 
0139 struct symtab_command_ {
0140     boost::uint32_t    cmd;        /* LC_SYMTAB_ */
0141     boost::uint32_t    cmdsize;    /* sizeof(struct symtab_command) */
0142     boost::uint32_t    symoff;     /* symbol table offset */
0143     boost::uint32_t    nsyms;      /* number of symbol table entries */
0144     boost::uint32_t    stroff;     /* string table offset */
0145     boost::uint32_t    strsize;    /* string table size in bytes */
0146 };
0147 
0148 template <class AddressOffsetT>
0149 struct nlist_template {
0150     boost::uint32_t     n_strx;
0151     boost::uint8_t      n_type;
0152     boost::uint8_t      n_sect;
0153     boost::uint16_t     n_desc;
0154     AddressOffsetT      n_value;
0155 };
0156 
0157 typedef nlist_template<boost::uint32_t> nlist_32_;
0158 typedef nlist_template<boost::uint64_t> nlist_64_;
0159 
0160 template <class AddressOffsetT>
0161 class macho_info {
0162     typedef boost::dll::detail::mach_header_template<AddressOffsetT>        header_t;
0163     typedef boost::dll::detail::load_command_                               load_command_t;
0164     typedef boost::dll::detail::segment_command_template<AddressOffsetT>    segment_t;
0165     typedef boost::dll::detail::section_template<AddressOffsetT>            section_t;
0166     typedef boost::dll::detail::symtab_command_                             symbol_header_t;
0167     typedef boost::dll::detail::nlist_template<AddressOffsetT>              nlist_t;
0168 
0169     BOOST_STATIC_CONSTANT(boost::uint32_t, SEGMENT_CMD_NUMBER = (sizeof(AddressOffsetT) > 4 ? load_command_types::LC_SEGMENT_64_ : load_command_types::LC_SEGMENT_));
0170 
0171 public:
0172     static bool parsing_supported(std::ifstream& fs) {
0173         static const uint32_t magic_bytes = (sizeof(AddressOffsetT) <= sizeof(uint32_t) ? 0xfeedface : 0xfeedfacf);
0174 
0175         uint32_t magic;
0176         fs.seekg(0);
0177         fs.read(reinterpret_cast<char*>(&magic), sizeof(magic));
0178         return (magic_bytes == magic);
0179     }
0180 
0181 private:
0182     template <class T>
0183     static void read_raw(std::ifstream& fs, T& value, std::size_t size = sizeof(T)) {
0184         fs.read(reinterpret_cast<char*>(&value), size);
0185     }
0186 
0187     template <class F>
0188     static void command_finder(std::ifstream& fs, uint32_t cmd_num, F callback_f) {
0189         const header_t h = header(fs);
0190         load_command_t command;
0191         fs.seekg(sizeof(header_t));
0192         for (std::size_t i = 0; i < h.ncmds; ++i) {
0193             const std::ifstream::pos_type pos = fs.tellg();
0194             read_raw(fs, command);
0195             if (command.cmd != cmd_num) {
0196                 fs.seekg(pos + static_cast<std::ifstream::pos_type>(command.cmdsize));
0197                 continue;
0198             }
0199 
0200             fs.seekg(pos);
0201             callback_f(fs);
0202             fs.seekg(pos + static_cast<std::ifstream::pos_type>(command.cmdsize));
0203         }
0204     }
0205 
0206     struct section_names_gather {
0207         std::vector<std::string>&       ret;
0208 
0209         void operator()(std::ifstream& fs) const {
0210             segment_t segment;
0211             read_raw(fs, segment);
0212 
0213             section_t section;
0214             ret.reserve(ret.size() + segment.nsects);
0215             for (std::size_t j = 0; j < segment.nsects; ++j) {
0216                 read_raw(fs, section);
0217                 // `segname` goes right after the `sectname`.
0218                 // Forcing `sectname` to end on '\0'
0219                 section.segname[0] = '\0';
0220                 ret.push_back(section.sectname);
0221                 if (ret.back().empty()) {
0222                     ret.pop_back(); // Do not show empty names
0223                 }
0224             }
0225         }
0226     };
0227 
0228     struct symbol_names_gather {
0229         std::vector<std::string>&       ret;
0230         std::size_t                     section_index;
0231 
0232         void operator()(std::ifstream& fs) const {
0233             symbol_header_t symbh;
0234             read_raw(fs, symbh);
0235             ret.reserve(ret.size() + symbh.nsyms);
0236 
0237             nlist_t symbol;
0238             std::string symbol_name;
0239             for (std::size_t j = 0; j < symbh.nsyms; ++j) {
0240                 fs.seekg(symbh.symoff + j * sizeof(nlist_t));
0241                 read_raw(fs, symbol);
0242                 if (!symbol.n_strx) {
0243                     continue; // Symbol has no name
0244                 }
0245 
0246                 if ((symbol.n_type & 0x0e) != 0xe || !symbol.n_sect) {
0247                     continue; // Symbol has no section
0248                 }
0249 
0250                 if (section_index && section_index != symbol.n_sect) {
0251                     continue; // Not in the required section
0252                 }
0253 
0254                 fs.seekg(symbh.stroff + symbol.n_strx);
0255                 std::getline(fs, symbol_name, '\0');
0256                 if (symbol_name.empty()) {
0257                     continue;
0258                 }
0259 
0260                 if (symbol_name[0] == '_') {
0261                     // Linker adds additional '_' symbol. Could not find official docs for that case.
0262                     ret.push_back(symbol_name.c_str() + 1);
0263                 } else {
0264                     ret.push_back(symbol_name);
0265                 }
0266             }
0267         }
0268     };
0269 
0270 public:
0271     static std::vector<std::string> sections(std::ifstream& fs) {
0272         std::vector<std::string> ret;
0273         section_names_gather f = { ret };
0274         command_finder(fs, SEGMENT_CMD_NUMBER, f);
0275         return ret;
0276     }
0277 
0278 private:
0279     static header_t header(std::ifstream& fs) {
0280         header_t h;
0281 
0282         fs.seekg(0);
0283         read_raw(fs, h);
0284 
0285         return h;
0286     }
0287 
0288 public:
0289     static std::vector<std::string> symbols(std::ifstream& fs) {
0290         std::vector<std::string> ret;
0291         symbol_names_gather f = { ret, 0 };
0292         command_finder(fs, load_command_types::LC_SYMTAB_, f);
0293         return ret;
0294     }
0295 
0296     static std::vector<std::string> symbols(std::ifstream& fs, const char* section_name) {
0297         // Not very optimal solution
0298         std::vector<std::string> ret = sections(fs);
0299         std::vector<std::string>::iterator it = std::find(ret.begin(), ret.end(), section_name);
0300         if (it == ret.end()) {
0301             // No section with such name
0302             ret.clear();
0303             return ret;
0304         }
0305 
0306         // section indexes start from 1
0307         symbol_names_gather f = { ret, static_cast<std::size_t>(1 + (it - ret.begin())) };
0308         ret.clear();
0309         command_finder(fs, load_command_types::LC_SYMTAB_, f);
0310         return ret;
0311     }
0312 };
0313 
0314 typedef macho_info<boost::uint32_t> macho_info32;
0315 typedef macho_info<boost::uint64_t> macho_info64;
0316 
0317 }}} // namespace boost::dll::detail
0318 
0319 #endif // BOOST_DLL_DETAIL_MACHO_INFO_HPP