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