File indexing completed on 2025-11-06 09:37:06
0001
0002
0003
0004
0005
0006
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)];
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;
0046 std::uint32_t cmdsize;
0047 };
0048
0049 struct load_command_types {
0050 static constexpr std::uint32_t LC_SEGMENT_ = 0x1;
0051 static constexpr std::uint32_t LC_SYMTAB_ = 0x2;
0052 static constexpr std::uint32_t LC_SYMSEG_ = 0x3;
0053 static constexpr std::uint32_t LC_THREAD_ = 0x4;
0054 static constexpr std::uint32_t LC_UNIXTHREAD_ = 0x5;
0055 static constexpr std::uint32_t LC_LOADFVMLIB_ = 0x6;
0056 static constexpr std::uint32_t LC_IDFVMLIB_ = 0x7;
0057 static constexpr std::uint32_t LC_IDENT_ = 0x8;
0058 static constexpr std::uint32_t LC_FVMFILE_ = 0x9;
0059 static constexpr std::uint32_t LC_PREPAGE_ = 0xa;
0060 static constexpr std::uint32_t LC_DYSYMTAB_ = 0xb;
0061 static constexpr std::uint32_t LC_LOAD_DYLIB_ = 0xc;
0062 static constexpr std::uint32_t LC_ID_DYLIB_ = 0xd;
0063 static constexpr std::uint32_t LC_LOAD_DYLINKER_ = 0xe;
0064 static constexpr std::uint32_t LC_ID_DYLINKER_ = 0xf;
0065 static constexpr std::uint32_t LC_PREBOUND_DYLIB_ = 0x10;
0066 static constexpr std::uint32_t LC_ROUTINES_ = 0x11;
0067 static constexpr std::uint32_t LC_SUB_FRAMEWORK_ = 0x12;
0068 static constexpr std::uint32_t LC_SUB_UMBRELLA_ = 0x13;
0069 static constexpr std::uint32_t LC_SUB_CLIENT_ = 0x14;
0070 static constexpr std::uint32_t LC_SUB_LIBRARY_ = 0x15;
0071 static constexpr std::uint32_t LC_TWOLEVEL_HINTS_ = 0x16;
0072 static constexpr std::uint32_t LC_PREBIND_CKSUM_ = 0x17;
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082 static constexpr std::uint32_t LC_REQ_DYLD_ = 0x80000000;
0083
0084
0085
0086
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;
0091 static constexpr std::uint32_t LC_ROUTINES_64_ = 0x1a;
0092 static constexpr std::uint32_t LC_UUID_ = 0x1b;
0093 static constexpr std::uint32_t LC_RPATH_ = (0x1c | LC_REQ_DYLD_);
0094 static constexpr std::uint32_t LC_CODE_SIGNATURE_ = 0x1d;
0095 static constexpr std::uint32_t LC_SEGMENT_SPLIT_INFO_= 0x1e;
0096 static constexpr std::uint32_t LC_REEXPORT_DYLIB_ = (0x1f | LC_REQ_DYLD_);
0097 static constexpr std::uint32_t LC_LAZY_LOAD_DYLIB_ = 0x20;
0098 static constexpr std::uint32_t LC_ENCRYPTION_INFO_ = 0x21;
0099 static constexpr std::uint32_t LC_DYLD_INFO_ = 0x22;
0100 static constexpr std::uint32_t LC_DYLD_INFO_ONLY_ = (0x22|LC_REQ_DYLD_);
0101 };
0102
0103 template <class AddressOffsetT>
0104 struct segment_command_template {
0105 std::uint32_t cmd;
0106 std::uint32_t cmdsize;
0107 char segname[16];
0108 AddressOffsetT vmaddr;
0109 AddressOffsetT vmsize;
0110 AddressOffsetT fileoff;
0111 AddressOffsetT filesize;
0112 vm_prot_t maxprot;
0113 vm_prot_t initprot;
0114 std::uint32_t nsects;
0115 std::uint32_t 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];
0124 char segname[16];
0125 AddressOffsetT addr;
0126 AddressOffsetT size;
0127 std::uint32_t offset;
0128 std::uint32_t align;
0129 std::uint32_t reloff;
0130 std::uint32_t nreloc;
0131 std::uint32_t flags;
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;
0140 std::uint32_t cmdsize;
0141 std::uint32_t symoff;
0142 std::uint32_t nsyms;
0143 std::uint32_t stroff;
0144 std::uint32_t strsize;
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
0217
0218 section.segname[0] = '\0';
0219 ret.push_back(section.sectname);
0220 if (ret.back().empty()) {
0221 ret.pop_back();
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;
0243 }
0244
0245 if ((symbol.n_type & 0x0e) != 0xe || !symbol.n_sect) {
0246 continue;
0247 }
0248
0249 if (section_index && section_index != symbol.n_sect) {
0250 continue;
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
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
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
0301 ret.clear();
0302 return ret;
0303 }
0304
0305
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 }}}
0317
0318 #endif