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