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