]> git.saurik.com Git - apple/dyld.git/blob - dyld3/APIs_macOS.cpp
dyld-519.2.2.tar.gz
[apple/dyld.git] / dyld3 / APIs_macOS.cpp
1 /*
2 * Copyright (c) 2017 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25 #include <string.h>
26 #include <stdio.h>
27 #include <stdint.h>
28 #include <_simple.h>
29 #include <sys/errno.h>
30 #include <sys/mman.h>
31 #include <sys/stat.h>
32 #include <dirent.h>
33 #include <fcntl.h>
34 #include <TargetConditionals.h>
35 #include <malloc/malloc.h>
36
37 #include <algorithm>
38
39 #include "dlfcn.h"
40 #include "dyld_priv.h"
41
42 #include "AllImages.h"
43 #include "MachOParser.h"
44 #include "Loading.h"
45 #include "Logging.h"
46 #include "Diagnostics.h"
47 #include "DyldSharedCache.h"
48 #include "APIs.h"
49
50
51
52 typedef dyld3::launch_cache::binary_format::Image BinaryImage;
53
54
55 namespace dyld3 {
56
57 // from APIs.cpp
58 void parseDlHandle(void* h, const mach_header** mh, bool* dontContinue);
59 const mach_header* loadImageAndDependents(Diagnostics& diag, const launch_cache::binary_format::Image* imageToLoad, bool bumpDlopenCount);
60
61
62 // only in macOS and deprecated
63 #if __MAC_OS_X_VERSION_MIN_REQUIRED
64
65 // macOS needs to support an old API that only works with fileype==MH_BUNDLE.
66 // In this deprecated API (unlike dlopen), loading and linking are separate steps.
67 // NSCreateObjectFileImageFrom*() just maps in the bundle mach-o file.
68 // NSLinkModule() does the load of dependent modules and rebasing/binding.
69 // To unload one of these, you must call NSUnLinkModule() and NSDestroyObjectFileImage() in any order!
70 //
71
72 NSObjectFileImageReturnCode NSCreateObjectFileImageFromFile(const char* path, NSObjectFileImage* ofi)
73 {
74 log_apis("NSCreateObjectFileImageFromFile(\"%s\", %p)\n", path, ofi);
75
76 // verify path exists
77 struct stat statbuf;
78 if ( ::stat(path, &statbuf) == -1 )
79 return NSObjectFileImageFailure;
80
81 // create ofi that just contains path. NSLinkModule does all the work
82 __NSObjectFileImage* result = gAllImages.addNSObjectFileImage();
83 result->path = strdup(path);
84 result->memSource = nullptr;
85 result->memLength = 0;
86 result->loadAddress = nullptr;
87 result->binImage = nullptr;
88 *ofi = result;
89
90 log_apis("NSCreateObjectFileImageFromFile() => %p\n", result);
91
92 return NSObjectFileImageSuccess;
93 }
94
95 NSObjectFileImageReturnCode NSCreateObjectFileImageFromMemory(const void* memImage, size_t memImageSize, NSObjectFileImage *ofi)
96 {
97 log_apis("NSCreateObjectFileImageFromMemory(%p, 0x%0lX, %p)\n", memImage, memImageSize, ofi);
98
99 // sanity check the buffer is a mach-o file
100 __block Diagnostics diag;
101 __block const mach_header* foundMH = nullptr;
102 if ( MachOParser::isMachO(diag, memImage, memImageSize) ) {
103 foundMH = (mach_header*)memImage;
104 }
105 else {
106 FatUtil::forEachSlice(diag, memImage, memImageSize, ^(uint32_t sliceCpuType, uint32_t sliceCpuSubType, const void* sliceStart, size_t sliceSize, bool& stop) {
107 if ( MachOParser::isMachO(diag, sliceStart, sliceSize) ) {
108 foundMH = (mach_header*)sliceStart;
109 stop = true;
110 }
111 });
112 }
113 if ( foundMH == nullptr ) {
114 log_apis("NSCreateObjectFileImageFromMemory() not mach-o\n");
115 return NSObjectFileImageFailure;
116 }
117
118 // this API can only be used with bundles
119 if ( foundMH->filetype != MH_BUNDLE ) {
120 log_apis("NSCreateObjectFileImageFromMemory() not a bundle, filetype=%d\n", foundMH->filetype);
121 return NSObjectFileImageInappropriateFile;
122 }
123
124 // allocate ofi that just lists the memory range
125 __NSObjectFileImage* result = gAllImages.addNSObjectFileImage();
126 result->path = nullptr;
127 result->memSource = memImage;
128 result->memLength = memImageSize;
129 result->loadAddress = nullptr;
130 result->binImage = nullptr;
131 *ofi = result;
132
133 log_apis("NSCreateObjectFileImageFromMemory() => %p\n", result);
134
135 return NSObjectFileImageSuccess;
136 }
137
138 NSModule NSLinkModule(NSObjectFileImage ofi, const char* moduleName, uint32_t options)
139 {
140 log_apis("NSLinkModule(%p, \"%s\", 0x%08X)\n", ofi, moduleName, options);
141
142 // ofi is invalid if not in list
143 if ( !gAllImages.hasNSObjectFileImage(ofi) ) {
144 log_apis("NSLinkModule() => NULL (invalid NSObjectFileImage)\n");
145 return nullptr;
146 }
147
148 // if this is memory based image, write to temp file, then use file based loading
149 const BinaryImage* imageToLoad = nullptr;
150 if ( ofi->memSource != nullptr ) {
151 // make temp file with content of memory buffer
152 bool successfullyWritten = false;
153 ofi->path = ::tempnam(nullptr, "NSCreateObjectFileImageFromMemory-");
154 if ( ofi->path != nullptr ) {
155 int fd = ::open(ofi->path, O_WRONLY | O_CREAT | O_EXCL, 0644);
156 if ( fd != -1 ) {
157 ssize_t writtenSize = ::pwrite(fd, ofi->memSource, ofi->memLength, 0);
158 if ( writtenSize == ofi->memLength )
159 successfullyWritten = true;
160 ::close(fd);
161 }
162 }
163 if ( !successfullyWritten ) {
164 if ( ofi->path != nullptr ) {
165 free((void*)ofi->path);
166 ofi->path = nullptr;
167 }
168 log_apis("NSLinkModule() => NULL (could not save memory image to temp file)\n");
169 return nullptr;
170 }
171 }
172 else {
173 // check if image is in a known ImageGroup, but not loaded. if so, load using existing closure info
174 log_apis(" NSLinkModule: checking for pre-built closure for path: %s\n", ofi->path);
175 imageToLoad = gAllImages.findImageInKnownGroups(ofi->path);
176 // TODO: check symlinks, realpath
177 }
178
179 // if no existing closure, RPC to closured to create one
180 if ( imageToLoad == nullptr ) {
181 const char* closuredErrorMessages[3];
182 int closuredErrorMessagesCount = 0;
183 if ( imageToLoad == nullptr ) {
184 imageToLoad = gAllImages.messageClosured(ofi->path, "NSLinkModule", closuredErrorMessages, closuredErrorMessagesCount);
185 }
186 for (int i=0; i < closuredErrorMessagesCount; ++i) {
187 log_apis(" NSLinkModule: failed: %s\n", closuredErrorMessages[i]);
188 free((void*)closuredErrorMessages[i]);
189 }
190 }
191
192 // use Image info to load and fixup image and all its dependents
193 if ( imageToLoad != nullptr ) {
194 Diagnostics diag;
195 ofi->loadAddress = loadImageAndDependents(diag, imageToLoad, true);
196 if ( diag.hasError() )
197 log_apis(" NSLinkModule: failed: %s\n", diag.errorMessage());
198 }
199
200 // if memory based load, delete temp file
201 if ( ofi->memSource != nullptr ) {
202 log_apis(" NSLinkModule: delete temp file: %s\n", ofi->path);
203 ::unlink(ofi->path);
204 }
205
206 log_apis("NSLinkModule() => %p\n", ofi->loadAddress);
207 return (NSModule)ofi->loadAddress;
208 }
209
210 // NSUnLinkModule unmaps the image, but does not release the NSObjectFileImage
211 bool NSUnLinkModule(NSModule module, uint32_t options)
212 {
213 log_apis("NSUnLinkModule(%p, 0x%08X)\n", module, options);
214
215 bool result = false;
216 const mach_header* mh = (mach_header*)module;
217 launch_cache::Image image = gAllImages.findByLoadAddress(mh);
218 if ( image.valid() ) {
219 // removes image if reference count went to zero
220 gAllImages.decRefCount(mh);
221 result = true;
222 }
223
224 log_apis("NSUnLinkModule() => %d\n", result);
225
226 return result;
227 }
228
229 // NSDestroyObjectFileImage releases the NSObjectFileImage, but the mapped image may remain in use
230 bool NSDestroyObjectFileImage(NSObjectFileImage ofi)
231 {
232 log_apis("NSDestroyObjectFileImage(%p)\n", ofi);
233
234 // ofi is invalid if not in list
235 if ( !gAllImages.hasNSObjectFileImage(ofi) )
236 return false;
237
238 // keep copy of info
239 const void* memSource = ofi->memSource;
240 size_t memLength = ofi->memLength;
241 const char* path = ofi->path;
242
243 // remove from list
244 gAllImages.removeNSObjectFileImage(ofi);
245
246 // if object was created from a memory, release that memory
247 // NOTE: this is the way dyld has always done this. NSCreateObjectFileImageFromMemory() hands ownership of the memory to dyld
248 if ( memSource != nullptr ) {
249 // we don't know if memory came from malloc or vm_allocate, so ask malloc
250 if ( malloc_size(memSource) != 0 )
251 free((void*)(memSource));
252 else
253 vm_deallocate(mach_task_self(), (vm_address_t)memSource, memLength);
254 }
255 free((void*)path);
256
257 return true;
258 }
259
260 uint32_t NSSymbolDefinitionCountInObjectFileImage(NSObjectFileImage objectFileImage)
261 {
262 halt("NSSymbolDefinitionCountInObjectFileImage() is obsolete");
263 }
264
265 const char* NSSymbolDefinitionNameInObjectFileImage(NSObjectFileImage objectFileImage, uint32_t ordinal)
266 {
267 halt("NSSymbolDefinitionNameInObjectFileImage() is obsolete");
268 }
269
270 uint32_t NSSymbolReferenceCountInObjectFileImage(NSObjectFileImage objectFileImage)
271 {
272 halt("NSSymbolReferenceCountInObjectFileImage() is obsolete");
273 }
274
275 const char* NSSymbolReferenceNameInObjectFileImage(NSObjectFileImage objectFileImage, uint32_t ordinal, bool *tentative_definition)
276 {
277 halt("NSSymbolReferenceNameInObjectFileImage() is obsolete");
278 }
279
280 bool NSIsSymbolDefinedInObjectFileImage(NSObjectFileImage ofi, const char* symbolName)
281 {
282 log_apis("NSIsSymbolDefinedInObjectFileImage(%p, %s)\n", ofi, symbolName);
283
284 // ofi is invalid if not in list
285 if ( !gAllImages.hasNSObjectFileImage(ofi) )
286 return false;
287
288 void* addr;
289 MachOParser parser(ofi->loadAddress);
290 return parser.hasExportedSymbol(symbolName, ^(uint32_t , const char*, void*, const mach_header**, void**) {
291 return false;
292 }, &addr);
293 }
294
295 void* NSGetSectionDataInObjectFileImage(NSObjectFileImage ofi, const char* segmentName, const char* sectionName, size_t* size)
296 {
297 // ofi is invalid if not in list
298 if ( !gAllImages.hasNSObjectFileImage(ofi) )
299 return nullptr;
300
301 __block void* result = nullptr;
302 MachOParser parser(ofi->loadAddress);
303 parser.forEachSection(^(const char* aSegName, const char* aSectName, uint32_t flags, const void* content, size_t aSize, bool illegalSectionSize, bool& stop) {
304 if ( (strcmp(sectionName, aSectName) == 0) && (strcmp(segmentName, aSegName) == 0) ) {
305 result = (void*)content;
306 if ( size != nullptr )
307 *size = aSize;
308 stop = true;
309 }
310 });
311 return result;
312 }
313
314 const char* NSNameOfModule(NSModule m)
315 {
316 log_apis("NSNameOfModule(%p)\n", m);
317
318 const mach_header* foundInLoadAddress;
319 launch_cache::Image image = gAllImages.findByOwnedAddress(m, &foundInLoadAddress);
320 if ( image.valid() ) {
321 return gAllImages.imagePath(image.binaryData());
322 }
323 return nullptr;
324 }
325
326 const char* NSLibraryNameForModule(NSModule m)
327 {
328 log_apis("NSLibraryNameForModule(%p)\n", m);
329
330 const mach_header* foundInLoadAddress;
331 launch_cache::Image image = gAllImages.findByOwnedAddress(m, &foundInLoadAddress);
332 if ( image.valid() ) {
333 return gAllImages.imagePath(image.binaryData());
334 }
335 return nullptr;
336 }
337
338
339 static bool flatFindSymbol(const char* symbolName, void** symbolAddress, const mach_header** foundInImageAtLoadAddress)
340 {
341 for (uint32_t index=0; index < gAllImages.count(); ++index) {
342 const mach_header* loadAddress;
343 launch_cache::Image image = gAllImages.findByLoadOrder(index, &loadAddress);
344 if ( image.valid() ) {
345 MachOParser parser(loadAddress);
346 if ( parser.hasExportedSymbol(symbolName, ^(uint32_t , const char* , void* , const mach_header** , void**) { return false; }, symbolAddress) ) {
347 *foundInImageAtLoadAddress = loadAddress;
348 return true;
349 }
350 }
351 }
352 return false;
353 }
354
355 bool NSIsSymbolNameDefined(const char* symbolName)
356 {
357 log_apis("NSIsSymbolNameDefined(%s)\n", symbolName);
358
359 const mach_header* foundInImageAtLoadAddress;
360 void* address;
361 return flatFindSymbol(symbolName, &address, &foundInImageAtLoadAddress);
362 }
363
364 bool NSIsSymbolNameDefinedWithHint(const char* symbolName, const char* libraryNameHint)
365 {
366 log_apis("NSIsSymbolNameDefinedWithHint(%s, %s)\n", symbolName, libraryNameHint);
367
368 const mach_header* foundInImageAtLoadAddress;
369 void* address;
370 return flatFindSymbol(symbolName, &address, &foundInImageAtLoadAddress);
371 }
372
373 bool NSIsSymbolNameDefinedInImage(const struct mach_header* mh, const char* symbolName)
374 {
375 log_apis("NSIsSymbolNameDefinedInImage(%p, %s)\n", mh, symbolName);
376
377 MachOParser::DependentFinder reExportFollower = ^(uint32_t depIndex, const char* depLoadPath, void* extra, const mach_header** foundMH, void** foundExtra) {
378 *foundMH = gAllImages.alreadyLoaded(depLoadPath, false);
379 return (*foundMH != nullptr);
380 };
381
382 MachOParser parser(mh);
383 void* result;
384 return parser.hasExportedSymbol(symbolName, reExportFollower, &result);
385 }
386
387 NSSymbol NSLookupAndBindSymbol(const char* symbolName)
388 {
389 log_apis("NSLookupAndBindSymbol(%s)\n", symbolName);
390
391 const mach_header* foundInImageAtLoadAddress;
392 void* symbolAddress;
393 if ( flatFindSymbol(symbolName, &symbolAddress, &foundInImageAtLoadAddress) ) {
394 return (NSSymbol)symbolAddress;
395 }
396 return nullptr;
397 }
398
399 NSSymbol NSLookupAndBindSymbolWithHint(const char* symbolName, const char* libraryNameHint)
400 {
401 log_apis("NSLookupAndBindSymbolWithHint(%s, %s)\n", symbolName, libraryNameHint);
402
403 const mach_header* foundInImageAtLoadAddress;
404 void* symbolAddress;
405 if ( flatFindSymbol(symbolName, &symbolAddress, &foundInImageAtLoadAddress) ) {
406 return (NSSymbol)symbolAddress;
407 }
408 return nullptr;
409 }
410
411 NSSymbol NSLookupSymbolInModule(NSModule module, const char* symbolName)
412 {
413 log_apis("NSLookupSymbolInModule(%p. %s)\n", module, symbolName);
414
415 MachOParser::DependentFinder reExportFollower = ^(uint32_t depIndex, const char* depLoadPath, void* extra, const mach_header** foundMH, void** foundExtra) {
416 *foundMH = gAllImages.alreadyLoaded(depLoadPath, false);
417 return (*foundMH != nullptr);
418 };
419
420 const mach_header* mh = (const mach_header*)module;
421 uint32_t loadIndex;
422 if ( gAllImages.findIndexForLoadAddress(mh, loadIndex) ) {
423 MachOParser parser(mh);
424 void* symAddress;
425 if ( parser.hasExportedSymbol(symbolName, reExportFollower, &symAddress) ) {
426 return (NSSymbol)symAddress;
427 }
428 }
429 return nullptr;
430 }
431
432 NSSymbol NSLookupSymbolInImage(const struct mach_header* mh, const char* symbolName, uint32_t options)
433 {
434 log_apis("NSLookupSymbolInImage(%p, \"%s\", 0x%08X)\n", mh, symbolName, options);
435
436 MachOParser::DependentFinder reExportFollower = ^(uint32_t depIndex, const char* depLoadPath, void* extra, const mach_header** foundMH, void** foundExtra) {
437 *foundMH = gAllImages.alreadyLoaded(depLoadPath, false);
438 return (*foundMH != nullptr);
439 };
440
441 MachOParser parser(mh);
442 void* result;
443 if ( parser.hasExportedSymbol(symbolName, reExportFollower, &result) ) {
444 log_apis(" NSLookupSymbolInImage() => %p\n", result);
445 return (NSSymbol)result;
446 }
447
448 if ( options & NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR ) {
449 log_apis(" NSLookupSymbolInImage() => NULL\n");
450 return nullptr;
451 }
452 return nullptr;
453 }
454
455 const char* NSNameOfSymbol(NSSymbol symbol)
456 {
457 halt("NSNameOfSymbol() is obsolete");
458 }
459
460 void* NSAddressOfSymbol(NSSymbol symbol)
461 {
462 log_apis("NSAddressOfSymbol(%p)\n", symbol);
463
464 // in dyld 1.0, NSSymbol was a pointer to the nlist entry in the symbol table
465 return (void*)symbol;
466 }
467
468 NSModule NSModuleForSymbol(NSSymbol symbol)
469 {
470 log_apis("NSModuleForSymbol(%p)\n", symbol);
471
472 const mach_header* foundInLoadAddress;
473 launch_cache::Image image = gAllImages.findByOwnedAddress(symbol, &foundInLoadAddress);
474 if ( image.valid() ) {
475 return (NSModule)foundInLoadAddress;
476 }
477 return nullptr;
478 }
479
480 void NSLinkEditError(NSLinkEditErrors *c, int *errorNumber, const char** fileName, const char** errorString)
481 {
482 log_apis("NSLinkEditError(%p, %p, %p, %p)\n", c, errorNumber, fileName, errorString);
483 *c = NSLinkEditOtherError;
484 *errorNumber = 0;
485 *fileName = NULL;
486 *errorString = NULL;
487 }
488
489 bool NSAddLibrary(const char* pathName)
490 {
491 log_apis("NSAddLibrary(%s)\n", pathName);
492
493 return ( dlopen(pathName, 0) != nullptr);
494 }
495
496 bool NSAddLibraryWithSearching(const char* pathName)
497 {
498 log_apis("NSAddLibraryWithSearching(%s)\n", pathName);
499
500 return ( dlopen(pathName, 0) != nullptr);
501 }
502
503 const mach_header* NSAddImage(const char* imageName, uint32_t options)
504 {
505 log_apis("NSAddImage(\"%s\", 0x%08X)\n", imageName, options);
506
507 // Note: this is a quick and dirty implementation that just uses dlopen() and ignores some option flags
508 uint32_t dloptions = 0;
509 if ( (options & NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED) != 0 )
510 dloptions |= RTLD_NOLOAD;
511
512 void* h = dlopen(imageName, dloptions);
513 if ( h != nullptr ) {
514 const mach_header* mh;
515 bool dontContinue;
516 parseDlHandle(h, &mh, &dontContinue);
517 return mh;
518 }
519
520 if ( (options & (NSADDIMAGE_OPTION_RETURN_ON_ERROR|NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED)) == 0 ) {
521 halt("NSAddImage() image not found");
522 }
523 return nullptr;
524 }
525
526 void NSInstallLinkEditErrorHandlers(const NSLinkEditErrorHandlers *handlers)
527 {
528 halt("NSInstallLinkEditErrorHandlers() is obsolete");
529 }
530
531 bool _dyld_present(void)
532 {
533 log_apis("_dyld_present()\n");
534
535 return true;
536 }
537
538 bool _dyld_launched_prebound(void)
539 {
540 halt("_dyld_launched_prebound() is obsolete");
541 }
542
543 bool _dyld_all_twolevel_modules_prebound(void)
544 {
545 halt("_dyld_all_twolevel_modules_prebound() is obsolete");
546 }
547
548 bool _dyld_bind_fully_image_containing_address(const void* address)
549 {
550 log_apis("_dyld_bind_fully_image_containing_address(%p)\n", address);
551
552 // in dyld3, everything is always fully bound
553 return true;
554 }
555
556 bool _dyld_image_containing_address(const void* address)
557 {
558 log_apis("_dyld_image_containing_address(%p)\n", address);
559
560 return (dyld_image_header_containing_address(address) != nullptr);
561 }
562
563 void _dyld_lookup_and_bind(const char* symbolName, void **address, NSModule* module)
564 {
565 log_apis("_dyld_lookup_and_bind(%s, %p, %p)\n", symbolName, address, module);
566
567 const mach_header* foundInImageAtLoadAddress;
568 if ( flatFindSymbol(symbolName, address, &foundInImageAtLoadAddress) ) {
569 *module = (NSModule)foundInImageAtLoadAddress;
570 return;
571 }
572
573 *address = 0;
574 *module = 0;
575 }
576
577 void _dyld_lookup_and_bind_with_hint(const char* symbolName, const char* libraryNameHint, void** address, NSModule* module)
578 {
579 log_apis("_dyld_lookup_and_bind_with_hint(%s, %s, %p, %p)\n", symbolName, libraryNameHint, address, module);
580
581 const mach_header* foundInImageAtLoadAddress;
582 if ( flatFindSymbol(symbolName, address, &foundInImageAtLoadAddress) ) {
583 *module = (NSModule)foundInImageAtLoadAddress;
584 return;
585 }
586
587 *address = 0;
588 *module = 0;
589 }
590
591
592 void _dyld_lookup_and_bind_fully(const char* symbolName, void** address, NSModule* module)
593 {
594 log_apis("_dyld_lookup_and_bind_fully(%s, %p, %p)\n", symbolName, address, module);
595
596 const mach_header* foundInImageAtLoadAddress;
597 if ( flatFindSymbol(symbolName, address, &foundInImageAtLoadAddress) ) {
598 *module = (NSModule)foundInImageAtLoadAddress;
599 return;
600 }
601
602 *address = 0;
603 *module = 0;
604 }
605
606 const struct mach_header* _dyld_get_image_header_containing_address(const void* address)
607 {
608 log_apis("_dyld_get_image_header_containing_address(%p)\n", address);
609
610 return dyld_image_header_containing_address(address);
611 }
612
613 #endif
614
615
616 } // namespace dyld3
617