Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-11-06 09:37:06

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