macho_info.hpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. // Copyright 2014 Renato Tegon Forti, Antony Polukhin.
  2. // Copyright 2015-2019 Antony Polukhin.
  3. //
  4. // Distributed under the Boost Software License, Version 1.0.
  5. // (See accompanying file LICENSE_1_0.txt
  6. // or copy at http://www.boost.org/LICENSE_1_0.txt)
  7. #ifndef BOOST_DLL_DETAIL_MACHO_INFO_HPP
  8. #define BOOST_DLL_DETAIL_MACHO_INFO_HPP
  9. #include <boost/dll/config.hpp>
  10. #ifdef BOOST_HAS_PRAGMA_ONCE
  11. # pragma once
  12. #endif
  13. #include <algorithm>
  14. #include <fstream>
  15. #include <boost/cstdint.hpp>
  16. #include <boost/dll/detail/x_info_interface.hpp>
  17. namespace boost { namespace dll { namespace detail {
  18. typedef int integer_t;
  19. typedef int vm_prot_t;
  20. typedef integer_t cpu_type_t;
  21. typedef integer_t cpu_subtype_t;
  22. template <class AddressOffsetT>
  23. struct mach_header_template {
  24. boost::uint32_t magic;
  25. cpu_type_t cputype;
  26. cpu_subtype_t cpusubtype;
  27. boost::uint32_t filetype;
  28. boost::uint32_t ncmds;
  29. boost::uint32_t sizeofcmds;
  30. boost::uint32_t flags[sizeof(AddressOffsetT) / sizeof(uint32_t)]; // Flags and reserved
  31. };
  32. typedef mach_header_template<boost::uint32_t> mach_header_32_;
  33. typedef mach_header_template<boost::uint64_t> mach_header_64_;
  34. struct load_command_ {
  35. boost::uint32_t cmd; /* type of command */
  36. boost::uint32_t cmdsize;
  37. };
  38. struct load_command_types {
  39. BOOST_STATIC_CONSTANT(boost::uint32_t, LC_SEGMENT_ = 0x1); /* segment of this file to be mapped */
  40. BOOST_STATIC_CONSTANT(boost::uint32_t, LC_SYMTAB_ = 0x2); /* link-edit stab symbol table info */
  41. BOOST_STATIC_CONSTANT(boost::uint32_t, LC_SYMSEG_ = 0x3); /* link-edit gdb symbol table info (obsolete) */
  42. BOOST_STATIC_CONSTANT(boost::uint32_t, LC_THREAD_ = 0x4); /* thread */
  43. BOOST_STATIC_CONSTANT(boost::uint32_t, LC_UNIXTHREAD_ = 0x5); /* unix thread (includes a stack) */
  44. BOOST_STATIC_CONSTANT(boost::uint32_t, LC_LOADFVMLIB_ = 0x6); /* load a specified fixed VM shared library */
  45. BOOST_STATIC_CONSTANT(boost::uint32_t, LC_IDFVMLIB_ = 0x7); /* fixed VM shared library identification */
  46. BOOST_STATIC_CONSTANT(boost::uint32_t, LC_IDENT_ = 0x8); /* object identification info (obsolete) */
  47. BOOST_STATIC_CONSTANT(boost::uint32_t, LC_FVMFILE_ = 0x9); /* fixed VM file inclusion (internal use) */
  48. BOOST_STATIC_CONSTANT(boost::uint32_t, LC_PREPAGE_ = 0xa); /* prepage command (internal use) */
  49. BOOST_STATIC_CONSTANT(boost::uint32_t, LC_DYSYMTAB_ = 0xb); /* dynamic link-edit symbol table info */
  50. BOOST_STATIC_CONSTANT(boost::uint32_t, LC_LOAD_DYLIB_ = 0xc); /* load a dynamically linked shared library */
  51. BOOST_STATIC_CONSTANT(boost::uint32_t, LC_ID_DYLIB_ = 0xd); /* dynamically linked shared lib ident */
  52. BOOST_STATIC_CONSTANT(boost::uint32_t, LC_LOAD_DYLINKER_ = 0xe); /* load a dynamic linker */
  53. BOOST_STATIC_CONSTANT(boost::uint32_t, LC_ID_DYLINKER_ = 0xf); /* dynamic linker identification */
  54. BOOST_STATIC_CONSTANT(boost::uint32_t, LC_PREBOUND_DYLIB_ = 0x10); /* modules prebound for a dynamically linked shared library */
  55. BOOST_STATIC_CONSTANT(boost::uint32_t, LC_ROUTINES_ = 0x11); /* image routines */
  56. BOOST_STATIC_CONSTANT(boost::uint32_t, LC_SUB_FRAMEWORK_ = 0x12); /* sub framework */
  57. BOOST_STATIC_CONSTANT(boost::uint32_t, LC_SUB_UMBRELLA_ = 0x13); /* sub umbrella */
  58. BOOST_STATIC_CONSTANT(boost::uint32_t, LC_SUB_CLIENT_ = 0x14); /* sub client */
  59. BOOST_STATIC_CONSTANT(boost::uint32_t, LC_SUB_LIBRARY_ = 0x15); /* sub library */
  60. BOOST_STATIC_CONSTANT(boost::uint32_t, LC_TWOLEVEL_HINTS_ = 0x16); /* two-level namespace lookup hints */
  61. BOOST_STATIC_CONSTANT(boost::uint32_t, LC_PREBIND_CKSUM_ = 0x17); /* prebind checksum */
  62. /*
  63. * After MacOS X 10.1 when a new load command is added that is required to be
  64. * understood by the dynamic linker for the image to execute properly the
  65. * LC_REQ_DYLD bit will be or'ed into the load command constant. If the dynamic
  66. * linker sees such a load command it it does not understand will issue a
  67. * "unknown load command required for execution" error and refuse to use the
  68. * image. Other load commands without this bit that are not understood will
  69. * simply be ignored.
  70. */
  71. BOOST_STATIC_CONSTANT(boost::uint32_t, LC_REQ_DYLD_ = 0x80000000);
  72. /*
  73. * load a dynamically linked shared library that is allowed to be missing
  74. * (all symbols are weak imported).
  75. */
  76. BOOST_STATIC_CONSTANT(boost::uint32_t, LC_LOAD_WEAK_DYLIB_ = (0x18 | LC_REQ_DYLD_));
  77. BOOST_STATIC_CONSTANT(boost::uint32_t, LC_SEGMENT_64_ = 0x19); /* 64-bit segment of this file to be mapped */
  78. BOOST_STATIC_CONSTANT(boost::uint32_t, LC_ROUTINES_64_ = 0x1a); /* 64-bit image routines */
  79. BOOST_STATIC_CONSTANT(boost::uint32_t, LC_UUID_ = 0x1b); /* the uuid */
  80. BOOST_STATIC_CONSTANT(boost::uint32_t, LC_RPATH_ = (0x1c | LC_REQ_DYLD_)); /* runpath additions */
  81. BOOST_STATIC_CONSTANT(boost::uint32_t, LC_CODE_SIGNATURE_ = 0x1d); /* local of code signature */
  82. BOOST_STATIC_CONSTANT(boost::uint32_t, LC_SEGMENT_SPLIT_INFO_= 0x1e); /* local of info to split segments */
  83. BOOST_STATIC_CONSTANT(boost::uint32_t, LC_REEXPORT_DYLIB_ = (0x1f | LC_REQ_DYLD_)); /* load and re-export dylib */
  84. BOOST_STATIC_CONSTANT(boost::uint32_t, LC_LAZY_LOAD_DYLIB_ = 0x20); /* delay load of dylib until first use */
  85. BOOST_STATIC_CONSTANT(boost::uint32_t, LC_ENCRYPTION_INFO_ = 0x21); /* encrypted segment information */
  86. BOOST_STATIC_CONSTANT(boost::uint32_t, LC_DYLD_INFO_ = 0x22); /* compressed dyld information */
  87. BOOST_STATIC_CONSTANT(boost::uint32_t, LC_DYLD_INFO_ONLY_ = (0x22|LC_REQ_DYLD_)); /* compressed dyld information only */
  88. };
  89. template <class AddressOffsetT>
  90. struct segment_command_template {
  91. boost::uint32_t cmd; /* LC_SEGMENT_ */
  92. boost::uint32_t cmdsize; /* includes sizeof section structs */
  93. char segname[16]; /* segment name */
  94. AddressOffsetT vmaddr; /* memory address of this segment */
  95. AddressOffsetT vmsize; /* memory size of this segment */
  96. AddressOffsetT fileoff; /* file offset of this segment */
  97. AddressOffsetT filesize; /* amount to map from the file */
  98. vm_prot_t maxprot; /* maximum VM protection */
  99. vm_prot_t initprot; /* initial VM protection */
  100. boost::uint32_t nsects; /* number of sections in segment */
  101. boost::uint32_t flags; /* flags */
  102. };
  103. typedef segment_command_template<boost::uint32_t> segment_command_32_;
  104. typedef segment_command_template<boost::uint64_t> segment_command_64_;
  105. template <class AddressOffsetT>
  106. struct section_template {
  107. char sectname[16]; /* name of this section */
  108. char segname[16]; /* segment this section goes in */
  109. AddressOffsetT addr; /* memory address of this section */
  110. AddressOffsetT size; /* size in bytes of this section */
  111. boost::uint32_t offset; /* file offset of this section */
  112. boost::uint32_t align; /* section alignment (power of 2) */
  113. boost::uint32_t reloff; /* file offset of relocation entries */
  114. boost::uint32_t nreloc; /* number of relocation entries */
  115. boost::uint32_t flags; /* flags (section type and attributes)*/
  116. boost::uint32_t reserved[1 + sizeof(AddressOffsetT) / sizeof(uint32_t)];
  117. };
  118. typedef section_template<boost::uint32_t> section_32_;
  119. typedef section_template<boost::uint64_t> section_64_;
  120. struct symtab_command_ {
  121. boost::uint32_t cmd; /* LC_SYMTAB_ */
  122. boost::uint32_t cmdsize; /* sizeof(struct symtab_command) */
  123. boost::uint32_t symoff; /* symbol table offset */
  124. boost::uint32_t nsyms; /* number of symbol table entries */
  125. boost::uint32_t stroff; /* string table offset */
  126. boost::uint32_t strsize; /* string table size in bytes */
  127. };
  128. template <class AddressOffsetT>
  129. struct nlist_template {
  130. boost::uint32_t n_strx;
  131. boost::uint8_t n_type;
  132. boost::uint8_t n_sect;
  133. boost::uint16_t n_desc;
  134. AddressOffsetT n_value;
  135. };
  136. typedef nlist_template<boost::uint32_t> nlist_32_;
  137. typedef nlist_template<boost::uint64_t> nlist_64_;
  138. template <class AddressOffsetT>
  139. class macho_info: public x_info_interface {
  140. std::ifstream& f_;
  141. typedef boost::dll::detail::mach_header_template<AddressOffsetT> header_t;
  142. typedef boost::dll::detail::load_command_ load_command_t;
  143. typedef boost::dll::detail::segment_command_template<AddressOffsetT> segment_t;
  144. typedef boost::dll::detail::section_template<AddressOffsetT> section_t;
  145. typedef boost::dll::detail::symtab_command_ symbol_header_t;
  146. typedef boost::dll::detail::nlist_template<AddressOffsetT> nlist_t;
  147. BOOST_STATIC_CONSTANT(boost::uint32_t, SEGMENT_CMD_NUMBER = (sizeof(AddressOffsetT) > 4 ? load_command_types::LC_SEGMENT_64_ : load_command_types::LC_SEGMENT_));
  148. public:
  149. static bool parsing_supported(std::ifstream& f) {
  150. static const uint32_t magic_bytes = (sizeof(AddressOffsetT) <= sizeof(uint32_t) ? 0xfeedface : 0xfeedfacf);
  151. uint32_t magic;
  152. f.seekg(0);
  153. f.read(reinterpret_cast<char*>(&magic), sizeof(magic));
  154. return (magic_bytes == magic);
  155. }
  156. explicit macho_info(std::ifstream& f) BOOST_NOEXCEPT
  157. : f_(f)
  158. {}
  159. private:
  160. template <class T>
  161. inline void read_raw(T& value, std::size_t size = sizeof(T)) const {
  162. f_.read(reinterpret_cast<char*>(&value), size);
  163. }
  164. template <class F>
  165. void command_finder(uint32_t cmd_num, F callback_f) {
  166. const header_t h = header();
  167. load_command_t command;
  168. f_.seekg(sizeof(header_t));
  169. for (std::size_t i = 0; i < h.ncmds; ++i) {
  170. const std::ifstream::pos_type pos = f_.tellg();
  171. read_raw(command);
  172. if (command.cmd != cmd_num) {
  173. f_.seekg(pos + static_cast<std::ifstream::pos_type>(command.cmdsize));
  174. continue;
  175. }
  176. f_.seekg(pos);
  177. callback_f(*this);
  178. f_.seekg(pos + static_cast<std::ifstream::pos_type>(command.cmdsize));
  179. }
  180. }
  181. struct section_names_gather {
  182. std::vector<std::string>& ret;
  183. void operator()(const macho_info& f) const {
  184. segment_t segment;
  185. f.read_raw(segment);
  186. section_t section;
  187. ret.reserve(ret.size() + segment.nsects);
  188. for (std::size_t j = 0; j < segment.nsects; ++j) {
  189. f.read_raw(section);
  190. // `segname` goes right after the `sectname`.
  191. // Forcing `sectname` to end on '\0'
  192. section.segname[0] = '\0';
  193. ret.push_back(section.sectname);
  194. if (ret.back().empty()) {
  195. ret.pop_back(); // Do not show empty names
  196. }
  197. }
  198. }
  199. };
  200. struct symbol_names_gather {
  201. std::vector<std::string>& ret;
  202. std::size_t section_index;
  203. void operator()(const macho_info& f) const {
  204. symbol_header_t symbh;
  205. f.read_raw(symbh);
  206. ret.reserve(ret.size() + symbh.nsyms);
  207. nlist_t symbol;
  208. std::string symbol_name;
  209. for (std::size_t j = 0; j < symbh.nsyms; ++j) {
  210. f.f_.seekg(symbh.symoff + j * sizeof(nlist_t));
  211. f.read_raw(symbol);
  212. if (!symbol.n_strx) {
  213. continue; // Symbol has no name
  214. }
  215. if ((symbol.n_type & 0x0e) != 0xe || !symbol.n_sect) {
  216. continue; // Symbol has no section
  217. }
  218. if (section_index && section_index != symbol.n_sect) {
  219. continue; // Not in the required section
  220. }
  221. f.f_.seekg(symbh.stroff + symbol.n_strx);
  222. getline(f.f_, symbol_name, '\0');
  223. if (symbol_name.empty()) {
  224. continue;
  225. }
  226. if (symbol_name[0] == '_') {
  227. // Linker adds additional '_' symbol. Could not find official docs for that case.
  228. ret.push_back(symbol_name.c_str() + 1);
  229. } else {
  230. ret.push_back(symbol_name);
  231. }
  232. }
  233. }
  234. };
  235. public:
  236. std::vector<std::string> sections() {
  237. std::vector<std::string> ret;
  238. section_names_gather f = { ret };
  239. command_finder(SEGMENT_CMD_NUMBER, f);
  240. return ret;
  241. }
  242. private:
  243. inline header_t header() {
  244. header_t h;
  245. f_.seekg(0);
  246. read_raw(h);
  247. return h;
  248. }
  249. public:
  250. std::vector<std::string> symbols() {
  251. std::vector<std::string> ret;
  252. symbol_names_gather f = { ret, 0 };
  253. command_finder(load_command_types::LC_SYMTAB_, f);
  254. return ret;
  255. }
  256. std::vector<std::string> symbols(const char* section_name) {
  257. // Not very optimal solution
  258. std::vector<std::string> ret = sections();
  259. std::vector<std::string>::iterator it = std::find(ret.begin(), ret.end(), section_name);
  260. if (it == ret.end()) {
  261. // No section with such name
  262. ret.clear();
  263. return ret;
  264. }
  265. // section indexes start from 1
  266. symbol_names_gather f = { ret, static_cast<std::size_t>(1 + (it - ret.begin())) };
  267. ret.clear();
  268. command_finder(load_command_types::LC_SYMTAB_, f);
  269. return ret;
  270. }
  271. };
  272. typedef macho_info<boost::uint32_t> macho_info32;
  273. typedef macho_info<boost::uint64_t> macho_info64;
  274. }}} // namespace boost::dll::detail
  275. #endif // BOOST_DLL_DETAIL_MACHO_INFO_HPP